1
0
mirror of https://github.com/guzzle/guzzle.git synced 2025-02-25 02:22:57 +01:00

Merge pull request #550 from kkopachev/rfc6265-cookie-path

RFC6265 compliant cookie default path and path mathing
This commit is contained in:
Michael Dowling 2014-02-07 11:57:56 -08:00
commit 246cd09118
4 changed files with 175 additions and 6 deletions

View File

@ -36,7 +36,7 @@ class CookieParser implements CookieParserInterface
$data = array_merge(array_fill_keys(array_keys(self::$cookieParts), null), array(
'cookies' => array(),
'data' => array(),
'path' => $path ?: '/',
'path' => null,
'http_only' => false,
'discard' => false,
'domain' => $host
@ -81,6 +81,51 @@ class CookieParser implements CookieParserInterface
$data['expires'] = time() + (int) $data['max_age'];
}
// Check path attribute according RFC6265 http://tools.ietf.org/search/rfc6265#section-5.2.4
// "If the attribute-value is empty or if the first character of the
// attribute-value is not %x2F ("/"):
// Let cookie-path be the default-path.
// Otherwise:
// Let cookie-path be the attribute-value."
if (!$data['path'] || substr($data['path'], 0, 1) !== '/') {
$data['path'] = $this->getDefaultPath($path);
}
return $data;
}
/**
* Get default cookie path according to RFC 6265
* http://tools.ietf.org/search/rfc6265#section-5.1.4 Paths and Path-Match
*
* @param string $path Request uri-path
*
* @return string
*/
protected function getDefaultPath($path) {
// "The user agent MUST use an algorithm equivalent to the following algorithm
// to compute the default-path of a cookie:"
// "2. If the uri-path is empty or if the first character of the uri-path is not
// a %x2F ("/") character, output %x2F ("/") and skip the remaining steps.
if (empty($path) || substr($path, 0, 1) !== '/') {
return '/';
}
// "3. If the uri-path contains no more than one %x2F ("/") character, output
// %x2F ("/") and skip the remaining step."
if ($path === "/") {
return $path;
}
$rightSlashPos = strrpos($path, '/');
if ($rightSlashPos === 0) {
return "/";
}
// "4. Output the characters of the uri-path from the first character up to,
// but not including, the right-most %x2F ("/")."
return substr($path, 0, $rightSlashPos);
}
}

View File

@ -412,7 +412,32 @@ class Cookie implements ToArrayInterface
*/
public function matchesPath($path)
{
return !$this->getPath() || 0 === stripos($path, $this->getPath());
// RFC6265 http://tools.ietf.org/search/rfc6265#section-5.1.4
// A request-path path-matches a given cookie-path if at least one of
// the following conditions holds:
// o The cookie-path and the request-path are identical.
if ($path == $this->getPath()) {
return true;
}
$pos = stripos($path, $this->getPath());
if ($pos === 0) {
// o The cookie-path is a prefix of the request-path, and the last
// character of the cookie-path is %x2F ("/").
if (substr($this->getPath(), -1, 1) === "/") {
return true;
}
// o The cookie-path is a prefix of the request-path, and the first
// character of the request-path that is not included in the cookie-
// path is a %x2F ("/") character.
if (substr($path, strlen($this->getPath()), 1) === "/") {
return true;
}
}
return false;
}
/**

View File

@ -107,7 +107,7 @@ class CookieParserProvider extends \Guzzle\Tests\GuzzleTestCase
),
// Tests getting the domain and path from a reference request
array(array(
'foo=1; port="80,8081"; httponly', 'foo=1; port="80,8081"; domain=www.test.com; HttpOnly;', 'foo=1; ; domain=www.test.com; path=/path/; port="80,8081"; HttpOnly;'),
'foo=1; port="80,8081"; httponly', 'foo=1; port="80,8081"; domain=www.test.com; HttpOnly;', 'foo=1; ; domain=www.test.com; path=/path; port="80,8081"; HttpOnly;'),
array(
'cookies' => array(
'foo' => 1
@ -117,7 +117,7 @@ class CookieParserProvider extends \Guzzle\Tests\GuzzleTestCase
'domain' => 'www.test.com',
'expires' => null,
'max_age' => null,
'path' => '/path/',
'path' => '/path',
'port' => array('80', '8081'),
'secure' => null,
'version' => null,
@ -135,7 +135,6 @@ class CookieParserProvider extends \Guzzle\Tests\GuzzleTestCase
'justacookie' => 'foo'
),
'domain' => 'example.com',
'path' => '',
'data' => array(),
'discard' => null,
'expires' => null,
@ -249,6 +248,91 @@ class CookieParserProvider extends \Guzzle\Tests\GuzzleTestCase
'http_only' => false
)
),
// rfc6265#section-5.1.4
array(
'cookie=value',
array(
'cookies' => array(
'cookie' => 'value'
),
'domain' => 'example.com',
'data' => array(),
'discard' => null,
'expires' => null,
'max_age' => null,
'path' => '/some/path',
'port' => null,
'secure' => null,
'version' => null,
'comment' => null,
'comment_url' => null,
'http_only' => false
),
'http://example.com/some/path/test.html'
),
array(
'empty=path',
array(
'cookies' => array(
'empty' => 'path'
),
'domain' => 'example.com',
'data' => array(),
'discard' => null,
'expires' => null,
'max_age' => null,
'path' => '/',
'port' => null,
'secure' => null,
'version' => null,
'comment' => null,
'comment_url' => null,
'http_only' => false
),
'http://example.com/test.html'
),
array(
'baz=qux',
array(
'cookies' => array(
'baz' => 'qux'
),
'domain' => 'example.com',
'data' => array(),
'discard' => null,
'expires' => null,
'max_age' => null,
'path' => '/',
'port' => null,
'secure' => null,
'version' => null,
'comment' => null,
'comment_url' => null,
'http_only' => false
),
'http://example.com?query=here'
),
array(
'test=noSlashPath; path=someString',
array(
'cookies' => array(
'test' => 'noSlashPath'
),
'domain' => 'example.com',
'data' => array(),
'discard' => null,
'expires' => null,
'max_age' => null,
'path' => '/real/path',
'port' => null,
'secure' => null,
'version' => null,
'comment' => null,
'comment_url' => null,
'http_only' => false
),
'http://example.com/real/path/'
),
);
}

View File

@ -164,9 +164,24 @@ class CookieTest extends \Guzzle\Tests\GuzzleTestCase
$this->assertTrue($cookie->matchesPath('/foo'));
$cookie->setPath('/foo');
// o The cookie-path and the request-path are identical.
$this->assertTrue($cookie->matchesPath('/foo'));
$this->assertTrue($cookie->matchesPath('/foo/bar'));
$this->assertFalse($cookie->matchesPath('/bar'));
// o The cookie-path is a prefix of the request-path, and the first
// character of the request-path that is not included in the cookie-
// path is a %x2F ("/") character.
$this->assertTrue($cookie->matchesPath('/foo/bar'));
$this->assertFalse($cookie->matchesPath('/fooBar'));
// o The cookie-path is a prefix of the request-path, and the last
// character of the cookie-path is %x2F ("/").
$cookie->setPath('/foo/');
$this->assertTrue($cookie->matchesPath('/foo/bar'));
$this->assertFalse($cookie->matchesPath('/fooBaz'));
$this->assertFalse($cookie->matchesPath('/foo'));
}
public function cookieValidateProvider()