diff --git a/core/composer.json b/core/composer.json index 75b45b96fbc0a06a7d0969cb14a741281b5f6e82..7fc070e67f3bb9e9cf19a8cc7a66651fe2e39f2b 100644 --- a/core/composer.json +++ b/core/composer.json @@ -21,7 +21,7 @@ "twig/twig": "~1.20", "doctrine/common": "2.5.*", "doctrine/annotations": "1.2.*", - "guzzlehttp/guzzle": "dev-master#1879fbe853b0c64d109e369c7aeff09849e62d1e", + "guzzlehttp/guzzle": "~6.1.0", "symfony-cmf/routing": "1.3.*", "easyrdf/easyrdf": "0.9.*", "phpunit/phpunit": "4.8.*", diff --git a/core/composer.lock b/core/composer.lock index 98265d4dfe1ec27a561b72085f5de325aded8b6c..d2d6b425e25e4db8cd43ad1b0422ebd566ac51c8 100644 --- a/core/composer.lock +++ b/core/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "d39a311bc4d6e7db527d6a43a8ac34d4", + "hash": "eb73d28ce27162c98ea1a8865fddbf7d", "packages": [ { "name": "behat/mink", @@ -790,12 +790,12 @@ "source": { "type": "git", "url": "https://github.com/guzzle/guzzle.git", - "reference": "1879fbe853b0c64d109e369c7aeff09849e62d1e" + "reference": "66fd14b4d0b8f2389eaf37c5458608c7cb793a81" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/guzzle/zipball/33af93ab4b5e76df7a4c774910590f814a3e576c", - "reference": "1879fbe853b0c64d109e369c7aeff09849e62d1e", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/66fd14b4d0b8f2389eaf37c5458608c7cb793a81", + "reference": "66fd14b4d0b8f2389eaf37c5458608c7cb793a81", "shasum": "" }, "require": { @@ -811,7 +811,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "6.0-dev" + "dev-master": "6.1-dev" } }, "autoload": { @@ -844,7 +844,7 @@ "rest", "web service" ], - "time": "2015-07-10 20:04:21" + "time": "2015-09-08 17:36:26" }, { "name": "guzzlehttp/promises", @@ -3376,7 +3376,6 @@ "aliases": [], "minimum-stability": "dev", "stability-flags": { - "guzzlehttp/guzzle": 20, "behat/mink-goutte-driver": 20 }, "prefer-stable": true, diff --git a/core/vendor/composer/installed.json b/core/vendor/composer/installed.json index 94733abcb6bfedcf8b1bf5c10e0c7548a4ed9609..47491938be73fe3fb1b233b6a295e7f8fbb464f3 100644 --- a/core/vendor/composer/installed.json +++ b/core/vendor/composer/installed.json @@ -581,70 +581,6 @@ "psr-7" ] }, - { - "name": "guzzlehttp/guzzle", - "version": "dev-master", - "version_normalized": "9999999-dev", - "source": { - "type": "git", - "url": "https://github.com/guzzle/guzzle.git", - "reference": "1879fbe853b0c64d109e369c7aeff09849e62d1e" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/guzzle/guzzle/zipball/33af93ab4b5e76df7a4c774910590f814a3e576c", - "reference": "1879fbe853b0c64d109e369c7aeff09849e62d1e", - "shasum": "" - }, - "require": { - "guzzlehttp/promises": "~1.0", - "guzzlehttp/psr7": "~1.1", - "php": ">=5.5.0" - }, - "require-dev": { - "ext-curl": "*", - "phpunit/phpunit": "~4.0", - "psr/log": "~1.0" - }, - "time": "2015-07-10 20:04:21", - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "6.0-dev" - } - }, - "installation-source": "dist", - "autoload": { - "files": [ - "src/functions_include.php" - ], - "psr-4": { - "GuzzleHttp\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Michael Dowling", - "email": "mtdowling@gmail.com", - "homepage": "https://github.com/mtdowling" - } - ], - "description": "Guzzle is a PHP HTTP client library", - "homepage": "http://guzzlephp.org/", - "keywords": [ - "client", - "curl", - "framework", - "http", - "http client", - "rest", - "web service" - ] - }, { "name": "behat/mink-goutte-driver", "version": "dev-master", @@ -3483,5 +3419,69 @@ "serializer", "xml" ] + }, + { + "name": "guzzlehttp/guzzle", + "version": "dev-master", + "version_normalized": "9999999-dev", + "source": { + "type": "git", + "url": "https://github.com/guzzle/guzzle.git", + "reference": "66fd14b4d0b8f2389eaf37c5458608c7cb793a81" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/66fd14b4d0b8f2389eaf37c5458608c7cb793a81", + "reference": "66fd14b4d0b8f2389eaf37c5458608c7cb793a81", + "shasum": "" + }, + "require": { + "guzzlehttp/promises": "~1.0", + "guzzlehttp/psr7": "~1.1", + "php": ">=5.5.0" + }, + "require-dev": { + "ext-curl": "*", + "phpunit/phpunit": "~4.0", + "psr/log": "~1.0" + }, + "time": "2015-09-08 17:36:26", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "6.1-dev" + } + }, + "installation-source": "dist", + "autoload": { + "files": [ + "src/functions_include.php" + ], + "psr-4": { + "GuzzleHttp\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "Guzzle is a PHP HTTP client library", + "homepage": "http://guzzlephp.org/", + "keywords": [ + "client", + "curl", + "framework", + "http", + "http client", + "rest", + "web service" + ] } ] diff --git a/core/vendor/guzzlehttp/guzzle/CHANGELOG.md b/core/vendor/guzzlehttp/guzzle/CHANGELOG.md index d639f4e655fb44feda43baed018fd45f326d090c..de7da2d6fd6e0ca64e5f7c57f4bb5f73a4a2a07f 100644 --- a/core/vendor/guzzlehttp/guzzle/CHANGELOG.md +++ b/core/vendor/guzzlehttp/guzzle/CHANGELOG.md @@ -1,5 +1,39 @@ # CHANGELOG +## 6.1.0 - 2015-09-08 + +* Feature: Added the `on_stats` request option to provide access to transfer + statistics for requests. https://github.com/guzzle/guzzle/pull/1202 +* Feature: Added the ability to persist session cookies in CookieJars. + https://github.com/guzzle/guzzle/pull/1195 +* Feature: Some compatibility updates for Google APP Engine + https://github.com/guzzle/guzzle/pull/1216 +* Feature: Added support for NO_PROXY to prevent the use of a proxy based on + a simple set of rules. https://github.com/guzzle/guzzle/pull/1197 +* Feature: Cookies can now contain square brackets. + https://github.com/guzzle/guzzle/pull/1237 +* Bug fix: Now correctly parsing `=` inside of quotes in Cookies. + https://github.com/guzzle/guzzle/pull/1232 +* Bug fix: Cusotm cURL options now correctly override curl options of the + same name. https://github.com/guzzle/guzzle/pull/1221 +* Bug fix: Content-Type header is now added when using an explicitly provided + multipart body. https://github.com/guzzle/guzzle/pull/1218 +* Bug fix: Now ignoring Set-Cookie headers that have no name. +* Bug fix: Reason phrase is no longer cast to an int in some cases in the + cURL handler. https://github.com/guzzle/guzzle/pull/1187 +* Bug fix: Remove the Authorization header when redirecting if the Host + header changes. https://github.com/guzzle/guzzle/pull/1207 +* Bug fix: Cookie path matching fixes + https://github.com/guzzle/guzzle/issues/1129 +* Bug fix: Fixing the cURL `body_as_string` setting + https://github.com/guzzle/guzzle/pull/1201 +* Bug fix: quotes are no longer stripped when parsing cookies. + https://github.com/guzzle/guzzle/issues/1172 +* Bug fix: `form_params` and `query` now always uses the `&` separator. + https://github.com/guzzle/guzzle/pull/1163 +* Bug fix: Adding a Content-Length to PHP stream wrapper requests if not set. + https://github.com/guzzle/guzzle/pull/1189 + ## 6.0.2 - 2015-07-04 * Fixed a memory leak in the curl handlers in which references to callbacks diff --git a/core/vendor/guzzlehttp/guzzle/README.md b/core/vendor/guzzlehttp/guzzle/README.md index c18c10b9e4d635e385b11fec2cd41e27ccfc77cb..2d721c06f00164f887ff1bc58c3491e557c906cc 100644 --- a/core/vendor/guzzlehttp/guzzle/README.md +++ b/core/vendor/guzzlehttp/guzzle/README.md @@ -19,7 +19,9 @@ trivial to integrate with web services. ```php $client = new GuzzleHttp\Client(); -$res = $client->get('https://api.github.com/user', ['auth' => ['user', 'pass']]); +$res = $client->request('GET', 'https://api.github.com/user', [ + 'auth' => ['user', 'pass'] +]); echo $res->getStatusCode(); // "200" echo $res->getHeader('content-type'); diff --git a/core/vendor/guzzlehttp/guzzle/UPGRADING.md b/core/vendor/guzzlehttp/guzzle/UPGRADING.md index 0e86214dafcaef16270d7d9625f750796cc8bab1..9e31ddcce3f246fbc6c37a08b0a03b517b58f392 100644 --- a/core/vendor/guzzlehttp/guzzle/UPGRADING.md +++ b/core/vendor/guzzlehttp/guzzle/UPGRADING.md @@ -83,6 +83,10 @@ functions that wrap handlers (or are injected into a - `GuzzleHttp\ClientInterface::getDefaultOption` has been renamed to `GuzzleHttp\ClientInterface::getConfig`. - `GuzzleHttp\ClientInterface::setDefaultOption` has been removed. +- The `json` and `xml` methods of response objects has been removed. With the + migration to strictly adhering to PSR-7 as the interface for Guzzle messages, + adding methods to message interfaces would actually require Guzzle messages + to extend from PSR-7 messages rather then work with them directly. ## Migrating to middleware diff --git a/core/vendor/guzzlehttp/guzzle/composer.json b/core/vendor/guzzlehttp/guzzle/composer.json index 35ccb8a3d2d53a5d958747936df64bab928d35d0..1f8b070041da64fbdf8644f4d7f16ebf77b69cfd 100644 --- a/core/vendor/guzzlehttp/guzzle/composer.json +++ b/core/vendor/guzzlehttp/guzzle/composer.json @@ -35,7 +35,7 @@ }, "extra": { "branch-alias": { - "dev-master": "6.0-dev" + "dev-master": "6.1-dev" } } } diff --git a/core/vendor/guzzlehttp/guzzle/src/Client.php b/core/vendor/guzzlehttp/guzzle/src/Client.php index 74f5cfe824531b5803c5ef4d8e3f060dbad6692c..2e86ecee4e83122bd6dd58a73ce01252f71e6c9b 100644 --- a/core/vendor/guzzlehttp/guzzle/src/Client.php +++ b/core/vendor/guzzlehttp/guzzle/src/Client.php @@ -7,7 +7,6 @@ use Psr\Http\Message\UriInterface; use Psr\Http\Message\RequestInterface; use Psr\Http\Message\ResponseInterface; -use \InvalidArgumentException as Iae; /** * @method ResponseInterface get($uri, array $options = []) @@ -150,8 +149,6 @@ private function buildUri($uri, array $config) * Configures the default options for a client. * * @param array $config - * - * @return array */ private function configureDefaults(array $config) { @@ -172,6 +169,11 @@ private function configureDefaults(array $config) $defaults['proxy']['https'] = $proxy; } + if ($noProxy = getenv('NO_PROXY')) { + $cleanedNoProxy = str_replace(' ', '', $noProxy); + $defaults['proxy']['no'] = explode(',', $cleanedNoProxy); + } + $this->config = $config + $defaults; if (!empty($config['cookies']) && $config['cookies'] === true) { @@ -298,9 +300,6 @@ private function applyOptions(RequestInterface $request, array &$options) $elements = $options['multipart']; unset($options['multipart']); $options['body'] = new Psr7\MultipartStream($elements); - // Use a multipart/form-data POST if a Content-Type is not set. - $options['_conditional']['Content-Type'] = 'multipart/form-data; boundary=' - . $options['body']->getBoundary(); } if (!empty($options['decode_content']) @@ -351,7 +350,7 @@ private function applyOptions(RequestInterface $request, array &$options) $value = http_build_query($value, null, '&', PHP_QUERY_RFC3986); } if (!is_string($value)) { - throw new Iae('query must be a string or array'); + throw new \InvalidArgumentException('query must be a string or array'); } $modify['query'] = $value; unset($options['query']); @@ -364,6 +363,11 @@ private function applyOptions(RequestInterface $request, array &$options) } $request = Psr7\modify_request($request, $modify); + if ($request->getBody() instanceof Psr7\MultipartStream) { + // Use a multipart/form-data POST if a Content-Type is not set. + $options['_conditional']['Content-Type'] = 'multipart/form-data; boundary=' + . $request->getBody()->getBoundary(); + } // Merge in conditional headers if they are not present. if (isset($options['_conditional'])) { diff --git a/core/vendor/guzzlehttp/guzzle/src/ClientInterface.php b/core/vendor/guzzlehttp/guzzle/src/ClientInterface.php index 7d155e5645ea94cd0710a6676958dc90ca645e43..b5b2306a44c7d59e01afeb619688ab713121890a 100644 --- a/core/vendor/guzzlehttp/guzzle/src/ClientInterface.php +++ b/core/vendor/guzzlehttp/guzzle/src/ClientInterface.php @@ -12,7 +12,7 @@ */ interface ClientInterface { - const VERSION = '6.0.2'; + const VERSION = '6.1.0'; /** * Send an HTTP request. diff --git a/core/vendor/guzzlehttp/guzzle/src/Cookie/CookieJar.php b/core/vendor/guzzlehttp/guzzle/src/Cookie/CookieJar.php index 4270469fc21ee1478354c6e7c50709fc774e200d..ea60068decdafaf2b9cd4f01b62ea6d5f1076aa0 100644 --- a/core/vendor/guzzlehttp/guzzle/src/Cookie/CookieJar.php +++ b/core/vendor/guzzlehttp/guzzle/src/Cookie/CookieJar.php @@ -18,8 +18,9 @@ class CookieJar implements CookieJarInterface /** * @param bool $strictMode Set to true to throw exceptions when invalid * cookies are added to the cookie jar. - * @param array $cookieArray Array of SetCookie objects or a hash of arrays - * that can be used with the SetCookie constructor + * @param array $cookieArray Array of SetCookie objects or a hash of + * arrays that can be used with the SetCookie + * constructor */ public function __construct($strictMode = false, $cookieArray = []) { @@ -68,7 +69,7 @@ public static function getCookieValue($value) { if (substr($value, 0, 1) !== '"' && substr($value, -1, 1) !== '"' && - strpbrk($value, ';,') + strpbrk($value, ';,=') ) { $value = '"' . $value . '"'; } @@ -76,6 +77,27 @@ public static function getCookieValue($value) return $value; } + /** + * Evaluate if this cookie should be persisted to storage + * that survives between requests. + * + * @param SetCookie $cookie Being evaluated. + * @param bool $allowSessionCookies If we should presist session cookies + * @return bool + */ + public static function shouldPersist( + SetCookie $cookie, + $allowSessionCookies = false + ) { + if ($cookie->getExpires() || $allowSessionCookies) { + if (!$cookie->getDiscard()) { + return true; + } + } + + return false; + } + public function toArray() { return array_map(function (SetCookie $cookie) { @@ -127,6 +149,13 @@ function (SetCookie $cookie) { public function setCookie(SetCookie $cookie) { + // If the name string is empty (but not 0), ignore the set-cookie + // string entirely. + $name = $cookie->getName(); + if (!$name && $name !== '0') { + return false; + } + // Only allow cookies with set and valid domain, name, value $result = $cookie->validate(); if ($result !== true) { diff --git a/core/vendor/guzzlehttp/guzzle/src/Cookie/FileCookieJar.php b/core/vendor/guzzlehttp/guzzle/src/Cookie/FileCookieJar.php index 28cfad54d5b79201fd9b31e3092ac94da8cdc43f..c55bb3478c03699ba762e35d6c3813b55a69cb1e 100644 --- a/core/vendor/guzzlehttp/guzzle/src/Cookie/FileCookieJar.php +++ b/core/vendor/guzzlehttp/guzzle/src/Cookie/FileCookieJar.php @@ -9,16 +9,22 @@ class FileCookieJar extends CookieJar /** @var string filename */ private $filename; + /** @var bool Control whether to presist session cookies or not. */ + private $storeSessionCookies; + /** * Create a new FileCookieJar object * - * @param string $cookieFile File to store the cookie data + * @param string $cookieFile File to store the cookie data + * @param bool $storeSessionCookies Set to true to store session cookies + * in the cookie jar. * * @throws \RuntimeException if the file cannot be found or created */ - public function __construct($cookieFile) + public function __construct($cookieFile, $storeSessionCookies = false) { $this->filename = $cookieFile; + $this->storeSessionCookies = $storeSessionCookies; if (file_exists($cookieFile)) { $this->load($cookieFile); @@ -44,7 +50,7 @@ public function save($filename) $json = []; foreach ($this as $cookie) { /** @var SetCookie $cookie */ - if ($cookie->getExpires() && !$cookie->getDiscard()) { + if (CookieJar::shouldPersist($cookie, $this->storeSessionCookies)) { $json[] = $cookie->toArray(); } } diff --git a/core/vendor/guzzlehttp/guzzle/src/Cookie/SessionCookieJar.php b/core/vendor/guzzlehttp/guzzle/src/Cookie/SessionCookieJar.php index 1688eb670295894bcda68641c9001cfb11c58544..d80c4804baac6021da3cad661e77e51117c22f2e 100644 --- a/core/vendor/guzzlehttp/guzzle/src/Cookie/SessionCookieJar.php +++ b/core/vendor/guzzlehttp/guzzle/src/Cookie/SessionCookieJar.php @@ -8,15 +8,22 @@ class SessionCookieJar extends CookieJar { /** @var string session key */ private $sessionKey; + + /** @var bool Control whether to presist session cookies or not. */ + private $storeSessionCookies; /** * Create a new SessionCookieJar object * - * @param string $sessionKey Session key name to store the cookie data in session + * @param string $sessionKey Session key name to store the cookie + * data in session + * @param bool $storeSessionCookies Set to true to store session cookies + * in the cookie jar. */ - public function __construct($sessionKey) + public function __construct($sessionKey, $storeSessionCookies = false) { $this->sessionKey = $sessionKey; + $this->storeSessionCookies = $storeSessionCookies; $this->load(); } @@ -36,7 +43,7 @@ public function save() $json = []; foreach ($this as $cookie) { /** @var SetCookie $cookie */ - if ($cookie->getExpires() && !$cookie->getDiscard()) { + if (CookieJar::shouldPersist($cookie, $this->storeSessionCookies)) { $json[] = $cookie->toArray(); } } diff --git a/core/vendor/guzzlehttp/guzzle/src/Cookie/SetCookie.php b/core/vendor/guzzlehttp/guzzle/src/Cookie/SetCookie.php index 8613e2584ebc71ba6a572562d9942a792a720eec..acd654df41daef3212cf198be5b8354e1610e8d3 100644 --- a/core/vendor/guzzlehttp/guzzle/src/Cookie/SetCookie.php +++ b/core/vendor/guzzlehttp/guzzle/src/Cookie/SetCookie.php @@ -46,7 +46,7 @@ public static function fromString($cookie) $cookieParts = explode('=', $part, 2); $key = trim($cookieParts[0]); $value = isset($cookieParts[1]) - ? trim($cookieParts[1], " \n\r\t\0\x0B\"") + ? trim($cookieParts[1], " \n\r\t\0\x0B") : true; // Only check for non-cookies when cookies have been found @@ -286,15 +286,43 @@ public function setHttpOnly($httpOnly) } /** - * Check if the cookie matches a path value + * Check if the cookie matches a path value. * - * @param string $path Path to check against + * A request-path path-matches a given cookie-path if at least one of + * the following conditions holds: + * + * - The cookie-path and the request-path are identical. + * - The cookie-path is a prefix of the request-path, and the last + * character of the cookie-path is %x2F ("/"). + * - The cookie-path is a prefix of the request-path, and the first + * character of the request-path that is not included in the cookie- + * path is a %x2F ("/") character. + * + * @param string $requestPath Path to check against * * @return bool */ - public function matchesPath($path) + public function matchesPath($requestPath) { - return !$this->getPath() || 0 === stripos($path, $this->getPath()); + $cookiePath = $this->getPath(); + + // Match on exact matches or when path is the default empty "/" + if ($cookiePath == '/' || $cookiePath == $requestPath) { + return true; + } + + // Ensure that the cookie-path is a prefix of the request path. + if (0 !== strpos($requestPath, $cookiePath)) { + return false; + } + + // Match if the last character of the cookie-path is "/" + if (substr($cookiePath, -1, 1) == '/') { + return true; + } + + // Match if the first character not included in cookie path is "/" + return substr($requestPath, strlen($cookiePath), 1) == '/'; } /** @@ -321,7 +349,7 @@ public function matchesDomain($domain) return false; } - return (bool) preg_match('/\.' . preg_quote($cookieDomain) . '$/i', $domain); + return (bool) preg_match('/\.' . preg_quote($cookieDomain) . '$/', $domain); } /** @@ -348,8 +376,13 @@ public function validate() } // Check if any of the invalid characters are present in the cookie name - if (preg_match('/[\x00-\x20\x22\x28-\x29\x2c\x2f\x3a-\x40\x5b-\x5d\x7b\x7d\x7f]/', $name)) { - return 'Cookie name must not contain invalid characters: ASCII Control characters (0-31;127), space, tab and the following characters: ()<>@,;:\"/[]?={}'; + if (preg_match( + '/[\x00-\x20\x22\x28-\x29\x2c\x2f\x3a-\x40\x5c\x7b\x7d\x7f]/', + $name) + ) { + return 'Cookie name must not contain invalid characters: ASCII ' + . 'Control characters (0-31;127), space, tab and the ' + . 'following characters: ()<>@,;:\"/?={}'; } // Value must not be empty, but can be 0 diff --git a/core/vendor/guzzlehttp/guzzle/src/Handler/CurlFactory.php b/core/vendor/guzzlehttp/guzzle/src/Handler/CurlFactory.php index dcf374d8e1943d80eab326a712e1d5c228df6ab9..e8d9388e251f0ff0f4ba0413b90ef0d173eb1e41 100644 --- a/core/vendor/guzzlehttp/guzzle/src/Handler/CurlFactory.php +++ b/core/vendor/guzzlehttp/guzzle/src/Handler/CurlFactory.php @@ -7,6 +7,7 @@ use GuzzleHttp\Promise\RejectedPromise; use GuzzleHttp\Psr7; use GuzzleHttp\Psr7\LazyOpenStream; +use GuzzleHttp\TransferStats; use Psr\Http\Message\RequestInterface; /** @@ -30,6 +31,11 @@ public function __construct($maxHandles) public function create(RequestInterface $request, array $options) { + if (isset($options['curl']['body_as_string'])) { + $options['_body_as_string'] = $options['curl']['body_as_string']; + unset($options['curl']['body_as_string']); + } + $easy = new EasyHandle; $easy->request = $request; $easy->options = $options; @@ -39,14 +45,9 @@ public function create(RequestInterface $request, array $options) $this->applyHeaders($easy, $conf); unset($conf['_headers']); - if (isset($options['curl']['body_as_string'])) { - $options['_body_as_string'] = $options['curl']['body_as_string']; - unset($options['curl']['body_as_string']); - } - // Add handler options from the request configuration options if (isset($options['curl'])) { - $conf += $options['curl']; + $conf = array_replace($conf, $options['curl']); } $conf[CURLOPT_HEADERFUNCTION] = $this->createHeaderFn($easy); @@ -94,6 +95,10 @@ public static function finish( EasyHandle $easy, CurlFactoryInterface $factory ) { + if (isset($easy->options['on_stats'])) { + self::invokeStats($easy); + } + if (!$easy->response || $easy->errno) { return self::finishError($handler, $easy, $factory); } @@ -110,6 +115,19 @@ public static function finish( return new FulfilledPromise($easy->response); } + private static function invokeStats(EasyHandle $easy) + { + $curlStats = curl_getinfo($easy->handle); + $stats = new TransferStats( + $easy->request, + $easy->response, + $curlStats['total_time'], + $easy->errno, + $curlStats + ); + call_user_func($easy->options['on_stats'], $stats); + } + private static function finishError( callable $handler, EasyHandle $easy, @@ -361,9 +379,15 @@ private function applyHandlerOptions(EasyHandle $easy, array &$conf) if (isset($options['proxy'])) { if (!is_array($options['proxy'])) { $conf[CURLOPT_PROXY] = $options['proxy']; - } elseif ($scheme = $easy->request->getUri()->getScheme()) { + } else { + $scheme = $easy->request->getUri()->getScheme(); if (isset($options['proxy'][$scheme])) { - $conf[CURLOPT_PROXY] = $options['proxy'][$scheme]; + $host = $easy->request->getUri()->getHost(); + if (!isset($options['proxy']['no']) || + !\GuzzleHttp\is_host_in_noproxy($host, $options['proxy']['no']) + ) { + $conf[CURLOPT_PROXY] = $options['proxy'][$scheme]; + } } } } diff --git a/core/vendor/guzzlehttp/guzzle/src/Handler/EasyHandle.php b/core/vendor/guzzlehttp/guzzle/src/Handler/EasyHandle.php index 35228f009adb6e4c4f6b5495d2d5beba4edde005..c4b927e5ee0b1b8c498a4960ddbab9089475e7e6 100644 --- a/core/vendor/guzzlehttp/guzzle/src/Handler/EasyHandle.php +++ b/core/vendor/guzzlehttp/guzzle/src/Handler/EasyHandle.php @@ -73,7 +73,7 @@ public function createResponse() $headers, $this->sink, substr($startLine[0], 5), - isset($startLine[2]) ? (int) $startLine[2] : null + isset($startLine[2]) ? (string) $startLine[2] : null ); } diff --git a/core/vendor/guzzlehttp/guzzle/src/Handler/MockHandler.php b/core/vendor/guzzlehttp/guzzle/src/Handler/MockHandler.php index 9854546eb8faea3afa5b8513ed5f8acf06acffae..4b1b0af8dece70ab1ff778705f966fd8fe59c221 100644 --- a/core/vendor/guzzlehttp/guzzle/src/Handler/MockHandler.php +++ b/core/vendor/guzzlehttp/guzzle/src/Handler/MockHandler.php @@ -4,6 +4,7 @@ use GuzzleHttp\HandlerStack; use GuzzleHttp\Promise\PromiseInterface; use GuzzleHttp\Promise\RejectedPromise; +use GuzzleHttp\TransferStats; use Psr\Http\Message\RequestInterface; use Psr\Http\Message\ResponseInterface; @@ -80,18 +81,16 @@ public function __invoke(RequestInterface $request, array $options) ? new RejectedPromise($response) : \GuzzleHttp\Promise\promise_for($response); - if (!$this->onFulfilled && !$this->onRejected) { - return $response; - } - return $response->then( - function ($value) { + function ($value) use ($request, $options) { + $this->invokeStats($request, $options, $value); if ($this->onFulfilled) { call_user_func($this->onFulfilled, $value); } return $value; }, - function ($reason) { + function ($reason) use ($request, $options) { + $this->invokeStats($request, $options, null, $reason); if ($this->onRejected) { call_user_func($this->onRejected, $reason); } @@ -149,4 +148,16 @@ public function count() { return count($this->queue); } + + private function invokeStats( + RequestInterface $request, + array $options, + ResponseInterface $response = null, + $reason = null + ) { + if (isset($options['on_stats'])) { + $stats = new TransferStats($request, $response, 0, $reason); + call_user_func($options['on_stats'], $stats); + } + } } diff --git a/core/vendor/guzzlehttp/guzzle/src/Handler/StreamHandler.php b/core/vendor/guzzlehttp/guzzle/src/Handler/StreamHandler.php index b94d1b7b62bd77af843d0de7ab391c1043663f5b..2f18a48276727081fbb84e679e003a1c0e0ea1df 100644 --- a/core/vendor/guzzlehttp/guzzle/src/Handler/StreamHandler.php +++ b/core/vendor/guzzlehttp/guzzle/src/Handler/StreamHandler.php @@ -7,7 +7,9 @@ use GuzzleHttp\Promise\RejectedPromise; use GuzzleHttp\Promise\PromiseInterface; use GuzzleHttp\Psr7; +use GuzzleHttp\TransferStats; use Psr\Http\Message\RequestInterface; +use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\StreamInterface; /** @@ -32,11 +34,24 @@ public function __invoke(RequestInterface $request, array $options) usleep($options['delay'] * 1000); } + $startTime = isset($options['on_stats']) ? microtime(true) : null; + try { // Does not support the expect header. $request = $request->withoutHeader('Expect'); - $stream = $this->createStream($request, $options); - return $this->createResponse($request, $options, $stream); + + // Append a content-length header if body size is zero to match + // cURL's behavior. + if (0 === $request->getBody()->getSize()) { + $request = $request->withHeader('Content-Length', 0); + } + + return $this->createResponse( + $request, + $options, + $this->createStream($request, $options), + $startTime + ); } catch (\InvalidArgumentException $e) { throw $e; } catch (\Exception $e) { @@ -49,16 +64,37 @@ public function __invoke(RequestInterface $request, array $options) ) { $e = new ConnectException($e->getMessage(), $request, $e); } - return new RejectedPromise( - RequestException::wrapException($request, $e) + $e = RequestException::wrapException($request, $e); + $this->invokeStats($options, $request, $startTime, null, $e); + + return new RejectedPromise($e); + } + } + + private function invokeStats( + array $options, + RequestInterface $request, + $startTime, + ResponseInterface $response = null, + $error = null + ) { + if (isset($options['on_stats'])) { + $stats = new TransferStats( + $request, + $response, + microtime(true) - $startTime, + $error, + [] ); + call_user_func($options['on_stats'], $stats); } } private function createResponse( RequestInterface $request, array $options, - $stream + $stream, + $startTime ) { $hdrs = $this->lastHeaders; $this->lastHeaders = []; @@ -86,6 +122,8 @@ private function createResponse( $this->drain($stream, $sink); } + $this->invokeStats($options, $request, $startTime, $response, null); + return new FulfilledPromise($response); } @@ -289,7 +327,14 @@ private function add_proxy(RequestInterface $request, &$options, $value, &$param } else { $scheme = $request->getUri()->getScheme(); if (isset($value[$scheme])) { - $options['http']['proxy'] = $value[$scheme]; + if (!isset($value['no']) + || !\GuzzleHttp\is_host_in_noproxy( + $request->getUri()->getHost(), + $value['no'] + ) + ) { + $options['http']['proxy'] = $value[$scheme]; + } } } } diff --git a/core/vendor/guzzlehttp/guzzle/src/RedirectMiddleware.php b/core/vendor/guzzlehttp/guzzle/src/RedirectMiddleware.php index 374931d9617aedd9d722d8344cd1645fec4cdd96..dbe8b87e5e2b3d0618f3bfe1ade0eced2014abf3 100644 --- a/core/vendor/guzzlehttp/guzzle/src/RedirectMiddleware.php +++ b/core/vendor/guzzlehttp/guzzle/src/RedirectMiddleware.php @@ -17,11 +17,14 @@ */ class RedirectMiddleware { + const HISTORY_HEADER = 'X-Guzzle-Redirect-History'; + public static $defaultSettings = [ - 'max' => 5, - 'protocols' => ['http', 'https'], - 'strict' => false, - 'referer' => false + 'max' => 5, + 'protocols' => ['http', 'https'], + 'strict' => false, + 'referer' => false, + 'track_redirects' => false, ]; /** @var callable */ @@ -98,7 +101,32 @@ public function checkRedirect( ); } - return $this($nextRequest, $options); + /** @var PromiseInterface|ResponseInterface $promise */ + $promise = $this($nextRequest, $options); + + // Add headers to be able to track history of redirects. + if (!empty($options['allow_redirects']['track_redirects'])) { + return $this->withTracking( + $promise, + (string) $nextRequest->getUri() + ); + } + + return $promise; + } + + private function withTracking(PromiseInterface $promise, $uri) + { + return $promise->then( + function (ResponseInterface $response) use ($uri) { + // Note that we are pushing to the front of the list as this + // would be an earlier response than what is currently present + // in the history header. + $header = $response->getHeader(self::HISTORY_HEADER); + array_unshift($header, $uri); + return $response->withHeader(self::HISTORY_HEADER, $header); + } + ); } private function guardMax(RequestInterface $request, array &$options) @@ -158,6 +186,11 @@ public function modifyRequest( $modify['remove_headers'][] = 'Referer'; } + // Remove Authorization header if host is different. + if ($request->getUri()->getHost() !== $modify['uri']->getHost()) { + $modify['remove_headers'][] = 'Authorization'; + } + return Psr7\modify_request($request, $modify); } diff --git a/core/vendor/guzzlehttp/guzzle/src/RequestOptions.php b/core/vendor/guzzlehttp/guzzle/src/RequestOptions.php index e142b3f2cb90f523d6cfefcac0df3e6f6deb2728..3af2f368a9bf3a98e49d3816a17052298974e22e 100644 --- a/core/vendor/guzzlehttp/guzzle/src/RequestOptions.php +++ b/core/vendor/guzzlehttp/guzzle/src/RequestOptions.php @@ -150,6 +150,24 @@ final class RequestOptions */ const MULTIPART = 'multipart'; + /** + * on_headers: (callable) A callable that is invoked when the HTTP headers + * of the response have been received but the body has not yet begun to + * download. + */ + const ON_HEADERS = 'on_headers'; + + /** + * on_stats: (callable) allows you to get access to transfer statistics of + * a request and access the lower level transfer details of the handler + * associated with your client. ``on_stats`` is a callable that is invoked + * when a handler has finished sending a request. The callback is invoked + * with transfer statistics about the request, the response received, or + * the error encountered. Included in the data is the total amount of time + * taken to send the request. + */ + const ON_STATS = 'on_stats'; + /** * progress: (callable) Defines a function to invoke when transfer * progress is made. The function accepts the following positional diff --git a/core/vendor/guzzlehttp/guzzle/src/TransferStats.php b/core/vendor/guzzlehttp/guzzle/src/TransferStats.php new file mode 100644 index 0000000000000000000000000000000000000000..15f717e1ea6e8edf6bc3a252f5a478e19e835b04 --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/src/TransferStats.php @@ -0,0 +1,126 @@ +<?php +namespace GuzzleHttp; + +use Psr\Http\Message\RequestInterface; +use Psr\Http\Message\ResponseInterface; +use Psr\Http\Message\UriInterface; + +/** + * Represents data at the point after it was transferred either successfully + * or after a network error. + */ +final class TransferStats +{ + private $request; + private $response; + private $transferTime; + private $handlerStats; + private $handlerErrorData; + + /** + * @param RequestInterface $request Request that was sent. + * @param ResponseInterface $response Response received (if any) + * @param null $transferTime Total handler transfer time. + * @param mixed $handlerErrorData Handler error data. + * @param array $handlerStats Handler specific stats. + */ + public function __construct( + RequestInterface $request, + ResponseInterface $response = null, + $transferTime = null, + $handlerErrorData = null, + $handlerStats = [] + ) { + $this->request = $request; + $this->response = $response; + $this->transferTime = $transferTime; + $this->handlerErrorData = $handlerErrorData; + $this->handlerStats = $handlerStats; + } + + /** + * @return RequestInterface + */ + public function getRequest() + { + return $this->request; + } + + /** + * Returns the response that was received (if any). + * + * @return ResponseInterface|null + */ + public function getResponse() + { + return $this->response; + } + + /** + * Returns true if a response was received. + * + * @return bool + */ + public function hasResponse() + { + return $this->response !== null; + } + + /** + * Gets handler specific error data. + * + * This might be an exception, a integer representing an error code, or + * anything else. Relying on this value assumes that you know what handler + * you are using. + * + * @return mixed + */ + public function getHandlerErrorData() + { + return $this->handlerErrorData; + } + + /** + * Get the effective URI the request was sent to. + * + * @return UriInterface + */ + public function getEffectiveUri() + { + return $this->request->getUri(); + } + + /** + * Get the estimated time the request was being transferred by the handler. + * + * @return float Time in seconds. + */ + public function getTransferTime() + { + return $this->transferTime; + } + + /** + * Gets an array of all of the handler specific transfer data. + * + * @return array + */ + public function getHandlerStats() + { + return $this->handlerStats; + } + + /** + * Get a specific handler statistic from the handler by name. + * + * @param string $stat Handler specific transfer stat to retrieve. + * + * @return mixed|null + */ + public function getHandlerStat($stat) + { + return isset($this->handlerStats[$stat]) + ? $this->handlerStats[$stat] + : null; + } +} diff --git a/core/vendor/guzzlehttp/guzzle/src/functions.php b/core/vendor/guzzlehttp/guzzle/src/functions.php index f5ff1fcb26f7d95e1b92f8f416d2dfed90d3d4f5..d0a2ca86dbee6e9f47eee1654cad6bff9164f9a1 100644 --- a/core/vendor/guzzlehttp/guzzle/src/functions.php +++ b/core/vendor/guzzlehttp/guzzle/src/functions.php @@ -131,7 +131,7 @@ function default_user_agent() if (!$defaultAgent) { $defaultAgent = 'GuzzleHttp/' . Client::VERSION; - if (extension_loaded('curl')) { + if (extension_loaded('curl') && function_exists('curl_version')) { $defaultAgent .= ' curl/' . \curl_version()['version']; } $defaultAgent .= ' PHP/' . PHP_VERSION; @@ -166,6 +166,8 @@ function default_ca_bundle() '/usr/local/share/certs/ca-root-nss.crt', // OS X provided by homebrew (using the default path) '/usr/local/etc/openssl/cert.pem', + // Google app engine + '/etc/ca-certificates.crt', // Windows? 'C:\\windows\\system32\\curl-ca-bundle.crt', 'C:\\windows\\curl-ca-bundle.crt', @@ -223,3 +225,56 @@ function normalize_header_keys(array $headers) return $result; } + +/** + * Returns true if the provided host matches any of the no proxy areas. + * + * This method will strip a port from the host if it is present. Each pattern + * can be matched with an exact match (e.g., "foo.com" == "foo.com") or a + * partial match: (e.g., "foo.com" == "baz.foo.com" and ".foo.com" == + * "baz.foo.com", but ".foo.com" != "foo.com"). + * + * Areas are matched in the following cases: + * 1. "*" (without quotes) always matches any hosts. + * 2. An exact match. + * 3. The area starts with "." and the area is the last part of the host. e.g. + * '.mit.edu' will match any host that ends with '.mit.edu'. + * + * @param string $host Host to check against the patterns. + * @param array $noProxyArray An array of host patterns. + * + * @return bool + */ +function is_host_in_noproxy($host, array $noProxyArray) +{ + if (strlen($host) === 0) { + throw new \InvalidArgumentException('Empty host provided'); + } + + // Strip port if present. + if (strpos($host, ':')) { + $host = explode($host, ':', 2)[0]; + } + + foreach ($noProxyArray as $area) { + // Always match on wildcards. + if ($area === '*') { + return true; + } elseif (empty($area)) { + // Don't match on empty values. + continue; + } elseif ($area === $host) { + // Exact matches. + return true; + } else { + // Special match if the area when prefixed with ".". Remove any + // existing leading "." and add a new leading ".". + $area = '.' . ltrim($area, '.'); + if (substr($host, -(strlen($area))) === $area) { + return true; + } + } + } + + return false; +}