[BrowserKit] first attempt at fixing CookieJar (closes #2209)

This commit is contained in:
Fabien Potencier 2011-09-20 20:51:19 +02:00
parent b46114a0f6
commit 66a18f3239
3 changed files with 84 additions and 27 deletions

View File

@ -98,6 +98,10 @@ To get the diff between two versions, go to https://github.com/symfony/symfony/c
* added a timeline panel
* The toolbar position can now be configured via the `position` option (can be `top` or `bottom`)
### BrowserKit
* [BC BREAK] The CookieJar internals have changed to allow cookies with the same name on different sub-domains/sub-paths
### Config
* added a way to add documentation on configuration

View File

@ -31,35 +31,51 @@ class CookieJar
*/
public function set(Cookie $cookie)
{
$this->cookieJar[$cookie->getName()] = $cookie;
$this->cookieJar[$cookie->getDomain()][$cookie->getPath()][$cookie->getName()] = $cookie;
}
/**
* Gets a cookie by name.
*
* @param string $name The cookie name
* @param string $name The cookie name
* @param string $path The cookie path
* @param string $domain The cookie domain
*
* @return Cookie|null A Cookie instance or null if the cookie does not exist
*
* @api
*/
public function get($name)
public function get($name, $path = '/', $domain = null)
{
$this->flushExpiredCookies();
return isset($this->cookieJar[$name]) ? $this->cookieJar[$name] : null;
return isset($this->cookieJar[$domain][$path][$name]) ? $this->cookieJar[$domain][$path][$name] : null;
}
/**
* Removes a cookie by name.
*
* @param string $name The cookie name
* @param string $name The cookie name
* @param string $path The cookie path
* @param string $domain The cookie domain
*
* @api
*/
public function expire($name)
public function expire($name, $path = '/', $domain = null)
{
unset($this->cookieJar[$name]);
if (null === $path) {
$path = '/';
}
unset($this->cookieJar[$domain][$path][$name]);
if (empty($this->cookieJar[$domain][$path])) {
unset($this->cookieJar[$domain][$path]);
if (empty($this->cookieJar[$domain])) {
unset($this->cookieJar[$domain]);
}
}
}
/**
@ -76,7 +92,7 @@ class CookieJar
* Updates the cookie jar from a Response object.
*
* @param Response $response A Response object
* @param string $uri The base URL
* @param string $uri The base URL
*/
public function updateFromResponse(Response $response, $uri = null)
{
@ -94,13 +110,22 @@ class CookieJar
{
$this->flushExpiredCookies();
return $this->cookieJar;
$flattenedCookies = array();
foreach ($this->cookieJar as $path) {
foreach ($path as $cookies) {
foreach ($cookies as $cookie) {
$flattenedCookies[] = $cookie;
}
}
}
return $flattenedCookies;
}
/**
* Returns not yet expired cookie values for the given URI.
*
* @param string $uri A URI
* @param string $uri A URI
* @param Boolean $returnsRawValue Returns raw value or urldecoded value
*
* @return array An array of cookie values
@ -110,25 +135,28 @@ class CookieJar
$this->flushExpiredCookies();
$parts = array_replace(array('path' => '/'), parse_url($uri));
$cookies = array();
foreach ($this->cookieJar as $cookie) {
if ($cookie->getDomain()) {
$domain = ltrim($cookie->getDomain(), '.');
foreach ($this->cookieJar as $domain => $pathCookies) {
if ($domain) {
$domain = ltrim($domain, '.');
if ($domain != substr($parts['host'], -strlen($domain))) {
continue;
}
}
if ($cookie->getPath() != substr($parts['path'], 0, strlen($cookie->getPath()))) {
continue;
}
foreach ($pathCookies as $path => $namedCookies) {
if ($path != substr($parts['path'], 0, strlen($path))) {
continue;
}
if ($cookie->isSecure() && 'https' != $parts['scheme']) {
continue;
}
foreach ($namedCookies as $name => $cookie) {
if ($cookie->isSecure() && 'https' != $parts['scheme']) {
continue;
}
$cookies[$cookie->getName()] = $returnsRawValue ? $cookie->getRawValue() : $cookie->getValue();
$cookies[$cookie->getName()] = $returnsRawValue ? $cookie->getRawValue() : $cookie->getValue();
}
}
}
return $cookies;
@ -151,10 +179,13 @@ class CookieJar
*/
public function flushExpiredCookies()
{
$cookies = $this->cookieJar;
foreach ($cookies as $name => $cookie) {
if ($cookie->isExpired()) {
unset($this->cookieJar[$name]);
foreach ($this->cookieJar as $domain => $pathCookies) {
foreach ($pathCookies as $path => $namedCookies) {
foreach ($namedCookies as $name => $cookie) {
if ($cookie->isExpired()) {
unset($this->cookieJar[$domain][$path][$name]);
}
}
}
}
}

View File

@ -44,7 +44,7 @@ class CookieJarTest extends \PHPUnit_Framework_TestCase
$cookieJar->set($cookie1 = new Cookie('foo', 'bar'));
$cookieJar->set($cookie2 = new Cookie('bar', 'foo'));
$this->assertEquals(array('foo' => $cookie1, 'bar' => $cookie2), $cookieJar->all(), '->all() returns all cookies in the jar');
$this->assertEquals(array($cookie1, $cookie2), $cookieJar->all(), '->all() returns all cookies in the jar');
}
public function testClear()
@ -93,7 +93,7 @@ class CookieJarTest extends \PHPUnit_Framework_TestCase
array('http://www.example.com/', array('foo_nothing', 'foo_domain')),
array('http://foo.example.com/', array('foo_nothing', 'foo_domain')),
array('http://foo.example1.com/', array('foo_nothing')),
array('https://foo.example.com/', array('foo_nothing', 'foo_domain', 'foo_secure')),
array('https://foo.example.com/', array('foo_nothing', 'foo_secure', 'foo_domain')),
array('http://www.example.com/foo/bar', array('foo_nothing', 'foo_path', 'foo_domain')),
array('http://www4.example.com/', array('foo_nothing', 'foo_domain', 'foo_strict_domain')),
);
@ -107,4 +107,26 @@ class CookieJarTest extends \PHPUnit_Framework_TestCase
$this->assertEquals(array('foo' => 'bar=baz'), $cookieJar->allValues('/'));
$this->assertEquals(array('foo' => 'bar%3Dbaz'), $cookieJar->allRawValues('/'));
}
public function testCookieWithSameNameButDifferentPaths()
{
$cookieJar = new CookieJar();
$cookieJar->set($cookie1 = new Cookie('foo', 'bar1', null, '/foo'));
$cookieJar->set($cookie2 = new Cookie('foo', 'bar2', null, '/bar'));
$this->assertEquals(array(), array_keys($cookieJar->allValues('http://example.com/')));
$this->assertEquals(array('foo' => 'bar1'), $cookieJar->allValues('http://example.com/foo'));
$this->assertEquals(array('foo' => 'bar2'), $cookieJar->allValues('http://example.com/bar'));
}
public function testCookieWithSameNameButDifferentDomains()
{
$cookieJar = new CookieJar();
$cookieJar->set($cookie1 = new Cookie('foo', 'bar1', null, '/', 'foo.example.com'));
$cookieJar->set($cookie2 = new Cookie('foo', 'bar2', null, '/', 'bar.example.com'));
$this->assertEquals(array(), array_keys($cookieJar->allValues('http://example.com/')));
$this->assertEquals(array('foo' => 'bar1'), $cookieJar->allValues('http://foo.example.com/'));
$this->assertEquals(array('foo' => 'bar2'), $cookieJar->allValues('http://bar.example.com/'));
}
}