[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 * added a timeline panel
* The toolbar position can now be configured via the `position` option (can be `top` or `bottom`) * 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 ### Config
* added a way to add documentation on configuration * added a way to add documentation on configuration

View File

@ -31,35 +31,51 @@ class CookieJar
*/ */
public function set(Cookie $cookie) public function set(Cookie $cookie)
{ {
$this->cookieJar[$cookie->getName()] = $cookie; $this->cookieJar[$cookie->getDomain()][$cookie->getPath()][$cookie->getName()] = $cookie;
} }
/** /**
* Gets a cookie by name. * 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 * @return Cookie|null A Cookie instance or null if the cookie does not exist
* *
* @api * @api
*/ */
public function get($name) public function get($name, $path = '/', $domain = null)
{ {
$this->flushExpiredCookies(); $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. * 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 * @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. * Updates the cookie jar from a Response object.
* *
* @param Response $response 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) public function updateFromResponse(Response $response, $uri = null)
{ {
@ -94,13 +110,22 @@ class CookieJar
{ {
$this->flushExpiredCookies(); $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. * 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 * @param Boolean $returnsRawValue Returns raw value or urldecoded value
* *
* @return array An array of cookie values * @return array An array of cookie values
@ -110,25 +135,28 @@ class CookieJar
$this->flushExpiredCookies(); $this->flushExpiredCookies();
$parts = array_replace(array('path' => '/'), parse_url($uri)); $parts = array_replace(array('path' => '/'), parse_url($uri));
$cookies = array(); $cookies = array();
foreach ($this->cookieJar as $cookie) { foreach ($this->cookieJar as $domain => $pathCookies) {
if ($cookie->getDomain()) { if ($domain) {
$domain = ltrim($cookie->getDomain(), '.'); $domain = ltrim($domain, '.');
if ($domain != substr($parts['host'], -strlen($domain))) { if ($domain != substr($parts['host'], -strlen($domain))) {
continue; continue;
} }
} }
if ($cookie->getPath() != substr($parts['path'], 0, strlen($cookie->getPath()))) { foreach ($pathCookies as $path => $namedCookies) {
continue; if ($path != substr($parts['path'], 0, strlen($path))) {
} continue;
}
if ($cookie->isSecure() && 'https' != $parts['scheme']) { foreach ($namedCookies as $name => $cookie) {
continue; 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; return $cookies;
@ -151,10 +179,13 @@ class CookieJar
*/ */
public function flushExpiredCookies() public function flushExpiredCookies()
{ {
$cookies = $this->cookieJar; foreach ($this->cookieJar as $domain => $pathCookies) {
foreach ($cookies as $name => $cookie) { foreach ($pathCookies as $path => $namedCookies) {
if ($cookie->isExpired()) { foreach ($namedCookies as $name => $cookie) {
unset($this->cookieJar[$name]); 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($cookie1 = new Cookie('foo', 'bar'));
$cookieJar->set($cookie2 = new Cookie('bar', 'foo')); $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() 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://www.example.com/', array('foo_nothing', 'foo_domain')),
array('http://foo.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('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://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')), 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=baz'), $cookieJar->allValues('/'));
$this->assertEquals(array('foo' => 'bar%3Dbaz'), $cookieJar->allRawValues('/')); $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/'));
}
} }