Skip to content

Commit

Permalink
Add CookieCollection::addToRequest()
Browse files Browse the repository at this point in the history
Copy and adapt code from the existing CookieCollection to enable it to
be used in the client context.
  • Loading branch information
markstory committed Mar 25, 2017
1 parent 6349b31 commit 8dbf562
Show file tree
Hide file tree
Showing 2 changed files with 135 additions and 2 deletions.
47 changes: 47 additions & 0 deletions src/Http/Cookie/CookieCollection.php
Expand Up @@ -174,6 +174,53 @@ public function getIterator()
return new ArrayIterator($this->cookies);
}

/**
* Add cookies that match the path/domain/expiration to the request.
*
* This allows CookieCollections to be used a 'cookie jar' in an HTTP client
* situation. Cookies that match the request's domain + path that are not expired
* when this method is called will be applied to the request.
*
* @param \Psr\Http\Message\RequestInterface $request The request to update.
* @return \Psr\Http\Message\RequestInterface An updated request.
*/
public function addToRequest(RequestInterface $request)
{
$uri = $request->getUri();
$path = $uri->getPath();
$host = $uri->getHost();
$scheme = $uri->getScheme();

$out = [];
foreach ($this->cookies as $cookie) {
if ($scheme === 'http' && $cookie->isSecure()) {
continue;
}
if (strpos($path, $cookie->getPath()) !== 0) {
continue;
}
$domain = $cookie->getDomain();
$leadingDot = substr($domain, 0, 1) === '.';
if ($leadingDot) {
$domain = ltrim($domain, '.');
}

if ($cookie->getExpiry() && time() > $cookie->getExpiry()) {
continue;
}

$pattern = '/' . preg_quote($domain, '/') . '$/';
if (!preg_match($pattern, $host)) {
continue;
}

$out[$cookie->getName()] = $cookie->getValue();
}
$cookies = array_merge($request->getCookieParams(), $out);

return $request->withCookieParams($cookies);
}

/**
* Create a new collection that includes cookies from the response.
*
Expand Down
90 changes: 88 additions & 2 deletions tests/TestCase/Http/Cookie/CookieCollectionTest.php
Expand Up @@ -17,6 +17,7 @@
use Cake\Http\ServerRequest;
use Cake\Http\Response;
use Cake\TestSuite\TestCase;
use DateTime;

/**
* Cookie collection test.
Expand Down Expand Up @@ -203,7 +204,7 @@ public function testAddFromResponse()
$response = (new Response())
->withAddedHeader('Set-Cookie', 'test=value')
->withAddedHeader('Set-Cookie', 'expiring=soon; Expires=Wed, 09-Jun-2021 10:18:14 GMT; Path=/; HttpOnly; Secure;')
->withAddedHeader('Set-Cookie', 'session=123abc');
->withAddedHeader('Set-Cookie', 'session=123abc; Domain=www.example.com');
$new = $collection->addFromResponse($response, $request);
$this->assertNotSame($new, $collection, 'Should clone collection');

Expand All @@ -218,12 +219,14 @@ public function testAddFromResponse()
$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',
date('Y-m-d H:i:s', $new->get('expiring')->getExpiry()),
'Has expiry'
);
$session = $new->get('session');
$this->assertSame(0, $session->getExpiry(), 'No expiry');
$this->assertSame('www.example.com', $session->getDomain(), 'Has domain');
}

/**
Expand Down Expand Up @@ -264,4 +267,87 @@ public function testAddFromResponseIgnoreExpired()
$new = $collection->addFromResponse($response, $request);
$this->assertFalse($new->has('expired'),'Should drop expired cookies');
}

/**
* Test adding cookies from the collection to request.
*
* @return void
*/
public function testAddToRequest()
{
$collection = new CookieCollection();
$collection = $collection
->add(new Cookie('api', 'A', null, '/api', 'example.com'))
->add(new Cookie('blog', 'b', null, '/blog', 'blog.example.com'))
->add(new Cookie('expired', 'ex', new DateTime('-2 seconds'), '/', 'example.com'));
$request = new ServerRequest([
'environment' => [
'HTTP_HOST' => 'example.com',
'REQUEST_URI' => '/api'
]
]);
$request = $collection->addToRequest($request);
$this->assertCount(1, $request->getCookieParams());
$this->assertSame(['api' => 'A'], $request->getCookieParams());

$request = new ServerRequest([
'environment' => [
'HTTP_HOST' => 'example.com',
'REQUEST_URI' => '/'
]
]);
$request = $collection->addToRequest($request);
$this->assertCount(0, $request->getCookieParams());

$request = new ServerRequest([
'environment' => [
'HTTP_HOST' => 'example.com',
'REQUEST_URI' => '/blog'
]
]);
$request = $collection->addToRequest($request);
$this->assertCount(0, $request->getCookieParams(), 'domain matching should apply');

$request = new ServerRequest([
'environment' => [
'HTTP_HOST' => 'foo.blog.example.com',
'REQUEST_URI' => '/blog'
]
]);
$request = $collection->addToRequest($request);
$this->assertCount(1, $request->getCookieParams(), 'domain matching should apply');
$this->assertSame(['blog' => 'b'], $request->getCookieParams());
}

/**
* Test adding cookies checks the secure crumb
*
* @return void
*/
public function testAddToRequestSecureCrumb()
{
$collection = new CookieCollection();
$collection = $collection
->add(new Cookie('secret', 'A', null, '/', 'example.com', true))
->add(new Cookie('public', 'b', null, '/', 'example.com', false));
$request = new ServerRequest([
'environment' => [
'HTTPS' => 'on',
'HTTP_HOST' => 'example.com',
'REQUEST_URI' => '/api'
]
]);
$request = $collection->addToRequest($request);
$this->assertSame(['secret' => 'A', 'public' => 'b'], $request->getCookieParams());

// no HTTPS set.
$request = new ServerRequest([
'environment' => [
'HTTP_HOST' => 'example.com',
'REQUEST_URI' => '/api'
]
]);
$request = $collection->addToRequest($request);
$this->assertSame(['public' => 'b'], $request->getCookieParams());
}
}

0 comments on commit 8dbf562

Please sign in to comment.