From 8051f44648535345b1177bd235057b99b93eb2c6 Mon Sep 17 00:00:00 2001 From: Nicholas Calugar Date: Fri, 13 Apr 2012 14:25:48 -0700 Subject: [PATCH 1/2] Adding circular forwarding detection to Forward plugin --- library/Zend/Mvc/Controller/Plugin/Forward.php | 9 +++++++++ tests/Zend/Mvc/Controller/Plugin/ForwardTest.php | 10 ++++++++++ .../Zend/Mvc/Controller/TestAsset/SampleController.php | 5 +++++ 3 files changed, 24 insertions(+) diff --git a/library/Zend/Mvc/Controller/Plugin/Forward.php b/library/Zend/Mvc/Controller/Plugin/Forward.php index afac79fa0d9..f86a2f6f4a9 100644 --- a/library/Zend/Mvc/Controller/Plugin/Forward.php +++ b/library/Zend/Mvc/Controller/Plugin/Forward.php @@ -14,6 +14,7 @@ class Forward extends AbstractPlugin { protected $event; protected $locator; + protected $actionStack = array(); /** * Dispatch another controller @@ -48,8 +49,16 @@ public function dispatch($name, array $params = null) $event->setRouteMatch($matches); } + $actionKey = get_class($controller) . ':' . (isset($params['action'])?$params['action']:'index'); + if (in_array($actionKey, $this->actionStack)) { + throw new Exception\DomainException("Circular forwarding detected: $actionKey is already in the stack"); + } + array_push($this->actionStack, $actionKey); + $return = $controller->dispatch($event->getRequest(), $event->getResponse()); + array_pop($this->actionStack); + if ($cachedMatches) { $event->setRouteMatch($cachedMatches); } diff --git a/tests/Zend/Mvc/Controller/Plugin/ForwardTest.php b/tests/Zend/Mvc/Controller/Plugin/ForwardTest.php index 325676737ae..52d6a73902c 100644 --- a/tests/Zend/Mvc/Controller/Plugin/ForwardTest.php +++ b/tests/Zend/Mvc/Controller/Plugin/ForwardTest.php @@ -73,6 +73,16 @@ public function testDispatchRaisesDomainExceptionIfDiscoveredControllerIsNotDisp $this->plugin->dispatch('bogus'); } + public function testDispatchRaisesDomainExceptionIfCircular() + { + $this->setExpectedException('Zend\Mvc\Exception\DomainException', 'Circular forwarding'); + $sampleController = $this->controller; + $sampleController->getLocator()->add('sample', function() use ($sampleController) { + return $sampleController; + }); + $this->plugin->dispatch('sample', array('action' => 'test-circular')); + } + public function testPluginDispatchsRequestedControllerWhenFound() { $result = $this->plugin->dispatch('forward'); diff --git a/tests/Zend/Mvc/Controller/TestAsset/SampleController.php b/tests/Zend/Mvc/Controller/TestAsset/SampleController.php index bc82c56141f..c19756a6763 100644 --- a/tests/Zend/Mvc/Controller/TestAsset/SampleController.php +++ b/tests/Zend/Mvc/Controller/TestAsset/SampleController.php @@ -15,4 +15,9 @@ public function testSomeStrangelySeparatedWordsAction() { return array('content' => 'Test Some Strangely Separated Words'); } + + public function testCircularAction() + { + return $this->forward()->dispatch('sample', array('action' => 'test-circular')); + } } From f371e6ba75a744dbf5a1a7109ff4061706c8e165 Mon Sep 17 00:00:00 2001 From: Nicholas Calugar Date: Wed, 2 May 2012 14:46:50 -0700 Subject: [PATCH 2/2] Detecting circular forwarding based on number of nested forwards instead of an action stack --- library/Zend/Mvc/Controller/Plugin/Forward.php | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/library/Zend/Mvc/Controller/Plugin/Forward.php b/library/Zend/Mvc/Controller/Plugin/Forward.php index f86a2f6f4a9..7c4d9f8ee95 100644 --- a/library/Zend/Mvc/Controller/Plugin/Forward.php +++ b/library/Zend/Mvc/Controller/Plugin/Forward.php @@ -14,7 +14,14 @@ class Forward extends AbstractPlugin { protected $event; protected $locator; - protected $actionStack = array(); + protected $maxNestedForwards = 10; + protected $numNestedForwards = 0; + + public function setMaxNestedForwards($maxNestedForwards) + { + $this->maxNestedForwards = (int) $maxNestedForwards; + return $this; + } /** * Dispatch another controller @@ -49,15 +56,14 @@ public function dispatch($name, array $params = null) $event->setRouteMatch($matches); } - $actionKey = get_class($controller) . ':' . (isset($params['action'])?$params['action']:'index'); - if (in_array($actionKey, $this->actionStack)) { - throw new Exception\DomainException("Circular forwarding detected: $actionKey is already in the stack"); + if ($this->numNestedForwards > $this->maxNestedForwards) { + throw new Exception\DomainException("Circular forwarding detected: greater than $this->maxNestedForwards nested forwards"); } - array_push($this->actionStack, $actionKey); + $this->numNestedForwards++; $return = $controller->dispatch($event->getRequest(), $event->getResponse()); - array_pop($this->actionStack); + $this->numNestedForwards--; if ($cachedMatches) { $event->setRouteMatch($cachedMatches);