Quellcode durchsuchen

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
Francis Besset vor 14 Jahren
Ursprung
Commit
f91f4dda13

+ 36 - 31
src/Symfony/Component/HttpFoundation/ResponseHeaderBag.php

@@ -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]);
+
+            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;
     }
 
     /**

+ 43 - 0
tests/Symfony/Tests/Component/HttpFoundation/ResponseHeaderBagTest.php

@@ -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']));
+    }
 }

+ 6 - 4
tests/Symfony/Tests/Component/Security/Http/Logout/CookieClearingLogoutHandlerTest.php

@@ -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());

+ 5 - 2
tests/Symfony/Tests/Component/Security/Http/RememberMe/PersistentTokenBasedRememberMeServicesTest.php

@@ -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());

+ 9 - 4
tests/Symfony/Tests/Component/Security/Http/RememberMe/TokenBasedRememberMeServicesTest.php

@@ -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());