From 70f3399f7ede50fce570b64c2fa937dbeb040845 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Mon, 8 Jul 2013 08:42:57 +0200 Subject: [PATCH 1/2] [HttpKernel] changed the fragment handler to explicitely disallow non-scalar in generated URIs (refs #8263) --- .../Fragment/InlineFragmentRenderer.php | 2 +- .../Fragment/RoutableFragmentRenderer.php | 22 ++++++++++-- .../Fragment/RoutableFragmentRendererTest.php | 34 +++++++++++++------ 3 files changed, 45 insertions(+), 13 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/Fragment/InlineFragmentRenderer.php b/src/Symfony/Component/HttpKernel/Fragment/InlineFragmentRenderer.php index 1cbdeab18ea02..5b963261fe60c 100644 --- a/src/Symfony/Component/HttpKernel/Fragment/InlineFragmentRenderer.php +++ b/src/Symfony/Component/HttpKernel/Fragment/InlineFragmentRenderer.php @@ -52,7 +52,7 @@ public function render($uri, Request $request, array $options = array()) $reference = null; if ($uri instanceof ControllerReference) { $reference = $uri; - $uri = $this->generateFragmentUri($uri, $request); + $uri = $this->generateFragmentUri($uri, $request, false); } $subRequest = $this->createSubRequest($uri, $request); diff --git a/src/Symfony/Component/HttpKernel/Fragment/RoutableFragmentRenderer.php b/src/Symfony/Component/HttpKernel/Fragment/RoutableFragmentRenderer.php index 879a0bb7ac5e4..1137ce59f620a 100644 --- a/src/Symfony/Component/HttpKernel/Fragment/RoutableFragmentRenderer.php +++ b/src/Symfony/Component/HttpKernel/Fragment/RoutableFragmentRenderer.php @@ -40,12 +40,17 @@ public function setFragmentPath($path) * Generates a fragment URI for a given controller. * * @param ControllerReference $reference A ControllerReference instance - * @param Request $request A Request instance + * @param Request $request A Request instance + * @param Boolean $strict Whether to allow non-scalar attributes or not * * @return string A fragment URI */ - protected function generateFragmentUri(ControllerReference $reference, Request $request) + protected function generateFragmentUri(ControllerReference $reference, Request $request, $strict = true) { + if ($strict) { + $this->checkNonScalar($reference->attributes); + } + if (!isset($reference->attributes['_format'])) { $reference->attributes['_format'] = $request->getRequestFormat(); } @@ -56,4 +61,17 @@ protected function generateFragmentUri(ControllerReference $reference, Request $ return $request->getUriForPath($this->fragmentPath.'?'.http_build_query($reference->query, '', '&')); } + + private function checkNonScalar($values) + { + foreach ($values as $value) { + if (is_array($value)) { + $this->checkNonScalar($value); + } + + if (!is_scalar($value)) { + throw new \LogicException('Controller attributes cannot contain non-scalar values.'); + } + } + } } diff --git a/src/Symfony/Component/HttpKernel/Tests/Fragment/RoutableFragmentRendererTest.php b/src/Symfony/Component/HttpKernel/Tests/Fragment/RoutableFragmentRendererTest.php index 2106f9de753e5..b780a162d1c50 100644 --- a/src/Symfony/Component/HttpKernel/Tests/Fragment/RoutableFragmentRendererTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/Fragment/RoutableFragmentRendererTest.php @@ -13,7 +13,6 @@ use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Controller\ControllerReference; -use Symfony\Component\HttpKernel\Fragment\RoutableFragmentRenderer; class RoutableFragmentRendererTest extends \PHPUnit_Framework_TestCase { @@ -22,7 +21,7 @@ class RoutableFragmentRendererTest extends \PHPUnit_Framework_TestCase */ public function testGenerateFragmentUri($uri, $controller) { - $this->assertEquals($uri, $this->getRenderer()->doGenerateFragmentUri($controller, Request::create('/'))); + $this->assertEquals($uri, $this->callGenerateFragmentUriMethod($controller, Request::create('/'))); } public function getGenerateFragmentUriData() @@ -33,6 +32,7 @@ public function getGenerateFragmentUriData() array('http://localhost/_fragment?_path=foo%3Dfoo%26_format%3Djson%26_controller%3Dcontroller', new ControllerReference('controller', array('foo' => 'foo', '_format' => 'json'), array())), array('http://localhost/_fragment?bar=bar&_path=foo%3Dfoo%26_format%3Dhtml%26_controller%3Dcontroller', new ControllerReference('controller', array('foo' => 'foo'), array('bar' => 'bar'))), array('http://localhost/_fragment?foo=foo&_path=_format%3Dhtml%26_controller%3Dcontroller', new ControllerReference('controller', array(), array('foo' => 'foo'))), + array('http://localhost/_fragment?_path=foo%255B0%255D%3Dfoo%26foo%255B1%255D%3Dbar%26_format%3Dhtml%26_controller%3Dcontroller', new ControllerReference('controller', array('foo' => array('foo', 'bar')), array())), ); } @@ -42,22 +42,36 @@ public function testGenerateFragmentUriWithARequest() $request->attributes->set('_format', 'json'); $controller = new ControllerReference('controller', array(), array()); - $this->assertEquals('http://localhost/_fragment?_path=_format%3Djson%26_controller%3Dcontroller', $this->getRenderer()->doGenerateFragmentUri($controller, $request)); + $this->assertEquals('http://localhost/_fragment?_path=_format%3Djson%26_controller%3Dcontroller', $this->callGenerateFragmentUriMethod($controller, $request)); } - private function getRenderer() + /** + * @expectedException LogicException + */ + public function testGenerateFragmentUriWithObject() { - return new Renderer(); + $controller = new ControllerReference('controller', array('foo' => new Foo(), 'bar' => 'bar'), array()); + + $this->callGenerateFragmentUriMethod($controller, Request::create('/')); + } + + private function callGenerateFragmentUriMethod(ControllerReference $reference, Request $request) + { + $renderer = $this->getMockForAbstractClass('Symfony\Component\HttpKernel\Fragment\RoutableFragmentRenderer'); + $r = new \ReflectionObject($renderer); + $m = $r->getMethod('generateFragmentUri'); + $m->setAccessible(true); + + return $m->invoke($renderer, $reference, $request); } } -class Renderer extends RoutableFragmentRenderer +class Foo { - public function render($uri, Request $request, array $options = array()) {} - public function getName() {} + public $foo; - public function doGenerateFragmentUri(ControllerReference $reference, Request $request) + public function getFoo() { - return parent::generateFragmentUri($reference, $request); + return $this->foo; } } From 43ce368deaf934bf60fb41377b9da6efab9d2065 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Mon, 8 Jul 2013 09:58:33 +0200 Subject: [PATCH 2/2] [HttpKernel] added a unit test to demonstrate that passing objects works for inline controllers --- .../Fragment/RoutableFragmentRenderer.php | 8 +++--- .../Fragment/InlineFragmentRendererTest.php | 27 +++++++++++++++++++ .../Fragment/RoutableFragmentRendererTest.php | 13 ++++++--- 3 files changed, 40 insertions(+), 8 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/Fragment/RoutableFragmentRenderer.php b/src/Symfony/Component/HttpKernel/Fragment/RoutableFragmentRenderer.php index 1137ce59f620a..d2300d139b1bd 100644 --- a/src/Symfony/Component/HttpKernel/Fragment/RoutableFragmentRenderer.php +++ b/src/Symfony/Component/HttpKernel/Fragment/RoutableFragmentRenderer.php @@ -64,13 +64,11 @@ protected function generateFragmentUri(ControllerReference $reference, Request $ private function checkNonScalar($values) { - foreach ($values as $value) { + foreach ($values as $key => $value) { if (is_array($value)) { $this->checkNonScalar($value); - } - - if (!is_scalar($value)) { - throw new \LogicException('Controller attributes cannot contain non-scalar values.'); + } elseif (!is_scalar($value)) { + throw new \LogicException(sprintf('Controller attributes cannot contain non-scalar values (value for key "%s" is not a scalar).', $key)); } } } diff --git a/src/Symfony/Component/HttpKernel/Tests/Fragment/InlineFragmentRendererTest.php b/src/Symfony/Component/HttpKernel/Tests/Fragment/InlineFragmentRendererTest.php index c7ae7dd9aabc2..f8d5416a07b09 100644 --- a/src/Symfony/Component/HttpKernel/Tests/Fragment/InlineFragmentRendererTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/Fragment/InlineFragmentRendererTest.php @@ -71,6 +71,24 @@ public function testRenderWithObjectsAsAttributes() $strategy->render(new ControllerReference('main_controller', array('object' => $object), array()), Request::create('/')); } + public function testRenderWithObjectsAsAttributesPassedAsObjectsInTheController() + { + $resolver = $this->getMock('Symfony\\Component\\HttpKernel\\Controller\\ControllerResolver', array('getController')); + $resolver + ->expects($this->once()) + ->method('getController') + ->will($this->returnValue(function (\stdClass $object, Bar $object1) { + return new Response($object1->getBar()); + })) + ; + + $kernel = new HttpKernel(new EventDispatcher(), $resolver); + $renderer = new InlineFragmentRenderer($kernel); + + $response = $renderer->render(new ControllerReference('main_controller', array('object' => new \stdClass(), 'object1' => new Bar()), array()), Request::create('/')); + $this->assertEquals('bar', $response->getContent()); + } + /** * @expectedException \RuntimeException */ @@ -168,3 +186,12 @@ public function testESIHeaderIsKeptInSubrequest() $strategy->render('/', $request); } } + +class Bar { + public $bar = 'bar'; + + public function getBar() + { + return $this->bar; + } +} diff --git a/src/Symfony/Component/HttpKernel/Tests/Fragment/RoutableFragmentRendererTest.php b/src/Symfony/Component/HttpKernel/Tests/Fragment/RoutableFragmentRendererTest.php index b780a162d1c50..dae52da9334d5 100644 --- a/src/Symfony/Component/HttpKernel/Tests/Fragment/RoutableFragmentRendererTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/Fragment/RoutableFragmentRendererTest.php @@ -47,14 +47,21 @@ public function testGenerateFragmentUriWithARequest() /** * @expectedException LogicException + * @dataProvider getGenerateFragmentUriDataWithNonScalar */ - public function testGenerateFragmentUriWithObject() + public function testGenerateFragmentUriWithNonScalar($controller) { - $controller = new ControllerReference('controller', array('foo' => new Foo(), 'bar' => 'bar'), array()); - $this->callGenerateFragmentUriMethod($controller, Request::create('/')); } + public function getGenerateFragmentUriDataWithNonScalar() + { + return array( + array(new ControllerReference('controller', array('foo' => new Foo(), 'bar' => 'bar'), array())), + array(new ControllerReference('controller', array('foo' => array('foo' => 'foo'), 'bar' => array('bar' => new Foo())), array())), + ); + } + private function callGenerateFragmentUriMethod(ControllerReference $reference, Request $request) { $renderer = $this->getMockForAbstractClass('Symfony\Component\HttpKernel\Fragment\RoutableFragmentRenderer');