Added the possibility to set cookies with the same name for different domains and paths for Symfony\Component\HttpFoundation\ResponseHeaderBag

ResponseHeaderBag::hasCookie() and ResponseHeaderBag::getCookie() were removed
This commit is contained in:
Francis Besset 2011-07-11 22:54:08 +02:00
parent f08eeb4433
commit f91f4dda13
5 changed files with 100 additions and 42 deletions

View File

@ -18,6 +18,9 @@ namespace Symfony\Component\HttpFoundation;
*/
class ResponseHeaderBag extends HeaderBag
{
const COOKIES_FLAT = 'flat';
const COOKIES_ARRAY = 'array';
protected $computedCacheControl = array();
protected $cookies = array();
@ -41,7 +44,7 @@ class ResponseHeaderBag extends HeaderBag
public function __toString()
{
$cookies = '';
foreach ($this->cookies as $cookie) {
foreach ($this->getCookies() as $cookie) {
$cookies .= 'Set-Cookie: '.$cookie."\r\n";
}
@ -111,57 +114,59 @@ class ResponseHeaderBag extends HeaderBag
*/
public function setCookie(Cookie $cookie)
{
$this->cookies[$cookie->getName()] = $cookie;
$this->cookies[$cookie->getDomain()][$cookie->getPath()][$cookie->getName()] = $cookie;
}
/**
* Removes a cookie from the array, but does not unset it in the browser
*
* @param string $name
* @param string $path
* @param string $domain
* @return void
*/
public function removeCookie($name)
public function removeCookie($name, $path = null, $domain = null)
{
unset($this->cookies[$name]);
}
unset($this->cookies[$domain][$path][$name]);
/**
* Whether the array contains any cookie with this name
*
* @param string $name
* @return Boolean
*/
public function hasCookie($name)
{
return isset($this->cookies[$name]);
}
if (empty($this->cookies[$domain][$path])) {
unset($this->cookies[$domain][$path]);
/**
* Returns a cookie
*
* @param string $name
*
* @throws \InvalidArgumentException When the cookie does not exist
*
* @return Cookie
*/
public function getCookie($name)
{
if (!$this->hasCookie($name)) {
throw new \InvalidArgumentException(sprintf('There is no cookie with name "%s".', $name));
if (empty($this->cookies[$domain])) {
unset($this->cookies[$domain]);
}
}
return $this->cookies[$name];
}
/**
* Returns an array with all cookies
*
* @param string $format
*
* @throws \InvalidArgumentException When the $format is invalid
*
* @return array
*/
public function getCookies()
public function getCookies($format = 'flat')
{
return $this->cookies;
if (!in_array($format, array(static::COOKIES_FLAT, static::COOKIES_ARRAY))) {
throw new \InvalidArgumentException(sprintf('Format "%s" invalid (%s).', $format, implode(', ', array(static::COOKIES_FLAT, static::COOKIES_ARRAY))));
}
if (static::COOKIES_ARRAY === $format) {
return $this->cookies;
}
$return = array();
foreach ($this->cookies as $path) {
foreach ($path as $cookies) {
foreach ($cookies as $cookie) {
$return[] = $cookie;
}
}
}
return $return;
}
/**

View File

@ -75,4 +75,47 @@ class ResponseHeaderBagTest extends \PHPUnit_Framework_TestCase
$this->assertContains("Set-Cookie: foo=deleted; expires=".gmdate("D, d-M-Y H:i:s T", time() - 31536001)."; httponly", explode("\r\n", $bag->__toString()));
}
public function testCookiesWithSameNames()
{
$bag = new ResponseHeaderBag();
$bag->setCookie(new Cookie('foo', 'bar', 0, '/path/foo', 'foo.bar'));
$bag->setCookie(new Cookie('foo', 'bar', 0, '/path/bar', 'foo.bar'));
$bag->setCookie(new Cookie('foo', 'bar', 0, '/path/bar', 'bar.foo'));
$bag->setCookie(new Cookie('foo', 'bar'));
$this->assertEquals(4, count($bag->getCookies()));
$headers = explode("\r\n", $bag->__toString());
$this->assertContains("Set-Cookie: foo=bar; path=/path/foo; domain=foo.bar; httponly", $headers);
$this->assertContains("Set-Cookie: foo=bar; path=/path/foo; domain=foo.bar; httponly", $headers);
$this->assertContains("Set-Cookie: foo=bar; path=/path/bar; domain=bar.foo; httponly", $headers);
$this->assertContains("Set-Cookie: foo=bar; path=/; httponly", $headers);
$cookies = $bag->getCookies(ResponseHeaderBag::COOKIES_ARRAY);
$this->assertTrue(isset($cookies['foo.bar']['/path/foo']['foo']));
$this->assertTrue(isset($cookies['foo.bar']['/path/bar']['foo']));
$this->assertTrue(isset($cookies['bar.foo']['/path/bar']['foo']));
$this->assertTrue(isset($cookies['']['/']['foo']));
}
public function testRemoveCookie()
{
$bag = new ResponseHeaderBag();
$bag->setCookie(new Cookie('foo', 'bar', 0, '/path/foo', 'foo.bar'));
$bag->setCookie(new Cookie('bar', 'foo', 0, '/path/bar', 'foo.bar'));
$cookies = $bag->getCookies(ResponseHeaderBag::COOKIES_ARRAY);
$this->assertTrue(isset($cookies['foo.bar']['/path/foo']));
$bag->removeCookie('foo', '/path/foo', 'foo.bar');
$cookies = $bag->getCookies(ResponseHeaderBag::COOKIES_ARRAY);
$this->assertFalse(isset($cookies['foo.bar']['/path/foo']));
$bag->removeCookie('bar', '/path/bar', 'foo.bar');
$cookies = $bag->getCookies(ResponseHeaderBag::COOKIES_ARRAY);
$this->assertFalse(isset($cookies['foo.bar']));
}
}

View File

@ -12,6 +12,7 @@
namespace Symfony\Tests\Component\Security\Http\Logout;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\ResponseHeaderBag;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Http\Logout\CookieClearingLogoutHandler;
@ -25,20 +26,21 @@ class CookieClearingLogoutHandlerTest extends \PHPUnit_Framework_TestCase
$handler = new CookieClearingLogoutHandler(array('foo' => array('path' => '/foo', 'domain' => 'foo.foo'), 'foo2' => array('path' => null, 'domain' => null)));
$this->assertFalse($response->headers->hasCookie('foo'));
$cookies = $response->headers->getCookies();
$this->assertEquals(0, count($cookies));
$handler->logout($request, $response, $token);
$cookies = $response->headers->getCookies();
$cookies = $response->headers->getCookies(ResponseHeaderBag::COOKIES_ARRAY);
$this->assertEquals(2, count($cookies));
$cookie = $cookies['foo'];
$cookie = $cookies['foo.foo']['/foo']['foo'];
$this->assertEquals('foo', $cookie->getName());
$this->assertEquals('/foo', $cookie->getPath());
$this->assertEquals('foo.foo', $cookie->getDomain());
$this->assertTrue($cookie->isCleared());
$cookie = $cookies['foo2'];
$cookie = $cookies['']['']['foo2'];
$this->assertStringStartsWith('foo2', $cookie->getName());
$this->assertNull($cookie->getPath());
$this->assertNull($cookie->getDomain());

View File

@ -19,6 +19,7 @@ use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
use Symfony\Component\Security\Core\Authentication\RememberMe\PersistentToken;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\ResponseHeaderBag;
use Symfony\Component\Security\Http\RememberMe\PersistentTokenBasedRememberMeServices;
use Symfony\Component\Security\Core\Exception\TokenNotFoundException;
use Symfony\Component\Security\Core\Exception\CookieTheftException;
@ -281,11 +282,13 @@ class PersistentTokenBasedRememberMeServicesTest extends \PHPUnit_Framework_Test
;
$service->setTokenProvider($tokenProvider);
$this->assertFalse($response->headers->hasCookie('foo'));
$cookies = $response->headers->getCookies();
$this->assertEquals(0, count($cookies));
$service->loginSuccess($request, $response, $token);
$cookie = $response->headers->getCookie('foo');
$cookies = $response->headers->getCookies(ResponseHeaderBag::COOKIES_ARRAY);
$cookie = $cookies['myfoodomain.foo']['/foo/path']['foo'];
$this->assertFalse($cookie->isCleared());
$this->assertTrue($cookie->isSecure());
$this->assertTrue($cookie->isHttpOnly());

View File

@ -19,6 +19,7 @@ use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
use Symfony\Component\Security\Core\Authentication\RememberMe\PersistentToken;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\ResponseHeaderBag;
use Symfony\Component\Security\Http\RememberMe\TokenBasedRememberMeServices;
use Symfony\Component\Security\Core\Exception\TokenNotFoundException;
use Symfony\Component\Security\Core\Exception\CookieTheftException;
@ -184,11 +185,13 @@ class TokenBasedRememberMeServicesTest extends \PHPUnit_Framework_TestCase
->will($this->returnValue('foo'))
;
$this->assertFalse($response->headers->hasCookie('foo'));
$cookies = $response->headers->getCookies();
$this->assertEquals(0, count($cookies));
$service->loginSuccess($request, $response, $token);
$this->assertFalse($response->headers->hasCookie('foo'));
$cookies = $response->headers->getCookies();
$this->assertEquals(0, count($cookies));
}
public function testLoginSuccess()
@ -215,11 +218,13 @@ class TokenBasedRememberMeServicesTest extends \PHPUnit_Framework_TestCase
->will($this->returnValue($user))
;
$this->assertFalse($response->headers->hasCookie('foo'));
$cookies = $response->headers->getCookies();
$this->assertEquals(0, count($cookies));
$service->loginSuccess($request, $response, $token);
$cookie = $response->headers->getCookie('foo');
$cookies = $response->headers->getCookies(ResponseHeaderBag::COOKIES_ARRAY);
$cookie = $cookies['myfoodomain.foo']['/foo/path']['foo'];
$this->assertFalse($cookie->isCleared());
$this->assertTrue($cookie->isSecure());
$this->assertTrue($cookie->isHttpOnly());