diff --git a/appveyor.yml b/appveyor.yml index 6cee17f6fe..cc1de26c5f 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -27,6 +27,7 @@ install: - 7z x php_memcache-3.0.8-5.5-nts-vc11-x86.zip -y >nul - cd .. - copy /Y php.ini-development php.ini-min + - echo memory_limit=-1 >> php.ini-min - echo serialize_precision=14 >> php.ini-min - echo max_execution_time=1200 >> php.ini-min - echo date.timezone="America/Los_Angeles" >> php.ini-min diff --git a/src/Symfony/Component/HttpFoundation/Request.php b/src/Symfony/Component/HttpFoundation/Request.php index 7b47948c67..da9a6adbc0 100644 --- a/src/Symfony/Component/HttpFoundation/Request.php +++ b/src/Symfony/Component/HttpFoundation/Request.php @@ -531,9 +531,21 @@ class Request return trigger_error($e, E_USER_ERROR); } + $cookieHeader = ''; + $cookies = array(); + + foreach ($this->cookies as $k => $v) { + $cookies[] = $k.'='.$v; + } + + if (!empty($cookies)) { + $cookieHeader = 'Cookie: '.implode('; ', $cookies)."\r\n"; + } + return sprintf('%s %s %s', $this->getMethod(), $this->getRequestUri(), $this->server->get('SERVER_PROTOCOL'))."\r\n". - $this->headers."\r\n". + $this->headers. + $cookieHeader."\r\n". $content; } diff --git a/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php b/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php index 4b9972bd88..45bc48b996 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php @@ -1523,8 +1523,18 @@ class RequestTest extends TestCase $request = new Request(); $request->headers->set('Accept-language', 'zh, en-us; q=0.8, en; q=0.6'); + $request->cookies->set('Foo', 'Bar'); - $this->assertContains('Accept-Language: zh, en-us; q=0.8, en; q=0.6', $request->__toString()); + $asString = (string) $request; + + $this->assertContains('Accept-Language: zh, en-us; q=0.8, en; q=0.6', $asString); + $this->assertContains('Cookie: Foo=Bar', $asString); + + $request->cookies->set('Another', 'Cookie'); + + $asString = (string) $request; + + $this->assertContains('Cookie: Foo=Bar; Another=Cookie', $asString); } public function testIsMethod() diff --git a/src/Symfony/Component/Routing/Loader/AnnotationFileLoader.php b/src/Symfony/Component/Routing/Loader/AnnotationFileLoader.php index 0ff9c9647c..cf9f0704c4 100644 --- a/src/Symfony/Component/Routing/Loader/AnnotationFileLoader.php +++ b/src/Symfony/Component/Routing/Loader/AnnotationFileLoader.php @@ -112,22 +112,22 @@ class AnnotationFileLoader extends FileLoader } if (T_CLASS === $token[0]) { - // Skip usage of ::class constant - $isClassConstant = false; + // Skip usage of ::class constant and anonymous classes + $skipClassToken = false; for ($j = $i - 1; $j > 0; --$j) { if (!isset($tokens[$j][1])) { break; } - if (T_DOUBLE_COLON === $tokens[$j][0]) { - $isClassConstant = true; + if (T_DOUBLE_COLON === $tokens[$j][0] || T_NEW === $tokens[$j][0]) { + $skipClassToken = true; break; } elseif (!in_array($tokens[$j][0], array(T_WHITESPACE, T_DOC_COMMENT, T_COMMENT))) { break; } } - if (!$isClassConstant) { + if (!$skipClassToken) { $class = true; } } diff --git a/src/Symfony/Component/Routing/Tests/Fixtures/OtherAnnotatedClasses/AnonymousClassInTrait.php b/src/Symfony/Component/Routing/Tests/Fixtures/OtherAnnotatedClasses/AnonymousClassInTrait.php new file mode 100644 index 0000000000..de87895649 --- /dev/null +++ b/src/Symfony/Component/Routing/Tests/Fixtures/OtherAnnotatedClasses/AnonymousClassInTrait.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Routing\Tests\Fixtures\OtherAnnotatedClasses; + +trait AnonymousClassInTrait +{ + public function test() + { + return new class() { + public function foo() + { + } + }; + } +} diff --git a/src/Symfony/Component/Routing/Tests/Loader/AnnotationFileLoaderTest.php b/src/Symfony/Component/Routing/Tests/Loader/AnnotationFileLoaderTest.php index 5d54f9f99f..7f1d576557 100644 --- a/src/Symfony/Component/Routing/Tests/Loader/AnnotationFileLoaderTest.php +++ b/src/Symfony/Component/Routing/Tests/Loader/AnnotationFileLoaderTest.php @@ -67,6 +67,17 @@ class AnnotationFileLoaderTest extends AbstractAnnotationLoaderTest $this->loader->load(__DIR__.'/../Fixtures/OtherAnnotatedClasses/VariadicClass.php'); } + /** + * @requires PHP 7.0 + */ + public function testLoadAnonymousClass() + { + $this->reader->expects($this->never())->method('getClassAnnotation'); + $this->reader->expects($this->never())->method('getMethodAnnotations'); + + $this->loader->load(__DIR__.'/../Fixtures/OtherAnnotatedClasses/AnonymousClassInTrait.php'); + } + public function testSupports() { $fixture = __DIR__.'/../Fixtures/annotated.php'; diff --git a/src/Symfony/Component/Security/Http/Firewall/ContextListener.php b/src/Symfony/Component/Security/Http/Firewall/ContextListener.php index 1017b32862..f9368b8496 100644 --- a/src/Symfony/Component/Security/Http/Firewall/ContextListener.php +++ b/src/Symfony/Component/Security/Http/Firewall/ContextListener.php @@ -43,8 +43,6 @@ class ContextListener implements ListenerInterface private $registered; private $trustResolver; - private static $unserializeExceptionCode = 0x37313bc; - public function __construct(TokenStorageInterface $tokenStorage, array $userProviders, $contextKey, LoggerInterface $logger = null, EventDispatcherInterface $dispatcher = null, AuthenticationTrustResolverInterface $trustResolver = null) { if (empty($contextKey)) { @@ -185,7 +183,7 @@ class ContextListener implements ListenerInterface $prevUnserializeHandler = ini_set('unserialize_callback_func', __CLASS__.'::handleUnserializeCallback'); $prevErrorHandler = set_error_handler(function ($type, $msg, $file, $line, $context = array()) use (&$prevErrorHandler) { if (__FILE__ === $file) { - throw new \UnexpectedValueException($msg, self::$unserializeExceptionCode); + throw new \UnexpectedValueException($msg, 0x37313bc); } return $prevErrorHandler ? $prevErrorHandler($type, $msg, $file, $line, $context) : false; @@ -199,7 +197,7 @@ class ContextListener implements ListenerInterface restore_error_handler(); ini_set('unserialize_callback_func', $prevUnserializeHandler); if ($e) { - if (!$e instanceof \UnexpectedValueException || self::$unserializeExceptionCode !== $e->getCode()) { + if (!$e instanceof \UnexpectedValueException || 0x37313bc !== $e->getCode()) { throw $e; } if ($this->logger) { @@ -215,6 +213,6 @@ class ContextListener implements ListenerInterface */ public static function handleUnserializeCallback($class) { - throw new \UnexpectedValueException('Class not found: '.$class, self::$unserializeExceptionCode); + throw new \UnexpectedValueException('Class not found: '.$class, 0x37313bc); } } diff --git a/src/Symfony/Component/Security/Http/Firewall/SimpleFormAuthenticationListener.php b/src/Symfony/Component/Security/Http/Firewall/SimpleFormAuthenticationListener.php index 4d060ab627..9d843667a6 100644 --- a/src/Symfony/Component/Security/Http/Firewall/SimpleFormAuthenticationListener.php +++ b/src/Symfony/Component/Security/Http/Firewall/SimpleFormAuthenticationListener.php @@ -13,6 +13,7 @@ namespace Symfony\Component\Security\Http\Firewall; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; use Symfony\Component\Security\Core\Exception\InvalidCsrfTokenException; use Symfony\Component\Security\Csrf\CsrfToken; use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface; @@ -98,15 +99,17 @@ class SimpleFormAuthenticationListener extends AbstractAuthenticationListener } } - if ($this->options['post_only']) { - $username = trim(ParameterBagUtils::getParameterBagValue($request->request, $this->options['username_parameter'])); - $password = ParameterBagUtils::getParameterBagValue($request->request, $this->options['password_parameter']); - } else { - $username = trim(ParameterBagUtils::getRequestParameterValue($request, $this->options['username_parameter'])); - $password = ParameterBagUtils::getRequestParameterValue($request, $this->options['password_parameter']); + $requestBag = $this->options['post_only'] ? $request->request : $request; + $username = ParameterBagUtils::getParameterBagValue($requestBag, $this->options['username_parameter']); + $password = ParameterBagUtils::getParameterBagValue($requestBag, $this->options['password_parameter']); + + if (!\is_string($username) || (\is_object($username) && !\method_exists($username, '__toString'))) { + throw new BadRequestHttpException(sprintf('The key "%s" must be a string, "%s" given.', $this->options['username_parameter'], \gettype($username))); } - if (strlen($username) > Security::MAX_USERNAME_LENGTH) { + $username = trim($username); + + if (\strlen($username) > Security::MAX_USERNAME_LENGTH) { throw new BadCredentialsException('Invalid username.'); } diff --git a/src/Symfony/Component/Security/Http/Firewall/UsernamePasswordFormAuthenticationListener.php b/src/Symfony/Component/Security/Http/Firewall/UsernamePasswordFormAuthenticationListener.php index 426457d182..5d0bee3ae2 100644 --- a/src/Symfony/Component/Security/Http/Firewall/UsernamePasswordFormAuthenticationListener.php +++ b/src/Symfony/Component/Security/Http/Firewall/UsernamePasswordFormAuthenticationListener.php @@ -13,6 +13,7 @@ namespace Symfony\Component\Security\Http\Firewall; use Symfony\Component\HttpFoundation\Request; use Psr\Log\LoggerInterface; +use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; use Symfony\Component\Security\Csrf\CsrfToken; use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface; use Symfony\Component\Security\Http\Authentication\AuthenticationFailureHandlerInterface; @@ -76,14 +77,16 @@ class UsernamePasswordFormAuthenticationListener extends AbstractAuthenticationL } } - if ($this->options['post_only']) { - $username = trim(ParameterBagUtils::getParameterBagValue($request->request, $this->options['username_parameter'])); - $password = ParameterBagUtils::getParameterBagValue($request->request, $this->options['password_parameter']); - } else { - $username = trim(ParameterBagUtils::getRequestParameterValue($request, $this->options['username_parameter'])); - $password = ParameterBagUtils::getRequestParameterValue($request, $this->options['password_parameter']); + $requestBag = $this->options['post_only'] ? $request->request : $request; + $username = ParameterBagUtils::getParameterBagValue($requestBag, $this->options['username_parameter']); + $password = ParameterBagUtils::getParameterBagValue($requestBag, $this->options['password_parameter']); + + if (!\is_string($username) || (\is_object($username) && !\method_exists($username, '__toString'))) { + throw new BadRequestHttpException(sprintf('The key "%s" must be a string, "%s" given.', $this->options['username_parameter'], \gettype($username))); } + $username = trim($username); + if (strlen($username) > Security::MAX_USERNAME_LENGTH) { throw new BadCredentialsException('Invalid username.'); } diff --git a/src/Symfony/Component/Security/Http/Tests/Firewall/UsernamePasswordFormAuthenticationListenerTest.php b/src/Symfony/Component/Security/Http/Tests/Firewall/UsernamePasswordFormAuthenticationListenerTest.php index 1e7649db97..f3962a391e 100644 --- a/src/Symfony/Component/Security/Http/Tests/Firewall/UsernamePasswordFormAuthenticationListenerTest.php +++ b/src/Symfony/Component/Security/Http/Tests/Firewall/UsernamePasswordFormAuthenticationListenerTest.php @@ -14,8 +14,15 @@ namespace Symfony\Component\Security\Tests\Http\Firewall; use PHPUnit\Framework\TestCase; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\Security\Http\Firewall\UsernamePasswordFormAuthenticationListener; +use Symfony\Component\HttpKernel\Event\GetResponseEvent; +use Symfony\Component\HttpKernel\HttpKernelInterface; +use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage; use Symfony\Component\Security\Core\Security; +use Symfony\Component\Security\Http\Authentication\DefaultAuthenticationFailureHandler; +use Symfony\Component\Security\Http\Authentication\DefaultAuthenticationSuccessHandler; +use Symfony\Component\Security\Http\Firewall\UsernamePasswordFormAuthenticationListener; +use Symfony\Component\Security\Http\HttpUtils; +use Symfony\Component\Security\Http\Session\SessionAuthenticationStrategy; class UsernamePasswordFormAuthenticationListenerTest extends TestCase { @@ -69,6 +76,31 @@ class UsernamePasswordFormAuthenticationListenerTest extends TestCase $listener->handle($event); } + /** + * @expectedException \Symfony\Component\HttpKernel\Exception\BadRequestHttpException + * @expectedExceptionMessage The key "_username" must be a string, "array" given. + */ + public function testHandleNonStringUsername() + { + $request = Request::create('/login_check', 'POST', array('_username' => array())); + $request->setSession($this->getMockBuilder('Symfony\Component\HttpFoundation\Session\SessionInterface')->getMock()); + + $listener = new UsernamePasswordFormAuthenticationListener( + new TokenStorage(), + $this->getMockBuilder('Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface')->getMock(), + new SessionAuthenticationStrategy(SessionAuthenticationStrategy::NONE), + $httpUtils = new HttpUtils(), + 'foo', + new DefaultAuthenticationSuccessHandler($httpUtils), + new DefaultAuthenticationFailureHandler($this->getMockBuilder('Symfony\Component\HttpKernel\HttpKernelInterface')->getMock(), $httpUtils), + array('require_previous_session' => false) + ); + + $event = new GetResponseEvent($this->getMockBuilder('Symfony\Component\HttpKernel\HttpKernelInterface')->getMock(), $request, HttpKernelInterface::MASTER_REQUEST); + + $listener->handle($event); + } + public function getUsernameForLength() { return array(