From cdf77e49f851638f1dccb6c37cb9390a4610836a Mon Sep 17 00:00:00 2001 From: Alex Pott <alex.a.pott@googlemail.com> Date: Mon, 11 Aug 2014 09:02:51 -0500 Subject: [PATCH] Issue #2317845 by sun | Arla: Upgrade Guzzle to version 4.1.7. --- composer.lock | 27 +-- core/vendor/composer/ClassLoader.php | 11 +- core/vendor/composer/autoload_real.php | 3 - core/vendor/composer/installed.json | 212 +++++++++--------- core/vendor/guzzlehttp/guzzle/.travis.yml | 3 +- core/vendor/guzzlehttp/guzzle/CHANGELOG.md | 43 ++++ core/vendor/guzzlehttp/guzzle/composer.json | 4 +- .../vendor/guzzlehttp/guzzle/docs/clients.rst | 2 +- core/vendor/guzzlehttp/guzzle/docs/events.rst | 9 +- .../guzzlehttp/guzzle/docs/quickstart.rst | 6 +- .../guzzle/src/Adapter/Curl/BatchContext.php | 21 +- .../guzzle/src/Adapter/Curl/CurlFactory.php | 19 +- .../guzzle/src/Adapter/Curl/MultiAdapter.php | 94 +++++++- .../guzzle/src/Adapter/StreamAdapter.php | 38 ++-- .../guzzlehttp/guzzle/src/ClientInterface.php | 2 +- .../guzzlehttp/guzzle/src/Event/Emitter.php | 22 +- .../guzzle/src/Event/SubscriberInterface.php | 10 +- .../guzzle/src/Message/AbstractMessage.php | 59 ++++- .../guzzlehttp/guzzle/src/Message/Request.php | 7 - .../guzzle/src/Message/Response.php | 9 +- .../guzzle/src/Message/ResponseInterface.php | 3 + .../guzzle/src/Post/MultipartBody.php | 92 ++------ .../guzzlehttp/guzzle/src/Post/PostBody.php | 21 +- .../guzzle/src/Subscriber/History.php | 6 +- core/vendor/guzzlehttp/guzzle/src/Url.php | 2 +- .../tests/Adapter/Curl/BatchContextTest.php | 2 + .../tests/Adapter/Curl/CurlAdapterTest.php | 19 ++ .../tests/Adapter/Curl/CurlFactoryTest.php | 23 ++ .../tests/Adapter/Curl/MultiAdapterTest.php | 126 +++++++++++ .../guzzle/tests/Event/EmitterTest.php | 17 ++ .../tests/Exception/RequestExceptionTest.php | 2 +- .../tests/Message/AbstractMessageTest.php | 69 +++--- .../guzzle/tests/Post/PostBodyTest.php | 63 +++++- .../guzzle/tests/Subscriber/HistoryTest.php | 12 + .../guzzlehttp/guzzle/tests/UrlTest.php | 4 +- core/vendor/guzzlehttp/streams/.travis.yml | 3 +- core/vendor/guzzlehttp/streams/CHANGELOG.rst | 21 ++ core/vendor/guzzlehttp/streams/Makefile | 6 + core/vendor/guzzlehttp/streams/README.rst | 2 +- core/vendor/guzzlehttp/streams/composer.json | 2 +- .../guzzlehttp/streams/src/AppendStream.php | 9 +- .../guzzlehttp/streams/src/CachingStream.php | 3 +- .../guzzlehttp/streams/src/LazyOpenStream.php | 117 ++++++++++ core/vendor/guzzlehttp/streams/src/Stream.php | 39 ++-- .../streams/src/StreamDecoratorTrait.php | 6 +- .../guzzlehttp/streams/src/functions.php | 35 +++ .../streams/tests/AppendStreamTest.php | 8 +- .../streams/tests/CachingStreamTest.php | 6 +- .../streams/tests/LazyOpenStreamTest.php | 61 +++++ .../streams/tests/NoSeekStreamTest.php | 9 + .../guzzlehttp/streams/tests/StreamTest.php | 13 ++ .../streams/tests/functionsTest.php | 16 ++ 52 files changed, 1034 insertions(+), 384 deletions(-) create mode 100644 core/vendor/guzzlehttp/streams/src/LazyOpenStream.php create mode 100644 core/vendor/guzzlehttp/streams/tests/LazyOpenStreamTest.php diff --git a/composer.lock b/composer.lock index 7b2dbb7ecb28..a21d52b8d334 100644 --- a/composer.lock +++ b/composer.lock @@ -459,21 +459,21 @@ }, { "name": "guzzlehttp/guzzle", - "version": "4.1.3", + "version": "4.1.7", "source": { "type": "git", "url": "https://github.com/guzzle/guzzle.git", - "reference": "012b2aecbda4e38f119c19580898685851015fa7" + "reference": "448f2c2076cf0fb756230611491c4f7ecb735a29" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/guzzle/zipball/012b2aecbda4e38f119c19580898685851015fa7", - "reference": "012b2aecbda4e38f119c19580898685851015fa7", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/448f2c2076cf0fb756230611491c4f7ecb735a29", + "reference": "448f2c2076cf0fb756230611491c4f7ecb735a29", "shasum": "" }, "require": { "ext-json": "*", - "guzzlehttp/streams": "~1.3", + "guzzlehttp/streams": "~1.4", "php": ">=5.4.0" }, "require-dev": { @@ -487,7 +487,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.1.x-dev" + "dev-master": "4.1-dev" } }, "autoload": { @@ -520,20 +520,20 @@ "rest", "web service" ], - "time": "2014-07-16 03:01:02" + "time": "2014-08-08 01:30:43" }, { "name": "guzzlehttp/streams", - "version": "1.3.0", + "version": "1.5.1", "source": { "type": "git", "url": "https://github.com/guzzle/streams.git", - "reference": "d6aaa91cfdbae86355dd2a168a3ca536755898a2" + "reference": "fb0d1ee29987c2bdc59867bffaade6fc88c2675f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/streams/zipball/d6aaa91cfdbae86355dd2a168a3ca536755898a2", - "reference": "d6aaa91cfdbae86355dd2a168a3ca536755898a2", + "url": "https://api.github.com/repos/guzzle/streams/zipball/fb0d1ee29987c2bdc59867bffaade6fc88c2675f", + "reference": "fb0d1ee29987c2bdc59867bffaade6fc88c2675f", "shasum": "" }, "require": { @@ -545,7 +545,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.2.x-dev" + "dev-master": "1.5-dev" } }, "autoload": { @@ -573,7 +573,7 @@ "Guzzle", "stream" ], - "time": "2014-07-15 22:02:02" + "time": "2014-08-10 23:57:01" }, { "name": "kriswallsmith/assetic", @@ -2448,6 +2448,7 @@ "symfony-cmf/routing": 15, "phpunit/phpunit-mock-objects": 20 }, + "prefer-stable": false, "platform": { "php": ">=5.4.2" }, diff --git a/core/vendor/composer/ClassLoader.php b/core/vendor/composer/ClassLoader.php index a7105553143a..443364959a54 100644 --- a/core/vendor/composer/ClassLoader.php +++ b/core/vendor/composer/ClassLoader.php @@ -143,6 +143,8 @@ public function add($prefix, $paths, $prepend = false) * @param string $prefix The prefix/namespace, with trailing '\\' * @param array|string $paths The PSR-0 base directories * @param bool $prepend Whether to prepend the directories + * + * @throws \InvalidArgumentException */ public function addPsr4($prefix, $paths, $prepend = false) { @@ -202,10 +204,13 @@ public function set($prefix, $paths) * Registers a set of PSR-4 directories for a given namespace, * replacing any others previously set for this namespace. * - * @param string $prefix The prefix/namespace, with trailing '\\' - * @param array|string $paths The PSR-4 base directories + * @param string $prefix The prefix/namespace, with trailing '\\' + * @param array|string $paths The PSR-4 base directories + * + * @throws \InvalidArgumentException */ - public function setPsr4($prefix, $paths) { + public function setPsr4($prefix, $paths) + { if (!$prefix) { $this->fallbackDirsPsr4 = (array) $paths; } else { diff --git a/core/vendor/composer/autoload_real.php b/core/vendor/composer/autoload_real.php index 0ecdb36774e7..f41b172e74af 100644 --- a/core/vendor/composer/autoload_real.php +++ b/core/vendor/composer/autoload_real.php @@ -23,9 +23,6 @@ public static function getLoader() self::$loader = $loader = new \Composer\Autoload\ClassLoader(); spl_autoload_unregister(array('ComposerAutoloaderInitDrupal8', 'loadClassLoader')); - $vendorDir = dirname(__DIR__); - $baseDir = dirname(dirname($vendorDir)); - $includePaths = require __DIR__ . '/include_paths.php'; array_push($includePaths, get_include_path()); set_include_path(join(PATH_SEPARATOR, $includePaths)); diff --git a/core/vendor/composer/installed.json b/core/vendor/composer/installed.json index cb411087ebb7..77784eb16082 100644 --- a/core/vendor/composer/installed.json +++ b/core/vendor/composer/installed.json @@ -2301,18 +2301,109 @@ ] }, { - "name": "guzzlehttp/streams", - "version": "1.3.0", + "name": "symfony/serializer", + "version": "v2.5.2", + "version_normalized": "2.5.2.0", + "target-dir": "Symfony/Component/Serializer", + "source": { + "type": "git", + "url": "https://github.com/symfony/Serializer.git", + "reference": "33185b290310ab1fd8283fb8ed2a434cdb88b9b9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/Serializer/zipball/33185b290310ab1fd8283fb8ed2a434cdb88b9b9", + "reference": "33185b290310ab1fd8283fb8ed2a434cdb88b9b9", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "time": "2014-07-09 09:05:48", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.5-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-0": { + "Symfony\\Component\\Serializer\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com", + "homepage": "http://fabien.potencier.org", + "role": "Lead Developer" + }, + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + } + ], + "description": "Symfony Serializer Component", + "homepage": "http://symfony.com" + }, + { + "name": "mikey179/vfsStream", + "version": "v1.3.0", "version_normalized": "1.3.0.0", + "source": { + "type": "git", + "url": "https://github.com/mikey179/vfsStream.git", + "reference": "8571f349567e02af1b7efc0fc4e3a4a1c98e664e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/mikey179/vfsStream/zipball/8571f349567e02af1b7efc0fc4e3a4a1c98e664e", + "reference": "8571f349567e02af1b7efc0fc4e3a4a1c98e664e", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.1" + }, + "time": "2014-07-21 20:15:54", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.3.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-0": { + "org\\bovigo\\vfs\\": "src/main/php" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD" + ], + "homepage": "http://vfs.bovigo.org/" + }, + { + "name": "guzzlehttp/streams", + "version": "1.5.1", + "version_normalized": "1.5.1.0", "source": { "type": "git", "url": "https://github.com/guzzle/streams.git", - "reference": "d6aaa91cfdbae86355dd2a168a3ca536755898a2" + "reference": "fb0d1ee29987c2bdc59867bffaade6fc88c2675f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/streams/zipball/d6aaa91cfdbae86355dd2a168a3ca536755898a2", - "reference": "d6aaa91cfdbae86355dd2a168a3ca536755898a2", + "url": "https://api.github.com/repos/guzzle/streams/zipball/fb0d1ee29987c2bdc59867bffaade6fc88c2675f", + "reference": "fb0d1ee29987c2bdc59867bffaade6fc88c2675f", "shasum": "" }, "require": { @@ -2321,11 +2412,11 @@ "require-dev": { "phpunit/phpunit": "~4.0" }, - "time": "2014-07-15 22:02:02", + "time": "2014-08-10 23:57:01", "type": "library", "extra": { "branch-alias": { - "dev-master": "1.2.x-dev" + "dev-master": "1.5-dev" } }, "installation-source": "dist", @@ -2357,22 +2448,22 @@ }, { "name": "guzzlehttp/guzzle", - "version": "4.1.3", - "version_normalized": "4.1.3.0", + "version": "4.1.7", + "version_normalized": "4.1.7.0", "source": { "type": "git", "url": "https://github.com/guzzle/guzzle.git", - "reference": "012b2aecbda4e38f119c19580898685851015fa7" + "reference": "448f2c2076cf0fb756230611491c4f7ecb735a29" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/guzzle/zipball/012b2aecbda4e38f119c19580898685851015fa7", - "reference": "012b2aecbda4e38f119c19580898685851015fa7", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/448f2c2076cf0fb756230611491c4f7ecb735a29", + "reference": "448f2c2076cf0fb756230611491c4f7ecb735a29", "shasum": "" }, "require": { "ext-json": "*", - "guzzlehttp/streams": "~1.3", + "guzzlehttp/streams": "~1.4", "php": ">=5.4.0" }, "require-dev": { @@ -2383,11 +2474,11 @@ "suggest": { "ext-curl": "Guzzle will use specific adapters if cURL is present" }, - "time": "2014-07-16 03:01:02", + "time": "2014-08-08 01:30:43", "type": "library", "extra": { "branch-alias": { - "dev-master": "4.1.x-dev" + "dev-master": "4.1-dev" } }, "installation-source": "dist", @@ -2421,96 +2512,5 @@ "rest", "web service" ] - }, - { - "name": "symfony/serializer", - "version": "v2.5.2", - "version_normalized": "2.5.2.0", - "target-dir": "Symfony/Component/Serializer", - "source": { - "type": "git", - "url": "https://github.com/symfony/Serializer.git", - "reference": "33185b290310ab1fd8283fb8ed2a434cdb88b9b9" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/Serializer/zipball/33185b290310ab1fd8283fb8ed2a434cdb88b9b9", - "reference": "33185b290310ab1fd8283fb8ed2a434cdb88b9b9", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "time": "2014-07-09 09:05:48", - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.5-dev" - } - }, - "installation-source": "dist", - "autoload": { - "psr-0": { - "Symfony\\Component\\Serializer\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com", - "homepage": "http://fabien.potencier.org", - "role": "Lead Developer" - }, - { - "name": "Symfony Community", - "homepage": "http://symfony.com/contributors" - } - ], - "description": "Symfony Serializer Component", - "homepage": "http://symfony.com" - }, - { - "name": "mikey179/vfsStream", - "version": "v1.3.0", - "version_normalized": "1.3.0.0", - "source": { - "type": "git", - "url": "https://github.com/mikey179/vfsStream.git", - "reference": "8571f349567e02af1b7efc0fc4e3a4a1c98e664e" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/mikey179/vfsStream/zipball/8571f349567e02af1b7efc0fc4e3a4a1c98e664e", - "reference": "8571f349567e02af1b7efc0fc4e3a4a1c98e664e", - "shasum": "" - }, - "require": { - "php": ">=5.3.0" - }, - "require-dev": { - "phpunit/phpunit": "~4.1" - }, - "time": "2014-07-21 20:15:54", - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.3.x-dev" - } - }, - "installation-source": "dist", - "autoload": { - "psr-0": { - "org\\bovigo\\vfs\\": "src/main/php" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD" - ], - "homepage": "http://vfs.bovigo.org/" } ] diff --git a/core/vendor/guzzlehttp/guzzle/.travis.yml b/core/vendor/guzzlehttp/guzzle/.travis.yml index 1e683366eb9d..65f2d69a0fe8 100644 --- a/core/vendor/guzzlehttp/guzzle/.travis.yml +++ b/core/vendor/guzzlehttp/guzzle/.travis.yml @@ -10,7 +10,8 @@ before_script: - curl --version - pear config-set php_ini ~/.phpenv/versions/`php -r 'echo phpversion();'`/etc/php.ini || echo 'Error modifying PEAR' - pecl install uri_template || echo 'Error installing uri_template' - - composer install + - composer self-update + - composer install --no-interaction --prefer-source --dev - ~/.nvm/nvm.sh install v0.6.14 - ~/.nvm/nvm.sh run v0.6.14 diff --git a/core/vendor/guzzlehttp/guzzle/CHANGELOG.md b/core/vendor/guzzlehttp/guzzle/CHANGELOG.md index 127335c043bf..9f641cafc8d2 100644 --- a/core/vendor/guzzlehttp/guzzle/CHANGELOG.md +++ b/core/vendor/guzzlehttp/guzzle/CHANGELOG.md @@ -1,6 +1,49 @@ CHANGELOG ========= +4.1.7 (2014-08-07) +------------------ + +* Fixed an error in the HistoryPlugin that caused the same request and response + to be logged multiple times when an HTTP protocol error occurs. +* Ensuring that cURL does not add a default Content-Type when no Content-Type + has been supplied by the user. This prevents the adapter layer from modifying + the request that is sent over the wire after any listeners may have already + put the request in a desired state (e.g., signed the request). +* Throwing an exception when you attempt to send requests that have the + "stream" set to true in parallel using the MultiAdapter. +* Only calling curl_multi_select when there are active cURL handles. This was + previously changed and caused performance problems on some systems due to PHP + always selecting until the maximum select timeout. +* Fixed a bug where multipart/form-data POST fields were not correctly + aggregated (e.g., values with "&"). + +4.1.6 (2014-08-03) +------------------ + +* Added helper methods to make it easier to represent messages as strings, + including getting the start line and getting headers as a string. + +4.1.5 (2014-08-02) +------------------ + +* Automatically retrying cURL "Connection died, retrying a fresh connect" + errors when possible. +* cURL implementation cleanup +* Allowing multiple event subscriber listeners to be registered per event by + passing an array of arrays of listener configuration. + +4.1.4 (2014-07-22) +------------------ + +* Fixed a bug that caused multi-part POST requests with more than one field to + serialize incorrectly. +* Paths can now be set to "0" +* `ResponseInterface::xml` now accepts a `libxml_options` option and added a + missing default argument that was required when parsing XML response bodies. +* A `save_to` stream is now created lazily, which means that files are not + created on disk unless a request succeeds. + 4.1.3 (2014-07-15) ------------------ diff --git a/core/vendor/guzzlehttp/guzzle/composer.json b/core/vendor/guzzlehttp/guzzle/composer.json index fc37c050a381..3d2244f82f46 100644 --- a/core/vendor/guzzlehttp/guzzle/composer.json +++ b/core/vendor/guzzlehttp/guzzle/composer.json @@ -17,7 +17,7 @@ "require": { "php": ">=5.4.0", "ext-json": "*", - "guzzlehttp/streams": "~1.3" + "guzzlehttp/streams": "~1.4" }, "suggest": { @@ -43,7 +43,7 @@ "extra": { "branch-alias": { - "dev-master": "4.1.x-dev" + "dev-master": "4.1-dev" } } } diff --git a/core/vendor/guzzlehttp/guzzle/docs/clients.rst b/core/vendor/guzzlehttp/guzzle/docs/clients.rst index 9790af04f188..30e879ba9ec2 100644 --- a/core/vendor/guzzlehttp/guzzle/docs/clients.rst +++ b/core/vendor/guzzlehttp/guzzle/docs/clients.rst @@ -297,7 +297,7 @@ immeditaley and prevent subsequent requests from being sent. use GuzzleHttp\Event\ErrorEvent; $client->sendAll($requests, [ - 'error' => function (ErrorEvent $event) use (&$errors) { + 'error' => function (ErrorEvent $event) { throw $event->getException(); } ]); diff --git a/core/vendor/guzzlehttp/guzzle/docs/events.rst b/core/vendor/guzzlehttp/guzzle/docs/events.rst index bae5fa41636f..933ec6ae5f85 100644 --- a/core/vendor/guzzlehttp/guzzle/docs/events.rst +++ b/core/vendor/guzzlehttp/guzzle/docs/events.rst @@ -184,7 +184,7 @@ priority of the listener (as shown in the ``before`` listener in the example). .. code-block:: php - use GuzzleHttp\Event\EventEmitterInterface; + use GuzzleHttp\Event\EmitterInterface; use GuzzleHttp\Event\SubscriberInterface; use GuzzleHttp\Event\BeforeEvent; use GuzzleHttp\Event\CompleteEvent; @@ -194,8 +194,11 @@ priority of the listener (as shown in the ``before`` listener in the example). public function getEvents() { return [ - 'before' => ['onBefore', 100], // Provide name and optional priority - 'complete' => ['onComplete'] + // Provide name and optional priority + 'before' => ['onBefore', 100], + 'complete' => ['onComplete'], + // You can pass a list of listeners with different priorities + 'error' => [['beforeError', 'first'], ['afterError', 'last]] ]; } diff --git a/core/vendor/guzzlehttp/guzzle/docs/quickstart.rst b/core/vendor/guzzlehttp/guzzle/docs/quickstart.rst index 41f2c7bacf3b..0687ca283922 100644 --- a/core/vendor/guzzlehttp/guzzle/docs/quickstart.rst +++ b/core/vendor/guzzlehttp/guzzle/docs/quickstart.rst @@ -50,7 +50,7 @@ then you'll need to use a ``GuzzleHttp\ClientInterface`` object. use GuzzleHttp\Client; $client = new Client(); - $response = $client->get('https://github.com/timeline.json'); + $response = $client->get('http://httpbin.org/get'); // You can use the same methods you saw in the procedural API $response = $client->delete('http://httpbin.org/delete'); @@ -120,9 +120,9 @@ response. .. code-block:: php - $response = $client->get('https://github.com/timeline.json'); + $response = $client->get('http://httpbin.org/get'); $json = $response->json(); - var_dump($json[0]['repository']); + var_dump($json[0]['origin']); Guzzle internally uses PHP's ``json_decode()`` function to parse responses. If Guzzle is unable to parse the JSON response body, then a diff --git a/core/vendor/guzzlehttp/guzzle/src/Adapter/Curl/BatchContext.php b/core/vendor/guzzlehttp/guzzle/src/Adapter/Curl/BatchContext.php index 01ab767a7abb..2fccbb2a126d 100644 --- a/core/vendor/guzzlehttp/guzzle/src/Adapter/Curl/BatchContext.php +++ b/core/vendor/guzzlehttp/guzzle/src/Adapter/Curl/BatchContext.php @@ -59,6 +59,16 @@ public function findTransaction($handle) throw new AdapterException('No curl handle was found'); } + /** + * Returns true if there are any active requests. + * + * @return bool + */ + public function isActive() + { + return count($this->handles) > 0; + } + /** * Returns true if there are any remaining pending transactions * @@ -143,16 +153,15 @@ public function removeTransaction(TransactionInterface $transaction) } $handle = $this->handles[$transaction]; - + $this->handles->detach($transaction); + $info = curl_getinfo($handle); $code = curl_multi_remove_handle($this->multi, $handle); - if ($code != CURLM_OK) { + curl_close($handle); + + if ($code !== CURLM_OK) { MultiAdapter::throwMultiError($code); } - $info = curl_getinfo($handle); - curl_close($handle); - unset($this->handles[$transaction]); - return $info; } } diff --git a/core/vendor/guzzlehttp/guzzle/src/Adapter/Curl/CurlFactory.php b/core/vendor/guzzlehttp/guzzle/src/Adapter/Curl/CurlFactory.php index f1cb393a770a..86c254987b43 100644 --- a/core/vendor/guzzlehttp/guzzle/src/Adapter/Curl/CurlFactory.php +++ b/core/vendor/guzzlehttp/guzzle/src/Adapter/Curl/CurlFactory.php @@ -91,6 +91,11 @@ protected function getDefaultOptions( $this->removeHeader('Accept-Encoding', $options); } + // cURL sometimes adds a content-type by default. Prevent this. + if (!$request->hasHeader('Content-Type')) { + $options[CURLOPT_HTTPHEADER][] = 'Content-Type:'; + } + return $options; } @@ -273,6 +278,18 @@ private function add_ssl_key( $options[CURLOPT_SSLKEY] = $value; } + private function add_stream() + { + throw new AdapterException('cURL adapters do not support the "stream"' + . ' request option. This error is typically encountered when trying' + . ' to send requests with the "stream" option set to true in ' + . ' parallel. You will either need to send these one at a time or' + . ' implement a custom ParallelAdapterInterface that supports' + . ' sending these types of requests in parallel. This error can' + . ' also occur if the StreamAdapter is not available on your' + . ' system (e.g., allow_url_fopen is disabled in your php.ini).'); + } + private function add_save_to( RequestInterface $request, RequestMediator $mediator, @@ -280,7 +297,7 @@ private function add_save_to( $value ) { $mediator->setResponseBody(is_string($value) - ? Stream\create(fopen($value, 'w')) + ? new Stream\LazyOpenStream($value, 'w') : Stream\create($value)); } diff --git a/core/vendor/guzzlehttp/guzzle/src/Adapter/Curl/MultiAdapter.php b/core/vendor/guzzlehttp/guzzle/src/Adapter/Curl/MultiAdapter.php index 306459569c80..9b2da4db2ddd 100644 --- a/core/vendor/guzzlehttp/guzzle/src/Adapter/Curl/MultiAdapter.php +++ b/core/vendor/guzzlehttp/guzzle/src/Adapter/Curl/MultiAdapter.php @@ -128,20 +128,25 @@ private function perform(BatchContext $context) $multi = $context->getMultiHandle(); do { - while (($mrc = curl_multi_exec($multi, $active)) == CURLM_CALL_MULTI_PERFORM); - if ($mrc != CURLM_OK && $mrc != CURLM_CALL_MULTI_PERFORM) { + do { + $mrc = curl_multi_exec($multi, $active); + } while ($mrc === CURLM_CALL_MULTI_PERFORM); + + if ($mrc != CURLM_OK) { self::throwMultiError($mrc); } - // Need to check if there are pending transactions before processing - // them so that we don't bail from the loop too early. - $pending = $context->hasPending(); + $this->processMessages($context); - if ($active && curl_multi_select($multi, $this->selectTimeout) === -1) { + + if ($active && + curl_multi_select($multi, $this->selectTimeout) === -1 + ) { // Perform a usleep if a select returns -1. // See: https://bugs.php.net/bug.php?id=61141 usleep(250); } - } while ($active || $pending); + + } while ($context->isActive() || $active); $this->releaseMultiHandle($multi); } @@ -168,7 +173,9 @@ private function processResponse( $info = $context->removeTransaction($transaction); try { - if (!$this->isCurlException($transaction, $curl, $context, $info)) { + if (!$this->isCurlException($transaction, $curl, $context, $info) && + $this->validateResponseWasSet($transaction, $context) + ) { RequestEvents::emitComplete($transaction, $info); } } catch (RequestException $e) { @@ -281,4 +288,75 @@ private function releaseMultiHandle($handle) unset($this->multiHandles[$id], $this->multiOwned[$id]); } } + + /** + * This function ensures that a response was set on a transaction. If one + * was not set, then the request is retried if possible. This error + * typically means you are sending a payload, curl encountered a + * "Connection died, retrying a fresh connect" error, tried to rewind the + * stream, and then encountered a "necessary data rewind wasn't possible" + * error, causing the request to be sent through curl_multi_info_read() + * without an error status. + * + * @param TransactionInterface $transaction + * @param BatchContext $context + * + * @return bool Returns true if it's OK, and false if it failed. + * @throws \GuzzleHttp\Exception\RequestException If it failed and cannot + * recover. + */ + private function validateResponseWasSet( + TransactionInterface $transaction, + BatchContext $context + ) { + if ($transaction->getResponse()) { + return true; + } + + $body = $transaction->getRequest()->getBody(); + + if (!$body) { + // This is weird and should probably never happen. + RequestEvents::emitError( + $transaction, + new RequestException( + 'No response was received for a request with no body. This' + . ' could mean that you are saturating your network.', + $transaction->getRequest() + ) + ); + } elseif (!$body->isSeekable() || !$body->seek(0)) { + // Nothing we can do with this. Sorry! + RequestEvents::emitError( + $transaction, + new RequestException( + 'The connection was unexpectedly closed. The request would' + . ' have been retried, but attempting to rewind the' + . ' request body failed. Consider wrapping your request' + . ' body in a CachingStream decorator to work around this' + . ' issue if necessary.', + $transaction->getRequest() + ) + ); + } else { + $this->retryFailedConnection($transaction, $context); + } + + return false; + } + + private function retryFailedConnection( + TransactionInterface $transaction, + BatchContext $context + ) { + // Add the request back to the batch to retry automatically. + $context->addTransaction( + $transaction, + call_user_func( + $this->curlFactory, + $transaction, + $this->messageFactory + ) + ); + } } diff --git a/core/vendor/guzzlehttp/guzzle/src/Adapter/StreamAdapter.php b/core/vendor/guzzlehttp/guzzle/src/Adapter/StreamAdapter.php index 79aa0b99ac78..4cf434ad4e59 100644 --- a/core/vendor/guzzlehttp/guzzle/src/Adapter/StreamAdapter.php +++ b/core/vendor/guzzlehttp/guzzle/src/Adapter/StreamAdapter.php @@ -72,7 +72,7 @@ private function getSaveToBody(RequestInterface $request, $stream) if ($saveTo = $request->getConfig()['save_to']) { // Stream the response into the destination stream $saveTo = is_string($saveTo) - ? Stream\create(fopen($saveTo, 'r+')) + ? new Stream\LazyOpenStream($saveTo, 'r+') : Stream\create($saveTo); } else { // Stream into the default temp stream @@ -151,7 +151,7 @@ private function createResource(callable $callback, RequestInterface $request, $ if (isset($options['http']['proxy'])) { $message .= "[proxy] {$options['http']['proxy']} "; } - foreach (error_get_last() as $key => $value) { + foreach ((array) error_get_last() as $key => $value) { $message .= "[{$key}] {$value} "; } throw new RequestException(trim($message), $request); @@ -316,13 +316,13 @@ private function createStreamContext( array $options, array $params ) { - return $this->createResource(function () use ( + return $this->createResource( + function () use ($request, $options, $params) { + return stream_context_create($options, $params); + }, $request, - $options, - $params - ) { - return stream_context_create($options, $params); - }, $request, $options); + $options + ); } private function createStreamResource( @@ -337,16 +337,16 @@ private function createStreamResource( $url = 'compress.zlib://' . $url; } - return $this->createResource(function () use ( - $url, - &$http_response_header, - $context - ) { - if (false === strpos($url, 'http')) { - trigger_error("URL is invalid: {$url}", E_USER_WARNING); - return null; - } - return fopen($url, 'r', null, $context); - }, $request, $options); + return $this->createResource( + function () use ($url, &$http_response_header, $context) { + if (false === strpos($url, 'http')) { + trigger_error("URL is invalid: {$url}", E_USER_WARNING); + return null; + } + return fopen($url, 'r', null, $context); + }, + $request, + $options + ); } } diff --git a/core/vendor/guzzlehttp/guzzle/src/ClientInterface.php b/core/vendor/guzzlehttp/guzzle/src/ClientInterface.php index a10d67f175c4..9923d63ec604 100644 --- a/core/vendor/guzzlehttp/guzzle/src/ClientInterface.php +++ b/core/vendor/guzzlehttp/guzzle/src/ClientInterface.php @@ -13,7 +13,7 @@ */ interface ClientInterface extends HasEmitterInterface { - const VERSION = '4.1.3'; + const VERSION = '4.1.7'; /** * Create and return a new {@see RequestInterface} object. diff --git a/core/vendor/guzzlehttp/guzzle/src/Event/Emitter.php b/core/vendor/guzzlehttp/guzzle/src/Event/Emitter.php index 49172bcb50ba..71e88d162a31 100644 --- a/core/vendor/guzzlehttp/guzzle/src/Event/Emitter.php +++ b/core/vendor/guzzlehttp/guzzle/src/Event/Emitter.php @@ -114,12 +114,22 @@ public function emit($eventName, EventInterface $event) public function attach(SubscriberInterface $subscriber) { - foreach ($subscriber->getEvents() as $eventName => $listener) { - $this->on( - $eventName, - array($subscriber, $listener[0]), - isset($listener[1]) ? $listener[1] : 0 - ); + foreach ($subscriber->getEvents() as $eventName => $listeners) { + if (is_array($listeners[0])) { + foreach ($listeners as $listener) { + $this->on( + $eventName, + [$subscriber, $listener[0]], + isset($listener[1]) ? $listener[1] : 0 + ); + } + } else { + $this->on( + $eventName, + [$subscriber, $listeners[0]], + isset($listeners[1]) ? $listeners[1] : 0 + ); + } } } diff --git a/core/vendor/guzzlehttp/guzzle/src/Event/SubscriberInterface.php b/core/vendor/guzzlehttp/guzzle/src/Event/SubscriberInterface.php index 22c7311900f8..223c23a00798 100644 --- a/core/vendor/guzzlehttp/guzzle/src/Event/SubscriberInterface.php +++ b/core/vendor/guzzlehttp/guzzle/src/Event/SubscriberInterface.php @@ -17,13 +17,17 @@ interface SubscriberInterface * * The returned array keys MUST map to an event name. Each array value * MUST be an array in which the first element is the name of a function - * on the EventSubscriber. The second element in the array is optional, and - * if specified, designates the event priority. + * on the EventSubscriber OR an array of arrays in the aforementioned + * format. The second element in the array is optional, and if specified, + * designates the event priority. * - * For example: + * For example, the following are all valid: * * - ['eventName' => ['methodName']] * - ['eventName' => ['methodName', $priority]] + * - ['eventName' => [['methodName'], ['otherMethod']] + * - ['eventName' => [['methodName'], ['otherMethod', $priority]] + * - ['eventName' => [['methodName', $priority], ['otherMethod', $priority]] * * @return array */ diff --git a/core/vendor/guzzlehttp/guzzle/src/Message/AbstractMessage.php b/core/vendor/guzzlehttp/guzzle/src/Message/AbstractMessage.php index 6037a70e6a28..52e306f32062 100644 --- a/core/vendor/guzzlehttp/guzzle/src/Message/AbstractMessage.php +++ b/core/vendor/guzzlehttp/guzzle/src/Message/AbstractMessage.php @@ -1,5 +1,4 @@ <?php - namespace GuzzleHttp\Message; use GuzzleHttp\Stream\StreamInterface; @@ -20,12 +19,8 @@ abstract class AbstractMessage implements MessageInterface public function __toString() { - $result = $this->getStartLine(); - foreach ($this->getHeaders() as $name => $values) { - $result .= "\r\n{$name}: " . implode(', ', $values); - } - - return $result . "\r\n\r\n" . $this->body; + return static::getStartLineAndHeaders($this) + . "\r\n\r\n" . $this->getBody(); } public function getProtocolVersion() @@ -214,11 +209,57 @@ public static function normalizeHeader(MessageInterface $message, $header) } /** - * Returns the start line of a message. + * Gets the start-line and headers of a message as a string + * + * @param MessageInterface $message + * + * @return string + */ + public static function getStartLineAndHeaders(MessageInterface $message) + { + return static::getStartLine($message) + . self::getHeadersAsString($message); + } + + /** + * Gets the headers of a message as a string + * + * @param MessageInterface $message + * + * @return string + */ + public static function getHeadersAsString(MessageInterface $message) + { + $result = ''; + foreach ($message->getHeaders() as $name => $values) { + $result .= "\r\n{$name}: " . implode(', ', $values); + } + + return $result; + } + + /** + * Gets the start line of a message + * + * @param MessageInterface $message * * @return string + * @throws \InvalidArgumentException */ - abstract protected function getStartLine(); + public static function getStartLine(MessageInterface $message) + { + if ($message instanceof RequestInterface) { + return trim($message->getMethod() . ' ' + . $message->getResource()) + . ' HTTP/' . $message->getProtocolVersion(); + } elseif ($message instanceof ResponseInterface) { + return 'HTTP/' . $message->getProtocolVersion() . ' ' + . $message->getStatusCode() . ' ' + . $message->getReasonPhrase(); + } else { + throw new \InvalidArgumentException('Unknown message type'); + } + } /** * Accepts and modifies the options provided to the message in the diff --git a/core/vendor/guzzlehttp/guzzle/src/Message/Request.php b/core/vendor/guzzlehttp/guzzle/src/Message/Request.php index 5c0e0aefbd5e..efc54503278a 100644 --- a/core/vendor/guzzlehttp/guzzle/src/Message/Request.php +++ b/core/vendor/guzzlehttp/guzzle/src/Message/Request.php @@ -1,5 +1,4 @@ <?php - namespace GuzzleHttp\Message; use GuzzleHttp\Event\HasEmitterTrait; @@ -179,12 +178,6 @@ protected function handleOptions(array &$options) } } - protected function getStartLine() - { - return trim($this->method . ' ' . $this->getResource()) - . ' HTTP/' . $this->getProtocolVersion(); - } - /** * Adds a subscriber that ensures a request's body is prepared before * sending. diff --git a/core/vendor/guzzlehttp/guzzle/src/Message/Response.php b/core/vendor/guzzlehttp/guzzle/src/Message/Response.php index 900196314dac..1c48aab875d5 100644 --- a/core/vendor/guzzlehttp/guzzle/src/Message/Response.php +++ b/core/vendor/guzzlehttp/guzzle/src/Message/Response.php @@ -150,7 +150,8 @@ public function xml(array $config = []) // Allow XML to be retrieved even if there is no response body $xml = new \SimpleXMLElement( (string) $this->getBody() ?: '<root />', - LIBXML_NONET, + isset($config['libxml_options']) ? $config['libxml_options'] : LIBXML_NONET, + false, isset($config['ns']) ? $config['ns'] : '', isset($config['ns_is_prefix']) ? $config['ns_is_prefix'] : false ); @@ -193,10 +194,4 @@ protected function handleOptions(array &$options = []) $this->reasonPhrase = $options['reason_phrase']; } } - - protected function getStartLine() - { - return 'HTTP/' . $this->getProtocolVersion() - . " {$this->statusCode} {$this->reasonPhrase}"; - } } diff --git a/core/vendor/guzzlehttp/guzzle/src/Message/ResponseInterface.php b/core/vendor/guzzlehttp/guzzle/src/Message/ResponseInterface.php index db8252c6b75f..55f48e7479bf 100644 --- a/core/vendor/guzzlehttp/guzzle/src/Message/ResponseInterface.php +++ b/core/vendor/guzzlehttp/guzzle/src/Message/ResponseInterface.php @@ -77,6 +77,9 @@ public function json(array $config = []); * - ns: Set to a string to represent the namespace prefix or URI * - ns_is_prefix: Set to true to specify that the NS is a prefix rather * than a URI (defaults to false). + * - libxml_options: Bitwise OR of the libxml option constants + * listed at http://php.net/manual/en/libxml.constants.php + * (defaults to LIBXML_NONET) * * @return \SimpleXMLElement * @throws \RuntimeException if the response body is not in XML format diff --git a/core/vendor/guzzlehttp/guzzle/src/Post/MultipartBody.php b/core/vendor/guzzlehttp/guzzle/src/Post/MultipartBody.php index 7ffead9d6871..85ea030697db 100644 --- a/core/vendor/guzzlehttp/guzzle/src/Post/MultipartBody.php +++ b/core/vendor/guzzlehttp/guzzle/src/Post/MultipartBody.php @@ -9,13 +9,13 @@ */ class MultipartBody implements Stream\StreamInterface { - /** @var Stream\StreamInterface */ - private $stream; + use Stream\StreamDecoratorTrait; + private $boundary; /** * @param array $fields Associative array of field names to values where - * each value is a string. + * each value is a string or array of strings. * @param array $files Associative array of PostFileInterface objects * @param string $boundary You can optionally provide a specific boundary * @throws \InvalidArgumentException @@ -26,17 +26,7 @@ public function __construct( $boundary = null ) { $this->boundary = $boundary ?: uniqid(); - $this->createStream($fields, $files); - } - - public function __toString() - { - return (string) $this->stream; - } - - public function getContents($maxLength = -1) - { - return $this->stream->getContents($maxLength); + $this->stream = $this->createStream($fields, $files); } /** @@ -49,63 +39,11 @@ public function getBoundary() return $this->boundary; } - public function close() - { - $this->stream->close(); - $this->detach(); - } - - public function detach() - { - $this->stream->detach(); - $this->size = 0; - } - - public function eof() - { - return $this->stream->eof(); - } - - public function tell() - { - return $this->stream->tell(); - } - - public function isReadable() - { - return true; - } - public function isWritable() { return false; } - public function isSeekable() - { - return $this->stream->isSeekable(); - } - - public function getSize() - { - return $this->stream->getSize(); - } - - public function read($length) - { - return $this->stream->read($length); - } - - public function seek($offset, $whence = SEEK_SET) - { - return $this->stream->seek($offset, $whence); - } - - public function write($string) - { - return false; - } - /** * Get the string needed to transfer a POST field */ @@ -137,12 +75,14 @@ private function getFileHeaders(PostFileInterface $file) */ private function createStream(array $fields, array $files) { - $this->stream = new Stream\AppendStream(); + $stream = new Stream\AppendStream(); - foreach ($fields as $name => $field) { - $this->stream->addStream( - Stream\create($this->getFieldString($name, $field)) - ); + foreach ($fields as $name => $fieldValues) { + foreach ((array) $fieldValues as $value) { + $stream->addStream( + Stream\create($this->getFieldString($name, $value)) + ); + } } foreach ($files as $file) { @@ -152,14 +92,16 @@ private function createStream(array $fields, array $files) . 'implement PostFieldInterface'); } - $this->stream->addStream( + $stream->addStream( Stream\create($this->getFileHeaders($file)) ); - $this->stream->addStream($file->getContent()); - $this->stream->addStream(Stream\create("\r\n")); + $stream->addStream($file->getContent()); + $stream->addStream(Stream\create("\r\n")); } // Add the trailing boundary - $this->stream->addStream(Stream\create("--{$this->boundary}--")); + $stream->addStream(Stream\create("--{$this->boundary}--")); + + return $stream; } } diff --git a/core/vendor/guzzlehttp/guzzle/src/Post/PostBody.php b/core/vendor/guzzlehttp/guzzle/src/Post/PostBody.php index 78ed9e041f81..e404b0460d02 100644 --- a/core/vendor/guzzlehttp/guzzle/src/Post/PostBody.php +++ b/core/vendor/guzzlehttp/guzzle/src/Post/PostBody.php @@ -1,5 +1,4 @@ <?php - namespace GuzzleHttp\Post; use GuzzleHttp\Message\RequestInterface; @@ -253,22 +252,10 @@ final protected function getAggregator() private function createMultipart() { // Flatten the nested query string values using the correct aggregator - if (!$this->fields) { - $fields = []; - } else { - $query = (string) (new Query($this->fields)) - ->setEncodingType(false) - ->setAggregator($this->getAggregator()); - - // Convert the flattened query string back into an array - $fields = []; - foreach (explode('&', $query, 2) as $kvp) { - $parts = explode('=', $kvp, 2); - $fields[$parts[0]] = isset($parts[1]) ? $parts[1] : null; - } - } - - return new MultipartBody($fields, $this->files); + return new MultipartBody( + call_user_func($this->getAggregator(), $this->fields), + $this->files + ); } /** diff --git a/core/vendor/guzzlehttp/guzzle/src/Subscriber/History.php b/core/vendor/guzzlehttp/guzzle/src/Subscriber/History.php index b2a49e044536..6ffbbb8db922 100644 --- a/core/vendor/guzzlehttp/guzzle/src/Subscriber/History.php +++ b/core/vendor/guzzlehttp/guzzle/src/Subscriber/History.php @@ -56,7 +56,11 @@ public function onComplete(CompleteEvent $event) public function onError(ErrorEvent $event) { - $this->add($event->getRequest(), $event->getResponse()); + // Only track when no response is present, meaning this didn't ever + // emit a complete event + if (!$event->getResponse()) { + $this->add($event->getRequest()); + } } /** diff --git a/core/vendor/guzzlehttp/guzzle/src/Url.php b/core/vendor/guzzlehttp/guzzle/src/Url.php index 23b765e7e22f..fcd72eb30835 100644 --- a/core/vendor/guzzlehttp/guzzle/src/Url.php +++ b/core/vendor/guzzlehttp/guzzle/src/Url.php @@ -555,7 +555,7 @@ public function combine($url) ); } - if (!$parts['path']) { + if (!$parts['path'] && $parts['path'] !== '0') { // The relative URL has no path, so check if it is just a query $path = $this->path ?: ''; $query = count($parts['query']) ? $parts['query'] : $this->query; diff --git a/core/vendor/guzzlehttp/guzzle/tests/Adapter/Curl/BatchContextTest.php b/core/vendor/guzzlehttp/guzzle/tests/Adapter/Curl/BatchContextTest.php index a3c82f2c553c..56266bac145b 100644 --- a/core/vendor/guzzlehttp/guzzle/tests/Adapter/Curl/BatchContextTest.php +++ b/core/vendor/guzzlehttp/guzzle/tests/Adapter/Curl/BatchContextTest.php @@ -51,8 +51,10 @@ public function testManagesHandles() new Request('GET', 'http://httbin.org') ); $b->addTransaction($t, $h); + $this->assertTrue($b->isActive()); $this->assertSame($t, $b->findTransaction($h)); $b->removeTransaction($t); + $this->assertFalse($b->isActive()); try { $this->assertEquals([], $b->findTransaction($h)); $this->fail('Did not throw'); diff --git a/core/vendor/guzzlehttp/guzzle/tests/Adapter/Curl/CurlAdapterTest.php b/core/vendor/guzzlehttp/guzzle/tests/Adapter/Curl/CurlAdapterTest.php index dd6389a58ffa..dbbdeed8d897 100644 --- a/core/vendor/guzzlehttp/guzzle/tests/Adapter/Curl/CurlAdapterTest.php +++ b/core/vendor/guzzlehttp/guzzle/tests/Adapter/Curl/CurlAdapterTest.php @@ -9,6 +9,7 @@ use GuzzleHttp\Client; use GuzzleHttp\Event\ErrorEvent; use GuzzleHttp\Event\HeadersEvent; +use GuzzleHttp\Exception\ServerException; use GuzzleHttp\Message\MessageFactory; use GuzzleHttp\Message\Request; use GuzzleHttp\Event\BeforeEvent; @@ -117,4 +118,22 @@ public function testReleasesAdditionalEasyHandles() $a->send($transaction); $this->assertCount(2, $this->readAttribute($a, 'handles')); } + + public function testDoesNotSaveToWhenFailed() + { + Server::flush(); + Server::enqueue([ + "HTTP/1.1 500 Internal Server Error\r\nContent-Length: 0\r\n\r\n" + ]); + + $tmp = tempnam('/tmp', 'test_save_to'); + unlink($tmp); + $a = new CurlAdapter(new MessageFactory()); + $client = new Client(['base_url' => Server::$url, 'adapter' => $a]); + try { + $client->get('/', ['save_to' => $tmp]); + } catch (ServerException $e) { + $this->assertFileNotExists($tmp); + } + } } diff --git a/core/vendor/guzzlehttp/guzzle/tests/Adapter/Curl/CurlFactoryTest.php b/core/vendor/guzzlehttp/guzzle/tests/Adapter/Curl/CurlFactoryTest.php index 23b76e6e41a7..d62283b00766 100644 --- a/core/vendor/guzzlehttp/guzzle/tests/Adapter/Curl/CurlFactoryTest.php +++ b/core/vendor/guzzlehttp/guzzle/tests/Adapter/Curl/CurlFactoryTest.php @@ -14,6 +14,7 @@ function curl_setopt_array($handle, array $options) use GuzzleHttp\Adapter\Curl\MultiAdapter; use GuzzleHttp\Event\BeforeEvent; + use GuzzleHttp\Exception\ServerException; use GuzzleHttp\Message\RequestInterface; use GuzzleHttp\Stream\Stream; use GuzzleHttp\Adapter\Curl\CurlFactory; @@ -308,5 +309,27 @@ private function emit(RequestInterface $request) $event = new BeforeEvent(new Transaction(new Client(), $request)); $request->getEmitter()->emit('before', $event); } + + public function testDoesNotAlwaysAddContentType() + { + Server::flush(); + Server::enqueue(["HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"]); + $client = new Client(); + $client->put(Server::$url . '/foo', ['body' => 'foo']); + $request = Server::received(true)[0]; + $this->assertEquals('', $request->getHeader('Content-Type')); + } + + /** + * @expectedException \GuzzleHttp\Exception\AdapterException + */ + public function testThrowsForStreamOption() + { + $request = new Request('GET', Server::$url . 'haha'); + $request->getConfig()->set('stream', true); + $t = new Transaction(new Client(), $request); + $f = new CurlFactory(); + $f($t, new MessageFactory()); + } } } diff --git a/core/vendor/guzzlehttp/guzzle/tests/Adapter/Curl/MultiAdapterTest.php b/core/vendor/guzzlehttp/guzzle/tests/Adapter/Curl/MultiAdapterTest.php index 7477b53b9a92..f6175ae41247 100644 --- a/core/vendor/guzzlehttp/guzzle/tests/Adapter/Curl/MultiAdapterTest.php +++ b/core/vendor/guzzlehttp/guzzle/tests/Adapter/Curl/MultiAdapterTest.php @@ -12,6 +12,9 @@ use GuzzleHttp\Exception\RequestException; use GuzzleHttp\Message\MessageFactory; use GuzzleHttp\Message\Request; +use GuzzleHttp\Message\Response; +use GuzzleHttp\Stream\NoSeekStream; +use GuzzleHttp\Stream\Stream; use GuzzleHttp\Tests\Server; /** @@ -193,4 +196,127 @@ public function testThrowsAndReleasesWhenErrorDuringCompleteEvent() $this->assertSame($request, $e->getRequest()); } } + + public function testEnsuresResponseWasSetForGet() + { + $client = new Client(); + $request = $client->createRequest('GET', Server::$url); + $response = new Response(200, []); + $er = null; + + $request->getEmitter()->on( + 'error', + function (ErrorEvent $e) use (&$er, $response) { + $er = $e; + } + ); + + $transaction = $this->getMockBuilder('GuzzleHttp\Adapter\Transaction') + ->setMethods(['getResponse', 'setResponse']) + ->setConstructorArgs([$client, $request]) + ->getMock(); + $transaction->expects($this->any())->method('setResponse'); + $transaction->expects($this->any()) + ->method('getResponse') + ->will($this->returnCallback(function () use ($response) { + $caller = debug_backtrace()[6]['function']; + return $caller == 'addHandle' || + $caller == 'validateResponseWasSet' + ? null + : $response; + })); + + $a = new MultiAdapter(new MessageFactory()); + Server::flush(); + Server::enqueue(["HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"]); + $a->sendAll(new \ArrayIterator([$transaction]), 10); + $this->assertNotNull($er); + + $this->assertContains( + 'No response was received', + $er->getException()->getMessage() + ); + } + + private function runConnectionTest( + $queue, + $stream, + $msg, + $statusCode = null + ) { + $obj = new \stdClass(); + $er = null; + $client = new Client(); + $request = $client->createRequest('PUT', Server::$url, [ + 'body' => $stream + ]); + + $request->getEmitter()->on( + 'error', + function (ErrorEvent $e) use (&$er) { + $er = $e; + } + ); + + $transaction = $this->getMockBuilder('GuzzleHttp\Adapter\Transaction') + ->setMethods(['getResponse', 'setResponse']) + ->setConstructorArgs([$client, $request]) + ->getMock(); + + $transaction->expects($this->any()) + ->method('setResponse') + ->will($this->returnCallback(function ($r) use (&$obj) { + $obj->res = $r; + })); + + $transaction->expects($this->any()) + ->method('getResponse') + ->will($this->returnCallback(function () use ($obj, &$called) { + $caller = debug_backtrace()[6]['function']; + if ($caller == 'addHandle') { + return null; + } elseif ($caller == 'validateResponseWasSet') { + return ++$called == 2 ? $obj->res : null; + } else { + return $obj->res; + } + })); + + $a = new MultiAdapter(new MessageFactory()); + Server::flush(); + Server::enqueue($queue); + $a->sendAll(new \ArrayIterator([$transaction]), 10); + + if ($msg) { + $this->assertNotNull($er); + $this->assertContains($msg, $er->getException()->getMessage()); + } else { + $this->assertEquals( + $statusCode, + $transaction->getResponse()->getStatusCode() + ); + } + } + + public function testThrowsWhenTheBodyCannotBeRewound() + { + $this->runConnectionTest( + ["HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"], + new NoSeekStream(Stream::factory('foo')), + 'attempting to rewind the request body failed' + ); + } + + public function testRetriesRewindableStreamsWhenClosedConnectionErrors() + { + $this->runConnectionTest( + [ + "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n", + "HTTP/1.1 201 OK\r\nContent-Length: 0\r\n\r\n", + ], + Stream::factory('foo'), + false, + 201 + ); + } } diff --git a/core/vendor/guzzlehttp/guzzle/tests/Event/EmitterTest.php b/core/vendor/guzzlehttp/guzzle/tests/Event/EmitterTest.php index 431b60b1eb6f..6c9ea61040e8 100644 --- a/core/vendor/guzzlehttp/guzzle/tests/Event/EmitterTest.php +++ b/core/vendor/guzzlehttp/guzzle/tests/Event/EmitterTest.php @@ -168,6 +168,15 @@ public function testAddSubscriber() $this->assertNotEmpty($this->emitter->listeners(self::postFoo)); } + public function testAddSubscriberWithMultiple() + { + $eventSubscriber = new TestEventSubscriberWithMultiple(); + $this->emitter->attach($eventSubscriber); + $listeners = $this->emitter->listeners('pre.foo'); + $this->assertNotEmpty($this->emitter->listeners(self::preFoo)); + $this->assertCount(2, $listeners); + } + public function testAddSubscriberWithPriorities() { $eventSubscriber = new TestEventSubscriber(); @@ -343,3 +352,11 @@ public function getEvents() ]; } } + +class TestEventSubscriberWithMultiple extends TestEventListener implements SubscriberInterface +{ + public function getEvents() + { + return ['pre.foo' => [['preFoo', 10],['preFoo', 20]]]; + } +} diff --git a/core/vendor/guzzlehttp/guzzle/tests/Exception/RequestExceptionTest.php b/core/vendor/guzzlehttp/guzzle/tests/Exception/RequestExceptionTest.php index 680e5026167c..c50816c8c460 100644 --- a/core/vendor/guzzlehttp/guzzle/tests/Exception/RequestExceptionTest.php +++ b/core/vendor/guzzlehttp/guzzle/tests/Exception/RequestExceptionTest.php @@ -76,7 +76,7 @@ public function testCannotSetEmittedErrorToFalse() $e->emittedError(true); $e->emittedError(false); } - + public function testHasStatusCodeAsExceptionCode() { $e = RequestException::create(new Request('GET', '/'), new Response(442)); $this->assertEquals(442, $e->getCode()); diff --git a/core/vendor/guzzlehttp/guzzle/tests/Message/AbstractMessageTest.php b/core/vendor/guzzlehttp/guzzle/tests/Message/AbstractMessageTest.php index 9ed91ee9a5fb..fd037ce7bd31 100644 --- a/core/vendor/guzzlehttp/guzzle/tests/Message/AbstractMessageTest.php +++ b/core/vendor/guzzlehttp/guzzle/tests/Message/AbstractMessageTest.php @@ -1,9 +1,9 @@ <?php - namespace GuzzleHttp\Tests\Message; use GuzzleHttp\Message\AbstractMessage; use GuzzleHttp\Message\Request; +use GuzzleHttp\Message\Response; use GuzzleHttp\Stream\Stream; /** @@ -13,13 +13,13 @@ class AbstractMessageTest extends \PHPUnit_Framework_TestCase { public function testHasProtocolVersion() { - $m = new Message(); + $m = new Request('GET', '/'); $this->assertEquals(1.1, $m->getProtocolVersion()); } public function testHasHeaders() { - $m = new Message(); + $m = new Request('GET', 'http://foo.com'); $this->assertFalse($m->hasHeader('foo')); $m->addHeader('foo', 'bar'); $this->assertTrue($m->hasHeader('foo')); @@ -35,7 +35,7 @@ public function testInitializesMessageWithProtocolVersionOption() public function testHasBody() { - $m = new Message(); + $m = new Request('GET', 'http://foo.com'); $this->assertNull($m->getBody()); $s = Stream::factory('test'); $m->setBody($s); @@ -45,7 +45,7 @@ public function testHasBody() public function testCanRemoveBodyBySettingToNullAndRemovesCommonBodyHeaders() { - $m = new Message(); + $m = new Request('GET', 'http://foo.com'); $m->setBody(Stream::factory('foo')); $m->setHeader('Content-Length', 3)->setHeader('Transfer-Encoding', 'chunked'); $m->setBody(null); @@ -56,10 +56,10 @@ public function testCanRemoveBodyBySettingToNullAndRemovesCommonBodyHeaders() public function testCastsToString() { - $m = new Message(); + $m = new Request('GET', 'http://foo.com'); $m->setHeader('foo', 'bar'); $m->setBody(Stream::factory('baz')); - $this->assertEquals("Foo!\r\nfoo: bar\r\n\r\nbaz", (string) $m); + $this->assertEquals("GET / HTTP/1.1\r\nHost: foo.com\r\nfoo: bar\r\n\r\nbaz", (string) $m); } public function parseParamsProvider() @@ -115,12 +115,12 @@ public function parseParamsProvider() public function testParseParams($header, $result) { $request = new Request('GET', '/', ['foo' => $header]); - $this->assertEquals($result, Message::parseHeader($request, 'foo')); + $this->assertEquals($result, Request::parseHeader($request, 'foo')); } public function testAddsHeadersWhenNotPresent() { - $h = new Message(); + $h = new Request('GET', 'http://foo.com'); $h->addHeader('foo', 'bar'); $this->assertInternalType('string', $h->getHeader('foo')); $this->assertEquals('bar', $h->getHeader('foo')); @@ -128,7 +128,7 @@ public function testAddsHeadersWhenNotPresent() public function testAddsHeadersWhenPresentSameCase() { - $h = new Message(); + $h = new Request('GET', 'http://foo.com'); $h->addHeader('foo', 'bar')->addHeader('foo', 'baz'); $this->assertEquals('bar, baz', $h->getHeader('foo')); $this->assertEquals(['bar', 'baz'], $h->getHeader('foo', true)); @@ -136,27 +136,28 @@ public function testAddsHeadersWhenPresentSameCase() public function testAddsMultipleHeaders() { - $h = new Message(); + $h = new Request('GET', 'http://foo.com'); $h->addHeaders([ 'foo' => ' bar', 'baz' => [' bam ', 'boo'] ]); $this->assertEquals([ 'foo' => ['bar'], - 'baz' => ['bam', 'boo'] + 'baz' => ['bam', 'boo'], + 'Host' => ['foo.com'] ], $h->getHeaders()); } public function testAddsHeadersWhenPresentDifferentCase() { - $h = new Message(); + $h = new Request('GET', 'http://foo.com'); $h->addHeader('Foo', 'bar')->addHeader('fOO', 'baz'); $this->assertEquals('bar, baz', $h->getHeader('foo')); } public function testAddsHeadersWithArray() { - $h = new Message(); + $h = new Request('GET', 'http://foo.com'); $h->addHeader('Foo', ['bar', 'baz']); $this->assertEquals('bar, baz', $h->getHeader('foo')); } @@ -166,12 +167,12 @@ public function testAddsHeadersWithArray() */ public function testThrowsExceptionWhenInvalidValueProvidedToAddHeader() { - (new Message())->addHeader('foo', false); + (new Request('GET', 'http://foo.com'))->addHeader('foo', false); } public function testGetHeadersReturnsAnArrayOfOverTheWireHeaderValues() { - $h = new Message(); + $h = new Request('GET', 'http://foo.com'); $h->addHeader('foo', 'bar'); $h->addHeader('Foo', 'baz'); $h->addHeader('boO', 'test'); @@ -186,7 +187,7 @@ public function testGetHeadersReturnsAnArrayOfOverTheWireHeaderValues() public function testSetHeaderOverwritesExistingValues() { - $h = new Message(); + $h = new Request('GET', 'http://foo.com'); $h->setHeader('foo', 'bar'); $this->assertEquals('bar', $h->getHeader('foo')); $h->setHeader('Foo', 'baz'); @@ -196,14 +197,14 @@ public function testSetHeaderOverwritesExistingValues() public function testSetHeaderOverwritesExistingValuesUsingHeaderArray() { - $h = new Message(); + $h = new Request('GET', 'http://foo.com'); $h->setHeader('foo', ['bar']); $this->assertEquals('bar', $h->getHeader('foo')); } public function testSetHeaderOverwritesExistingValuesUsingArray() { - $h = new Message(); + $h = new Request('GET', 'http://foo.com'); $h->setHeader('foo', ['bar']); $this->assertEquals('bar', $h->getHeader('foo')); } @@ -213,12 +214,12 @@ public function testSetHeaderOverwritesExistingValuesUsingArray() */ public function testThrowsExceptionWhenInvalidValueProvidedToSetHeader() { - (new Message())->setHeader('foo', false); + (new Request('GET', 'http://foo.com'))->setHeader('foo', false); } public function testSetHeadersOverwritesAllHeaders() { - $h = new Message(); + $h = new Request('GET', 'http://foo.com'); $h->setHeader('foo', 'bar'); $h->setHeaders(['foo' => 'a', 'boo' => 'b']); $this->assertEquals(['foo' => ['a'], 'boo' => ['b']], $h->getHeaders()); @@ -226,7 +227,7 @@ public function testSetHeadersOverwritesAllHeaders() public function testChecksIfCaseInsensitiveHeaderIsPresent() { - $h = new Message(); + $h = new Request('GET', 'http://foo.com'); $h->setHeader('foo', 'bar'); $this->assertTrue($h->hasHeader('foo')); $this->assertTrue($h->hasHeader('Foo')); @@ -236,7 +237,7 @@ public function testChecksIfCaseInsensitiveHeaderIsPresent() public function testRemovesHeaders() { - $h = new Message(); + $h = new Request('GET', 'http://foo.com'); $h->setHeader('foo', 'bar'); $h->removeHeader('foo'); $this->assertFalse($h->hasHeader('foo')); @@ -247,14 +248,14 @@ public function testRemovesHeaders() public function testReturnsCorrectTypeWhenMissing() { - $h = new Message(); + $h = new Request('GET', 'http://foo.com'); $this->assertInternalType('string', $h->getHeader('foo')); $this->assertInternalType('array', $h->getHeader('foo', true)); } public function testSetsIntegersAndFloatsAsHeaders() { - $h = new Message(); + $h = new Request('GET', 'http://foo.com'); $h->setHeader('foo', 10); $h->setHeader('bar', 10.5); $h->addHeader('foo', 10); @@ -262,12 +263,20 @@ public function testSetsIntegersAndFloatsAsHeaders() $this->assertSame('10, 10', $h->getHeader('foo')); $this->assertSame('10.5, 10.5', $h->getHeader('bar')); } -} -class Message extends AbstractMessage -{ - protected function getStartLine() + public function testGetsResponseStartLine() + { + $m = new Response(200); + $this->assertEquals('HTTP/1.1 200 OK', Response::getStartLine($m)); + } + + /** + * @expectedException \InvalidArgumentException + */ + public function testThrowsWhenMessageIsUnknown() { - return 'Foo!'; + $m = $this->getMockBuilder('GuzzleHttp\Message\AbstractMessage') + ->getMockForAbstractClass(); + AbstractMessage::getStartLine($m); } } diff --git a/core/vendor/guzzlehttp/guzzle/tests/Post/PostBodyTest.php b/core/vendor/guzzlehttp/guzzle/tests/Post/PostBodyTest.php index 18729b351c53..e9c53229205d 100644 --- a/core/vendor/guzzlehttp/guzzle/tests/Post/PostBodyTest.php +++ b/core/vendor/guzzlehttp/guzzle/tests/Post/PostBodyTest.php @@ -36,7 +36,10 @@ public function testCanForceMultipartUploadsWhenApplying() $b->forceMultipartUpload(true); $m = new Request('POST', '/'); $b->applyRequestHeaders($m); - $this->assertContains('multipart/form-data', (string) $m->getHeader('Content-Type')); + $this->assertContains( + 'multipart/form-data', + $m->getHeader('Content-Type') + ); } public function testApplyingWithFilesAddsMultipartUpload() @@ -49,7 +52,10 @@ public function testApplyingWithFilesAddsMultipartUpload() $this->assertSame($p, $b->getFile('foo')); $m = new Request('POST', '/'); $b->applyRequestHeaders($m); - $this->assertContains('multipart/form-data', (string) $m->getHeader('Content-Type')); + $this->assertContains( + 'multipart/form-data', + $m->getHeader('Content-Type') + ); $this->assertTrue($m->hasHeader('Content-Length')); } @@ -60,7 +66,10 @@ public function testApplyingWithFieldsAddsMultipartUpload() $this->assertEquals(['foo' => 'bar'], $b->getFields()); $m = new Request('POST', '/'); $b->applyRequestHeaders($m); - $this->assertContains('application/x-www-form', (string) $m->getHeader('Content-Type')); + $this->assertContains( + 'application/x-www-form', + $m->getHeader('Content-Type') + ); $this->assertTrue($m->hasHeader('Content-Length')); } @@ -72,7 +81,10 @@ public function testMultipartWithNestedFields() $this->assertEquals(['foo' => ['bar' => 'baz']], $b->getFields()); $m = new Request('POST', '/'); $b->applyRequestHeaders($m); - $this->assertContains('multipart/form-data', (string) $m->getHeader('Content-Type')); + $this->assertContains( + 'multipart/form-data', + $m->getHeader('Content-Type') + ); $this->assertTrue($m->hasHeader('Content-Length')); $contents = $b->getContents(); $this->assertContains('name="foo[bar]"', $contents); @@ -147,10 +159,20 @@ public function testCreatesMultipartUploadWithMultiFields() { $b = new PostBody(); $b->setField('testing', ['baz', 'bar']); + $b->setField('other', 'hi'); + $b->setField('third', 'there'); $b->addFile(new PostFile('foo', fopen(__FILE__, 'r'))); $s = (string) $b; $this->assertContains(file_get_contents(__FILE__), $s); $this->assertContains('testing=bar', $s); + $this->assertContains( + 'Content-Disposition: form-data; name="third"', + $s + ); + $this->assertContains( + 'Content-Disposition: form-data; name="other"', + $s + ); } public function testMultipartWithBase64Fields() @@ -158,13 +180,40 @@ public function testMultipartWithBase64Fields() $b = new PostBody(); $b->setField('foo64', '/xA2JhWEqPcgyLRDdir9WSRi/khpb2Lh3ooqv+5VYoc='); $b->forceMultipartUpload(true); - $this->assertEquals(['foo64' => '/xA2JhWEqPcgyLRDdir9WSRi/khpb2Lh3ooqv+5VYoc='], $b->getFields()); + $this->assertEquals( + ['foo64' => '/xA2JhWEqPcgyLRDdir9WSRi/khpb2Lh3ooqv+5VYoc='], + $b->getFields() + ); $m = new Request('POST', '/'); $b->applyRequestHeaders($m); - $this->assertContains('multipart/form-data', (string) $m->getHeader('Content-Type')); + $this->assertContains( + 'multipart/form-data', + $m->getHeader('Content-Type') + ); $this->assertTrue($m->hasHeader('Content-Length')); $contents = $b->getContents(); $this->assertContains('name="foo64"', $contents); - $this->assertContains('/xA2JhWEqPcgyLRDdir9WSRi/khpb2Lh3ooqv+5VYoc=', $contents); + $this->assertContains( + '/xA2JhWEqPcgyLRDdir9WSRi/khpb2Lh3ooqv+5VYoc=', + $contents + ); + } + + public function testMultipartWithAmpersandInValue() + { + $b = new PostBody(); + $b->setField('a', 'b&c=d'); + $b->forceMultipartUpload(true); + $this->assertEquals(['a' => 'b&c=d'], $b->getFields()); + $m = new Request('POST', '/'); + $b->applyRequestHeaders($m); + $this->assertContains( + 'multipart/form-data', + $m->getHeader('Content-Type') + ); + $this->assertTrue($m->hasHeader('Content-Length')); + $contents = $b->getContents(); + $this->assertContains('name="a"', $contents); + $this->assertContains('b&c=d', $contents); } } diff --git a/core/vendor/guzzlehttp/guzzle/tests/Subscriber/HistoryTest.php b/core/vendor/guzzlehttp/guzzle/tests/Subscriber/HistoryTest.php index d5f1dc84c5ad..58c2e30fb135 100644 --- a/core/vendor/guzzlehttp/guzzle/tests/Subscriber/HistoryTest.php +++ b/core/vendor/guzzlehttp/guzzle/tests/Subscriber/HistoryTest.php @@ -28,6 +28,18 @@ public function testAddsForErrorEvent() $ev = new ErrorEvent($t, $e); $h = new History(2); $h->onError($ev); + // Only tracks when no response is present + $this->assertEquals([], $h->getRequests()); + } + + public function testLogsConnectionErrors() + { + $request = new Request('GET', '/'); + $t = new Transaction(new Client(), $request); + $e = new RequestException('foo', $request); + $ev = new ErrorEvent($t, $e); + $h = new History(); + $h->onError($ev); $this->assertEquals([$request], $h->getRequests()); } diff --git a/core/vendor/guzzlehttp/guzzle/tests/UrlTest.php b/core/vendor/guzzlehttp/guzzle/tests/UrlTest.php index 668855dc48ad..1321c010b709 100644 --- a/core/vendor/guzzlehttp/guzzle/tests/UrlTest.php +++ b/core/vendor/guzzlehttp/guzzle/tests/UrlTest.php @@ -162,7 +162,9 @@ public function urlCombineDataProvider() ['http://www.example.com/path', 'http://u:a@www.example.com/', 'http://u:a@www.example.com/'], ['/path?q=2', 'http://www.test.com/', 'http://www.test.com/path?q=2'], ['http://api.flickr.com/services/', 'http://www.flickr.com/services/oauth/access_token', 'http://www.flickr.com/services/oauth/access_token'], - ['https://www.example.com/path', '//foo.com/abc', 'https://foo.com/abc'], + ['https://www.example.com/path', '//foo.com/abc', 'https://foo.com/abc'], + ['https://www.example.com/0/', 'relative/foo', 'https://www.example.com/0/relative/foo'], + ['', '0', '0'], // RFC 3986 test cases [self::RFC3986_BASE, 'g:h', 'g:h'], [self::RFC3986_BASE, 'g', 'http://a/b/c/g'], diff --git a/core/vendor/guzzlehttp/streams/.travis.yml b/core/vendor/guzzlehttp/streams/.travis.yml index 90df122be4da..4355f26b1f42 100644 --- a/core/vendor/guzzlehttp/streams/.travis.yml +++ b/core/vendor/guzzlehttp/streams/.travis.yml @@ -7,6 +7,7 @@ php: - hhvm before_script: - - composer install + - composer self-update + - composer install --no-interaction --prefer-source --dev script: vendor/bin/phpunit diff --git a/core/vendor/guzzlehttp/streams/CHANGELOG.rst b/core/vendor/guzzlehttp/streams/CHANGELOG.rst index cdc18f4bc449..8f0116b76d43 100644 --- a/core/vendor/guzzlehttp/streams/CHANGELOG.rst +++ b/core/vendor/guzzlehttp/streams/CHANGELOG.rst @@ -2,6 +2,27 @@ Changelog ========= +1.5.1 (2014-09-10) +------------------ + +* Stream metadata is grabbed from the underlying stream each time + ``getMetadata`` is called rather than returning a value from a cache. +* Properly closing all underlying streams when AppendStream is closed. +* Seek functions no longer throw exceptions. +* LazyOpenStream now correctly returns the underlying stream resource when + detached. + +1.5.0 (2014-08-07) +------------------ + +* Added ``Stream\safe_open`` to open stream resources and throw exceptions + instead of raising errors. + +1.4.0 (2014-07-19) +------------------ + +* Added a LazyOpenStream + 1.3.0 (2014-07-15) ------------------ diff --git a/core/vendor/guzzlehttp/streams/Makefile b/core/vendor/guzzlehttp/streams/Makefile index c39ff76e72ed..f4d42849e528 100644 --- a/core/vendor/guzzlehttp/streams/Makefile +++ b/core/vendor/guzzlehttp/streams/Makefile @@ -1,5 +1,11 @@ all: clean coverage +release: tag + git push origin --tags + +tag: + chag tag --sign --debug CHANGELOG.rst + test: vendor/bin/phpunit diff --git a/core/vendor/guzzlehttp/streams/README.rst b/core/vendor/guzzlehttp/streams/README.rst index 3fe5dad05402..0ff85dd49d19 100644 --- a/core/vendor/guzzlehttp/streams/README.rst +++ b/core/vendor/guzzlehttp/streams/README.rst @@ -17,7 +17,7 @@ Simply add the following to the composer.json file at the root of your project: { "require": { - "guzzlehttp/streams": "1.*" + "guzzlehttp/streams": "~1.0" } } diff --git a/core/vendor/guzzlehttp/streams/composer.json b/core/vendor/guzzlehttp/streams/composer.json index d1fc4f57270d..cf3825fb15ef 100644 --- a/core/vendor/guzzlehttp/streams/composer.json +++ b/core/vendor/guzzlehttp/streams/composer.json @@ -23,7 +23,7 @@ }, "extra": { "branch-alias": { - "dev-master": "1.2.x-dev" + "dev-master": "1.5-dev" } } } diff --git a/core/vendor/guzzlehttp/streams/src/AppendStream.php b/core/vendor/guzzlehttp/streams/src/AppendStream.php index ffa73962479d..406b3adb5055 100644 --- a/core/vendor/guzzlehttp/streams/src/AppendStream.php +++ b/core/vendor/guzzlehttp/streams/src/AppendStream.php @@ -86,7 +86,6 @@ public function close() */ public function detach() { - $this->streams = []; $this->close(); } @@ -132,12 +131,8 @@ public function eof() */ public function seek($offset, $whence = SEEK_SET) { - if (!$this->seekable) { + if (!$this->seekable || $whence !== SEEK_SET) { return false; - } elseif ($whence !== SEEK_SET) { - throw new \InvalidArgumentException( - 'AppendStream only supports SEEK_SET' - ); } $success = true; @@ -207,6 +202,6 @@ public function isSeekable() public function write($string) { - return 0; + return false; } } diff --git a/core/vendor/guzzlehttp/streams/src/CachingStream.php b/core/vendor/guzzlehttp/streams/src/CachingStream.php index 35419f1ed95a..2d891b82fb5e 100644 --- a/core/vendor/guzzlehttp/streams/src/CachingStream.php +++ b/core/vendor/guzzlehttp/streams/src/CachingStream.php @@ -47,8 +47,7 @@ public function seek($offset, $whence = SEEK_SET) } elseif ($whence == SEEK_CUR) { $byte = $offset + $this->tell(); } else { - throw new \RuntimeException(__CLASS__ . ' supports only SEEK_SET' - .' and SEEK_CUR seek operations'); + return false; } // You cannot skip ahead past where you've read from the remote stream diff --git a/core/vendor/guzzlehttp/streams/src/LazyOpenStream.php b/core/vendor/guzzlehttp/streams/src/LazyOpenStream.php new file mode 100644 index 000000000000..35f0df7a6962 --- /dev/null +++ b/core/vendor/guzzlehttp/streams/src/LazyOpenStream.php @@ -0,0 +1,117 @@ +<?php +namespace GuzzleHttp\Stream; + +/** + * Lazily reads or writes to a file that is opened only after an IO operation + * take place on the stream. + */ +class LazyOpenStream implements StreamInterface, MetadataStreamInterface +{ + /** @var string File to open */ + private $filename; + + /** @var string $mode */ + private $mode; + + /** @var MetadataStreamInterface */ + private $stream; + + /** + * @param string $filename File to lazily open + * @param string $mode fopen mode to use when opening the stream + */ + public function __construct($filename, $mode) + { + $this->filename = $filename; + $this->mode = $mode; + } + + public function __toString() + { + try { + return (string) $this->getStream(); + } catch (\Exception $e) { + return ''; + } + } + + private function getStream() + { + if (!$this->stream) { + $this->stream = create(safe_open($this->filename, $this->mode)); + } + + return $this->stream; + } + + public function getContents($maxLength = -1) + { + return copy_to_string($this->getStream(), $maxLength); + } + + public function close() + { + if ($this->stream) { + $this->stream->close(); + } + } + + public function detach() + { + $stream = $this->getStream(); + $result = $stream->detach(); + $this->close(); + + return $result; + } + + public function tell() + { + return $this->stream ? $this->stream->tell() : 0; + } + + public function getSize() + { + return $this->getStream()->getSize(); + } + + public function eof() + { + return $this->getStream()->eof(); + } + + public function seek($offset, $whence = SEEK_SET) + { + return $this->getStream()->seek($offset, $whence); + } + + public function read($length) + { + return $this->getStream()->read($length); + } + + public function isReadable() + { + return $this->getStream()->isReadable(); + } + + public function isWritable() + { + return $this->getStream()->isWritable(); + } + + public function isSeekable() + { + return $this->getStream()->isSeekable(); + } + + public function write($string) + { + return $this->getStream()->write($string); + } + + public function getMetadata($key = null) + { + return $this->getStream()->getMetadata($key); + } +} diff --git a/core/vendor/guzzlehttp/streams/src/Stream.php b/core/vendor/guzzlehttp/streams/src/Stream.php index 73eb445f94b1..0ff006eba062 100644 --- a/core/vendor/guzzlehttp/streams/src/Stream.php +++ b/core/vendor/guzzlehttp/streams/src/Stream.php @@ -7,19 +7,12 @@ */ class Stream implements MetadataStreamInterface { - /** @var resource Stream resource */ private $stream; - - /** @var int Size of the stream contents in bytes */ private $size; - - /** @var bool */ private $seekable; private $readable; private $writable; - - /** @var array Stream metadata */ - private $meta = []; + private $uri; /** @var array Hash of readable and writable stream types */ private static $readWriteHash = [ @@ -66,10 +59,11 @@ public function __construct($stream, $size = null) $this->size = $size; $this->stream = $stream; - $this->meta = stream_get_meta_data($this->stream); - $this->seekable = $this->meta['seekable']; - $this->readable = isset(self::$readWriteHash['read'][$this->meta['mode']]); - $this->writable = isset(self::$readWriteHash['write'][$this->meta['mode']]); + $meta = stream_get_meta_data($this->stream); + $this->seekable = $meta['seekable']; + $this->readable = isset(self::$readWriteHash['read'][$meta['mode']]); + $this->writable = isset(self::$readWriteHash['write'][$meta['mode']]); + $this->uri = isset($meta['uri']) ? $meta['uri'] : null; } /** @@ -104,14 +98,13 @@ public function close() fclose($this->stream); } - $this->meta = []; - $this->stream = null; + $this->detach(); } public function detach() { $result = $this->stream; - $this->stream = $this->size = null; + $this->stream = $this->size = $this->uri = null; $this->readable = $this->writable = $this->seekable = false; return $result; @@ -121,13 +114,15 @@ public function getSize() { if ($this->size !== null) { return $this->size; - } elseif (!$this->stream) { + } + + if (!$this->stream) { return null; } - // If the stream is a file based stream and local, then use fstat - if (isset($this->meta['uri'])) { - clearstatcache(true, $this->meta['uri']); + // Clear the stat cache if the stream has a URI + if ($this->uri) { + clearstatcache(true, $this->uri); } $stats = fstat($this->stream); @@ -207,8 +202,8 @@ public function write($string) */ public function getMetadata($key = null) { - return !$key - ? $this->meta - : (isset($this->meta[$key]) ? $this->meta[$key] : null); + $meta = $this->stream ? stream_get_meta_data($this->stream) : []; + + return !$key ? $meta : (isset($meta[$key]) ? $meta[$key] : null); } } diff --git a/core/vendor/guzzlehttp/streams/src/StreamDecoratorTrait.php b/core/vendor/guzzlehttp/streams/src/StreamDecoratorTrait.php index 801129742c11..ecb902a4b9b5 100644 --- a/core/vendor/guzzlehttp/streams/src/StreamDecoratorTrait.php +++ b/core/vendor/guzzlehttp/streams/src/StreamDecoratorTrait.php @@ -54,7 +54,7 @@ public function __call($method, array $args) public function close() { - return $this->stream->close(); + $this->stream->close(); } public function getMetadata($key = null) @@ -66,9 +66,7 @@ public function getMetadata($key = null) public function detach() { - $this->stream->detach(); - - return $this; + return $this->stream->detach(); } public function getSize() diff --git a/core/vendor/guzzlehttp/streams/src/functions.php b/core/vendor/guzzlehttp/streams/src/functions.php index 057d1db1fe23..372d51ba17da 100644 --- a/core/vendor/guzzlehttp/streams/src/functions.php +++ b/core/vendor/guzzlehttp/streams/src/functions.php @@ -171,4 +171,39 @@ function read_line(StreamInterface $stream, $maxLength = null) return $buffer; } + + /** + * Safely opens a PHP stream resource using a filename. + * + * When fopen fails, PHP normally raises a warning. This function adds an + * error handler that checks for errors and throws an exception instead. + * + * @param string $filename File to open + * @param string $mode Mode used to open the file + * + * @return resource + * @throws \RuntimeException if the file cannot be opened + */ + function safe_open($filename, $mode) + { + $ex = null; + set_error_handler(function () use ($filename, $mode, &$ex) { + $ex = new \RuntimeException(sprintf( + 'Unable to open %s using mode %s: %s', + $filename, + $mode, + func_get_args()[1] + )); + }); + + $handle = fopen($filename, $mode); + restore_error_handler(); + + if ($ex) { + /** @var $ex \RuntimeException */ + throw $ex; + } + + return $handle; + } } diff --git a/core/vendor/guzzlehttp/streams/tests/AppendStreamTest.php b/core/vendor/guzzlehttp/streams/tests/AppendStreamTest.php index b35990d56755..61aa5d47cae3 100644 --- a/core/vendor/guzzlehttp/streams/tests/AppendStreamTest.php +++ b/core/vendor/guzzlehttp/streams/tests/AppendStreamTest.php @@ -22,14 +22,10 @@ public function testValidatesStreamsAreReadable() $a->addStream($s); } - /** - * @expectedException \InvalidArgumentException - * @expectedExceptionMessage only supports SEEK_SET - */ public function testValidatesSeekType() { $a = new AppendStream(); - $a->seek(100, SEEK_CUR); + $this->assertFalse($a->seek(100, SEEK_CUR)); } public function testTriesToRewindOnSeek() @@ -92,7 +88,7 @@ public function testIsNotWritable() $this->assertFalse($a->isWritable()); $this->assertTrue($a->isSeekable()); $this->assertTrue($a->isReadable()); - $this->assertSame(0, $a->write('foo')); + $this->assertFalse($a->write('foo')); } public function testDoesNotNeedStreams() diff --git a/core/vendor/guzzlehttp/streams/tests/CachingStreamTest.php b/core/vendor/guzzlehttp/streams/tests/CachingStreamTest.php index a7688ba26dae..d7f625f5fe20 100644 --- a/core/vendor/guzzlehttp/streams/tests/CachingStreamTest.php +++ b/core/vendor/guzzlehttp/streams/tests/CachingStreamTest.php @@ -44,13 +44,9 @@ public function testCannotSeekPastWhatHasBeenRead() $this->body->seek(10); } - /** - * @expectedException \RuntimeException - * @expectedExceptionMessage supports only SEEK_SET and SEEK_CUR - */ public function testCannotUseSeekEnd() { - $this->body->seek(2, SEEK_END); + $this->assertFalse($this->body->seek(2, SEEK_END)); } public function testRewindUsesSeek() diff --git a/core/vendor/guzzlehttp/streams/tests/LazyOpenStreamTest.php b/core/vendor/guzzlehttp/streams/tests/LazyOpenStreamTest.php new file mode 100644 index 000000000000..e5ee7307f03f --- /dev/null +++ b/core/vendor/guzzlehttp/streams/tests/LazyOpenStreamTest.php @@ -0,0 +1,61 @@ +<?php +namespace GuzzleHttp\Tests\Stream; + +use GuzzleHttp\Stream\LazyOpenStream; + +class LazyOpenStreamTest extends \PHPUnit_Framework_TestCase +{ + private $fname; + + public function setup() + { + $this->fname = tempnam('/tmp', 'tfile'); + + if (file_exists($this->fname)) { + unlink($this->fname); + } + } + + public function tearDown() + { + if (file_exists($this->fname)) { + unlink($this->fname); + } + } + + public function testOpensLazily() + { + $l = new LazyOpenStream($this->fname, 'w+'); + $l->write('foo'); + $this->assertInternalType('array', $l->getMetadata()); + $this->assertFileExists($this->fname); + $this->assertEquals('foo', file_get_contents($this->fname)); + } + + public function testProxiesToFile() + { + file_put_contents($this->fname, 'foo'); + $l = new LazyOpenStream($this->fname, 'r'); + $this->assertEquals('foo', $l->read(4)); + $this->assertTrue($l->eof()); + $this->assertEquals(3, $l->tell()); + $this->assertTrue($l->isReadable()); + $this->assertTrue($l->isSeekable()); + $this->assertFalse($l->isWritable()); + $l->seek(1); + $this->assertEquals('oo', $l->getContents()); + $this->assertEquals('foo', (string) $l); + $this->assertEquals(3, $l->getSize()); + $this->assertInternalType('array', $l->getMetadata()); + $l->close(); + } + + public function testDetachesUnderlyingStream() + { + file_put_contents($this->fname, 'foo'); + $l = new LazyOpenStream($this->fname, 'r'); + $r = $l->detach(); + $this->assertInternalType('resource', $r); + fclose($r); + } +} diff --git a/core/vendor/guzzlehttp/streams/tests/NoSeekStreamTest.php b/core/vendor/guzzlehttp/streams/tests/NoSeekStreamTest.php index b8988eead30f..e6fdbe1f96ce 100644 --- a/core/vendor/guzzlehttp/streams/tests/NoSeekStreamTest.php +++ b/core/vendor/guzzlehttp/streams/tests/NoSeekStreamTest.php @@ -7,6 +7,7 @@ /** * @covers GuzzleHttp\Stream\NoSeekStream + * @covers GuzzleHttp\Stream\StreamDecoratorTrait */ class NoSeekStreamTest extends \PHPUnit_Framework_TestCase { @@ -21,4 +22,12 @@ public function testCannotSeek() $this->assertFalse($wrapped->isSeekable()); $this->assertFalse($wrapped->seek(2)); } + + public function testHandlesClose() + { + $s = Stream::factory('foo'); + $wrapped = new NoSeekStream($s); + $wrapped->close(); + $this->assertFalse($wrapped->write('foo')); + } } diff --git a/core/vendor/guzzlehttp/streams/tests/StreamTest.php b/core/vendor/guzzlehttp/streams/tests/StreamTest.php index d8a4d7e23561..20566e4653f1 100644 --- a/core/vendor/guzzlehttp/streams/tests/StreamTest.php +++ b/core/vendor/guzzlehttp/streams/tests/StreamTest.php @@ -151,6 +151,19 @@ public function testCanDetachStream() $stream->close(); } + public function testCloseClearProperties() + { + $handle = fopen('php://temp', 'r+'); + $stream = new Stream($handle); + $stream->close(); + + $this->assertEmpty($stream->getMetadata()); + $this->assertFalse($stream->isSeekable()); + $this->assertFalse($stream->isReadable()); + $this->assertFalse($stream->isWritable()); + $this->assertNull($stream->getSize()); + } + public function testCreatesWithFactory() { $stream = Stream::factory('foo'); diff --git a/core/vendor/guzzlehttp/streams/tests/functionsTest.php b/core/vendor/guzzlehttp/streams/tests/functionsTest.php index f6af8a0ffd28..b2ef89cf93d9 100644 --- a/core/vendor/guzzlehttp/streams/tests/functionsTest.php +++ b/core/vendor/guzzlehttp/streams/tests/functionsTest.php @@ -116,6 +116,22 @@ public function testThrowsExceptionForUnknown() { Stream\create(new \stdClass()); } + + public function testOpensFilesSuccessfully() + { + $r = Stream\safe_open(__FILE__, 'r'); + $this->assertInternalType('resource', $r); + fclose($r); + } + + /** + * @expectedException \RuntimeException + * @expectedExceptionMessage Unable to open /path/to/does/not/exist using mode r + */ + public function testThrowsExceptionNotWarning() + { + Stream\safe_open('/path/to/does/not/exist', 'r'); + } } class HasToString -- GitLab