From e9f047ccf8dc470b80c1c298b6ed010101a06c7f Mon Sep 17 00:00:00 2001 From: Pantheon Automation Date: Mon, 18 Jul 2016 09:07:48 -0700 Subject: [PATCH] Update to Drupal 8.1.7. For more information, see https://www.drupal.org/project/drupal/releases/8.1.7 --- .htaccess | 4 +- composer.lock | 52 +-- core/CHANGELOG.txt | 4 + core/composer.json | 2 +- core/lib/Drupal.php | 2 +- .../Config/Entity/ConfigDependencyManager.php | 4 +- core/lib/Drupal/Core/Http/ClientFactory.php | 7 + core/modules/ckeditor/ckeditor.module | 7 +- core/modules/system/system.install | 16 - core/modules/user/src/MigratePassword.php | 5 + core/modules/user/src/UserServiceProvider.php | 5 + .../classy/templates/layout/page.html.twig | 1 - sites/default/default.settings.php | 3 - vendor/composer/installed.json | 58 +-- vendor/guzzlehttp/guzzle/.travis.yml | 5 +- vendor/guzzlehttp/guzzle/CHANGELOG.md | 44 +++ vendor/guzzlehttp/guzzle/LICENSE | 2 +- vendor/guzzlehttp/guzzle/README.md | 10 +- vendor/guzzlehttp/guzzle/composer.json | 12 +- vendor/guzzlehttp/guzzle/src/Client.php | 59 +-- .../guzzlehttp/guzzle/src/ClientInterface.php | 4 +- .../guzzle/src/Cookie/CookieJar.php | 22 +- .../guzzle/src/Cookie/FileCookieJar.php | 11 +- .../guzzle/src/Cookie/SessionCookieJar.php | 11 +- .../guzzle/src/Cookie/SetCookie.php | 10 +- .../guzzle/src/Exception/RequestException.php | 64 +++- .../guzzle/src/Handler/CurlFactory.php | 19 +- .../guzzle/src/Handler/CurlMultiHandler.php | 2 +- .../guzzle/src/Handler/EasyHandle.php | 5 + .../guzzle/src/Handler/MockHandler.php | 17 +- .../guzzlehttp/guzzle/src/Handler/Proxy.php | 3 +- .../guzzle/src/Handler/StreamHandler.php | 56 ++- vendor/guzzlehttp/guzzle/src/HandlerStack.php | 23 +- vendor/guzzlehttp/guzzle/src/Middleware.php | 13 +- vendor/guzzlehttp/guzzle/src/Pool.php | 6 +- vendor/guzzlehttp/guzzle/src/UriTemplate.php | 54 +-- vendor/guzzlehttp/guzzle/src/functions.php | 53 ++- vendor/guzzlehttp/promises/CHANGELOG.md | 16 + vendor/guzzlehttp/promises/README.md | 10 +- .../guzzlehttp/promises/src/EachPromise.php | 31 +- .../promises/src/FulfilledPromise.php | 2 + vendor/guzzlehttp/promises/src/Promise.php | 31 +- .../promises/src/RejectedPromise.php | 3 + vendor/guzzlehttp/promises/src/TaskQueue.php | 1 + vendor/guzzlehttp/promises/src/functions.php | 17 +- vendor/guzzlehttp/psr7/CHANGELOG.md | 42 +++ vendor/guzzlehttp/psr7/Makefile | 16 + vendor/guzzlehttp/psr7/README.md | 43 +-- vendor/guzzlehttp/psr7/composer.json | 2 +- vendor/guzzlehttp/psr7/src/CachingStream.php | 12 +- vendor/guzzlehttp/psr7/src/InflateStream.php | 27 +- vendor/guzzlehttp/psr7/src/MessageTrait.php | 123 ++++--- .../guzzlehttp/psr7/src/MultipartStream.php | 4 +- vendor/guzzlehttp/psr7/src/Request.php | 69 ++-- vendor/guzzlehttp/psr7/src/Response.php | 19 +- vendor/guzzlehttp/psr7/src/ServerRequest.php | 346 ++++++++++++++++++ vendor/guzzlehttp/psr7/src/Stream.php | 2 +- vendor/guzzlehttp/psr7/src/UploadedFile.php | 316 ++++++++++++++++ vendor/guzzlehttp/psr7/src/Uri.php | 307 ++++++++-------- vendor/guzzlehttp/psr7/src/functions.php | 52 ++- web.config | 8 + 61 files changed, 1613 insertions(+), 561 deletions(-) create mode 100644 core/modules/user/src/MigratePassword.php create mode 100644 core/modules/user/src/UserServiceProvider.php create mode 100644 vendor/guzzlehttp/psr7/src/ServerRequest.php create mode 100644 vendor/guzzlehttp/psr7/src/UploadedFile.php diff --git a/.htaccess b/.htaccess index f4024c632..4716fa12c 100644 --- a/.htaccess +++ b/.htaccess @@ -180,8 +180,10 @@ AddEncoding gzip svgz -# Add headers to all responses. +# Various header fixes. # Disable content sniffing, since it's an attack vector. Header always set X-Content-Type-Options nosniff + # Disable Proxy header, since it's an attack vector. + RequestHeader unset Proxy diff --git a/composer.lock b/composer.lock index f2c6c183a..9f9324119 100644 --- a/composer.lock +++ b/composer.lock @@ -678,32 +678,32 @@ }, { "name": "guzzlehttp/guzzle", - "version": "6.1.0", + "version": "6.2.1", "source": { "type": "git", "url": "https://github.com/guzzle/guzzle.git", - "reference": "66fd14b4d0b8f2389eaf37c5458608c7cb793a81" + "reference": "3f808fba627f2c5b69e2501217bf31af349c1427" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/guzzle/zipball/66fd14b4d0b8f2389eaf37c5458608c7cb793a81", - "reference": "66fd14b4d0b8f2389eaf37c5458608c7cb793a81", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/3f808fba627f2c5b69e2501217bf31af349c1427", + "reference": "3f808fba627f2c5b69e2501217bf31af349c1427", "shasum": "" }, "require": { - "guzzlehttp/promises": "~1.0", - "guzzlehttp/psr7": "~1.1", - "php": ">=5.5.0" + "guzzlehttp/promises": "^1.0", + "guzzlehttp/psr7": "^1.3.1", + "php": ">=5.5" }, "require-dev": { "ext-curl": "*", - "phpunit/phpunit": "~4.0", - "psr/log": "~1.0" + "phpunit/phpunit": "^4.0", + "psr/log": "^1.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "6.1-dev" + "dev-master": "6.2-dev" } }, "autoload": { @@ -736,20 +736,20 @@ "rest", "web service" ], - "time": "2015-09-08 17:36:26" + "time": "2016-07-15 17:22:37" }, { "name": "guzzlehttp/promises", - "version": "1.0.2", + "version": "1.2.0", "source": { "type": "git", "url": "https://github.com/guzzle/promises.git", - "reference": "97fe7210def29451ec74923b27e552238defd75a" + "reference": "c10d860e2a9595f8883527fa0021c7da9e65f579" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/promises/zipball/97fe7210def29451ec74923b27e552238defd75a", - "reference": "97fe7210def29451ec74923b27e552238defd75a", + "url": "https://api.github.com/repos/guzzle/promises/zipball/c10d860e2a9595f8883527fa0021c7da9e65f579", + "reference": "c10d860e2a9595f8883527fa0021c7da9e65f579", "shasum": "" }, "require": { @@ -787,20 +787,20 @@ "keywords": [ "promise" ], - "time": "2015-08-15 19:37:21" + "time": "2016-05-18 16:56:05" }, { "name": "guzzlehttp/psr7", - "version": "1.2.0", + "version": "1.3.1", "source": { "type": "git", "url": "https://github.com/guzzle/psr7.git", - "reference": "4ef919b0cf3b1989523138b60163bbcb7ba1ff7e" + "reference": "5c6447c9df362e8f8093bda8f5d8873fe5c7f65b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/psr7/zipball/4ef919b0cf3b1989523138b60163bbcb7ba1ff7e", - "reference": "4ef919b0cf3b1989523138b60163bbcb7ba1ff7e", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/5c6447c9df362e8f8093bda8f5d8873fe5c7f65b", + "reference": "5c6447c9df362e8f8093bda8f5d8873fe5c7f65b", "shasum": "" }, "require": { @@ -816,7 +816,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "1.4-dev" } }, "autoload": { @@ -845,7 +845,7 @@ "stream", "uri" ], - "time": "2015-08-15 19:32:36" + "time": "2016-06-24 23:00:38" }, { "name": "ircmaxell/password-compat", @@ -1057,12 +1057,12 @@ "source": { "type": "git", "url": "https://github.com/php-fig/log.git", - "reference": "fe0936ee26643249e916849d48e3a51d5f5e278b" + "reference": "1.0.0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/log/zipball/fe0936ee26643249e916849d48e3a51d5f5e278b", - "reference": "fe0936ee26643249e916849d48e3a51d5f5e278b", + "url": "https://api.github.com/repos/php-fig/log/zipball/1.0.0", + "reference": "1.0.0", "shasum": "" }, "type": "library", @@ -1183,7 +1183,7 @@ ], "authors": [ { - "name": "Symfony CMF Community", + "name": "Symfony CMF community", "homepage": "https://github.com/symfony-cmf/Routing/contributors" } ], diff --git a/core/CHANGELOG.txt b/core/CHANGELOG.txt index 64ad16798..f6fad6c59 100644 --- a/core/CHANGELOG.txt +++ b/core/CHANGELOG.txt @@ -1,3 +1,7 @@ +Drupal 8.1.7, 2016-07-18 +------------------------ +- Fixed security issue. SA-CORE-2016-003. + Drupal 8.1.3, 2016-06-15 ------------------------ - Fixed security issue. SA-CORE-2016-002. diff --git a/core/composer.json b/core/composer.json index a8ee73e4c..fbe4c1b7c 100644 --- a/core/composer.json +++ b/core/composer.json @@ -21,7 +21,7 @@ "twig/twig": "^1.23.1", "doctrine/common": "2.5.*", "doctrine/annotations": "1.2.*", - "guzzlehttp/guzzle": "~6.1", + "guzzlehttp/guzzle": "~6.2", "symfony-cmf/routing": "1.3.*", "easyrdf/easyrdf": "0.9.*", "zendframework/zend-feed": "~2.4", diff --git a/core/lib/Drupal.php b/core/lib/Drupal.php index aa4fc0aee..9582f0e43 100644 --- a/core/lib/Drupal.php +++ b/core/lib/Drupal.php @@ -81,7 +81,7 @@ class Drupal { /** * The current system version. */ - const VERSION = '8.1.5'; + const VERSION = '8.1.7'; /** * Core API compatibility. diff --git a/core/lib/Drupal/Core/Config/Entity/ConfigDependencyManager.php b/core/lib/Drupal/Core/Config/Entity/ConfigDependencyManager.php index c274f28a1..ef522ad8d 100644 --- a/core/lib/Drupal/Core/Config/Entity/ConfigDependencyManager.php +++ b/core/lib/Drupal/Core/Config/Entity/ConfigDependencyManager.php @@ -206,7 +206,7 @@ class ConfigDependencyManager { * @return int * The comparison result for uasort(). */ - protected function sortGraphByWeight(array $a, array $b) { + protected static function sortGraphByWeight(array $a, array $b) { $weight_cmp = SortArray::sortByKeyInt($a, $b, 'weight'); if ($weight_cmp === 0) { @@ -227,7 +227,7 @@ class ConfigDependencyManager { * @return int * The comparison result for uasort(). */ - public function sortGraph(array $a, array $b) { + public static function sortGraph(array $a, array $b) { $weight_cmp = SortArray::sortByKeyInt($a, $b, 'weight') * -1; if ($weight_cmp === 0) { diff --git a/core/lib/Drupal/Core/Http/ClientFactory.php b/core/lib/Drupal/Core/Http/ClientFactory.php index a68f08517..3dcf35374 100644 --- a/core/lib/Drupal/Core/Http/ClientFactory.php +++ b/core/lib/Drupal/Core/Http/ClientFactory.php @@ -52,6 +52,13 @@ class ClientFactory { 'User-Agent' => 'Drupal/' . \Drupal::VERSION . ' (+https://www.drupal.org/) ' . \GuzzleHttp\default_user_agent(), ], 'handler' => $this->stack, + // Security consideration: prevent Guzzle from using environment variables + // to configure the outbound proxy. + 'proxy' => [ + 'http' => NULL, + 'https' => NULL, + 'no' => [], + ] ]; $config = NestedArray::mergeDeep($default_config, Settings::get('http_client_config', []), $config); diff --git a/core/modules/ckeditor/ckeditor.module b/core/modules/ckeditor/ckeditor.module index a7a85383d..115afe24c 100644 --- a/core/modules/ckeditor/ckeditor.module +++ b/core/modules/ckeditor/ckeditor.module @@ -68,13 +68,14 @@ function ckeditor_ckeditor_css_alter(array &$css, Editor $editor) { } /** - * Retrieves the default theme's CKEditor stylesheets defined in the .info file. + * Retrieves the default theme's CKEditor stylesheets. * * Themes may specify iframe-specific CSS files for use with CKEditor by - * including a "ckeditor_stylesheets" key in the theme .info file. + * including a "ckeditor_stylesheets" key in their .info.yml file. * * @code - * ckeditor_stylesheets[] = css/ckeditor-iframe.css + * ckeditor_stylesheets: + * - css/ckeditor-iframe.css * @endcode */ function _ckeditor_theme_css($theme = NULL) { diff --git a/core/modules/system/system.install b/core/modules/system/system.install index 5bc7d2ab9..4a39f7bdd 100644 --- a/core/modules/system/system.install +++ b/core/modules/system/system.install @@ -797,22 +797,6 @@ function system_requirements($phase) { } } - // Check if the Twig C extension is available. - if ($phase == 'runtime') { - $url = 'http://twig.sensiolabs.org/doc/installation.html#installing-the-c-extension'; - $requirements['twig_c_extension'] = [ - 'title' => t('Twig C extension'), - 'severity' => REQUIREMENT_INFO, - ]; - if (!function_exists('twig_template_get_attributes')) { - $requirements['twig_c_extension']['value'] = t('Not available'); - $requirements['twig_c_extension']['description'] = t('Enabling the Twig C extension can greatly increase rendering performance. See the installation instructions for more detail.', [':url' => $url]); - } - else { - $requirements['twig_c_extension']['description'] = t('The Twig C extension is available', [':url' => $url]); - } - } - // Check xdebug.max_nesting_level, as some pages will not work if it is too // low. if (extension_loaded('xdebug')) { diff --git a/core/modules/user/src/MigratePassword.php b/core/modules/user/src/MigratePassword.php new file mode 100644 index 000000000..79715dfc8 --- /dev/null +++ b/core/modules/user/src/MigratePassword.php @@ -0,0 +1,5 @@ +=5.5.0" + "guzzlehttp/promises": "^1.0", + "guzzlehttp/psr7": "^1.3.1", + "php": ">=5.5" }, "require-dev": { "ext-curl": "*", - "phpunit/phpunit": "~4.0", - "psr/log": "~1.0" + "phpunit/phpunit": "^4.0", + "psr/log": "^1.0" }, - "time": "2015-09-08 17:36:26", + "time": "2016-07-15 17:22:37", "type": "library", "extra": { "branch-alias": { - "dev-master": "6.1-dev" + "dev-master": "6.2-dev" } }, "installation-source": "dist", diff --git a/vendor/guzzlehttp/guzzle/.travis.yml b/vendor/guzzlehttp/guzzle/.travis.yml index c0689d161..a4cd64ccd 100644 --- a/vendor/guzzlehttp/guzzle/.travis.yml +++ b/vendor/guzzlehttp/guzzle/.travis.yml @@ -1,5 +1,7 @@ language: php +sudo: false + php: - 5.5 - 5.6 @@ -12,16 +14,17 @@ before_script: - composer install --no-interaction --prefer-source --dev - ~/.nvm/nvm.sh install v0.6.14 - ~/.nvm/nvm.sh run v0.6.14 + - '[ "$TRAVIS_PHP_VERSION" != "7.0" ] || echo "xdebug.overload_var_dump = 1" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini' script: make test matrix: allow_failures: - php: hhvm - - php: 7.0 fast_finish: true before_deploy: + - rvm 1.9.3 do gem install mime-types -v 2.6.2 - make package deploy: diff --git a/vendor/guzzlehttp/guzzle/CHANGELOG.md b/vendor/guzzlehttp/guzzle/CHANGELOG.md index de7da2d6f..affddab49 100644 --- a/vendor/guzzlehttp/guzzle/CHANGELOG.md +++ b/vendor/guzzlehttp/guzzle/CHANGELOG.md @@ -1,5 +1,49 @@ # CHANGELOG +## 6.2.1 - 2016-07-18 + +* Address HTTP_PROXY security vulnerability, CVE-2016-5385: + https://httpoxy.org/ +* Fixing timeout bug with StreamHandler: + https://github.com/guzzle/guzzle/pull/1488 +* Only read up to `Content-Length` in PHP StreamHandler to avoid timeouts when + a server does not honor `Connection: close`. +* Ignore URI fragment when sending requests. + +## 6.2.0 - 2016-03-21 + +* Feature: added `GuzzleHttp\json_encode` and `GuzzleHttp\json_decode`. + https://github.com/guzzle/guzzle/pull/1389 +* Bug fix: Fix sleep calculation when waiting for delayed requests. + https://github.com/guzzle/guzzle/pull/1324 +* Feature: More flexible history containers. + https://github.com/guzzle/guzzle/pull/1373 +* Bug fix: defer sink stream opening in StreamHandler. + https://github.com/guzzle/guzzle/pull/1377 +* Bug fix: do not attempt to escape cookie values. + https://github.com/guzzle/guzzle/pull/1406 +* Feature: report original content encoding and length on decoded responses. + https://github.com/guzzle/guzzle/pull/1409 +* Bug fix: rewind seekable request bodies before dispatching to cURL. + https://github.com/guzzle/guzzle/pull/1422 +* Bug fix: provide an empty string to `http_build_query` for HHVM workaround. + https://github.com/guzzle/guzzle/pull/1367 + +## 6.1.1 - 2015-11-22 + +* Bug fix: Proxy::wrapSync() now correctly proxies to the appropriate handler + https://github.com/guzzle/guzzle/commit/911bcbc8b434adce64e223a6d1d14e9a8f63e4e4 +* Feature: HandlerStack is now more generic. + https://github.com/guzzle/guzzle/commit/f2102941331cda544745eedd97fc8fd46e1ee33e +* Bug fix: setting verify to false in the StreamHandler now disables peer + verification. https://github.com/guzzle/guzzle/issues/1256 +* Feature: Middleware now uses an exception factory, including more error + context. https://github.com/guzzle/guzzle/pull/1282 +* Feature: better support for disabled functions. + https://github.com/guzzle/guzzle/pull/1287 +* Bug fix: fixed regression where MockHandler was not using `sink`. + https://github.com/guzzle/guzzle/pull/1292 + ## 6.1.0 - 2015-09-08 * Feature: Added the `on_stats` request option to provide access to transfer diff --git a/vendor/guzzlehttp/guzzle/LICENSE b/vendor/guzzlehttp/guzzle/LICENSE index 9af9fba68..ea7f07c54 100644 --- a/vendor/guzzlehttp/guzzle/LICENSE +++ b/vendor/guzzlehttp/guzzle/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2011-2015 Michael Dowling, https://github.com/mtdowling +Copyright (c) 2011-2016 Michael Dowling, https://github.com/mtdowling Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/vendor/guzzlehttp/guzzle/README.md b/vendor/guzzlehttp/guzzle/README.md index 2d721c06f..772b18d0b 100644 --- a/vendor/guzzlehttp/guzzle/README.md +++ b/vendor/guzzlehttp/guzzle/README.md @@ -1,7 +1,7 @@ Guzzle, PHP HTTP client ======================= -[![Build Status](https://secure.travis-ci.org/guzzle/guzzle.svg?branch=master)](http://travis-ci.org/guzzle/guzzle) +[![Build Status](https://travis-ci.org/guzzle/guzzle.svg?branch=master)](https://travis-ci.org/guzzle/guzzle) Guzzle is a PHP HTTP client that makes it easy to send HTTP requests and trivial to integrate with web services. @@ -18,13 +18,13 @@ trivial to integrate with web services. - Middleware system allows you to augment and compose client behavior. ```php -$client = new GuzzleHttp\Client(); +$client = new \GuzzleHttp\Client(); $res = $client->request('GET', 'https://api.github.com/user', [ 'auth' => ['user', 'pass'] ]); echo $res->getStatusCode(); -// "200" -echo $res->getHeader('content-type'); +// 200 +echo $res->getHeaderLine('content-type'); // 'application/json; charset=utf8' echo $res->getBody(); // {"type":"User"...' @@ -57,7 +57,7 @@ curl -sS https://getcomposer.org/installer | php Next, run the Composer command to install the latest stable version of Guzzle: ```bash -composer.phar require guzzlehttp/guzzle +php composer.phar require guzzlehttp/guzzle ``` After installing, you need to require Composer's autoloader: diff --git a/vendor/guzzlehttp/guzzle/composer.json b/vendor/guzzlehttp/guzzle/composer.json index 1f8b07004..218c24736 100644 --- a/vendor/guzzlehttp/guzzle/composer.json +++ b/vendor/guzzlehttp/guzzle/composer.json @@ -13,14 +13,14 @@ } ], "require": { - "php": ">=5.5.0", - "guzzlehttp/psr7": "~1.1", - "guzzlehttp/promises": "~1.0" + "php": ">=5.5", + "guzzlehttp/psr7": "^1.3.1", + "guzzlehttp/promises": "^1.0" }, "require-dev": { "ext-curl": "*", - "phpunit/phpunit": "~4.0", - "psr/log": "~1.0" + "phpunit/phpunit": "^4.0", + "psr/log": "^1.0" }, "autoload": { "files": ["src/functions_include.php"], @@ -35,7 +35,7 @@ }, "extra": { "branch-alias": { - "dev-master": "6.1-dev" + "dev-master": "6.2-dev" } } } diff --git a/vendor/guzzlehttp/guzzle/src/Client.php b/vendor/guzzlehttp/guzzle/src/Client.php index 2e86ecee4..6089c1869 100644 --- a/vendor/guzzlehttp/guzzle/src/Client.php +++ b/vendor/guzzlehttp/guzzle/src/Client.php @@ -93,7 +93,7 @@ class Client implements ClientInterface $options = $this->prepareDefaults($options); return $this->transfer( - $request->withUri($this->buildUri($request->getUri(), $options)), + $request->withUri($this->buildUri($request->getUri(), $options), $request->hasHeader('Host')), $options ); } @@ -104,7 +104,7 @@ class Client implements ClientInterface return $this->sendAsync($request, $options)->wait(); } - public function requestAsync($method, $uri = null, array $options = []) + public function requestAsync($method, $uri = '', array $options = []) { $options = $this->prepareDefaults($options); // Remove request modifying parameter because it can be done up-front. @@ -123,7 +123,7 @@ class Client implements ClientInterface return $this->transfer($request, $options); } - public function request($method, $uri = null, array $options = []) + public function request($method, $uri = '', array $options = []) { $options[RequestOptions::SYNCHRONOUS] = true; return $this->requestAsync($method, $uri, $options)->wait(); @@ -138,11 +138,14 @@ class Client implements ClientInterface private function buildUri($uri, array $config) { - if (!isset($config['base_uri'])) { - return $uri instanceof UriInterface ? $uri : new Psr7\Uri($uri); + // for BC we accept null which would otherwise fail in uri_for + $uri = Psr7\uri_for($uri === null ? '' : $uri); + + if (isset($config['base_uri'])) { + $uri = Psr7\Uri::resolve(Psr7\uri_for($config['base_uri']), $uri); } - return Psr7\Uri::resolve(Psr7\uri_for($config['base_uri']), $uri); + return $uri->getScheme() === '' ? $uri->withScheme('http') : $uri; } /** @@ -160,9 +163,13 @@ class Client implements ClientInterface 'cookies' => false ]; - // Use the standard Linux HTTP_PROXY and HTTPS_PROXY if set - if ($proxy = getenv('HTTP_PROXY')) { - $defaults['proxy']['http'] = $proxy; + // Use the standard Linux HTTP_PROXY and HTTPS_PROXY if set. + + // We can only trust the HTTP_PROXY environment variable in a CLI + // process due to the fact that PHP has no reliable mechanism to + // get environment variables that start with "HTTP_". + if (php_sapi_name() == 'cli' && getenv('HTTP_PROXY')) { + $defaults['proxy']['http'] = getenv('HTTP_PROXY'); } if ($proxy = getenv('HTTPS_PROXY')) { @@ -173,7 +180,7 @@ class Client implements ClientInterface $cleanedNoProxy = str_replace(' ', '', $noProxy); $defaults['proxy']['no'] = explode(',', $cleanedNoProxy); } - + $this->config = $config + $defaults; if (!empty($config['cookies']) && $config['cookies'] === true) { @@ -255,7 +262,7 @@ class Client implements ClientInterface unset($options['save_to']); } - // exceptions -> http_error + // exceptions -> http_errors if (isset($options['exceptions'])) { $options['http_errors'] = $options['exceptions']; unset($options['exceptions']); @@ -291,15 +298,20 @@ class Client implements ClientInterface . 'x-www-form-urlencoded requests, and the multipart ' . 'option to send multipart/form-data requests.'); } - $options['body'] = http_build_query($options['form_params'], null, '&'); + $options['body'] = http_build_query($options['form_params'], '', '&'); unset($options['form_params']); $options['_conditional']['Content-Type'] = 'application/x-www-form-urlencoded'; } if (isset($options['multipart'])) { - $elements = $options['multipart']; + $options['body'] = new Psr7\MultipartStream($options['multipart']); unset($options['multipart']); - $options['body'] = new Psr7\MultipartStream($elements); + } + + if (isset($options['json'])) { + $options['body'] = \GuzzleHttp\json_encode($options['json']); + unset($options['json']); + $options['_conditional']['Content-Type'] = 'application/json'; } if (!empty($options['decode_content']) @@ -325,13 +337,10 @@ class Client implements ClientInterface unset($options['body']); } - if (!empty($options['auth'])) { + if (!empty($options['auth']) && is_array($options['auth'])) { $value = $options['auth']; - $type = is_array($value) - ? (isset($value[2]) ? strtolower($value[2]) : 'basic') - : $value; - $config['auth'] = $value; - switch (strtolower($type)) { + $type = isset($value[2]) ? strtolower($value[2]) : 'basic'; + switch ($type) { case 'basic': $modify['set_headers']['Authorization'] = 'Basic ' . base64_encode("$value[0]:$value[1]"); @@ -356,10 +365,12 @@ class Client implements ClientInterface unset($options['query']); } - if (isset($options['json'])) { - $modify['body'] = Psr7\stream_for(json_encode($options['json'])); - $options['_conditional']['Content-Type'] = 'application/json'; - unset($options['json']); + // Ensure that sink is not an invalid value. + if (isset($options['sink'])) { + // TODO: Add more sink validation? + if (is_bool($options['sink'])) { + throw new \InvalidArgumentException('sink must not be a boolean'); + } } $request = Psr7\modify_request($request, $modify); diff --git a/vendor/guzzlehttp/guzzle/src/ClientInterface.php b/vendor/guzzlehttp/guzzle/src/ClientInterface.php index b5b2306a4..5a67b66bf 100644 --- a/vendor/guzzlehttp/guzzle/src/ClientInterface.php +++ b/vendor/guzzlehttp/guzzle/src/ClientInterface.php @@ -12,7 +12,7 @@ use Psr\Http\Message\UriInterface; */ interface ClientInterface { - const VERSION = '6.1.0'; + const VERSION = '6.2.1'; /** * Send an HTTP request. @@ -44,7 +44,7 @@ interface ClientInterface * relative path to append to the base path of the client. The URL can * contain the query string as well. * - * @param string $method HTTP method + * @param string $method HTTP method. * @param string|UriInterface $uri URI object or string. * @param array $options Request options to apply. * diff --git a/vendor/guzzlehttp/guzzle/src/Cookie/CookieJar.php b/vendor/guzzlehttp/guzzle/src/Cookie/CookieJar.php index ea60068de..7fffd30ef 100644 --- a/vendor/guzzlehttp/guzzle/src/Cookie/CookieJar.php +++ b/vendor/guzzlehttp/guzzle/src/Cookie/CookieJar.php @@ -5,7 +5,7 @@ use Psr\Http\Message\RequestInterface; use Psr\Http\Message\ResponseInterface; /** - * Cookie jar that stores cookies an an array + * Cookie jar that stores cookies as an array */ class CookieJar implements CookieJarInterface { @@ -58,22 +58,10 @@ class CookieJar implements CookieJarInterface } /** - * Quote the cookie value if it is not already quoted and it contains - * problematic characters. - * - * @param string $value Value that may or may not need to be quoted - * - * @return string + * @deprecated */ public static function getCookieValue($value) { - if (substr($value, 0, 1) !== '"' && - substr($value, -1, 1) !== '"' && - strpbrk($value, ';,=') - ) { - $value = '"' . $value . '"'; - } - return $value; } @@ -82,7 +70,7 @@ class CookieJar implements CookieJarInterface * that survives between requests. * * @param SetCookie $cookie Being evaluated. - * @param bool $allowSessionCookies If we should presist session cookies + * @param bool $allowSessionCookies If we should persist session cookies * @return bool */ public static function shouldPersist( @@ -245,10 +233,10 @@ class CookieJar implements CookieJarInterface if ($cookie->matchesPath($path) && $cookie->matchesDomain($host) && !$cookie->isExpired() && - (!$cookie->getSecure() || $scheme == 'https') + (!$cookie->getSecure() || $scheme === 'https') ) { $values[] = $cookie->getName() . '=' - . self::getCookieValue($cookie->getValue()); + . $cookie->getValue(); } } diff --git a/vendor/guzzlehttp/guzzle/src/Cookie/FileCookieJar.php b/vendor/guzzlehttp/guzzle/src/Cookie/FileCookieJar.php index c55bb3478..9887c1d54 100644 --- a/vendor/guzzlehttp/guzzle/src/Cookie/FileCookieJar.php +++ b/vendor/guzzlehttp/guzzle/src/Cookie/FileCookieJar.php @@ -9,9 +9,9 @@ class FileCookieJar extends CookieJar /** @var string filename */ private $filename; - /** @var bool Control whether to presist session cookies or not. */ + /** @var bool Control whether to persist session cookies or not. */ private $storeSessionCookies; - + /** * Create a new FileCookieJar object * @@ -55,7 +55,8 @@ class FileCookieJar extends CookieJar } } - if (false === file_put_contents($filename, json_encode($json))) { + $jsonStr = \GuzzleHttp\json_encode($json); + if (false === file_put_contents($filename, $jsonStr)) { throw new \RuntimeException("Unable to save file {$filename}"); } } @@ -73,9 +74,11 @@ class FileCookieJar extends CookieJar $json = file_get_contents($filename); if (false === $json) { throw new \RuntimeException("Unable to load file {$filename}"); + } elseif ($json === '') { + return; } - $data = json_decode($json, true); + $data = \GuzzleHttp\json_decode($json, true); if (is_array($data)) { foreach (json_decode($json, true) as $cookie) { $this->setCookie(new SetCookie($cookie)); diff --git a/vendor/guzzlehttp/guzzle/src/Cookie/SessionCookieJar.php b/vendor/guzzlehttp/guzzle/src/Cookie/SessionCookieJar.php index d80c4804b..e4bfafd4f 100644 --- a/vendor/guzzlehttp/guzzle/src/Cookie/SessionCookieJar.php +++ b/vendor/guzzlehttp/guzzle/src/Cookie/SessionCookieJar.php @@ -9,7 +9,7 @@ class SessionCookieJar extends CookieJar /** @var string session key */ private $sessionKey; - /** @var bool Control whether to presist session cookies or not. */ + /** @var bool Control whether to persist session cookies or not. */ private $storeSessionCookies; /** @@ -56,11 +56,10 @@ class SessionCookieJar extends CookieJar */ protected function load() { - $cookieJar = isset($_SESSION[$this->sessionKey]) - ? $_SESSION[$this->sessionKey] - : null; - - $data = json_decode($cookieJar, true); + if (!isset($_SESSION[$this->sessionKey])) { + return; + } + $data = json_decode($_SESSION[$this->sessionKey], true); if (is_array($data)) { foreach ($data as $cookie) { $this->setCookie(new SetCookie($cookie)); diff --git a/vendor/guzzlehttp/guzzle/src/Cookie/SetCookie.php b/vendor/guzzlehttp/guzzle/src/Cookie/SetCookie.php index acd654df4..c911e2a3f 100644 --- a/vendor/guzzlehttp/guzzle/src/Cookie/SetCookie.php +++ b/vendor/guzzlehttp/guzzle/src/Cookie/SetCookie.php @@ -86,8 +86,8 @@ class SetCookie { $str = $this->data['Name'] . '=' . $this->data['Value'] . '; '; foreach ($this->data as $k => $v) { - if ($k != 'Name' && $k != 'Value' && $v !== null && $v !== false) { - if ($k == 'Expires') { + if ($k !== 'Name' && $k !== 'Value' && $v !== null && $v !== false) { + if ($k === 'Expires') { $str .= 'Expires=' . gmdate('D, d M Y H:i:s \G\M\T', $v) . '; '; } else { $str .= ($v === true ? $k : "{$k}={$v}") . '; '; @@ -307,7 +307,7 @@ class SetCookie $cookiePath = $this->getPath(); // Match on exact matches or when path is the default empty "/" - if ($cookiePath == '/' || $cookiePath == $requestPath) { + if ($cookiePath === '/' || $cookiePath == $requestPath) { return true; } @@ -317,12 +317,12 @@ class SetCookie } // Match if the last character of the cookie-path is "/" - if (substr($cookiePath, -1, 1) == '/') { + if (substr($cookiePath, -1, 1) === '/') { return true; } // Match if the first character not included in cookie path is "/" - return substr($requestPath, strlen($cookiePath), 1) == '/'; + return substr($requestPath, strlen($cookiePath), 1) === '/'; } /** diff --git a/vendor/guzzlehttp/guzzle/src/Exception/RequestException.php b/vendor/guzzlehttp/guzzle/src/Exception/RequestException.php index 23dd02c42..f01f06d99 100644 --- a/vendor/guzzlehttp/guzzle/src/Exception/RequestException.php +++ b/vendor/guzzlehttp/guzzle/src/Exception/RequestException.php @@ -77,26 +77,70 @@ class RequestException extends TransferException ); } - $level = floor($response->getStatusCode() / 100); - if ($level == '4') { - $label = 'Client error response'; + $level = (int) floor($response->getStatusCode() / 100); + if ($level === 4) { + $label = 'Client error'; $className = __NAMESPACE__ . '\\ClientException'; - } elseif ($level == '5') { - $label = 'Server error response'; + } elseif ($level === 5) { + $label = 'Server error'; $className = __NAMESPACE__ . '\\ServerException'; } else { - $label = 'Unsuccessful response'; + $label = 'Unsuccessful request'; $className = __CLASS__; } - $message = $label . ' [url] ' . $request->getUri() - . ' [http method] ' . $request->getMethod() - . ' [status code] ' . $response->getStatusCode() - . ' [reason phrase] ' . $response->getReasonPhrase(); + // Server Error: `GET /` resulted in a `404 Not Found` response: + // ... (truncated) + $message = sprintf( + '%s: `%s` resulted in a `%s` response', + $label, + $request->getMethod() . ' ' . $request->getUri(), + $response->getStatusCode() . ' ' . $response->getReasonPhrase() + ); + + $summary = static::getResponseBodySummary($response); + + if ($summary !== null) { + $message .= ":\n{$summary}\n"; + } return new $className($message, $request, $response, $previous, $ctx); } + /** + * Get a short summary of the response + * + * Will return `null` if the response is not printable. + * + * @param ResponseInterface $response + * + * @return string|null + */ + public static function getResponseBodySummary(ResponseInterface $response) + { + $body = $response->getBody(); + + if (!$body->isSeekable()) { + return null; + } + + $size = $body->getSize(); + $summary = $body->read(120); + $body->rewind(); + + if ($size > 120) { + $summary .= ' (truncated...)'; + } + + // Matches any printable character, including unicode characters: + // letters, marks, numbers, punctuation, spacing, and separators. + if (preg_match('/[^\pL\pM\pN\pP\pS\pZ\n\r\t]/', $summary)) { + return null; + } + + return $summary; + } + /** * Get the request that caused the exception * diff --git a/vendor/guzzlehttp/guzzle/src/Handler/CurlFactory.php b/vendor/guzzlehttp/guzzle/src/Handler/CurlFactory.php index e8d9388e2..9f7574542 100644 --- a/vendor/guzzlehttp/guzzle/src/Handler/CurlFactory.php +++ b/vendor/guzzlehttp/guzzle/src/Handler/CurlFactory.php @@ -194,7 +194,7 @@ class CurlFactory implements CurlFactoryInterface $conf = [ '_headers' => $easy->request->getHeaders(), CURLOPT_CUSTOMREQUEST => $easy->request->getMethod(), - CURLOPT_URL => (string) $easy->request->getUri(), + CURLOPT_URL => (string) $easy->request->getUri()->withFragment(''), CURLOPT_RETURNTRANSFER => false, CURLOPT_HEADER => false, CURLOPT_CONNECTTIMEOUT => 150, @@ -265,6 +265,9 @@ class CurlFactory implements CurlFactoryInterface $this->removeHeader('Content-Length', $conf); } $body = $request->getBody(); + if ($body->isSeekable()) { + $body->rewind(); + } $conf[CURLOPT_READFUNCTION] = function ($ch, $fd, $length) use ($body) { return $body->read($length); }; @@ -492,12 +495,14 @@ class CurlFactory implements CurlFactoryInterface private function createHeaderFn(EasyHandle $easy) { - if (!isset($easy->options['on_headers'])) { - $onHeaders = null; - } elseif (!is_callable($easy->options['on_headers'])) { - throw new \InvalidArgumentException('on_headers must be callable'); - } else { + if (isset($easy->options['on_headers'])) { $onHeaders = $easy->options['on_headers']; + + if (!is_callable($onHeaders)) { + throw new \InvalidArgumentException('on_headers must be callable'); + } + } else { + $onHeaders = null; } return function ($ch, $h) use ( @@ -509,7 +514,7 @@ class CurlFactory implements CurlFactoryInterface if ($value === '') { $startingResponse = true; $easy->createResponse(); - if ($onHeaders) { + if ($onHeaders !== null) { try { $onHeaders($easy->response); } catch (\Exception $e) { diff --git a/vendor/guzzlehttp/guzzle/src/Handler/CurlMultiHandler.php b/vendor/guzzlehttp/guzzle/src/Handler/CurlMultiHandler.php index 417850b44..945d06ee4 100644 --- a/vendor/guzzlehttp/guzzle/src/Handler/CurlMultiHandler.php +++ b/vendor/guzzlehttp/guzzle/src/Handler/CurlMultiHandler.php @@ -192,6 +192,6 @@ class CurlMultiHandler } } - return max(0, $currentTime - $nextTime); + return max(0, $nextTime - $currentTime) * 1000000; } } diff --git a/vendor/guzzlehttp/guzzle/src/Handler/EasyHandle.php b/vendor/guzzlehttp/guzzle/src/Handler/EasyHandle.php index c4b927e5e..7754e9111 100644 --- a/vendor/guzzlehttp/guzzle/src/Handler/EasyHandle.php +++ b/vendor/guzzlehttp/guzzle/src/Handler/EasyHandle.php @@ -56,8 +56,13 @@ final class EasyHandle if (!empty($this->options['decode_content']) && isset($normalizedKeys['content-encoding']) ) { + $headers['x-encoded-content-encoding'] + = $headers[$normalizedKeys['content-encoding']]; unset($headers[$normalizedKeys['content-encoding']]); if (isset($normalizedKeys['content-length'])) { + $headers['x-encoded-content-length'] + = $headers[$normalizedKeys['content-length']]; + $bodyLength = (int) $this->sink->getSize(); if ($bodyLength) { $headers[$normalizedKeys['content-length']] = $bodyLength; diff --git a/vendor/guzzlehttp/guzzle/src/Handler/MockHandler.php b/vendor/guzzlehttp/guzzle/src/Handler/MockHandler.php index 4b1b0af8d..7bbe7354c 100644 --- a/vendor/guzzlehttp/guzzle/src/Handler/MockHandler.php +++ b/vendor/guzzlehttp/guzzle/src/Handler/MockHandler.php @@ -27,7 +27,7 @@ class MockHandler implements \Countable * @param callable $onFulfilled Callback to invoke when the return value is fulfilled. * @param callable $onRejected Callback to invoke when the return value is rejected. * - * @return MockHandler + * @return HandlerStack */ public static function createWithMiddleware( array $queue = null, @@ -74,7 +74,7 @@ class MockHandler implements \Countable $response = array_shift($this->queue); if (is_callable($response)) { - $response = $response($request, $options); + $response = call_user_func($response, $request, $options); } $response = $response instanceof \Exception @@ -87,6 +87,19 @@ class MockHandler implements \Countable if ($this->onFulfilled) { call_user_func($this->onFulfilled, $value); } + if (isset($options['sink'])) { + $contents = (string) $value->getBody(); + $sink = $options['sink']; + + if (is_resource($sink)) { + fwrite($sink, $contents); + } elseif (is_string($sink)) { + file_put_contents($sink, $contents); + } elseif ($sink instanceof \Psr\Http\Message\StreamInterface) { + $sink->write($contents); + } + } + return $value; }, function ($reason) use ($request, $options) { diff --git a/vendor/guzzlehttp/guzzle/src/Handler/Proxy.php b/vendor/guzzlehttp/guzzle/src/Handler/Proxy.php index 9bd76d251..f8b00be0b 100644 --- a/vendor/guzzlehttp/guzzle/src/Handler/Proxy.php +++ b/vendor/guzzlehttp/guzzle/src/Handler/Proxy.php @@ -1,6 +1,7 @@ checkDecode($options, $headers, $stream); $stream = Psr7\stream_for($stream); - $sink = $this->createSink($stream, $options); + $sink = $stream; + + if (strcasecmp('HEAD', $request->getMethod())) { + $sink = $this->createSink($stream, $options); + } + $response = new Psr7\Response($status, $headers, $sink, $ver, $reason); if (isset($options['on_headers'])) { @@ -118,8 +123,14 @@ class StreamHandler } } + // Do not drain when the request is a HEAD request because they have + // no body. if ($sink !== $stream) { - $this->drain($stream, $sink); + $this->drain( + $stream, + $sink, + $response->getHeaderLine('Content-Length') + ); } $this->invokeStats($options, $request, $startTime, $response, null); @@ -138,7 +149,7 @@ class StreamHandler : fopen('php://temp', 'r+'); return is_string($sink) - ? new Psr7\Stream(Psr7\try_fopen($sink, 'r+')) + ? new Psr7\LazyOpenStream($sink, 'w+') : Psr7\stream_for($sink); } @@ -149,16 +160,21 @@ class StreamHandler $normalizedKeys = \GuzzleHttp\normalize_header_keys($headers); if (isset($normalizedKeys['content-encoding'])) { $encoding = $headers[$normalizedKeys['content-encoding']]; - if ($encoding[0] == 'gzip' || $encoding[0] == 'deflate') { + if ($encoding[0] === 'gzip' || $encoding[0] === 'deflate') { $stream = new Psr7\InflateStream( Psr7\stream_for($stream) ); + $headers['x-encoded-content-encoding'] + = $headers[$normalizedKeys['content-encoding']]; // Remove content-encoding header unset($headers[$normalizedKeys['content-encoding']]); // Fix content-length header if (isset($normalizedKeys['content-length'])) { + $headers['x-encoded-content-length'] + = $headers[$normalizedKeys['content-length']]; + $length = (int) $stream->getSize(); - if ($length == 0) { + if ($length === 0) { unset($headers[$normalizedKeys['content-length']]); } else { $headers[$normalizedKeys['content-length']] = [$length]; @@ -176,13 +192,27 @@ class StreamHandler * * @param StreamInterface $source * @param StreamInterface $sink + * @param string $contentLength Header specifying the amount of + * data to read. * * @return StreamInterface * @throws \RuntimeException when the sink option is invalid. */ - private function drain(StreamInterface $source, StreamInterface $sink) - { - Psr7\copy_to_stream($source, $sink); + private function drain( + StreamInterface $source, + StreamInterface $sink, + $contentLength + ) { + // If a content-length header is provided, then stop reading once + // that number of bytes has been read. This can prevent infinitely + // reading from a stream when dealing with servers that do not honor + // Connection: Close headers. + Psr7\copy_to_stream( + $source, + $sink, + strlen($contentLength) > 0 ? (int) $contentLength : -1 + ); + $sink->seek(0); $source->close(); @@ -279,7 +309,7 @@ class StreamHandler return $this->createResource( function () use ($request, &$http_response_header, $context) { - $resource = fopen($request->getUri(), 'r', null, $context); + $resource = fopen((string) $request->getUri()->withFragment(''), 'r', null, $context); $this->lastHeaders = $http_response_header; return $resource; } @@ -341,7 +371,9 @@ class StreamHandler private function add_timeout(RequestInterface $request, &$options, $value, &$params) { - $options['http']['timeout'] = $value; + if ($value > 0) { + $options['http']['timeout'] = $value; + } } private function add_verify(RequestInterface $request, &$options, $value, &$params) @@ -359,12 +391,14 @@ class StreamHandler } } elseif ($value === false) { $options['ssl']['verify_peer'] = false; + $options['ssl']['verify_peer_name'] = false; return; } else { throw new \InvalidArgumentException('Invalid verify request option'); } $options['ssl']['verify_peer'] = true; + $options['ssl']['verify_peer_name'] = true; $options['ssl']['allow_self_signed'] = false; } @@ -416,7 +450,7 @@ class StreamHandler 'bytes_transferred', 'bytes_max']; $value = \GuzzleHttp\debug_resource($value); - $ident = $request->getMethod() . ' ' . $request->getUri(); + $ident = $request->getMethod() . ' ' . $request->getUri()->withFragment(''); $this->addNotification( $params, function () use ($ident, $value, $map, $args) { diff --git a/vendor/guzzlehttp/guzzle/src/HandlerStack.php b/vendor/guzzlehttp/guzzle/src/HandlerStack.php index f85184953..a72e38a53 100644 --- a/vendor/guzzlehttp/guzzle/src/HandlerStack.php +++ b/vendor/guzzlehttp/guzzle/src/HandlerStack.php @@ -62,11 +62,8 @@ class HandlerStack */ public function __invoke(RequestInterface $request, array $options) { - if (!$this->cached) { - $this->cached = $this->resolve(); - } + $handler = $this->resolve(); - $handler = $this->cached; return $handler($request, $options); } @@ -193,15 +190,19 @@ class HandlerStack */ public function resolve() { - if (!($prev = $this->handler)) { - throw new \LogicException('No handler has been specified'); + if (!$this->cached) { + if (!($prev = $this->handler)) { + throw new \LogicException('No handler has been specified'); + } + + foreach (array_reverse($this->stack) as $fn) { + $prev = $fn[0]($prev); + } + + $this->cached = $prev; } - foreach (array_reverse($this->stack) as $fn) { - $prev = $fn[0]($prev); - } - - return $prev; + return $this->cached; } /** diff --git a/vendor/guzzlehttp/guzzle/src/Middleware.php b/vendor/guzzlehttp/guzzle/src/Middleware.php index 2f165f39a..449ab4bf0 100644 --- a/vendor/guzzlehttp/guzzle/src/Middleware.php +++ b/vendor/guzzlehttp/guzzle/src/Middleware.php @@ -2,9 +2,7 @@ namespace GuzzleHttp; use GuzzleHttp\Cookie\CookieJarInterface; -use GuzzleHttp\Exception\ClientException; use GuzzleHttp\Exception\RequestException; -use GuzzleHttp\Exception\ServerException; use GuzzleHttp\Promise\RejectedPromise; use GuzzleHttp\Psr7; use Psr\Http\Message\ResponseInterface; @@ -64,9 +62,7 @@ final class Middleware if ($code < 400) { return $response; } - throw $code > 499 - ? new ServerException("Server error: $code", $request, $response) - : new ClientException("Client error: $code", $request, $response); + throw RequestException::create($request, $response); } ); }; @@ -79,9 +75,14 @@ final class Middleware * @param array $container Container to hold the history (by reference). * * @return callable Returns a function that accepts the next handler. + * @throws \InvalidArgumentException if container is not an array or ArrayAccess. */ - public static function history(array &$container) + public static function history(&$container) { + if (!is_array($container) && !$container instanceof \ArrayAccess) { + throw new \InvalidArgumentException('history container must be an array or object implementing ArrayAccess'); + } + return function (callable $handler) use (&$container) { return function ($request, array $options) use ($handler, &$container) { return $handler($request, $options)->then( diff --git a/vendor/guzzlehttp/guzzle/src/Pool.php b/vendor/guzzlehttp/guzzle/src/Pool.php index bc41d6e6b..8f1be33cd 100644 --- a/vendor/guzzlehttp/guzzle/src/Pool.php +++ b/vendor/guzzlehttp/guzzle/src/Pool.php @@ -52,11 +52,11 @@ class Pool implements PromisorInterface $iterable = \GuzzleHttp\Promise\iter_for($requests); $requests = function () use ($iterable, $client, $opts) { - foreach ($iterable as $rfn) { + foreach ($iterable as $key => $rfn) { if ($rfn instanceof RequestInterface) { - yield $client->sendAsync($rfn, $opts); + yield $key => $client->sendAsync($rfn, $opts); } elseif (is_callable($rfn)) { - yield $rfn($opts); + yield $key => $rfn($opts); } else { throw new \InvalidArgumentException('Each value yielded by ' . 'the iterator must be a Psr7\Http\Message\RequestInterface ' diff --git a/vendor/guzzlehttp/guzzle/src/UriTemplate.php b/vendor/guzzlehttp/guzzle/src/UriTemplate.php index 55dfeb5a4..0b1623eca 100644 --- a/vendor/guzzlehttp/guzzle/src/UriTemplate.php +++ b/vendor/guzzlehttp/guzzle/src/UriTemplate.php @@ -15,25 +15,25 @@ class UriTemplate private $variables; /** @var array Hash for quick operator lookups */ - private static $operatorHash = array( - '' => array('prefix' => '', 'joiner' => ',', 'query' => false), - '+' => array('prefix' => '', 'joiner' => ',', 'query' => false), - '#' => array('prefix' => '#', 'joiner' => ',', 'query' => false), - '.' => array('prefix' => '.', 'joiner' => '.', 'query' => false), - '/' => array('prefix' => '/', 'joiner' => '/', 'query' => false), - ';' => array('prefix' => ';', 'joiner' => ';', 'query' => true), - '?' => array('prefix' => '?', 'joiner' => '&', 'query' => true), - '&' => array('prefix' => '&', 'joiner' => '&', 'query' => true) - ); + private static $operatorHash = [ + '' => ['prefix' => '', 'joiner' => ',', 'query' => false], + '+' => ['prefix' => '', 'joiner' => ',', 'query' => false], + '#' => ['prefix' => '#', 'joiner' => ',', 'query' => false], + '.' => ['prefix' => '.', 'joiner' => '.', 'query' => false], + '/' => ['prefix' => '/', 'joiner' => '/', 'query' => false], + ';' => ['prefix' => ';', 'joiner' => ';', 'query' => true], + '?' => ['prefix' => '?', 'joiner' => '&', 'query' => true], + '&' => ['prefix' => '&', 'joiner' => '&', 'query' => true] + ]; /** @var array Delimiters */ - private static $delims = array(':', '/', '?', '#', '[', ']', '@', '!', '$', - '&', '\'', '(', ')', '*', '+', ',', ';', '='); + private static $delims = [':', '/', '?', '#', '[', ']', '@', '!', '$', + '&', '\'', '(', ')', '*', '+', ',', ';', '=']; /** @var array Percent encoded delimiters */ - private static $delimsPct = array('%3A', '%2F', '%3F', '%23', '%5B', '%5D', + private static $delimsPct = ['%3A', '%2F', '%3F', '%23', '%5B', '%5D', '%40', '%21', '%24', '%26', '%27', '%28', '%29', '%2A', '%2B', '%2C', - '%3B', '%3D'); + '%3B', '%3D']; public function expand($template, array $variables) { @@ -60,7 +60,7 @@ class UriTemplate */ private function parseExpression($expression) { - $result = array(); + $result = []; if (isset(self::$operatorHash[$expression[0]])) { $result['operator'] = $expression[0]; @@ -71,12 +71,12 @@ class UriTemplate foreach (explode(',', $expression) as $value) { $value = trim($value); - $varspec = array(); + $varspec = []; if ($colonPos = strpos($value, ':')) { $varspec['value'] = substr($value, 0, $colonPos); $varspec['modifier'] = ':'; $varspec['position'] = (int) substr($value, $colonPos + 1); - } elseif (substr($value, -1) == '*') { + } elseif (substr($value, -1) === '*') { $varspec['modifier'] = '*'; $varspec['value'] = substr($value, 0, -1); } else { @@ -98,9 +98,9 @@ class UriTemplate */ private function expandMatch(array $matches) { - static $rfc1738to3986 = array('+' => '%20', '%7e' => '~'); + static $rfc1738to3986 = ['+' => '%20', '%7e' => '~']; - $replacements = array(); + $replacements = []; $parsed = self::parseExpression($matches[1]); $prefix = self::$operatorHash[$parsed['operator']]['prefix']; $joiner = self::$operatorHash[$parsed['operator']]['joiner']; @@ -119,7 +119,7 @@ class UriTemplate if (is_array($variable)) { $isAssoc = $this->isAssoc($variable); - $kvp = array(); + $kvp = []; foreach ($variable as $key => $var) { if ($isAssoc) { @@ -131,14 +131,14 @@ class UriTemplate if (!$isNestedArray) { $var = rawurlencode($var); - if ($parsed['operator'] == '+' || - $parsed['operator'] == '#' + if ($parsed['operator'] === '+' || + $parsed['operator'] === '#' ) { $var = $this->decodeReserved($var); } } - if ($value['modifier'] == '*') { + if ($value['modifier'] === '*') { if ($isAssoc) { if ($isNestedArray) { // Nested arrays must allow for deeply nested @@ -160,7 +160,7 @@ class UriTemplate if (empty($variable)) { $actuallyUseQuery = false; - } elseif ($value['modifier'] == '*') { + } elseif ($value['modifier'] === '*') { $expanded = implode($joiner, $kvp); if ($isAssoc) { // Don't prepend the value name when using the explode @@ -181,17 +181,17 @@ class UriTemplate } } else { - if ($value['modifier'] == ':') { + if ($value['modifier'] === ':') { $variable = substr($variable, 0, $value['position']); } $expanded = rawurlencode($variable); - if ($parsed['operator'] == '+' || $parsed['operator'] == '#') { + if ($parsed['operator'] === '+' || $parsed['operator'] === '#') { $expanded = $this->decodeReserved($expanded); } } if ($actuallyUseQuery) { - if (!$expanded && $joiner != '&') { + if (!$expanded && $joiner !== '&') { $expanded = $value['value']; } else { $expanded = $value['value'] . '=' . $expanded; diff --git a/vendor/guzzlehttp/guzzle/src/functions.php b/vendor/guzzlehttp/guzzle/src/functions.php index d0a2ca86d..85cf9c641 100644 --- a/vendor/guzzlehttp/guzzle/src/functions.php +++ b/vendor/guzzlehttp/guzzle/src/functions.php @@ -5,7 +5,6 @@ use GuzzleHttp\Handler\CurlHandler; use GuzzleHttp\Handler\CurlMultiHandler; use GuzzleHttp\Handler\Proxy; use GuzzleHttp\Handler\StreamHandler; -use Psr\Http\Message\StreamInterface; /** * Expands a URI template @@ -104,8 +103,12 @@ function debug_resource($value = null) function choose_handler() { $handler = null; - if (extension_loaded('curl')) { + if (function_exists('curl_multi_exec') && function_exists('curl_exec')) { $handler = Proxy::wrapSync(new CurlMultiHandler(), new CurlHandler()); + } elseif (function_exists('curl_exec')) { + $handler = new CurlHandler(); + } elseif (function_exists('curl_multi_exec')) { + $handler = new CurlMultiHandler(); } if (ini_get('allow_url_fopen')) { @@ -278,3 +281,49 @@ function is_host_in_noproxy($host, array $noProxyArray) return false; } + +/** + * Wrapper for json_decode that throws when an error occurs. + * + * @param string $json JSON data to parse + * @param bool $assoc When true, returned objects will be converted + * into associative arrays. + * @param int $depth User specified recursion depth. + * @param int $options Bitmask of JSON decode options. + * + * @return mixed + * @throws \InvalidArgumentException if the JSON cannot be decoded. + * @link http://www.php.net/manual/en/function.json-decode.php + */ +function json_decode($json, $assoc = false, $depth = 512, $options = 0) +{ + $data = \json_decode($json, $assoc, $depth, $options); + if (JSON_ERROR_NONE !== json_last_error()) { + throw new \InvalidArgumentException( + 'json_decode error: ' . json_last_error_msg()); + } + + return $data; +} + +/** + * Wrapper for JSON encoding that throws when an error occurs. + * + * @param mixed $value The value being encoded + * @param int $options JSON encode option bitmask + * @param int $depth Set the maximum depth. Must be greater than zero. + * + * @return string + * @throws \InvalidArgumentException if the JSON cannot be encoded. + * @link http://www.php.net/manual/en/function.json-encode.php + */ +function json_encode($value, $options = 0, $depth = 512) +{ + $json = \json_encode($value, $options, $depth); + if (JSON_ERROR_NONE !== json_last_error()) { + throw new \InvalidArgumentException( + 'json_encode error: ' . json_last_error_msg()); + } + + return $json; +} diff --git a/vendor/guzzlehttp/promises/CHANGELOG.md b/vendor/guzzlehttp/promises/CHANGELOG.md index daad986cf..99603e5d0 100644 --- a/vendor/guzzlehttp/promises/CHANGELOG.md +++ b/vendor/guzzlehttp/promises/CHANGELOG.md @@ -1,5 +1,21 @@ # CHANGELOG +## 1.2.0 - 2016-05-18 + +* Update to now catch `\Throwable` on PHP 7+ + +## 1.1.0 - 2016-03-07 + +* Update EachPromise to prevent recurring on a iterator when advancing, as this + could trigger fatal generator errors. +* Update Promise to allow recursive waiting without unwrapping exceptions. + +## 1.0.3 - 2015-10-15 + +* Update EachPromise to immediately resolve when the underlying promise iterator + is empty. Previously, such a promise would throw an exception when its `wait` + function was called. + ## 1.0.2 - 2015-05-15 * Conditionally require functions.php. diff --git a/vendor/guzzlehttp/promises/README.md b/vendor/guzzlehttp/promises/README.md index c6780abd2..0dea84014 100644 --- a/vendor/guzzlehttp/promises/README.md +++ b/vendor/guzzlehttp/promises/README.md @@ -208,7 +208,7 @@ of the promise is called. ```php $promise = new Promise(function () use (&$promise) { - $promise->deliver('foo'); + $promise->resolve('foo'); }); // Calling wait will return the value of the promise. @@ -227,11 +227,11 @@ $promise->wait(); // throws the exception. ``` Calling `wait` on a promise that has been fulfilled will not trigger the wait -function. It will simply return the previously delivered value. +function. It will simply return the previously resolved value. ```php $promise = new Promise(function () { die('this is not called!'); }); -$promise->deliver('foo'); +$promise->resolve('foo'); echo $promise->wait(); // outputs "foo" ``` @@ -268,7 +268,7 @@ $promise->reject('foo'); $promise->wait(false); ``` -When unwrapping a promise, the delivered value of the promise will be waited +When unwrapping a promise, the resolved value of the promise will be waited upon until the unwrapped value is not a promise. This means that if you resolve promise A with a promise B and unwrap promise A, the value returned by the wait function will be the value delivered to promise B. @@ -496,6 +496,6 @@ deferred, it is a small price to pay for keeping the stack size constant. $promise = new Promise(); $promise->then(function ($value) { echo $value; }); // The promise is the deferred value, so you can deliver a value to it. -$promise->deliver('foo'); +$promise->resolve('foo'); // prints "foo" ``` diff --git a/vendor/guzzlehttp/promises/src/EachPromise.php b/vendor/guzzlehttp/promises/src/EachPromise.php index 855d83378..d0ddf603f 100644 --- a/vendor/guzzlehttp/promises/src/EachPromise.php +++ b/vendor/guzzlehttp/promises/src/EachPromise.php @@ -24,6 +24,9 @@ class EachPromise implements PromisorInterface /** @var Promise */ private $aggregate; + /** @var bool */ + private $mutex; + /** * Configuration hash can include the following key value pairs: * @@ -72,6 +75,8 @@ class EachPromise implements PromisorInterface $this->createPromise(); $this->iterable->rewind(); $this->refillPending(); + } catch (\Throwable $e) { + $this->aggregate->reject($e); } catch (\Exception $e) { $this->aggregate->reject($e); } @@ -81,8 +86,14 @@ class EachPromise implements PromisorInterface private function createPromise() { + $this->mutex = false; $this->aggregate = new Promise(function () { reset($this->pending); + if (empty($this->pending) && !$this->iterable->valid()) { + $this->aggregate->resolve(null); + return; + } + // Consume a potentially fluctuating list of promises while // ensuring that indexes are maintained (precluding array_shift). while ($promise = current($this->pending)) { @@ -164,11 +175,25 @@ class EachPromise implements PromisorInterface private function advanceIterator() { + // Place a lock on the iterator so that we ensure to not recurse, + // preventing fatal generator errors. + if ($this->mutex) { + return false; + } + + $this->mutex = true; + try { $this->iterable->next(); + $this->mutex = false; return true; + } catch (\Throwable $e) { + $this->aggregate->reject($e); + $this->mutex = false; + return false; } catch (\Exception $e) { $this->aggregate->reject($e); + $this->mutex = false; return false; } } @@ -181,9 +206,11 @@ class EachPromise implements PromisorInterface } unset($this->pending[$idx]); - $this->advanceIterator(); - if (!$this->checkIfFinished()) { + // Only refill pending promises if we are not locked, preventing the + // EachPromise to recursively invoke the provided iterator, which + // cause a fatal error: "Cannot resume an already running generator" + if ($this->advanceIterator() && !$this->checkIfFinished()) { // Add more pending promises if possible. $this->refillPending(); } diff --git a/vendor/guzzlehttp/promises/src/FulfilledPromise.php b/vendor/guzzlehttp/promises/src/FulfilledPromise.php index 559629653..dbbeeb9f7 100644 --- a/vendor/guzzlehttp/promises/src/FulfilledPromise.php +++ b/vendor/guzzlehttp/promises/src/FulfilledPromise.php @@ -37,6 +37,8 @@ class FulfilledPromise implements PromiseInterface if ($p->getState() === self::PENDING) { try { $p->resolve($onFulfilled($value)); + } catch (\Throwable $e) { + $p->reject($e); } catch (\Exception $e) { $p->reject($e); } diff --git a/vendor/guzzlehttp/promises/src/Promise.php b/vendor/guzzlehttp/promises/src/Promise.php index c2cf969da..04f3ea043 100644 --- a/vendor/guzzlehttp/promises/src/Promise.php +++ b/vendor/guzzlehttp/promises/src/Promise.php @@ -61,17 +61,19 @@ class Promise implements PromiseInterface { $this->waitIfPending(); - if (!$unwrap) { - return null; - } + $inner = $this->result instanceof PromiseInterface + ? $this->result->wait($unwrap) + : $this->result; - if ($this->result instanceof PromiseInterface) { - return $this->result->wait($unwrap); - } elseif ($this->state === self::FULFILLED) { - return $this->result; - } else { - // It's rejected so "unwrap" and throw an exception. - throw exception_for($this->result); + if ($unwrap) { + if ($this->result instanceof PromiseInterface + || $this->state === self::FULFILLED + ) { + return $inner; + } else { + // It's rejected so "unwrap" and throw an exception. + throw exception_for($inner); + } } } @@ -93,6 +95,8 @@ class Promise implements PromiseInterface $this->cancelFn = null; try { $fn(); + } catch (\Throwable $e) { + $this->reject($e); } catch (\Exception $e) { $this->reject($e); } @@ -204,6 +208,8 @@ class Promise implements PromiseInterface // Forward rejections down the chain. $promise->reject($value); } + } catch (\Throwable $reason) { + $promise->reject($reason); } catch (\Exception $reason) { $promise->reject($reason); } @@ -257,11 +263,10 @@ class Promise implements PromiseInterface $this->waitList = null; foreach ($waitList as $result) { - descend: $result->waitIfPending(); - if ($result->result instanceof Promise) { + while ($result->result instanceof Promise) { $result = $result->result; - goto descend; + $result->waitIfPending(); } } } diff --git a/vendor/guzzlehttp/promises/src/RejectedPromise.php b/vendor/guzzlehttp/promises/src/RejectedPromise.php index bd499e691..2bc6508e7 100644 --- a/vendor/guzzlehttp/promises/src/RejectedPromise.php +++ b/vendor/guzzlehttp/promises/src/RejectedPromise.php @@ -38,6 +38,9 @@ class RejectedPromise implements PromiseInterface try { // Return a resolved promise if onRejected does not throw. $p->resolve($onRejected($reason)); + } catch (\Throwable $e) { + // onRejected threw, so return a rejected promise. + $p->reject($e); } catch (\Exception $e) { // onRejected threw, so return a rejected promise. $p->reject($e); diff --git a/vendor/guzzlehttp/promises/src/TaskQueue.php b/vendor/guzzlehttp/promises/src/TaskQueue.php index 502636313..39fe5bbb6 100644 --- a/vendor/guzzlehttp/promises/src/TaskQueue.php +++ b/vendor/guzzlehttp/promises/src/TaskQueue.php @@ -56,6 +56,7 @@ class TaskQueue */ public function run() { + /** @var callable $task */ while ($task = array_shift($this->queue)) { $task(); } diff --git a/vendor/guzzlehttp/promises/src/functions.php b/vendor/guzzlehttp/promises/src/functions.php index 89c656911..8f9008f15 100644 --- a/vendor/guzzlehttp/promises/src/functions.php +++ b/vendor/guzzlehttp/promises/src/functions.php @@ -42,6 +42,8 @@ function task(callable $task) $queue->add(function () use ($task, $promise) { try { $promise->resolve($task()); + } catch (\Throwable $e) { + $promise->reject($e); } catch (\Exception $e) { $promise->reject($e); } @@ -97,11 +99,11 @@ function rejection_for($reason) * * @param mixed $reason * - * @return \Exception + * @return \Exception|\Throwable */ function exception_for($reason) { - return $reason instanceof \Exception + return $reason instanceof \Exception || $reason instanceof \Throwable ? $reason : new RejectionException($reason); } @@ -146,9 +148,11 @@ function inspect(PromiseInterface $promise) 'value' => $promise->wait() ]; } catch (RejectionException $e) { - return ['state' => 'rejected', 'reason' => $e->getReason()]; + return ['state' => PromiseInterface::REJECTED, 'reason' => $e->getReason()]; + } catch (\Throwable $e) { + return ['state' => PromiseInterface::REJECTED, 'reason' => $e]; } catch (\Exception $e) { - return ['state' => 'rejected', 'reason' => $e]; + return ['state' => PromiseInterface::REJECTED, 'reason' => $e]; } } @@ -184,6 +188,7 @@ function inspect_all($promises) * * @return array * @throws \Exception on error + * @throws \Throwable on error in PHP >=7 */ function unwrap($promises) { @@ -304,10 +309,10 @@ function settle($promises) return each( $promises, function ($value, $idx) use (&$results) { - $results[$idx] = ['state' => 'fulfilled', 'value' => $value]; + $results[$idx] = ['state' => PromiseInterface::FULFILLED, 'value' => $value]; }, function ($reason, $idx) use (&$results) { - $results[$idx] = ['state' => 'rejected', 'reason' => $reason]; + $results[$idx] = ['state' => PromiseInterface::REJECTED, 'reason' => $reason]; } )->then(function () use (&$results) { ksort($results); diff --git a/vendor/guzzlehttp/psr7/CHANGELOG.md b/vendor/guzzlehttp/psr7/CHANGELOG.md index 642dc9a4b..0771a9aca 100644 --- a/vendor/guzzlehttp/psr7/CHANGELOG.md +++ b/vendor/guzzlehttp/psr7/CHANGELOG.md @@ -1,5 +1,47 @@ # CHANGELOG +## 1.3.1 - 2016-06-25 + +* Fix `Uri::__toString` for network path references, e.g. `//example.org`. +* Fix missing lowercase normalization for host. +* Fix handling of URI components in case they are `'0'` in a lot of places, + e.g. as a user info password. +* Fix `Uri::withAddedHeader` to correctly merge headers with different case. +* Fix trimming of header values in `Uri::withAddedHeader`. Header values may + be surrounded by whitespace which should be ignored according to RFC 7230 + Section 3.2.4. This does not apply to header names. +* Fix `Uri::withAddedHeader` with an array of header values. +* Fix `Uri::resolve` when base path has no slash and handling of fragment. +* Fix handling of encoding in `Uri::with(out)QueryValue` so one can pass the + key/value both in encoded as well as decoded form to those methods. This is + consistent with withPath, withQuery etc. +* Fix `ServerRequest::withoutAttribute` when attribute value is null. + +## 1.3.0 - 2016-04-13 + +* Added remaining interfaces needed for full PSR7 compatibility + (ServerRequestInterface, UploadedFileInterface, etc.). +* Added support for stream_for from scalars. +* Can now extend Uri. +* Fixed a bug in validating request methods by making it more permissive. + +## 1.2.3 - 2016-02-18 + +* Fixed support in `GuzzleHttp\Psr7\CachingStream` for seeking forward on remote + streams, which can sometimes return fewer bytes than requested with `fread`. +* Fixed handling of gzipped responses with FNAME headers. + +## 1.2.2 - 2016-01-22 + +* Added support for URIs without any authority. +* Added support for HTTP 451 'Unavailable For Legal Reasons.' +* Added support for using '0' as a filename. +* Added support for including non-standard ports in Host headers. + +## 1.2.1 - 2015-11-02 + +* Now supporting negative offsets when seeking to SEEK_END. + ## 1.2.0 - 2015-08-15 * Body as `"0"` is now properly added to a response. diff --git a/vendor/guzzlehttp/psr7/Makefile b/vendor/guzzlehttp/psr7/Makefile index 9c210960e..8b00b43e6 100644 --- a/vendor/guzzlehttp/psr7/Makefile +++ b/vendor/guzzlehttp/psr7/Makefile @@ -9,5 +9,21 @@ coverage: view-coverage: open artifacts/coverage/index.html +check-tag: + $(if $(TAG),,$(error TAG is not defined. Pass via "make tag TAG=4.2.1")) + +tag: check-tag + @echo Tagging $(TAG) + chag update $(TAG) + git commit -a -m '$(TAG) release' + chag tag + @echo "Release has been created. Push using 'make release'" + @echo "Changes made in the release commit" + git diff HEAD~1 HEAD + +release: check-tag + git push origin master + git push origin $(TAG) + clean: rm -rf artifacts/* diff --git a/vendor/guzzlehttp/psr7/README.md b/vendor/guzzlehttp/psr7/README.md index 0b30d5ab0..2642164ff 100644 --- a/vendor/guzzlehttp/psr7/README.md +++ b/vendor/guzzlehttp/psr7/README.md @@ -1,9 +1,11 @@ # PSR-7 Message Implementation -This repository contains a partial [PSR-7](http://www.php-fig.org/psr/psr-7/) +This repository contains a full [PSR-7](http://www.php-fig.org/psr/psr-7/) message implementation, several stream decorators, and some helpful -functionality like query string parsing. Currently missing -ServerRequestInterface and UploadedFileInterface; a pull request for these features is welcome. +functionality like query string parsing. + + +[![Build Status](https://travis-ci.org/guzzle/psr7.svg?branch=master)](https://travis-ci.org/guzzle/psr7) # Stream implementation @@ -25,9 +27,9 @@ $a = Psr7\stream_for('abc, '); $b = Psr7\stream_for('123.'); $composed = new Psr7\AppendStream([$a, $b]); -$composed->addStream(Psr7\stream_for(' Above all listen to me'). +$composed->addStream(Psr7\stream_for(' Above all listen to me')); -echo $composed(); // abc, 123. Above all listen to me. +echo $composed; // abc, 123. Above all listen to me. ``` @@ -35,7 +37,7 @@ echo $composed(); // abc, 123. Above all listen to me. `GuzzleHttp\Psr7\BufferStream` -Provides a buffer stream that can be written to to fill a buffer, and read +Provides a buffer stream that can be written to fill a buffer, and read from to remove bytes from the buffer. This stream returns a "hwm" metadata value that tells upstream consumers @@ -92,7 +94,7 @@ $stream = Psr7\stream_for(); // Start dropping data when the stream has more than 10 bytes $dropping = new Psr7\DroppingStream($stream, 10); -$stream->write('01234567890123456789'); +$dropping->write('01234567890123456789'); echo $stream; // 0123456789 ``` @@ -103,7 +105,7 @@ echo $stream; // 0123456789 Compose stream implementations based on a hash of functions. -Allows for easy testing and extension of a provided stream without needing to +Allows for easy testing and extension of a provided stream without needing to create a concrete class for a simple extension point. ```php @@ -498,7 +500,7 @@ an associative array (e.g., `foo[a]=1&foo[b]=2` will be parsed into Build a query string from an array of key value pairs. -This function can use the return value of parseQuery() to build a query string. +This function can use the return value of parse_query() to build a query string. This function does not modify the provided keys when an array is encountered (like http_build_query would). @@ -524,7 +526,7 @@ The `GuzzleHttp\Psr7\Uri` class has several static methods to manipulate URIs. ## `GuzzleHttp\Psr7\Uri::removeDotSegments` -`public static function removeDotSegments($path) -> UriInterface` +`public static function removeDotSegments(string $path): string` Removes dot segments from a path and returns the new path. @@ -533,7 +535,7 @@ See http://tools.ietf.org/html/rfc3986#section-5.2.4 ## `GuzzleHttp\Psr7\Uri::resolve` -`public static function resolve(UriInterface $base, $rel) -> UriInterface` +`public static function resolve(UriInterface $base, $rel): UriInterface` Resolve a base URI with a relative URI and return a new URI. @@ -542,39 +544,26 @@ See http://tools.ietf.org/html/rfc3986#section-5 ## `GuzzleHttp\Psr7\Uri::withQueryValue` -`public static function withQueryValue(UriInterface $uri, $key, $value) -> UriInterface` +`public static function withQueryValue(UriInterface $uri, $key, $value): UriInterface` Create a new URI with a specific query string value. Any existing query string values that exactly match the provided key are removed and replaced with the given key value pair. -Note: this function will convert "=" to "%3D" and "&" to "%26". - ## `GuzzleHttp\Psr7\Uri::withoutQueryValue` -`public static function withoutQueryValue(UriInterface $uri, $key, $value) -> UriInterface` +`public static function withoutQueryValue(UriInterface $uri, $key): UriInterface` Create a new URI with a specific query string value removed. Any existing query string values that exactly match the provided key are removed. -Note: this function will convert "=" to "%3D" and "&" to "%26". - ## `GuzzleHttp\Psr7\Uri::fromParts` -`public static function fromParts(array $parts) -> UriInterface` +`public static function fromParts(array $parts): UriInterface` Create a `GuzzleHttp\Psr7\Uri` object from a hash of `parse_url` parts. - - -# Not Implemented - -A few aspects of PSR-7 are not implemented in this project. A pull request for -any of these features is welcome: - -- `Psr\Http\Message\ServerRequestInterface` -- `Psr\Http\Message\UploadedFileInterface` diff --git a/vendor/guzzlehttp/psr7/composer.json b/vendor/guzzlehttp/psr7/composer.json index f2e9d4c5f..fdfb97bdd 100644 --- a/vendor/guzzlehttp/psr7/composer.json +++ b/vendor/guzzlehttp/psr7/composer.json @@ -29,7 +29,7 @@ }, "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "1.4-dev" } } } diff --git a/vendor/guzzlehttp/psr7/src/CachingStream.php b/vendor/guzzlehttp/psr7/src/CachingStream.php index 796d581b8..ed68f0861 100644 --- a/vendor/guzzlehttp/psr7/src/CachingStream.php +++ b/vendor/guzzlehttp/psr7/src/CachingStream.php @@ -52,8 +52,7 @@ class CachingStream implements StreamInterface if ($size === null) { $size = $this->cacheEntireStream(); } - // Because 0 is the first byte, we seek to size - 1. - $byte = $size - 1 - $offset; + $byte = $size + $offset; } else { throw new \InvalidArgumentException('Invalid whence'); } @@ -61,9 +60,12 @@ class CachingStream implements StreamInterface $diff = $byte - $this->stream->getSize(); if ($diff > 0) { - // If the seek byte is greater the number of read bytes, then read - // the difference of bytes to cache the bytes and inherently seek. - $this->read($diff); + // Read the remoteStream until we have read in at least the amount + // of bytes requested, or we reach the end of the file. + while ($diff > 0 && !$this->remoteStream->eof()) { + $this->read($diff); + $diff = $byte - $this->stream->getSize(); + } } else { // We can just do a normal seek since we've already seen this byte. $this->stream->seek($byte); diff --git a/vendor/guzzlehttp/psr7/src/InflateStream.php b/vendor/guzzlehttp/psr7/src/InflateStream.php index 2c8628b07..0051d3fec 100644 --- a/vendor/guzzlehttp/psr7/src/InflateStream.php +++ b/vendor/guzzlehttp/psr7/src/InflateStream.php @@ -20,10 +20,33 @@ class InflateStream implements StreamInterface public function __construct(StreamInterface $stream) { - // Skip the first 10 bytes - $stream = new LimitStream($stream, -1, 10); + // read the first 10 bytes, ie. gzip header + $header = $stream->read(10); + $filenameHeaderLength = $this->getLengthOfPossibleFilenameHeader($stream, $header); + // Skip the header, that is 10 + length of filename + 1 (nil) bytes + $stream = new LimitStream($stream, -1, 10 + $filenameHeaderLength); $resource = StreamWrapper::getResource($stream); stream_filter_append($resource, 'zlib.inflate', STREAM_FILTER_READ); $this->stream = new Stream($resource); } + + /** + * @param StreamInterface $stream + * @param $header + * @return int + */ + private function getLengthOfPossibleFilenameHeader(StreamInterface $stream, $header) + { + $filename_header_length = 0; + + if (substr(bin2hex($header), 6, 2) === '08') { + // we have a filename, read until nil + $filename_header_length = 1; + while ($stream->read(1) !== chr(0)) { + $filename_header_length++; + } + } + + return $filename_header_length; + } } diff --git a/vendor/guzzlehttp/psr7/src/MessageTrait.php b/vendor/guzzlehttp/psr7/src/MessageTrait.php index 123205cf6..1e4da649a 100644 --- a/vendor/guzzlehttp/psr7/src/MessageTrait.php +++ b/vendor/guzzlehttp/psr7/src/MessageTrait.php @@ -8,11 +8,11 @@ use Psr\Http\Message\StreamInterface; */ trait MessageTrait { - /** @var array Cached HTTP header collection with lowercase key to values */ + /** @var array Map of all registered headers, as original name => array of values */ private $headers = []; - /** @var array Actual key to list of values per header. */ - private $headerLines = []; + /** @var array Map of lowercase header name => original name at registration */ + private $headerNames = []; /** @var string */ private $protocol = '1.1'; @@ -38,18 +38,25 @@ trait MessageTrait public function getHeaders() { - return $this->headerLines; + return $this->headers; } public function hasHeader($header) { - return isset($this->headers[strtolower($header)]); + return isset($this->headerNames[strtolower($header)]); } public function getHeader($header) { - $name = strtolower($header); - return isset($this->headers[$name]) ? $this->headers[$name] : []; + $header = strtolower($header); + + if (!isset($this->headerNames[$header])) { + return []; + } + + $header = $this->headerNames[$header]; + + return $this->headers[$header]; } public function getHeaderLine($header) @@ -59,59 +66,56 @@ trait MessageTrait public function withHeader($header, $value) { - $new = clone $this; - $header = trim($header); - $name = strtolower($header); - if (!is_array($value)) { - $new->headers[$name] = [trim($value)]; - } else { - $new->headers[$name] = $value; - foreach ($new->headers[$name] as &$v) { - $v = trim($v); - } + $value = [$value]; } - // Remove the header lines. - foreach (array_keys($new->headerLines) as $key) { - if (strtolower($key) === $name) { - unset($new->headerLines[$key]); - } - } + $value = $this->trimHeaderValues($value); + $normalized = strtolower($header); - // Add the header line. - $new->headerLines[$header] = $new->headers[$name]; + $new = clone $this; + if (isset($new->headerNames[$normalized])) { + unset($new->headers[$new->headerNames[$normalized]]); + } + $new->headerNames[$normalized] = $header; + $new->headers[$header] = $value; return $new; } public function withAddedHeader($header, $value) { - if (!$this->hasHeader($header)) { - return $this->withHeader($header, $value); + if (!is_array($value)) { + $value = [$value]; } + $value = $this->trimHeaderValues($value); + $normalized = strtolower($header); + $new = clone $this; - $new->headers[strtolower($header)][] = $value; - $new->headerLines[$header][] = $value; + if (isset($new->headerNames[$normalized])) { + $header = $this->headerNames[$normalized]; + $new->headers[$header] = array_merge($this->headers[$header], $value); + } else { + $new->headerNames[$normalized] = $header; + $new->headers[$header] = $value; + } + return $new; } public function withoutHeader($header) { - if (!$this->hasHeader($header)) { + $normalized = strtolower($header); + + if (!isset($this->headerNames[$normalized])) { return $this; } - $new = clone $this; - $name = strtolower($header); - unset($new->headers[$name]); + $header = $this->headerNames[$normalized]; - foreach (array_keys($new->headerLines) as $key) { - if (strtolower($key) === $name) { - unset($new->headerLines[$key]); - } - } + $new = clone $this; + unset($new->headers[$header], $new->headerNames[$normalized]); return $new; } @@ -138,21 +142,42 @@ trait MessageTrait private function setHeaders(array $headers) { - $this->headerLines = $this->headers = []; + $this->headerNames = $this->headers = []; foreach ($headers as $header => $value) { - $header = trim($header); - $name = strtolower($header); if (!is_array($value)) { - $value = trim($value); - $this->headers[$name][] = $value; - $this->headerLines[$header][] = $value; + $value = [$value]; + } + + $value = $this->trimHeaderValues($value); + $normalized = strtolower($header); + if (isset($this->headerNames[$normalized])) { + $header = $this->headerNames[$normalized]; + $this->headers[$header] = array_merge($this->headers[$header], $value); } else { - foreach ($value as $v) { - $v = trim($v); - $this->headers[$name][] = $v; - $this->headerLines[$header][] = $v; - } + $this->headerNames[$normalized] = $header; + $this->headers[$header] = $value; } } } + + /** + * Trims whitespace from the header values. + * + * Spaces and tabs ought to be excluded by parsers when extracting the field value from a header field. + * + * header-field = field-name ":" OWS field-value OWS + * OWS = *( SP / HTAB ) + * + * @param string[] $values Header values + * + * @return string[] Trimmed header values + * + * @see https://tools.ietf.org/html/rfc7230#section-3.2.4 + */ + private function trimHeaderValues(array $values) + { + return array_map(function ($value) { + return trim($value, " \t"); + }, $values); + } } diff --git a/vendor/guzzlehttp/psr7/src/MultipartStream.php b/vendor/guzzlehttp/psr7/src/MultipartStream.php index fd006ecf8..2988fcba0 100644 --- a/vendor/guzzlehttp/psr7/src/MultipartStream.php +++ b/vendor/guzzlehttp/psr7/src/MultipartStream.php @@ -113,7 +113,7 @@ class MultipartStream implements StreamInterface // Set a default content-disposition header if one was no provided $disposition = $this->getHeader($headers, 'content-disposition'); if (!$disposition) { - $headers['Content-Disposition'] = $filename + $headers['Content-Disposition'] = ($filename === '0' || $filename) ? sprintf('form-data; name="%s"; filename="%s"', $name, basename($filename)) @@ -130,7 +130,7 @@ class MultipartStream implements StreamInterface // Set a default Content-Type if one was not supplied $type = $this->getHeader($headers, 'content-type'); - if (!$type && $filename) { + if (!$type && ($filename === '0' || $filename)) { if ($type = mimetype_from_filename($filename)) { $headers['Content-Type'] = $type; } diff --git a/vendor/guzzlehttp/psr7/src/Request.php b/vendor/guzzlehttp/psr7/src/Request.php index 0189b14ce..4a3db6ece 100644 --- a/vendor/guzzlehttp/psr7/src/Request.php +++ b/vendor/guzzlehttp/psr7/src/Request.php @@ -11,9 +11,7 @@ use Psr\Http\Message\UriInterface; */ class Request implements RequestInterface { - use MessageTrait { - withHeader as protected withParentHeader; - } + use MessageTrait; /** @var string */ private $method; @@ -25,40 +23,33 @@ class Request implements RequestInterface private $uri; /** - * @param null|string $method HTTP method for the request. - * @param null|string $uri URI for the request. - * @param array $headers Headers for the message. - * @param string|resource|StreamInterface $body Message body. - * @param string $protocolVersion HTTP protocol version. - * - * @throws InvalidArgumentException for an invalid URI + * @param string $method HTTP method + * @param string|UriInterface $uri URI + * @param array $headers Request headers + * @param string|null|resource|StreamInterface $body Request body + * @param string $version Protocol version */ public function __construct( $method, $uri, array $headers = [], $body = null, - $protocolVersion = '1.1' + $version = '1.1' ) { - if (is_string($uri)) { + if (!($uri instanceof UriInterface)) { $uri = new Uri($uri); - } elseif (!($uri instanceof UriInterface)) { - throw new \InvalidArgumentException( - 'URI must be a string or Psr\Http\Message\UriInterface' - ); } $this->method = strtoupper($method); $this->uri = $uri; $this->setHeaders($headers); - $this->protocol = $protocolVersion; + $this->protocol = $version; - $host = $uri->getHost(); - if ($host && !$this->hasHeader('Host')) { - $this->updateHostFromUri($host); + if (!$this->hasHeader('Host')) { + $this->updateHostFromUri(); } - if ($body) { + if ($body !== '' && $body !== null) { $this->stream = stream_for($body); } } @@ -70,10 +61,10 @@ class Request implements RequestInterface } $target = $this->uri->getPath(); - if ($target == null) { + if ($target == '') { $target = '/'; } - if ($this->uri->getQuery()) { + if ($this->uri->getQuery() != '') { $target .= '?' . $this->uri->getQuery(); } @@ -120,30 +111,32 @@ class Request implements RequestInterface $new->uri = $uri; if (!$preserveHost) { - if ($host = $uri->getHost()) { - $new->updateHostFromUri($host); - } + $new->updateHostFromUri(); } return $new; } - public function withHeader($header, $value) + private function updateHostFromUri() { - /** @var Request $newInstance */ - $newInstance = $this->withParentHeader($header, $value); - return $newInstance; - } + $host = $this->uri->getHost(); - private function updateHostFromUri($host) - { - // Ensure Host is the first header. - // See: http://tools.ietf.org/html/rfc7230#section-5.4 - if ($port = $this->uri->getPort()) { + if ($host == '') { + return; + } + + if (($port = $this->uri->getPort()) !== null) { $host .= ':' . $port; } - $this->headerLines = ['Host' => [$host]] + $this->headerLines; - $this->headers = ['host' => [$host]] + $this->headers; + if (isset($this->headerNames['host'])) { + $header = $this->headerNames['host']; + } else { + $header = 'Host'; + $this->headerNames['host'] = 'Host'; + } + // Ensure Host is the first header. + // See: http://tools.ietf.org/html/rfc7230#section-5.4 + $this->headers = [$header => [$host]] + $this->headers; } } diff --git a/vendor/guzzlehttp/psr7/src/Response.php b/vendor/guzzlehttp/psr7/src/Response.php index c94bf8f7f..841ff0200 100644 --- a/vendor/guzzlehttp/psr7/src/Response.php +++ b/vendor/guzzlehttp/psr7/src/Response.php @@ -59,6 +59,7 @@ class Response implements ResponseInterface 428 => 'Precondition Required', 429 => 'Too Many Requests', 431 => 'Request Header Fields Too Large', + 451 => 'Unavailable For Legal Reasons', 500 => 'Internal Server Error', 501 => 'Not Implemented', 502 => 'Bad Gateway', @@ -71,18 +72,18 @@ class Response implements ResponseInterface 511 => 'Network Authentication Required', ]; - /** @var null|string */ + /** @var string */ private $reasonPhrase = ''; /** @var int */ private $statusCode = 200; /** - * @param int $status Status code for the response, if any. - * @param array $headers Headers for the response, if any. - * @param mixed $body Stream body. - * @param string $version Protocol version. - * @param string $reason Reason phrase (a default will be used if possible). + * @param int $status Status code + * @param array $headers Response headers + * @param string|null|resource|StreamInterface $body Response body + * @param string $version Protocol version + * @param string|null $reason Reason phrase (when empty a default will be used based on the status code) */ public function __construct( $status = 200, @@ -93,12 +94,12 @@ class Response implements ResponseInterface ) { $this->statusCode = (int) $status; - if ($body !== null) { + if ($body !== '' && $body !== null) { $this->stream = stream_for($body); } $this->setHeaders($headers); - if (!$reason && isset(self::$phrases[$this->statusCode])) { + if ($reason == '' && isset(self::$phrases[$this->statusCode])) { $this->reasonPhrase = self::$phrases[$status]; } else { $this->reasonPhrase = (string) $reason; @@ -121,7 +122,7 @@ class Response implements ResponseInterface { $new = clone $this; $new->statusCode = (int) $code; - if (!$reasonPhrase && isset(self::$phrases[$new->statusCode])) { + if ($reasonPhrase == '' && isset(self::$phrases[$new->statusCode])) { $reasonPhrase = self::$phrases[$new->statusCode]; } $new->reasonPhrase = $reasonPhrase; diff --git a/vendor/guzzlehttp/psr7/src/ServerRequest.php b/vendor/guzzlehttp/psr7/src/ServerRequest.php new file mode 100644 index 000000000..a6a47bec4 --- /dev/null +++ b/vendor/guzzlehttp/psr7/src/ServerRequest.php @@ -0,0 +1,346 @@ +serverParams = $serverParams; + + parent::__construct($method, $uri, $headers, $body, $version); + } + + /** + * Return an UploadedFile instance array. + * + * @param array $files A array which respect $_FILES structure + * @throws InvalidArgumentException for unrecognized values + * @return array + */ + public static function normalizeFiles(array $files) + { + $normalized = []; + + foreach ($files as $key => $value) { + if ($value instanceof UploadedFileInterface) { + $normalized[$key] = $value; + } elseif (is_array($value) && isset($value['tmp_name'])) { + $normalized[$key] = self::createUploadedFileFromSpec($value); + } elseif (is_array($value)) { + $normalized[$key] = self::normalizeFiles($value); + continue; + } else { + throw new InvalidArgumentException('Invalid value in files specification'); + } + } + + return $normalized; + } + + /** + * Create and return an UploadedFile instance from a $_FILES specification. + * + * If the specification represents an array of values, this method will + * delegate to normalizeNestedFileSpec() and return that return value. + * + * @param array $value $_FILES struct + * @return array|UploadedFileInterface + */ + private static function createUploadedFileFromSpec(array $value) + { + if (is_array($value['tmp_name'])) { + return self::normalizeNestedFileSpec($value); + } + + return new UploadedFile( + $value['tmp_name'], + (int) $value['size'], + (int) $value['error'], + $value['name'], + $value['type'] + ); + } + + /** + * Normalize an array of file specifications. + * + * Loops through all nested files and returns a normalized array of + * UploadedFileInterface instances. + * + * @param array $files + * @return UploadedFileInterface[] + */ + private static function normalizeNestedFileSpec(array $files = []) + { + $normalizedFiles = []; + + foreach (array_keys($files['tmp_name']) as $key) { + $spec = [ + 'tmp_name' => $files['tmp_name'][$key], + 'size' => $files['size'][$key], + 'error' => $files['error'][$key], + 'name' => $files['name'][$key], + 'type' => $files['type'][$key], + ]; + $normalizedFiles[$key] = self::createUploadedFileFromSpec($spec); + } + + return $normalizedFiles; + } + + /** + * Return a ServerRequest populated with superglobals: + * $_GET + * $_POST + * $_COOKIE + * $_FILES + * $_SERVER + * + * @return ServerRequestInterface + */ + public static function fromGlobals() + { + $method = isset($_SERVER['REQUEST_METHOD']) ? $_SERVER['REQUEST_METHOD'] : 'GET'; + $headers = function_exists('getallheaders') ? getallheaders() : []; + $uri = self::getUriFromGlobals(); + $body = new LazyOpenStream('php://input', 'r+'); + $protocol = isset($_SERVER['SERVER_PROTOCOL']) ? str_replace('HTTP/', '', $_SERVER['SERVER_PROTOCOL']) : '1.1'; + + $serverRequest = new ServerRequest($method, $uri, $headers, $body, $protocol, $_SERVER); + + return $serverRequest + ->withCookieParams($_COOKIE) + ->withQueryParams($_GET) + ->withParsedBody($_POST) + ->withUploadedFiles(self::normalizeFiles($_FILES)); + } + + /** + * Get a Uri populated with values from $_SERVER. + * + * @return UriInterface + */ + public static function getUriFromGlobals() { + $uri = new Uri(''); + + if (isset($_SERVER['HTTPS'])) { + $uri = $uri->withScheme($_SERVER['HTTPS'] == 'on' ? 'https' : 'http'); + } + + if (isset($_SERVER['HTTP_HOST'])) { + $uri = $uri->withHost($_SERVER['HTTP_HOST']); + } elseif (isset($_SERVER['SERVER_NAME'])) { + $uri = $uri->withHost($_SERVER['SERVER_NAME']); + } + + if (isset($_SERVER['SERVER_PORT'])) { + $uri = $uri->withPort($_SERVER['SERVER_PORT']); + } + + if (isset($_SERVER['REQUEST_URI'])) { + $uri = $uri->withPath(current(explode('?', $_SERVER['REQUEST_URI']))); + } + + if (isset($_SERVER['QUERY_STRING'])) { + $uri = $uri->withQuery($_SERVER['QUERY_STRING']); + } + + return $uri; + } + + + /** + * {@inheritdoc} + */ + public function getServerParams() + { + return $this->serverParams; + } + + /** + * {@inheritdoc} + */ + public function getUploadedFiles() + { + return $this->uploadedFiles; + } + + /** + * {@inheritdoc} + */ + public function withUploadedFiles(array $uploadedFiles) + { + $new = clone $this; + $new->uploadedFiles = $uploadedFiles; + + return $new; + } + + /** + * {@inheritdoc} + */ + public function getCookieParams() + { + return $this->cookieParams; + } + + /** + * {@inheritdoc} + */ + public function withCookieParams(array $cookies) + { + $new = clone $this; + $new->cookieParams = $cookies; + + return $new; + } + + /** + * {@inheritdoc} + */ + public function getQueryParams() + { + return $this->queryParams; + } + + /** + * {@inheritdoc} + */ + public function withQueryParams(array $query) + { + $new = clone $this; + $new->queryParams = $query; + + return $new; + } + + /** + * {@inheritdoc} + */ + public function getParsedBody() + { + return $this->parsedBody; + } + + /** + * {@inheritdoc} + */ + public function withParsedBody($data) + { + $new = clone $this; + $new->parsedBody = $data; + + return $new; + } + + /** + * {@inheritdoc} + */ + public function getAttributes() + { + return $this->attributes; + } + + /** + * {@inheritdoc} + */ + public function getAttribute($attribute, $default = null) + { + if (false === array_key_exists($attribute, $this->attributes)) { + return $default; + } + + return $this->attributes[$attribute]; + } + + /** + * {@inheritdoc} + */ + public function withAttribute($attribute, $value) + { + $new = clone $this; + $new->attributes[$attribute] = $value; + + return $new; + } + + /** + * {@inheritdoc} + */ + public function withoutAttribute($attribute) + { + if (false === array_key_exists($attribute, $this->attributes)) { + return $this; + } + + $new = clone $this; + unset($new->attributes[$attribute]); + + return $new; + } +} diff --git a/vendor/guzzlehttp/psr7/src/Stream.php b/vendor/guzzlehttp/psr7/src/Stream.php index 0b0db0110..214af151c 100644 --- a/vendor/guzzlehttp/psr7/src/Stream.php +++ b/vendor/guzzlehttp/psr7/src/Stream.php @@ -38,7 +38,7 @@ class Stream implements StreamInterface * This constructor accepts an associative array of options. * * - size: (int) If a read stream would otherwise have an indeterminate - * size, but the size is known due to foreknownledge, then you can + * size, but the size is known due to foreknowledge, then you can * provide that size, in bytes. * - metadata: (array) Any additional metadata to return when the metadata * of the stream is accessed. diff --git a/vendor/guzzlehttp/psr7/src/UploadedFile.php b/vendor/guzzlehttp/psr7/src/UploadedFile.php new file mode 100644 index 000000000..e62bd5c80 --- /dev/null +++ b/vendor/guzzlehttp/psr7/src/UploadedFile.php @@ -0,0 +1,316 @@ +setError($errorStatus); + $this->setSize($size); + $this->setClientFilename($clientFilename); + $this->setClientMediaType($clientMediaType); + + if ($this->isOk()) { + $this->setStreamOrFile($streamOrFile); + } + } + + /** + * Depending on the value set file or stream variable + * + * @param mixed $streamOrFile + * @throws InvalidArgumentException + */ + private function setStreamOrFile($streamOrFile) + { + if (is_string($streamOrFile)) { + $this->file = $streamOrFile; + } elseif (is_resource($streamOrFile)) { + $this->stream = new Stream($streamOrFile); + } elseif ($streamOrFile instanceof StreamInterface) { + $this->stream = $streamOrFile; + } else { + throw new InvalidArgumentException( + 'Invalid stream or file provided for UploadedFile' + ); + } + } + + /** + * @param int $error + * @throws InvalidArgumentException + */ + private function setError($error) + { + if (false === is_int($error)) { + throw new InvalidArgumentException( + 'Upload file error status must be an integer' + ); + } + + if (false === in_array($error, UploadedFile::$errors)) { + throw new InvalidArgumentException( + 'Invalid error status for UploadedFile' + ); + } + + $this->error = $error; + } + + /** + * @param int $size + * @throws InvalidArgumentException + */ + private function setSize($size) + { + if (false === is_int($size)) { + throw new InvalidArgumentException( + 'Upload file size must be an integer' + ); + } + + $this->size = $size; + } + + /** + * @param mixed $param + * @return boolean + */ + private function isStringOrNull($param) + { + return in_array(gettype($param), ['string', 'NULL']); + } + + /** + * @param mixed $param + * @return boolean + */ + private function isStringNotEmpty($param) + { + return is_string($param) && false === empty($param); + } + + /** + * @param string|null $clientFilename + * @throws InvalidArgumentException + */ + private function setClientFilename($clientFilename) + { + if (false === $this->isStringOrNull($clientFilename)) { + throw new InvalidArgumentException( + 'Upload file client filename must be a string or null' + ); + } + + $this->clientFilename = $clientFilename; + } + + /** + * @param string|null $clientMediaType + * @throws InvalidArgumentException + */ + private function setClientMediaType($clientMediaType) + { + if (false === $this->isStringOrNull($clientMediaType)) { + throw new InvalidArgumentException( + 'Upload file client media type must be a string or null' + ); + } + + $this->clientMediaType = $clientMediaType; + } + + /** + * Return true if there is no upload error + * + * @return boolean + */ + private function isOk() + { + return $this->error === UPLOAD_ERR_OK; + } + + /** + * @return boolean + */ + public function isMoved() + { + return $this->moved; + } + + /** + * @throws RuntimeException if is moved or not ok + */ + private function validateActive() + { + if (false === $this->isOk()) { + throw new RuntimeException('Cannot retrieve stream due to upload error'); + } + + if ($this->isMoved()) { + throw new RuntimeException('Cannot retrieve stream after it has already been moved'); + } + } + + /** + * {@inheritdoc} + * @throws RuntimeException if the upload was not successful. + */ + public function getStream() + { + $this->validateActive(); + + if ($this->stream instanceof StreamInterface) { + return $this->stream; + } + + return new LazyOpenStream($this->file, 'r+'); + } + + /** + * {@inheritdoc} + * + * @see http://php.net/is_uploaded_file + * @see http://php.net/move_uploaded_file + * @param string $targetPath Path to which to move the uploaded file. + * @throws RuntimeException if the upload was not successful. + * @throws InvalidArgumentException if the $path specified is invalid. + * @throws RuntimeException on any error during the move operation, or on + * the second or subsequent call to the method. + */ + public function moveTo($targetPath) + { + $this->validateActive(); + + if (false === $this->isStringNotEmpty($targetPath)) { + throw new InvalidArgumentException( + 'Invalid path provided for move operation; must be a non-empty string' + ); + } + + if ($this->file) { + $this->moved = php_sapi_name() == 'cli' + ? rename($this->file, $targetPath) + : move_uploaded_file($this->file, $targetPath); + } else { + copy_to_stream( + $this->getStream(), + new LazyOpenStream($targetPath, 'w') + ); + + $this->moved = true; + } + + if (false === $this->moved) { + throw new RuntimeException( + sprintf('Uploaded file could not be moved to %s', $targetPath) + ); + } + } + + /** + * {@inheritdoc} + * + * @return int|null The file size in bytes or null if unknown. + */ + public function getSize() + { + return $this->size; + } + + /** + * {@inheritdoc} + * + * @see http://php.net/manual/en/features.file-upload.errors.php + * @return int One of PHP's UPLOAD_ERR_XXX constants. + */ + public function getError() + { + return $this->error; + } + + /** + * {@inheritdoc} + * + * @return string|null The filename sent by the client or null if none + * was provided. + */ + public function getClientFilename() + { + return $this->clientFilename; + } + + /** + * {@inheritdoc} + */ + public function getClientMediaType() + { + return $this->clientMediaType; + } +} diff --git a/vendor/guzzlehttp/psr7/src/Uri.php b/vendor/guzzlehttp/psr7/src/Uri.php index d428f2e1d..44a1e9d49 100644 --- a/vendor/guzzlehttp/psr7/src/Uri.php +++ b/vendor/guzzlehttp/psr7/src/Uri.php @@ -4,10 +4,11 @@ namespace GuzzleHttp\Psr7; use Psr\Http\Message\UriInterface; /** - * Basic PSR-7 URI implementation. + * PSR-7 URI implementation. * - * @link https://github.com/phly/http This class is based upon - * Matthew Weier O'Phinney's URI implementation in phly/http. + * @author Michael Dowling + * @author Tobias Schultze + * @author Matthew Weier O'Phinney */ class Uri implements UriInterface { @@ -42,11 +43,11 @@ class Uri implements UriInterface private $fragment = ''; /** - * @param string $uri URI to parse and wrap. + * @param string $uri URI to parse */ public function __construct($uri = '') { - if ($uri != null) { + if ($uri != '') { $parts = parse_url($uri); if ($parts === false) { throw new \InvalidArgumentException("Unable to parse URI: $uri"); @@ -60,7 +61,7 @@ class Uri implements UriInterface return self::createUriString( $this->scheme, $this->getAuthority(), - $this->getPath(), + $this->path, $this->query, $this->fragment ); @@ -86,7 +87,7 @@ class Uri implements UriInterface $results = []; $segments = explode('/', $path); foreach ($segments as $segment) { - if ($segment == '..') { + if ($segment === '..') { array_pop($results); } elseif (!isset($ignoreSegments[$segment])) { $results[] = $segment; @@ -102,7 +103,7 @@ class Uri implements UriInterface } // Add the trailing slash if necessary - if ($newPath != '/' && isset($ignoreSegments[end($segments)])) { + if ($newPath !== '/' && isset($ignoreSegments[end($segments)])) { $newPath .= '/'; } @@ -112,74 +113,62 @@ class Uri implements UriInterface /** * Resolve a base URI with a relative URI and return a new URI. * - * @param UriInterface $base Base URI - * @param string $rel Relative URI + * @param UriInterface $base Base URI + * @param string|UriInterface $rel Relative URI * * @return UriInterface + * @link http://tools.ietf.org/html/rfc3986#section-5.2 */ public static function resolve(UriInterface $base, $rel) { - if ($rel === null || $rel === '') { - return $base; - } - if (!($rel instanceof UriInterface)) { $rel = new self($rel); } - // Return the relative uri as-is if it has a scheme. - if ($rel->getScheme()) { - return $rel->withPath(static::removeDotSegments($rel->getPath())); + if ((string) $rel === '') { + // we can simply return the same base URI instance for this same-document reference + return $base; } - $relParts = [ - 'scheme' => $rel->getScheme(), - 'authority' => $rel->getAuthority(), - 'path' => $rel->getPath(), - 'query' => $rel->getQuery(), - 'fragment' => $rel->getFragment() - ]; + if ($rel->getScheme() != '') { + return $rel->withPath(self::removeDotSegments($rel->getPath())); + } - $parts = [ - 'scheme' => $base->getScheme(), - 'authority' => $base->getAuthority(), - 'path' => $base->getPath(), - 'query' => $base->getQuery(), - 'fragment' => $base->getFragment() - ]; - - if (!empty($relParts['authority'])) { - $parts['authority'] = $relParts['authority']; - $parts['path'] = self::removeDotSegments($relParts['path']); - $parts['query'] = $relParts['query']; - $parts['fragment'] = $relParts['fragment']; - } elseif (!empty($relParts['path'])) { - if (substr($relParts['path'], 0, 1) == '/') { - $parts['path'] = self::removeDotSegments($relParts['path']); - $parts['query'] = $relParts['query']; - $parts['fragment'] = $relParts['fragment']; + if ($rel->getAuthority() != '') { + $targetAuthority = $rel->getAuthority(); + $targetPath = self::removeDotSegments($rel->getPath()); + $targetQuery = $rel->getQuery(); + } else { + $targetAuthority = $base->getAuthority(); + if ($rel->getPath() === '') { + $targetPath = $base->getPath(); + $targetQuery = $rel->getQuery() != '' ? $rel->getQuery() : $base->getQuery(); } else { - if (!empty($parts['authority']) && empty($parts['path'])) { - $mergedPath = '/'; + if ($rel->getPath()[0] === '/') { + $targetPath = $rel->getPath(); } else { - $mergedPath = substr($parts['path'], 0, strrpos($parts['path'], '/') + 1); + if ($targetAuthority != '' && $base->getPath() === '') { + $targetPath = '/' . $rel->getPath(); + } else { + $lastSlashPos = strrpos($base->getPath(), '/'); + if ($lastSlashPos === false) { + $targetPath = $rel->getPath(); + } else { + $targetPath = substr($base->getPath(), 0, $lastSlashPos + 1) . $rel->getPath(); + } + } } - $parts['path'] = self::removeDotSegments($mergedPath . $relParts['path']); - $parts['query'] = $relParts['query']; - $parts['fragment'] = $relParts['fragment']; + $targetPath = self::removeDotSegments($targetPath); + $targetQuery = $rel->getQuery(); } - } elseif (!empty($relParts['query'])) { - $parts['query'] = $relParts['query']; - } elseif ($relParts['fragment'] != null) { - $parts['fragment'] = $relParts['fragment']; } - return new self(static::createUriString( - $parts['scheme'], - $parts['authority'], - $parts['path'], - $parts['query'], - $parts['fragment'] + return new self(self::createUriString( + $base->getScheme(), + $targetAuthority, + $targetPath, + $targetQuery, + $rel->getFragment() )); } @@ -189,26 +178,22 @@ class Uri implements UriInterface * Any existing query string values that exactly match the provided key are * removed. * - * Note: this function will convert "=" to "%3D" and "&" to "%26". - * * @param UriInterface $uri URI to use as a base. - * @param string $key Query string key value pair to remove. + * @param string $key Query string key to remove. * * @return UriInterface */ public static function withoutQueryValue(UriInterface $uri, $key) { $current = $uri->getQuery(); - if (!$current) { + if ($current == '') { return $uri; } - $result = []; - foreach (explode('&', $current) as $part) { - if (explode('=', $part)[0] !== $key) { - $result[] = $part; - }; - } + $decodedKey = rawurldecode($key); + $result = array_filter(explode('&', $current), function ($part) use ($decodedKey) { + return rawurldecode(explode('=', $part)[0]) !== $decodedKey; + }); return $uri->withQuery(implode('&', $result)); } @@ -219,30 +204,33 @@ class Uri implements UriInterface * Any existing query string values that exactly match the provided key are * removed and replaced with the given key value pair. * - * Note: this function will convert "=" to "%3D" and "&" to "%26". + * A value of null will set the query string key without a value, e.g. "key" + * instead of "key=value". * - * @param UriInterface $uri URI to use as a base. - * @param string $key Key to set. - * @param string $value Value to set. + * @param UriInterface $uri URI to use as a base. + * @param string $key Key to set. + * @param string|null $value Value to set * * @return UriInterface */ public static function withQueryValue(UriInterface $uri, $key, $value) { $current = $uri->getQuery(); - $key = strtr($key, self::$replaceQuery); - if (!$current) { + if ($current == '') { $result = []; } else { - $result = []; - foreach (explode('&', $current) as $part) { - if (explode('=', $part)[0] !== $key) { - $result[] = $part; - }; - } + $decodedKey = rawurldecode($key); + $result = array_filter(explode('&', $current), function ($part) use ($decodedKey) { + return rawurldecode(explode('=', $part)[0]) !== $decodedKey; + }); } + // Query string separators ("=", "&") within the key or value need to be encoded + // (while preventing double-encoding) before setting the query string. All other + // chars that need percent-encoding will be encoded by withQuery(). + $key = strtr($key, self::$replaceQuery); + if ($value !== null) { $result[] = $key . '=' . strtr($value, self::$replaceQuery); } else { @@ -273,16 +261,16 @@ class Uri implements UriInterface public function getAuthority() { - if (empty($this->host)) { + if ($this->host == '') { return ''; } $authority = $this->host; - if (!empty($this->userInfo)) { + if ($this->userInfo != '') { $authority = $this->userInfo . '@' . $authority; } - if ($this->isNonStandardPort($this->scheme, $this->host, $this->port)) { + if ($this->port !== null) { $authority .= ':' . $this->port; } @@ -306,7 +294,7 @@ class Uri implements UriInterface public function getPath() { - return $this->path == null ? '' : $this->path; + return $this->path; } public function getQuery() @@ -329,14 +317,14 @@ class Uri implements UriInterface $new = clone $this; $new->scheme = $scheme; - $new->port = $new->filterPort($new->scheme, $new->host, $new->port); + $new->port = $new->filterPort($new->port); return $new; } public function withUserInfo($user, $password = null) { $info = $user; - if ($password) { + if ($password != '') { $info .= ':' . $password; } @@ -351,6 +339,8 @@ class Uri implements UriInterface public function withHost($host) { + $host = $this->filterHost($host); + if ($this->host === $host) { return $this; } @@ -362,7 +352,7 @@ class Uri implements UriInterface public function withPort($port) { - $port = $this->filterPort($this->scheme, $this->host, $port); + $port = $this->filterPort($port); if ($this->port === $port) { return $this; @@ -375,12 +365,6 @@ class Uri implements UriInterface public function withPath($path) { - if (!is_string($path)) { - throw new \InvalidArgumentException( - 'Invalid path provided; must be a string' - ); - } - $path = $this->filterPath($path); if ($this->path === $path) { @@ -394,17 +378,6 @@ class Uri implements UriInterface public function withQuery($query) { - if (!is_string($query) && !method_exists($query, '__toString')) { - throw new \InvalidArgumentException( - 'Query string must be a string' - ); - } - - $query = (string) $query; - if (substr($query, 0, 1) === '?') { - $query = substr($query, 1); - } - $query = $this->filterQueryAndFragment($query); if ($this->query === $query) { @@ -418,10 +391,6 @@ class Uri implements UriInterface public function withFragment($fragment) { - if (substr($fragment, 0, 1) === '#') { - $fragment = substr($fragment, 1); - } - $fragment = $this->filterQueryAndFragment($fragment); if ($this->fragment === $fragment) { @@ -436,7 +405,7 @@ class Uri implements UriInterface /** * Apply parse_url parts to a URI. * - * @param $parts Array of parse_url parts to apply. + * @param array $parts Array of parse_url parts to apply. */ private function applyParts(array $parts) { @@ -444,9 +413,11 @@ class Uri implements UriInterface ? $this->filterScheme($parts['scheme']) : ''; $this->userInfo = isset($parts['user']) ? $parts['user'] : ''; - $this->host = isset($parts['host']) ? $parts['host'] : ''; - $this->port = !empty($parts['port']) - ? $this->filterPort($this->scheme, $this->host, $parts['port']) + $this->host = isset($parts['host']) + ? $this->filterHost($parts['host']) + : ''; + $this->port = isset($parts['port']) + ? $this->filterPort($parts['port']) : null; $this->path = isset($parts['path']) ? $this->filterPath($parts['path']) @@ -476,27 +447,36 @@ class Uri implements UriInterface { $uri = ''; - if (!empty($scheme)) { - $uri .= $scheme . '://'; + if ($scheme != '') { + $uri .= $scheme . ':'; } - if (!empty($authority)) { - $uri .= $authority; + if ($authority != '') { + $uri .= '//' . $authority; } - if ($path != null) { - // Add a leading slash if necessary. - if ($uri && substr($path, 0, 1) !== '/') { - $uri .= '/'; + if ($path != '') { + if ($path[0] !== '/') { + if ($authority != '') { + // If the path is rootless and an authority is present, the path MUST be prefixed by "/" + $path = '/' . $path; + } + } elseif (isset($path[1]) && $path[1] === '/') { + if ($authority == '') { + // If the path is starting with more than one "/" and no authority is present, the + // starting slashes MUST be reduced to one. + $path = '/' . ltrim($path, '/'); + } } + $uri .= $path; } - if ($query != null) { + if ($query != '') { $uri .= '?' . $query; } - if ($fragment != null) { + if ($fragment != '') { $uri .= '#' . $fragment; } @@ -507,70 +487,87 @@ class Uri implements UriInterface * Is a given port non-standard for the current scheme? * * @param string $scheme - * @param string $host - * @param int $port + * @param int $port + * * @return bool */ - private static function isNonStandardPort($scheme, $host, $port) + private static function isNonStandardPort($scheme, $port) { - if (!$scheme && $port) { - return true; - } - - if (!$host || !$port) { - return false; - } - - return !isset(static::$schemes[$scheme]) || $port !== static::$schemes[$scheme]; + return !isset(self::$schemes[$scheme]) || $port !== self::$schemes[$scheme]; } /** * @param string $scheme * * @return string + * + * @throws \InvalidArgumentException If the scheme is invalid. */ private function filterScheme($scheme) { - $scheme = strtolower($scheme); - $scheme = rtrim($scheme, ':/'); + if (!is_string($scheme)) { + throw new \InvalidArgumentException('Scheme must be a string'); + } - return $scheme; + return strtolower($scheme); } /** - * @param string $scheme * @param string $host - * @param int $port + * + * @return string + * + * @throws \InvalidArgumentException If the host is invalid. + */ + private function filterHost($host) + { + if (!is_string($host)) { + throw new \InvalidArgumentException('Host must be a string'); + } + + return strtolower($host); + } + + /** + * @param int|null $port * * @return int|null * * @throws \InvalidArgumentException If the port is invalid. */ - private function filterPort($scheme, $host, $port) + private function filterPort($port) { - if (null !== $port) { - $port = (int) $port; - if (1 > $port || 0xffff < $port) { - throw new \InvalidArgumentException( - sprintf('Invalid port: %d. Must be between 1 and 65535', $port) - ); - } + if ($port === null) { + return null; } - return $this->isNonStandardPort($scheme, $host, $port) ? $port : null; + $port = (int) $port; + if (1 > $port || 0xffff < $port) { + throw new \InvalidArgumentException( + sprintf('Invalid port: %d. Must be between 1 and 65535', $port) + ); + } + + return self::isNonStandardPort($this->scheme, $port) ? $port : null; } /** * Filters the path of a URI * - * @param $path + * @param string $path * * @return string + * + * @throws \InvalidArgumentException If the path is invalid. */ private function filterPath($path) { + if (!is_string($path)) { + throw new \InvalidArgumentException('Path must be a string'); + } + return preg_replace_callback( - '/(?:[^' . self::$charUnreserved . self::$charSubDelims . ':@\/%]+|%(?![A-Fa-f0-9]{2}))/', + '/(?:[^' . self::$charUnreserved . self::$charSubDelims . '%:@\/]++|%(?![A-Fa-f0-9]{2}))/', [$this, 'rawurlencodeMatchZero'], $path ); @@ -579,14 +576,20 @@ class Uri implements UriInterface /** * Filters the query string or fragment of a URI. * - * @param $str + * @param string $str * * @return string + * + * @throws \InvalidArgumentException If the query or fragment is invalid. */ private function filterQueryAndFragment($str) { + if (!is_string($str)) { + throw new \InvalidArgumentException('Query and fragment must be a string'); + } + return preg_replace_callback( - '/(?:[^' . self::$charUnreserved . self::$charSubDelims . '%:@\/\?]+|%(?![A-Fa-f0-9]{2}))/', + '/(?:[^' . self::$charUnreserved . self::$charSubDelims . '%:@\/\?]++|%(?![A-Fa-f0-9]{2}))/', [$this, 'rawurlencodeMatchZero'], $str ); diff --git a/vendor/guzzlehttp/psr7/src/functions.php b/vendor/guzzlehttp/psr7/src/functions.php index fd3e7f516..96bf92611 100644 --- a/vendor/guzzlehttp/psr7/src/functions.php +++ b/vendor/guzzlehttp/psr7/src/functions.php @@ -4,6 +4,7 @@ namespace GuzzleHttp\Psr7; use Psr\Http\Message\MessageInterface; use Psr\Http\Message\RequestInterface; use Psr\Http\Message\ResponseInterface; +use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Message\StreamInterface; use Psr\Http\Message\UriInterface; @@ -68,22 +69,24 @@ function uri_for($uri) * - metadata: Array of custom metadata. * - size: Size of the stream. * - * @param resource|string|StreamInterface $resource Entity body data - * @param array $options Additional options + * @param resource|string|null|int|float|bool|StreamInterface|callable $resource Entity body data + * @param array $options Additional options * * @return Stream * @throws \InvalidArgumentException if the $resource arg is not valid. */ function stream_for($resource = '', array $options = []) { + if (is_scalar($resource)) { + $stream = fopen('php://temp', 'r+'); + if ($resource !== '') { + fwrite($stream, $resource); + fseek($stream, 0); + } + return new Stream($stream, $options); + } + switch (gettype($resource)) { - case 'string': - $stream = fopen('php://temp', 'r+'); - if ($resource !== '') { - fwrite($stream, $resource); - fseek($stream, 0); - } - return new Stream($stream, $options); case 'resource': return new Stream($resource, $options); case 'object': @@ -209,6 +212,14 @@ function modify_request(RequestInterface $request, array $changes) // Remove the host header if one is on the URI if ($host = $changes['uri']->getHost()) { $changes['set_headers']['Host'] = $host; + + if ($port = $changes['uri']->getPort()) { + $standardPorts = ['http' => 80, 'https' => 443]; + $scheme = $changes['uri']->getScheme(); + if (isset($standardPorts[$scheme]) && $port != $standardPorts[$scheme]) { + $changes['set_headers']['Host'] .= ':'.$port; + } + } } $uri = $changes['uri']; } @@ -226,6 +237,19 @@ function modify_request(RequestInterface $request, array $changes) $uri = $uri->withQuery($changes['query']); } + if ($request instanceof ServerRequestInterface) { + return new ServerRequest( + isset($changes['method']) ? $changes['method'] : $request->getMethod(), + $uri, + $headers, + isset($changes['body']) ? $changes['body'] : $request->getBody(), + isset($changes['version']) + ? $changes['version'] + : $request->getProtocolVersion(), + $request->getServerParams() + ); + } + return new Request( isset($changes['method']) ? $changes['method'] : $request->getMethod(), $uri, @@ -422,7 +446,7 @@ function readline(StreamInterface $stream, $maxLength = null) } $buffer .= $byte; // Break when a new line is found or the max length - 1 is reached - if ($byte == PHP_EOL || ++$size == $maxLength - 1) { + if ($byte === "\n" || ++$size === $maxLength - 1) { break; } } @@ -441,7 +465,7 @@ function parse_request($message) { $data = _parse_message($message); $matches = []; - if (!preg_match('/^[a-zA-Z]+\s+([a-zA-Z]+:\/\/|\/).*/', $data['start-line'], $matches)) { + if (!preg_match('/^[\S]+\s+([a-zA-Z]+:\/\/|\/).*/', $data['start-line'], $matches)) { throw new \InvalidArgumentException('Invalid request string'); } $parts = explode(' ', $data['start-line'], 3); @@ -535,7 +559,7 @@ function parse_query($str, $urlEncoding = true) /** * Build a query string from an array of key value pairs. * - * This function can use the return value of parseQuery() to build a query + * This function can use the return value of parse_query() to build a query * string. This function does not modify the provided keys when an array is * encountered (like http_build_query would). * @@ -553,9 +577,9 @@ function build_query(array $params, $encoding = PHP_QUERY_RFC3986) if ($encoding === false) { $encoder = function ($str) { return $str; }; - } elseif ($encoding == PHP_QUERY_RFC3986) { + } elseif ($encoding === PHP_QUERY_RFC3986) { $encoder = 'rawurlencode'; - } elseif ($encoding == PHP_QUERY_RFC1738) { + } elseif ($encoding === PHP_QUERY_RFC1738) { $encoder = 'urlencode'; } else { throw new \InvalidArgumentException('Invalid type'); diff --git a/web.config b/web.config index a0535a10d..562847125 100644 --- a/web.config +++ b/web.config @@ -34,6 +34,14 @@ + + + + + + + +