Merge branch '4.4' into 5.1
* 4.4: [HttpClient] fix using proxies with NativeHttpClient [4.4] Ignore more deprecations for Mockery mocks [Routing] fix using !important and defaults/reqs in inline route definitions [ErrorHandler][DebugClassLoader] Do not check Mockery mocks classes [HttpClient] Fix using https with proxies [TwigBundle] Only remove kernel exception listener if twig is used Adjust expired range check Fix redis connection error message
This commit is contained in:
commit
d8255138ae
@ -306,7 +306,7 @@ class Cookie
|
|||||||
*/
|
*/
|
||||||
public function isExpired()
|
public function isExpired()
|
||||||
{
|
{
|
||||||
return null !== $this->expires && 0 != $this->expires && $this->expires < time();
|
return null !== $this->expires && 0 != $this->expires && $this->expires <= time();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -13,6 +13,7 @@ namespace Symfony\Component\ErrorHandler;
|
|||||||
|
|
||||||
use Doctrine\Common\Persistence\Proxy as LegacyProxy;
|
use Doctrine\Common\Persistence\Proxy as LegacyProxy;
|
||||||
use Doctrine\Persistence\Proxy;
|
use Doctrine\Persistence\Proxy;
|
||||||
|
use Mockery\MockInterface;
|
||||||
use PHPUnit\Framework\MockObject\Matcher\StatelessInvocation;
|
use PHPUnit\Framework\MockObject\Matcher\StatelessInvocation;
|
||||||
use PHPUnit\Framework\MockObject\MockObject;
|
use PHPUnit\Framework\MockObject\MockObject;
|
||||||
use Prophecy\Prophecy\ProphecySubjectInterface;
|
use Prophecy\Prophecy\ProphecySubjectInterface;
|
||||||
@ -306,6 +307,7 @@ class DebugClassLoader
|
|||||||
&& !is_subclass_of($symbols[$i], Proxy::class)
|
&& !is_subclass_of($symbols[$i], Proxy::class)
|
||||||
&& !is_subclass_of($symbols[$i], ProxyInterface::class)
|
&& !is_subclass_of($symbols[$i], ProxyInterface::class)
|
||||||
&& !is_subclass_of($symbols[$i], LegacyProxy::class)
|
&& !is_subclass_of($symbols[$i], LegacyProxy::class)
|
||||||
|
&& !is_subclass_of($symbols[$i], MockInterface::class)
|
||||||
) {
|
) {
|
||||||
$loader->checkClass($symbols[$i]);
|
$loader->checkClass($symbols[$i]);
|
||||||
}
|
}
|
||||||
|
@ -171,7 +171,7 @@ final class NativeHttpClient implements HttpClientInterface, LoggerAwareInterfac
|
|||||||
|
|
||||||
$this->logger && $this->logger->info(sprintf('Request: "%s %s"', $method, implode('', $url)));
|
$this->logger && $this->logger->info(sprintf('Request: "%s %s"', $method, implode('', $url)));
|
||||||
|
|
||||||
[$host, $port, $url['authority']] = self::dnsResolve($url, $this->multi, $info, $onProgress);
|
[$host, $port] = self::parseHostPort($url, $info);
|
||||||
|
|
||||||
if (!isset($options['normalized_headers']['host'])) {
|
if (!isset($options['normalized_headers']['host'])) {
|
||||||
$options['headers'][] = 'Host: '.$host.$port;
|
$options['headers'][] = 'Host: '.$host.$port;
|
||||||
@ -198,7 +198,6 @@ final class NativeHttpClient implements HttpClientInterface, LoggerAwareInterfac
|
|||||||
'follow_location' => false, // We follow redirects ourselves - the native logic is too limited
|
'follow_location' => false, // We follow redirects ourselves - the native logic is too limited
|
||||||
],
|
],
|
||||||
'ssl' => array_filter([
|
'ssl' => array_filter([
|
||||||
'peer_name' => $host,
|
|
||||||
'verify_peer' => $options['verify_peer'],
|
'verify_peer' => $options['verify_peer'],
|
||||||
'verify_peer_name' => $options['verify_host'],
|
'verify_peer_name' => $options['verify_host'],
|
||||||
'cafile' => $options['cafile'],
|
'cafile' => $options['cafile'],
|
||||||
@ -222,7 +221,11 @@ final class NativeHttpClient implements HttpClientInterface, LoggerAwareInterfac
|
|||||||
$proxy = self::getProxy($options['proxy'], $url, $options['no_proxy']);
|
$proxy = self::getProxy($options['proxy'], $url, $options['no_proxy']);
|
||||||
$resolveRedirect = self::createRedirectResolver($options, $host, $proxy, $info, $onProgress);
|
$resolveRedirect = self::createRedirectResolver($options, $host, $proxy, $info, $onProgress);
|
||||||
$context = stream_context_create($context, ['notification' => $notification]);
|
$context = stream_context_create($context, ['notification' => $notification]);
|
||||||
self::configureHeadersAndProxy($context, $host, $options['headers'], $proxy);
|
|
||||||
|
if (!self::configureHeadersAndProxy($context, $host, $options['headers'], $proxy, 'https:' === $url['scheme'])) {
|
||||||
|
$ip = self::dnsResolve($host, $this->multi, $info, $onProgress);
|
||||||
|
$url['authority'] = substr_replace($url['authority'], $ip, -\strlen($host) - \strlen($port), \strlen($host));
|
||||||
|
}
|
||||||
|
|
||||||
return new NativeResponse($this->multi, $context, implode('', $url), $options, $info, $resolveRedirect, $onProgress, $this->logger);
|
return new NativeResponse($this->multi, $context, implode('', $url), $options, $info, $resolveRedirect, $onProgress, $this->logger);
|
||||||
}
|
}
|
||||||
@ -265,9 +268,9 @@ final class NativeHttpClient implements HttpClientInterface, LoggerAwareInterfac
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resolves the IP of the host using the local DNS cache if possible.
|
* Extracts the host and the port from the URL.
|
||||||
*/
|
*/
|
||||||
private static function dnsResolve(array $url, NativeClientState $multi, array &$info, ?\Closure $onProgress): array
|
private static function parseHostPort(array $url, array &$info): array
|
||||||
{
|
{
|
||||||
if ($port = parse_url($url['authority'], \PHP_URL_PORT) ?: '') {
|
if ($port = parse_url($url['authority'], \PHP_URL_PORT) ?: '') {
|
||||||
$info['primary_port'] = $port;
|
$info['primary_port'] = $port;
|
||||||
@ -276,8 +279,14 @@ final class NativeHttpClient implements HttpClientInterface, LoggerAwareInterfac
|
|||||||
$info['primary_port'] = 'http:' === $url['scheme'] ? 80 : 443;
|
$info['primary_port'] = 'http:' === $url['scheme'] ? 80 : 443;
|
||||||
}
|
}
|
||||||
|
|
||||||
$host = parse_url($url['authority'], \PHP_URL_HOST);
|
return [parse_url($url['authority'], \PHP_URL_HOST), $port];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolves the IP of the host using the local DNS cache if possible.
|
||||||
|
*/
|
||||||
|
private static function dnsResolve($host, NativeClientState $multi, array &$info, ?\Closure $onProgress): string
|
||||||
|
{
|
||||||
if (null === $ip = $multi->dnsCache[$host] ?? null) {
|
if (null === $ip = $multi->dnsCache[$host] ?? null) {
|
||||||
$info['debug'] .= "* Hostname was NOT found in DNS cache\n";
|
$info['debug'] .= "* Hostname was NOT found in DNS cache\n";
|
||||||
$now = microtime(true);
|
$now = microtime(true);
|
||||||
@ -300,7 +309,7 @@ final class NativeHttpClient implements HttpClientInterface, LoggerAwareInterfac
|
|||||||
$onProgress();
|
$onProgress();
|
||||||
}
|
}
|
||||||
|
|
||||||
return [$host, $port, substr_replace($url['authority'], $ip, -\strlen($host) - \strlen($port), \strlen($host))];
|
return $ip;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -363,24 +372,33 @@ final class NativeHttpClient implements HttpClientInterface, LoggerAwareInterfac
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[$host, $port, $url['authority']] = self::dnsResolve($url, $multi, $info, $onProgress);
|
[$host, $port] = self::parseHostPort($url, $info);
|
||||||
stream_context_set_option($context, 'ssl', 'peer_name', $host);
|
|
||||||
|
|
||||||
if (false !== (parse_url($location, \PHP_URL_HOST) ?? false)) {
|
if (false !== (parse_url($location, \PHP_URL_HOST) ?? false)) {
|
||||||
// Authorization and Cookie headers MUST NOT follow except for the initial host name
|
// Authorization and Cookie headers MUST NOT follow except for the initial host name
|
||||||
$requestHeaders = $redirectHeaders['host'] === $host ? $redirectHeaders['with_auth'] : $redirectHeaders['no_auth'];
|
$requestHeaders = $redirectHeaders['host'] === $host ? $redirectHeaders['with_auth'] : $redirectHeaders['no_auth'];
|
||||||
$requestHeaders[] = 'Host: '.$host.$port;
|
$requestHeaders[] = 'Host: '.$host.$port;
|
||||||
self::configureHeadersAndProxy($context, $host, $requestHeaders, $proxy);
|
$dnsResolve = !self::configureHeadersAndProxy($context, $host, $requestHeaders, $proxy, 'https:' === $url['scheme']);
|
||||||
|
} else {
|
||||||
|
$dnsResolve = isset(stream_context_get_options($context)['ssl']['peer_name']);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($dnsResolve) {
|
||||||
|
$ip = self::dnsResolve($host, $multi, $info, $onProgress);
|
||||||
|
$url['authority'] = substr_replace($url['authority'], $ip, -\strlen($host) - \strlen($port), \strlen($host));
|
||||||
}
|
}
|
||||||
|
|
||||||
return implode('', $url);
|
return implode('', $url);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function configureHeadersAndProxy($context, string $host, array $requestHeaders, ?array $proxy): bool
|
private static function configureHeadersAndProxy($context, string $host, array $requestHeaders, ?array $proxy, bool $isSsl): bool
|
||||||
{
|
{
|
||||||
if (null === $proxy) {
|
if (null === $proxy) {
|
||||||
return stream_context_set_option($context, 'http', 'header', $requestHeaders);
|
stream_context_set_option($context, 'http', 'header', $requestHeaders);
|
||||||
|
stream_context_set_option($context, 'ssl', 'peer_name', $host);
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Matching "no_proxy" should follow the behavior of curl
|
// Matching "no_proxy" should follow the behavior of curl
|
||||||
@ -389,17 +407,24 @@ final class NativeHttpClient implements HttpClientInterface, LoggerAwareInterfac
|
|||||||
$dotRule = '.'.ltrim($rule, '.');
|
$dotRule = '.'.ltrim($rule, '.');
|
||||||
|
|
||||||
if ('*' === $rule || $host === $rule || substr($host, -\strlen($dotRule)) === $dotRule) {
|
if ('*' === $rule || $host === $rule || substr($host, -\strlen($dotRule)) === $dotRule) {
|
||||||
return stream_context_set_option($context, 'http', 'header', $requestHeaders);
|
stream_context_set_option($context, 'http', 'proxy', null);
|
||||||
|
stream_context_set_option($context, 'http', 'request_fulluri', false);
|
||||||
|
stream_context_set_option($context, 'http', 'header', $requestHeaders);
|
||||||
|
stream_context_set_option($context, 'ssl', 'peer_name', $host);
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
stream_context_set_option($context, 'http', 'proxy', $proxy['url']);
|
|
||||||
stream_context_set_option($context, 'http', 'request_fulluri', true);
|
|
||||||
|
|
||||||
if (null !== $proxy['auth']) {
|
if (null !== $proxy['auth']) {
|
||||||
$requestHeaders[] = 'Proxy-Authorization: '.$proxy['auth'];
|
$requestHeaders[] = 'Proxy-Authorization: '.$proxy['auth'];
|
||||||
}
|
}
|
||||||
|
|
||||||
return stream_context_set_option($context, 'http', 'header', $requestHeaders);
|
stream_context_set_option($context, 'http', 'proxy', $proxy['url']);
|
||||||
|
stream_context_set_option($context, 'http', 'request_fulluri', !$isSsl);
|
||||||
|
stream_context_set_option($context, 'http', 'header', $requestHeaders);
|
||||||
|
stream_context_set_option($context, 'ssl', 'peer_name', null);
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -69,11 +69,11 @@ class Connection
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (null !== $auth && !$this->connection->auth($auth)) {
|
if (null !== $auth && !$this->connection->auth($auth)) {
|
||||||
throw new InvalidArgumentException('Redis connection failed: '.$redis->getLastError());
|
throw new InvalidArgumentException('Redis connection failed: '.$this->connection->getLastError());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (($dbIndex = $configuration['dbindex'] ?? self::DEFAULT_OPTIONS['dbindex']) && !$this->connection->select($dbIndex)) {
|
if (($dbIndex = $configuration['dbindex'] ?? self::DEFAULT_OPTIONS['dbindex']) && !$this->connection->select($dbIndex)) {
|
||||||
throw new InvalidArgumentException('Redis connection failed: '.$redis->getLastError());
|
throw new InvalidArgumentException('Redis connection failed: '.$this->connection->getLastError());
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (['stream', 'group', 'consumer'] as $key) {
|
foreach (['stream', 'group', 'consumer'] as $key) {
|
||||||
|
@ -131,7 +131,7 @@ class Route implements \Serializable
|
|||||||
public function setPath(string $pattern)
|
public function setPath(string $pattern)
|
||||||
{
|
{
|
||||||
if (false !== strpbrk($pattern, '?<')) {
|
if (false !== strpbrk($pattern, '?<')) {
|
||||||
$pattern = preg_replace_callback('#\{(\w++)(<.*?>)?(\?[^\}]*+)?\}#', function ($m) {
|
$pattern = preg_replace_callback('#\{(!?\w++)(<.*?>)?(\?[^\}]*+)?\}#', function ($m) {
|
||||||
if (isset($m[3][0])) {
|
if (isset($m[3][0])) {
|
||||||
$this->setDefault($m[1], '?' !== $m[3] ? substr($m[3], 1) : null);
|
$this->setDefault($m[1], '?' !== $m[3] ? substr($m[3], 1) : null);
|
||||||
}
|
}
|
||||||
|
@ -207,6 +207,7 @@ class RouteTest extends TestCase
|
|||||||
$this->assertEquals((new Route('/foo/{bar}'))->setDefault('bar', null), new Route('/foo/{bar?}'));
|
$this->assertEquals((new Route('/foo/{bar}'))->setDefault('bar', null), new Route('/foo/{bar?}'));
|
||||||
$this->assertEquals((new Route('/foo/{bar}'))->setDefault('bar', 'baz'), new Route('/foo/{bar?baz}'));
|
$this->assertEquals((new Route('/foo/{bar}'))->setDefault('bar', 'baz'), new Route('/foo/{bar?baz}'));
|
||||||
$this->assertEquals((new Route('/foo/{bar}'))->setDefault('bar', 'baz<buz>'), new Route('/foo/{bar?baz<buz>}'));
|
$this->assertEquals((new Route('/foo/{bar}'))->setDefault('bar', 'baz<buz>'), new Route('/foo/{bar?baz<buz>}'));
|
||||||
|
$this->assertEquals((new Route('/foo/{!bar}'))->setDefault('!bar', 'baz<buz>'), new Route('/foo/{!bar?baz<buz>}'));
|
||||||
$this->assertEquals((new Route('/foo/{bar}'))->setDefault('bar', 'baz'), new Route('/foo/{bar?}', ['bar' => 'baz']));
|
$this->assertEquals((new Route('/foo/{bar}'))->setDefault('bar', 'baz'), new Route('/foo/{bar?}', ['bar' => 'baz']));
|
||||||
|
|
||||||
$this->assertEquals((new Route('/foo/{bar}'))->setRequirement('bar', '.*'), new Route('/foo/{bar<.*>}'));
|
$this->assertEquals((new Route('/foo/{bar}'))->setRequirement('bar', '.*'), new Route('/foo/{bar<.*>}'));
|
||||||
|
Reference in New Issue
Block a user