From 0f6dffd9697575cbc360569e881cc7a65b6a8627 Mon Sep 17 00:00:00 2001 From: Mark Story Date: Fri, 24 Mar 2017 12:06:33 -0400 Subject: [PATCH] Allow cookie collections to store duplicates. Duplicate cookie names are required for Http\Client use cases. Because a client can make requests to multiple hosts, we need to store and track all the cookies. This seemed preferrable to having a cookie collection per domain in the client. --- src/Http/Cookie/CookieCollection.php | 35 +++++++++++++------ .../Http/Cookie/CookieCollectionTest.php | 21 ++++++++--- 2 files changed, 42 insertions(+), 14 deletions(-) diff --git a/src/Http/Cookie/CookieCollection.php b/src/Http/Cookie/CookieCollection.php index 5a856ef8bf2..8ca9432dcb9 100644 --- a/src/Http/Cookie/CookieCollection.php +++ b/src/Http/Cookie/CookieCollection.php @@ -65,20 +65,22 @@ public function count() /** * Add a cookie and get an updated collection. * + * Cookie names do not have to be unique in a collection, but + * having duplicate cookie names will change how get() behaves. + * * @param \Cake\Http\Cookie\CookieInterface $cookie Cookie instance to add. * @return static */ public function add(CookieInterface $cookie) { - $key = mb_strtolower($cookie->getName()); $new = clone $this; - $new->cookies[$key] = $cookie; + $new->cookies[] = $cookie; return $new; } /** - * Get a cookie by name + * Get the first cookie by name. * * If the provided name matches a URL (matches `#^https?://#`) this method * will assume you want a list of cookies that match that URL. This is @@ -91,8 +93,10 @@ public function add(CookieInterface $cookie) public function get($name) { $key = mb_strtolower($name); - if (isset($this->cookies[$key])) { - return $this->cookies[$key]; + foreach ($this->cookies as $cookie) { + if (mb_strtolower($cookie->getName()) === $key) { + return $cookie; + } } return null; @@ -106,11 +110,18 @@ public function get($name) */ public function has($name) { - return isset($this->cookies[mb_strtolower($name)]); + $key = mb_strtolower($name); + foreach ($this->cookies as $cookie) { + if (mb_strtolower($cookie->getName()) === $key) { + return true; + } + } + + return false; } /** - * Remove a cookie from the collection and get a new collection + * Create a new collection with all cookies matching $name removed. * * If the cookie is not in the collection, this method will do nothing. * @@ -120,7 +131,12 @@ public function has($name) public function remove($name) { $new = clone $this; - unset($new->cookies[mb_strtolower($name)]); + $key = mb_strtolower($name); + foreach ($new->cookies as $i => $cookie) { + if (mb_strtolower($cookie->getName()) === $key) { + unset($new->cookies[$i]); + } + } return $new; } @@ -189,8 +205,7 @@ public function addFromResponse(ResponseInterface $response, RequestInterface $r if ($expires && $expires <= time()) { continue; } - $key = mb_strtolower($cookie->getName()); - $new->cookies[$key] = $cookie; + $new->cookies[] = $cookie; } return $new; diff --git a/tests/TestCase/Http/Cookie/CookieCollectionTest.php b/tests/TestCase/Http/Cookie/CookieCollectionTest.php index 473627c98fd..81a34a87cff 100644 --- a/tests/TestCase/Http/Cookie/CookieCollectionTest.php +++ b/tests/TestCase/Http/Cookie/CookieCollectionTest.php @@ -92,12 +92,24 @@ public function testAdd() $this->assertFalse($collection->has('remember_me'), 'Original instance not modified'); $this->assertTrue($new->has('remember_me')); $this->assertSame($remember, $new->get('remember_me')); + } + /** + * Cookie collections need to support duplicate cookie names because + * of use cases in Http\Client + * + * @return void + */ + public function testAddDuplicates() + { + $remember = new Cookie('remember_me', 'yes'); $rememberNo = new Cookie('remember_me', 'no'); - $second = $new->add($remember)->add($rememberNo); - $this->assertCount(1, $second); - $this->assertNotSame($second, $new); - $this->assertSame($rememberNo, $second->get('remember_me')); + $collection = new CookieCollection([]); + $new = $collection->add($remember)->add($rememberNo); + + $this->assertCount(2, $new); + $this->assertNotSame($new, $collection); + $this->assertSame($remember, $new->get('remember_me'), 'get() fetches first cookie'); } /** @@ -205,6 +217,7 @@ public function testAddFromResponse() $this->assertSame('/app', $new->get('test')->getPath(), 'cookies should inherit request path'); $this->assertSame('/', $new->get('expiring')->getPath(), 'path attribute should be used.'); + $this->assertSame(0, $new->get('test')->getExpiry(), 'No expiry'); $this->assertSame(0, $new->get('session')->getExpiry(), 'No expiry'); $this->assertSame( '2021-06-09 10:18:14',