Skip to content

Commit

Permalink
Added the possibility to set cookies with the same name for different…
Browse files Browse the repository at this point in the history
… domains and paths for Symfony\Component\HttpFoundation\ResponseHeaderBag

ResponseHeaderBag::hasCookie() and ResponseHeaderBag::getCookie() were removed
  • Loading branch information
francisbesset committed Jul 11, 2011
1 parent f08eeb4 commit f91f4dd
Show file tree
Hide file tree
Showing 5 changed files with 99 additions and 41 deletions.
67 changes: 36 additions & 31 deletions src/Symfony/Component/HttpFoundation/ResponseHeaderBag.php
Expand Up @@ -18,6 +18,9 @@
*/
class ResponseHeaderBag extends HeaderBag
{
const COOKIES_FLAT = 'flat';
const COOKIES_ARRAY = 'array';

protected $computedCacheControl = array();
protected $cookies = array();

Expand All @@ -41,7 +44,7 @@ public function __construct(array $headers = array())
public function __toString()
{
$cookies = '';
foreach ($this->cookies as $cookie) {
foreach ($this->getCookies() as $cookie) {
$cookies .= 'Set-Cookie: '.$cookie."\r\n";
}

Expand Down Expand Up @@ -111,57 +114,59 @@ public function getCacheControlDirective($key)
*/
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]);

if (empty($this->cookies[$domain])) {
unset($this->cookies[$domain]);
}
}
}

/**
* Returns a cookie
* Returns an array with all cookies
*
* @param string $name
* @param string $format
*
* @throws \InvalidArgumentException When the cookie does not exist
* @throws \InvalidArgumentException When the $format is invalid
*
* @return Cookie
* @return array
*/
public function getCookie($name)
public function getCookies($format = 'flat')
{
if (!$this->hasCookie($name)) {
throw new \InvalidArgumentException(sprintf('There is no cookie with name "%s".', $name));
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))));
}

return $this->cookies[$name];
}
if (static::COOKIES_ARRAY === $format) {
return $this->cookies;
}

/**
* Returns an array with all cookies
*
* @return array
*/
public function getCookies()
{
return $this->cookies;
$return = array();
foreach ($this->cookies as $path) {
foreach ($path as $cookies) {
foreach ($cookies as $cookie) {
$return[] = $cookie;
}
}
}

return $return;
}

/**
Expand Down
Expand Up @@ -75,4 +75,47 @@ public function testToStringIncludesCookieHeaders()

$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']));
}
}
Expand Up @@ -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;

Expand All @@ -25,20 +26,21 @@ public function testLogout()

$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());
Expand Down
Expand Up @@ -19,6 +19,7 @@
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;
Expand Down Expand Up @@ -281,11 +282,13 @@ public function testLoginSuccessSetsCookieWhenLoggedInWithNonRememberMeTokenInte
;
$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());
Expand Down
Expand Up @@ -19,6 +19,7 @@
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;
Expand Down Expand Up @@ -184,11 +185,13 @@ public function testLoginSuccessIgnoresTokensWhichDoNotContainAnUserInterfaceImp
->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()
Expand All @@ -215,11 +218,13 @@ public function testLoginSuccess()
->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());
Expand Down

1 comment on commit f91f4dd

@lsmith77
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"ResponseHeaderBag::hasCookie() and ResponseHeaderBag::getCookie() were removed"

why?

Please sign in to comment.