Merge branch '4.4'
* 4.4: [Security] Revise UserPasswordEncoderInterface::needsRehash() [Form] update type of form $name arguments [HttpClient] Preserve the case of headers when sending them [Ldap][Security] use right arguments count in sercurity factories
This commit is contained in:
commit
f1368b4e29
@ -35,8 +35,8 @@ class FormLoginLdapFactory extends FormLoginFactory
|
||||
->replaceArgument(2, $id)
|
||||
->replaceArgument(3, new Reference($config['service']))
|
||||
->replaceArgument(4, $config['dn_string'])
|
||||
->replaceArgument(5, $config['search_dn'])
|
||||
->replaceArgument(6, $config['search_password'])
|
||||
->replaceArgument(6, $config['search_dn'])
|
||||
->replaceArgument(7, $config['search_password'])
|
||||
;
|
||||
|
||||
if (!empty($config['query_string'])) {
|
||||
|
@ -36,8 +36,8 @@ class HttpBasicLdapFactory extends HttpBasicFactory
|
||||
->replaceArgument(2, $id)
|
||||
->replaceArgument(3, new Reference($config['service']))
|
||||
->replaceArgument(4, $config['dn_string'])
|
||||
->replaceArgument(5, $config['search_dn'])
|
||||
->replaceArgument(6, $config['search_password'])
|
||||
->replaceArgument(6, $config['search_dn'])
|
||||
->replaceArgument(7, $config['search_password'])
|
||||
;
|
||||
|
||||
// entry point
|
||||
|
@ -37,8 +37,8 @@ class JsonLoginLdapFactory extends JsonLoginFactory
|
||||
->replaceArgument(2, $id)
|
||||
->replaceArgument(3, new Reference($config['service']))
|
||||
->replaceArgument(4, $config['dn_string'])
|
||||
->replaceArgument(5, $config['search_dn'])
|
||||
->replaceArgument(6, $config['search_password'])
|
||||
->replaceArgument(6, $config['search_dn'])
|
||||
->replaceArgument(7, $config['search_password'])
|
||||
;
|
||||
|
||||
if (!empty($config['query_string'])) {
|
||||
|
@ -69,9 +69,8 @@ class ButtonBuilder implements \IteratorAggregate, FormBuilderInterface
|
||||
*
|
||||
* This method should not be invoked.
|
||||
*
|
||||
* @param string|int|FormBuilderInterface $child
|
||||
* @param string|FormBuilderInterface $child
|
||||
* @param string|FormTypeInterface $type
|
||||
* @param array $options
|
||||
*
|
||||
* @throws BadMethodCallException
|
||||
*/
|
||||
|
@ -843,7 +843,7 @@ class Form implements \IteratorAggregate, FormInterface, ClearableErrorsInterfac
|
||||
|
||||
if (!$child instanceof FormInterface) {
|
||||
if (!\is_string($child) && !\is_int($child)) {
|
||||
throw new UnexpectedTypeException($child, 'string, integer or Symfony\Component\Form\FormInterface');
|
||||
throw new UnexpectedTypeException($child, 'string or Symfony\Component\Form\FormInterface');
|
||||
}
|
||||
|
||||
$child = (string) $child;
|
||||
|
@ -63,7 +63,7 @@ class FormBuilder extends FormConfigBuilder implements \IteratorAggregate, FormB
|
||||
}
|
||||
|
||||
if (!\is_string($child) && !\is_int($child)) {
|
||||
throw new UnexpectedTypeException($child, 'string, integer or Symfony\Component\Form\FormBuilderInterface');
|
||||
throw new UnexpectedTypeException($child, 'string or Symfony\Component\Form\FormBuilderInterface');
|
||||
}
|
||||
|
||||
if (null !== $type && !\is_string($type) && !$type instanceof FormTypeInterface) {
|
||||
|
@ -23,9 +23,8 @@ interface FormBuilderInterface extends \Traversable, \Countable, FormConfigBuild
|
||||
* If you add a nested group, this group should also be represented in the
|
||||
* object hierarchy.
|
||||
*
|
||||
* @param string|int|FormBuilderInterface $child
|
||||
* @param string|FormBuilderInterface $child
|
||||
* @param string|null $type
|
||||
* @param array $options
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
@ -36,7 +35,6 @@ interface FormBuilderInterface extends \Traversable, \Countable, FormConfigBuild
|
||||
*
|
||||
* @param string $name The name of the form or the name of the property
|
||||
* @param string|null $type The type of the form or null if name is a property
|
||||
* @param array $options The options
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
|
@ -108,8 +108,6 @@ class FormConfigBuilder implements FormConfigBuilderInterface
|
||||
*
|
||||
* @param string|null $name The form name
|
||||
* @param string|null $dataClass The class of the form's data
|
||||
* @param EventDispatcherInterface $dispatcher The event dispatcher
|
||||
* @param array $options The form options
|
||||
*
|
||||
* @throws InvalidArgumentException if the data class is not a valid class or if
|
||||
* the name contains invalid characters
|
||||
|
@ -38,10 +38,9 @@ interface FormFactoryInterface
|
||||
*
|
||||
* @see createNamedBuilder()
|
||||
*
|
||||
* @param string|int $name The name of the form
|
||||
* @param string $name The name of the form
|
||||
* @param string $type The type of the form
|
||||
* @param mixed $data The initial data
|
||||
* @param array $options The options
|
||||
*
|
||||
* @return FormInterface The form
|
||||
*
|
||||
@ -81,10 +80,9 @@ interface FormFactoryInterface
|
||||
/**
|
||||
* Returns a form builder.
|
||||
*
|
||||
* @param string|int $name The name of the form
|
||||
* @param string $name The name of the form
|
||||
* @param string $type The type of the form
|
||||
* @param mixed $data The initial data
|
||||
* @param array $options The options
|
||||
*
|
||||
* @return FormBuilderInterface The form builder
|
||||
*
|
||||
|
@ -43,7 +43,7 @@ interface FormInterface extends \ArrayAccess, \Traversable, \Countable
|
||||
/**
|
||||
* Adds or replaces a child to the form.
|
||||
*
|
||||
* @param FormInterface|string|int $child The FormInterface instance or the name of the child
|
||||
* @param FormInterface|string $child The FormInterface instance or the name of the child
|
||||
* @param string|null $type The child's type, if a name was passed
|
||||
* @param array $options The child's options, if a name was passed
|
||||
*
|
||||
|
@ -109,12 +109,14 @@ final class CurlHttpClient implements HttpClientInterface, LoggerAwareInterface
|
||||
if ($pushedResponse = $this->multi->pushedResponses[$url] ?? null) {
|
||||
unset($this->multi->pushedResponses[$url]);
|
||||
// Accept pushed responses only if their headers related to authentication match the request
|
||||
$expectedHeaders = [
|
||||
$options['headers']['authorization'] ?? null,
|
||||
$options['headers']['cookie'] ?? null,
|
||||
$options['headers']['x-requested-with'] ?? null,
|
||||
$options['headers']['range'] ?? null,
|
||||
];
|
||||
$expectedHeaders = ['authorization', 'cookie', 'x-requested-with', 'range'];
|
||||
foreach ($expectedHeaders as $k => $v) {
|
||||
$expectedHeaders[$k] = null;
|
||||
|
||||
foreach ($options['normalized_headers'][$v] ?? [] as $h) {
|
||||
$expectedHeaders[$k][] = substr($h, 2 + \strlen($v));
|
||||
}
|
||||
}
|
||||
|
||||
if ('GET' === $method && $expectedHeaders === $pushedResponse->headers && !$options['body']) {
|
||||
$this->logger && $this->logger->debug(sprintf('Connecting request to pushed response: "%s %s"', $method, $url));
|
||||
@ -226,11 +228,11 @@ final class CurlHttpClient implements HttpClientInterface, LoggerAwareInterface
|
||||
$curlopts[CURLOPT_NOSIGNAL] = true;
|
||||
}
|
||||
|
||||
if (!isset($options['headers']['accept-encoding'])) {
|
||||
if (!isset($options['normalized_headers']['accept-encoding'])) {
|
||||
$curlopts[CURLOPT_ENCODING] = ''; // Enable HTTP compression
|
||||
}
|
||||
|
||||
foreach ($options['request_headers'] as $header) {
|
||||
foreach ($options['headers'] as $header) {
|
||||
if (':' === $header[-2] && \strlen($header) - 2 === strpos($header, ': ')) {
|
||||
// curl requires a special syntax to send empty headers
|
||||
$curlopts[CURLOPT_HTTPHEADER][] = substr_replace($header, ';', -2);
|
||||
@ -241,7 +243,7 @@ final class CurlHttpClient implements HttpClientInterface, LoggerAwareInterface
|
||||
|
||||
// Prevent curl from sending its default Accept and Expect headers
|
||||
foreach (['accept', 'expect'] as $header) {
|
||||
if (!isset($options['headers'][$header])) {
|
||||
if (!isset($options['normalized_headers'][$header])) {
|
||||
$curlopts[CURLOPT_HTTPHEADER][] = $header.':';
|
||||
}
|
||||
}
|
||||
@ -257,9 +259,9 @@ final class CurlHttpClient implements HttpClientInterface, LoggerAwareInterface
|
||||
};
|
||||
}
|
||||
|
||||
if (isset($options['headers']['content-length'][0])) {
|
||||
$curlopts[CURLOPT_INFILESIZE] = $options['headers']['content-length'][0];
|
||||
} elseif (!isset($options['headers']['transfer-encoding'])) {
|
||||
if (isset($options['normalized_headers']['content-length'][0])) {
|
||||
$curlopts[CURLOPT_INFILESIZE] = substr($options['normalized_headers']['content-length'][0], \strlen('Content-Length: '));
|
||||
} elseif (!isset($options['normalized_headers']['transfer-encoding'])) {
|
||||
$curlopts[CURLOPT_HTTPHEADER][] = 'Transfer-Encoding: chunked'; // Enable chunked request bodies
|
||||
}
|
||||
|
||||
@ -407,12 +409,12 @@ final class CurlHttpClient implements HttpClientInterface, LoggerAwareInterface
|
||||
$redirectHeaders = [];
|
||||
if (0 < $options['max_redirects']) {
|
||||
$redirectHeaders['host'] = $host;
|
||||
$redirectHeaders['with_auth'] = $redirectHeaders['no_auth'] = array_filter($options['request_headers'], static function ($h) {
|
||||
$redirectHeaders['with_auth'] = $redirectHeaders['no_auth'] = array_filter($options['headers'], static function ($h) {
|
||||
return 0 !== stripos($h, 'Host:');
|
||||
});
|
||||
|
||||
if (isset($options['headers']['authorization']) || isset($options['headers']['cookie'])) {
|
||||
$redirectHeaders['no_auth'] = array_filter($options['request_headers'], static function ($h) {
|
||||
if (isset($options['normalized_headers']['authorization']) || isset($options['normalized_headers']['cookie'])) {
|
||||
$redirectHeaders['no_auth'] = array_filter($options['headers'], static function ($h) {
|
||||
return 0 !== stripos($h, 'Authorization:') && 0 !== stripos($h, 'Cookie:');
|
||||
});
|
||||
}
|
||||
|
@ -48,7 +48,10 @@ trait HttpClientTrait
|
||||
}
|
||||
$options['body'] = self::jsonEncode($options['json']);
|
||||
unset($options['json']);
|
||||
$options['headers']['content-type'] = $options['headers']['content-type'] ?? ['application/json'];
|
||||
|
||||
if (!isset($options['normalized_headers']['content-type'])) {
|
||||
$options['normalized_headers']['content-type'] = [$options['headers'][] = 'Content-Type: application/json'];
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($options['body'])) {
|
||||
@ -59,19 +62,6 @@ trait HttpClientTrait
|
||||
$options['peer_fingerprint'] = self::normalizePeerFingerprint($options['peer_fingerprint']);
|
||||
}
|
||||
|
||||
// Compute request headers
|
||||
$requestHeaders = $headers = [];
|
||||
|
||||
foreach ($options['headers'] as $name => $values) {
|
||||
foreach ($values as $value) {
|
||||
$requestHeaders[] = $name.': '.$headers[$name][] = $value = (string) $value;
|
||||
|
||||
if (\strlen($value) !== strcspn($value, "\r\n\0")) {
|
||||
throw new InvalidArgumentException(sprintf('Invalid header value: CR/LF/NUL found in "%s".', $value));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Validate on_progress
|
||||
if (!\is_callable($onProgress = $options['on_progress'] ?? 'var_dump')) {
|
||||
throw new InvalidArgumentException(sprintf('Option "on_progress" must be callable, %s given.', \is_object($onProgress) ? \get_class($onProgress) : \gettype($onProgress)));
|
||||
@ -100,15 +90,14 @@ trait HttpClientTrait
|
||||
|
||||
if (null !== $url) {
|
||||
// Merge auth with headers
|
||||
if (($options['auth_basic'] ?? false) && !($headers['authorization'] ?? false)) {
|
||||
$requestHeaders[] = 'authorization: '.$headers['authorization'][] = 'Basic '.base64_encode($options['auth_basic']);
|
||||
if (($options['auth_basic'] ?? false) && !($options['normalized_headers']['authorization'] ?? false)) {
|
||||
$options['normalized_headers']['authorization'] = [$options['headers'][] = 'Authorization: Basic '.base64_encode($options['auth_basic'])];
|
||||
}
|
||||
// Merge bearer with headers
|
||||
if (($options['auth_bearer'] ?? false) && !($headers['authorization'] ?? false)) {
|
||||
$requestHeaders[] = 'authorization: '.$headers['authorization'][] = 'Bearer '.$options['auth_bearer'];
|
||||
if (($options['auth_bearer'] ?? false) && !($options['normalized_headers']['authorization'] ?? false)) {
|
||||
$options['normalized_headers']['authorization'] = [$options['headers'][] = 'Authorization: Bearer '.$options['auth_bearer']];
|
||||
}
|
||||
|
||||
$options['request_headers'] = $requestHeaders;
|
||||
unset($options['auth_basic'], $options['auth_bearer']);
|
||||
|
||||
// Parse base URI
|
||||
@ -122,7 +111,6 @@ trait HttpClientTrait
|
||||
}
|
||||
|
||||
// Finalize normalization of options
|
||||
$options['headers'] = $headers;
|
||||
$options['http_version'] = (string) ($options['http_version'] ?? '') ?: null;
|
||||
$options['timeout'] = (float) ($options['timeout'] ?? ini_get('default_socket_timeout'));
|
||||
|
||||
@ -134,31 +122,38 @@ trait HttpClientTrait
|
||||
*/
|
||||
private static function mergeDefaultOptions(array $options, array $defaultOptions, bool $allowExtraOptions = false): array
|
||||
{
|
||||
unset($options['request_headers'], $defaultOptions['request_headers']);
|
||||
|
||||
$options['headers'] = self::normalizeHeaders($options['headers'] ?? []);
|
||||
$options['normalized_headers'] = self::normalizeHeaders($options['headers'] ?? []);
|
||||
|
||||
if ($defaultOptions['headers'] ?? false) {
|
||||
$options['headers'] += self::normalizeHeaders($defaultOptions['headers']);
|
||||
$options['normalized_headers'] += self::normalizeHeaders($defaultOptions['headers']);
|
||||
}
|
||||
|
||||
if ($options['resolve'] ?? false) {
|
||||
$options['resolve'] = array_change_key_case($options['resolve']);
|
||||
$options['headers'] = array_merge(...array_values($options['normalized_headers']) ?: [[]]);
|
||||
|
||||
if ($resolve = $options['resolve'] ?? false) {
|
||||
$options['resolve'] = [];
|
||||
foreach ($resolve as $k => $v) {
|
||||
$options['resolve'][substr(self::parseUrl('http://'.$k)['authority'], 2)] = (string) $v;
|
||||
}
|
||||
}
|
||||
|
||||
// Option "query" is never inherited from defaults
|
||||
$options['query'] = $options['query'] ?? [];
|
||||
|
||||
foreach ($defaultOptions as $k => $v) {
|
||||
$options[$k] = $options[$k] ?? $v;
|
||||
if ('normalized_headers' !== $k && !isset($options[$k])) {
|
||||
$options[$k] = $v;
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($defaultOptions['extra'])) {
|
||||
$options['extra'] += $defaultOptions['extra'];
|
||||
}
|
||||
|
||||
if ($defaultOptions['resolve'] ?? false) {
|
||||
$options['resolve'] += array_change_key_case($defaultOptions['resolve']);
|
||||
if ($resolve = $defaultOptions['resolve'] ?? false) {
|
||||
foreach ($resolve as $k => $v) {
|
||||
$options['resolve'] += [substr(self::parseUrl('http://'.$k)['authority'], 2) => (string) $v];
|
||||
}
|
||||
}
|
||||
|
||||
if ($allowExtraOptions || !$defaultOptions) {
|
||||
@ -167,7 +162,7 @@ trait HttpClientTrait
|
||||
|
||||
// Look for unsupported options
|
||||
foreach ($options as $name => $v) {
|
||||
if (\array_key_exists($name, $defaultOptions)) {
|
||||
if (\array_key_exists($name, $defaultOptions) || 'normalized_headers' === $name) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -190,9 +185,9 @@ trait HttpClientTrait
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalizes headers by putting their names as lowercased keys.
|
||||
*
|
||||
* @return string[][]
|
||||
*
|
||||
* @throws InvalidArgumentException When an invalid header is found
|
||||
*/
|
||||
private static function normalizeHeaders(array $headers): array
|
||||
{
|
||||
@ -206,10 +201,15 @@ trait HttpClientTrait
|
||||
$values = (array) $values;
|
||||
}
|
||||
|
||||
$normalizedHeaders[$name = strtolower($name)] = [];
|
||||
$lcName = strtolower($name);
|
||||
$normalizedHeaders[$lcName] = [];
|
||||
|
||||
foreach ($values as $value) {
|
||||
$normalizedHeaders[$name][] = $value;
|
||||
$normalizedHeaders[$lcName][] = $value = $name.': '.$value;
|
||||
|
||||
if (\strlen($value) !== strcspn($value, "\r\n\0")) {
|
||||
throw new InvalidArgumentException(sprintf('Invalid header: CR/LF/NUL found in "%s".', $value));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -71,13 +71,13 @@ final class NativeHttpClient implements HttpClientInterface, LoggerAwareInterfac
|
||||
|
||||
$options['body'] = self::getBodyAsString($options['body']);
|
||||
|
||||
if ('' !== $options['body'] && 'POST' === $method && !isset($options['headers']['content-type'])) {
|
||||
$options['request_headers'][] = 'content-type: application/x-www-form-urlencoded';
|
||||
if ('' !== $options['body'] && 'POST' === $method && !isset($options['normalized_headers']['content-type'])) {
|
||||
$options['headers'][] = 'Content-Type: application/x-www-form-urlencoded';
|
||||
}
|
||||
|
||||
if ($gzipEnabled = \extension_loaded('zlib') && !isset($options['headers']['accept-encoding'])) {
|
||||
if ($gzipEnabled = \extension_loaded('zlib') && !isset($options['normalized_headers']['accept-encoding'])) {
|
||||
// gzip is the most widely available algo, no need to deal with deflate
|
||||
$options['request_headers'][] = 'accept-encoding: gzip';
|
||||
$options['headers'][] = 'Accept-Encoding: gzip';
|
||||
}
|
||||
|
||||
if ($options['peer_fingerprint']) {
|
||||
@ -158,12 +158,12 @@ final class NativeHttpClient implements HttpClientInterface, LoggerAwareInterfac
|
||||
|
||||
[$host, $port, $url['authority']] = self::dnsResolve($url, $this->multi, $info, $onProgress);
|
||||
|
||||
if (!isset($options['headers']['host'])) {
|
||||
$options['request_headers'][] = 'host: '.$host.$port;
|
||||
if (!isset($options['normalized_headers']['host'])) {
|
||||
$options['headers'][] = 'Host: '.$host.$port;
|
||||
}
|
||||
|
||||
if (!isset($options['headers']['user-agent'])) {
|
||||
$options['request_headers'][] = 'user-agent: Symfony HttpClient/Native';
|
||||
if (!isset($options['normalized_headers']['user-agent'])) {
|
||||
$options['headers'][] = 'User-Agent: Symfony HttpClient/Native';
|
||||
}
|
||||
|
||||
$context = [
|
||||
@ -206,7 +206,7 @@ final class NativeHttpClient implements HttpClientInterface, LoggerAwareInterfac
|
||||
|
||||
$resolveRedirect = self::createRedirectResolver($options, $host, $proxy, $noProxy, $info, $onProgress);
|
||||
$context = stream_context_create($context, ['notification' => $notification]);
|
||||
self::configureHeadersAndProxy($context, $host, $options['request_headers'], $proxy, $noProxy);
|
||||
self::configureHeadersAndProxy($context, $host, $options['headers'], $proxy, $noProxy);
|
||||
|
||||
return new NativeResponse($this->multi, $context, implode('', $url), $options, $gzipEnabled, $info, $resolveRedirect, $onProgress, $this->logger);
|
||||
}
|
||||
@ -333,12 +333,12 @@ final class NativeHttpClient implements HttpClientInterface, LoggerAwareInterfac
|
||||
$redirectHeaders = [];
|
||||
if (0 < $maxRedirects = $options['max_redirects']) {
|
||||
$redirectHeaders = ['host' => $host];
|
||||
$redirectHeaders['with_auth'] = $redirectHeaders['no_auth'] = array_filter($options['request_headers'], static function ($h) {
|
||||
$redirectHeaders['with_auth'] = $redirectHeaders['no_auth'] = array_filter($options['headers'], static function ($h) {
|
||||
return 0 !== stripos($h, 'Host:');
|
||||
});
|
||||
|
||||
if (isset($options['headers']['authorization']) || isset($options['headers']['cookie'])) {
|
||||
$redirectHeaders['no_auth'] = array_filter($options['request_headers'], static function ($h) {
|
||||
if (isset($options['normalized_headers']['authorization']) || isset($options['normalized_headers']['cookie'])) {
|
||||
$redirectHeaders['no_auth'] = array_filter($options['headers'], static function ($h) {
|
||||
return 0 !== stripos($h, 'Authorization:') && 0 !== stripos($h, 'Cookie:');
|
||||
});
|
||||
}
|
||||
@ -391,7 +391,7 @@ final class NativeHttpClient implements HttpClientInterface, LoggerAwareInterfac
|
||||
if (false !== (parse_url($location, PHP_URL_HOST) ?? false)) {
|
||||
// Authorization and Cookie headers MUST NOT follow except for the initial host name
|
||||
$requestHeaders = $redirectHeaders['host'] === $host ? $redirectHeaders['with_auth'] : $redirectHeaders['no_auth'];
|
||||
$requestHeaders[] = 'host: '.$host.$port;
|
||||
$requestHeaders[] = 'Host: '.$host.$port;
|
||||
self::configureHeadersAndProxy($context, $host, $requestHeaders, $proxy, $noProxy);
|
||||
}
|
||||
|
||||
|
@ -241,6 +241,7 @@ final class NativeResponse implements ResponseInterface
|
||||
try {
|
||||
// Notify the progress callback so that it can e.g. cancel
|
||||
// the request if the stream is inactive for too long
|
||||
$info['total_time'] = microtime(true) - $info['start_time'];
|
||||
$onProgress();
|
||||
} catch (\Throwable $e) {
|
||||
// no-op
|
||||
|
@ -172,8 +172,8 @@ class HttpClientTraitTest extends TestCase
|
||||
public function testAuthBearerOption()
|
||||
{
|
||||
[, $options] = self::prepareRequest('POST', 'http://example.com', ['auth_bearer' => 'foobar'], HttpClientInterface::OPTIONS_DEFAULTS);
|
||||
$this->assertSame('Bearer foobar', $options['headers']['authorization'][0]);
|
||||
$this->assertSame('authorization: Bearer foobar', $options['request_headers'][0]);
|
||||
$this->assertSame(['Authorization: Bearer foobar'], $options['headers']);
|
||||
$this->assertSame(['Authorization: Bearer foobar'], $options['normalized_headers']['authorization']);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -226,7 +226,7 @@ class HttpClientTraitTest extends TestCase
|
||||
public function testPrepareAuthBasic($arg, $result)
|
||||
{
|
||||
[, $options] = $this->prepareRequest('POST', 'http://example.com', ['auth_basic' => $arg], HttpClientInterface::OPTIONS_DEFAULTS);
|
||||
$this->assertSame('Basic '.$result, $options['headers']['authorization'][0]);
|
||||
$this->assertSame('Authorization: Basic '.$result, $options['normalized_headers']['authorization'][0]);
|
||||
}
|
||||
|
||||
public function provideFingerprints()
|
||||
|
@ -44,9 +44,9 @@ class ScopingHttpClientTest extends TestCase
|
||||
$client = new ScopingHttpClient($mockClient, $options);
|
||||
|
||||
$response = $client->request('GET', $url);
|
||||
$reuestedOptions = $response->getRequestOptions();
|
||||
$requestedOptions = $response->getRequestOptions();
|
||||
|
||||
$this->assertEquals($reuestedOptions['case'], $options[$regexp]['case']);
|
||||
$this->assertSame($options[$regexp]['case'], $requestedOptions['case']);
|
||||
}
|
||||
|
||||
public function provideMatchingUrls()
|
||||
@ -64,8 +64,8 @@ class ScopingHttpClientTest extends TestCase
|
||||
public function testMatchingUrlsAndOptions()
|
||||
{
|
||||
$defaultOptions = [
|
||||
'.*/foo-bar' => ['headers' => ['x-app' => 'unit-test-foo-bar']],
|
||||
'.*' => ['headers' => ['content-type' => 'text/html']],
|
||||
'.*/foo-bar' => ['headers' => ['X-FooBar' => 'unit-test-foo-bar']],
|
||||
'.*' => ['headers' => ['Content-Type' => 'text/html']],
|
||||
];
|
||||
|
||||
$mockClient = new MockHttpClient();
|
||||
@ -73,20 +73,20 @@ class ScopingHttpClientTest extends TestCase
|
||||
|
||||
$response = $client->request('GET', 'http://example.com/foo-bar', ['json' => ['url' => 'http://example.com']]);
|
||||
$requestOptions = $response->getRequestOptions();
|
||||
$this->assertEquals($requestOptions['headers']['content-type'][0], 'application/json');
|
||||
$this->assertSame('Content-Type: application/json', $requestOptions['headers'][1]);
|
||||
$requestJson = json_decode($requestOptions['body'], true);
|
||||
$this->assertEquals($requestJson['url'], 'http://example.com');
|
||||
$this->assertEquals($requestOptions['headers']['x-app'][0], $defaultOptions['.*/foo-bar']['headers']['x-app']);
|
||||
$this->assertSame('http://example.com', $requestJson['url']);
|
||||
$this->assertSame('X-FooBar: '.$defaultOptions['.*/foo-bar']['headers']['X-FooBar'], $requestOptions['headers'][0]);
|
||||
|
||||
$response = $client->request('GET', 'http://example.com/bar-foo', ['headers' => ['x-app' => 'unit-test']]);
|
||||
$response = $client->request('GET', 'http://example.com/bar-foo', ['headers' => ['X-FooBar' => 'unit-test']]);
|
||||
$requestOptions = $response->getRequestOptions();
|
||||
$this->assertEquals($requestOptions['headers']['x-app'][0], 'unit-test');
|
||||
$this->assertEquals($requestOptions['headers']['content-type'][0], 'text/html');
|
||||
$this->assertSame('X-FooBar: unit-test', $requestOptions['headers'][0]);
|
||||
$this->assertSame('Content-Type: text/html', $requestOptions['headers'][1]);
|
||||
|
||||
$response = $client->request('GET', 'http://example.com/foobar-foo', ['headers' => ['x-app' => 'unit-test']]);
|
||||
$response = $client->request('GET', 'http://example.com/foobar-foo', ['headers' => ['X-FooBar' => 'unit-test']]);
|
||||
$requestOptions = $response->getRequestOptions();
|
||||
$this->assertEquals($requestOptions['headers']['x-app'][0], 'unit-test');
|
||||
$this->assertEquals($requestOptions['headers']['content-type'][0], 'text/html');
|
||||
$this->assertSame('X-FooBar: unit-test', $requestOptions['headers'][0]);
|
||||
$this->assertSame('Content-Type: text/html', $requestOptions['headers'][1]);
|
||||
}
|
||||
|
||||
public function testForBaseUri()
|
||||
|
@ -50,10 +50,10 @@ class UserPasswordEncoder implements UserPasswordEncoderInterface
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function needsRehash(UserInterface $user, string $encoded): bool
|
||||
public function needsRehash(UserInterface $user): bool
|
||||
{
|
||||
$encoder = $this->encoderFactory->getEncoder($user);
|
||||
|
||||
return $encoder->needsRehash($encoded);
|
||||
return $encoder->needsRehash($user->getPassword());
|
||||
}
|
||||
}
|
||||
|
@ -35,5 +35,5 @@ interface UserPasswordEncoderInterface
|
||||
/**
|
||||
* Checks if an encoded password would benefit from rehashing.
|
||||
*/
|
||||
public function needsRehash(UserInterface $user, string $encoded): bool;
|
||||
public function needsRehash(UserInterface $user): bool;
|
||||
}
|
||||
|
@ -85,9 +85,9 @@ class UserPasswordEncoderTest extends TestCase
|
||||
|
||||
$passwordEncoder = new UserPasswordEncoder($mockEncoderFactory);
|
||||
|
||||
$hash = $passwordEncoder->encodePassword($user, 'foo', 'salt');
|
||||
$this->assertFalse($passwordEncoder->needsRehash($user, $hash));
|
||||
$this->assertTrue($passwordEncoder->needsRehash($user, $hash));
|
||||
$this->assertFalse($passwordEncoder->needsRehash($user, $hash));
|
||||
$user->setPassword($passwordEncoder->encodePassword($user, 'foo', 'salt'));
|
||||
$this->assertFalse($passwordEncoder->needsRehash($user));
|
||||
$this->assertTrue($passwordEncoder->needsRehash($user));
|
||||
$this->assertFalse($passwordEncoder->needsRehash($user));
|
||||
}
|
||||
}
|
||||
|
@ -165,4 +165,9 @@ final class User implements UserInterface, EquatableInterface
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function setPassword(string $password)
|
||||
{
|
||||
$this->password = $password;
|
||||
}
|
||||
}
|
||||
|
@ -40,8 +40,8 @@ interface HttpClientInterface
|
||||
// value if they are not defined - typically "application/json"
|
||||
'user_data' => null, // mixed - any extra data to attach to the request (scalar, callable, object...) that
|
||||
// MUST be available via $response->getInfo('user_data') - not used internally
|
||||
'max_redirects' => 20, // int - the maximum number of redirects to follow; a value lower or equal to 0 means
|
||||
// redirects should not be followed; "Authorization" and "Cookie" headers MUST
|
||||
'max_redirects' => 20, // int - the maximum number of redirects to follow; a value lower than or equal to 0
|
||||
// means redirects should not be followed; "Authorization" and "Cookie" headers MUST
|
||||
// NOT follow except for the initial host name
|
||||
'http_version' => null, // string - defaults to the best supported version, typically 1.1 or 2.0
|
||||
'base_uri' => null, // string - the URI to resolve relative URLs, following rules in RFC 3986, section 2
|
||||
|
Reference in New Issue
Block a user