From c1ae7b6ad7af213c7ecc21a1c68a72c41a6f397f Mon Sep 17 00:00:00 2001 From: Wesley Lancel Date: Tue, 4 Oct 2016 09:14:18 +0200 Subject: [PATCH 1/4] Prevent infinite loop in PropertyMetadata --- .../Component/Validator/Mapping/PropertyMetadata.php | 6 ++++++ .../Validator/Tests/Mapping/PropertyMetadataTest.php | 10 ++++++++++ 2 files changed, 16 insertions(+) diff --git a/src/Symfony/Component/Validator/Mapping/PropertyMetadata.php b/src/Symfony/Component/Validator/Mapping/PropertyMetadata.php index ac71be8285..ebc83e1d6f 100644 --- a/src/Symfony/Component/Validator/Mapping/PropertyMetadata.php +++ b/src/Symfony/Component/Validator/Mapping/PropertyMetadata.php @@ -58,8 +58,14 @@ class PropertyMetadata extends MemberMetadata */ protected function newReflectionMember($objectOrClassName) { + $originalClass = is_string($objectOrClassName) ? $objectOrClassName : get_class($objectOrClassName); + while (!property_exists($objectOrClassName, $this->getName())) { $objectOrClassName = get_parent_class($objectOrClassName); + + if (false === $objectOrClassName) { + throw new ValidatorException(sprintf('Property "%s" does not exist in class "%s"', $this->getName(), $originalClass)); + } } $member = new \ReflectionProperty($objectOrClassName, $this->getName()); diff --git a/src/Symfony/Component/Validator/Tests/Mapping/PropertyMetadataTest.php b/src/Symfony/Component/Validator/Tests/Mapping/PropertyMetadataTest.php index f411d950e1..e0ff920fe1 100644 --- a/src/Symfony/Component/Validator/Tests/Mapping/PropertyMetadataTest.php +++ b/src/Symfony/Component/Validator/Tests/Mapping/PropertyMetadataTest.php @@ -42,4 +42,14 @@ class PropertyMetadataTest extends \PHPUnit_Framework_TestCase $this->assertTrue($metadata->isPublic($entity)); $this->assertEquals('Overridden data', $metadata->getPropertyValue($entity)); } + + public function testGetPropertyValueFromRemovedProperty() + { + $entity = new Entity('foobar'); + $metadata = new PropertyMetadata(self::CLASSNAME, 'internal'); + $metadata->name = 'test'; + + $this->setExpectedException('Symfony\Component\Validator\Exception\ValidatorException'); + $metadata->getPropertyValue($entity); + } } From df138fb636867b396185e634263e310aaafbd75f Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Thu, 13 Oct 2016 07:02:27 -0700 Subject: [PATCH 2/4] fixed CS --- src/Symfony/Component/Validator/Mapping/PropertyMetadata.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Validator/Mapping/PropertyMetadata.php b/src/Symfony/Component/Validator/Mapping/PropertyMetadata.php index ebc83e1d6f..d12701cb44 100644 --- a/src/Symfony/Component/Validator/Mapping/PropertyMetadata.php +++ b/src/Symfony/Component/Validator/Mapping/PropertyMetadata.php @@ -64,7 +64,7 @@ class PropertyMetadata extends MemberMetadata $objectOrClassName = get_parent_class($objectOrClassName); if (false === $objectOrClassName) { - throw new ValidatorException(sprintf('Property "%s" does not exist in class "%s"', $this->getName(), $originalClass)); + throw new ValidatorException(sprintf('Property "%s" does not exist in class "%s".', $this->getName(), $originalClass)); } } From c43de7f21a587649bb42ca08bce9ad8d0c0e731d Mon Sep 17 00:00:00 2001 From: David Maicher Date: Thu, 13 Oct 2016 22:14:35 +0200 Subject: [PATCH 3/4] [HttpCache] fix: do not cache OPTIONS request --- .../Component/HttpFoundation/Request.php | 10 +++++++ .../HttpFoundation/Tests/RequestTest.php | 26 +++++++++++++++++++ .../HttpKernel/HttpCache/HttpCache.php | 2 +- .../Tests/HttpCache/HttpCacheTest.php | 15 +++++++++++ .../Component/HttpKernel/composer.json | 2 +- 5 files changed, 53 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/HttpFoundation/Request.php b/src/Symfony/Component/HttpFoundation/Request.php index dc32f4a39a..00a16223b4 100644 --- a/src/Symfony/Component/HttpFoundation/Request.php +++ b/src/Symfony/Component/HttpFoundation/Request.php @@ -1473,6 +1473,16 @@ class Request return in_array($this->getMethod(), array('GET', 'HEAD', 'OPTIONS', 'TRACE')); } + /** + * Checks whether the method is cachaeble or not. + * + * @return bool + */ + public function isMethodCacheable() + { + return in_array($this->getMethod(), array('GET', 'HEAD')); + } + /** * Returns the request body content. * diff --git a/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php b/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php index f90a368775..0c54c16b29 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php @@ -1948,6 +1948,32 @@ class RequestTest extends \PHPUnit_Framework_TestCase array('CONNECT', false), ); } + + /** + * @dataProvider methodCacheableProvider + */ + public function testMethodCacheable($method, $chacheable) + { + $request = new Request(); + $request->setMethod($method); + $this->assertEquals($chacheable, $request->isMethodCacheable()); + } + + public function methodCacheableProvider() + { + return array( + array('HEAD', true), + array('GET', true), + array('POST', false), + array('PUT', false), + array('PATCH', false), + array('DELETE', false), + array('PURGE', false), + array('OPTIONS', false), + array('TRACE', false), + array('CONNECT', false), + ); + } } class RequestContentProxy extends Request diff --git a/src/Symfony/Component/HttpKernel/HttpCache/HttpCache.php b/src/Symfony/Component/HttpKernel/HttpCache/HttpCache.php index 253deb143a..efb08d693c 100644 --- a/src/Symfony/Component/HttpKernel/HttpCache/HttpCache.php +++ b/src/Symfony/Component/HttpKernel/HttpCache/HttpCache.php @@ -204,7 +204,7 @@ class HttpCache implements HttpKernelInterface, TerminableInterface if (!$request->isMethodSafe()) { $response = $this->invalidate($request, $catch); - } elseif ($request->headers->has('expect')) { + } elseif ($request->headers->has('expect') || !$request->isMethodCacheable()) { $response = $this->pass($request, $catch); } else { $response = $this->lookup($request, $catch); diff --git a/src/Symfony/Component/HttpKernel/Tests/HttpCache/HttpCacheTest.php b/src/Symfony/Component/HttpKernel/Tests/HttpCache/HttpCacheTest.php index 68d2b88ed6..7751f6e0cc 100644 --- a/src/Symfony/Component/HttpKernel/Tests/HttpCache/HttpCacheTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/HttpCache/HttpCacheTest.php @@ -1264,6 +1264,21 @@ class HttpCacheTest extends HttpCacheTestCase $this->assertNull($this->response->getETag()); $this->assertNull($this->response->getLastModified()); } + + public function testDoesNotCacheOptionsRequest() + { + $this->setNextResponse(200, array('Cache-Control' => 'public, s-maxage=60'), 'get'); + $this->request('GET', '/'); + $this->assertHttpKernelIsCalled(); + + $this->setNextResponse(200, array('Cache-Control' => 'public, s-maxage=60'), 'options'); + $this->request('OPTIONS', '/'); + $this->assertHttpKernelIsCalled(); + + $this->request('GET', '/'); + $this->assertHttpKernelIsNotCalled(); + $this->assertSame('get', $this->response->getContent()); + } } class TestKernel implements HttpKernelInterface diff --git a/src/Symfony/Component/HttpKernel/composer.json b/src/Symfony/Component/HttpKernel/composer.json index 1774b641e3..ec2333d9b4 100644 --- a/src/Symfony/Component/HttpKernel/composer.json +++ b/src/Symfony/Component/HttpKernel/composer.json @@ -18,7 +18,7 @@ "require": { "php": ">=5.3.9", "symfony/event-dispatcher": "~2.6,>=2.6.7", - "symfony/http-foundation": "~2.7.15|~2.8.8", + "symfony/http-foundation": "~2.7.20|~2.8.13", "symfony/debug": "~2.6,>=2.6.2", "psr/log": "~1.0" }, From f76e77f924142a3c00023d23d1ff82bdb3ade1f1 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Thu, 13 Oct 2016 18:29:00 -0700 Subject: [PATCH 4/4] fixed typo --- src/Symfony/Component/HttpFoundation/Request.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/HttpFoundation/Request.php b/src/Symfony/Component/HttpFoundation/Request.php index 00a16223b4..5e07af3790 100644 --- a/src/Symfony/Component/HttpFoundation/Request.php +++ b/src/Symfony/Component/HttpFoundation/Request.php @@ -1474,7 +1474,7 @@ class Request } /** - * Checks whether the method is cachaeble or not. + * Checks whether the method is cacheable or not. * * @return bool */