Skip to content
This repository has been archived by the owner on Jan 8, 2020. It is now read-only.

Commit

Permalink
Merge branch 'hotfix/4215' into develop
Browse files Browse the repository at this point in the history
Close #4215
  • Loading branch information
weierophinney committed Apr 22, 2013
2 parents 6adeba3 + 9d50a29 commit 126400d
Show file tree
Hide file tree
Showing 2 changed files with 208 additions and 27 deletions.
94 changes: 67 additions & 27 deletions library/Zend/Http/Client.php
Expand Up @@ -298,8 +298,18 @@ public function getRedirectionsCount()
public function setUri($uri)
{
if (!empty($uri)) {
// remember host of last request
$lastHost = $this->getRequest()->getUri()->getHost();
$this->getRequest()->setUri($uri);

// if host changed, the HTTP authentication should be cleared for security
// reasons, see #4215 for a discussion - currently authentication is also
// cleared for peer subdomains due to technical limits
$nextHost = $this->getRequest()->getUri()->getHost();
if (!preg_match('/' . preg_quote($lastHost, '/') . '$/i', $nextHost)) {
$this->clearAuth();
}

// Set auth if username and password has been specified in the uri
if ($this->getUri()->getUser() && $this->getUri()->getPassword()) {
$this->setAuth($this->getUri()->getUser(), $this->getUri()->getPassword());
Expand Down Expand Up @@ -444,6 +454,37 @@ public function setParameterGet(array $query)
return $this;
}

/**
* Reset all the HTTP parameters (request, response, etc)
*
* @param bool $clearCookies Also clear all valid cookies? (defaults to false)
* @param bool $clearAuth Also clear http authentication? (defaults to true)
* @return Client
*/
public function resetParameters($clearCookies = false, $clearAuth = true)
{
$uri = $this->getUri();

$this->streamName = null;
$this->encType = null;
$this->request = null;
$this->response = null;
$this->lastRawRequest = null;
$this->lastRawResponse = null;

$this->setUri($uri);

if ($clearCookies) {
$this->clearCookies();
}

if ($clearAuth) {
$this->clearAuth();
}

return $this;
}

/**
* Return the current cookies
*
Expand Down Expand Up @@ -673,6 +714,14 @@ public function setAuth($user, $password, $type = self::AUTH_BASIC)
return $this;
}

/**
* Clear http authentication
*/
public function clearAuth()
{
$this->auth = array();
}

/**
* Calculate the response value according to the HTTP authentication type
*
Expand Down Expand Up @@ -728,31 +777,6 @@ protected function calcAuthDigest($user, $password, $type = self::AUTH_BASIC, $d
return $response;
}

/**
* Reset all the HTTP parameters (auth,cookies,request, response, etc)
*
* @param bool $clearCookies Also clear all valid cookies? (defaults to false)
* @return Client
*/
public function resetParameters($clearCookies = false)
{
$uri = $this->getUri();

$this->auth = null;
$this->streamName = null;
$this->encType = null;
$this->request = null;
$this->response = null;

$this->setUri($uri);

if ($clearCookies) {
$this->clearCookies();
}

return $this;
}

/**
* Dispatch
*
Expand Down Expand Up @@ -897,13 +921,15 @@ public function send(Request $request = null)
((! $this->config['strictredirects']) && ($response->getStatusCode() == 302 ||
$response->getStatusCode() == 301))) {

$this->resetParameters();
$this->resetParameters(false, false);
$this->setMethod(Request::METHOD_GET);
}


// If we got a well formed absolute URI
if (($scheme = substr($location, 0, 6)) &&
($scheme == 'http:/' || $scheme == 'https:')) {
// setURI() clears parameters if host changed, see #4215
$this->setUri($location);
} else {

Expand Down Expand Up @@ -933,12 +959,26 @@ public function send(Request $request = null)
break;
}

} while ($this->redirectCounter < $this->config['maxredirects']);
} while ($this->redirectCounter <= $this->config['maxredirects']);

$this->response = $response;
return $response;
}

/**
* Fully reset the HTTP client (auth, cookies, request, response, etc.)
*
* @return Client
*/
public function reset()
{
$this->resetParameters();
$this->clearAuth();
$this->clearCookies();

return $this;
}

/**
* Set a file to upload (using a POST request)
*
Expand Down
141 changes: 141 additions & 0 deletions tests/ZendTest/Http/ClientTest.php
Expand Up @@ -18,6 +18,7 @@
use Zend\Http\Header\SetCookie;
use Zend\Http\Request;
use Zend\Http\Response;
use Zend\Http\Client\Adapter\Test;


class ClientTest extends \PHPUnit_Framework_TestCase
Expand Down Expand Up @@ -198,4 +199,144 @@ public function testEncodeAuthHeaderThrowsExceptionWhenInvalidAuthTypeIsUsed()
{
$encoded = Client::encodeAuthHeader('test', 'test', 'test');
}

public function testIfMaxredirectWorksCorrectly()
{
$testAdapter = new Test();
// first response, contains a redirect
$testAdapter->setResponse(
"HTTP/1.1 303 See Other\r\n"
. "Location: http://www.example.org/part2\r\n\r\n"
. "Page #1"
);
// seconds response, contains a redirect
$testAdapter->addResponse(
"HTTP/1.1 303 See Other\r\n"
. "Location: http://www.example.org/part3\r\n\r\n"
. "Page #2"
);
// third response
$testAdapter->addResponse(
"HTTP/1.1 303 See Other\r\n\r\n"
. "Page #3"
);

// create a client which allows one redirect at most!
$client = new Client('http://www.example.org/part1', array(
'adapter' => $testAdapter,
'maxredirects' => 1,
'storeresponse' => true
));

// do the request
$response = $client->setMethod('GET')->send();

// response should be the second response, since third response should not
// be requested, due to the maxredirects = 1 limit
$this->assertEquals($response->getContent(), "Page #2");
}

public function testIfClientDoesNotLooseAuthenticationOnRedirect()
{
// set up user credentials
$user = 'username123';
$password = 'password456';
$encoded = Client::encodeAuthHeader($user, $password, Client::AUTH_BASIC);

// set up two responses that simulate a redirection
$testAdapter = new Test();
$testAdapter->setResponse(
"HTTP/1.1 303 See Other\r\n"
. "Location: http://www.example.org/part2\r\n\r\n"
. "The URL of this page has changed."
);
$testAdapter->addResponse(
"HTTP/1.1 200 OK\r\n\r\n"
. "Welcome to this Website."
);

// create client with HTTP basic authentication
$client = new Client('http://www.example.org/part1', array(
'adapter' => $testAdapter,
'maxredirects' => 1
));
$client->setAuth($user, $password, Client::AUTH_BASIC);

// do request
$response = $client->setMethod('GET')->send();

// the last request should contain the Authorization header
$this->assertTrue(strpos($client->getLastRawRequest(), $encoded) !== false);
}

public function testIfClientDoesNotForwardAuthenticationToForeignHost()
{
// set up user credentials
$user = 'username123';
$password = 'password456';
$encoded = Client::encodeAuthHeader($user, $password, Client::AUTH_BASIC);

$testAdapter = new Test();
$client = new Client(null, array('adapter' => $testAdapter));

// set up two responses that simulate a redirection from example.org to example.com
$testAdapter->setResponse(
"HTTP/1.1 303 See Other\r\n"
. "Location: http://example.com/part2\r\n\r\n"
. "The URL of this page has changed."
);
$testAdapter->addResponse(
"HTTP/1.1 200 OK\r\n\r\n"
. "Welcome to this Website."
);

// set auth and do request
$client->setUri('http://example.org/part1')
->setAuth($user, $password, Client::AUTH_BASIC);
$response = $client->setMethod('GET')->send();

// the last request should NOT contain the Authorization header,
// because example.com is different from example.org
$this->assertTrue(strpos($client->getLastRawRequest(), $encoded) === false);

// set up two responses that simulate a rediration from example.org to sub.example.org
$testAdapter->setResponse(
"HTTP/1.1 303 See Other\r\n"
. "Location: http://sub.example.org/part2\r\n\r\n"
. "The URL of this page has changed."
);
$testAdapter->addResponse(
"HTTP/1.1 200 OK\r\n\r\n"
. "Welcome to this Website."
);

// set auth and do request
$client->setUri('http://example.org/part1')
->setAuth($user, $password, Client::AUTH_BASIC);
$response = $client->setMethod('GET')->send();

// the last request should contain the Authorization header,
// because sub.example.org is a subdomain unter example.org
$this->assertFalse(strpos($client->getLastRawRequest(), $encoded) === false);

// set up two responses that simulate a rediration from sub.example.org to example.org
$testAdapter->setResponse(
"HTTP/1.1 303 See Other\r\n"
. "Location: http://example.org/part2\r\n\r\n"
. "The URL of this page has changed."
);
$testAdapter->addResponse(
"HTTP/1.1 200 OK\r\n\r\n"
. "Welcome to this Website."
);

// set auth and do request
$client->setUri('http://sub.example.org/part1')
->setAuth($user, $password, Client::AUTH_BASIC);
$response = $client->setMethod('GET')->send();

// the last request should NOT contain the Authorization header,
// because example.org is not a subdomain unter sub.example.org
$this->assertTrue(strpos($client->getLastRawRequest(), $encoded) === false);
}
}

0 comments on commit 126400d

Please sign in to comment.