From 64890e5e6f6be9462903ecb2a5b518d04acc44b3 Mon Sep 17 00:00:00 2001 From: mark_story Date: Fri, 11 Jan 2013 22:40:02 -0500 Subject: [PATCH] Adapt Network\Http\Client for path based cookies. Following the details on http://curl.haxx.se/rfc/cookie_spec.html cookies are matched by path now. --- lib/Cake/Network/Http/Client.php | 28 ++++-- lib/Cake/Network/Http/Response.php | 2 +- .../Test/TestCase/Network/Http/ClientTest.php | 97 +++++++++++++++++-- 3 files changed, 108 insertions(+), 19 deletions(-) diff --git a/lib/Cake/Network/Http/Client.php b/lib/Cake/Network/Http/Client.php index b6836f82c75..562d5c8a509 100644 --- a/lib/Cake/Network/Http/Client.php +++ b/lib/Cake/Network/Http/Client.php @@ -323,18 +323,20 @@ protected function _storeCookies(Response $response, $host) { $cookies = $response->cookies(); foreach ($cookies as $name => $cookie) { $expires = isset($cookie['expires']) ? $cookie['expires'] : false; - $domain = isset($cookie['domain']) ? $cookie['domain'] : $host; - $domain = trim($domain, '.'); if ($expires) { $expires = \DateTime::createFromFormat('D, j-M-Y H:i:s e', $expires); } if ($expires && $expires->getTimestamp() <= time()) { continue; } - if (empty($this->_cookies[$domain])) { - $this->_cookies[$domain] = []; + if (empty($cookie['domain'])) { + $cookie['domain'] = $host; } - $this->_cookies[$domain][$name] = $cookie['value']; + $cookie['domain'] = trim($cookie['domain'], '.'); + if (empty($cookie['path'])) { + $cookie['path'] = '/'; + } + $this->_cookies[] = $cookie; } } @@ -349,11 +351,19 @@ protected function _storeCookies(Response $response, $host) { * @return void */ protected function _addCookies(Request $request) { - $parts = explode('.', parse_url($request->url(), PHP_URL_HOST)); + $url = $request->url(); + $path = parse_url($url, PHP_URL_PATH); + $parts = explode('.', parse_url($url, PHP_URL_HOST)); + $domains = []; for ($i = 0, $len = count($parts); $i < $len - 1; $i++) { - $host = implode('.', array_slice($parts, $i)); - if (isset($this->_cookies[$host])) { - $request->cookie($this->_cookies[$host]); + $domains[] = implode('.', array_slice($parts, $i)); + } + foreach ($this->_cookies as $cookie) { + if ( + in_array($cookie['domain'], $domains) && + strpos($path, $cookie['path']) === 0 + ) { + $request->cookie($cookie['name'], $cookie['value']); } } } diff --git a/lib/Cake/Network/Http/Response.php b/lib/Cake/Network/Http/Response.php index 55cdcd7b707..218ad87e468 100644 --- a/lib/Cake/Network/Http/Response.php +++ b/lib/Cake/Network/Http/Response.php @@ -146,7 +146,6 @@ protected function _parseCookie($value) { } $name = false; - $cookie = []; foreach ($parts as $i => $part) { if (strpos($part, '=') !== false) { list($key, $value) = explode('=', $part, 2); @@ -164,6 +163,7 @@ protected function _parseCookie($value) { $cookie[$key] = $value; } } + $cookie['name'] = $name; $this->_cookies[$name] = $cookie; } diff --git a/lib/Cake/Test/TestCase/Network/Http/ClientTest.php b/lib/Cake/Test/TestCase/Network/Http/ClientTest.php index 1f1162095ec..3352fd34cc3 100644 --- a/lib/Cake/Test/TestCase/Network/Http/ClientTest.php +++ b/lib/Cake/Test/TestCase/Network/Http/ClientTest.php @@ -450,10 +450,18 @@ public function testCookiesExpiring() { $result = $http->cookies(); $expected = [ - 'cakephp.org' => [ - 'first' => 1, - 'second' => 2 - ] + [ + 'name' => 'first', + 'value' => '1', + 'domain' => 'cakephp.org', + 'path' => '/' + ], + [ + 'name' => 'second', + 'value' => '2', + 'domain' => 'cakephp.org', + 'path' => '/' + ], ]; $this->assertEquals($expected, $result); } @@ -514,12 +522,83 @@ public function testCookiesWithDomain() { $result = $http->cookies(); $expected = [ - 'cakephp.org' => [ - 'first' => '1', - 'third' => '3', + [ + 'domain' => 'cakephp.org', + 'path' => '/', + 'name' => 'first', + 'value' => 1, + ], + [ + 'domain' => 'test.cakephp.org', + 'path' => '/', + 'name' => 'second', + 'value' => 2, ], - 'test.cakephp.org' => [ - 'second' => '2', + [ + 'domain' => 'cakephp.org', + 'path' => '/', + 'name' => 'third', + 'value' => 3, + ], + ]; + $this->assertEquals($expected, $result); + } + +/** + * Test path based cookies + * + * @return void + */ + public function testCookiesWithPath() { + $firstHeaders = [ + 'HTTP/1.0 200 Ok', + 'Set-Cookie: first=1; Domain=.cakephp.org; Path=/projects', + ]; + $firstResponse = new Response($firstHeaders, ''); + + $secondResponse = new Response([], ''); + + $mock = $this->getMock( + 'Cake\Network\Http\Adapter\Stream', + ['send'] + ); + + $mock->expects($this->at(0)) + ->method('send') + ->will($this->returnValue([$firstResponse])); + + $mock->expects($this->at(1)) + ->method('send') + ->with($this->attributeEqualTo( + '_cookies', + [] + )) + ->will($this->returnValue([$secondResponse])); + + $mock->expects($this->at(2)) + ->method('send') + ->with($this->attributeEqualTo( + '_cookies', + ['first' => '1'] + )) + ->will($this->returnValue([$secondResponse])); + + $http = new Client([ + 'host' => 'cakephp.org', + 'adapter' => $mock + ]); + + $http->get('/projects'); + $http->get('/versions'); + $http->get('/projects/foo'); + + $result = $http->cookies(); + $expected = [ + [ + 'domain' => 'cakephp.org', + 'name' => 'first', + 'value' => 1, + 'path' => '/projects' ] ]; $this->assertEquals($expected, $result);