Skip to content

Commit

Permalink
Merge 7739877 into f444eb4
Browse files Browse the repository at this point in the history
  • Loading branch information
j0k3r committed Oct 5, 2021
2 parents f444eb4 + 7739877 commit 8933ce1
Show file tree
Hide file tree
Showing 4 changed files with 173 additions and 4 deletions.
4 changes: 2 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
"php-http/message": "^1.9",
"simplepie/simplepie": "^1.5",
"smalot/pdfparser": "^1.0",
"symfony/options-resolver": "^3.4|^4.0|^5.0",
"symfony/options-resolver": "^3.4|^4.4|^5.3",
"true/punycode": "^2.1"
},
"require-dev": {
Expand All @@ -42,7 +42,7 @@
"phpstan/phpstan": "^0.12",
"phpstan/phpstan-deprecation-rules": "^0.12",
"phpstan/phpstan-phpunit": "^0.12",
"symfony/phpunit-bridge": "^5.1"
"symfony/phpunit-bridge": "^5.3"
},
"extra": {
"branch-alias": {
Expand Down
2 changes: 1 addition & 1 deletion phpunit.xml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,6 @@
</listeners>

<!-- <logging>
<log type="coverage-html" target="build/coverage" lowUpperBound="35" highLowerBound="70"/>
<log type="coverage-html" target="build" lowUpperBound="35" highLowerBound="70"/>
</logging> -->
</phpunit>
2 changes: 1 addition & 1 deletion src/Graby.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@

use Graby\Extractor\ContentExtractor;
use Graby\Extractor\HttpClient;
use Graby\HttpClient\Plugin\CookiePlugin;
use Graby\SiteConfig\ConfigBuilder;
use GuzzleHttp\Psr7\Uri;
use GuzzleHttp\Psr7\UriResolver;
use Http\Client\Common\Plugin\CookiePlugin;
use Http\Client\Common\PluginClient;
use Http\Client\HttpClient as Client;
use Http\Discovery\HttpClientDiscovery;
Expand Down
169 changes: 169 additions & 0 deletions src/HttpClient/Plugin/CookiePlugin.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
<?php

namespace Graby\HttpClient\Plugin;

use Http\Client\Common\Plugin;
use Http\Client\Exception\TransferException;
use Http\Message\Cookie;
use Http\Message\CookieJar;
use Http\Message\CookieUtil;
use Http\Message\Exception\UnexpectedValueException;
use Http\Promise\Promise;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;

/**
* Handle request cookies.
*
* Similar to `Http\Client\Common\Plugin\CookiePlugin` but it rejects bad cookie.
*/
class CookiePlugin implements Plugin
{
/**
* Cookie storage.
*
* @var CookieJar
*/
private $cookieJar;

public function __construct(CookieJar $cookieJar)
{
$this->cookieJar = $cookieJar;
}

/**
* {@inheritdoc}
*/
public function handleRequest(RequestInterface $request, callable $next, callable $first): Promise
{
$cookies = [];
foreach ($this->cookieJar->getCookies() as $cookie) {
if ($cookie->isExpired()) {
continue;
}

if (!$cookie->matchDomain($request->getUri()->getHost())) {
continue;
}

if (!$cookie->matchPath($request->getUri()->getPath())) {
continue;
}

if ($cookie->isSecure() && ('https' !== $request->getUri()->getScheme())) {
continue;
}

$cookies[] = sprintf('%s=%s', $cookie->getName(), $cookie->getValue());
}

if (!empty($cookies)) {
$request = $request->withAddedHeader('Cookie', implode('; ', array_unique($cookies)));
}

return $next($request)->then(function (ResponseInterface $response) use ($request) {
if ($response->hasHeader('Set-Cookie')) {
$setCookies = $response->getHeader('Set-Cookie');

foreach ($setCookies as $setCookie) {
$cookie = $this->createCookie($request, $setCookie);

// Cookie invalid do not use it
if (null === $cookie) {
continue;
}

// Restrict setting cookie from another domain
if (!preg_match("/\.{$cookie->getDomain()}$/", '.' . $request->getUri()->getHost())) {
continue;
}

$this->cookieJar->addCookie($cookie);
}
}

return $response;
});
}

/**
* Creates a cookie from a string.
*
* @throws TransferException
*/
private function createCookie(RequestInterface $request, string $setCookieHeader): ?Cookie
{
$parts = array_map('trim', explode(';', $setCookieHeader));

if (empty($parts) || !strpos($parts[0], '=')) {
return null;
}

list($name, $cookieValue) = $this->createValueKey(array_shift($parts));

$maxAge = null;
$expires = null;
$domain = $request->getUri()->getHost();
$path = $request->getUri()->getPath();
$secure = false;
$httpOnly = false;

// Add the cookie pieces into the parsed data array
foreach ($parts as $part) {
list($key, $value) = $this->createValueKey($part);

switch (strtolower($key)) {
case 'expires':
try {
$expires = CookieUtil::parseDate((string) $value);
} catch (UnexpectedValueException $e) {
throw new TransferException(sprintf('Cookie header `%s` expires value `%s` could not be converted to date', $name, $value), 0, $e);
}

break;
case 'max-age':
$maxAge = (int) $value;

break;
case 'domain':
$domain = $value;

break;
case 'path':
$path = $value;

break;
case 'secure':
$secure = true;

break;
case 'httponly':
$httpOnly = true;

break;
}
}

try {
return new Cookie($name, $cookieValue, $maxAge, $domain, $path, $secure, $httpOnly, $expires);
} catch (\InvalidArgumentException $e) {
return null;
}
}

/**
* Separates key/value pair from cookie.
*
* @param string $part A single cookie value in format key=value
*
* @return array{0:string, 1:?string}
*/
private function createValueKey(string $part): array
{
$parts = explode('=', $part, 2);
$key = trim($parts[0]);
$value = isset($parts[1]) ? trim($parts[1]) : null;

return [$key, $value];
}
}

0 comments on commit 8933ce1

Please sign in to comment.