diff --git a/src/Symfony/Component/BrowserKit/Client.php b/src/Symfony/Component/BrowserKit/Client.php index 39945740b0..825cd42a05 100644 --- a/src/Symfony/Component/BrowserKit/Client.php +++ b/src/Symfony/Component/BrowserKit/Client.php @@ -42,6 +42,10 @@ abstract class Client protected $redirect; protected $followRedirects; + private $maxRedirects; + private $redirectCount; + private $isMainRequest; + /** * Constructor. * @@ -58,6 +62,9 @@ abstract class Client $this->cookieJar = null === $cookieJar ? new CookieJar() : $cookieJar; $this->insulated = false; $this->followRedirects = true; + $this->maxRedirects = -1; + $this->redirectCount = 0; + $this->isMainRequest = true; } /** @@ -71,6 +78,17 @@ abstract class Client { $this->followRedirects = (Boolean) $followRedirect; } + + /** + * Sets the maximum number of requests that crawler can follow. + * + * @param integer $maxRedirects + */ + public function setMaxRedirects($maxRedirects) + { + $this->maxRedirects = $maxRedirects < 0 ? -1 : $maxRedirects; + $this->followRedirects = -1 != $this->maxRedirects; + } /** * Sets the insulated flag. @@ -277,6 +295,12 @@ abstract class Client */ public function request($method, $uri, array $parameters = array(), array $files = array(), array $server = array(), $content = null, $changeHistory = true) { + if ($this->isMainRequest) { + $this->redirectCount = 0; + } else { + ++$this->redirectCount; + } + $uri = $this->getAbsoluteUri($uri); $server = array_merge($this->server, $server); @@ -456,7 +480,19 @@ abstract class Client throw new \LogicException('The request was not redirected.'); } - return $this->request('get', $this->redirect); + if (-1 !== $this->maxRedirects) { + if ($this->redirectCount > $this->maxRedirects) { + throw new \LogicException(sprintf('The maximum number (%d) of redirections was reached.', $this->maxRedirects)); + } + } + + $this->isMainRequest = false; + + $response = $this->request('get', $this->redirect); + + $this->isMainRequest = true; + + return $response; } /** diff --git a/src/Symfony/Component/BrowserKit/Tests/ClientTest.php b/src/Symfony/Component/BrowserKit/Tests/ClientTest.php index 82322acc5c..3f96091c12 100644 --- a/src/Symfony/Component/BrowserKit/Tests/ClientTest.php +++ b/src/Symfony/Component/BrowserKit/Tests/ClientTest.php @@ -349,6 +349,27 @@ class ClientTest extends \PHPUnit_Framework_TestCase $this->assertEquals('http://www.example.com/redirected', $client->getRequest()->getUri(), '->followRedirect() automatically follows redirects if followRedirects is true'); } + + public function testFollowRedirectWithMaxRedirects() + { + $client = new TestClient(); + $client->setMaxRedirects(1); + $client->setNextResponse(new Response('', 302, array('Location' => 'http://www.example.com/redirected'))); + $client->request('GET', 'http://www.example.com/foo/foobar'); + $this->assertEquals('http://www.example.com/redirected', $client->getRequest()->getUri(), '->followRedirect() follows a redirect if any'); + + $client->setNextResponse(new Response('', 302, array('Location' => 'http://www.example.com/redirected2'))); + try { + $client->followRedirect(); + $this->fail('->followRedirect() throws a \LogicException if the request was redirected and limit of redirections was reached'); + } catch (\Exception $e) { + $this->assertInstanceof('LogicException', $e, '->followRedirect() throws a \LogicException if the request was redirected and limit of redirections was reached'); + } + + $client->setNextResponse(new Response('', 302, array('Location' => 'http://www.example.com/redirected'))); + $client->request('GET', 'http://www.example.com/foo/foobar'); + $this->assertEquals('http://www.example.com/redirected', $client->getRequest()->getUri(), '->followRedirect() follows a redirect if any'); + } public function testFollowRedirectWithCookies() {