Permalink
Browse files

Merge pull request #10876 from cakephp/client-redirects

Move redirects handling to the Client.
  • Loading branch information...
markstory committed Jul 9, 2017
2 parents be4dd7b + bcd9407 commit 1d3c5732d60457ce969fb4c80d1ca8e0494d1274
Showing with 124 additions and 0 deletions.
  1. +38 −0 src/Http/Client.php
  2. +86 −0 tests/TestCase/Http/ClientTest.php
View
@@ -19,6 +19,7 @@
use Cake\Http\Client\CookieCollection;
use Cake\Http\Client\Request;
use Cake\Utility\Hash;
use Zend\Diactoros\Uri;
/**
* The end user interface for doing HTTP requests.
@@ -370,6 +371,43 @@ protected function _mergeOptions($options)
* @return \Cake\Http\Client\Response
*/
public function send(Request $request, $options = [])
{
$redirects = 0;
if (isset($options['redirect'])) {
$redirects = (int)$options['redirect'];
unset($options['redirect']);
}
do {
$response = $this->_sendRequest($request, $options);
$handleRedirect = $response->isRedirect() && $redirects-- > 0;
if ($handleRedirect) {
$url = $request->getUri();
$request->cookie($this->_cookies->get($url));
$location = $response->getHeaderLine('Location');
$locationUrl = $this->buildUrl($location, [], [
'host' => $url->getHost(),
'port' => $url->getPort(),
'scheme' => $url->getScheme()
]);
$request = $request->withUri(new Uri($locationUrl));
}
} while ($handleRedirect);
return $response;
}
/**
* Send a request without redirection.
*
* @param \Cake\Http\Client\Request $request The request to send.
* @param array $options Additional options to use.
* @return \Cake\Http\Client\Response
*/
protected function _sendRequest(Request $request, $options)
{
$responses = $this->_adapter->send($request, $options);
$url = $request->getUri();
@@ -659,4 +659,90 @@ public function testHeadQuerystring()
]);
$this->assertSame($result, $response);
}
/**
* test redirects
*
* @return void
*/
public function testRedirects()
{
$url = 'http://cakephp.org';
$adapter = $this->getMockBuilder(Client\Adapter\Stream::class)
->setMethods(['send'])
->getMock();
$redirect = new Response([
'HTTP/1.0 301',
'Location: http://cakephp.org/redirect1?foo=bar',
'Set-Cookie: redirect1=true;path=/',
]);
$adapter->expects($this->at(0))
->method('send')
->with(
$this->callback(function ($request) use ($url) {
$this->assertInstanceOf(Request::class, $request);
$this->assertEquals($url, $request->getUri());
return true;
}),
$this->callback(function ($options) {
$this->assertArrayNotHasKey('redirect', $options);
return true;
})
)
->willReturn([$redirect]);
$redirect2 = new Response([
'HTTP/1.0 301',
'Location: /redirect2#foo',
'Set-Cookie: redirect2=true;path=/',
]);
$adapter->expects($this->at(1))
->method('send')
->with(
$this->callback(function ($request) use ($url) {
$this->assertInstanceOf(Request::class, $request);
$this->assertEquals($url . '/redirect1?foo=bar', $request->getUri());
return true;
}),
$this->callback(function ($options) {
$this->assertArrayNotHasKey('redirect', $options);
return true;
})
)
->willReturn([$redirect2]);
$response = new Response([
'HTTP/1.0 200'
]);
$adapter->expects($this->at(2))
->method('send')
->with($this->callback(function ($request) use ($url) {
$this->assertInstanceOf(Request::class, $request);
$this->assertEquals($url . '/redirect2#foo', $request->getUri());
return true;
}))
->willReturn([$response]);
$client = new Client([
'adapter' => $adapter
]);
$result = $client->send(new Request($url), [
'redirect' => 10
]);
$this->assertInstanceOf(Response::class, $result);
$this->assertTrue($result->isOk());
$cookies = $client->cookies()->get($url);
$this->assertArrayHasKey('redirect1', $cookies);
$this->assertArrayHasKey('redirect2', $cookies);
}
}

0 comments on commit 1d3c573

Please sign in to comment.