diff --git a/composer.json b/composer.json index 9fa6935..4c4f823 100644 --- a/composer.json +++ b/composer.json @@ -15,7 +15,7 @@ "symfony/yaml": "2.3.*", "twig/twig": "1.12.*", "doctrine/common": "2.4.*@beta", - "guzzle/http": "3.1.*", + "guzzle/http": "3.7.*", "kriswallsmith/assetic": "1.1.*@alpha", "symfony-cmf/routing": "1.1.*@alpha", "easyrdf/easyrdf": "0.8.*@beta", diff --git a/composer.lock b/composer.lock index 35f3e82..ce988ad 100644 --- a/composer.lock +++ b/composer.lock @@ -3,7 +3,7 @@ "This file locks the dependencies of your project to a known state", "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file" ], - "hash": "99355ea2b3166a2c7d7029c8ddc76f4e", + "hash": "eb2c59507a34a3831afe33b16c4d5775", "packages": [ { "name": "doctrine/annotations", @@ -449,17 +449,17 @@ }, { "name": "guzzle/common", - "version": "v3.1.2", + "version": "v3.7.1", "target-dir": "Guzzle/Common", "source": { "type": "git", - "url": "git://github.com/guzzle/common.git", - "reference": "v3.1.2" + "url": "https://github.com/guzzle/common.git", + "reference": "v3.7.1" }, "dist": { "type": "zip", - "url": "https://github.com/guzzle/common/archive/v3.1.2.zip", - "reference": "v3.1.2", + "url": "https://api.github.com/repos/guzzle/common/zipball/v3.7.1", + "reference": "v3.7.1", "shasum": "" }, "require": { @@ -469,7 +469,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-master": "3.7-dev" } }, "autoload": { @@ -489,21 +489,21 @@ "event", "exception" ], - "time": "2013-01-28 00:07:40" + "time": "2013-07-05 20:17:54" }, { "name": "guzzle/http", - "version": "v3.1.2", + "version": "v3.7.1", "target-dir": "Guzzle/Http", "source": { "type": "git", - "url": "git://github.com/guzzle/http.git", - "reference": "v3.1.2" + "url": "https://github.com/guzzle/http.git", + "reference": "v3.7.1" }, "dist": { "type": "zip", - "url": "https://github.com/guzzle/http/archive/v3.1.2.zip", - "reference": "v3.1.2", + "url": "https://api.github.com/repos/guzzle/http/zipball/v3.7.1", + "reference": "v3.7.1", "shasum": "" }, "require": { @@ -518,7 +518,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-master": "3.7-dev" } }, "autoload": { @@ -546,21 +546,21 @@ "http", "http client" ], - "time": "2013-01-26 08:20:43" + "time": "2013-07-02 19:53:26" }, { "name": "guzzle/parser", - "version": "v3.1.2", + "version": "v3.7.1", "target-dir": "Guzzle/Parser", "source": { "type": "git", - "url": "git://github.com/guzzle/parser.git", - "reference": "v3.1.2" + "url": "https://github.com/guzzle/parser.git", + "reference": "v3.7.1" }, "dist": { "type": "zip", - "url": "https://github.com/guzzle/parser/archive/v3.1.2.zip", - "reference": "v3.1.2", + "url": "https://api.github.com/repos/guzzle/parser/zipball/v3.7.1", + "reference": "v3.7.1", "shasum": "" }, "require": { @@ -569,7 +569,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-master": "3.7-dev" } }, "autoload": { @@ -590,31 +590,34 @@ "message", "url" ], - "time": "2013-01-12 21:43:21" + "time": "2013-06-11 00:24:07" }, { "name": "guzzle/stream", - "version": "v3.1.2", + "version": "v3.7.1", "target-dir": "Guzzle/Stream", "source": { "type": "git", - "url": "https://github.com/guzzle/stream", - "reference": "v3.0.7" + "url": "https://github.com/guzzle/stream.git", + "reference": "v3.7.1" }, "dist": { "type": "zip", - "url": "https://github.com/guzzle/stream/archive/v3.0.7.zip", - "reference": "v3.0.7", + "url": "https://api.github.com/repos/guzzle/stream/zipball/v3.7.1", + "reference": "v3.7.1", "shasum": "" }, "require": { "guzzle/common": "self.version", "php": ">=5.3.2" }, + "suggest": { + "guzzle/http": "To convert Guzzle request objects to PHP streams" + }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-master": "3.7-dev" } }, "autoload": { @@ -640,7 +643,7 @@ "component", "stream" ], - "time": "2012-12-07 16:45:11" + "time": "2013-06-27 00:50:43" }, { "name": "kriswallsmith/assetic", diff --git a/core/vendor/autoload.php b/core/vendor/autoload.php index d0e42c0..2c0fbf3 100644 --- a/core/vendor/autoload.php +++ b/core/vendor/autoload.php @@ -4,4 +4,4 @@ require_once __DIR__ . '/composer' . '/autoload_real.php'; -return ComposerAutoloaderInitae9396db2008f9b266cde1fb85dfa4f8::getLoader(); +return ComposerAutoloaderInit3a4905090abf2f2252330204ffd02eb8::getLoader(); diff --git a/core/vendor/composer/autoload_real.php b/core/vendor/composer/autoload_real.php index c2b428f..8b99b80 100644 --- a/core/vendor/composer/autoload_real.php +++ b/core/vendor/composer/autoload_real.php @@ -2,7 +2,7 @@ // autoload_real.php generated by Composer -class ComposerAutoloaderInitae9396db2008f9b266cde1fb85dfa4f8 +class ComposerAutoloaderInit3a4905090abf2f2252330204ffd02eb8 { private static $loader; @@ -19,9 +19,9 @@ public static function getLoader() return self::$loader; } - spl_autoload_register(array('ComposerAutoloaderInitae9396db2008f9b266cde1fb85dfa4f8', 'loadClassLoader'), true, true); + spl_autoload_register(array('ComposerAutoloaderInit3a4905090abf2f2252330204ffd02eb8', 'loadClassLoader'), true, true); self::$loader = $loader = new \Composer\Autoload\ClassLoader(); - spl_autoload_unregister(array('ComposerAutoloaderInitae9396db2008f9b266cde1fb85dfa4f8', 'loadClassLoader')); + spl_autoload_unregister(array('ComposerAutoloaderInit3a4905090abf2f2252330204ffd02eb8', 'loadClassLoader')); $vendorDir = dirname(__DIR__); $baseDir = dirname(dirname($vendorDir)); diff --git a/core/vendor/composer/installed.json b/core/vendor/composer/installed.json index 8319606..65e1fbf 100644 --- a/core/vendor/composer/installed.json +++ b/core/vendor/composer/installed.json @@ -534,209 +534,6 @@ "homepage": "http://symfony.com" }, { - "name": "guzzle/common", - "version": "v3.1.2", - "version_normalized": "3.1.2.0", - "target-dir": "Guzzle/Common", - "source": { - "type": "git", - "url": "git://github.com/guzzle/common.git", - "reference": "v3.1.2" - }, - "dist": { - "type": "zip", - "url": "https://github.com/guzzle/common/archive/v3.1.2.zip", - "reference": "v3.1.2", - "shasum": "" - }, - "require": { - "php": ">=5.3.2", - "symfony/event-dispatcher": ">=2.1" - }, - "time": "2013-01-28 00:07:40", - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.0-dev" - } - }, - "installation-source": "dist", - "autoload": { - "psr-0": { - "Guzzle\\Common": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "Common libraries used by Guzzle", - "homepage": "http://guzzlephp.org/", - "keywords": [ - "collection", - "common", - "event", - "exception" - ] - }, - { - "name": "guzzle/stream", - "version": "v3.1.2", - "version_normalized": "3.1.2.0", - "target-dir": "Guzzle/Stream", - "source": { - "type": "git", - "url": "https://github.com/guzzle/stream", - "reference": "v3.0.7" - }, - "dist": { - "type": "zip", - "url": "https://github.com/guzzle/stream/archive/v3.0.7.zip", - "reference": "v3.0.7", - "shasum": "" - }, - "require": { - "guzzle/common": "self.version", - "php": ">=5.3.2" - }, - "time": "2012-12-07 16:45:11", - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.0-dev" - } - }, - "installation-source": "dist", - "autoload": { - "psr-0": { - "Guzzle\\Stream": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Michael Dowling", - "email": "mtdowling@gmail.com", - "homepage": "https://github.com/mtdowling" - } - ], - "description": "Guzzle stream wrapper component", - "homepage": "http://guzzlephp.org/", - "keywords": [ - "Guzzle", - "component", - "stream" - ] - }, - { - "name": "guzzle/parser", - "version": "v3.1.2", - "version_normalized": "3.1.2.0", - "target-dir": "Guzzle/Parser", - "source": { - "type": "git", - "url": "git://github.com/guzzle/parser.git", - "reference": "v3.1.2" - }, - "dist": { - "type": "zip", - "url": "https://github.com/guzzle/parser/archive/v3.1.2.zip", - "reference": "v3.1.2", - "shasum": "" - }, - "require": { - "php": ">=5.3.2" - }, - "time": "2013-01-12 21:43:21", - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.0-dev" - } - }, - "installation-source": "dist", - "autoload": { - "psr-0": { - "Guzzle\\Parser": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "Interchangeable parsers used by Guzzle", - "homepage": "http://guzzlephp.org/", - "keywords": [ - "URI Template", - "cookie", - "http", - "message", - "url" - ] - }, - { - "name": "guzzle/http", - "version": "v3.1.2", - "version_normalized": "3.1.2.0", - "target-dir": "Guzzle/Http", - "source": { - "type": "git", - "url": "git://github.com/guzzle/http.git", - "reference": "v3.1.2" - }, - "dist": { - "type": "zip", - "url": "https://github.com/guzzle/http/archive/v3.1.2.zip", - "reference": "v3.1.2", - "shasum": "" - }, - "require": { - "guzzle/common": "self.version", - "guzzle/parser": "self.version", - "guzzle/stream": "self.version", - "php": ">=5.3.2" - }, - "suggest": { - "ext-curl": "*" - }, - "time": "2013-01-26 08:20:43", - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.0-dev" - } - }, - "installation-source": "dist", - "autoload": { - "psr-0": { - "Guzzle\\Http": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Michael Dowling", - "email": "mtdowling@gmail.com", - "homepage": "https://github.com/mtdowling" - } - ], - "description": "HTTP libraries used by Guzzle", - "homepage": "http://guzzlephp.org/", - "keywords": [ - "Guzzle", - "client", - "curl", - "http", - "http client" - ] - }, - { "name": "symfony/process", "version": "v2.3.1", "version_normalized": "2.3.1.0", @@ -2060,5 +1857,211 @@ "persistence", "spl" ] + }, + { + "name": "guzzle/common", + "version": "v3.7.1", + "version_normalized": "3.7.1.0", + "target-dir": "Guzzle/Common", + "source": { + "type": "git", + "url": "https://github.com/guzzle/common.git", + "reference": "v3.7.1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/common/zipball/v3.7.1", + "reference": "v3.7.1", + "shasum": "" + }, + "require": { + "php": ">=5.3.2", + "symfony/event-dispatcher": ">=2.1" + }, + "time": "2013-07-05 20:17:54", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.7-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-0": { + "Guzzle\\Common": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Common libraries used by Guzzle", + "homepage": "http://guzzlephp.org/", + "keywords": [ + "collection", + "common", + "event", + "exception" + ] + }, + { + "name": "guzzle/stream", + "version": "v3.7.1", + "version_normalized": "3.7.1.0", + "target-dir": "Guzzle/Stream", + "source": { + "type": "git", + "url": "https://github.com/guzzle/stream.git", + "reference": "v3.7.1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/stream/zipball/v3.7.1", + "reference": "v3.7.1", + "shasum": "" + }, + "require": { + "guzzle/common": "self.version", + "php": ">=5.3.2" + }, + "suggest": { + "guzzle/http": "To convert Guzzle request objects to PHP streams" + }, + "time": "2013-06-27 00:50:43", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.7-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-0": { + "Guzzle\\Stream": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "Guzzle stream wrapper component", + "homepage": "http://guzzlephp.org/", + "keywords": [ + "Guzzle", + "component", + "stream" + ] + }, + { + "name": "guzzle/parser", + "version": "v3.7.1", + "version_normalized": "3.7.1.0", + "target-dir": "Guzzle/Parser", + "source": { + "type": "git", + "url": "https://github.com/guzzle/parser.git", + "reference": "v3.7.1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/parser/zipball/v3.7.1", + "reference": "v3.7.1", + "shasum": "" + }, + "require": { + "php": ">=5.3.2" + }, + "time": "2013-06-11 00:24:07", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.7-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-0": { + "Guzzle\\Parser": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Interchangeable parsers used by Guzzle", + "homepage": "http://guzzlephp.org/", + "keywords": [ + "URI Template", + "cookie", + "http", + "message", + "url" + ] + }, + { + "name": "guzzle/http", + "version": "v3.7.1", + "version_normalized": "3.7.1.0", + "target-dir": "Guzzle/Http", + "source": { + "type": "git", + "url": "https://github.com/guzzle/http.git", + "reference": "v3.7.1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/http/zipball/v3.7.1", + "reference": "v3.7.1", + "shasum": "" + }, + "require": { + "guzzle/common": "self.version", + "guzzle/parser": "self.version", + "guzzle/stream": "self.version", + "php": ">=5.3.2" + }, + "suggest": { + "ext-curl": "*" + }, + "time": "2013-07-02 19:53:26", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.7-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-0": { + "Guzzle\\Http": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "HTTP libraries used by Guzzle", + "homepage": "http://guzzlephp.org/", + "keywords": [ + "Guzzle", + "client", + "curl", + "http", + "http client" + ] } ] diff --git a/core/vendor/guzzle/common/Guzzle/Common/AbstractHasDispatcher.php b/core/vendor/guzzle/common/Guzzle/Common/AbstractHasDispatcher.php index f022555..9c6874f 100644 --- a/core/vendor/guzzle/common/Guzzle/Common/AbstractHasDispatcher.php +++ b/core/vendor/guzzle/common/Guzzle/Common/AbstractHasDispatcher.php @@ -11,22 +11,14 @@ */ class AbstractHasDispatcher implements HasDispatcherInterface { - /** - * @var EventDispatcherInterface - */ + /** @var EventDispatcherInterface */ protected $eventDispatcher; - /** - * {@inheritdoc} - */ public static function getAllEvents() { return array(); } - /** - * {@inheritdoc} - */ public function setEventDispatcher(EventDispatcherInterface $eventDispatcher) { $this->eventDispatcher = $eventDispatcher; @@ -34,9 +26,6 @@ public function setEventDispatcher(EventDispatcherInterface $eventDispatcher) return $this; } - /** - * {@inheritdoc} - */ public function getEventDispatcher() { if (!$this->eventDispatcher) { @@ -46,17 +35,11 @@ public function getEventDispatcher() return $this->eventDispatcher; } - /** - * {@inheritdoc} - */ public function dispatch($eventName, array $context = array()) { $this->getEventDispatcher()->dispatch($eventName, new Event($context)); } - /** - * {@inheritdoc} - */ public function addSubscriber(EventSubscriberInterface $subscriber) { $this->getEventDispatcher()->addSubscriber($subscriber); diff --git a/core/vendor/guzzle/common/Guzzle/Common/Collection.php b/core/vendor/guzzle/common/Guzzle/Common/Collection.php index 6650580..5cb1535 100644 --- a/core/vendor/guzzle/common/Guzzle/Common/Collection.php +++ b/core/vendor/guzzle/common/Guzzle/Common/Collection.php @@ -3,25 +3,22 @@ namespace Guzzle\Common; use Guzzle\Common\Exception\InvalidArgumentException; +use Guzzle\Common\Exception\RuntimeException; /** * Key value pair collection object */ class Collection implements \ArrayAccess, \IteratorAggregate, \Countable, ToArrayInterface { - /** - * @var array Data associated with the object. - */ + /** @var array Data associated with the object. */ protected $data; /** - * Constructor - * * @param array $data Associative array of data to set */ - public function __construct(array $data = null) + public function __construct(array $data = array()) { - $this->data = $data ?: array(); + $this->data = $data; } /** @@ -34,43 +31,30 @@ public function __construct(array $data = null) * @return self * @throws InvalidArgumentException if a parameter is missing */ - public static function fromConfig(array $config = null, array $defaults = null, array $required = null) + public static function fromConfig(array $config = array(), array $defaults = array(), array $required = array()) { - $collection = new self($defaults); + $data = $config + $defaults; - foreach ((array) $config as $key => $value) { - $collection->set($key, $value); + if ($missing = array_diff($required, array_keys($data))) { + throw new InvalidArgumentException('Config is missing the following keys: ' . implode(', ', $missing)); } - foreach ((array) $required as $key) { - if ($collection->hasKey($key) === false) { - throw new InvalidArgumentException("Config must contain a '{$key}' key"); - } - } + return new self($data); + } - return $collection; + public function count() + { + return count($this->data); } - /** - * Add a value to a key. If a key of the same name has already been added, the key value will be converted into an - * array and the new value will be pushed to the end of the array. - * - * @param string $key Key to add - * @param mixed $value Value to add to the key - * - * @return Collection Returns a reference to the object. - */ - public function add($key, $value) + public function getIterator() { - if (!array_key_exists($key, $this->data)) { - $this->data[$key] = $value; - } elseif (is_array($this->data[$key])) { - $this->data[$key][] = $value; - } else { - $this->data[$key] = array($this->data[$key], $value); - } + return new \ArrayIterator($this->data); + } - return $this; + public function toArray() + { + return $this->data; } /** @@ -86,77 +70,78 @@ public function clear() } /** - * Return the number of keys + * Get all or a subset of matching key value pairs * - * @return integer + * @param array $keys Pass an array of keys to retrieve only a subset of key value pairs + * + * @return array Returns an array of all matching key value pairs */ - public function count() + public function getAll(array $keys = null) { - return count($this->data); + return $keys ? array_intersect_key($this->data, array_flip($keys)) : $this->data; } /** - * Iterates over each key value pair in the collection passing them to the Closure. If the Closure function returns - * true, the current value from input is returned into the result Collection. The Closure must accept three - * parameters: (string) $key, (string) $value and return Boolean TRUE or FALSE for each value. + * Get a specific key value. * - * @param \Closure $closure Closure evaluation function - * @param bool $static Set to TRUE to use the same class as the return rather than returning a Collection + * @param string $key Key to retrieve. * - * @return Collection + * @return mixed|null Value of the key or NULL */ - public function filter(\Closure $closure, $static = true) + public function get($key) { - $collection = ($static) ? new static() : new self(); - foreach ($this->data as $key => $value) { - if ($closure($key, $value)) { - $collection->add($key, $value); - } - } - - return $collection; + return isset($this->data[$key]) ? $this->data[$key] : null; } /** - * Get an iterator object + * Set a key value pair * - * @return array + * @param string $key Key to set + * @param mixed $value Value to set + * + * @return Collection Returns a reference to the object */ - public function getIterator() + public function set($key, $value) { - return new \ArrayIterator($this->data); + $this->data[$key] = $value; + + return $this; } /** - * Get a specific key value. + * Add a value to a key. If a key of the same name has already been added, the key value will be converted into an + * array and the new value will be pushed to the end of the array. * - * @param string $key Key to retrieve. + * @param string $key Key to add + * @param mixed $value Value to add to the key * - * @return mixed|null Value of the key or NULL + * @return Collection Returns a reference to the object. */ - public function get($key) + public function add($key, $value) { - return isset($this->data[$key]) ? $this->data[$key] : null; + if (!array_key_exists($key, $this->data)) { + $this->data[$key] = $value; + } elseif (is_array($this->data[$key])) { + $this->data[$key][] = $value; + } else { + $this->data[$key] = array($this->data[$key], $value); + } + + return $this; } /** - * Get all or a subset of matching key value pairs + * Remove a specific key value pair * - * @param array $keys Pass an array of keys to retrieve only a subset of key value pairs + * @param string $key A key to remove * - * @return array Returns an array of all matching key value pairs + * @return Collection */ - public function getAll(array $keys = null) + public function remove($key) { - return $keys ? array_intersect_key($this->data, array_flip($keys)) : $this->data; - } + unset($this->data[$key]); - /** - * {@inheritdoc} - */ - public function toArray() - { - return $this->data; + return $this; } /** @@ -212,24 +197,17 @@ public function hasValue($value) } /** - * Returns a Collection containing all the elements of the collection after applying the callback function to each - * one. The Closure should accept three parameters: (string) $key, (string) $value, (array) $context and return a - * modified value + * Replace the data of the object with the value of an array * - * @param \Closure $closure Closure to apply - * @param array $context Context to pass to the closure - * @param bool $static Set to TRUE to use the same class as the return rather than returning a Collection + * @param array $data Associative array of data * - * @return Collection + * @return Collection Returns a reference to the object */ - public function map(\Closure $closure, array $context = array(), $static = true) + public function replace(array $data) { - $collection = $static ? new static() : new self(); - foreach ($this as $key => $value) { - $collection->add($key, $closure($key, $value, $context)); - } + $this->data = $data; - return $collection; + return $this; } /** @@ -241,126 +219,125 @@ public function map(\Closure $closure, array $context = array(), $static = true) */ public function merge($data) { - if ($data instanceof self) { - $data = $data->getAll(); - } elseif (!is_array($data)) { - return $this; - } - - if (empty($this->data)) { - $this->data = $data; - } else { - foreach ($data as $key => $value) { - $this->add($key, $value); - } + foreach ($data as $key => $value) { + $this->add($key, $value); } return $this; } /** - * ArrayAccess implementation of offsetExists() + * Over write key value pairs in this collection with all of the data from an array or collection. * - * @param string $offset Array key + * @param array|\Traversable $data Values to override over this config * - * @return bool + * @return self */ - public function offsetExists($offset) + public function overwriteWith($data) { - return $this->hasKey($offset) !== false; - } + if (is_array($data)) { + $this->data = $data + $this->data; + } elseif ($data instanceof Collection) { + $this->data = $data->toArray() + $this->data; + } else { + foreach ($data as $key => $value) { + $this->data[$key] = $value; + } + } - /** - * ArrayAccess implementation of offsetGet() - * - * @param string $offset Array key - * - * @return null|mixed - */ - public function offsetGet($offset) - { - return $this->get($offset); + return $this; } /** - * ArrayAccess implementation of offsetGet() + * Returns a Collection containing all the elements of the collection after applying the callback function to each + * one. The Closure should accept three parameters: (string) $key, (string) $value, (array) $context and return a + * modified value * - * @param string $offset Array key - * @param mixed $value Value to set - */ - public function offsetSet($offset, $value) - { - $this->set($offset, $value); - } - - /** - * ArrayAccess implementation of offsetUnset() + * @param \Closure $closure Closure to apply + * @param array $context Context to pass to the closure + * @param bool $static Set to TRUE to use the same class as the return rather than returning a Collection * - * @param string $offset Array key + * @return Collection */ - public function offsetUnset($offset) + public function map(\Closure $closure, array $context = array(), $static = true) { - $this->remove($offset); + $collection = $static ? new static() : new self(); + foreach ($this as $key => $value) { + $collection->add($key, $closure($key, $value, $context)); + } + + return $collection; } /** - * Remove a specific key value pair + * Iterates over each key value pair in the collection passing them to the Closure. If the Closure function returns + * true, the current value from input is returned into the result Collection. The Closure must accept three + * parameters: (string) $key, (string) $value and return Boolean TRUE or FALSE for each value. * - * @param string $key A key to remove + * @param \Closure $closure Closure evaluation function + * @param bool $static Set to TRUE to use the same class as the return rather than returning a Collection * * @return Collection */ - public function remove($key) + public function filter(\Closure $closure, $static = true) { - unset($this->data[$key]); + $collection = ($static) ? new static() : new self(); + foreach ($this->data as $key => $value) { + if ($closure($key, $value)) { + $collection->add($key, $value); + } + } - return $this; + return $collection; } - /** - * Replace the data of the object with the value of an array - * - * @param array $data Associative array of data - * - * @return Collection Returns a reference to the object - */ - public function replace(array $data) + public function offsetExists($offset) { - $this->data = $data; + return isset($this->data[$offset]); + } - return $this; + public function offsetGet($offset) + { + return isset($this->data[$offset]) ? $this->data[$offset] : null; } - /** - * Set a key value pair - * - * @param string $key Key to set - * @param mixed $value Value to set - * - * @return Collection Returns a reference to the object - */ - public function set($key, $value) + public function offsetSet($offset, $value) { - $this->data[$key] = $value; + $this->data[$offset] = $value; + } - return $this; + public function offsetUnset($offset) + { + unset($this->data[$offset]); } /** - * Inject configuration settings into an input string + * Set a value into a nested array key. Keys will be created as needed to set the value. * - * @param string $input Input to inject + * @param string $path Path to set + * @param mixed $value Value to set at the key * - * @return string + * @return self + * @throws RuntimeException when trying to setPath using a nested path that travels through a scalar value */ - public function inject($input) + public function setPath($path, $value) { - $replace = array(); - foreach ($this->data as $key => $val) { - $replace['{' . $key . '}'] = $val; + $current =& $this->data; + $queue = explode('/', $path); + while (null !== ($key = array_shift($queue))) { + if (!is_array($current)) { + throw new RuntimeException("Trying to setPath {$path}, but {$key} is set and is not an array"); + } elseif (!$queue) { + $current[$key] = $value; + } elseif (isset($current[$key])) { + $current =& $current[$key]; + } else { + $current[$key] = array(); + $current =& $current[$key]; + } } - return strtr($input, $replace); + return $this; } /** @@ -376,67 +353,51 @@ public function inject($input) */ public function getPath($path, $separator = '/', $data = null) { - // Assume the data of the collection if no data was passed into the method if ($data === null) { - $data = &$this->data; + $data =& $this->data; } - // Break the path into an array if needed - if (!is_array($path)) { - $path = explode($separator, $path); - } - - // Using an iterative approach rather than recursion for speed + $path = is_array($path) ? $path : explode($separator, $path); while (null !== ($part = array_shift($path))) { - if (!is_array($data)) { return null; - } - - // The value does not exist in the array or the path has more but the value is not an array - if (!isset($data[$part])) { - - // Not using a wildcard and the key was not found, so return null - if ($part != '*') { - return null; - } - - // If using a wildcard search, then diverge and combine paths + } elseif (isset($data[$part])) { + $data =& $data[$part]; + } elseif ($part != '*') { + return null; + } else { + // Perform a wildcard search by diverging and merging paths $result = array(); foreach ($data as $value) { if (!$path) { $result = array_merge_recursive($result, (array) $value); - } else { - $test = $this->getPath($path, $separator, $value); - if ($test !== null) { - $result = array_merge_recursive($result, (array) $test); - } + } elseif (null !== ($test = $this->getPath($path, $separator, $value))) { + $result = array_merge_recursive($result, (array) $test); } } - return $result; } - - // Descend deeper into the data - $data = &$data[$part]; } return $data; } /** - * Over write key value pairs in this collection with all of the data from an array or collection. + * Inject configuration settings into an input string * - * @param array|\Traversable $data Values to override over this config + * @param string $input Input to inject * - * @return self + * @return string + * @deprecated */ - public function overwriteWith($data) + public function inject($input) { - foreach ($data as $k => $v) { - $this->set($k, $v); + Version::warn(__METHOD__ . ' is deprecated'); + $replace = array(); + foreach ($this->data as $key => $val) { + $replace['{' . $key . '}'] = $val; } - return $this; + return strtr($input, $replace); } } diff --git a/core/vendor/guzzle/common/Guzzle/Common/Event.php b/core/vendor/guzzle/common/Guzzle/Common/Event.php index e02546c..fad76a9 100644 --- a/core/vendor/guzzle/common/Guzzle/Common/Event.php +++ b/core/vendor/guzzle/common/Guzzle/Common/Event.php @@ -7,16 +7,12 @@ /** * Default event for Guzzle notifications */ -class Event extends SymfonyEvent implements \ArrayAccess, \IteratorAggregate +class Event extends SymfonyEvent implements ToArrayInterface, \ArrayAccess, \IteratorAggregate { - /** - * @var array - */ + /** @var array */ private $context; /** - * Constructor - * * @param array $context Contextual information */ public function __construct(array $context = array()) @@ -24,43 +20,33 @@ public function __construct(array $context = array()) $this->context = $context; } - /** - * {@inheritdoc} - */ public function getIterator() { return new \ArrayIterator($this->context); } - /** - * {@inheritdoc} - */ public function offsetGet($offset) { - return array_key_exists($offset, $this->context) ? $this->context[$offset] : null; + return isset($this->context[$offset]) ? $this->context[$offset] : null; } - /** - * {@inheritdoc} - */ public function offsetSet($offset, $value) { $this->context[$offset] = $value; } - /** - * {@inheritdoc} - */ public function offsetExists($offset) { - return array_key_exists($offset, $this->context); + return isset($this->context[$offset]); } - /** - * {@inheritdoc} - */ public function offsetUnset($offset) { unset($this->context[$offset]); } + + public function toArray() + { + return $this->context; + } } diff --git a/core/vendor/guzzle/common/Guzzle/Common/Exception/ExceptionCollection.php b/core/vendor/guzzle/common/Guzzle/Common/Exception/ExceptionCollection.php index 76d499e..185d05c 100644 --- a/core/vendor/guzzle/common/Guzzle/Common/Exception/ExceptionCollection.php +++ b/core/vendor/guzzle/common/Guzzle/Common/Exception/ExceptionCollection.php @@ -7,9 +7,7 @@ */ class ExceptionCollection extends \Exception implements GuzzleException, \IteratorAggregate, \Countable { - /** - * @var array Array of Exceptions - */ + /** @var array Array of Exceptions */ protected $exceptions = array(); /** @@ -21,7 +19,10 @@ class ExceptionCollection extends \Exception implements GuzzleException, \Iterat */ public function setExceptions(array $exceptions) { - $this->exceptions = $exceptions; + $this->exceptions = array(); + foreach ($exceptions as $exception) { + $this->add($exception); + } return $this; } @@ -35,18 +36,20 @@ public function setExceptions(array $exceptions) */ public function add($e) { + if ($this->message) { + $this->message .= "\n"; + } + if ($e instanceof self) { - foreach ($e as $exception) { - $this->exceptions[] = $exception; + $this->message .= '(' . get_class($e) . ")"; + foreach (explode("\n", $e->getMessage()) as $message) { + $this->message .= "\n {$message}"; } } elseif ($e instanceof \Exception) { $this->exceptions[] = $e; + $this->message .= '(' . get_class($e) . ') ' . $e->getMessage(); } - $this->message = implode("\n", array_map(function($e) { - return $e->getMessage(); - }, $this->exceptions)); - return $this; } diff --git a/core/vendor/guzzle/common/Guzzle/Common/HasDispatcherInterface.php b/core/vendor/guzzle/common/Guzzle/Common/HasDispatcherInterface.php index 3cb1235..75727ed 100644 --- a/core/vendor/guzzle/common/Guzzle/Common/HasDispatcherInterface.php +++ b/core/vendor/guzzle/common/Guzzle/Common/HasDispatcherInterface.php @@ -22,7 +22,7 @@ public static function getAllEvents(); * * @param EventDispatcherInterface $eventDispatcher * - * @return HasDispatcherInterface + * @return self */ public function setEventDispatcher(EventDispatcherInterface $eventDispatcher); @@ -46,7 +46,7 @@ public function dispatch($eventName, array $context = array()); * * @param EventSubscriberInterface $subscriber Event subscriber * - * @return AbstractHasDispatcher + * @return self */ public function addSubscriber(EventSubscriberInterface $subscriber); } diff --git a/core/vendor/guzzle/common/Guzzle/Common/Version.php b/core/vendor/guzzle/common/Guzzle/Common/Version.php index 9b8a827..af4529b 100644 --- a/core/vendor/guzzle/common/Guzzle/Common/Version.php +++ b/core/vendor/guzzle/common/Guzzle/Common/Version.php @@ -7,5 +7,23 @@ */ class Version { - const VERSION = '3.1.2'; + const VERSION = '3.7.1'; + + /** + * @var bool Set this value to true to enable warnings for deprecated functionality use. This should be on in your + * unit tests, but probably not in production. + */ + public static $emitWarnings = false; + + /** + * Emit a deprecation warning + * + * @param string $message Warning message + */ + public static function warn($message) + { + if (self::$emitWarnings) { + trigger_error('Deprecation warning: ' . $message, E_USER_DEPRECATED); + } + } } diff --git a/core/vendor/guzzle/common/Guzzle/Common/composer.json b/core/vendor/guzzle/common/Guzzle/Common/composer.json index 5693c4d..c02fa69 100644 --- a/core/vendor/guzzle/common/Guzzle/Common/composer.json +++ b/core/vendor/guzzle/common/Guzzle/Common/composer.json @@ -14,7 +14,7 @@ "target-dir": "Guzzle/Common", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-master": "3.7-dev" } } } diff --git a/core/vendor/guzzle/http/Guzzle/Http/AbstractEntityBodyDecorator.php b/core/vendor/guzzle/http/Guzzle/Http/AbstractEntityBodyDecorator.php index 28d3820..5005a88 100644 --- a/core/vendor/guzzle/http/Guzzle/Http/AbstractEntityBodyDecorator.php +++ b/core/vendor/guzzle/http/Guzzle/Http/AbstractEntityBodyDecorator.php @@ -9,14 +9,10 @@ */ class AbstractEntityBodyDecorator implements EntityBodyInterface { - /** - * @var EntityBodyInterface Decorated entity body - */ + /** @var EntityBodyInterface Decorated entity body */ protected $body; /** - * Wrap a entity body - * * @param EntityBodyInterface $body Entity body to decorate */ public function __construct(EntityBodyInterface $body) @@ -24,9 +20,6 @@ public function __construct(EntityBodyInterface $body) $this->body = $body; } - /** - * {@inheritdoc} - */ public function __toString() { return (string) $this->body; @@ -39,68 +32,49 @@ public function __toString() * @param array $args Method arguments * * @return mixed - * @codeCoverageIgnore */ - public function __call($method, array $args = null) + public function __call($method, array $args) { return call_user_func_array(array($this->body, $method), $args); } - /** - * {@inheritdoc} - * @codeCoverageIgnore - */ + public function close() + { + return $this->body->close(); + } + public function setRewindFunction($callable) { - return $this->body->setRewindFunction($callable); + $this->body->setRewindFunction($callable); + + return $this; } - /** - * {@inheritdoc} - * @codeCoverageIgnore - */ public function rewind() { return $this->body->rewind(); } - /** - * {@inheritdoc} - * @codeCoverageIgnore - */ public function compress($filter = 'zlib.deflate') { return $this->body->compress($filter); } - /** - * {@inheritdoc} - * @codeCoverageIgnore - */ public function uncompress($filter = 'zlib.inflate') { return $this->body->uncompress($filter); } - /** - * {@inheritdoc} - */ public function getContentLength() { - return $this->body->getContentLength(); + return $this->getSize(); } - /** - * {@inheritdoc} - */ public function getContentType() { return $this->body->getContentType(); } - /** - * {@inheritdoc} - */ public function getContentMd5($rawOutput = false, $base64Encode = false) { $hash = Stream::getHash($this, 'md5', $rawOutput); @@ -108,162 +82,140 @@ public function getContentMd5($rawOutput = false, $base64Encode = false) return $hash && $base64Encode ? base64_encode($hash) : $hash; } - /** - * {@inheritdoc} - */ public function getContentEncoding() { return $this->body->getContentEncoding(); } - /** - * {@inheritdoc} - * @codeCoverageIgnore - */ public function getMetaData($key = null) { return $this->body->getMetaData($key); } - /** - * {@inheritdoc} - */ public function getStream() { return $this->body->getStream(); } - /** - * {@inheritdoc} - * @codeCoverageIgnore - */ public function setStream($stream, $size = 0) { - return $this->body->setStream($stream, $size); + $this->body->setStream($stream, $size); + + return $this; + } + + public function detachStream() + { + $this->body->detachStream(); + + return $this; } - /** - * {@inheritdoc} - */ public function getWrapper() { return $this->body->getWrapper(); } - /** - * {@inheritdoc} - */ public function getWrapperData() { return $this->body->getWrapperData(); } - /** - * {@inheritdoc} - */ public function getStreamType() { return $this->body->getStreamType(); } - /** - * {@inheritdoc} - */ public function getUri() { return $this->body->getUri(); } - /** - * {@inheritdoc} - */ public function getSize() { return $this->body->getSize(); } - /** - * {@inheritdoc} - */ public function isReadable() { return $this->body->isReadable(); } - /** - * {@inheritdoc} - */ + public function isRepeatable() + { + return $this->isSeekable() && $this->isReadable(); + } + public function isWritable() { return $this->body->isWritable(); } - /** - * {@inheritdoc} - */ public function isConsumed() { return $this->body->isConsumed(); } /** + * Alias of isConsumed() * {@inheritdoc} */ + public function feof() + { + return $this->isConsumed(); + } + public function isLocal() { return $this->body->isLocal(); } - /** - * {@inheritdoc} - */ public function isSeekable() { return $this->body->isSeekable(); } - /** - * {@inheritdoc} - * @codeCoverageIgnore - */ public function setSize($size) { - return $this->body->setSize($size); + $this->body->setSize($size); + + return $this; } - /** - * {@inheritdoc} - * @codeCoverageIgnore - */ public function seek($offset, $whence = SEEK_SET) { return $this->body->seek($offset, $whence); } - /** - * {@inheritdoc} - * @codeCoverageIgnore - */ public function read($length) { return $this->body->read($length); } - /** - * {@inheritdoc} - * @codeCoverageIgnore - */ public function write($string) { return $this->body->write($string); } - /** - * {@inheritdoc} - * @codeCoverageIgnore - */ + public function readLine($maxLength = null) + { + return $this->body->readLine($maxLength); + } + public function ftell() { return $this->body->ftell(); } + + public function getCustomData($key) + { + return $this->body->getCustomData($key); + } + + public function setCustomData($key, $value) + { + $this->body->setCustomData($key, $value); + + return $this; + } } diff --git a/core/vendor/guzzle/http/Guzzle/Http/CachingEntityBody.php b/core/vendor/guzzle/http/Guzzle/Http/CachingEntityBody.php new file mode 100644 index 0000000..c65c136 --- /dev/null +++ b/core/vendor/guzzle/http/Guzzle/Http/CachingEntityBody.php @@ -0,0 +1,229 @@ +remoteStream = $body; + $this->body = new EntityBody(fopen('php://temp', 'r+')); + } + + /** + * Will give the contents of the buffer followed by the exhausted remote stream. + * + * Warning: Loads the entire stream into memory + * + * @return string + */ + public function __toString() + { + $pos = $this->ftell(); + $this->rewind(); + + $str = ''; + while (!$this->isConsumed()) { + $str .= $this->read(16384); + } + + $this->seek($pos); + + return $str; + } + + public function getSize() + { + return max($this->body->getSize(), $this->remoteStream->getSize()); + } + + /** + * {@inheritdoc} + * @throws RuntimeException When seeking with SEEK_END or when seeking past the total size of the buffer stream + */ + public function seek($offset, $whence = SEEK_SET) + { + if ($whence == SEEK_SET) { + $byte = $offset; + } elseif ($whence == SEEK_CUR) { + $byte = $offset + $this->ftell(); + } else { + throw new RuntimeException(__CLASS__ . ' supports only SEEK_SET and SEEK_CUR seek operations'); + } + + // You cannot skip ahead past where you've read from the remote stream + if ($byte > $this->body->getSize()) { + throw new RuntimeException( + "Cannot seek to byte {$byte} when the buffered stream only contains {$this->body->getSize()} bytes" + ); + } + + return $this->body->seek($byte); + } + + public function rewind() + { + return $this->seek(0); + } + + /** + * Does not support custom rewind functions + * + * @throws RuntimeException + */ + public function setRewindFunction($callable) + { + throw new RuntimeException(__CLASS__ . ' does not support custom stream rewind functions'); + } + + public function read($length) + { + // Perform a regular read on any previously read data from the buffer + $data = $this->body->read($length); + $remaining = $length - strlen($data); + + // More data was requested so read from the remote stream + if ($remaining) { + // If data was written to the buffer in a position that would have been filled from the remote stream, + // then we must skip bytes on the remote stream to emulate overwriting bytes from that position. This + // mimics the behavior of other PHP stream wrappers. + $remoteData = $this->remoteStream->read($remaining + $this->skipReadBytes); + + if ($this->skipReadBytes) { + $len = strlen($remoteData); + $remoteData = substr($remoteData, $this->skipReadBytes); + $this->skipReadBytes = max(0, $this->skipReadBytes - $len); + } + + $data .= $remoteData; + $this->body->write($remoteData); + } + + return $data; + } + + public function write($string) + { + // When appending to the end of the currently read stream, you'll want to skip bytes from being read from + // the remote stream to emulate other stream wrappers. Basically replacing bytes of data of a fixed length. + $overflow = (strlen($string) + $this->ftell()) - $this->remoteStream->ftell(); + if ($overflow > 0) { + $this->skipReadBytes += $overflow; + } + + return $this->body->write($string); + } + + /** + * {@inheritdoc} + * @link http://php.net/manual/en/function.fgets.php + */ + public function readLine($maxLength = null) + { + $buffer = ''; + $size = 0; + while (!$this->isConsumed()) { + $byte = $this->read(1); + $buffer .= $byte; + // Break when a new line is found or the max length - 1 is reached + if ($byte == PHP_EOL || ++$size == $maxLength - 1) { + break; + } + } + + return $buffer; + } + + public function isConsumed() + { + return $this->body->isConsumed() && $this->remoteStream->isConsumed(); + } + + /** + * Close both the remote stream and buffer stream + */ + public function close() + { + return $this->remoteStream->close() && $this->body->close(); + } + + public function setStream($stream, $size = 0) + { + $this->remoteStream->setStream($stream, $size); + } + + public function getContentType() + { + return $this->remoteStream->getContentType(); + } + + public function getContentEncoding() + { + return $this->remoteStream->getContentEncoding(); + } + + public function getMetaData($key = null) + { + return $this->remoteStream->getMetaData($key); + } + + public function getStream() + { + return $this->remoteStream->getStream(); + } + + public function getWrapper() + { + return $this->remoteStream->getWrapper(); + } + + public function getWrapperData() + { + return $this->remoteStream->getWrapperData(); + } + + public function getStreamType() + { + return $this->remoteStream->getStreamType(); + } + + public function getUri() + { + return $this->remoteStream->getUri(); + } + + /** + * Always retrieve custom data from the remote stream + * {@inheritdoc} + */ + public function getCustomData($key) + { + return $this->remoteStream->getCustomData($key); + } + + /** + * Always set custom data on the remote stream + * {@inheritdoc} + */ + public function setCustomData($key, $value) + { + $this->remoteStream->setCustomData($key, $value); + + return $this; + } +} diff --git a/core/vendor/guzzle/http/Guzzle/Http/Client.php b/core/vendor/guzzle/http/Guzzle/Http/Client.php index 38b40e5..4659621 100644 --- a/core/vendor/guzzle/http/Guzzle/Http/Client.php +++ b/core/vendor/guzzle/http/Guzzle/Http/Client.php @@ -6,129 +6,132 @@ use Guzzle\Common\AbstractHasDispatcher; use Guzzle\Common\Exception\ExceptionCollection; use Guzzle\Common\Exception\InvalidArgumentException; +use Guzzle\Common\Exception\RuntimeException; +use Guzzle\Common\Version; use Guzzle\Parser\ParserRegistry; use Guzzle\Parser\UriTemplate\UriTemplateInterface; use Guzzle\Http\Message\RequestInterface; use Guzzle\Http\Message\RequestFactory; use Guzzle\Http\Message\RequestFactoryInterface; use Guzzle\Http\Curl\CurlMultiInterface; -use Guzzle\Http\Curl\CurlMulti; +use Guzzle\Http\Curl\CurlMultiProxy; use Guzzle\Http\Curl\CurlHandle; +use Guzzle\Http\Curl\CurlVersion; /** * HTTP client */ class Client extends AbstractHasDispatcher implements ClientInterface { + /** @deprecated Use [request.options][params] */ const REQUEST_PARAMS = 'request.params'; + + const REQUEST_OPTIONS = 'request.options'; const CURL_OPTIONS = 'curl.options'; const SSL_CERT_AUTHORITY = 'ssl.certificate_authority'; const DISABLE_REDIRECTS = RedirectPlugin::DISABLE; - /** - * @var Collection Default HTTP headers to set on each request - */ + /** @var Collection Default HTTP headers to set on each request */ protected $defaultHeaders; - /** - * @var string The user agent string to set on each request - */ + /** @var string The user agent string to set on each request */ protected $userAgent; - /** - * @var Collection Parameter object holding configuration data - */ + /** @var Collection Parameter object holding configuration data */ private $config; - /** - * @var Url Base URL of the client - */ + /** @var Url Base URL of the client */ private $baseUrl; - /** - * @var CurlMultiInterface CurlMulti object used internally - */ + /** @var CurlMultiInterface CurlMulti object used internally */ private $curlMulti; - /** - * @var UriTemplateInterface URI template owned by the client - */ + /** @var UriTemplateInterface URI template owned by the client */ private $uriTemplate; - /** - * @var RequestFactoryInterface Request factory used by the client - */ + /** @var RequestFactoryInterface Request factory used by the client */ protected $requestFactory; - /** - * {@inheritdoc} - */ public static function getAllEvents() { return array(self::CREATE_REQUEST); } /** - * Client constructor - * * @param string $baseUrl Base URL of the web service * @param array|Collection $config Configuration settings + * + * @throws RuntimeException if cURL is not installed */ public function __construct($baseUrl = '', $config = null) { - $this->setConfig($config ?: new Collection()); - // Allow ssl.certificate_authority config setting to control the certificate authority used by curl - $authority = $this->config->get(self::SSL_CERT_AUTHORITY); - // Use the system's cacert if in a phar (curl can't read from a phar stream wrapper) - if (strpos(__FILE__, 'phar://') !== false && (null === $authority || $authority === true)) { - $authority = 'system'; - } - // Set the config setting to system to use the certificate authority bundle on your system - if ($authority !== 'system') { - $this->setSslVerification($authority !== null ? $authority : true); + if (!extension_loaded('curl')) { + // @codeCoverageIgnoreStart + throw new RuntimeException('The PHP cURL extension must be installed to use Guzzle.'); + // @codeCoverageIgnoreEnd } + $this->setConfig($config ?: new Collection()); + $this->initSsl(); $this->setBaseUrl($baseUrl); $this->defaultHeaders = new Collection(); $this->setRequestFactory(RequestFactory::getInstance()); - // Redirect by default, but allow for redirects to be globally disabled on a client - if (!$this->config->get(self::DISABLE_REDIRECTS)) { + $this->userAgent = $this->getDefaultUserAgent(); + if (!$this->config[self::DISABLE_REDIRECTS]) { $this->addSubscriber(new RedirectPlugin()); } } - /** - * {@inheritdoc} - */ final public function setConfig($config) { - // Set the configuration object if ($config instanceof Collection) { $this->config = $config; } elseif (is_array($config)) { $this->config = new Collection($config); } else { - throw new InvalidArgumentException( - 'Config must be an array or Collection' - ); + throw new InvalidArgumentException('Config must be an array or Collection'); } return $this; } + final public function getConfig($key = false) + { + return $key ? $this->config[$key] : $this->config; + } + /** - * {@inheritdoc} + * Set a default request option on the client that will be used as a default for each request + * + * @param string $keyOrPath request.options key (e.g. allow_redirects) or path to a nested key (e.g. headers/foo) + * @param mixed $value Value to set + * + * @return $this */ - final public function getConfig($key = false) + public function setDefaultOption($keyOrPath, $value) { - return $key ? $this->config->get($key) : $this->config; + $keyOrPath = self::REQUEST_OPTIONS . '/' . $keyOrPath; + $this->config->setPath($keyOrPath, $value); + + return $this; } /** - * {@inheritdoc} + * Retrieve a default request option from the client + * + * @param string $keyOrPath request.options key (e.g. allow_redirects) or path to a nested key (e.g. headers/foo) + * + * @return mixed|null */ + public function getDefaultOption($keyOrPath) + { + $keyOrPath = self::REQUEST_OPTIONS . '/' . $keyOrPath; + + return $this->config->getPath($keyOrPath); + } + final public function setSslVerification($certificateAuthority = true, $verifyPeer = true, $verifyHost = 2) { - $opts = $this->config->get(self::CURL_OPTIONS) ?: array(); + $opts = $this->config[self::CURL_OPTIONS] ?: array(); if ($certificateAuthority === true) { // use bundled CA bundle, set secure defaults @@ -152,6 +155,10 @@ public function __construct($baseUrl = '', $config = null) } elseif (is_dir($certificateAuthority)) { unset($opts[CURLOPT_CAINFO]); $opts[CURLOPT_CAPATH] = $certificateAuthority; + } else { + throw new RuntimeException( + 'Invalid option passed to ' . self::SSL_CERT_AUTHORITY . ': ' . $certificateAuthority + ); } } @@ -160,123 +167,43 @@ public function __construct($baseUrl = '', $config = null) return $this; } - /** - * {@inheritdoc} - */ - public function getDefaultHeaders() - { - return $this->defaultHeaders; - } - - /** - * {@inheritdoc} - */ - public function setDefaultHeaders($headers) + public function createRequest($method = 'GET', $uri = null, $headers = null, $body = null, array $options = array()) { - if ($headers instanceof Collection) { - $this->defaultHeaders = $headers; - } elseif (is_array($headers)) { - $this->defaultHeaders = new Collection($headers); - } else { - throw new InvalidArgumentException('Headers must be an array or Collection'); - } - - return $this; - } - - /** - * {@inheritdoc} - */ - public function expandTemplate($template, array $variables = null) - { - $expansionVars = $this->getConfig()->getAll(); - if ($variables) { - $expansionVars = array_merge($expansionVars, $variables); - } - - return $this->getUriTemplate()->expand($template, $expansionVars); - } - - /** - * {@inheritdoc} - */ - public function setUriTemplate(UriTemplateInterface $uriTemplate) - { - $this->uriTemplate = $uriTemplate; - - return $this; - } - - /** - * {@inheritdoc} - */ - public function getUriTemplate() - { - if (!$this->uriTemplate) { - $this->uriTemplate = ParserRegistry::getInstance()->getParser('uri_template'); - } - - return $this->uriTemplate; - } - - /** - * {@inheritdoc} - */ - public function createRequest($method = RequestInterface::GET, $uri = null, $headers = null, $body = null) - { - if (!is_array($uri)) { - $templateVars = null; - } else { - if (count($uri) != 2 || !isset($uri[1]) || !is_array($uri[1])) { - throw new InvalidArgumentException( - 'You must provide a URI template followed by an array of template variables ' - . 'when using an array for a URI template' - ); - } - list($uri, $templateVars) = $uri; - } - if (!$uri) { $url = $this->getBaseUrl(); - } elseif (substr($uri, 0, 4) === 'http') { - // Use absolute URLs as-is - $url = $this->expandTemplate($uri, $templateVars); } else { - $url = Url::factory($this->getBaseUrl())->combine($this->expandTemplate($uri, $templateVars)); - } - - if ($this->userAgent) { - $this->defaultHeaders->set('User-Agent', $this->userAgent); + if (!is_array($uri)) { + $templateVars = null; + } else { + list($uri, $templateVars) = $uri; + } + if (substr($uri, 0, 4) === 'http') { + // Use absolute URLs as-is + $url = $this->expandTemplate($uri, $templateVars); + } else { + $url = Url::factory($this->getBaseUrl())->combine($this->expandTemplate($uri, $templateVars)); + } } - // If default headers are provided, then merge them into existing headers - // If a collision occurs, the header is completely replaced + // If default headers are provided, then merge them under any explicitly provided headers for the request if (count($this->defaultHeaders)) { - if ($headers instanceof Collection) { - $headers = array_merge($this->defaultHeaders->getAll(), $headers->getAll()); + if (!$headers) { + $headers = $this->defaultHeaders->toArray(); } elseif (is_array($headers)) { - $headers = array_merge($this->defaultHeaders->getAll(), $headers); - } else { - $headers = $this->defaultHeaders; + $headers += $this->defaultHeaders->toArray(); + } elseif ($headers instanceof Collection) { + $headers = $headers->toArray() + $this->defaultHeaders->toArray(); } } - return $this->prepareRequest( - $this->requestFactory->create($method, (string) $url, $headers, $body) - ); + return $this->prepareRequest($this->requestFactory->create($method, (string) $url, $headers, $body), $options); } - /** - * {@inheritdoc} - */ public function getBaseUrl($expand = true) { return $expand ? $this->expandTemplate($this->baseUrl) : $this->baseUrl; } - /** - * {@inheritdoc} - */ public function setBaseUrl($url) { $this->baseUrl = $url; @@ -284,13 +211,10 @@ public function setBaseUrl($url) return $this; } - /** - * {@inheritdoc} - */ public function setUserAgent($userAgent, $includeDefault = false) { if ($includeDefault) { - $userAgent .= ' ' . Utils::getDefaultUserAgent(); + $userAgent .= ' ' . $this->getDefaultUserAgent(); } $this->userAgent = $userAgent; @@ -298,91 +222,76 @@ public function setUserAgent($userAgent, $includeDefault = false) } /** - * {@inheritdoc} + * Get the default User-Agent string to use with Guzzle + * + * @return string */ - public function get($uri = null, $headers = null, $body = null) + public function getDefaultUserAgent() { - return $this->createRequest('GET', $uri, $headers, $body); + return 'Guzzle/' . Version::VERSION + . ' curl/' . CurlVersion::getInstance()->get('version') + . ' PHP/' . PHP_VERSION; } - /** - * {@inheritdoc} - */ - public function head($uri = null, $headers = null) + public function get($uri = null, $headers = null, $options = array()) { - return $this->createRequest('HEAD', $uri, $headers); + // BC compat: $options can be a string, resource, etc to specify where the response body is downloaded + return is_array($options) + ? $this->createRequest('GET', $uri, $headers, null, $options) + : $this->createRequest('GET', $uri, $headers, $options); } - /** - * {@inheritdoc} - */ - public function delete($uri = null, $headers = null, $body = null) + public function head($uri = null, $headers = null, array $options = array()) { - return $this->createRequest('DELETE', $uri, $headers, $body); + return $this->createRequest('HEAD', $uri, $headers, null, $options); } - /** - * {@inheritdoc} - */ - public function put($uri = null, $headers = null, $body = null) + public function delete($uri = null, $headers = null, $body = null, array $options = array()) { - return $this->createRequest('PUT', $uri, $headers, $body); + return $this->createRequest('DELETE', $uri, $headers, $body, $options); } - /** - * {@inheritdoc} - */ - public function patch($uri = null, $headers = null, $body = null) + public function put($uri = null, $headers = null, $body = null, array $options = array()) { - return $this->createRequest('PATCH', $uri, $headers, $body); + return $this->createRequest('PUT', $uri, $headers, $body, $options); } - /** - * {@inheritdoc} - */ - public function post($uri = null, $headers = null, $postBody = null) + public function patch($uri = null, $headers = null, $body = null, array $options = array()) { - return $this->createRequest('POST', $uri, $headers, $postBody); + return $this->createRequest('PATCH', $uri, $headers, $body, $options); } - /** - * {@inheritdoc} - */ - public function options($uri = null) + public function post($uri = null, $headers = null, $postBody = null, array $options = array()) { - return $this->createRequest('OPTIONS', $uri); + return $this->createRequest('POST', $uri, $headers, $postBody, $options); } - /** - * {@inheritdoc} - */ - public function send($requests) + public function options($uri = null, array $options = array()) { - $curlMulti = $this->getCurlMulti(); - $multipleRequests = !($requests instanceof RequestInterface); - if (!$multipleRequests) { - $requests = array($requests); - } + return $this->createRequest('OPTIONS', $uri, $options); + } - foreach ($requests as $request) { - $curlMulti->add($request); + public function send($requests) + { + if (!($requests instanceof RequestInterface)) { + return $this->sendMultiple($requests); } try { - $curlMulti->send(); + /** @var $requests RequestInterface */ + $this->getCurlMulti()->add($requests)->send(); + return $requests->getResponse(); } catch (ExceptionCollection $e) { - throw $multipleRequests ? $e : $e->getFirst(); - } - - if (!$multipleRequests) { - return end($requests)->getResponse(); - } else { - return array_map(function ($request) { return $request->getResponse(); }, $requests); + throw $e->getFirst(); } } /** - * {@inheritdoc} + * Set a curl multi object to be used internally by the client for transferring requests. + * + * @param CurlMultiInterface $curlMulti Multi object + * + * @return self */ public function setCurlMulti(CurlMultiInterface $curlMulti) { @@ -392,20 +301,17 @@ public function setCurlMulti(CurlMultiInterface $curlMulti) } /** - * {@inheritdoc} + * @return CurlMultiInterface|CurlMultiProxy */ public function getCurlMulti() { if (!$this->curlMulti) { - $this->curlMulti = CurlMulti::getInstance(); + $this->curlMulti = new CurlMultiProxy(); } return $this->curlMulti; } - /** - * {@inheritdoc} - */ public function setRequestFactory(RequestFactoryInterface $factory) { $this->requestFactory = $factory; @@ -414,37 +320,187 @@ public function setRequestFactory(RequestFactoryInterface $factory) } /** + * Set the URI template expander to use with the client + * + * @param UriTemplateInterface $uriTemplate URI template expander + * + * @return self + */ + public function setUriTemplate(UriTemplateInterface $uriTemplate) + { + $this->uriTemplate = $uriTemplate; + + return $this; + } + + /** + * Copy the cacert.pem file from the phar if it is not in the temp folder and validate the MD5 checksum + * + * @param bool $md5Check Set to false to not perform the MD5 validation + * + * @return string Returns the path to the extracted cacert + * @throws RuntimeException if the file cannot be copied or there is a MD5 mismatch + */ + public function preparePharCacert($md5Check = true) + { + $from = __DIR__ . '/Resources/cacert.pem'; + $certFile = sys_get_temp_dir() . '/guzzle-cacert.pem'; + if (!file_exists($certFile) && !copy($from, $certFile)) { + throw new RuntimeException("Could not copy {$from} to {$certFile}: " . var_export(error_get_last(), true)); + } elseif ($md5Check) { + $actualMd5 = md5_file($certFile); + $expectedMd5 = trim(file_get_contents("{$from}.md5")); + if ($actualMd5 != $expectedMd5) { + throw new RuntimeException("{$certFile} MD5 mismatch: expected {$expectedMd5} but got {$actualMd5}"); + } + } + + return $certFile; + } + + /** + * Expand a URI template while merging client config settings into the template variables + * + * @param string $template Template to expand + * @param array $variables Variables to inject + * + * @return string + */ + protected function expandTemplate($template, array $variables = null) + { + $expansionVars = $this->getConfig()->toArray(); + if ($variables) { + $expansionVars = $variables + $expansionVars; + } + + return $this->getUriTemplate()->expand($template, $expansionVars); + } + + /** + * Get the URI template expander used by the client + * + * @return UriTemplateInterface + */ + protected function getUriTemplate() + { + if (!$this->uriTemplate) { + $this->uriTemplate = ParserRegistry::getInstance()->getParser('uri_template'); + } + + return $this->uriTemplate; + } + + /** + * Send multiple requests in parallel + * + * @param array $requests Array of RequestInterface objects + * + * @return array Returns an array of Response objects + */ + protected function sendMultiple(array $requests) + { + $curlMulti = $this->getCurlMulti(); + foreach ($requests as $request) { + $curlMulti->add($request); + } + $curlMulti->send(); + + /** @var $request RequestInterface */ + $result = array(); + foreach ($requests as $request) { + $result[] = $request->getResponse(); + } + + return $result; + } + + /** * Prepare a request to be sent from the Client by adding client specific behaviors and properties to the request. * * @param RequestInterface $request Request to prepare for the client + * @param array $options Options to apply to the request * * @return RequestInterface */ - protected function prepareRequest(RequestInterface $request) + protected function prepareRequest(RequestInterface $request, array $options = array()) { - $request->setClient($this); + $request->setClient($this)->setEventDispatcher(clone $this->getEventDispatcher()); - // Add any curl options to the request - if ($options = $this->config->get(self::CURL_OPTIONS)) { - $request->getCurlOptions()->merge(CurlHandle::parseCurlConfig($options)); + if ($curl = $this->config[self::CURL_OPTIONS]) { + $request->getCurlOptions()->overwriteWith(CurlHandle::parseCurlConfig($curl)); } - // Add request parameters to the request - if ($options = $this->config->get(self::REQUEST_PARAMS)) { - $request->getParams()->merge($options); + if ($params = $this->config[self::REQUEST_PARAMS]) { + Version::warn('request.params is deprecated. Use request.options to add default request options.'); + $request->getParams()->overwriteWith($params); } - // Attach client observers to the request - $request->setEventDispatcher(clone $this->getEventDispatcher()); + if ($this->userAgent && !$request->hasHeader('User-Agent')) { + $request->setHeader('User-Agent', $this->userAgent); + } - $this->dispatch( - 'client.create_request', - array( - 'client' => $this, - 'request' => $request - ) - ); + if ($defaults = $this->config[self::REQUEST_OPTIONS]) { + $this->requestFactory->applyOptions($request, $defaults, RequestFactoryInterface::OPTIONS_AS_DEFAULTS); + } + + if ($options) { + $this->requestFactory->applyOptions($request, $options); + } + + $this->dispatch('client.create_request', array('client' => $this, 'request' => $request)); return $request; } + + /** + * Initializes SSL settings + */ + protected function initSsl() + { + if ('system' == ($authority = $this->config[self::SSL_CERT_AUTHORITY])) { + return; + } + + if ($authority === null) { + $authority = true; + } + + if ($authority === true && substr(__FILE__, 0, 7) == 'phar://') { + $authority = $this->preparePharCacert(); + $that = $this; + $this->getEventDispatcher()->addListener('request.before_send', function ($event) use ($authority, $that) { + if ($authority == $event['request']->getCurlOptions()->get(CURLOPT_CAINFO)) { + $that->preparePharCacert(false); + } + }); + } + + $this->setSslVerification($authority); + } + + /** + * @deprecated + */ + public function getDefaultHeaders() + { + Version::warn(__METHOD__ . ' is deprecated. Use the request.options array to retrieve default request options'); + return $this->defaultHeaders; + } + + /** + * @deprecated + */ + public function setDefaultHeaders($headers) + { + Version::warn(__METHOD__ . ' is deprecated. Use the request.options array to specify default request options'); + if ($headers instanceof Collection) { + $this->defaultHeaders = $headers; + } elseif (is_array($headers)) { + $this->defaultHeaders = new Collection($headers); + } else { + throw new InvalidArgumentException('Headers must be an array or Collection'); + } + + return $this; + } } diff --git a/core/vendor/guzzle/http/Guzzle/Http/ClientInterface.php b/core/vendor/guzzle/http/Guzzle/Http/ClientInterface.php index de55f08..10e4de2 100644 --- a/core/vendor/guzzle/http/Guzzle/Http/ClientInterface.php +++ b/core/vendor/guzzle/http/Guzzle/Http/ClientInterface.php @@ -7,9 +7,6 @@ use Guzzle\Common\Exception\InvalidArgumentException; use Guzzle\Http\Message\EntityEnclosingRequestInterface; use Guzzle\Http\Message\RequestInterface; -use Guzzle\Http\Message\RequestFactoryInterface; -use Guzzle\Parser\UriTemplate\UriTemplateInterface; -use Guzzle\Http\Curl\CurlMultiInterface; /** * Client interface for send HTTP requests @@ -18,171 +15,99 @@ { const CREATE_REQUEST = 'client.create_request'; + /** @var string RFC 1123 HTTP-Date */ + const HTTP_DATE = 'D, d M Y H:i:s \G\M\T'; + /** * Set the configuration object to use with the client * - * @param array|Collection|string $config Parameters that define how the client behaves and connects to a - * webservice. Pass an array or a Collection object. - * @return ClientInterface + * @param array|Collection $config Parameters that define how the client behaves + * + * @return self */ public function setConfig($config); /** - * Get a configuration setting or all of the configuration settings + * Get a configuration setting or all of the configuration settings. The Collection result of this method can be + * modified to change the configuration settings of a client. + * + * A client should honor the following special values: * - * @param bool|string $key Configuration value to retrieve. Set to FALSE to retrieve all values of the client. + * - request.options: Associative array of default RequestFactory options to apply to each request + * - request.params: Associative array of request parameters (data values) to apply to each request + * - curl.options: Associative array of cURL configuration settings to apply to each request + * - ssl.certificate_authority: Path a CAINFO, CAPATH, true to use strict defaults, or false to disable verification + * - redirect.disable: Set to true to disable redirects + * + * @param bool|string $key Configuration value to retrieve. Set to FALSE to retrieve all values of the client. * The object return can be modified, and modifications will affect the client's config. * @return mixed|Collection + * @see \Guzzle\Http\Message\RequestFactoryInterface::applyOptions for a full list of request.options options */ public function getConfig($key = false); /** - * Set SSL verification options. - * - * Setting $certificateAuthority to TRUE will result in the bundled - * cacert.pem being used to verify against the remote host. - * - * Alternate certificates to verify against can be specified with the - * $certificateAuthority option set to a certificate file location to be - * used with CURLOPT_CAINFO, or a certificate directory path to be used - * with the CURLOPT_CAPATH option. - * - * Setting $certificateAuthority to FALSE will turn off peer verification, - * unset the bundled cacert.pem, and disable host verification. Please - * don't do this unless you really know what you're doing, and why - * you're doing it. - * - * @param string|bool $certificateAuthority bool, file path, or directory path - * @param bool $verifyPeer FALSE to stop cURL from verifying the peer's certificate. - * @param int $verifyHost Set the cURL handle's CURLOPT_SSL_VERIFYHOST option - * - * @return ClientInterface - */ - public function setSslVerification($certificateAuthority = true, $verifyPeer = true, $verifyHost = 2); - - /** - * Get the default HTTP headers to add to each request created by the client - * - * @return Collection - */ - public function getDefaultHeaders(); - - /** - * Set the default HTTP headers to add to each request created by the client - * - * @param array|Collection $headers Default HTTP headers - * - * @return ClientInterface - */ - public function setDefaultHeaders($headers); - - /** - * Set the URI template expander to use with the client - * - * @param UriTemplateInterface $uriTemplate URI template expander - * - * @return ClientInterface - */ - public function setUriTemplate(UriTemplateInterface $uriTemplate); - - /** - * Get the URI template expander used by the client - * - * @return UriTemplateInterface - */ - public function getUriTemplate(); - - /** - * Expand a URI template using client configuration data - * - * @param string $template URI template to expand - * @param array $variables Additional variables to use in the expansion - * - * @return string - */ - public function expandTemplate($template, array $variables = null); - - /** * Create and return a new {@see RequestInterface} configured for the client. * * Use an absolute path to override the base path of the client, or a relative path to append to the base path of - * the client. The URI can contain the query string as well. Use an array to provide a URI template and additional + * the client. The URI can contain the query string as well. Use an array to provide a URI template and additional * variables to use in the URI template expansion. * - * @param string $method HTTP method. Defaults to GET + * @param string $method HTTP method. Defaults to GET * @param string|array $uri Resource URI. * @param array|Collection $headers HTTP headers * @param string|resource|array|EntityBodyInterface $body Entity body of request (POST/PUT) or response (GET) + * @param array $options Array of options to apply to the request * * @return RequestInterface * @throws InvalidArgumentException if a URI array is passed that does not contain exactly two elements: the URI * followed by template variables */ - public function createRequest($method = RequestInterface::GET, $uri = null, $headers = null, $body = null); - - /** - * Get the client's base URL as either an expanded or raw URI template - * - * @param bool $expand Set to FALSE to get the raw base URL without URI template expansion - * - * @return string|null - */ - public function getBaseUrl($expand = true); - - /** - * Set the base URL of the client - * - * @param string $url The base service endpoint URL of the webservice - * - * @return ClientInterface - */ - public function setBaseUrl($url); - - /** - * Set the name of your application and application version that will be - * appended to the User-Agent header of all requests. - * - * @param string $userAgent User agent string - * @param bool $includeDefault Set to TRUE to append the default Guzzle use agent - * - * @return ClientInterface - */ - public function setUserAgent($userAgent, $includeDefault = false); + public function createRequest( + $method = RequestInterface::GET, + $uri = null, + $headers = null, + $body = null, + array $options = array() + ); /** * Create a GET request for the client * - * @param string|array $uri Resource URI - * @param array|Collection $headers HTTP headers - * @param string|resource|array|EntityBodyInterface $body Where to store the response entity body - * + * @param string|array $uri Resource URI + * @param array|Collection $headers HTTP headers + * @param array $options Options to apply to the request. For BC compatibility, you can also pass a + * string to tell Guzzle to download the body of the response to a particular + * location. Use the 'body' option instead for forward compatibility. * @return RequestInterface * @see Guzzle\Http\ClientInterface::createRequest() */ - public function get($uri = null, $headers = null, $body = null); + public function get($uri = null, $headers = null, $options = array()); /** * Create a HEAD request for the client * * @param string|array $uri Resource URI * @param array|Collection $headers HTTP headers + * @param array $options Options to apply to the request * * @return RequestInterface * @see Guzzle\Http\ClientInterface::createRequest() */ - public function head($uri = null, $headers = null); + public function head($uri = null, $headers = null, array $options = array()); /** * Create a DELETE request for the client * - * @param string|array $uri Resource URI - * @param array|Collection $headers HTTP headers + * @param string|array $uri Resource URI + * @param array|Collection $headers HTTP headers * @param string|resource|EntityBodyInterface $body Body to send in the request + * @param array $options Options to apply to the request * * @return EntityEnclosingRequestInterface * @see Guzzle\Http\ClientInterface::createRequest() */ - public function delete($uri = null, $headers = null, $body = null); + public function delete($uri = null, $headers = null, $body = null, array $options = array()); /** * Create a PUT request for the client @@ -190,11 +115,12 @@ public function delete($uri = null, $headers = null, $body = null); * @param string|array $uri Resource URI * @param array|Collection $headers HTTP headers * @param string|resource|EntityBodyInterface $body Body to send in the request + * @param array $options Options to apply to the request * * @return EntityEnclosingRequestInterface * @see Guzzle\Http\ClientInterface::createRequest() */ - public function put($uri = null, $headers = null, $body = null); + public function put($uri = null, $headers = null, $body = null, array $options = array()); /** * Create a PATCH request for the client @@ -202,11 +128,12 @@ public function put($uri = null, $headers = null, $body = null); * @param string|array $uri Resource URI * @param array|Collection $headers HTTP headers * @param string|resource|EntityBodyInterface $body Body to send in the request + * @param array $options Options to apply to the request * * @return EntityEnclosingRequestInterface * @see Guzzle\Http\ClientInterface::createRequest() */ - public function patch($uri = null, $headers = null, $body = null); + public function patch($uri = null, $headers = null, $body = null, array $options = array()); /** * Create a POST request for the client @@ -215,54 +142,82 @@ public function patch($uri = null, $headers = null, $body = null); * @param array|Collection $headers HTTP headers * @param array|Collection|string|EntityBodyInterface $postBody POST body. Can be a string, EntityBody, or * associative array of POST fields to send in the body of the - * request. Prefix a value in the array with the @ symbol to + * request. Prefix a value in the array with the @ symbol to * reference a file. + * @param array $options Options to apply to the request + * * @return EntityEnclosingRequestInterface * @see Guzzle\Http\ClientInterface::createRequest() */ - public function post($uri = null, $headers = null, $postBody = null); + public function post($uri = null, $headers = null, $postBody = null, array $options = array()); /** * Create an OPTIONS request for the client * - * @param string|array $uri Resource URI + * @param string|array $uri Resource URI + * @param array $options Options to apply to the request * * @return RequestInterface * @see Guzzle\Http\ClientInterface::createRequest() */ - public function options($uri = null); + public function options($uri = null, array $options = array()); /** * Sends a single request or an array of requests in parallel * - * @param array $requests Request(s) to send + * @param array|RequestInterface $requests One or more RequestInterface objects to send * - * @return array Returns the response(s) + * @return \Guzzle\Http\Message\Response|array Returns a single Response or an array of Response objects */ public function send($requests); /** - * Set a curl multi object to be used internally by the client for transferring requests. + * Get the client's base URL as either an expanded or raw URI template + * + * @param bool $expand Set to FALSE to get the raw base URL without URI template expansion + * + * @return string|null + */ + public function getBaseUrl($expand = true); + + /** + * Set the base URL of the client * - * @param CurlMultiInterface $curlMulti Multi object + * @param string $url The base service endpoint URL of the webservice * - * @return ClientInterface + * @return self */ - public function setCurlMulti(CurlMultiInterface $curlMulti); + public function setBaseUrl($url); /** - * Get the curl multi object to be used internally by the client for transferring requests. + * Set the User-Agent header to be used on all requests from the client * - * @return CurlMultiInterface + * @param string $userAgent User agent string + * @param bool $includeDefault Set to true to prepend the value to Guzzle's default user agent string + * + * @return self */ - public function getCurlMulti(); + public function setUserAgent($userAgent, $includeDefault = false); /** - * Set the request factory to use with the client when creating requests + * Set SSL verification options. + * + * Setting $certificateAuthority to TRUE will result in the bundled cacert.pem being used to verify against the + * remote host. + * + * Alternate certificates to verify against can be specified with the $certificateAuthority option set to the full + * path to a certificate file, or the path to a directory containing certificates. * - * @param RequestFactoryInterface $factory Request factory + * Setting $certificateAuthority to FALSE will turn off peer verification, unset the bundled cacert.pem, and + * disable host verification. Please don't do this unless you really know what you're doing, and why you're doing + * it. * - * @return ClientInterface + * @param string|bool $certificateAuthority bool, file path, or directory path + * @param bool $verifyPeer FALSE to stop from verifying the peer's certificate. + * @param int $verifyHost Set to 1 to check the existence of a common name in the SSL peer + * certificate. 2 to check the existence of a common name and also verify + * that it matches the hostname provided. + * @return self */ - public function setRequestFactory(RequestFactoryInterface $factory); + public function setSslVerification($certificateAuthority = true, $verifyPeer = true, $verifyHost = 2); } diff --git a/core/vendor/guzzle/http/Guzzle/Http/Curl/CurlHandle.php b/core/vendor/guzzle/http/Guzzle/Http/Curl/CurlHandle.php index 3d14d56..78f9bde 100644 --- a/core/vendor/guzzle/http/Guzzle/Http/Curl/CurlHandle.php +++ b/core/vendor/guzzle/http/Guzzle/Http/Curl/CurlHandle.php @@ -5,9 +5,9 @@ use Guzzle\Common\Exception\InvalidArgumentException; use Guzzle\Common\Exception\RuntimeException; use Guzzle\Common\Collection; +use Guzzle\Http\Message\EntityEnclosingRequest; use Guzzle\Http\Message\RequestInterface; use Guzzle\Parser\ParserRegistry; -use Guzzle\Http\Message\EntityEnclosingRequestInterface; use Guzzle\Http\Url; /** @@ -19,19 +19,13 @@ class CurlHandle const PROGRESS = 'progress'; const DEBUG = 'debug'; - /** - * @var Collection Curl options - */ + /** @var Collection Curl options */ protected $options; - /** - * @var resource Curl resource handle - */ + /** @var resource Curl resource handle */ protected $handle; - /** - * @var int CURLE_* error - */ + /** @var int CURLE_* error */ protected $errorNo = CURLE_OK; /** @@ -48,8 +42,8 @@ class CurlHandle */ public static function factory(RequestInterface $request) { - $mediator = new RequestMediator($request); $requestCurlOptions = $request->getCurlOptions(); + $mediator = new RequestMediator($request, $requestCurlOptions->get('emit_io')); $tempContentLength = null; $method = $request->getMethod(); $bodyAsString = $requestCurlOptions->get(self::BODY_AS_STRING); @@ -57,12 +51,12 @@ public static function factory(RequestInterface $request) // Array of default cURL options. $curlOptions = array( CURLOPT_URL => $request->getUrl(), - CURLOPT_CONNECTTIMEOUT => 10, + CURLOPT_CONNECTTIMEOUT => 150, CURLOPT_RETURNTRANSFER => false, CURLOPT_HEADER => false, - CURLOPT_USERAGENT => (string) $request->getHeader('User-Agent'), CURLOPT_PORT => $request->getPort(), CURLOPT_HTTPHEADER => array(), + CURLOPT_WRITEFUNCTION => array($mediator, 'writeResponseBody'), CURLOPT_HEADERFUNCTION => array($mediator, 'receiveResponseHeader'), CURLOPT_HTTP_VERSION => $request->getProtocolVersion() === '1.0' ? CURL_HTTP_VERSION_1_0 : CURL_HTTP_VERSION_1_1, @@ -72,6 +66,11 @@ public static function factory(RequestInterface $request) CURLOPT_SSL_VERIFYHOST => 2 ); + if (defined('CURLOPT_PROTOCOLS')) { + // Allow only HTTP and HTTPS protocols + $curlOptions[CURLOPT_PROTOCOLS] = CURLPROTO_HTTP | CURLPROTO_HTTPS; + } + // Add CURLOPT_ENCODING if Accept-Encoding header is provided if ($acceptEncodingHeader = $request->getHeader('Accept-Encoding')) { $curlOptions[CURLOPT_ENCODING] = (string) $acceptEncodingHeader; @@ -79,12 +78,6 @@ public static function factory(RequestInterface $request) $request->removeHeader('Accept-Encoding'); } - // Enable the progress function if the 'progress' param was set - if ($requestCurlOptions->get('progress')) { - $curlOptions[CURLOPT_PROGRESSFUNCTION] = array($mediator, 'progress'); - $curlOptions[CURLOPT_NOPROGRESS] = false; - } - // Enable curl debug information if the 'debug' param was set if ($requestCurlOptions->get('debug')) { $curlOptions[CURLOPT_STDERR] = fopen('php://temp', 'r+'); @@ -96,49 +89,29 @@ public static function factory(RequestInterface $request) $curlOptions[CURLOPT_VERBOSE] = true; } - // HEAD requests need no response body, everything else might - if ($method != 'HEAD') { - $curlOptions[CURLOPT_WRITEFUNCTION] = array($mediator, 'writeResponseBody'); - } - // Specify settings according to the HTTP method - switch ($method) { - case 'GET': - $curlOptions[CURLOPT_HTTPGET] = true; - break; - case 'HEAD': - $curlOptions[CURLOPT_NOBODY] = true; - break; - case 'POST': - $curlOptions[CURLOPT_POST] = true; - // Special handling for POST specific fields and files - if (count($request->getPostFiles())) { - $fields = $request->getPostFields()->useUrlEncoding(false)->urlEncode(); - foreach ($request->getPostFiles() as $key => $data) { - $prefixKeys = count($data) > 1; - foreach ($data as $index => $file) { - // Allow multiple files in the same key - $fieldKey = $prefixKeys ? "{$key}[{$index}]" : $key; - $fields[$fieldKey] = $file->getCurlString(); - } - } - $curlOptions[CURLOPT_POSTFIELDS] = $fields; - $request->removeHeader('Content-Length'); - } elseif (count($request->getPostFields())) { - $curlOptions[CURLOPT_POSTFIELDS] = (string) $request->getPostFields()->useUrlEncoding(true); - $request->removeHeader('Content-Length'); - } elseif (!$request->getBody()) { - // Need to remove CURLOPT_POST to prevent chunked encoding for an empty POST - unset($curlOptions[CURLOPT_POST]); - $curlOptions[CURLOPT_CUSTOMREQUEST] = 'POST'; - } - break; - case 'PUT': - case 'PATCH': - case 'DELETE': - default: - $curlOptions[CURLOPT_CUSTOMREQUEST] = $method; + if ($method == 'GET') { + $curlOptions[CURLOPT_HTTPGET] = true; + } elseif ($method == 'HEAD') { + $curlOptions[CURLOPT_NOBODY] = true; + // HEAD requests do not use a write function + unset($curlOptions[CURLOPT_WRITEFUNCTION]); + } elseif (!($request instanceof EntityEnclosingRequest)) { + $curlOptions[CURLOPT_CUSTOMREQUEST] = $method; + } else { + + $curlOptions[CURLOPT_CUSTOMREQUEST] = $method; + + // Handle sending raw bodies in a request + if ($request->getBody()) { + // You can send the body as a string using curl's CURLOPT_POSTFIELDS if ($bodyAsString) { + $curlOptions[CURLOPT_POSTFIELDS] = (string) $request->getBody(); + // Allow curl to add the Content-Length for us to account for the times when + // POST redirects are followed by GET requests + if ($tempContentLength = $request->getHeader('Content-Length')) { + $tempContentLength = (int) (string) $tempContentLength; + } // Remove the curl generated Content-Type header if none was set manually if (!$request->hasHeader('Content-Type')) { $curlOptions[CURLOPT_HTTPHEADER][] = 'Content-Type:'; @@ -150,26 +123,40 @@ public static function factory(RequestInterface $request) $tempContentLength = (int) (string) $tempContentLength; $curlOptions[CURLOPT_INFILESIZE] = $tempContentLength; } - } - } - - // Special handling for requests sending raw data - if ($request instanceof EntityEnclosingRequestInterface) { - if ($request->getBody()) { - if ($bodyAsString) { - $curlOptions[CURLOPT_POSTFIELDS] = (string) $request->getBody(); - // Allow curl to add the Content-Length for us to account for the times when - // POST redirects are followed by GET requests - if ($tempContentLength = $request->getHeader('Content-Length')) { - $tempContentLength = (int) (string) $tempContentLength; - } - } else { // Add a callback for curl to read data to send with the request only if a body was specified $curlOptions[CURLOPT_READFUNCTION] = array($mediator, 'readRequestBody'); // Attempt to seek to the start of the stream $request->getBody()->seek(0); } + + } else { + + // Special handling for POST specific fields and files + $postFields = false; + if (count($request->getPostFiles())) { + $postFields = $request->getPostFields()->useUrlEncoding(false)->urlEncode(); + foreach ($request->getPostFiles() as $key => $data) { + $prefixKeys = count($data) > 1; + foreach ($data as $index => $file) { + // Allow multiple files in the same key + $fieldKey = $prefixKeys ? "{$key}[{$index}]" : $key; + $postFields[$fieldKey] = $file->getCurlValue(); + } + } + } elseif (count($request->getPostFields())) { + $postFields = (string) $request->getPostFields()->useUrlEncoding(true); + } + + if ($postFields !== false) { + if ($method == 'POST') { + unset($curlOptions[CURLOPT_CUSTOMREQUEST]); + $curlOptions[CURLOPT_POST] = true; + } + $curlOptions[CURLOPT_POSTFIELDS] = $postFields; + $request->removeHeader('Content-Length'); + } } + // If the Expect header is not present, prevent curl from adding it if (!$request->hasHeader('Expect')) { $curlOptions[CURLOPT_HTTPHEADER][] = 'Expect:'; @@ -182,7 +169,7 @@ public static function factory(RequestInterface $request) } // Set custom cURL options - foreach ($requestCurlOptions as $key => $value) { + foreach ($requestCurlOptions->toArray() as $key => $value) { if (is_numeric($key)) { $curlOptions[$key] = $value; } @@ -193,37 +180,34 @@ public static function factory(RequestInterface $request) $curlOptions[CURLOPT_HTTPHEADER][] = 'Accept:'; } - // Check if any headers or cURL options are blacklisted - if ($blacklist = $requestCurlOptions->get('blacklist')) { - foreach ($blacklist as $value) { - if (strpos($value, 'header.') !== 0) { - unset($curlOptions[$value]); - } else { - // Remove headers that may have previously been set but are supposed to be blacklisted - $key = substr($value, 7); - $request->removeHeader($key); - $curlOptions[CURLOPT_HTTPHEADER][] = $key . ':'; - } - } - } - // Add any custom headers to the request. Empty headers will cause curl to not send the header at all. foreach ($request->getHeaderLines() as $line) { $curlOptions[CURLOPT_HTTPHEADER][] = $line; } + // Add the content-length header back if it was temporarily removed + if ($tempContentLength) { + $request->setHeader('Content-Length', $tempContentLength); + } + // Apply the options to a new cURL handle. $handle = curl_init(); - curl_setopt_array($handle, $curlOptions); - if ($tempContentLength) { - $request->setHeader('Content-Length', $tempContentLength); + // Enable the progress function if the 'progress' param was set + if ($requestCurlOptions->get('progress')) { + // Wrap the function in a function that provides the curl handle to the mediator's progress function + // Using this rather than injecting the handle into the mediator prevents a circular reference + $curlOptions[CURLOPT_PROGRESSFUNCTION] = function () use ($mediator, $handle) { + $args = func_get_args(); + $args[] = $handle; + call_user_func_array(array($mediator, 'progress'), $args); + }; + $curlOptions[CURLOPT_NOPROGRESS] = false; } - $handle = new static($handle, $curlOptions); - $mediator->setCurlHandle($handle); + curl_setopt_array($handle, $curlOptions); - return $handle; + return new static($handle, $curlOptions); } /** @@ -452,11 +436,14 @@ public static function parseCurlConfig($config) { $curlOptions = array(); foreach ($config as $key => $value) { - if (!is_numeric($key) && defined($key)) { + if (is_string($key) && defined($key)) { // Convert constants represented as string to constant int values $key = constant($key); } - $curlOptions[$key] = is_string($value) && defined($value) ? constant($value) : $value; + if (is_string($value) && defined($value)) { + $value = constant($value); + } + $curlOptions[$key] = $value; } return $curlOptions; diff --git a/core/vendor/guzzle/http/Guzzle/Http/Curl/CurlMulti.php b/core/vendor/guzzle/http/Guzzle/Http/Curl/CurlMulti.php index ceceb90..a8c5699 100644 --- a/core/vendor/guzzle/http/Guzzle/Http/Curl/CurlMulti.php +++ b/core/vendor/guzzle/http/Guzzle/Http/Curl/CurlMulti.php @@ -3,64 +3,35 @@ namespace Guzzle\Http\Curl; use Guzzle\Common\AbstractHasDispatcher; +use Guzzle\Common\Event; use Guzzle\Http\Exception\MultiTransferException; use Guzzle\Http\Exception\CurlException; use Guzzle\Http\Message\RequestInterface; /** * Send {@see RequestInterface} objects in parallel using curl_multi - * - * This implementation allows callers to send blocking requests that return back to the caller when their requests - * complete, regardless of whether or not previously sending requests in the curl_multi object have completed. The - * implementation relies on managing the recursion scope in which a caller adds a request to the CurlMulti object, and - * tracking the requests in the current scope until they complete. Although the CurlMulti object only tracks whether - * or not requests in the current scope have completed, it still sends all requests added to the object in parallel. */ class CurlMulti extends AbstractHasDispatcher implements CurlMultiInterface { - /** - * @var resource cURL multi handle. - */ + /** @var resource cURL multi handle. */ protected $multiHandle; - /** - * @var string The current state of the pool - */ - protected $state = self::STATE_IDLE; - - /** - * @var array Attached {@see RequestInterface} objects. - */ + /** @var array Attached {@see RequestInterface} objects. */ protected $requests; - /** - * @var array Cache of all requests currently in any scope - */ - protected $requestCache; - - /** - * @var \SplObjectStorage {@see RequestInterface} to {@see CurlHandle} storage - */ + /** @var \SplObjectStorage RequestInterface to CurlHandle hash */ protected $handles; - /** - * @var array Hash mapping curl handle resource IDs to request objects - */ + /** @var array Hash mapping curl handle resource IDs to request objects */ protected $resourceHash; - /** - * @var array Queued exceptions - */ + /** @var array Queued exceptions */ protected $exceptions = array(); - /** - * @var array Queue of handles to remove once everything completes - */ - protected $removeHandles; + /** @var array Requests that succeeded */ + protected $successful = array(); - /** - * @var array cURL multi error values and codes - */ + /** @var array cURL multi error values and codes */ protected $multiErrors = array( CURLM_BAD_HANDLE => array('CURLM_BAD_HANDLE', 'The passed-in handle is not a valid CURLM handle.'), CURLM_BAD_EASY_HANDLE => array('CURLM_BAD_EASY_HANDLE', "An easy handle was not good/valid. It could mean that it isn't an easy handle at all, or possibly that the handle already is in used by this or another multi handle."), @@ -68,70 +39,17 @@ class CurlMulti extends AbstractHasDispatcher implements CurlMultiInterface CURLM_INTERNAL_ERROR => array('CURLM_INTERNAL_ERROR', 'This can only be returned if libcurl bugs. Please report it to us!') ); - /** - * @var CurlMulti - */ - private static $instance; - - /** - * @var int - */ - private $scope = -1; - - /** - * Get a cached instance of the curl multi object - * - * @return CurlMulti - */ - public static function getInstance() + public function __construct() { + $this->multiHandle = curl_multi_init(); // @codeCoverageIgnoreStart - if (!self::$instance) { - self::$instance = new self(); + if ($this->multiHandle === false) { + throw new CurlException('Unable to create multi handle'); } // @codeCoverageIgnoreEnd - - return self::$instance; - } - - /** - * {@inheritdoc} - */ - public static function getAllEvents() - { - return array( - // A request was added - self::ADD_REQUEST, - // A request was removed - self::REMOVE_REQUEST, - // Requests are about to be sent - self::BEFORE_SEND, - // The pool finished sending the requests - self::COMPLETE, - // A request is still polling (sent to request's event dispatchers) - self::POLLING_REQUEST, - // A request exception occurred - self::MULTI_EXCEPTION - ); + $this->reset(); } - /** - * {@inheritdoc} - */ - public function __construct() - { - // You can get some weird "Too many open files" errors when sending a large amount of requests in parallel.These - // two statements autoload classes before a system runs out of file descriptors so that you can get back - // valuable error messages if you run out. - class_exists('Guzzle\Http\Message\Response'); - class_exists('Guzzle\Http\Exception\CurlException'); - - $this->createMultiHandle(); - } - - /** - * {@inheritdoc} - */ public function __destruct() { if (is_resource($this->multiHandle)) { @@ -139,235 +57,115 @@ public function __destruct() } } - /** - * {@inheritdoc} - * - * Adds a request to a batch of requests to be sent in parallel. - * - * Async requests adds a request to the current scope to be executed in parallel with any currently executing cURL - * handles. You may only add an async request while other requests are transferring. Attempting to add an async - * request while no requests are transferring will add the request normally in the next available scope (e.g. 0). - * - * @param RequestInterface $request Request to add - * @param bool $async Set to TRUE to add to the current scope - * - * @return self - */ - public function add(RequestInterface $request, $async = false) + public function add(RequestInterface $request) { - if ($async && $this->state != self::STATE_SENDING) { - $async = false; - } - - $this->requestCache = null; - $scope = $async ? $this->scope : $this->scope + 1; - - if (!isset($this->requests[$scope])) { - $this->requests[$scope] = array($request); - } else { - $this->requests[$scope][] = $request; - } - - $this->dispatch(self::ADD_REQUEST, array('request' => $request)); - + $this->requests[] = $request; // If requests are currently transferring and this is async, then the // request must be prepared now as the send() method is not called. - if ($async && $this->state == self::STATE_SENDING) { - $this->beforeSend($request); - } + $this->beforeSend($request); + $this->dispatch(self::ADD_REQUEST, array('request' => $request)); return $this; } - /** - * {@inheritdoc} - */ public function all() { - if (!$this->requestCache) { - $this->requestCache = empty($this->requests) ? array() : call_user_func_array('array_merge', $this->requests); - } - - return $this->requestCache; + return $this->requests; } - /** - * {@inheritdoc} - */ - public function getState() - { - return $this->state; - } - - /** - * {@inheritdoc} - */ public function remove(RequestInterface $request) { $this->removeHandle($request); - $this->requestCache = null; - - foreach ($this->requests as $scope => $scopedRequests) { - $pos = array_search($request, $scopedRequests, true); - if ($pos !== false) { - unset($this->requests[$scope][$pos]); - break; + foreach ($this->requests as $i => $r) { + if ($request === $r) { + unset($this->requests[$i]); + $this->requests = array_values($this->requests); + $this->dispatch(self::REMOVE_REQUEST, array('request' => $request)); + return true; } } - $this->dispatch(self::REMOVE_REQUEST, array('request' => $request)); - - return $this; + return false; } - /** - * {@inheritdoc} - */ public function reset($hard = false) { // Remove each request - foreach ($this->all() as $request) { - $this->remove($request); - } - - $this->requests = array(); - $this->exceptions = array(); - $this->state = self::STATE_IDLE; - $this->scope = -1; - $this->requestCache = null; - - // Remove any curl handles that were queued for removal - if ($this->scope == -1 || $hard) { - foreach ($this->removeHandles as $handle) { - curl_multi_remove_handle($this->multiHandle, $handle->getHandle()); - $handle->close(); + if ($this->requests) { + foreach ($this->requests as $request) { + $this->remove($request); } - $this->removeHandles = array(); } - if ($hard) { - $this->createMultiHandle(); - } + $this->handles = new \SplObjectStorage(); + $this->requests = $this->resourceHash = $this->exceptions = $this->successful = array(); } - /** - * {@inheritdoc} - */ public function send() { - $this->scope++; - $this->state = self::STATE_SENDING; - $requestsInScope = empty($this->requests[$this->scope]) ? array() : $this->requests[$this->scope]; - - // Only prepare and send requests that are in the current recursion scope - // Only enter the main perform() loop if there are requests in scope - if ($requestsInScope) { - - // Any exceptions thrown from this event should break the entire flow of sending requests - $this->dispatch(self::BEFORE_SEND, array( - 'requests' => $this->requests[$this->scope] - )); - - foreach ($this->requests[$this->scope] as $request) { - if ($request->getState() != RequestInterface::STATE_TRANSFER) { - $this->beforeSend($request); - } - } + $this->perform(); + $exceptions = $this->exceptions; + $successful = $this->successful; + $this->reset(); - try { - $this->perform(); - } catch (\Exception $e) { - $this->exceptions[] = array('request' => null, 'exception' => $e); - } - } - - $this->scope--; - - // Aggregate exceptions into a MultiTransferException if needed - $multiException = $this->buildMultiTransferException($requestsInScope); - - // Complete the transfer if this is not a nested scope - if ($this->scope == -1) { - $this->state = self::STATE_COMPLETE; - $this->dispatch(self::COMPLETE); - $this->reset(); - } - - // Throw any exceptions that were encountered - if ($multiException) { - throw $multiException; + if ($exceptions) { + $this->throwMultiException($exceptions, $successful); } } - /** - * {@inheritdoc} - */ public function count() { - return count($this->all()); + return count($this->requests); } /** - * Build a MultiTransferException if needed - * - * @param array $requestsInScope All requests in the previous scope + * Build and throw a MultiTransferException * - * @return MultiTransferException|null + * @param array $exceptions Exceptions encountered + * @param array $successful Successful requests + * @throws MultiTransferException */ - protected function buildMultiTransferException(array $requestsInScope) + protected function throwMultiException(array $exceptions, array $successful) { - if (empty($this->exceptions)) { - return null; - } - - // Keep a list of all requests, and remove errored requests from the list - $store = new \SplObjectStorage(); - foreach ($requestsInScope as $request) { - $store->attach($request); - } - $multiException = new MultiTransferException('Errors during multi transfer'); - while ($e = array_shift($this->exceptions)) { + + while ($e = array_shift($exceptions)) { $multiException->add($e['exception']); - if (isset($e['request'])) { - $multiException->addFailedRequest($e['request']); - // Remove from the total list so that it becomes a list of successful requests - unset($store[$e['request']]); - } + $multiException->addFailedRequest($e['request']); } // Add successful requests - foreach ($store as $request) { - $multiException->addSuccessfulRequest($request); + foreach ($successful as $request) { + if (!$multiException->containsRequest($request)) { + $multiException->addSuccessfulRequest($request); + } } - return $multiException; + throw $multiException; } /** * Prepare for sending * * @param RequestInterface $request Request to prepare + * @throws \Exception on error preparing the request */ protected function beforeSend(RequestInterface $request) { try { - $request->setState(RequestInterface::STATE_TRANSFER); - $request->dispatch('request.before_send', array( - 'request' => $request - )); - if ($request->getState() != RequestInterface::STATE_TRANSFER) { + $state = $request->setState(RequestInterface::STATE_TRANSFER); + if ($state == RequestInterface::STATE_TRANSFER) { + // Add the request curl handle to the multi handle + $this->checkCurlResult(curl_multi_add_handle($this->multiHandle, $this->createCurlHandle($request)->getHandle())); + } else { // Requests might decide they don't need to be sent just before transfer (e.g. CachePlugin) $this->remove($request); - } elseif ($request->getParams()->get('queued_response')) { - // Queued responses do not need to be sent using curl - $this->remove($request); - $request->setState(RequestInterface::STATE_COMPLETE); - } else { - // Add the request's curl handle to the multi handle - $this->checkCurlResult(curl_multi_add_handle($this->multiHandle, $this->createCurlHandle($request)->getHandle())); + if ($state == RequestInterface::STATE_COMPLETE) { + $this->successful[] = $request; + } } } catch (\Exception $e) { + // Queue the exception to be thrown when sent $this->removeErroredRequest($request, $e); } } @@ -382,7 +180,7 @@ protected function beforeSend(RequestInterface $request) protected function createCurlHandle(RequestInterface $request) { $wrapper = CurlHandle::factory($request); - $this->handles->attach($request, $wrapper); + $this->handles[$request] = $wrapper; $this->resourceHash[(int) $wrapper->getHandle()] = $request; return $wrapper; @@ -393,41 +191,24 @@ protected function createCurlHandle(RequestInterface $request) */ protected function perform() { - // @codeCoverageIgnoreStart - // Weird things can happen when making HTTP requests in __destruct methods - if (!$this->multiHandle) { - return; - } - // @codeCoverageIgnoreEnd - - // If there are no requests to send, then exit from the function - if ($this->scope <= 0) { - if ($this->count() == 0) { - return; - } - } elseif (empty($this->requests[$this->scope])) { + if (!$this->requests) { return; } - // Create the polling event external to the loop - $event = array('curl_multi' => $this); - $active = $this->executeHandles(); - - while (1) { - - $this->processMessages(); + // Initialize the handles with a very quick select timeout + $active = $mrc = null; + $this->executeHandles($active, $mrc, 0.001); + $event = new Event(array('curl_multi' => $this)); + $this->processMessages(); - // Exit the function if there are no more requests to send - if (!($scopedPolling = $this->scope <= 0 ? $this->all() : $this->requests[$this->scope])) { - break; - } + while ($this->requests) { // Notify each request as polling $blocking = $total = 0; - foreach ($scopedPolling as $request) { - $event['request'] = $request; - $request->dispatch(self::POLLING_REQUEST, $event); + foreach ($this->requests as $request) { ++$total; + $event['request'] = $request; + $request->getEventDispatcher()->dispatch(self::POLLING_REQUEST, $event); // The blocking variable just has to be non-falsey to block the loop if ($request->getParams()->hasKey(self::BLOCKING)) { ++$blocking; @@ -438,10 +219,11 @@ protected function perform() // Sleep to prevent eating CPU because no requests are actually pending a select call usleep(500); } else { - // Select the curl handles until there is any activity on any of the open file descriptors - // See https://github.com/php/php-src/blob/master/ext/curl/multi.c#L170 - $active = $this->executeHandles(true, 0.02, $active); + do { + $this->executeHandles($active, $mrc, 1); + } while ($active); } + $this->processMessages(); } } @@ -454,8 +236,11 @@ private function processMessages() while ($done = curl_multi_info_read($this->multiHandle)) { try { $request = $this->resourceHash[(int) $done['handle']]; - $handle = $this->handles[$request]; - $this->processResponse($request, $handle, $done); + $this->processResponse($request, $this->handles[$request], $done); + $this->successful[] = $request; + } catch (MultiTransferException $e) { + $this->removeErroredRequest($request, $e, false); + throw $e; } catch (\Exception $e) { $this->removeErroredRequest($request, $e); } @@ -465,31 +250,26 @@ private function processMessages() /** * Execute and select curl handles until there is activity * - * @param bool $select Set to TRUE to select the file descriptors - * @param int $timeout Select timeout in seconds - * @param int $active Previous active value - * - * @return int Returns the number of active handles + * @param int $active Active value to update + * @param int $mrc Multi result value to update + * @param int $timeout Select timeout in seconds */ - private function executeHandles($select = false, $timeout = 1, $active = 0) + private function executeHandles(&$active, &$mrc, $timeout = 1) { do { - // @codeCoverageIgnoreStart - if ($select && $active && curl_multi_select($this->multiHandle, $timeout) == -1) { - // Perform a usleep if a previously executed select returned -1 - // @see https://bugs.php.net/bug.php?id=61141 - usleep(125); - } - // @codeCoverageIgnoreEnd - do { - $mrc = curl_multi_exec($this->multiHandle, $active); - } while ($mrc == CURLM_CALL_MULTI_PERFORM); - // Check the return value to ensure an error did not occur - $this->checkCurlResult($mrc); - // Poll once if not selecting, or poll until there are no handles with activity - } while ($select && $active); - - return $active; + $mrc = curl_multi_exec($this->multiHandle, $active); + } while ($mrc == CURLM_CALL_MULTI_PERFORM && $active); + $this->checkCurlResult($mrc); + + // @codeCoverageIgnoreStart + // Select the curl handles until there is any activity on any of the open file descriptors + // See https://github.com/php/php-src/blob/master/ext/curl/multi.c#L170 + if ($active && $mrc == CURLM_OK && curl_multi_select($this->multiHandle, $timeout) == -1) { + // Perform a usleep if a previously executed select returned -1 + // @see https://bugs.php.net/bug.php?id=61141 + usleep(100); + } + // @codeCoverageIgnoreEnd } /** @@ -497,16 +277,16 @@ private function executeHandles($select = false, $timeout = 1, $active = 0) * * @param RequestInterface $request Request to remove * @param \Exception $e Exception encountered + * @param bool $buffer Set to false to not buffer the exception */ - protected function removeErroredRequest(RequestInterface $request, \Exception $e) + protected function removeErroredRequest(RequestInterface $request, \Exception $e = null, $buffer = true) { - $this->exceptions[] = array('request' => $request, 'exception' => $e); + if ($buffer) { + $this->exceptions[] = array('request' => $request, 'exception' => $e); + } + $this->remove($request); - $request->setState(RequestInterface::STATE_ERROR); - $this->dispatch(self::MULTI_EXCEPTION, array( - 'exception' => $e, - 'all_exceptions' => $this->exceptions - )); + $this->dispatch(self::MULTI_EXCEPTION, array('exception' => $e, 'all_exceptions' => $this->exceptions)); } /** @@ -530,28 +310,21 @@ protected function processResponse(RequestInterface $request, CurlHandle $handle $this->removeHandle($request); if (!$curlException) { - $request->setState(RequestInterface::STATE_COMPLETE, array('handle' => $handle)); + $state = $request->setState(RequestInterface::STATE_COMPLETE, array('handle' => $handle)); // Only remove the request if it wasn't resent as a result of the state change - if ($request->getState() != RequestInterface::STATE_TRANSFER) { + if ($state != RequestInterface::STATE_TRANSFER) { $this->remove($request); } } else { // Set the state of the request to an error - $request->setState(RequestInterface::STATE_ERROR); - // Notify things that listen to the request of the failure - $request->dispatch('request.exception', array( - 'request' => $this, - 'exception' => $curlException - )); - + $state = $request->setState(RequestInterface::STATE_ERROR, array('exception' => $curlException)); // Allow things to ignore the error if possible - $state = $request->getState(); if ($state != RequestInterface::STATE_TRANSFER) { $this->remove($request); } // The error was not handled, so fail if ($state == RequestInterface::STATE_ERROR) { - /** @var $curlException \Exception */ + /** @var CurlException $curlException */ throw $curlException; } } @@ -560,19 +333,16 @@ protected function processResponse(RequestInterface $request, CurlHandle $handle /** * Remove a curl handle from the curl multi object * - * Nasty things (bus errors, segmentation faults) can sometimes occur when removing curl handles when in a callback - * or a recursive scope. Here we are queueing all curl handles that need to be removed and closed so that this - * happens only in the outermost scope when everything has completed sending. - * * @param RequestInterface $request Request that owns the handle */ protected function removeHandle(RequestInterface $request) { - if ($this->handles->contains($request)) { + if (isset($this->handles[$request])) { $handle = $this->handles[$request]; - unset($this->resourceHash[(int) $handle->getHandle()]); unset($this->handles[$request]); - $this->removeHandles[] = $handle; + unset($this->resourceHash[(int) $handle->getHandle()]); + curl_multi_remove_handle($this->multiHandle, $handle->getHandle()); + $handle->close(); } } @@ -583,7 +353,7 @@ protected function removeHandle(RequestInterface $request) * @param CurlHandle $handle Curl handle object * @param array $curl Array returned from curl_multi_info_read * - * @return \Exception|bool + * @return CurlException|bool */ private function isCurlException(RequestInterface $request, CurlHandle $handle, array $curl) { @@ -595,9 +365,9 @@ private function isCurlException(RequestInterface $request, CurlHandle $handle, $e = new CurlException(sprintf('[curl] %s: %s [url] %s', $handle->getErrorNo(), $handle->getError(), $handle->getUrl())); $e->setCurlHandle($handle) - ->setRequest($request) - ->setCurlInfo($handle->getInfo()) - ->setError($handle->getError(), $handle->getErrorNo()); + ->setRequest($request) + ->setCurlInfo($handle->getInfo()) + ->setError($handle->getError(), $handle->getErrorNo()); return $e; } @@ -606,7 +376,6 @@ private function isCurlException(RequestInterface $request, CurlHandle $handle, * Throw an exception for a cURL multi response if needed * * @param int $code Curl response code - * * @throws CurlException */ private function checkCurlResult($code) @@ -618,26 +387,4 @@ private function checkCurlResult($code) ); } } - - /** - * Create the new cURL multi handle with error checking - */ - private function createMultiHandle() - { - if ($this->multiHandle && is_resource($this->multiHandle)) { - curl_multi_close($this->multiHandle); - } - - $this->requests = array(); - $this->multiHandle = curl_multi_init(); - $this->handles = new \SplObjectStorage(); - $this->resourceHash = array(); - $this->removeHandles = array(); - - // @codeCoverageIgnoreStart - if ($this->multiHandle === false) { - throw new CurlException('Unable to create multi handle'); - } - // @codeCoverageIgnoreEnd - } } diff --git a/core/vendor/guzzle/http/Guzzle/Http/Curl/CurlMultiInterface.php b/core/vendor/guzzle/http/Guzzle/Http/Curl/CurlMultiInterface.php index ff39a1a..0ead757 100644 --- a/core/vendor/guzzle/http/Guzzle/Http/Curl/CurlMultiInterface.php +++ b/core/vendor/guzzle/http/Guzzle/Http/Curl/CurlMultiInterface.php @@ -9,20 +9,14 @@ /** * Interface for sending a pool of {@see RequestInterface} objects in parallel */ -interface CurlMultiInterface extends HasDispatcherInterface, \Countable +interface CurlMultiInterface extends \Countable, HasDispatcherInterface { - const BEFORE_SEND = 'curl_multi.before_send'; const POLLING_REQUEST = 'curl_multi.polling_request'; - const COMPLETE = 'curl_multi.complete'; const ADD_REQUEST = 'curl_multi.add_request'; const REMOVE_REQUEST = 'curl_multi.remove_request'; const MULTI_EXCEPTION = 'curl_multi.exception'; const BLOCKING = 'curl_multi.blocking'; - const STATE_IDLE = 'idle'; - const STATE_SENDING = 'sending'; - const STATE_COMPLETE = 'complete'; - /** * Add a request to the pool. * @@ -40,18 +34,11 @@ public function add(RequestInterface $request); public function all(); /** - * Get the current state of the Pool - * - * @return string - */ - public function getState(); - - /** * Remove a request from the pool. * * @param RequestInterface $request Request to remove * - * @return CurlMultiInterface + * @return bool Returns true on success or false on failure */ public function remove(RequestInterface $request); diff --git a/core/vendor/guzzle/http/Guzzle/Http/Curl/CurlMultiProxy.php b/core/vendor/guzzle/http/Guzzle/Http/Curl/CurlMultiProxy.php new file mode 100644 index 0000000..665f029 --- /dev/null +++ b/core/vendor/guzzle/http/Guzzle/Http/Curl/CurlMultiProxy.php @@ -0,0 +1,147 @@ +maxHandles = $maxHandles; + // You can get some weird "Too many open files" errors when sending a large amount of requests in parallel. + // These two statements autoload classes before a system runs out of file descriptors so that you can get back + // valuable error messages if you run out. + class_exists('Guzzle\Http\Message\Response'); + class_exists('Guzzle\Http\Exception\CurlException'); + } + + public function add(RequestInterface $request) + { + $this->queued[] = $request; + + return $this; + } + + public function all() + { + $requests = $this->queued; + foreach ($this->handles as $handle) { + $requests = array_merge($requests, $handle->all()); + } + + return $requests; + } + + public function remove(RequestInterface $request) + { + foreach ($this->queued as $i => $r) { + if ($request === $r) { + unset($this->queued[$i]); + return true; + } + } + + foreach ($this->handles as $handle) { + if ($handle->remove($request)) { + return true; + } + } + + return false; + } + + public function reset($hard = false) + { + $this->queued = array(); + $this->groups = array(); + foreach ($this->handles as $handle) { + $handle->reset(); + } + if ($hard) { + $this->handles = array(); + } + + return $this; + } + + public function send() + { + if ($this->queued) { + $group = $this->getAvailableHandle(); + // Add this handle to a list of handles than is claimed + $this->groups[] = $group; + while ($request = array_shift($this->queued)) { + $group->add($request); + } + try { + $group->send(); + array_pop($this->groups); + $this->cleanupHandles(); + } catch (\Exception $e) { + // Remove the group and cleanup if an exception was encountered and no more requests in group + if (!$group->count()) { + array_pop($this->groups); + $this->cleanupHandles(); + } + throw $e; + } + } + } + + public function count() + { + return count($this->all()); + } + + /** + * Get an existing available CurlMulti handle or create a new one + * + * @return CurlMulti + */ + protected function getAvailableHandle() + { + // Grab a handle that is not claimed + foreach ($this->handles as $h) { + if (!in_array($h, $this->groups, true)) { + return $h; + } + } + + // All are claimed, so create one + $handle = new CurlMulti(); + $handle->setEventDispatcher($this->getEventDispatcher()); + $this->handles[] = $handle; + + return $handle; + } + + /** + * Trims down unused CurlMulti handles to limit the number of open connections + */ + protected function cleanupHandles() + { + if ($diff = max(0, count($this->handles) - $this->maxHandles)) { + for ($i = count($this->handles) - 1; $i > 0 && $diff > 0; $i--) { + if (!count($this->handles[$i])) { + unset($this->handles[$i]); + $diff--; + } + } + $this->handles = array_values($this->handles); + } + } +} diff --git a/core/vendor/guzzle/http/Guzzle/Http/Curl/CurlVersion.php b/core/vendor/guzzle/http/Guzzle/Http/Curl/CurlVersion.php index 41f55ba..c3f99dd 100644 --- a/core/vendor/guzzle/http/Guzzle/Http/Curl/CurlVersion.php +++ b/core/vendor/guzzle/http/Guzzle/Http/Curl/CurlVersion.php @@ -7,24 +7,16 @@ */ class CurlVersion { - /** - * @var array curl_version() information - */ + /** @var array curl_version() information */ protected $version; - /** - * @var CurlVersion - */ + /** @var CurlVersion */ protected static $instance; - /** - * @var string Default user agent - */ + /** @var string Default user agent */ protected $userAgent; /** - * Get the singleton instance of the CurlVersion object - * * @return CurlVersion */ public static function getInstance() diff --git a/core/vendor/guzzle/http/Guzzle/Http/Curl/RequestMediator.php b/core/vendor/guzzle/http/Guzzle/Http/Curl/RequestMediator.php index b85bc08..54b1b0d 100644 --- a/core/vendor/guzzle/http/Guzzle/Http/Curl/RequestMediator.php +++ b/core/vendor/guzzle/http/Guzzle/Http/Curl/RequestMediator.php @@ -3,49 +3,28 @@ namespace Guzzle\Http\Curl; use Guzzle\Http\Message\RequestInterface; +use Guzzle\Http\EntityBody; +use Guzzle\Http\Message\Response; /** * Mediator between curl handles and request objects */ class RequestMediator { - /** - * @var RequestInterface - */ + /** @var RequestInterface */ protected $request; - /** - * @var bool Whether or not to emit read/write events - */ + /** @var bool Whether or not to emit read/write events */ protected $emitIo; /** - * @var CurlHandle - */ - protected $curlHandle; - - /** * @param RequestInterface $request Request to mediate + * @param bool $emitIo Set to true to dispatch events on input and output */ - public function __construct(RequestInterface $request) + public function __construct(RequestInterface $request, $emitIo = false) { $this->request = $request; - $this->emitIo = $request->getParams()->get('curl.emit_io'); - } - - /** - * Set the associated CurlHandle object - * - * @param CurlHandle $handle Curl handle - * - * @return RequestMediator - */ - public function setCurlHandle(CurlHandle $handle) - { - $this->curlHandle = $handle; - $this->request->getParams()->set('curl_handle', $handle); - - return $this; + $this->emitIo = $emitIo; } /** @@ -58,22 +37,59 @@ public function setCurlHandle(CurlHandle $handle) */ public function receiveResponseHeader($curl, $header) { - return $this->request->receiveResponseHeader($header); + static $normalize = array("\r", "\n"); + $length = strlen($header); + $header = str_replace($normalize, '', $header); + + if (strpos($header, 'HTTP/') === 0) { + + $startLine = explode(' ', $header, 3); + $code = $startLine[1]; + $status = isset($startLine[2]) ? $startLine[2] : ''; + + // Only download the body of the response to the specified response + // body when a successful response is received. + if ($code >= 200 && $code < 300) { + $body = $this->request->getResponseBody(); + } else { + $body = EntityBody::factory(); + } + + $response = new Response($code, null, $body); + $response->setStatus($code, $status); + $this->request->startResponse($response); + + $this->request->dispatch('request.receive.status_line', array( + 'request' => $this, + 'line' => $header, + 'status_code' => $code, + 'reason_phrase' => $status + )); + + } elseif ($pos = strpos($header, ':')) { + $this->request->getResponse()->addHeader( + trim(substr($header, 0, $pos)), + trim(substr($header, $pos + 1)) + ); + } + + return $length; } /** * Received a progress notification * - * @param int $downloadSize Total download size - * @param int $downloaded Amount of bytes downloaded - * @param int $uploadSize Total upload size - * @param int $uploaded Amount of bytes uploaded + * @param int $downloadSize Total download size + * @param int $downloaded Amount of bytes downloaded + * @param int $uploadSize Total upload size + * @param int $uploaded Amount of bytes uploaded + * @param resource $handle CurlHandle object */ - public function progress($downloadSize, $downloaded, $uploadSize, $uploaded) + public function progress($downloadSize, $downloaded, $uploadSize, $uploaded, $handle = null) { $this->request->dispatch('curl.callback.progress', array( 'request' => $this->request, - 'handle' => $this->curlHandle, + 'handle' => $handle, 'download_size' => $downloadSize, 'downloaded' => $downloaded, 'upload_size' => $uploadSize, @@ -112,18 +128,15 @@ public function writeResponseBody($curl, $write) */ public function readRequestBody($ch, $fd, $length) { - $read = ''; - - if ($this->request->getBody()) { - $read = $this->request->getBody()->read($length); - if ($this->emitIo) { - $this->request->dispatch('curl.callback.read', array( - 'request' => $this->request, - 'read' => $read - )); - } + if (!($body = $this->request->getBody())) { + return ''; + } + + $read = (string) $body->read($length); + if ($this->emitIo) { + $this->request->dispatch('curl.callback.read', array('request' => $this->request, 'read' => $read)); } - return !$read ? '' : $read; + return $read; } } diff --git a/core/vendor/guzzle/http/Guzzle/Http/EntityBody.php b/core/vendor/guzzle/http/Guzzle/Http/EntityBody.php index f9abbf9..b60d170 100644 --- a/core/vendor/guzzle/http/Guzzle/Http/EntityBody.php +++ b/core/vendor/guzzle/http/Guzzle/Http/EntityBody.php @@ -2,6 +2,7 @@ namespace Guzzle\Http; +use Guzzle\Common\Version; use Guzzle\Stream\Stream; use Guzzle\Common\Exception\InvalidArgumentException; use Guzzle\Http\Mimetypes; @@ -11,14 +12,10 @@ */ class EntityBody extends Stream implements EntityBodyInterface { - /** - * @var bool Content-Encoding of the entity body if known - */ + /** @var bool Content-Encoding of the entity body if known */ protected $contentEncoding = false; - /** - * @var callable Method to invoke for rewinding a stream - */ + /** @var callable Method to invoke for rewinding a stream */ protected $rewindFunction; /** @@ -53,9 +50,6 @@ public static function factory($resource = '', $size = null) throw new InvalidArgumentException('Invalid resource type'); } - /** - * {@inheritdoc} - */ public function setRewindFunction($callable) { if (!is_callable($callable)) { @@ -67,9 +61,6 @@ public function setRewindFunction($callable) return $this; } - /** - * {@inheritdoc} - */ public function rewind() { return $this->rewindFunction ? call_user_func($this->rewindFunction, $this) : parent::rewind(); @@ -85,15 +76,14 @@ public function rewind() public static function fromString($string) { $stream = fopen('php://temp', 'r+'); - fwrite($stream, $string); - rewind($stream); + if ($string !== '') { + fwrite($stream, $string); + rewind($stream); + } return new static($stream); } - /** - * {@inheritdoc} - */ public function compress($filter = 'zlib.deflate') { $result = $this->handleCompression($filter); @@ -102,9 +92,6 @@ public function compress($filter = 'zlib.deflate') return $result; } - /** - * {@inheritdoc} - */ public function uncompress($filter = 'zlib.inflate') { $offsetStart = 0; @@ -127,34 +114,23 @@ public function uncompress($filter = 'zlib.inflate') return $this->handleCompression($filter, $offsetStart); } - /** - * {@inheritdoc} - */ public function getContentLength() { return $this->getSize(); } - /** - * {@inheritdoc} - */ public function getContentType() { - if (!($this->isLocal() && $this->getWrapper() == 'plainfile' && file_exists($this->getUri()))) { - return 'application/octet-stream'; - } - - return Mimetypes::getInstance()->fromFilename($this->getUri()) ?: 'application/octet-stream'; + return $this->getUri() ? Mimetypes::getInstance()->fromFilename($this->getUri()) : null; } - /** - * {@inheritdoc} - */ public function getContentMd5($rawOutput = false, $base64Encode = false) { - $hash = self::getHash($this, 'md5', $rawOutput); - - return $hash && $base64Encode ? base64_encode($hash) : $hash; + if ($hash = self::getHash($this, 'md5', $rawOutput)) { + return $hash && $base64Encode ? base64_encode($hash) : $hash; + } else { + return false; + } } /** @@ -170,12 +146,10 @@ public function getContentMd5($rawOutput = false, $base64Encode = false) */ public static function calculateMd5(EntityBodyInterface $body, $rawOutput = false, $base64Encode = false) { + Version::warn(__CLASS__ . ' is deprecated. Use getContentMd5()'); return $body->getContentMd5($rawOutput, $base64Encode); } - /** - * {@inheritdoc} - */ public function setStreamFilterContentEncoding($streamFilterContentEncoding) { $this->contentEncoding = $streamFilterContentEncoding; @@ -183,9 +157,6 @@ public function setStreamFilterContentEncoding($streamFilterContentEncoding) return $this; } - /** - * {@inheritdoc} - */ public function getContentEncoding() { return strtr($this->contentEncoding, array( @@ -194,9 +165,6 @@ public function getContentEncoding() )) ?: false; } - /** - * {@inheritdoc} - */ protected function handleCompression($filter, $offsetStart = 0) { // @codeCoverageIgnoreStart diff --git a/core/vendor/guzzle/http/Guzzle/Http/EntityBodyInterface.php b/core/vendor/guzzle/http/Guzzle/Http/EntityBodyInterface.php index 97c90ff..e640f57 100644 --- a/core/vendor/guzzle/http/Guzzle/Http/EntityBodyInterface.php +++ b/core/vendor/guzzle/http/Guzzle/Http/EntityBodyInterface.php @@ -47,9 +47,9 @@ public function uncompress($filter = 'zlib.inflate'); public function getContentLength(); /** - * Guess the Content-Type or return the default application/octet-stream + * Guess the Content-Type of a local stream * - * @return string + * @return string|null * @see http://www.php.net/manual/en/function.finfo-open.php */ public function getContentType(); diff --git a/core/vendor/guzzle/http/Guzzle/Http/Exception/BadResponseException.php b/core/vendor/guzzle/http/Guzzle/Http/Exception/BadResponseException.php index e340095..9b98a86 100644 --- a/core/vendor/guzzle/http/Guzzle/Http/Exception/BadResponseException.php +++ b/core/vendor/guzzle/http/Guzzle/Http/Exception/BadResponseException.php @@ -10,9 +10,7 @@ */ class BadResponseException extends RequestException { - /** - * @var Response - */ + /** @var Response */ private $response; /** @@ -41,8 +39,6 @@ public static function factory(RequestInterface $request, Response $response) '[status code] ' . $response->getStatusCode(), '[reason phrase] ' . $response->getReasonPhrase(), '[url] ' . $request->getUrl(), - '[request] ' . (string) $request, - '[response] ' . (string) $response )); $e = new $class($message); diff --git a/core/vendor/guzzle/http/Guzzle/Http/Exception/MultiTransferException.php b/core/vendor/guzzle/http/Guzzle/Http/Exception/MultiTransferException.php index 27e4e58..5bea80f 100644 --- a/core/vendor/guzzle/http/Guzzle/Http/Exception/MultiTransferException.php +++ b/core/vendor/guzzle/http/Guzzle/Http/Exception/MultiTransferException.php @@ -98,4 +98,16 @@ public function getFailedRequests() { return $this->failedRequests; } + + /** + * Check if the exception object contains a request + * + * @param RequestInterface $request Request to check + * + * @return bool + */ + public function containsRequest(RequestInterface $request) + { + return in_array($request, $this->failedRequests, true) || in_array($request, $this->successfulRequests, true); + } } diff --git a/core/vendor/guzzle/http/Guzzle/Http/Exception/RequestException.php b/core/vendor/guzzle/http/Guzzle/Http/Exception/RequestException.php index 5fb274b..274df2c 100644 --- a/core/vendor/guzzle/http/Guzzle/Http/Exception/RequestException.php +++ b/core/vendor/guzzle/http/Guzzle/Http/Exception/RequestException.php @@ -10,9 +10,7 @@ */ class RequestException extends RuntimeException implements HttpException { - /** - * @var RequestInterface - */ + /** @var RequestInterface */ protected $request; /** diff --git a/core/vendor/guzzle/http/Guzzle/Http/IoEmittingEntityBody.php b/core/vendor/guzzle/http/Guzzle/Http/IoEmittingEntityBody.php index 15193c1..ae32dee 100644 --- a/core/vendor/guzzle/http/Guzzle/Http/IoEmittingEntityBody.php +++ b/core/vendor/guzzle/http/Guzzle/Http/IoEmittingEntityBody.php @@ -13,14 +13,9 @@ */ class IoEmittingEntityBody extends AbstractEntityBodyDecorator implements HasDispatcherInterface { - /** - * @var EventDispatcherInterface - */ + /** @var EventDispatcherInterface */ protected $eventDispatcher; - /** - * {@inheritdoc} - */ public static function getAllEvents() { return array('body.read', 'body.write'); @@ -37,9 +32,6 @@ public function setEventDispatcher(EventDispatcherInterface $eventDispatcher) return $this; } - /** - * {@inheritdoc} - */ public function getEventDispatcher() { if (!$this->eventDispatcher) { @@ -49,9 +41,6 @@ public function getEventDispatcher() return $this->eventDispatcher; } - /** - * {@inheritdoc} - */ public function dispatch($eventName, array $context = array()) { $this->getEventDispatcher()->dispatch($eventName, new Event($context)); @@ -68,9 +57,6 @@ public function addSubscriber(EventSubscriberInterface $subscriber) return $this; } - /** - * {@inheritdoc} - */ public function read($length) { $event = array( @@ -83,9 +69,6 @@ public function read($length) return $event['read']; } - /** - * {@inheritdoc} - */ public function write($string) { $event = array( diff --git a/core/vendor/guzzle/http/Guzzle/Http/Message/AbstractMessage.php b/core/vendor/guzzle/http/Guzzle/Http/Message/AbstractMessage.php index 4288a7e..0d066ff 100644 --- a/core/vendor/guzzle/http/Guzzle/Http/Message/AbstractMessage.php +++ b/core/vendor/guzzle/http/Guzzle/Http/Message/AbstractMessage.php @@ -2,61 +2,72 @@ namespace Guzzle\Http\Message; +use Guzzle\Common\Version; use Guzzle\Common\Collection; -use Guzzle\Common\Exception\InvalidArgumentException; +use Guzzle\Http\Message\Header\HeaderCollection; +use Guzzle\Http\Message\Header\HeaderFactory; +use Guzzle\Http\Message\Header\HeaderFactoryInterface; +use Guzzle\Http\Message\Header\HeaderInterface; /** * Abstract HTTP request/response message */ abstract class AbstractMessage implements MessageInterface { - /** - * @var array HTTP headers - */ - protected $headers = array(); + /** @var array HTTP header collection */ + protected $headers; - /** - * @var Collection Custom message parameters that are extendable by plugins - */ + /** @var HeaderFactoryInterface $headerFactory */ + protected $headerFactory; + + /** @var Collection Custom message parameters that are extendable by plugins */ protected $params; - /** - * @var array Cache-Control directive information - */ - private $cacheControl = array(); + /** @var string Message protocol */ + protected $protocol = 'HTTP'; - /* - * @var string HTTP protocol version of the message - */ + /** @var string HTTP protocol version of the message */ protected $protocolVersion = '1.1'; + public function __construct() + { + $this->params = new Collection(); + $this->headerFactory = new HeaderFactory(); + $this->headers = new HeaderCollection(); + } + /** - * {@inheritdoc} + * Set the header factory to use to create headers + * + * @param HeaderFactoryInterface $factory + * + * @return self */ + public function setHeaderFactory(HeaderFactoryInterface $factory) + { + $this->headerFactory = $factory; + + return $this; + } + public function getParams() { return $this->params; } - /** - * {@inheritdoc} - */ public function addHeader($header, $value) { - $key = strtolower($header); - if (!isset($this->headers[$key])) { - $this->headers[$key] = new Header($header, $value); + if (isset($this->headers[$header])) { + $this->headers[$header]->add($value); + } elseif ($value instanceof HeaderInterface) { + $this->headers[$header] = $value; } else { - $this->headers[$key]->add($value, $header); + $this->headers[$header] = $this->headerFactory->createHeader($header, $value); } - $this->changedHeader($key); return $this; } - /** - * {@inheritdoc} - */ public function addHeaders(array $headers) { foreach ($headers as $key => $value) { @@ -66,249 +77,144 @@ public function addHeaders(array $headers) return $this; } - /** - * {@inheritdoc} - */ - public function getHeader($header, $string = false) + public function getHeader($header) { - $key = strtolower($header); - if (!isset($this->headers[$key])) { - return null; - } - - return $string ? (string) $this->headers[$key] : $this->headers[$key]; + return $this->headers[$header]; } - /** - * {@inheritdoc} - */ - public function getHeaders($asObjects = false) + public function getHeaders() { - if ($asObjects) { - $result = $this->headers; - } else { - $result = array(); - // Convert all of the headers into a collection - foreach ($this->headers as $header) { - foreach ($header->raw() as $key => $value) { - $result[$key] = $value; - } - } - } - - return new Collection($result); + return $this->headers; } - /** - * {@inheritdoc} - */ public function getHeaderLines() { $headers = array(); foreach ($this->headers as $value) { - $glue = $value->getGlue(); - foreach ($value->raw() as $key => $v) { - $headers[] = rtrim($key . ': ' . implode($glue, $v)); - } + $headers[] = $value->getName() . ': ' . $value; } return $headers; } - /** - * {@inheritdoc} - */ public function setHeader($header, $value) { - // Remove any existing header - $key = strtolower($header); - unset($this->headers[$key]); - - if ($value instanceof Header) { - $this->headers[$key] = $value; - } else { - // Allow for 0, '', and NULL to be set - if (!$value) { - $value = array($value); - } - $this->headers[$key] = new Header($header, $value); - } - $this->changedHeader($key); + unset($this->headers[$header]); + $this->addHeader($header, $value); return $this; } - /** - * {@inheritdoc} - */ public function setHeaders(array $headers) { - // Get the keys that are changing - $changed = array_keys($this->headers); - // Erase the old headers - $this->headers = array(); - // Add the new headers + $this->headers->clear(); foreach ($headers as $key => $value) { - $changed[] = $key; $this->addHeader($key, $value); } - // Notify of the changed headers - foreach (array_unique($changed) as $header) { - $this->changedHeader(strtolower($header)); - } - return $this; } - /** - * {@inheritdoc} - */ public function hasHeader($header) { - return array_key_exists(strtolower($header), $this->headers); + return isset($this->headers[$header]); } - /** - * {@inheritdoc} - */ public function removeHeader($header) { - $header = strtolower($header); unset($this->headers[$header]); - $this->changedHeader($header); return $this; } /** - * {@inheritdoc} + * @deprecated Use $message->getHeader()->parseParams() + * @codeCoverageIgnore */ public function getTokenizedHeader($header, $token = ';') { - if (!$this->hasHeader($header)) { - return null; - } - - $data = new Collection(); - - foreach ($this->getHeader($header) as $singleValue) { - foreach (explode($token, $singleValue) as $kvp) { - $parts = explode('=', $kvp, 2); - if (!isset($parts[1])) { - $data[count($data)] = trim($parts[0]); - } else { - $data->add(trim($parts[0]), trim($parts[1])); + Version::warn(__METHOD__ . ' is deprecated. Use $message->getHeader()->parseParams()'); + if ($this->hasHeader($header)) { + $data = new Collection(); + foreach ($this->getHeader($header)->parseParams() as $values) { + foreach ($values as $key => $value) { + if ($value === '') { + $data->set($data->count(), $key); + } else { + $data->add($key, $value); + } } } + return $data; } - - foreach ($data as $key => $value) { - if (is_array($value)) { - $data->set($key, array_unique($value)); - } - } - - return $data; } /** - * {@inheritdoc} + * @deprecated + * @codeCoverageIgnore */ public function setTokenizedHeader($header, $data, $token = ';') { - if (!($data instanceof Collection) && !is_array($data)) { - throw new InvalidArgumentException('Data must be a Collection or array'); - } - - $values = array(); - foreach ($data as $key => $value) { - foreach ((array) $value as $v) { - $values[] = is_int($key) ? $v : $key . '=' . $v; - } - } - - return $this->setHeader($header, implode($token, $values)); + Version::warn(__METHOD__ . ' is deprecated.'); + return $this; } /** - * {@inheritdoc} + * @deprecated + * @codeCoverageIgnore */ public function getCacheControlDirective($directive) { - return isset($this->cacheControl[$directive]) ? $this->cacheControl[$directive] : null; + Version::warn(__METHOD__ . ' is deprecated. Use $message->getHeader(\'Cache-Control\')->getDirective()'); + if (!($header = $this->getHeader('Cache-Control'))) { + return null; + } + + return $header->getDirective($directive); } /** - * {@inheritdoc} + * @deprecated + * @codeCoverageIgnore */ public function hasCacheControlDirective($directive) { - return isset($this->cacheControl[$directive]); + Version::warn(__METHOD__ . ' is deprecated. Use $message->getHeader(\'Cache-Control\')->hasDirective()'); + if ($header = $this->getHeader('Cache-Control')) { + return $header->hasDirective($directive); + } else { + return false; + } } /** - * {@inheritdoc} + * @deprecated + * @codeCoverageIgnore */ public function addCacheControlDirective($directive, $value = true) { - $this->cacheControl[$directive] = $value; - $this->rebuildCacheControlDirective(); + Version::warn(__METHOD__ . ' is deprecated. Use $message->getHeader(\'Cache-Control\')->addDirective()'); + if (!($header = $this->getHeader('Cache-Control'))) { + $this->addHeader('Cache-Control', ''); + $header = $this->getHeader('Cache-Control'); + } + + $header->addDirective($directive, $value); return $this; } /** - * {@inheritdoc} + * @deprecated + * @codeCoverageIgnore */ public function removeCacheControlDirective($directive) { - if (array_key_exists($directive, $this->cacheControl)) { - unset($this->cacheControl[$directive]); - $this->rebuildCacheControlDirective(); + Version::warn(__METHOD__ . ' is deprecated. Use $message->getHeader(\'Cache-Control\')->removeDirective()'); + if ($header = $this->getHeader('Cache-Control')) { + $header->removeDirective($directive); } return $this; } - - /** - * Check to see if the modified headers need to reset any of the managed - * headers like cache-control - * - * @param string $header Header that changed - */ - protected function changedHeader($header) - { - if ($header == 'cache-control') { - $this->parseCacheControlDirective(); - } - } - - /** - * Parse the Cache-Control HTTP header into an array - */ - private function parseCacheControlDirective() - { - $this->cacheControl = array(); - $tokenized = $this->getTokenizedHeader('Cache-Control', ',') ?: array(); - foreach ($tokenized as $key => $value) { - if (is_numeric($key)) { - $this->cacheControl[$value] = true; - } else { - $this->cacheControl[$key] = $value; - } - } - } - - /** - * Rebuild the Cache-Control HTTP header using the user-specified values - */ - private function rebuildCacheControlDirective() - { - $cacheControl = array(); - foreach ($this->cacheControl as $key => $value) { - $cacheControl[] = ($value === true) ? $key : ($key . '=' . $value); - } - $this->headers['cache-control'] = new Header('Cache-Control', $cacheControl, ', '); - } } diff --git a/core/vendor/guzzle/http/Guzzle/Http/Message/EntityEnclosingRequest.php b/core/vendor/guzzle/http/Guzzle/Http/Message/EntityEnclosingRequest.php index 46bd515..d9c83d8 100644 --- a/core/vendor/guzzle/http/Guzzle/Http/Message/EntityEnclosingRequest.php +++ b/core/vendor/guzzle/http/Guzzle/Http/Message/EntityEnclosingRequest.php @@ -7,45 +7,32 @@ use Guzzle\Http\QueryString; use Guzzle\Http\RedirectPlugin; use Guzzle\Http\Exception\RequestException; +use Guzzle\Http\Mimetypes; /** * HTTP request that sends an entity-body in the request message (POST, PUT, PATCH, DELETE) */ class EntityEnclosingRequest extends Request implements EntityEnclosingRequestInterface { - /** - * @var int When the size of the body is greater than 1MB, then send Expect: 100-Continue - */ + /** @var int When the size of the body is greater than 1MB, then send Expect: 100-Continue */ protected $expectCutoff = 1048576; - /** - * @var EntityBodyInterface $body Body of the request - */ + /** @var EntityBodyInterface $body Body of the request */ protected $body; - /** - * @var QueryString POST fields to use in the EntityBody - */ + /** @var QueryString POST fields to use in the EntityBody */ protected $postFields; - /** - * @var array POST files to send with the request - */ + /** @var array POST files to send with the request */ protected $postFiles = array(); - /** - * {@inheritdoc} - */ public function __construct($method, $url, $headers = array()) { $this->postFields = new QueryString(); - $this->postFields->setPrefix(''); parent::__construct($method, $url, $headers); } /** - * Get the HTTP request as a string - * * @return string */ public function __toString() @@ -58,9 +45,6 @@ public function __toString() return parent::__toString() . $this->body; } - /** - * {@inheritdoc} - */ public function setState($state, array $context = array()) { parent::setState($state, $context); @@ -68,19 +52,20 @@ public function setState($state, array $context = array()) $this->setHeader('Content-Length', 0)->removeHeader('Transfer-Encoding'); } - return $this; + return $this->state; } - /** - * {@inheritdoc} - */ - public function setBody($body, $contentType = null, $tryChunkedTransfer = false) + public function setBody($body, $contentType = null) { $this->body = EntityBody::factory($body); - $this->removeHeader('Content-Length'); + + // Auto detect the Content-Type from the path of the request if possible + if ($contentType === null && !$this->hasHeader('Content-Type')) { + $contentType = $this->body->getContentType() ?: Mimetypes::getInstance()->fromFilename($this->getPath()); + } if ($contentType) { - $this->setHeader('Content-Type', (string) $contentType); + $this->setHeader('Content-Type', $contentType); } // Always add the Expect 100-Continue header if the body cannot be rewound. This helps with redirects. @@ -88,18 +73,15 @@ public function setBody($body, $contentType = null, $tryChunkedTransfer = false) $this->setHeader('Expect', '100-Continue'); } - if ($tryChunkedTransfer) { - $this->setHeader('Transfer-Encoding', 'chunked'); - } else { - $this->removeHeader('Transfer-Encoding'); - // Set the Content-Length header if it can be determined - $size = $this->body->getContentLength(); - if ($size !== null && $size !== false) { - $this->setHeader('Content-Length', $size); - if ($size > $this->expectCutoff) { - $this->setHeader('Expect', '100-Continue'); - } - } elseif ('1.1' == $this->protocolVersion) { + // Set the Content-Length header if it can be determined + $size = $this->body->getContentLength(); + if ($size !== null && $size !== false) { + $this->setHeader('Content-Length', $size); + if ($size > $this->expectCutoff) { + $this->setHeader('Expect', '100-Continue'); + } + } elseif (!$this->hasHeader('Content-Length')) { + if ('1.1' == $this->protocolVersion) { $this->setHeader('Transfer-Encoding', 'chunked'); } else { throw new RequestException( @@ -111,9 +93,6 @@ public function setBody($body, $contentType = null, $tryChunkedTransfer = false) return $this; } - /** - * {@inheritdoc} - */ public function getBody() { return $this->body; @@ -138,9 +117,6 @@ public function setExpectHeaderCutoff($size) return $this; } - /** - * {@inheritdoc} - */ public function configureRedirects($strict = false, $maxRedirects = 5) { $this->getParams()->set(RedirectPlugin::STRICT_REDIRECTS, $strict); @@ -153,25 +129,16 @@ public function configureRedirects($strict = false, $maxRedirects = 5) return $this; } - /** - * {@inheritdoc} - */ public function getPostField($field) { return $this->postFields->get($field); } - /** - * {@inheritdoc} - */ public function getPostFields() { return $this->postFields; } - /** - * {@inheritdoc} - */ public function setPostField($key, $value) { $this->postFields->set($key, $value); @@ -180,9 +147,6 @@ public function setPostField($key, $value) return $this; } - /** - * {@inheritdoc} - */ public function addPostFields($fields) { $this->postFields->merge($fields); @@ -191,9 +155,6 @@ public function addPostFields($fields) return $this; } - /** - * {@inheritdoc} - */ public function removePostField($field) { $this->postFields->remove($field); @@ -202,25 +163,16 @@ public function removePostField($field) return $this; } - /** - * {@inheritdoc} - */ public function getPostFiles() { return $this->postFiles; } - /** - * {@inheritdoc} - */ public function getPostFile($fieldName) { return isset($this->postFiles[$fieldName]) ? $this->postFiles[$fieldName] : null; } - /** - * {@inheritdoc} - */ public function removePostFile($fieldName) { unset($this->postFiles[$fieldName]); @@ -229,15 +181,18 @@ public function removePostFile($fieldName) return $this; } - /** - * {@inheritdoc} - */ public function addPostFile($field, $filename = null, $contentType = null) { $data = null; if ($field instanceof PostFileInterface) { $data = $field; + } elseif (is_array($filename)) { + // Allow multiple values to be set in a single key + foreach ($filename as $file) { + $this->addPostFile($field, $file, $contentType); + } + return $this; } elseif (!is_string($filename)) { throw new RequestException('The path to a file must be a string'); } elseif (!empty($filename)) { @@ -257,9 +212,6 @@ public function addPostFile($field, $filename = null, $contentType = null) return $this; } - /** - * {@inheritdoc} - */ public function addPostFiles(array $files) { foreach ($files as $key => $file) { @@ -284,7 +236,7 @@ public function addPostFiles(array $files) */ protected function processPostFields() { - if (empty($this->postFiles)) { + if (!$this->postFiles) { $this->removeHeader('Expect')->setHeader('Content-Type', self::URL_ENCODED); } else { $this->setHeader('Content-Type', self::MULTIPART); diff --git a/core/vendor/guzzle/http/Guzzle/Http/Message/EntityEnclosingRequestInterface.php b/core/vendor/guzzle/http/Guzzle/Http/Message/EntityEnclosingRequestInterface.php index 8ddd42d..d9c037d 100644 --- a/core/vendor/guzzle/http/Guzzle/Http/Message/EntityEnclosingRequestInterface.php +++ b/core/vendor/guzzle/http/Guzzle/Http/Message/EntityEnclosingRequestInterface.php @@ -11,21 +11,19 @@ */ interface EntityEnclosingRequestInterface extends RequestInterface { - const URL_ENCODED = 'application/x-www-form-urlencoded'; + const URL_ENCODED = 'application/x-www-form-urlencoded; charset=utf-8'; const MULTIPART = 'multipart/form-data'; /** * Set the body of the request * - * @param string|resource|EntityBodyInterface $body Body to use in the entity body of the request - * @param string $contentType Content-Type to set. Leave null to use an existing - * Content-Type or to guess the Content-Type - * @param bool $tryChunkedTransfer Try to use chunked Transfer-Encoding - * - * @return EntityEnclosingRequestInterface + * @param string|resource|EntityBodyInterface $body Body to use in the entity body of the request + * @param string $contentType Content-Type to set. Leave null to use an existing + * Content-Type or to guess the Content-Type + * @return self * @throws RequestException if the protocol is < 1.1 and Content-Length can not be determined */ - public function setBody($body, $contentType = null, $tryChunkedTransfer = false); + public function setBody($body, $contentType = null); /** * Get the body of the request if set @@ -56,7 +54,7 @@ public function getPostFields(); * @param string $key Key to set * @param string $value Value to set * - * @return EntityEnclosingRequestInterface + * @return self */ public function setPostField($key, $value); @@ -65,7 +63,7 @@ public function setPostField($key, $value); * * @param QueryString|array $fields POST fields * - * @return EntityEnclosingRequestInterface + * @return self */ public function addPostFields($fields); @@ -74,7 +72,7 @@ public function addPostFields($fields); * * @param string $field Name of the POST field or file to remove * - * @return EntityEnclosingRequestInterface + * @return self */ public function removePostField($field); @@ -99,7 +97,7 @@ public function getPostFile($fieldName); * * @param string $fieldName POST file field name to remove * - * @return EntityEnclosingRequestInterface + * @return self */ public function removePostFile($fieldName); @@ -110,8 +108,7 @@ public function removePostFile($fieldName); * @param string $filename Full path to the file. Do not include the @ symbol. * @param string $contentType Optional Content-Type to add to the Content-Disposition. * Default behavior is to guess. Set to false to not specify. - * - * @return EntityEnclosingRequestInterface + * @return self */ public function addPostFile($field, $filename = null, $contentType = null); @@ -120,7 +117,7 @@ public function addPostFile($field, $filename = null, $contentType = null); * * @param array $files An array of POST fields => filenames where filename can be a string or PostFileInterface * - * @return EntityEnclosingRequestInterface + * @return self */ public function addPostFiles(array $files); diff --git a/core/vendor/guzzle/http/Guzzle/Http/Message/Header.php b/core/vendor/guzzle/http/Guzzle/Http/Message/Header.php index 9233b4d..b919166 100644 --- a/core/vendor/guzzle/http/Guzzle/Http/Message/Header.php +++ b/core/vendor/guzzle/http/Guzzle/Http/Message/Header.php @@ -2,249 +2,176 @@ namespace Guzzle\Http\Message; -use Guzzle\Common\ToArrayInterface; +use Guzzle\Common\Version; +use Guzzle\Http\Message\Header\HeaderInterface; /** * Represents a header and all of the values stored by that header */ -class Header implements ToArrayInterface, \IteratorAggregate, \Countable +class Header implements HeaderInterface { protected $values = array(); protected $header; protected $glue; - protected $stringCache; - protected $arrayCache; /** - * Construct a new header object - * - * @param string $header Name of the header - * @param array $values Values of the header - * @param string $glue Glue used to combine multiple values into a string + * @param string $header Name of the header + * @param array|string $values Values of the header as an array or a scalar + * @param string $glue Glue used to combine multiple values into a string */ - public function __construct($header, $values = array(), $glue = ', ') + public function __construct($header, $values = array(), $glue = ',') { - $this->header = $header; + $this->header = trim($header); $this->glue = $glue; - if (null !== $values) { - foreach ((array) $values as $key => $value) { - if (is_numeric($key)) { - $key = $header; - } - if ($value === null) { - $this->add($value, $key); - } else { - foreach ((array) $value as $v) { - $this->add($v, $key); - } - } + foreach ((array) $values as $value) { + foreach ((array) $value as $v) { + $this->values[] = $v; } } } - /** - * Convert the header to a string - * - * @return string - */ public function __toString() { - if (!$this->stringCache) { - $this->stringCache = implode($this->glue, $this->toArray()); - } - - return $this->stringCache; + return implode($this->glue . ' ', $this->toArray()); } - /** - * Add a value to the list of header values - * - * @param string $value Value to add - * @param string $header The exact header casing to add with. Defaults to the name of the header. - * - * @return Header - */ - public function add($value, $header = null) + public function add($value) { - if (!$header) { - $header = $this->getName(); - } - - if (!array_key_exists($header, $this->values)) { - $this->values[$header] = array($value); - } else { - $this->values[$header][] = $value; - } - - $this->clearCache(); + $this->values[] = $value; return $this; } - /** - * Get the name of the header - * - * @return string - */ public function getName() { return $this->header; } - /** - * Change the glue used to implode the values - * - * @param string $glue Glue used to implode multiple values - * - * @return Header - */ + public function setName($name) + { + $this->header = $name; + + return $this; + } + public function setGlue($glue) { $this->glue = $glue; - $this->stringCache = null; return $this; } - /** - * Get the glue used to implode multiple values into a string - * - * @return string - */ public function getGlue() { return $this->glue; } /** - * Normalize the header into a single standard header with an array of values + * Normalize the header to be a single header with an array of values. + * + * If any values of the header contains the glue string value (e.g. ","), then the value will be exploded into + * multiple entries in the header. * - * @return Header + * @return self */ public function normalize() { - $this->clearCache(); - $this->values = array( - $this->getName() => $this->toArray() - ); + $values = $this->toArray(); + + for ($i = 0, $total = count($values); $i < $total; $i++) { + if (strpos($values[$i], $this->glue) !== false) { + foreach (explode($this->glue, $values[$i]) as $v) { + $values[] = trim($v); + } + unset($values[$i]); + } + } + + $this->values = array_values($values); return $this; } - /** - * Check if a particular case variation is present in the header - * Example: A header exists on a message for 'Foo', and 'foo'. The Header object will contain all of the values of - * 'Foo' and all of the values of 'foo'. You can use this method to check to see if a header was set using - * 'foo' (true), 'Foo' (true), 'FOO' (false), etc. - * - * @param string $header Exact header to check for - * - * @return bool - */ - public function hasExactHeader($header) + public function hasValue($searchValue) { - return array_key_exists($header, $this->values); + return in_array($searchValue, $this->toArray()); } - /** - * Check if the collection of headers has a particular value - * - * @param string $searchValue Value to search for - * @param bool $caseInsensitive Set to TRUE to use a case insensitive search - * - * @return bool - */ - public function hasValue($searchValue, $caseInsensitive = false) + public function removeValue($searchValue) { - foreach ($this->toArray() as $value) { - if ($value == $searchValue) { - return true; - } elseif ($caseInsensitive && !strcasecmp($value, $searchValue)) { - return true; - } - } + $this->values = array_values(array_filter($this->values, function ($value) use ($searchValue) { + return $value != $searchValue; + })); - return false; + return $this; } - /** - * Remove a specific value from the header - * - * @param string $value Value to remove - * - * @return self - */ - public function removeValue($searchValue) + public function toArray() { - foreach ($this->values as $key => $values) { - foreach ($values as $index => $value) { - if ($value == $searchValue) { - unset($this->values[$key][$index]); - $this->clearCache(); - break 2; - } - } - } + return $this->values; + } - return $this; + public function count() + { + return count($this->toArray()); } - /** - * Get all of the header values as a flat array - * {@inheritdoc} - */ - public function toArray() + public function getIterator() { - if (!$this->arrayCache) { - $this->arrayCache = array(); - foreach ($this->values as $values) { - foreach ($values as $value) { - $this->arrayCache[] = $value; - } + return new \ArrayIterator($this->toArray()); + } + + public function parseParams() + { + $params = $matches = array(); + $callback = array($this, 'trimHeader'); + + // Normalize the header into a single array and iterate over all values + foreach ($this->normalize()->toArray() as $val) { + $part = array(); + foreach (preg_split('/;(?=([^"]*"[^"]*")*[^"]*$)/', $val) as $kvp) { + preg_match_all('/<[^>]+>|[^=]+/', $kvp, $matches); + $pieces = array_map($callback, $matches[0]); + $part[$pieces[0]] = isset($pieces[1]) ? $pieces[1] : ''; } + $params[] = $part; } - return $this->arrayCache; + return $params; } /** - * Get the raw data array of the headers. This array is represented as an associative array of the various cases - * that might be stored in the header and an array of values associated with each case variation. - * - * @return array + * @deprecated + * @codeCoverageIgnore */ - public function raw() + public function hasExactHeader($header) { - return $this->values; + Version::warn(__METHOD__ . ' is deprecated'); + return $this->header == $header; } /** - * Returns the total number of header values - * - * @return int + * @deprecated + * @codeCoverageIgnore */ - public function count() + public function raw() { - return count($this->toArray()); + Version::warn(__METHOD__ . ' is deprecated. Use toArray()'); + return $this->toArray(); } /** - * Get an iterator that can be used to easily iterate over each header value + * Trim a header by removing excess spaces and wrapping quotes * - * @return \ArrayIterator + * @param $str + * + * @return string */ - public function getIterator() + protected function trimHeader($str) { - return new \ArrayIterator($this->toArray()); - } + static $trimmed = "\"' \n\t"; - /** - * Clear the internal header cache - */ - private function clearCache() - { - $this->arrayCache = null; - $this->stringCache = null; + return trim($str, $trimmed); } } diff --git a/core/vendor/guzzle/http/Guzzle/Http/Message/Header/CacheControl.php b/core/vendor/guzzle/http/Guzzle/Http/Message/Header/CacheControl.php new file mode 100644 index 0000000..77789e5 --- /dev/null +++ b/core/vendor/guzzle/http/Guzzle/Http/Message/Header/CacheControl.php @@ -0,0 +1,121 @@ +directives = null; + } + + public function removeValue($searchValue) + { + parent::removeValue($searchValue); + $this->directives = null; + } + + /** + * Check if a specific cache control directive exists + * + * @param string $param Directive to retrieve + * + * @return bool + */ + public function hasDirective($param) + { + $directives = $this->getDirectives(); + + return isset($directives[$param]); + } + + /** + * Get a specific cache control directive + * + * @param string $param Directive to retrieve + * + * @return string|bool|null + */ + public function getDirective($param) + { + $directives = $this->getDirectives(); + + return isset($directives[$param]) ? $directives[$param] : null; + } + + /** + * Add a cache control directive + * + * @param string $param Directive to add + * @param string $value Value to set + * + * @return self + */ + public function addDirective($param, $value) + { + $directives = $this->getDirectives(); + $directives[$param] = $value; + $this->updateFromDirectives($directives); + + return $this; + } + + /** + * Remove a cache control directive by name + * + * @param string $param Directive to remove + * + * @return self + */ + public function removeDirective($param) + { + $directives = $this->getDirectives(); + unset($directives[$param]); + $this->updateFromDirectives($directives); + + return $this; + } + + /** + * Get an associative array of cache control directives + * + * @return array + */ + public function getDirectives() + { + if ($this->directives === null) { + $this->directives = array(); + foreach ($this->parseParams() as $collection) { + foreach ($collection as $key => $value) { + $this->directives[$key] = $value === '' ? true : $value; + } + } + } + + return $this->directives; + } + + /** + * Updates the header value based on the parsed directives + * + * @param array $directives Array of cache control directives + */ + protected function updateFromDirectives(array $directives) + { + $this->directives = $directives; + $this->values = array(); + + foreach ($directives as $key => $value) { + $this->values[] = $value === true ? $key : "{$key}={$value}"; + } + } +} diff --git a/core/vendor/guzzle/http/Guzzle/Http/Message/Header/HeaderCollection.php b/core/vendor/guzzle/http/Guzzle/Http/Message/Header/HeaderCollection.php new file mode 100644 index 0000000..ec282d9 --- /dev/null +++ b/core/vendor/guzzle/http/Guzzle/Http/Message/Header/HeaderCollection.php @@ -0,0 +1,109 @@ +headers = $headers; + } + + public function __clone() + { + foreach ($this->headers as &$header) { + $header = clone $header; + } + } + + /** + * Clears the header collection + */ + public function clear() + { + $this->headers = array(); + } + + /** + * Set a header on the collection + * + * @param HeaderInterface $header Header to add + * + * @return self + */ + public function add(HeaderInterface $header) + { + $this->headers[strtolower($header->getName())] = $header; + + return $this; + } + + /** + * Get an array of header objects + * + * @return array + */ + public function getAll() + { + return $this->headers; + } + + /** + * Alias of offsetGet + */ + public function get($key) + { + return $this->offsetGet($key); + } + + public function count() + { + return count($this->headers); + } + + public function offsetExists($offset) + { + return isset($this->headers[strtolower($offset)]); + } + + public function offsetGet($offset) + { + $l = strtolower($offset); + + return isset($this->headers[$l]) ? $this->headers[$l] : null; + } + + public function offsetSet($offset, $value) + { + $this->add($value); + } + + public function offsetUnset($offset) + { + unset($this->headers[strtolower($offset)]); + } + + public function getIterator() + { + return new \ArrayIterator($this->headers); + } + + public function toArray() + { + $result = array(); + foreach ($this->headers as $header) { + $result[$header->getName()] = $header->toArray(); + } + + return $result; + } +} diff --git a/core/vendor/guzzle/http/Guzzle/Http/Message/Header/HeaderFactory.php b/core/vendor/guzzle/http/Guzzle/Http/Message/Header/HeaderFactory.php new file mode 100644 index 0000000..0273be5 --- /dev/null +++ b/core/vendor/guzzle/http/Guzzle/Http/Message/Header/HeaderFactory.php @@ -0,0 +1,26 @@ + 'Guzzle\Http\Message\Header\CacheControl', + 'link' => 'Guzzle\Http\Message\Header\Link', + ); + + public function createHeader($header, $value = null) + { + $lowercase = strtolower($header); + + return isset($this->mapping[$lowercase]) + ? new $this->mapping[$lowercase]($header, $value) + : new Header($header, $value); + } +} diff --git a/core/vendor/guzzle/http/Guzzle/Http/Message/Header/HeaderFactoryInterface.php b/core/vendor/guzzle/http/Guzzle/Http/Message/Header/HeaderFactoryInterface.php new file mode 100644 index 0000000..9457cf6 --- /dev/null +++ b/core/vendor/guzzle/http/Guzzle/Http/Message/Header/HeaderFactoryInterface.php @@ -0,0 +1,19 @@ +", "rel=\"{$rel}\""); + + foreach ($params as $k => $v) { + $values[] = "{$k}=\"{$v}\""; + } + + return $this->add(implode('; ', $values)); + } + + /** + * Check if a specific link exists for a given rel attribute + * + * @param string $rel rel value + * + * @return bool + */ + public function hasLink($rel) + { + return $this->getLink($rel) !== null; + } + + /** + * Get a specific link for a given rel attribute + * + * @param string $rel Rel value + * + * @return array|null + */ + public function getLink($rel) + { + foreach ($this->getLinks() as $link) { + if (isset($link['rel']) && $link['rel'] == $rel) { + return $link; + } + } + + return null; + } + + /** + * Get an associative array of links + * + * For example: + * Link: ; rel=front; type="image/jpeg", ; rel=back; type="image/jpeg" + * + * + * var_export($response->getLinks()); + * array( + * array( + * 'url' => 'http:/.../front.jpeg', + * 'rel' => 'back', + * 'type' => 'image/jpeg', + * ) + * ) + * + * + * @return array + */ + public function getLinks() + { + $links = $this->parseParams(); + + foreach ($links as &$link) { + $key = key($link); + unset($link[$key]); + $link['url'] = trim($key, '<> '); + } + + return $links; + } +} diff --git a/core/vendor/guzzle/http/Guzzle/Http/Message/HeaderComparison.php b/core/vendor/guzzle/http/Guzzle/Http/Message/HeaderComparison.php deleted file mode 100644 index 5ef64b4..0000000 --- a/core/vendor/guzzle/http/Guzzle/Http/Message/HeaderComparison.php +++ /dev/null @@ -1,128 +0,0 @@ -getAll(); - } - - foreach ($filteredHeaders as $k => $v) { - if ($k[0] == '_') { - // This header should be ignored - $ignore[] = str_replace('_', '', $k); - } elseif ($k[0] == '!') { - // This header must not be present - $absent[] = str_replace('!', '', $k); - } else { - $expected[$k] = $v; - } - } - - return $this->compareArray($expected, $actualHeaders, $ignore, $absent); - } - - /** - * Check if an array of HTTP headers matches another array of HTTP headers while taking * into account as a wildcard - * - * @param array $expected Expected HTTP headers (allows wildcard values) - * @param array|Collection $actual Actual HTTP header array - * @param array $ignore Headers to ignore from the comparison - * @param array $absent Array of headers that must not be present - * - * @return array|bool Returns an array of the differences or FALSE if none - */ - public function compareArray(array $expected, $actual, array $ignore = array(), array $absent = array()) - { - $differences = array(); - - // Add information about headers that were present but weren't supposed to be - foreach ($absent as $header) { - if ($this->hasKey($header, $actual)) { - $differences["++ {$header}"] = $actual[$header]; - unset($actual[$header]); - } - } - - // Check if expected headers are missing - foreach ($expected as $header => $value) { - if (!$this->hasKey($header, $actual)) { - $differences["- {$header}"] = $value; - } - } - - // Flip the ignore array so it works with the case insensitive helper - $ignore = array_flip($ignore); - // Allow case-insensitive comparisons in wildcards - $expected = array_change_key_case($expected); - - // Compare the expected and actual HTTP headers in no particular order - foreach ($actual as $key => $value) { - - // If this is to be ignored, the skip it - if ($this->hasKey($key, $ignore)) { - continue; - } - - // If the header was not expected - if (!$this->hasKey($key, $expected)) { - $differences["+ {$key}"] = $value; - continue; - } - - // Check values and take wildcards into account - $lkey = strtolower($key); - $pos = is_string($expected[$lkey]) ? strpos($expected[$lkey], '*') : false; - - foreach ((array) $actual[$key] as $v) { - if (($pos === false && $v != $expected[$lkey]) || $pos > 0 && substr($v, 0, $pos) != substr($expected[$lkey], 0, $pos)) { - $differences[$key] = "{$value} != {$expected[$lkey]}"; - } - } - } - - return empty($differences) ? false : $differences; - } - - /** - * Case insensitive check if an array have a key - * - * @param string $key Key to check - * @param array $array Array to check - * - * @return bool - */ - protected function hasKey($key, $array) - { - foreach (array_keys($array) as $k) { - if (!strcasecmp($k, $key)) { - return true; - } - } - - return false; - } -} diff --git a/core/vendor/guzzle/http/Guzzle/Http/Message/MessageInterface.php b/core/vendor/guzzle/http/Guzzle/Http/Message/MessageInterface.php index 9b45e06..62bcd43 100644 --- a/core/vendor/guzzle/http/Guzzle/Http/Message/MessageInterface.php +++ b/core/vendor/guzzle/http/Guzzle/Http/Message/MessageInterface.php @@ -2,9 +2,6 @@ namespace Guzzle\Http\Message; -use Guzzle\Common\Exception\InvalidArgumentException; -use Guzzle\Common\Collection; - /** * Request and response message interface */ @@ -13,7 +10,7 @@ /** * Get application and plugin specific parameters set on the message. * - * @return Collection + * @return \Guzzle\Common\Collection */ public function getParams(); @@ -23,7 +20,7 @@ public function getParams(); * @param string $header Header name to add * @param string $value Value of the header * - * @return MessageInterface + * @return self */ public function addHeader($header, $value); @@ -32,7 +29,7 @@ public function addHeader($header, $value); * * @param array $headers Associative array of header data. * - * @return MessageInterface + * @return self */ public function addHeaders(array $headers); @@ -40,57 +37,24 @@ public function addHeaders(array $headers); * Retrieve an HTTP header by name. Performs a case-insensitive search of all headers. * * @param string $header Header to retrieve. - * @param bool $string Set to true to get the header as a string - * - * @return string|Header|null Returns NULL if no matching header is found. Returns a string if $string is set to - * TRUE. Returns a Header object if a matching header is found. - */ - public function getHeader($header, $string = false); - - /** - * Get a tokenized header as a Collection - * - * @param string $header Header to retrieve - * @param string $token Token separator - * - * @return Collection|null - */ - public function getTokenizedHeader($header, $token = ';'); - - /** - * Set a tokenized header on the request that implodes a Collection of data into a string separated by a token. - * - * @param string $header Header to set - * @param array|Collection $data Header data - * @param string $token Token delimiter * - * @return MessageInterface - * @throws InvalidArgumentException if data is not an array or Collection + * @return Header|null */ - public function setTokenizedHeader($header, $data, $token = ';'); + public function getHeader($header); /** * Get all headers as a collection * - * @param bool $asObjects Set to true to retrieve a collection of Header objects - * - * @return Collection Returns a {@see Collection} of all headers + * @return \Guzzle\Http\Message\Header\HeaderCollection */ - public function getHeaders($asObjects = false); - - /** - * Get an array of message header lines - * - * @return array - */ - public function getHeaderLines(); + public function getHeaders(); /** * Check if the specified header is present. * * @param string $header The header to check. * - * @return bool Returns TRUE or FALSE if the header is present + * @return bool */ public function hasHeader($header); @@ -99,17 +63,17 @@ public function hasHeader($header); * * @param string $header HTTP header to remove. * - * @return MessageInterface + * @return self */ public function removeHeader($header); /** - * Set an HTTP header + * Set an HTTP header and overwrite any existing value for the header * * @param string $header Name of the header to set. * @param mixed $value Value to set. * - * @return MessageInterface + * @return self */ public function setHeader($header, $value); @@ -118,51 +82,21 @@ public function setHeader($header, $value); * * @param array $headers Associative array of header data. * - * @return MessageInterface + * @return self */ public function setHeaders(array $headers); /** - * Get the raw message headers as a string - * - * @return string - */ - public function getRawHeaders(); - - /** - * Get a Cache-Control directive from the message - * - * @param string $directive Directive to retrieve - * - * @return null|string - */ - public function getCacheControlDirective($directive); - - /** - * Check if the message has a Cache-Control directive - * - * @param string $directive Directive to check - * - * @return bool - */ - public function hasCacheControlDirective($directive); - - /** - * Add a Cache-Control directive on the message - * - * @param string $directive Directive to set - * @param bool|string $value Value to set + * Get an array of message header lines (e.g. ["Host: example.com", ...]) * - * @return MessageInterface + * @return array */ - public function addCacheControlDirective($directive, $value = true); + public function getHeaderLines(); /** - * Remove a Cache-Control directive from the message - * - * @param string $directive Directive to remove + * Get the raw message headers as a string * - * @return MessageInterface + * @return string */ - public function removeCacheControlDirective($directive); + public function getRawHeaders(); } diff --git a/core/vendor/guzzle/http/Guzzle/Http/Message/PostFile.php b/core/vendor/guzzle/http/Guzzle/Http/Message/PostFile.php index 54f0fed..0beb7a7 100644 --- a/core/vendor/guzzle/http/Guzzle/Http/Message/PostFile.php +++ b/core/vendor/guzzle/http/Guzzle/Http/Message/PostFile.php @@ -2,6 +2,7 @@ namespace Guzzle\Http\Message; +use Guzzle\Common\Version; use Guzzle\Common\Exception\InvalidArgumentException; use Guzzle\Http\Mimetypes; @@ -26,9 +27,6 @@ public function __construct($fieldName, $filename, $contentType = null) $this->contentType = $contentType ?: $this->guessContentType(); } - /** - * {@inheritdoc} - */ public function setFieldName($name) { $this->fieldName = $name; @@ -36,17 +34,11 @@ public function setFieldName($name) return $this; } - /** - * {@inheritdoc} - */ public function getFieldName() { return $this->fieldName; } - /** - * {@inheritdoc} - */ public function setFilename($filename) { // Remove leading @ symbol @@ -63,17 +55,11 @@ public function setFilename($filename) return $this; } - /** - * {@inheritdoc} - */ public function getFilename() { return $this->filename; } - /** - * {@inheritdoc} - */ public function setContentType($type) { $this->contentType = $type; @@ -81,24 +67,36 @@ public function setContentType($type) return $this; } - /** - * {@inheritdoc} - */ public function getContentType() { return $this->contentType; } + public function getCurlValue() + { + // PHP 5.5 introduced a CurlFile object that deprecates the old @filename syntax + // See: https://wiki.php.net/rfc/curl-file-upload + if (function_exists('curl_file_create')) { + return curl_file_create($this->filename, $this->contentType, basename($this->filename)); + } + + // Use the old style if using an older version of PHP + $value = "@{$this->filename};filename=" . basename($this->filename); + if ($this->contentType) { + $value .= ';type=' . $this->contentType; + } + + return $value; + } + /** - * {@inheritdoc} + * @deprecated + * @codeCoverageIgnore */ public function getCurlString() { - $disposition = ';filename=' . basename($this->filename); - - return $this->contentType - ? '@' . $this->filename . ';type=' . $this->contentType . $disposition - : '@' . $this->filename . $disposition; + Version::warn(__METHOD__ . ' is deprecated. Use getCurlValue()'); + return $this->getCurlValue(); } /** diff --git a/core/vendor/guzzle/http/Guzzle/Http/Message/PostFileInterface.php b/core/vendor/guzzle/http/Guzzle/Http/Message/PostFileInterface.php index 683933f..99dc706 100644 --- a/core/vendor/guzzle/http/Guzzle/Http/Message/PostFileInterface.php +++ b/core/vendor/guzzle/http/Guzzle/Http/Message/PostFileInterface.php @@ -59,9 +59,9 @@ public function setContentType($type); public function getContentType(); /** - * Get a cURL ready string for the upload + * Get a cURL ready string or CurlFile object for the upload * * @return string */ - public function getCurlString(); + public function getCurlValue(); } diff --git a/core/vendor/guzzle/http/Guzzle/Http/Message/Request.php b/core/vendor/guzzle/http/Guzzle/Http/Message/Request.php index a41b933..37d7690 100644 --- a/core/vendor/guzzle/http/Guzzle/Http/Message/Request.php +++ b/core/vendor/guzzle/http/Guzzle/Http/Message/Request.php @@ -2,16 +2,17 @@ namespace Guzzle\Http\Message; +use Guzzle\Common\Version; use Guzzle\Common\Event; use Guzzle\Common\Collection; use Guzzle\Common\Exception\RuntimeException; use Guzzle\Common\Exception\InvalidArgumentException; -use Guzzle\Http\Utils; use Guzzle\Http\Exception\RequestException; use Guzzle\Http\Exception\BadResponseException; use Guzzle\Http\ClientInterface; use Guzzle\Http\EntityBody; use Guzzle\Http\EntityBodyInterface; +use Guzzle\Http\Message\Header\HeaderInterface; use Guzzle\Http\Url; use Guzzle\Parser\ParserRegistry; use Symfony\Component\EventDispatcher\EventDispatcherInterface; @@ -23,59 +24,39 @@ */ class Request extends AbstractMessage implements RequestInterface { - /** - * @var EventDispatcherInterface - */ + /** @var EventDispatcherInterface */ protected $eventDispatcher; - /** - * @var Url HTTP Url - */ + /** @var Url HTTP Url */ protected $url; - /** - * @var string HTTP method (GET, PUT, POST, DELETE, HEAD, OPTIONS, TRACE) - */ + /** @var string HTTP method (GET, PUT, POST, DELETE, HEAD, OPTIONS, TRACE) */ protected $method; - /** - * @var ClientInterface - */ + /** @var ClientInterface */ protected $client; - /** - * @var Response Response of the request - */ + /** @var Response Response of the request */ protected $response; - /** - * @var EntityBodyInterface Response body - */ + /** @var EntityBodyInterface Response body */ protected $responseBody; - /** - * @var string State of the request object - */ + /** @var string State of the request object */ protected $state; - /** - * @var string Authentication username - */ + /** @var string Authentication username */ protected $username; - /** - * @var string Auth password - */ + /** @var string Auth password */ protected $password; - /** - * @var Collection cURL specific transfer options - */ + /** @var Collection cURL specific transfer options */ protected $curlOptions; - /** - * {@inheritdoc} - */ + /** @var bool */ + protected $isRedirect = false; + public static function getAllEvents() { return array( @@ -92,15 +73,11 @@ public static function getAllEvents() // An exception is being thrown because of an unsuccessful response 'request.exception', // Received response status line - 'request.receive.status_line', - // Manually set a response - 'request.set_response' + 'request.receive.status_line' ); } /** - * Create a new request - * * @param string $method HTTP method * @param string|Url $url HTTP URL to connect to. The URI scheme, host header, and URI are parsed from the * full URL. If query string parameters are present they will be parsed as well. @@ -108,26 +85,19 @@ public static function getAllEvents() */ public function __construct($method, $url, $headers = array()) { + parent::__construct(); $this->method = strtoupper($method); $this->curlOptions = new Collection(); - $this->params = new Collection(); $this->setUrl($url); if ($headers) { // Special handling for multi-value headers foreach ($headers as $key => $value) { - $lkey = strtolower($key); // Deal with collisions with Host and Authorization - if ($lkey == 'host') { + if ($key == 'host' || $key == 'Host') { $this->setHeader($key, $value); - } elseif ($lkey == 'authorization') { - $parts = explode(' ', $value); - if ($parts[0] == 'Basic' && isset($parts[1])) { - list($user, $pass) = explode(':', base64_decode($parts[1])); - $this->setAuth($user, $pass); - } else { - $this->setHeader($key, $value); - } + } elseif ($value instanceof HeaderInterface) { + $this->addHeader($key, $value); } else { foreach ((array) $value as $v) { $this->addHeader($key, $v); @@ -136,17 +106,9 @@ public function __construct($method, $url, $headers = array()) } } - if (!$this->hasHeader('User-Agent', true)) { - $this->setHeader('User-Agent', Utils::getDefaultUserAgent()); - } - $this->setState(self::STATE_NEW); } - /** - * Clone the request object, leaving off any response that was received - * @see Guzzle\Plugin\Redirect\RedirectPlugin::cloneRequestWithGetMethod - */ public function __clone() { if ($this->eventDispatcher) { @@ -154,15 +116,9 @@ public function __clone() } $this->curlOptions = clone $this->curlOptions; $this->params = clone $this->params; - // Remove state based parameters from the cloned request - $this->params->remove('curl_handle')->remove('queued_response')->remove('curl_multi'); $this->url = clone $this->url; $this->response = $this->responseBody = null; - - // Clone each header - foreach ($this->headers as $key => &$value) { - $value = clone $value; - } + $this->headers = clone $this->headers; $this->setState(RequestInterface::STATE_NEW); $this->dispatch('request.clone', array('request' => $this)); @@ -179,8 +135,7 @@ public function __toString() } /** - * Default method that will throw exceptions if an unsuccessful response - * is received. + * Default method that will throw exceptions if an unsuccessful response is received. * * @param Event $event Received * @throws BadResponseException if the response is not successful @@ -188,18 +143,10 @@ public function __toString() public static function onRequestError(Event $event) { $e = BadResponseException::factory($event['request'], $event['response']); - $event['request']->dispatch('request.exception', array( - 'request' => $event['request'], - 'response' => $event['response'], - 'exception' => $e - )); - + $event['request']->setState(self::STATE_ERROR, array('exception' => $e) + $event->toArray()); throw $e; } - /** - * {@inheritdoc} - */ public function setClient(ClientInterface $client) { $this->client = $client; @@ -207,17 +154,11 @@ public function setClient(ClientInterface $client) return $this; } - /** - * {@inheritdoc} - */ public function getClient() { return $this->client; } - /** - * {@inheritdoc} - */ public function getRawHeaders() { $protocolVersion = $this->protocolVersion ?: '1.1'; @@ -227,9 +168,6 @@ public function getRawHeaders() . '/' . $protocolVersion . "\r\n" . implode("\r\n", $this->getHeaderLines()); } - /** - * {@inheritdoc} - */ public function setUrl($url) { if ($url instanceof Url) { @@ -251,9 +189,6 @@ public function setUrl($url) return $this; } - /** - * {@inheritdoc} - */ public function send() { if (!$this->client) { @@ -263,17 +198,11 @@ public function send() return $this->client->send($this); } - /** - * {@inheritdoc} - */ public function getResponse() { return $this->response; } - /** - * {@inheritdoc} - */ public function getQuery($asString = false) { return $asString @@ -281,25 +210,16 @@ public function getQuery($asString = false) : $this->url->getQuery(); } - /** - * {@inheritdoc} - */ public function getMethod() { return $this->method; } - /** - * {@inheritdoc} - */ public function getScheme() { return $this->url->getScheme(); } - /** - * {@inheritdoc} - */ public function setScheme($scheme) { $this->url->setScheme($scheme); @@ -307,17 +227,11 @@ public function setScheme($scheme) return $this; } - /** - * {@inheritdoc} - */ public function getHost() { return $this->url->getHost(); } - /** - * {@inheritdoc} - */ public function setHost($host) { $this->url->setHost($host); @@ -326,17 +240,11 @@ public function setHost($host) return $this; } - /** - * {@inheritdoc} - */ public function getProtocolVersion() { return $this->protocolVersion; } - /** - * {@inheritdoc} - */ public function setProtocolVersion($protocol) { $this->protocolVersion = $protocol; @@ -344,17 +252,11 @@ public function setProtocolVersion($protocol) return $this; } - /** - * {@inheritdoc} - */ public function getPath() { - return $this->url->getPath(); + return '/' . ltrim($this->url->getPath(), '/'); } - /** - * {@inheritdoc} - */ public function setPath($path) { $this->url->setPath($path); @@ -362,17 +264,11 @@ public function setPath($path) return $this; } - /** - * {@inheritdoc} - */ public function getPort() { return $this->url->getPort(); } - /** - * {@inheritdoc} - */ public function setPort($port) { $this->url->setPort($port); @@ -380,169 +276,160 @@ public function setPort($port) // Include the port in the Host header if it is not the default port for the scheme of the URL $scheme = $this->url->getScheme(); if (($scheme == 'http' && $port != 80) || ($scheme == 'https' && $port != 443)) { - $this->headers['host'] = new Header('Host', $this->url->getHost() . ':' . $port); + $this->headers['host'] = $this->headerFactory->createHeader('Host', $this->url->getHost() . ':' . $port); } else { - $this->headers['host'] = new Header('Host', $this->url->getHost()); + $this->headers['host'] = $this->headerFactory->createHeader('Host', $this->url->getHost()); } return $this; } - /** - * {@inheritdoc} - */ public function getUsername() { return $this->username; } - /** - * {@inheritdoc} - */ public function getPassword() { return $this->password; } - /** - * {@inheritdoc} - */ public function setAuth($user, $password = '', $scheme = CURLAUTH_BASIC) { + static $authMap = array( + 'basic' => CURLAUTH_BASIC, + 'digest' => CURLAUTH_DIGEST, + 'ntlm' => CURLAUTH_NTLM, + 'any' => CURLAUTH_ANY + ); + // If we got false or null, disable authentication - if (!$user || !$password) { + if (!$user) { $this->password = $this->username = null; $this->removeHeader('Authorization'); $this->getCurlOptions()->remove(CURLOPT_HTTPAUTH); - } else { - $this->username = $user; - $this->password = $password; - // Bypass CURL when using basic auth to promote connection reuse - if ($scheme == CURLAUTH_BASIC) { - $this->getCurlOptions()->remove(CURLOPT_HTTPAUTH); - $this->setHeader('Authorization', 'Basic ' . base64_encode($this->username . ':' . $this->password)); - } else { - $this->getCurlOptions()->set(CURLOPT_HTTPAUTH, $scheme) - ->set(CURLOPT_USERPWD, $this->username . ':' . $this->password); + return $this; + } + + if (!is_numeric($scheme)) { + $scheme = strtolower($scheme); + if (!isset($authMap[$scheme])) { + throw new InvalidArgumentException($scheme . ' is not a valid authentication type'); } + $scheme = $authMap[$scheme]; + } + + $this->username = $user; + $this->password = $password; + + // Bypass CURL when using basic auth to promote connection reuse + if ($scheme == CURLAUTH_BASIC) { + $this->getCurlOptions()->remove(CURLOPT_HTTPAUTH); + $this->setHeader('Authorization', 'Basic ' . base64_encode($this->username . ':' . $this->password)); + } else { + $this->getCurlOptions() + ->set(CURLOPT_HTTPAUTH, $scheme) + ->set(CURLOPT_USERPWD, $this->username . ':' . $this->password); } return $this; } - /** - * {@inheritdoc} - */ public function getResource() { - return $this->url->getPath() . (string) $this->url->getQuery(); + $resource = $this->getPath(); + if ($query = (string) $this->url->getQuery()) { + $resource .= '?' . $query; + } + + return $resource; } - /** - * {@inheritdoc} - */ public function getUrl($asObject = false) { return $asObject ? clone $this->url : (string) $this->url; } - /** - * {@inheritdoc} - */ public function getState() { return $this->state; } - /** - * {@inheritdoc} - */ public function setState($state, array $context = array()) { + $oldState = $this->state; $this->state = $state; - if ($this->state == self::STATE_NEW) { - $this->response = null; - } elseif ($this->state == self::STATE_COMPLETE) { - $this->processResponse($context); - $this->responseBody = null; + + switch ($state) { + case self::STATE_NEW: + $this->response = null; + break; + case self::STATE_TRANSFER: + if ($oldState !== $state) { + // Fix Content-Length and Transfer-Encoding collisions + if ($this->hasHeader('Transfer-Encoding') && $this->hasHeader('Content-Length')) { + $this->removeHeader('Transfer-Encoding'); + } + $this->dispatch('request.before_send', array('request' => $this)); + } + break; + case self::STATE_COMPLETE: + if ($oldState !== $state) { + $this->processResponse($context); + $this->responseBody = null; + } + break; + case self::STATE_ERROR: + if (isset($context['exception'])) { + $this->dispatch('request.exception', array( + 'request' => $this, + 'response' => isset($context['response']) ? $context['response'] : $this->response, + 'exception' => isset($context['exception']) ? $context['exception'] : null + )); + } } - return $this; + return $this->state; } - /** - * {@inheritdoc} - */ public function getCurlOptions() { return $this->curlOptions; } - /** - * {@inheritdoc} - */ - public function receiveResponseHeader($data) + public function startResponse(Response $response) { - static $normalize = array("\r", "\n"); $this->state = self::STATE_TRANSFER; - $length = strlen($data); - $data = str_replace($normalize, '', $data); - - if (strpos($data, 'HTTP/') === 0) { - - $startLine = explode(' ', $data, 3); - $code = $startLine[1]; - $status = isset($startLine[2]) ? $startLine[2] : ''; - - // Only download the body of the response to the specified response - // body when a successful response is received. - $body = $code >= 200 && $code < 300 ? $this->getResponseBody() : EntityBody::factory(); - - $this->response = new Response($code, null, $body); - $this->response->setStatus($code, $status)->setRequest($this); - $this->dispatch('request.receive.status_line', array( - 'request' => $this, - 'line' => $data, - 'status_code' => $code, - 'reason_phrase' => $status - )); - - } elseif (strpos($data, ':') !== false) { - - list($header, $value) = explode(':', $data, 2); - $this->response->addHeader(trim($header), trim($value)); - } + $response->setEffectiveUrl((string) $this->getUrl()); + $this->response = $response; - return $length; + return $this; } - /** - * {@inheritdoc} - */ public function setResponse(Response $response, $queued = false) { - // Never overwrite the request associated with the response (useful for redirect history) - if (!$response->getRequest()) { - $response->setRequest($this); - } + $response->setEffectiveUrl((string) $this->url); if ($queued) { - $this->getParams()->set('queued_response', $response); + $ed = $this->getEventDispatcher(); + $ed->addListener('request.before_send', $f = function ($e) use ($response, &$f, $ed) { + $e['request']->setResponse($response); + $ed->removeListener('request.before_send', $f); + }, -9999); } else { - $this->getParams()->remove('queued_response'); $this->response = $response; - $this->responseBody = $response->getBody(); - $this->processResponse(); + // If a specific response body is specified, then use it instead of the response's body + if ($this->responseBody && !$this->responseBody->getCustomData('default') && !$response->isRedirect()) { + $this->getResponseBody()->write((string) $this->response->getBody()); + } else { + $this->responseBody = $this->response->getBody(); + } + $this->setState(self::STATE_COMPLETE); } - $this->dispatch('request.set_response', $this->getEventArray()); - return $this; } - /** - * {@inheritdoc} - */ public function setResponseBody($body) { // Attempt to open a file for writing if a string was passed @@ -559,17 +446,28 @@ public function setResponseBody($body) return $this; } + public function getResponseBody() + { + if ($this->responseBody === null) { + $this->responseBody = EntityBody::factory()->setCustomData('default', true); + } + + return $this->responseBody; + } + /** - * {@inheritdoc} + * Determine if the response body is repeatable (readable + seekable) + * + * @return bool + * @deprecated Use getResponseBody()->isSeekable() + * @codeCoverageIgnore */ public function isResponseBodyRepeatable() { - return !$this->responseBody ? true : $this->responseBody->isSeekable() && $this->responseBody->isReadable(); + Version::warn(__METHOD__ . ' is deprecated. Use $request->getResponseBody()->isRepeatable()'); + return !$this->responseBody ? true : $this->responseBody->isRepeatable(); } - /** - * {@inheritdoc} - */ public function getCookies() { if ($cookie = $this->getHeader('Cookie')) { @@ -580,9 +478,6 @@ public function getCookies() return array(); } - /** - * {@inheritdoc} - */ public function getCookie($name) { $cookies = $this->getCookies(); @@ -590,9 +485,6 @@ public function getCookie($name) return isset($cookies[$name]) ? $cookies[$name] : null; } - /** - * {@inheritdoc} - */ public function addCookie($name, $value) { if (!$this->hasHeader('Cookie')) { @@ -602,14 +494,11 @@ public function addCookie($name, $value) } // Always use semicolons to separate multiple cookie headers - $this->getHeader('Cookie')->setGlue('; '); + $this->getHeader('Cookie')->setGlue(';'); return $this; } - /** - * {@inheritdoc} - */ public function removeCookie($name) { if ($cookie = $this->getHeader('Cookie')) { @@ -623,27 +512,6 @@ public function removeCookie($name) return $this; } - /** - * {@inheritdoc} - */ - public function canCache() - { - // Only GET and HEAD requests can be cached - if ($this->method != RequestInterface::GET && $this->method != RequestInterface::HEAD) { - return false; - } - - // Never cache requests when using no-store - if ($this->hasCacheControlDirective('no-store')) { - return false; - } - - return true; - } - - /** - * {@inheritdoc} - */ public function setEventDispatcher(EventDispatcherInterface $eventDispatcher) { $this->eventDispatcher = $eventDispatcher; @@ -652,9 +520,6 @@ public function setEventDispatcher(EventDispatcherInterface $eventDispatcher) return $this; } - /** - * {@inheritdoc} - */ public function getEventDispatcher() { if (!$this->eventDispatcher) { @@ -664,19 +529,12 @@ public function getEventDispatcher() return $this->eventDispatcher; } - /** - * {@inheritdoc} - */ public function dispatch($eventName, array $context = array()) { $context['request'] = $this; $this->getEventDispatcher()->dispatch($eventName, new Event($context)); } - /** - * {@inheritdoc} - * @codeCoverageIgnore - */ public function addSubscriber(EventSubscriberInterface $subscriber) { $this->getEventDispatcher()->addSubscriber($subscriber); @@ -685,31 +543,6 @@ public function addSubscriber(EventSubscriberInterface $subscriber) } /** - * {@inheritdoc} - */ - protected function changedHeader($header) - { - parent::changedHeader($header); - - if ($header == 'host') { - // If the Host header was changed, be sure to update the internal URL - $this->setHost((string) $this->getHeader('Host')); - } - } - - /** - * {@inheritdoc} - */ - protected function getResponseBody() - { - if ($this->responseBody === null) { - $this->responseBody = EntityBody::factory(); - } - - return $this->responseBody; - } - - /** * Get an array containing the request and response for event notifications * * @return array @@ -726,17 +559,11 @@ protected function getEventArray() * Process a received response * * @param array $context Contextual information - * - * @throws BadResponseException on unsuccessful responses + * @throws RequestException|BadResponseException on unsuccessful responses */ protected function processResponse(array $context = array()) { - // Use the queued response if one is set - if ($this->getParams()->get('queued_response')) { - $this->response = $this->getParams()->get('queued_response'); - $this->responseBody = $this->response->getBody(); - $this->getParams()->remove('queued_response'); - } elseif (!$this->response) { + if (!$this->response) { // If no response, then processResponse shouldn't have been called $e = new RequestException('Error completing request'); $e->setRequest($this); @@ -770,7 +597,41 @@ protected function processResponse(array $context = array()) $this->dispatch('request.success', $this->getEventArray()); } } + } + + /** + * @deprecated Use Guzzle\Plugin\Cache\DefaultCanCacheStrategy + * @codeCoverageIgnore + */ + public function canCache() + { + Version::warn(__METHOD__ . ' is deprecated. Use Guzzle\Plugin\Cache\DefaultCanCacheStrategy.'); + if (class_exists('Guzzle\Plugin\Cache\DefaultCanCacheStrategy')) { + $canCache = new \Guzzle\Plugin\Cache\DefaultCanCacheStrategy(); + return $canCache->canCacheRequest($this); + } else { + return false; + } + } + + /** + * @deprecated Use the history plugin (not emitting a warning as this is built-into the RedirectPlugin for now) + * @codeCoverageIgnore + */ + public function setIsRedirect($isRedirect) + { + $this->isRedirect = $isRedirect; return $this; } + + /** + * @deprecated Use the history plugin + * @codeCoverageIgnore + */ + public function isRedirect() + { + Version::warn(__METHOD__ . ' is deprecated. Use the HistoryPlugin to track this.'); + return $this->isRedirect; + } } diff --git a/core/vendor/guzzle/http/Guzzle/Http/Message/RequestFactory.php b/core/vendor/guzzle/http/Guzzle/Http/Message/RequestFactory.php index 212b44e..5fae2d2 100644 --- a/core/vendor/guzzle/http/Guzzle/Http/Message/RequestFactory.php +++ b/core/vendor/guzzle/http/Guzzle/Http/Message/RequestFactory.php @@ -3,28 +3,27 @@ namespace Guzzle\Http\Message; use Guzzle\Common\Collection; -use Guzzle\Http\EntityBody; +use Guzzle\Common\Exception\InvalidArgumentException; +use Guzzle\Http\RedirectPlugin; use Guzzle\Http\Url; use Guzzle\Parser\ParserRegistry; +use Guzzle\Plugin\Log\LogPlugin; /** * Default HTTP request factory used to create the default {@see Request} and {@see EntityEnclosingRequest} objects. */ class RequestFactory implements RequestFactoryInterface { - /** - * @var RequestFactory Singleton instance of the default request factory - */ + /** @var RequestFactory Singleton instance of the default request factory */ protected static $instance; - /** - * @var string Class to instantiate for requests with no body - */ + /** @var array Hash of methods available to the class (provides fast isset() lookups) */ + protected $methods; + + /** @var string Class to instantiate for requests with no body */ protected $requestClass = 'Guzzle\\Http\\Message\\Request'; - /** - * @var string Class to instantiate for requests with a body - */ + /** @var string Class to instantiate for requests with a body */ protected $entityEnclosingRequestClass = 'Guzzle\\Http\\Message\\EntityEnclosingRequest'; /** @@ -43,9 +42,11 @@ public static function getInstance() return static::$instance; } - /** - * {@inheritdoc} - */ + public function __construct() + { + $this->methods = array_flip(get_class_methods(__CLASS__)); + } + public function fromMessage($message) { $parsed = ParserRegistry::getInstance()->getParser('message')->parseRequest($message); @@ -68,9 +69,6 @@ public function fromMessage($message) return $request; } - /** - * {@inheritdoc} - */ public function fromParts( $method, array $urlParts, @@ -79,65 +77,280 @@ public function fromParts( $protocol = 'HTTP', $protocolVersion = '1.1' ) { - return $this->create($method, Url::buildUrl($urlParts, true), $headers, $body) + return $this->create($method, Url::buildUrl($urlParts), $headers, $body) ->setProtocolVersion($protocolVersion); } - /** - * {@inheritdoc} - */ - public function create($method, $url, $headers = null, $body = null) + public function create($method, $url, $headers = null, $body = null, array $options = array()) { $method = strtoupper($method); if ($method == 'GET' || $method == 'HEAD' || $method == 'TRACE' || $method == 'OPTIONS') { - $c = $this->requestClass; - $request = new $c($method, $url, $headers); + // Handle non-entity-enclosing request methods + $request = new $this->requestClass($method, $url, $headers); if ($body) { // The body is where the response body will be stored - $request->setResponseBody(EntityBody::factory($body)); + $type = gettype($body); + if ($type == 'string' || $type == 'resource' || $type == 'object') { + $request->setResponseBody($body); + } + } + } else { + // Create an entity enclosing request by default + $request = new $this->entityEnclosingRequestClass($method, $url, $headers); + if ($body) { + // Add POST fields and files to an entity enclosing request if an array is used + if (is_array($body) || $body instanceof Collection) { + // Normalize PHP style cURL uploads with a leading '@' symbol + foreach ($body as $key => $value) { + if (is_string($value) && substr($value, 0, 1) == '@') { + $request->addPostFile($key, $value); + unset($body[$key]); + } + } + // Add the fields if they are still present and not all files + $request->addPostFields($body); + } else { + // Add a raw entity body body to the request + $request->setBody($body, (string) $request->getHeader('Content-Type')); + if ((string) $request->getHeader('Transfer-Encoding') == 'chunked') { + $request->removeHeader('Content-Length'); + } + } } - return $request; } - $c = $this->entityEnclosingRequestClass; - $request = new $c($method, $url, $headers); + if ($options) { + $this->applyOptions($request, $options); + } + + return $request; + } + + /** + * Clone a request while changing the method. Emulates the behavior of + * {@see Guzzle\Http\Message\Request::clone}, but can change the HTTP method. + * + * @param RequestInterface $request Request to clone + * @param string $method Method to set + * + * @return RequestInterface + */ + public function cloneRequestWithMethod(RequestInterface $request, $method) + { + // Create the request with the same client if possible + if ($client = $request->getClient()) { + $cloned = $request->getClient()->createRequest($method, $request->getUrl(), $request->getHeaders()); + } else { + $cloned = $this->create($method, $request->getUrl(), $request->getHeaders()); + } + + $cloned->getCurlOptions()->replace($request->getCurlOptions()->toArray()); + $cloned->setEventDispatcher(clone $request->getEventDispatcher()); + // Ensure that that the Content-Length header is not copied if changing to GET or HEAD + if (!($cloned instanceof EntityEnclosingRequestInterface)) { + $cloned->removeHeader('Content-Length'); + } elseif ($request instanceof EntityEnclosingRequestInterface) { + $cloned->setBody($request->getBody()); + } + $cloned->getParams()->replace($request->getParams()->toArray()); + $cloned->dispatch('request.clone', array('request' => $cloned)); - if ($body) { + return $cloned; + } - $isChunked = (string) $request->getHeader('Transfer-Encoding') == 'chunked'; + public function applyOptions(RequestInterface $request, array $options = array(), $flags = self::OPTIONS_NONE) + { + // Iterate over each key value pair and attempt to apply a config using function visitors + foreach ($options as $key => $value) { + $method = "visit_{$key}"; + if (isset($this->methods[$method])) { + $this->{$method}($request, $value, $flags); + } + } + } - if ($method == 'POST' && (is_array($body) || $body instanceof Collection)) { + protected function visit_headers(RequestInterface $request, $value, $flags) + { + if (!is_array($value)) { + throw new InvalidArgumentException('headers value must be an array'); + } - // Normalize PHP style cURL uploads with a leading '@' symbol - $files = array(); - foreach ($body as $key => $value) { - if (is_string($value) && strpos($value, '@') === 0) { - $files[$key] = $value; - unset($body[$key]); - } + if ($flags & self::OPTIONS_AS_DEFAULTS) { + // Merge headers in but do not overwrite existing values + foreach ($value as $key => $header) { + if (!$request->hasHeader($key)) { + $request->setHeader($key, $header); } + } + } else { + $request->addHeaders($value); + } + } - // Add the fields if they are still present and not all files - if (count($body) > 0) { - $request->addPostFields($body); - } - // Add any files that were prefixed with '@' - if (!empty($files)) { - $request->addPostFiles($files); - } + protected function visit_body(RequestInterface $request, $value, $flags) + { + if ($request instanceof EntityEnclosingRequestInterface) { + $request->setBody($value); + } else { + throw new InvalidArgumentException('Attempting to set a body on a non-entity-enclosing request'); + } + } - if ($isChunked) { - $request->setHeader('Transfer-Encoding', 'chunked'); - } + protected function visit_allow_redirects(RequestInterface $request, $value, $flags) + { + if ($value === false) { + $request->getParams()->set(RedirectPlugin::DISABLE, true); + } + } + + protected function visit_auth(RequestInterface $request, $value, $flags) + { + if (!is_array($value)) { + throw new InvalidArgumentException('auth value must be an array'); + } + + $request->setAuth($value[0], isset($value[1]) ? $value[1] : null, isset($value[2]) ? $value[2] : 'basic'); + } - } elseif (is_resource($body) || $body instanceof EntityBody) { - $request->setBody($body, (string) $request->getHeader('Content-Type'), $isChunked); + protected function visit_query(RequestInterface $request, $value, $flags) + { + if (!is_array($value)) { + throw new InvalidArgumentException('query value must be an array'); + } + + if ($flags & self::OPTIONS_AS_DEFAULTS) { + // Merge query string values in but do not overwrite existing values + $query = $request->getQuery(); + $query->overwriteWith(array_diff_key($value, $query->toArray())); + } else { + $request->getQuery()->overwriteWith($value); + } + } + + protected function visit_cookies(RequestInterface $request, $value, $flags) + { + if (!is_array($value)) { + throw new InvalidArgumentException('cookies value must be an array'); + } + + foreach ($value as $name => $v) { + $request->addCookie($name, $v); + } + } + + protected function visit_events(RequestInterface $request, $value, $flags) + { + if (!is_array($value)) { + throw new InvalidArgumentException('events value must be an array'); + } + + foreach ($value as $name => $method) { + if (is_array($method)) { + $request->getEventDispatcher()->addListener($name, $method[0], $method[1]); } else { - $request->setBody((string) $body, (string) $request->getHeader('Content-Type'), $isChunked); + $request->getEventDispatcher()->addListener($name, $method); } } + } - return $request; + protected function visit_plugins(RequestInterface $request, $value, $flags) + { + if (!is_array($value)) { + throw new InvalidArgumentException('plugins value must be an array'); + } + + foreach ($value as $plugin) { + $request->addSubscriber($plugin); + } + } + + protected function visit_exceptions(RequestInterface $request, $value, $flags) + { + if ($value === false || $value === 0) { + $dispatcher = $request->getEventDispatcher(); + foreach ($dispatcher->getListeners('request.error') as $listener) { + if ($listener[0] == 'Guzzle\Http\Message\Request' && $listener[1] = 'onRequestError') { + $dispatcher->removeListener('request.error', $listener); + break; + } + } + } + } + + protected function visit_save_to(RequestInterface $request, $value, $flags) + { + $request->setResponseBody($value); + } + + protected function visit_params(RequestInterface $request, $value, $flags) + { + if (!is_array($value)) { + throw new InvalidArgumentException('params value must be an array'); + } + + $request->getParams()->overwriteWith($value); + } + + protected function visit_timeout(RequestInterface $request, $value, $flags) + { + $request->getCurlOptions()->set(CURLOPT_TIMEOUT_MS, $value * 1000); + } + + protected function visit_connect_timeout(RequestInterface $request, $value, $flags) + { + $request->getCurlOptions()->set(CURLOPT_CONNECTTIMEOUT_MS, $value * 1000); + } + + protected function visit_debug(RequestInterface $request, $value, $flags) + { + if (class_exists('Guzzle\Plugin\Log\LogPlugin')) { + $request->addSubscriber(LogPlugin::getDebugPlugin()); + } else { + // @codeCoverageIgnoreStart + $request->getCurlOptions()->set(CURLOPT_VERBOSE, true); + // @codeCoverageIgnoreEnd + } + } + + protected function visit_verify(RequestInterface $request, $value, $flags) + { + $curl = $request->getCurlOptions(); + if ($value === true || is_string($value)) { + $curl[CURLOPT_SSL_VERIFYHOST] = 2; + $curl[CURLOPT_SSL_VERIFYPEER] = true; + if ($value !== true) { + $curl[CURLOPT_CAINFO] = $value; + } + } elseif ($value === false) { + unset($curl[CURLOPT_CAINFO]); + $curl[CURLOPT_SSL_VERIFYHOST] = 0; + $curl[CURLOPT_SSL_VERIFYPEER] = false; + } + } + + protected function visit_proxy(RequestInterface $request, $value, $flags) + { + $request->getCurlOptions()->set(CURLOPT_PROXY, $value, $flags); + } + + protected function visit_cert(RequestInterface $request, $value, $flags) + { + if (is_array($value)) { + $request->getCurlOptions()->set(CURLOPT_SSLCERT, $value[0]); + $request->getCurlOptions()->set(CURLOPT_SSLCERTPASSWD, $value[1]); + } else { + $request->getCurlOptions()->set(CURLOPT_SSLCERT, $value); + } + } + + protected function visit_ssl_key(RequestInterface $request, $value, $flags) + { + if (is_array($value)) { + $request->getCurlOptions()->set(CURLOPT_SSLKEY, $value[0]); + $request->getCurlOptions()->set(CURLOPT_SSLKEYPASSWD, $value[1]); + } else { + $request->getCurlOptions()->set(CURLOPT_SSLKEY, $value); + } } } diff --git a/core/vendor/guzzle/http/Guzzle/Http/Message/RequestFactoryInterface.php b/core/vendor/guzzle/http/Guzzle/Http/Message/RequestFactoryInterface.php index 4bbd937..6088f10 100644 --- a/core/vendor/guzzle/http/Guzzle/Http/Message/RequestFactoryInterface.php +++ b/core/vendor/guzzle/http/Guzzle/Http/Message/RequestFactoryInterface.php @@ -11,6 +11,9 @@ */ interface RequestFactoryInterface { + const OPTIONS_NONE = 0; + const OPTIONS_AS_DEFAULTS = 1; + /** * Create a new request based on an HTTP message * @@ -56,8 +59,47 @@ public function fromParts( * @param string|Url $url HTTP URL to connect to * @param array|Collection $headers HTTP headers * @param string|resource|array|EntityBodyInterface $body Body to send in the request + * @param array $options Array of options to apply to the request * * @return RequestInterface */ - public function create($method, $url, $headers = null, $body = null); + public function create($method, $url, $headers = null, $body = null, array $options = array()); + + /** + * Apply an associative array of options to the request + * + * @param RequestInterface $request Request to update + * @param array $options Options to use with the request. Available options are: + * "headers": Associative array of headers + * "query": Associative array of query string values to add to the request + * "body": Body of a request, including an EntityBody, string, or array when sending POST requests. + * "auth": Array of HTTP authentication parameters to use with the request. The array must contain the + * username in index [0], the password in index [2], and can optionally contain the authentication type + * in index [3]. The authentication types are: "Basic", "Digest", "NTLM", "Any" (defaults to "Basic"). + * "cookies": Associative array of cookies + * "allow_redirects": Set to false to disable redirects + * "save_to": String, fopen resource, or EntityBody object used to store the body of the response + * "events": Associative array mapping event names to a closure or array of (priority, closure) + * "plugins": Array of plugins to add to the request + * "exceptions": Set to false to disable throwing exceptions on an HTTP level error (e.g. 404, 500, etc) + * "params": Set custom request data parameters on a request. (Note: these are not query string parameters) + * "timeout": Float describing the timeout of the request in seconds + * "connect_timeout": Float describing the number of seconds to wait while trying to connect. Use 0 to wait + * indefinitely. + * "verify": Set to true to enable SSL cert validation (the default), false to disable, or supply the path + * to a CA bundle to enable verification using a custom certificate. + * "cert": Set to a string to specify the path to a file containing a PEM formatted certificate. If a + * password is required, then set an array containing the path to the PEM file followed by the the + * password required for the certificate. + * "ssl_key": Specify the path to a file containing a private SSL key in PEM format. If a password is + * required, then set an array containing the path to the SSL key followed by the password required for + * the certificate. + * "proxy": Specify an HTTP proxy (e.g. "http://username:password@192.168.16.1:10") + * "debug": Set to true to display all data sent over the wire + * @param int $flags Bitwise flags to apply when applying the options to the request. Defaults to no special + * options. `1` (OPTIONS_AS_DEFAULTS): When specified, options will only update a request when + * the value does not already exist on the request. This is only supported by "query" and + * "headers". Other bitwise options may be added in the future. + */ + public function applyOptions(RequestInterface $request, array $options = array(), $flags = self::OPTIONS_NONE); } diff --git a/core/vendor/guzzle/http/Guzzle/Http/Message/RequestInterface.php b/core/vendor/guzzle/http/Guzzle/Http/Message/RequestInterface.php index 3928e4e..2f6b3c8 100644 --- a/core/vendor/guzzle/http/Guzzle/Http/Message/RequestInterface.php +++ b/core/vendor/guzzle/http/Guzzle/Http/Message/RequestInterface.php @@ -31,18 +31,24 @@ const PATCH = 'PATCH'; /** - * Get the HTTP request as a string - * * @return string */ public function __toString(); /** + * Send the request + * + * @return Response + * @throws RequestException on a request error + */ + public function send(); + + /** * Set the client used to transport the request * * @param ClientInterface $client * - * @return RequestInterface + * @return self */ public function setClient(ClientInterface $client); @@ -56,34 +62,30 @@ public function getClient(); /** * Set the URL of the request * - * Warning: Calling this method will modify headers, rewrite the query string object, and set other data - * associated with the request. - * * @param string $url|Url Full URL to set including query string * - * @return RequestInterface + * @return self */ public function setUrl($url); /** - * Send the request + * Get the full URL of the request (e.g. 'http://www.guzzle-project.com/') * - * @return Response - * @throws RequestException on a request error + * @param bool $asObject Set to TRUE to retrieve the URL as a clone of the URL object owned by the request. + * + * @return string|Url */ - public function send(); + public function getUrl($asObject = false); /** - * Get the previously received {@see Response} or NULL if the request has - * not been sent + * Get the resource part of the the request, including the path, query string, and fragment * - * @return Response|null + * @return string */ - public function getResponse(); + public function getResource(); /** - * Get the collection of key value pairs that will be used as the query - * string in the request + * Get the collection of key value pairs that will be used as the query string in the request * * @return QueryString */ @@ -108,7 +110,7 @@ public function getScheme(); * * @param string $scheme Scheme to set * - * @return RequestInterface + * @return self */ public function setScheme($scheme); @@ -120,32 +122,15 @@ public function setScheme($scheme); public function getHost(); /** - * Set the host of the request. Including a port in the host will modify - * the port of the request. + * Set the host of the request. Including a port in the host will modify the port of the request. * * @param string $host Host to set (e.g. www.yahoo.com, www.yahoo.com:80) * - * @return RequestInterface + * @return self */ public function setHost($host); /** - * Get the HTTP protocol version of the request - * - * @return string - */ - public function getProtocolVersion(); - - /** - * Set the HTTP protocol version of the request (e.g. 1.1 or 1.0) - * - * @param string $protocol HTTP protocol version to use with the request - * - * @return RequestInterface - */ - public function setProtocolVersion($protocol); - - /** * Get the path of the request (e.g. '/', '/index.html') * * @return string @@ -157,7 +142,7 @@ public function getPath(); * * @param string|array $path Path to set or array of segments to implode * - * @return RequestInterface + * @return self */ public function setPath($path); @@ -173,7 +158,7 @@ public function getPort(); * * @param int $port Port number to set * - * @return RequestInterface + * @return self */ public function setPort($port); @@ -185,79 +170,74 @@ public function setPort($port); public function getUsername(); /** + * Get the password to pass in the URL if set + * + * @return string|null + */ + public function getPassword(); + + /** * Set HTTP authorization parameters * * @param string|bool $user User name or false disable authentication * @param string $password Password - * @param string $scheme Authentication scheme to use (Basic, Digest) + * @param string $scheme Authentication scheme ('Basic', 'Digest', or a CURLAUTH_* constant (deprecated)) * - * @return Request - * - * @see http://www.ietf.org/rfc/rfc2617.txt + * @return self + * @link http://www.ietf.org/rfc/rfc2617.txt + * @link http://php.net/manual/en/function.curl-setopt.php See the available options for CURLOPT_HTTPAUTH * @throws RequestException */ public function setAuth($user, $password = '', $scheme = 'Basic'); /** - * Get the password to pass in the URL if set - * - * @return string|null - */ - public function getPassword(); - - /** - * Get the resource part of the the request, including the path, query - * string, and fragment + * Get the HTTP protocol version of the request * * @return string */ - public function getResource(); + public function getProtocolVersion(); /** - * Get the full URL of the request (e.g. 'http://www.guzzle-project.com/') - * scheme://username:password@domain:port/path?query_string#fragment + * Set the HTTP protocol version of the request (e.g. 1.1 or 1.0) * - * @param bool $asObject Set to TRUE to retrieve the URL as a clone of the URL object owned by the request. + * @param string $protocol HTTP protocol version to use with the request * - * @return string|Url + * @return self */ - public function getUrl($asObject = false); + public function setProtocolVersion($protocol); /** - * Get the state of the request. One of 'complete', 'sending', 'new' + * Get the previously received {@see Response} or NULL if the request has not been sent * - * @return string + * @return Response|null */ - public function getState(); + public function getResponse(); /** - * Set the state of the request + * Manually set a response for the request. * - * @param string $state State of the request (complete, sending, or new) - * @param array $context Contextual information about the state change + * This method is useful for specifying a mock response for the request or setting the response using a cache. + * Manually setting a response will bypass the actual sending of a request. * - * @return RequestInterface - */ - public function setState($state, array $context = array()); - - /** - * Get the cURL options that will be applied when the cURL handle is created + * @param Response $response Response object to set + * @param bool $queued Set to TRUE to keep the request in a state of not having been sent, but queue the + * response for send() * - * @return Collection + * @return self Returns a reference to the object. */ - public function getCurlOptions(); + public function setResponse(Response $response, $queued = false); /** - * Method to receive HTTP response headers as they are retrieved + * The start of a response has been received for a request and the request is still in progress * - * @param string $data Header data. + * @param Response $response Response that has been received so far * - * @return integer Returns the size of the data. + * @return self */ - public function receiveResponseHeader($data); + public function startResponse(Response $response); /** - * Set the EntityBody that will hold the response message's entity body. + * Set the EntityBody that will hold a successful response message's entity body. * * This method should be invoked when you need to send the response's entity body somewhere other than the normal * php://temp buffer. For example, you can send the entity body to a socket, file, or some other custom stream. @@ -269,25 +249,37 @@ public function receiveResponseHeader($data); public function setResponseBody($body); /** - * Determine if the response body is repeatable (readable + seekable) + * Get the EntityBody that will hold the resulting response message's entity body. This response body will only + * be used for successful responses. Intermediate responses (e.g. redirects) will not use the targeted response + * body. * - * @return bool + * @return EntityBodyInterface */ - public function isResponseBodyRepeatable(); + public function getResponseBody(); /** - * Manually set a response for the request. + * Get the state of the request. One of 'complete', 'transfer', 'new', 'error' * - * This method is useful for specifying a mock response for the request or setting the response using a cache. - * Manually setting a response will bypass the actual sending of a request. + * @return string + */ + public function getState(); + + /** + * Set the state of the request * - * @param Response $response Response object to set - * @param bool $queued Set to TRUE to keep the request in a state of not having been sent, but queue the - * response for send() + * @param string $state State of the request ('complete', 'transfer', 'new', 'error') + * @param array $context Contextual information about the state change * - * @return RequestInterface Returns a reference to the object. + * @return string Returns the current state of the request (which may have changed due to events being fired) */ - public function setResponse(Response $response, $queued = false); + public function setState($state, array $context = array()); + + /** + * Get the cURL options that will be applied when the cURL handle is created + * + * @return Collection + */ + public function getCurlOptions(); /** * Get an array of Cookies @@ -311,7 +303,7 @@ public function getCookie($name); * @param string $name Name of the cookie to add * @param string $value Value to set * - * @return RequestInterface + * @return self */ public function addCookie($name, $value); @@ -320,14 +312,7 @@ public function addCookie($name, $value); * * @param string $name Cookie to remove by name * - * @return RequestInterface + * @return self */ public function removeCookie($name); - - /** - * Returns whether or not the request can be cached - * - * @return bool - */ - public function canCache(); } diff --git a/core/vendor/guzzle/http/Guzzle/Http/Message/Response.php b/core/vendor/guzzle/http/Guzzle/Http/Message/Response.php index 8c94023..654ea76 100644 --- a/core/vendor/guzzle/http/Guzzle/Http/Message/Response.php +++ b/core/vendor/guzzle/http/Guzzle/Http/Message/Response.php @@ -2,17 +2,19 @@ namespace Guzzle\Http\Message; -use Guzzle\Common\Collection; +use Guzzle\Common\Version; +use Guzzle\Common\ToArrayInterface; use Guzzle\Common\Exception\RuntimeException; use Guzzle\Http\EntityBodyInterface; use Guzzle\Http\EntityBody; use Guzzle\Http\Exception\BadResponseException; +use Guzzle\Http\RedirectPlugin; use Guzzle\Parser\ParserRegistry; /** * Guzzle HTTP response object */ -class Response extends AbstractMessage +class Response extends AbstractMessage implements \Serializable { /** * @var array Array of reason phrases and their corresponding status codes @@ -78,52 +80,30 @@ class Response extends AbstractMessage 511 => 'Network Authentication Required', ); - /** - * @var EntityBodyInterface The response body - */ + /** @var EntityBodyInterface The response body */ protected $body; - /** - * @var string The reason phrase of the response (human readable code) - */ + /** @var string The reason phrase of the response (human readable code) */ protected $reasonPhrase; - /** - * @var string The status code of the response - */ + /** @var string The status code of the response */ protected $statusCode; - /** - * @var string Response protocol - */ - protected $protocol = 'HTTP'; - - /** - * @var array Information about the request - */ + /** @var array Information about the request */ protected $info = array(); - /** - * @var RequestInterface Request object that may or may not be set - */ - protected $request = null; + /** @var string The effective URL that returned this response */ + protected $effectiveUrl; - /** - * @var array Cacheable response codes (see RFC 2616:13.4) - */ - protected $cacheResponseCodes = array(200, 203, 206, 300, 301, 410); - - /** - * @var Response If a redirect was issued or an intermediate response was issued - */ - protected $previous; + /** @var array Cacheable response codes (see RFC 2616:13.4) */ + protected static $cacheResponseCodes = array(200, 203, 206, 300, 301, 410); /** * Create a new Response based on a raw response message * * @param string $message Response message * - * @return Response|bool Returns false on error + * @return self|bool Returns false on error */ public static function fromMessage($message) { @@ -150,30 +130,29 @@ public static function fromMessage($message) * Construct the response * * @param string $statusCode The response status code (e.g. 200, 404, etc) - * @param Collection|array $headers The response headers + * @param ToArrayInterface|array $headers The response headers * @param string|resource|EntityBodyInterface $body The body of the response * * @throws BadResponseException if an invalid response code is given */ public function __construct($statusCode, $headers = null, $body = null) { + parent::__construct(); $this->setStatus($statusCode); - $this->params = new Collection(); $this->body = EntityBody::factory($body !== null ? $body : ''); if ($headers) { - if (!is_array($headers) && !($headers instanceof Collection)) { + if (is_array($headers)) { + $this->setHeaders($headers); + } elseif ($headers instanceof ToArrayInterface) { + $this->setHeaders($headers->toArray()); + } else { throw new BadResponseException('Invalid headers argument received'); } - foreach ($headers as $key => $value) { - $this->addHeaders(array($key => $value)); - } } } /** - * Convert the response object to a string - * * @return string */ public function __toString() @@ -181,6 +160,21 @@ public function __toString() return $this->getMessage(); } + public function serialize() + { + return json_encode(array( + 'status' => $this->statusCode, + 'body' => (string) $this->body, + 'headers' => $this->headers->toArray() + )); + } + + public function unserialize($serialize) + { + $data = json_decode($serialize, true); + $this->__construct($data['status'], $data['headers'], $data['body']); + } + /** * Get the response entity body * @@ -213,7 +207,7 @@ public function setBody($body) * @param string $protocol Response protocol * @param string $version Protocol version * - * @return Response + * @return self */ public function setProtocol($protocol, $version) { @@ -230,7 +224,7 @@ public function setProtocol($protocol, $version) */ public function getProtocol() { - return $this->protocol ?: 'HTTP'; + return $this->protocol; } /** @@ -240,7 +234,7 @@ public function getProtocol() */ public function getProtocolVersion() { - return $this->protocolVersion ?: '1.1'; + return $this->protocolVersion; } /** @@ -268,7 +262,7 @@ public function getInfo($key = null) * * @param array $info Array of cURL transfer stats * - * @return Response + * @return self */ public function setInfo(array $info) { @@ -283,14 +277,14 @@ public function setInfo(array $info) * @param int $statusCode Response status code to set * @param string $reasonPhrase Response reason phrase * - * @return Response + * @return self * @throws BadResponseException when an invalid response code is received */ public function setStatus($statusCode, $reasonPhrase = '') { $this->statusCode = (int) $statusCode; - if (!$reasonPhrase && array_key_exists($this->statusCode, self::$statusTexts)) { + if (!$reasonPhrase && isset(self::$statusTexts[$this->statusCode])) { $this->reasonPhrase = self::$statusTexts[$this->statusCode]; } else { $this->reasonPhrase = $reasonPhrase; @@ -344,16 +338,6 @@ public function getRawHeaders() } /** - * Get the request object (or null) that is associated with this response - * - * @return RequestInterface - */ - public function getRequest() - { - return $this->request; - } - - /** * Get the response reason phrase- a human readable version of the numeric * status code * @@ -371,25 +355,33 @@ public function getReasonPhrase() */ public function getAcceptRanges() { - return $this->getHeader('Accept-Ranges', true); + return (string) $this->getHeader('Accept-Ranges'); } /** - * Get the Age HTTP header + * Calculate the age of the response * - * @param bool $headerOnly Set to TRUE to only retrieve the Age header rather than calculating the age - * - * @return integer|null Returns the age the object has been in a proxy cache in seconds. + * @return integer */ - public function getAge($headerOnly = false) + public function calculateAge() { - $age = $this->getHeader('Age', true); + $age = $this->getHeader('Age'); - if (!$headerOnly && $age === null && $this->getDate()) { + if ($age === null && $this->getDate()) { $age = time() - strtotime($this->getDate()); } - return $age; + return $age === null ? null : (int) (string) $age; + } + + /** + * Get the Age HTTP header + * + * @return integer|null Returns the age the object has been in a proxy cache in seconds. + */ + public function getAge() + { + return (string) $this->getHeader('Age'); } /** @@ -399,7 +391,7 @@ public function getAge($headerOnly = false) */ public function getAllow() { - return $this->getHeader('Allow', true); + return (string) $this->getHeader('Allow'); } /** @@ -426,12 +418,11 @@ public function isMethodAllowed($method) /** * Get the Cache-Control HTTP header * - * @return Header|null Returns a Header object that tells all caching mechanisms from server to client whether they - * may cache this object. + * @return string */ public function getCacheControl() { - return $this->getHeader('Cache-Control'); + return (string) $this->getHeader('Cache-Control'); } /** @@ -441,17 +432,17 @@ public function getCacheControl() */ public function getConnection() { - return $this->getHeader('Connection', true); + return (string) $this->getHeader('Connection'); } /** * Get the Content-Encoding HTTP header * - * @return string|null Returns the type of encoding used on the data. One of compress, deflate, gzip, identity. + * @return string|null */ public function getContentEncoding() { - return $this->getHeader('Content-Encoding', true); + return (string) $this->getHeader('Content-Encoding'); } /** @@ -461,7 +452,7 @@ public function getContentEncoding() */ public function getContentLanguage() { - return $this->getHeader('Content-Language', true); + return (string) $this->getHeader('Content-Language'); } /** @@ -471,7 +462,7 @@ public function getContentLanguage() */ public function getContentLength() { - return (int) $this->getHeader('Content-Length', true); + return (int) (string) $this->getHeader('Content-Length'); } /** @@ -481,7 +472,7 @@ public function getContentLength() */ public function getContentLocation() { - return $this->getHeader('Content-Location', true); + return (string) $this->getHeader('Content-Location'); } /** @@ -491,7 +482,7 @@ public function getContentLocation() */ public function getContentDisposition() { - return (string) $this->getHeader('Content-Disposition')->setGlue(';'); + return (string) $this->getHeader('Content-Disposition'); } /** @@ -501,7 +492,7 @@ public function getContentDisposition() */ public function getContentMd5() { - return $this->getHeader('Content-MD5', true); + return (string) $this->getHeader('Content-MD5'); } /** @@ -511,7 +502,7 @@ public function getContentMd5() */ public function getContentRange() { - return $this->getHeader('Content-Range', true); + return (string) $this->getHeader('Content-Range'); } /** @@ -521,7 +512,7 @@ public function getContentRange() */ public function getContentType() { - return $this->getHeader('Content-Type', true); + return (string) $this->getHeader('Content-Type'); } /** @@ -535,7 +526,7 @@ public function getContentType() */ public function isContentType($type) { - return stripos($this->getContentType(), $type) !== false; + return stripos($this->getHeader('Content-Type'), $type) !== false; } /** @@ -545,7 +536,7 @@ public function isContentType($type) */ public function getDate() { - return $this->getHeader('Date', true); + return (string) $this->getHeader('Date'); } /** @@ -555,9 +546,7 @@ public function getDate() */ public function getEtag() { - $etag = $this->getHeader('ETag', true); - - return $etag ? str_replace('"', '', $etag) : null; + return (string) $this->getHeader('ETag'); } /** @@ -567,7 +556,7 @@ public function getEtag() */ public function getExpires() { - return $this->getHeader('Expires', true); + return (string) $this->getHeader('Expires'); } /** @@ -578,7 +567,7 @@ public function getExpires() */ public function getLastModified() { - return $this->getHeader('Last-Modified', true); + return (string) $this->getHeader('Last-Modified'); } /** @@ -588,7 +577,7 @@ public function getLastModified() */ public function getLocation() { - return $this->getHeader('Location', true); + return (string) $this->getHeader('Location'); } /** @@ -599,7 +588,7 @@ public function getLocation() */ public function getPragma() { - return $this->getHeader('Pragma'); + return (string) $this->getHeader('Pragma'); } /** @@ -609,7 +598,7 @@ public function getPragma() */ public function getProxyAuthenticate() { - return $this->getHeader('Proxy-Authenticate', true); + return (string) $this->getHeader('Proxy-Authenticate'); } /** @@ -620,16 +609,7 @@ public function getProxyAuthenticate() */ public function getRetryAfter() { - $time = $this->getHeader('Retry-After', true); - if ($time === null) { - return null; - } - - if (!is_numeric($time)) { - $time = strtotime($time) - time(); - } - - return (int) $time; + return (string) $this->getHeader('Retry-After'); } /** @@ -639,17 +619,17 @@ public function getRetryAfter() */ public function getServer() { - return $this->getHeader('Server', true); + return (string) $this->getHeader('Server'); } /** * Get the Set-Cookie HTTP header * - * @return Header|null An HTTP cookie. + * @return string|null An HTTP cookie. */ public function getSetCookie() { - return $this->getHeader('Set-Cookie'); + return (string) $this->getHeader('Set-Cookie'); } /** @@ -660,18 +640,17 @@ public function getSetCookie() */ public function getTrailer() { - return $this->getHeader('Trailer', true); + return (string) $this->getHeader('Trailer'); } /** * Get the Transfer-Encoding HTTP header * - * @return string|null The form of encoding used to safely transfer the entity to the user. Currently defined - * methods are: chunked + * @return string|null The form of encoding used to safely transfer the entity to the user */ public function getTransferEncoding() { - return $this->getHeader('Transfer-Encoding', true); + return (string) $this->getHeader('Transfer-Encoding'); } /** @@ -682,40 +661,37 @@ public function getTransferEncoding() */ public function getVary() { - return $this->getHeader('Vary', true); + return (string) $this->getHeader('Vary'); } /** * Get the Via HTTP header * * @return string|null Informs the client of proxies through which the response was sent. - * (e.g. 1.0 fred, 1.1 nowhere.com (Apache/1.1)) */ public function getVia() { - return $this->getHeader('Via', true); + return (string) $this->getHeader('Via'); } /** * Get the Warning HTTP header * - * @return string|null A general warning about possible problems with the entity body. - * (e.g. 199 Miscellaneous warning) + * @return string|null A general warning about possible problems with the entity body */ public function getWarning() { - return $this->getHeader('Warning', true); + return (string) $this->getHeader('Warning'); } /** * Get the WWW-Authenticate HTTP header * * @return string|null Indicates the authentication scheme that should be used to access the requested entity - * (e.g. Basic) */ public function getWwwAuthenticate() { - return $this->getHeader('WWW-Authenticate', true); + return (string) $this->getHeader('WWW-Authenticate'); } /** @@ -779,28 +755,14 @@ public function isSuccessful() } /** - * Set the request object associated with the response - * - * @param RequestInterface $request The request object used to generate the response - * - * @return Response - */ - public function setRequest(RequestInterface $request) - { - $this->request = $request; - - return $this; - } - - /** - * Check if the response can be cached + * Check if the response can be cached based on the response headers * * @return bool Returns TRUE if the response can be cached or false if not */ public function canCache() { // Check if the response is cacheable based on the code - if (!in_array((int) $this->getStatusCode(), $this->cacheResponseCodes)) { + if (!in_array((int) $this->getStatusCode(), self::$cacheResponseCodes)) { return false; } @@ -812,7 +774,7 @@ public function canCache() // Never cache no-store resources (this is a private cache, so private // can be cached) - if ($this->hasCacheControlDirective('no-store')) { + if ($this->getHeader('Cache-Control') && $this->getHeader('Cache-Control')->hasDirective('no-store')) { return false; } @@ -826,13 +788,14 @@ public function canCache() */ public function getMaxAge() { - // s-max-age, then max-age, then Expires - if ($age = $this->getCacheControlDirective('s-maxage')) { - return $age; - } - - if ($age = $this->getCacheControlDirective('max-age')) { - return $age; + if ($header = $this->getHeader('Cache-Control')) { + // s-max-age, then max-age, then Expires + if ($age = $header->getDirective('s-maxage')) { + return $age; + } + if ($age = $header->getDirective('max-age')) { + return $age; + } } if ($this->getHeader('Expires')) { @@ -845,7 +808,8 @@ public function getMaxAge() /** * Check if the response is considered fresh. * - * A response is considered fresh when its age is less than the freshness lifetime (maximum age) of the response. + * A response is considered fresh when its age is less than or equal to the freshness lifetime (maximum age) of the + * response. * * @return bool|null */ @@ -853,7 +817,7 @@ public function isFresh() { $fresh = $this->getFreshness(); - return $fresh === null ? null : $this->getFreshness() > 0; + return $fresh === null ? null : $fresh >= 0; } /** @@ -879,39 +843,15 @@ public function canValidate() public function getFreshness() { $maxAge = $this->getMaxAge(); - $age = $this->getAge(); + $age = $this->calculateAge(); return $maxAge && $age ? ($maxAge - $age) : null; } /** - * Get the previous response (e.g. Redirect response) - * - * @return null|Response - */ - public function getPreviousResponse() - { - return $this->previous; - } - - /** - * Set the previous response - * - * @param Response $response Response to set - * - * @return self - */ - public function setPreviousResponse(Response $response) - { - $this->previous = $response; - - return $this; - } - - /** * Parse the JSON response body and return an array * - * @return array + * @return array|string|int|bool|float * @throws RuntimeException if the response body is not in JSON format */ public function json() @@ -921,7 +861,7 @@ public function json() throw new RuntimeException('Unable to parse response body into JSON: ' . json_last_error()); } - return $data ?: array(); + return $data === null ? array() : $data; } /** @@ -941,4 +881,68 @@ public function xml() return $xml; } + + /** + * Get the redirect count of this response + * + * @return int + */ + public function getRedirectCount() + { + return (int) $this->params->get(RedirectPlugin::REDIRECT_COUNT); + } + + /** + * Set the effective URL that resulted in this response (e.g. the last redirect URL) + * + * @param string $url The effective URL + * + * @return self + */ + public function setEffectiveUrl($url) + { + $this->effectiveUrl = $url; + + return $this; + } + + /** + * Get the effective URL that resulted in this response (e.g. the last redirect URL) + * + * @return string + */ + public function getEffectiveUrl() + { + return $this->effectiveUrl; + } + + /** + * @deprecated + * @codeCoverageIgnore + */ + public function getPreviousResponse() + { + Version::warn(__METHOD__ . ' is deprecated. Use the HistoryPlugin.'); + return null; + } + + /** + * @deprecated + * @codeCoverageIgnore + */ + public function setRequest($request) + { + Version::warn(__METHOD__ . ' is deprecated'); + return $this; + } + + /** + * @deprecated + * @codeCoverageIgnore + */ + public function getRequest() + { + Version::warn(__METHOD__ . ' is deprecated'); + return null; + } } diff --git a/core/vendor/guzzle/http/Guzzle/Http/Mimetypes.php b/core/vendor/guzzle/http/Guzzle/Http/Mimetypes.php index 7bf2d28..15af061 100644 --- a/core/vendor/guzzle/http/Guzzle/Http/Mimetypes.php +++ b/core/vendor/guzzle/http/Guzzle/Http/Mimetypes.php @@ -8,14 +8,10 @@ */ class Mimetypes { - /** - * @var self - */ + /** @var self */ protected static $instance; - /** - * @var array Mapping of extension to mimetype - */ + /** @var array Mapping of extension to mimetype */ protected $mimetypes = array( '3dml' => 'text/vnd.in3d.3dml', '3g2' => 'video/3gpp2', diff --git a/core/vendor/guzzle/http/Guzzle/Http/QueryAggregator/CommaAggregator.php b/core/vendor/guzzle/http/Guzzle/Http/QueryAggregator/CommaAggregator.php new file mode 100644 index 0000000..4b4e49d --- /dev/null +++ b/core/vendor/guzzle/http/Guzzle/Http/QueryAggregator/CommaAggregator.php @@ -0,0 +1,20 @@ +isUrlEncoding()) { + return array($query->encodeValue($key) => implode(',', array_map(array($query, 'encodeValue'), $value))); + } else { + return array($key => implode(',', $value)); + } + } +} diff --git a/core/vendor/guzzle/http/Guzzle/Http/QueryAggregator/DuplicateAggregator.php b/core/vendor/guzzle/http/Guzzle/Http/QueryAggregator/DuplicateAggregator.php new file mode 100644 index 0000000..1bf1730 --- /dev/null +++ b/core/vendor/guzzle/http/Guzzle/Http/QueryAggregator/DuplicateAggregator.php @@ -0,0 +1,22 @@ +isUrlEncoding()) { + return array($query->encodeValue($key) => array_map(array($query, 'encodeValue'), $value)); + } else { + return array($key => $value); + } + } +} diff --git a/core/vendor/guzzle/http/Guzzle/Http/QueryAggregator/PhpAggregator.php b/core/vendor/guzzle/http/Guzzle/Http/QueryAggregator/PhpAggregator.php new file mode 100644 index 0000000..133ea2b --- /dev/null +++ b/core/vendor/guzzle/http/Guzzle/Http/QueryAggregator/PhpAggregator.php @@ -0,0 +1,27 @@ + $v) { + $k = "{$key}[{$k}]"; + if (is_array($v)) { + $ret = array_merge($ret, self::aggregate($k, $v, $query)); + } else { + $ret[$query->encodeValue($k)] = $query->encodeValue($v); + } + } + + return $ret; + } +} diff --git a/core/vendor/guzzle/http/Guzzle/Http/QueryAggregator/QueryAggregatorInterface.php b/core/vendor/guzzle/http/Guzzle/Http/QueryAggregator/QueryAggregatorInterface.php new file mode 100644 index 0000000..72bee62 --- /dev/null +++ b/core/vendor/guzzle/http/Guzzle/Http/QueryAggregator/QueryAggregatorInterface.php @@ -0,0 +1,22 @@ +add($key, rawurldecode(str_replace('+', '%20', $parts[1]))); + if (isset($parts[1])) { + $value = rawurldecode(str_replace('+', '%20', $parts[1])); + if ($paramIsPhpStyleArray && !$q->hasKey($key)) { + $value = array($value); + } + $q->add($key, $value); } else { - $q->add($key, ''); + $q->add($key, null); } } } @@ -80,19 +80,15 @@ public static function fromString($query) */ public function __toString() { - if (empty($this->data)) { + if (!$this->data) { return ''; } - $queryString = $this->prefix; - $firstValue = true; + $queryString = ''; - foreach ($this->encodeData($this->data) as $name => $value) { - $value = $value === null ? array('') : (array) $value; - foreach ($value as $v) { - if ($firstValue) { - $firstValue = false; - } else { + foreach ($this->prepareData($this->data) as $name => $value) { + foreach ((array) $value as $v) { + if ($queryString) { $queryString .= $this->fieldSeparator; } $queryString .= $name; @@ -106,69 +102,6 @@ public function __toString() } /** - * Aggregate multi-valued parameters using PHP style syntax - * - * @param string $key The name of the query string parameter - * @param array $value The values of the parameter - * @param bool $encode Set to TRUE to encode field names and values - * - * @return array Returns an array of the combined values - */ - public static function aggregateUsingPhp($key, array $value, $encode = false) - { - $ret = array(); - - foreach ($value as $k => $v) { - $k = "{$key}[{$k}]"; - if (is_array($v)) { - $ret = array_merge($ret, self::aggregateUsingPhp($k, $v, $encode)); - } else { - if ($encode) { - $ret[rawurlencode($k)] = rawurlencode($v); - } else { - $ret[$k] = $v; - } - } - } - - return $ret; - } - - /** - * Aggregate multi-valued parameters by joining the values using a comma - * - * @param string $key The name of the query string parameter - * @param array $value The values of the parameter - * @param bool $encode Set to TRUE to encode field names and values - * - * @return array Returns an array of the combined values - */ - public static function aggregateUsingComma($key, array $value, $encode = false) - { - return $encode - ? array(rawurlencode($key) => implode(',', array_map('rawurlencode', $value))) - : array($key => implode(',', $value)); - } - - /** - * Aggregate multi-valued parameters using duplicate values in a query string - * - * Example: http://test.com?q=1&q=2 - * - * @param string $key The name of the query string parameter - * @param array $value The values of the parameter - * @param bool $encode Set to TRUE to encode field names and values - * - * @return array Returns an array of the combined values - */ - public static function aggregateUsingDuplicates($key, array $value, $encode = false) - { - return $encode - ? array(rawurlencode($key) => array_map('rawurlencode', $value)) - : array($key => $value); - } - - /** * Get the query string field separator * * @return string @@ -179,47 +112,59 @@ public function getFieldSeparator() } /** - * Get the query string prefix + * Get the query string value separator * * @return string */ - public function getPrefix() + public function getValueSeparator() { - return $this->prefix; + return $this->valueSeparator; } /** - * Get the query string value separator + * Returns the type of URL encoding used by the query string * - * @return string + * One of: false, "RFC 3986", or "application/x-www-form-urlencoded" + * + * @return bool|string */ - public function getValueSeparator() + public function getUrlEncoding() { - return $this->valueSeparator; + return $this->urlEncode; } /** - * Returns whether or not field names and values will be urlencoded + * Returns true or false if using URL encoding * * @return bool */ public function isUrlEncoding() { - return $this->urlEncode; + return $this->urlEncode !== false; } /** * Provide a function for combining multi-valued query string parameters into a single or multiple fields * - * @param callable|null $callback A function or callback array that accepts a $key, $value, $encodeFields, and - * $encodeValues as arguments and returns an associative array containing the - * combined values. Set to null to remove any custom aggregator. - * @return QueryString + * @param null|QueryAggregatorInterface $aggregator Pass in a QueryAggregatorInterface object to handle converting + * deeply nested query string variables into a flattened array. + * Pass null to use the default PHP style aggregator. For legacy + * reasons, this function accepts a callable that must accepts a + * $key, $value, and query object. + * @return self * @see \Guzzle\Http\QueryString::aggregateUsingComma() */ - public function setAggregateFunction($callback) + public function setAggregator(QueryAggregatorInterface $aggregator = null) { - $this->aggregator = $callback; + // Use the default aggregator if none was set + if (!$aggregator) { + if (!self::$defaultAggregator) { + self::$defaultAggregator = new PhpAggregator(); + } + $aggregator = self::$defaultAggregator; + } + + $this->aggregator = $aggregator; return $this; } @@ -227,13 +172,13 @@ public function setAggregateFunction($callback) /** * Set whether or not field names and values should be rawurlencoded * - * @param bool $encode Set whether or not to encode - * - * @return QueryString + * @param bool|string $encode Set to TRUE to use RFC 3986 encoding (rawurlencode), false to disable encoding, or + * form_urlencoding to use application/x-www-form-urlencoded encoding (urlencode) + * @return self */ public function useUrlEncoding($encode) { - $this->urlEncode = $encode; + $this->urlEncode = ($encode === true) ? self::RFC_3986 : $encode; return $this; } @@ -243,7 +188,7 @@ public function useUrlEncoding($encode) * * @param string $separator The query string separator that will separate fields * - * @return QueryString + * @return self */ public function setFieldSeparator($separator) { @@ -253,25 +198,11 @@ public function setFieldSeparator($separator) } /** - * Set the query string prefix - * - * @param string $prefix Prefix to use with the query string (e.g. '?') - * - * @return QueryString - */ - public function setPrefix($prefix) - { - $this->prefix = $prefix; - - return $this; - } - - /** * Set the query string value separator * * @param string $separator The query string separator that will separate values from fields * - * @return QueryString + * @return self */ public function setValueSeparator($separator) { @@ -287,31 +218,47 @@ public function setValueSeparator($separator) */ public function urlEncode() { - return $this->encodeData($this->data); + return $this->prepareData($this->data); } /** - * Url encode parameter data. + * URL encodes a value based on the url encoding type of the query string object * - * If a parameter value is an array and no aggregator has been set, the values of the array will be converted into - * a PHP compatible form array. If an aggregator is set, the values will be converted using the aggregator function + * @param string $value Value to encode + * + * @return string + */ + public function encodeValue($value) + { + if ($this->urlEncode == self::RFC_3986) { + return rawurlencode($value); + } elseif ($this->urlEncode == self::FORM_URLENCODED) { + return urlencode($value); + } else { + return (string) $value; + } + } + + /** + * Url encode parameter data and convert nested query strings into a flattened hash. * * @param array $data The data to encode * * @return array Returns an array of encoded values and keys */ - protected function encodeData(array $data) + protected function prepareData(array $data) { + // If no aggregator is present then set the default + if (!$this->aggregator) { + $this->setAggregator(null); + } + $temp = array(); foreach ($data as $key => $value) { if (is_array($value)) { - $temp = array_merge($temp, call_user_func_array($this->aggregator, array($key, $value, $this->urlEncode))); + $temp = array_merge($temp, $this->aggregator->aggregate($key, $value, $this)); } else { - if ($this->urlEncode) { - $temp[rawurlencode($key)] = rawurlencode($value); - } else { - $temp[$key] = (string) $value; - } + $temp[$this->encodeValue($key)] = $this->encodeValue($value); } } diff --git a/core/vendor/guzzle/http/Guzzle/Http/ReadLimitEntityBody.php b/core/vendor/guzzle/http/Guzzle/Http/ReadLimitEntityBody.php index 4aabde7..d0bc867 100644 --- a/core/vendor/guzzle/http/Guzzle/Http/ReadLimitEntityBody.php +++ b/core/vendor/guzzle/http/Guzzle/Http/ReadLimitEntityBody.php @@ -7,14 +7,10 @@ */ class ReadLimitEntityBody extends AbstractEntityBodyDecorator { - /** - * @var int Limit the number of bytes that can be read - */ + /** @var int Limit the number of bytes that can be read */ protected $limit; - /** - * @var int Offset to start reading from - */ + /** @var int Offset to start reading from */ protected $offset; /** @@ -35,12 +31,9 @@ public function __construct(EntityBodyInterface $body, $limit, $offset = 0) */ public function __toString() { - return substr((string) $this->body, $this->offset, $this->limit); + return substr((string) $this->body, $this->offset, $this->limit) ?: ''; } - /** - * {@inheritdoc} - */ public function isConsumed() { return (($this->offset + $this->limit) - $this->body->ftell()) <= 0; @@ -99,9 +92,6 @@ public function setLimit($limit) return $this; } - /** - * {@inheritdoc} - */ public function read($length) { // Check if the current position is less than the total allowed bytes + original offset diff --git a/core/vendor/guzzle/http/Guzzle/Http/RedirectPlugin.php b/core/vendor/guzzle/http/Guzzle/Http/RedirectPlugin.php index de48176..391edb1 100644 --- a/core/vendor/guzzle/http/Guzzle/Http/RedirectPlugin.php +++ b/core/vendor/guzzle/http/Guzzle/Http/RedirectPlugin.php @@ -3,9 +3,11 @@ namespace Guzzle\Http; use Guzzle\Common\Event; +use Guzzle\Http\Exception\BadResponseException; use Guzzle\Http\Url; use Guzzle\Http\Message\Response; use Guzzle\Http\Message\RequestInterface; +use Guzzle\Http\Message\RequestFactory; use Guzzle\Http\Message\EntityEnclosingRequestInterface; use Guzzle\Http\Exception\TooManyRedirectsException; use Guzzle\Http\Exception\CouldNotRewindStreamException; @@ -27,14 +29,12 @@ class RedirectPlugin implements EventSubscriberInterface */ protected $defaultMaxRedirects = 5; - /** - * {@inheritdoc} - */ public static function getSubscribedEvents() { return array( - 'request.sent' => array('onRequestSent', 100), - 'request.clone' => 'onRequestClone' + 'request.sent' => array('onRequestSent', 100), + 'request.clone' => 'cleanupRequest', + 'request.before_send' => 'cleanupRequest' ); } @@ -43,9 +43,11 @@ public static function getSubscribedEvents() * * @param Event $event Event emitted */ - public function onRequestClone(Event $event) + public function cleanupRequest(Event $event) { - $event['request']->getParams()->remove(self::REDIRECT_COUNT)->remove(self::PARENT_REQUEST); + $params = $event['request']->getParams(); + unset($params[self::REDIRECT_COUNT]); + unset($params[self::PARENT_REQUEST]); } /** @@ -59,29 +61,43 @@ public function onRequestSent(Event $event) $request = $event['request']; // Only act on redirect requests with Location headers - if (!$response || !$response->isRedirect() || !$response->hasHeader('Location') - || $request->getParams()->get(self::DISABLE) - ) { + if (!$response || $request->getParams()->get(self::DISABLE)) { return; } - // Prepare the request for a redirect and grab the original request that started the transaction - $originalRequest = $this->prepareRedirection($request); + // Trace the original request based on parameter history + $original = $this->getOriginalRequest($request); - // Create a redirect request based on the redirect rules set on the request - $redirectRequest = $this->createRedirectRequest( - $request, - $event['response']->getStatusCode(), - trim($response->getHeader('Location')), - $originalRequest - ); + // Terminating condition to set the effective repsonse on the original request + if (!$response->isRedirect() || !$response->hasHeader('Location')) { + if ($request !== $original) { + // This is a terminating redirect response, so set it on the original request + $response->getParams()->set(self::REDIRECT_COUNT, $original->getParams()->get(self::REDIRECT_COUNT)); + $original->setResponse($response); + $response->setEffectiveUrl($request->getUrl()); + } + return; + } + + $this->sendRedirectRequest($original, $request, $response); + } - // Send the redirect request and hijack the response of the original request - $redirectResponse = $redirectRequest->send(); - $request->setResponse($redirectResponse); - if (!$redirectResponse->getPreviousResponse()) { - $redirectResponse->setPreviousResponse($response); + /** + * Get the original request that initiated a series of redirects + * + * @param RequestInterface $request Request to get the original request from + * + * @return RequestInterface + */ + protected function getOriginalRequest(RequestInterface $request) + { + $original = $request; + // The number of redirects is held on the original request, so determine which request that is + while ($parent = $original->getParams()->get(self::PARENT_REQUEST)) { + $original = $parent; } + + return $original; } /** @@ -106,14 +122,19 @@ protected function createRedirectRequest( ) { $redirectRequest = null; $strict = $original->getParams()->get(self::STRICT_REDIRECTS); + // Use a GET request if this is an entity enclosing request and we are not forcing RFC compliance, but rather // emulating what all browsers would do if ($request instanceof EntityEnclosingRequestInterface && !$strict && $statusCode <= 302) { - $redirectRequest = $this->cloneRequestWithGetMethod($request); + $redirectRequest = RequestFactory::getInstance()->cloneRequestWithMethod($request, 'GET'); } else { $redirectRequest = clone $request; } + $redirectRequest->setIsRedirect(true); + // Always use the same response body when redirecting + $redirectRequest->setResponseBody($request->getResponseBody()); + $location = Url::factory($location); // If the location is not absolute, then combine it with the original URL if (!$location->isAbsolute()) { @@ -124,7 +145,15 @@ protected function createRedirectRequest( } $redirectRequest->setUrl($location); - $redirectRequest->getParams()->set(self::PARENT_REQUEST, $request); + + // Add the parent request to the request before it sends (make sure it's before the onRequestClone event too) + $redirectRequest->getEventDispatcher()->addListener( + 'request.before_send', + $func = function ($e) use (&$func, $request, $redirectRequest) { + $redirectRequest->getEventDispatcher()->removeListener('request.before_send', $func); + $e['request']->getParams()->set(RedirectPlugin::PARENT_REQUEST, $request); + } + ); // Rewind the entity body of the request if needed if ($redirectRequest instanceof EntityEnclosingRequestInterface && $redirectRequest->getBody()) { @@ -143,85 +172,79 @@ protected function createRedirectRequest( } /** - * Clone a request while changing the method to GET. Emulates the behavior of - * {@see Guzzle\Http\Message\Request::clone}, but can change the HTTP method. - * - * @param EntityEnclosingRequestInterface $request Request to clone - * - * @return RequestInterface Returns a GET request - */ - protected function cloneRequestWithGetMethod(EntityEnclosingRequestInterface $request) - { - // Create a new GET request using the original request's URL - $redirectRequest = $request->getClient()->get($request->getUrl()); - $redirectRequest->getCurlOptions()->replace($request->getCurlOptions()->getAll()); - // Copy over the headers, while ensuring that the Content-Length is not copied - $redirectRequest->setHeaders($request->getHeaders()->getAll())->removeHeader('Content-Length'); - $redirectRequest->setEventDispatcher(clone $request->getEventDispatcher()); - $redirectRequest->getParams() - ->replace($request->getParams()->getAll()) - ->remove('curl_handle')->remove('queued_response')->remove('curl_multi'); - - return $redirectRequest; - } - - /** * Prepare the request for redirection and enforce the maximum number of allowed redirects per client * - * @param RequestInterface $request Request to prepare and validate + * @param RequestInterface $original Origina request + * @param RequestInterface $request Request to prepare and validate + * @param Response $response The current response * - * @return RequestInterface Returns the original request + * @return RequestInterface */ - protected function prepareRedirection(RequestInterface $request) + protected function prepareRedirection(RequestInterface $original, RequestInterface $request, Response $response) { - $original = $request; - // The number of redirects is held on the original request, so determine which request that is - while ($parent = $original->getParams()->get(self::PARENT_REQUEST)) { - $original = $parent; - } - - // Always associate the parent response with the current response so that a chain can be established - if ($parent = $request->getParams()->get(self::PARENT_REQUEST)) { - $request->getResponse()->setPreviousResponse($parent->getResponse()); - } - $params = $original->getParams(); // This is a new redirect, so increment the redirect counter - $current = $params->get(self::REDIRECT_COUNT) + 1; - $params->set(self::REDIRECT_COUNT, $current); - + $current = $params[self::REDIRECT_COUNT] + 1; + $params[self::REDIRECT_COUNT] = $current; // Use a provided maximum value or default to a max redirect count of 5 - $max = $params->hasKey(self::MAX_REDIRECTS) - ? $params->get(self::MAX_REDIRECTS) - : $this->defaultMaxRedirects; + $max = isset($params[self::MAX_REDIRECTS]) ? $params[self::MAX_REDIRECTS] : $this->defaultMaxRedirects; // Throw an exception if the redirect count is exceeded if ($current > $max) { - return $this->throwTooManyRedirectsException($request); + $this->throwTooManyRedirectsException($original, $max); + return false; + } else { + // Create a redirect request based on the redirect rules set on the request + return $this->createRedirectRequest( + $request, + $response->getStatusCode(), + trim($response->getLocation()), + $original + ); } + } - return $original; + /** + * Send a redirect request and handle any errors + * + * @param RequestInterface $original The originating request + * @param RequestInterface $request The current request being redirected + * @param Response $response The response of the current request + * + * @throws BadResponseException|\Exception + */ + protected function sendRedirectRequest(RequestInterface $original, RequestInterface $request, Response $response) + { + // Validate and create a redirect request based on the original request and current response + if ($redirectRequest = $this->prepareRedirection($original, $request, $response)) { + try { + $redirectRequest->send(); + } catch (BadResponseException $e) { + $e->getResponse(); + if (!$e->getResponse()) { + throw $e; + } + } + } } /** * Throw a too many redirects exception for a request * - * @param RequestInterface $request Request + * @param RequestInterface $original Request + * @param int $max Max allowed redirects + * * @throws TooManyRedirectsException when too many redirects have been issued */ - protected function throwTooManyRedirectsException(RequestInterface $request) + protected function throwTooManyRedirectsException(RequestInterface $original, $max) { - $responses = array(); - - // Create a nice message to use when throwing the exception that shows each request/response transaction - do { - $response = $request->getResponse(); - $responses[] = '> ' . $request->getRawHeaders() . "\n\n< " . $response->getRawHeaders(); - $request = $response->getPreviousResponse() ? $response->getPreviousResponse()->getRequest() : null; - } while ($request); - - $transaction = implode("* Sending redirect request\n", array_reverse($responses)); - - throw new TooManyRedirectsException("Too many redirects were issued for this transaction:\n{$transaction}"); + $original->getEventDispatcher()->addListener( + 'request.complete', + $func = function ($e) use (&$func, $original, $max) { + $original->getEventDispatcher()->removeListener('request.complete', $func); + $str = "{$max} redirects were issued for this request:\n" . $e['request']->getRawHeaders(); + throw new TooManyRedirectsException($str); + } + ); } } diff --git a/core/vendor/guzzle/http/Guzzle/Http/Resources/cacert.pem b/core/vendor/guzzle/http/Guzzle/Http/Resources/cacert.pem index 8660a40..99b310b 100644 --- a/core/vendor/guzzle/http/Guzzle/Http/Resources/cacert.pem +++ b/core/vendor/guzzle/http/Guzzle/Http/Resources/cacert.pem @@ -1,7 +1,7 @@ ## ## ca-bundle.crt -- Bundle of CA Root Certificates ## -## Certificate data from Mozilla as of: Thu Jun 28 13:50:18 2012 +## Certificate data from Mozilla as of: Sat Dec 29 20:03:40 2012 ## ## This is a bundle of X.509 certificates of public Certificate Authorities ## (CA). These were automatically extracted from Mozilla's root certificates @@ -14,7 +14,7 @@ ## Just configure this file as the SSLCACertificateFile. ## -# @(#) $RCSfile: certdata.txt,v $ $Revision: 1.85 $ $Date: 2012/06/28 13:50:18 $ +# @(#) $RCSfile: certdata.txt,v $ $Revision: 1.87 $ $Date: 2012/12/29 16:32:45 $ GTE CyberTrust Global Root ========================== @@ -3847,3 +3847,49 @@ UZTLfhbrES+jkkXITHHZvMmZUldGL1DPvTVp9D0VzgalLA8+9oG6lLvDu79leNKGef9JOxqDDPDe eOzI8k1MGt6CKfjBWtrt7uYnXuhF0J0cUahoq0Tj0Itq4/g7u9xN12TyUb7mqqta6THuBrxzvxNi Cp/HuZc= -----END CERTIFICATE----- + +T-TeleSec GlobalRoot Class 3 +============================ +-----BEGIN CERTIFICATE----- +MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoM +IlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBU +cnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDMwHhcNMDgx +MDAxMTAyOTU2WhcNMzMxMDAxMjM1OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lz +dGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBD +ZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDMwggEiMA0GCSqGSIb3 +DQEBAQUAA4IBDwAwggEKAoIBAQC9dZPwYiJvJK7genasfb3ZJNW4t/zN8ELg63iIVl6bmlQdTQyK +9tPPcPRStdiTBONGhnFBSivwKixVA9ZIw+A5OO3yXDw/RLyTPWGrTs0NvvAgJ1gORH8EGoel15YU +NpDQSXuhdfsaa3Ox+M6pCSzyU9XDFES4hqX2iys52qMzVNn6chr3IhUciJFrf2blw2qAsCTz34ZF +iP0Zf3WHHx+xGwpzJFu5ZeAsVMhg02YXP+HMVDNzkQI6pn97djmiH5a2OK61yJN0HZ65tOVgnS9W +0eDrXltMEnAMbEQgqxHY9Bn20pxSN+f6tsIxO0rUFJmtxxr1XV/6B7h8DR/Wgx6zAgMBAAGjQjBA +MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS1A/d2O2GCahKqGFPr +AyGUv/7OyjANBgkqhkiG9w0BAQsFAAOCAQEAVj3vlNW92nOyWL6ukK2YJ5f+AbGwUgC4TeQbIXQb +fsDuXmkqJa9c1h3a0nnJ85cp4IaH3gRZD/FZ1GSFS5mvJQQeyUapl96Cshtwn5z2r3Ex3XsFpSzT +ucpH9sry9uetuUg/vBa3wW306gmv7PO15wWeph6KU1HWk4HMdJP2udqmJQV0eVp+QD6CSyYRMG7h +P0HHRwA11fXT91Q+gT3aSWqas+8QPebrb9HIIkfLzM8BMZLZGOMivgkeGj5asuRrDFR6fUNOuIml +e9eiPZaGzPImNC1qkp2aGtAw4l1OBLBfiyB+d8E9lYLRRpo7PHi4b6HQDWSieB4pTpPDpFQUWw== +-----END CERTIFICATE----- + +EE Certification Centre Root CA +=============================== +-----BEGIN CERTIFICATE----- +MIIEAzCCAuugAwIBAgIQVID5oHPtPwBMyonY43HmSjANBgkqhkiG9w0BAQUFADB1MQswCQYDVQQG +EwJFRTEiMCAGA1UECgwZQVMgU2VydGlmaXRzZWVyaW1pc2tlc2t1czEoMCYGA1UEAwwfRUUgQ2Vy +dGlmaWNhdGlvbiBDZW50cmUgUm9vdCBDQTEYMBYGCSqGSIb3DQEJARYJcGtpQHNrLmVlMCIYDzIw +MTAxMDMwMTAxMDMwWhgPMjAzMDEyMTcyMzU5NTlaMHUxCzAJBgNVBAYTAkVFMSIwIAYDVQQKDBlB +UyBTZXJ0aWZpdHNlZXJpbWlza2Vza3VzMSgwJgYDVQQDDB9FRSBDZXJ0aWZpY2F0aW9uIENlbnRy +ZSBSb290IENBMRgwFgYJKoZIhvcNAQkBFglwa2lAc2suZWUwggEiMA0GCSqGSIb3DQEBAQUAA4IB +DwAwggEKAoIBAQDIIMDs4MVLqwd4lfNE7vsLDP90jmG7sWLqI9iroWUyeuuOF0+W2Ap7kaJjbMeM +TC55v6kF/GlclY1i+blw7cNRfdCT5mzrMEvhvH2/UpvObntl8jixwKIy72KyaOBhU8E2lf/slLo2 +rpwcpzIP5Xy0xm90/XsY6KxX7QYgSzIwWFv9zajmofxwvI6Sc9uXp3whrj3B9UiHbCe9nyV0gVWw +93X2PaRka9ZP585ArQ/dMtO8ihJTmMmJ+xAdTX7Nfh9WDSFwhfYggx/2uh8Ej+p3iDXE/+pOoYtN +P2MbRMNE1CV2yreN1x5KZmTNXMWcg+HCCIia7E6j8T4cLNlsHaFLAgMBAAGjgYowgYcwDwYDVR0T +AQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFBLyWj7qVhy/zQas8fElyalL1BSZ +MEUGA1UdJQQ+MDwGCCsGAQUFBwMCBggrBgEFBQcDAQYIKwYBBQUHAwMGCCsGAQUFBwMEBggrBgEF +BQcDCAYIKwYBBQUHAwkwDQYJKoZIhvcNAQEFBQADggEBAHv25MANqhlHt01Xo/6tu7Fq1Q+e2+Rj +xY6hUFaTlrg4wCQiZrxTFGGVv9DHKpY5P30osxBAIWrEr7BSdxjhlthWXePdNl4dp1BUoMUq5KqM +lIpPnTX/dqQGE5Gion0ARD9V04I8GtVbvFZMIi5GQ4okQC3zErg7cBqklrkar4dBGmoYDQZPxz5u +uSlNDUmJEYcyW+ZLBMjkXOZ0c5RdFpgTlf7727FE5TpwrDdr5rMzcijJs1eg9gIWiAYLtqZLICjU +3j2LrTcFU3T+bsy8QxdxXvnFzBqpYe73dgzzcvRyrc9yAjYHR8/vGVCJYMzpJJUPwssd8m92kMfM +dcGWxZ0= +-----END CERTIFICATE----- diff --git a/core/vendor/guzzle/http/Guzzle/Http/Resources/cacert.pem.md5 b/core/vendor/guzzle/http/Guzzle/Http/Resources/cacert.pem.md5 new file mode 100644 index 0000000..56f626a --- /dev/null +++ b/core/vendor/guzzle/http/Guzzle/Http/Resources/cacert.pem.md5 @@ -0,0 +1 @@ +47961e7ef15667c93cd99be01b51f00a diff --git a/core/vendor/guzzle/http/Guzzle/Http/StaticClient.php b/core/vendor/guzzle/http/Guzzle/Http/StaticClient.php new file mode 100644 index 0000000..dbd4c18 --- /dev/null +++ b/core/vendor/guzzle/http/Guzzle/Http/StaticClient.php @@ -0,0 +1,157 @@ +createRequest($method, $url, null, null, $options); + + if (isset($options['stream'])) { + if ($options['stream'] instanceof StreamRequestFactoryInterface) { + return $options['stream']->fromRequest($request); + } elseif ($options['stream'] == true) { + $streamFactory = new PhpStreamRequestFactory(); + return $streamFactory->fromRequest($request); + } + } + + return $request->send(); + } + + /** + * Send a GET request + * + * @param string $url URL of the request + * @param array $options Array of request options + * + * @return \Guzzle\Http\Message\Response + * @see Guzzle::request for a list of available options + */ + public static function get($url, $options = array()) + { + return self::request('GET', $url, $options); + } + + /** + * Send a HEAD request + * + * @param string $url URL of the request + * @param array $options Array of request options + * + * @return \Guzzle\Http\Message\Response + * @see Guzzle::request for a list of available options + */ + public static function head($url, $options = array()) + { + return self::request('HEAD', $url, $options); + } + + /** + * Send a DELETE request + * + * @param string $url URL of the request + * @param array $options Array of request options + * + * @return \Guzzle\Http\Message\Response + * @see Guzzle::request for a list of available options + */ + public static function delete($url, $options = array()) + { + return self::request('DELETE', $url, $options); + } + + /** + * Send a POST request + * + * @param string $url URL of the request + * @param array $options Array of request options + * + * @return \Guzzle\Http\Message\Response + * @see Guzzle::request for a list of available options + */ + public static function post($url, $options = array()) + { + return self::request('POST', $url, $options); + } + + /** + * Send a PUT request + * + * @param string $url URL of the request + * @param array $options Array of request options + * + * @return \Guzzle\Http\Message\Response + * @see Guzzle::request for a list of available options + */ + public static function put($url, $options = array()) + { + return self::request('PUT', $url, $options); + } + + /** + * Send a PATCH request + * + * @param string $url URL of the request + * @param array $options Array of request options + * + * @return \Guzzle\Http\Message\Response + * @see Guzzle::request for a list of available options + */ + public static function patch($url, $options = array()) + { + return self::request('PATCH', $url, $options); + } + + /** + * Send an OPTIONS request + * + * @param string $url URL of the request + * @param array $options Array of request options + * + * @return \Guzzle\Http\Message\Response + * @see Guzzle::request for a list of available options + */ + public static function options($url, $options = array()) + { + return self::request('OPTIONS', $url, $options); + } +} diff --git a/core/vendor/guzzle/http/Guzzle/Http/Url.php b/core/vendor/guzzle/http/Guzzle/Http/Url.php index 30a26a4..b9b87c6 100644 --- a/core/vendor/guzzle/http/Guzzle/Http/Url.php +++ b/core/vendor/guzzle/http/Guzzle/Http/Url.php @@ -15,12 +15,10 @@ class Url protected $port; protected $username; protected $password; - protected $path = '/'; + protected $path = ''; protected $fragment; - /** - * @var QueryString Query part of the URL - */ + /** @var QueryString Query part of the URL */ protected $query; /** @@ -29,13 +27,21 @@ class Url * @param string $url Full URL used to create a Url object * * @return Url + * @throws InvalidArgumentException */ public static function factory($url) { - $parts = ParserRegistry::getInstance()->getParser('url')->parseUrl($url); + static $defaults = array('scheme' => null, 'host' => null, 'path' => null, 'port' => null, 'query' => null, + 'user' => null, 'pass' => null, 'fragment' => null); + + if (false === ($parts = parse_url($url))) { + throw new InvalidArgumentException('Was unable to parse malformed url: ' . $url); + } + + $parts += $defaults; // Convert the query string into a QueryString object - if ($parts['query']) { + if ($parts['query'] || 0 !== strlen($parts['query'])) { $parts['query'] = QueryString::fromString($parts['query']); } @@ -57,11 +63,11 @@ public static function buildUrl(array $parts) if (isset($parts['scheme'])) { $scheme = $parts['scheme']; - $url .= $scheme . '://'; + $url .= $scheme . ':'; } if (isset($parts['host'])) { - + $url .= '//'; if (isset($parts['user'])) { $url .= $parts['user']; if (isset($parts['pass'])) { @@ -74,32 +80,28 @@ public static function buildUrl(array $parts) // Only include the port if it is not the default port of the scheme if (isset($parts['port']) - && !(($scheme == 'http' && $parts['port'] == 80) - || ($scheme == 'https' && $parts['port'] == 443))) { + && !(($scheme == 'http' && $parts['port'] == 80) || ($scheme == 'https' && $parts['port'] == 443)) + ) { $url .= ':' . $parts['port']; } } - if (empty($parts['path'])) { - $url .= '/'; - } else { - if ($parts['path'][0] != '/') { + // Add the path component if present + if (isset($parts['path']) && 0 !== strlen($parts['path'])) { + // Always ensure that the path begins with '/' if set and something is before the path + if ($url && $parts['path'][0] != '/' && substr($url, -1) != '/') { $url .= '/'; } $url .= $parts['path']; } // Add the query string if present - if (!empty($parts['query'])) { - if ($parts['query'][0] != '?') { - $url .= array_key_exists('query_prefix', $parts) - ? $parts['query_prefix'] : '?'; - } - $url .= $parts['query']; + if (isset($parts['query'])) { + $url .= '?' . $parts['query']; } // Ensure that # is only added to the url if fragment contains anything. - if (isset($parts['fragment']) && !empty($parts['fragment'])) { + if (isset($parts['fragment'])) { $url .= '#' . $parts['fragment']; } @@ -126,11 +128,12 @@ public function __construct($scheme, $host, $username = null, $password = null, $this->username = $username; $this->password = $password; $this->fragment = $fragment; - $this->setQuery($query ?: new QueryString()); - - if ($path) { - $this->setPath($path); + if (!$query) { + $this->query = new QueryString(); + } else { + $this->setQuery($query); } + $this->setPath($path); } /** @@ -165,9 +168,8 @@ public function getParts() 'host' => $this->host, 'port' => $this->port, 'path' => $this->getPath(), - 'query' => (string) $this->query, + 'query' => (string) $this->query ?: null, 'fragment' => $this->fragment, - 'query_prefix' => $this->query->getPrefix() ); } @@ -269,10 +271,7 @@ public function setPath($path) if (is_array($path)) { $this->path = '/' . implode('/', $path); } else { - if (substr($path, 0, 1) != '/' && $path != '*') { - $path = '/' . $path; - } - $this->path = $path; + $this->path = (string) $path; } return $this; @@ -285,14 +284,15 @@ public function setPath($path) */ public function normalizePath() { - if ($this->path == '*') { + if (!$this->path || $this->path == '/' || $this->path == '*') { return $this; } - if ($this->path && $this->path != '/') { + // Replace // and /./ with / + $this->path = str_replace(array('/./', '//'), '/', $this->path); - // Replace // and /./ with / - $this->path = str_replace(array('/./', '//'), '/', $this->path); + // Remove dot segments + if (strpos($this->path, '..') !== false) { // Remove trailing relative paths if possible $segments = $this->getPathSegments(); @@ -319,11 +319,6 @@ public function normalizePath() } } - // Must always start with a slash - if (substr($this->path, 0, 1) != '/') { - $this->path = '/' . $this->path; - } - return $this; } @@ -355,7 +350,7 @@ public function addPath($relativePath) */ public function getPath() { - return $this->path ?: '/'; + return $this->path; } /** @@ -483,60 +478,66 @@ public function isAbsolute() } /** - * Combine the URL with another URL. Parts specified in the passed URL will supersede parts in the current URL. + * Combine the URL with another URL. Follows the rules specific in RFC 3986 section 5.4. * * @param string $url Relative URL to combine with * * @return Url * @throws InvalidArgumentException + * @link http://tools.ietf.org/html/rfc3986#section-5.4 */ public function combine($url) { - $absolutePath = $url[0] == '/'; $url = self::factory($url); + // Use the more absolute URL as the base URL + if (!$this->isAbsolute() && $url->isAbsolute()) { + $url = $url->combine($this); + } + + // Passing a URL with a scheme overrides everything if ($buffer = $url->getScheme()) { $this->scheme = $buffer; + $this->host = $url->getHost(); + $this->port = $url->getPort(); + $this->username = $url->getUsername(); + $this->password = $url->getPassword(); + $this->path = $url->getPath(); + $this->query = $url->getQuery(); + $this->fragment = $url->getFragment(); + return $this; } + // Setting a host overrides the entire rest of the URL if ($buffer = $url->getHost()) { $this->host = $buffer; + $this->port = $url->getPort(); + $this->username = $url->getUsername(); + $this->password = $url->getPassword(); + $this->path = $url->getPath(); + $this->fragment = $url->getFragment(); + return $this; } - if ($buffer = $url->getPort()) { - $this->port = $buffer; - } - - if ($buffer = $url->getUsername()) { - $this->username = $buffer; - } - - if ($buffer = $url->getPassword()) { - $this->password = $buffer; - } - - if ($buffer = $url->getFragment()) { - $this->fragment = $buffer; - } + $path = $url->getPath(); + $query = $url->getQuery(); - if ($absolutePath) { - // Replace the current URL and query if set - if ($buffer = $url->getPath()) { - $this->path = $buffer; - } - if (count($url->getQuery())) { - $this->query = clone $url->getQuery(); + if (!$path) { + if (count($query)) { + $this->query = $query; } } else { - // Append to the current path and query string - if ($buffer = $url->getPath()) { - $this->addPath($buffer); - } - if ($buffer = $url->getQuery()) { - $this->query->merge($buffer); + if ($path[0] == '/') { + $this->path = $path; + } else { + $this->path .= '/' . $path; } + $this->normalizePath(); + $this->query = $query; } + $this->fragment = $url->getFragment(); + return $this; } } diff --git a/core/vendor/guzzle/http/Guzzle/Http/Utils.php b/core/vendor/guzzle/http/Guzzle/Http/Utils.php deleted file mode 100644 index fd02bd0..0000000 --- a/core/vendor/guzzle/http/Guzzle/Http/Utils.php +++ /dev/null @@ -1,52 +0,0 @@ -get('version'), - PHP_VERSION - ); - } - - return self::$userAgent; - } -} diff --git a/core/vendor/guzzle/http/Guzzle/Http/composer.json b/core/vendor/guzzle/http/Guzzle/Http/composer.json index 292cd83..9384a5b 100644 --- a/core/vendor/guzzle/http/Guzzle/Http/composer.json +++ b/core/vendor/guzzle/http/Guzzle/Http/composer.json @@ -26,7 +26,7 @@ "target-dir": "Guzzle/Http", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-master": "3.7-dev" } } } diff --git a/core/vendor/guzzle/parser/Guzzle/Parser/Cookie/CookieParser.php b/core/vendor/guzzle/parser/Guzzle/Parser/Cookie/CookieParser.php index 1ba8e79..8e825f9 100644 --- a/core/vendor/guzzle/parser/Guzzle/Parser/Cookie/CookieParser.php +++ b/core/vendor/guzzle/parser/Guzzle/Parser/Cookie/CookieParser.php @@ -7,9 +7,7 @@ */ class CookieParser implements CookieParserInterface { - /** - * @var array Cookie part names to snake_case array values - */ + /** @var array Cookie part names to snake_case array values */ protected static $cookieParts = array( 'domain' => 'Domain', 'path' => 'Path', @@ -24,9 +22,6 @@ class CookieParser implements CookieParserInterface 'http_only' => 'HttpOnly' ); - /** - * {@inheritdoc} - */ public function parseCookie($cookie, $host = null, $path = null, $decode = false) { // Explode the cookie string using a series of semicolons diff --git a/core/vendor/guzzle/parser/Guzzle/Parser/Message/AbstractMessageParser.php b/core/vendor/guzzle/parser/Guzzle/Parser/Message/AbstractMessageParser.php index cb97500..d25f9cc 100644 --- a/core/vendor/guzzle/parser/Guzzle/Parser/Message/AbstractMessageParser.php +++ b/core/vendor/guzzle/parser/Guzzle/Parser/Message/AbstractMessageParser.php @@ -29,7 +29,7 @@ protected function getUrlPartsFromMessage($requestUrl, array $parts) } elseif (isset($parts['headers']['host'])) { $urlParts['host'] = $parts['headers']['host']; } else { - $urlParts['host'] = ''; + $urlParts['host'] = null; } if (false === strpos($urlParts['host'], ':')) { diff --git a/core/vendor/guzzle/parser/Guzzle/Parser/Message/MessageParser.php b/core/vendor/guzzle/parser/Guzzle/Parser/Message/MessageParser.php index 47f9908..1047400 100644 --- a/core/vendor/guzzle/parser/Guzzle/Parser/Message/MessageParser.php +++ b/core/vendor/guzzle/parser/Guzzle/Parser/Message/MessageParser.php @@ -7,9 +7,6 @@ */ class MessageParser extends AbstractMessageParser { - /** - * {@inheritdoc} - */ public function parseRequest($message) { if (!$message) { @@ -41,9 +38,6 @@ public function parseRequest($message) return $parsed; } - /** - * {@inheritdoc} - */ public function parseResponse($message) { if (!$message) { diff --git a/core/vendor/guzzle/parser/Guzzle/Parser/Message/PeclHttpMessageParser.php b/core/vendor/guzzle/parser/Guzzle/Parser/Message/PeclHttpMessageParser.php index b7366a1..944aaa2 100644 --- a/core/vendor/guzzle/parser/Guzzle/Parser/Message/PeclHttpMessageParser.php +++ b/core/vendor/guzzle/parser/Guzzle/Parser/Message/PeclHttpMessageParser.php @@ -7,9 +7,6 @@ */ class PeclHttpMessageParser extends AbstractMessageParser { - /** - * {@inheritdoc} - */ public function parseRequest($message) { if (!$message) { @@ -31,9 +28,6 @@ public function parseRequest($message) return $parsed; } - /** - * {@inheritdoc} - */ public function parseResponse($message) { if (!$message) { diff --git a/core/vendor/guzzle/parser/Guzzle/Parser/ParserRegistry.php b/core/vendor/guzzle/parser/Guzzle/Parser/ParserRegistry.php index 3b5193b..f838683 100644 --- a/core/vendor/guzzle/parser/Guzzle/Parser/ParserRegistry.php +++ b/core/vendor/guzzle/parser/Guzzle/Parser/ParserRegistry.php @@ -7,19 +7,13 @@ */ class ParserRegistry { - /** - * @var ParserRegistry Singleton instance - */ + /** @var ParserRegistry Singleton instance */ protected static $instance; - /** - * @var array Array of parser instances - */ + /** @var array Array of parser instances */ protected $instances = array(); - /** - * @var array Mapping of parser name to default class - */ + /** @var array Mapping of parser name to default class */ protected $mapping = array( 'message' => 'Guzzle\\Parser\\Message\\MessageParser', 'cookie' => 'Guzzle\\Parser\\Cookie\\CookieParser', @@ -28,8 +22,6 @@ class ParserRegistry ); /** - * Get a singleton instance - * * @return self * @codeCoverageIgnore */ @@ -42,9 +34,6 @@ public static function getInstance() return self::$instance; } - /** - * Constructor used to apply the most performant parsers based on loaded extensions - */ public function __construct() { // Use the PECL URI template parser if available @@ -83,31 +72,4 @@ public function registerParser($name, $parser) { $this->instances[$name] = $parser; } - - /** - * Get a specific parser by handle name - * - * @param string $name Name of the parser to retrieve - * - * @return mixed|null Returns null if the parser is not found or cannot be instantiated - * @deprecated Will be removed in 3.1.0 - * @codeCoverageIgnore - */ - public static function get($name) - { - return self::getInstance()->getParser($name); - } - - /** - * Register a custom parser by name with the register - * - * @param string $name Name or handle of the parser to register - * @param mixed $parser Instantiated parser to register - * @deprecated Will be removed in 3.1.0 - * @codeCoverageIgnore - */ - public static function set($name, $parser) - { - self::getInstance()->registerParser($name, $parser); - } } diff --git a/core/vendor/guzzle/parser/Guzzle/Parser/UriTemplate/PeclUriTemplate.php b/core/vendor/guzzle/parser/Guzzle/Parser/UriTemplate/PeclUriTemplate.php index 700e5d2..b0764e8 100644 --- a/core/vendor/guzzle/parser/Guzzle/Parser/UriTemplate/PeclUriTemplate.php +++ b/core/vendor/guzzle/parser/Guzzle/Parser/UriTemplate/PeclUriTemplate.php @@ -12,10 +12,6 @@ */ class PeclUriTemplate implements UriTemplateInterface { - /** - * Validates that the uri_template extension is installed - * @codeCoverageIgnore - */ public function __construct() { if (!extension_loaded('uri_template')) { @@ -23,9 +19,6 @@ public function __construct() } } - /** - * {@inheritdoc} - */ public function expand($template, array $variables) { return uri_template($template, $variables); diff --git a/core/vendor/guzzle/parser/Guzzle/Parser/UriTemplate/UriTemplate.php b/core/vendor/guzzle/parser/Guzzle/Parser/UriTemplate/UriTemplate.php index 00d2310..2044810 100644 --- a/core/vendor/guzzle/parser/Guzzle/Parser/UriTemplate/UriTemplate.php +++ b/core/vendor/guzzle/parser/Guzzle/Parser/UriTemplate/UriTemplate.php @@ -9,46 +9,31 @@ */ class UriTemplate implements UriTemplateInterface { - /** - * @var string URI template - */ + /** @var string URI template */ private $template; - /** - * @var array Variables to use in the template expansion - */ + /** @var array Variables to use in the template expansion */ private $variables; - /** - * @var string Regex used to parse expressions - */ + /** @var string Regex used to parse expressions */ private static $regex = '/\{([^\}]+)\}/'; - /** - * @var array Hash for quick operator lookups - */ + /** @var array Hash for quick operator lookups */ private static $operatorHash = array( '+' => true, '#' => true, '.' => true, '/' => true, ';' => true, '?' => true, '&' => true ); - /** - * @var array Delimiters - */ + /** @var array Delimiters */ private static $delims = array( ':', '/', '?', '#', '[', ']', '@', '!', '$', '&', '\'', '(', ')', '*', '+', ',', ';', '=' ); - /** - * @var array Percent encoded delimiters - */ + /** @var array Percent encoded delimiters */ private static $delimsPct = array( '%3A', '%2F', '%3F', '%23', '%5B', '%5D', '%40', '%21', '%24', '%26', '%27', '%28', '%29', '%2A', '%2B', '%2C', '%3B', '%3D' ); - /** - * {@inheritdoc} - */ public function expand($template, array $variables) { $this->template = $template; diff --git a/core/vendor/guzzle/parser/Guzzle/Parser/Url/UrlParser.php b/core/vendor/guzzle/parser/Guzzle/Parser/Url/UrlParser.php index 7d37d04..c4cc896 100644 --- a/core/vendor/guzzle/parser/Guzzle/Parser/Url/UrlParser.php +++ b/core/vendor/guzzle/parser/Guzzle/Parser/Url/UrlParser.php @@ -2,14 +2,16 @@ namespace Guzzle\Parser\Url; +use Guzzle\Common\Version; + /** * Parses URLs into parts using PHP's built-in parse_url() function + * @deprecated Just use parse_url. UTF-8 characters should be percent encoded anyways. + * @codeCoverageIgnore */ class UrlParser implements UrlParserInterface { - /** - * @var bool Whether or not to work with UTF-8 strings - */ + /** @var bool Whether or not to work with UTF-8 strings */ protected $utf8 = false; /** @@ -22,11 +24,13 @@ public function setUtf8Support($utf8) $this->utf8 = $utf8; } - /** - * {@inheritdoc} - */ public function parseUrl($url) { + Version::warn(__CLASS__ . ' is deprecated. Just use parse_url()'); + + static $defaults = array('scheme' => null, 'host' => null, 'path' => null, 'port' => null, 'query' => null, + 'user' => null, 'pass' => null, 'fragment' => null); + $parts = parse_url($url); // Need to handle query parsing specially for UTF-8 requirements @@ -39,15 +43,6 @@ public function parseUrl($url) } } - $parts['scheme'] = isset($parts['scheme']) ? $parts['scheme'] : null; - $parts['host'] = isset($parts['host']) ? $parts['host'] : null; - $parts['path'] = isset($parts['path']) ? $parts['path'] : null; - $parts['port'] = isset($parts['port']) ? $parts['port'] : null; - $parts['query'] = isset($parts['query']) ? $parts['query'] : null; - $parts['user'] = isset($parts['user']) ? $parts['user'] : null; - $parts['pass'] = isset($parts['pass']) ? $parts['pass'] : null; - $parts['fragment'] = isset($parts['fragment']) ? $parts['fragment'] : null; - - return $parts; + return $parts + $defaults; } } diff --git a/core/vendor/guzzle/parser/Guzzle/Parser/composer.json b/core/vendor/guzzle/parser/Guzzle/Parser/composer.json index 9c10342..378b281 100644 --- a/core/vendor/guzzle/parser/Guzzle/Parser/composer.json +++ b/core/vendor/guzzle/parser/Guzzle/Parser/composer.json @@ -13,7 +13,7 @@ "target-dir": "Guzzle/Parser", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-master": "3.7-dev" } } } diff --git a/core/vendor/guzzle/stream/Guzzle/Stream/PhpStreamRequestFactory.php b/core/vendor/guzzle/stream/Guzzle/Stream/PhpStreamRequestFactory.php new file mode 100644 index 0000000..91461c6 --- /dev/null +++ b/core/vendor/guzzle/stream/Guzzle/Stream/PhpStreamRequestFactory.php @@ -0,0 +1,270 @@ +contextOptions = stream_context_get_options($context); + $this->context = $context; + } elseif (is_array($context) || !$context) { + $this->contextOptions = $context; + $this->createContext($params); + } elseif ($context) { + throw new InvalidArgumentException('$context must be an array or resource'); + } + + // Dispatch the before send event + $request->dispatch('request.before_send', array( + 'request' => $request, + 'context' => $this->context, + 'context_options' => $this->contextOptions + )); + + $this->setUrl($request); + $this->addDefaultContextOptions($request); + $this->addSslOptions($request); + $this->addBodyOptions($request); + $this->addProxyOptions($request); + + // Create the file handle but silence errors + return $this->createStream($params) + ->setCustomData('request', $request) + ->setCustomData('response_headers', $this->getLastResponseHeaders()); + } + + /** + * Set an option on the context and the internal options array + * + * @param string $wrapper Stream wrapper name of http + * @param string $name Context name + * @param mixed $value Context value + * @param bool $overwrite Set to true to overwrite an existing value + */ + protected function setContextValue($wrapper, $name, $value, $overwrite = false) + { + if (!isset($this->contextOptions[$wrapper])) { + $this->contextOptions[$wrapper] = array($name => $value); + } elseif (!$overwrite && isset($this->contextOptions[$wrapper][$name])) { + return; + } + $this->contextOptions[$wrapper][$name] = $value; + stream_context_set_option($this->context, $wrapper, $name, $value); + } + + /** + * Create a stream context + * + * @param array $params Parameter array + */ + protected function createContext(array $params) + { + $options = $this->contextOptions; + $this->context = $this->createResource(function () use ($params, $options) { + return stream_context_create($options, $params); + }); + } + + /** + * Get the last response headers received by the HTTP request + * + * @return array + */ + public function getLastResponseHeaders() + { + return $this->lastResponseHeaders; + } + + /** + * Adds the default context options to the stream context options + * + * @param RequestInterface $request Request + */ + protected function addDefaultContextOptions(RequestInterface $request) + { + $this->setContextValue('http', 'method', $request->getMethod()); + $this->setContextValue('http', 'header', $request->getHeaderLines()); + // Force 1.0 for now until PHP fully support chunked transfer-encoding decoding + $this->setContextValue('http', 'protocol_version', '1.0'); + $this->setContextValue('http', 'ignore_errors', true); + } + + /** + * Set the URL to use with the factory + * + * @param RequestInterface $request Request that owns the URL + */ + protected function setUrl(RequestInterface $request) + { + $this->url = $request->getUrl(true); + + // Check for basic Auth username + if ($request->getUsername()) { + $this->url->setUsername($request->getUsername()); + } + + // Check for basic Auth password + if ($request->getPassword()) { + $this->url->setPassword($request->getPassword()); + } + } + + /** + * Add SSL options to the stream context + * + * @param RequestInterface $request Request + */ + protected function addSslOptions(RequestInterface $request) + { + if ($verify = $request->getCurlOptions()->get(CURLOPT_SSL_VERIFYPEER)) { + $this->setContextValue('ssl', 'verify_peer', true, true); + if ($cafile = $request->getCurlOptions()->get(CURLOPT_CAINFO)) { + $this->setContextValue('ssl', 'cafile', $cafile, true); + } + } else { + $this->setContextValue('ssl', 'verify_peer', false, true); + } + } + + /** + * Add body (content) specific options to the context options + * + * @param RequestInterface $request + */ + protected function addBodyOptions(RequestInterface $request) + { + // Add the content for the request if needed + if (!($request instanceof EntityEnclosingRequestInterface)) { + return; + } + + if (count($request->getPostFields())) { + $this->setContextValue('http', 'content', (string) $request->getPostFields(), true); + } elseif ($request->getBody()) { + $this->setContextValue('http', 'content', (string) $request->getBody(), true); + } + + // Always ensure a content-length header is sent + if (isset($this->contextOptions['http']['content'])) { + $headers = isset($this->contextOptions['http']['header']) ? $this->contextOptions['http']['header'] : array(); + $headers[] = 'Content-Length: ' . strlen($this->contextOptions['http']['content']); + $this->setContextValue('http', 'header', $headers, true); + } + } + + /** + * Add proxy parameters to the context if needed + * + * @param RequestInterface $request Request + */ + protected function addProxyOptions(RequestInterface $request) + { + if ($proxy = $request->getCurlOptions()->get(CURLOPT_PROXY)) { + $this->setContextValue('http', 'proxy', $proxy); + } + } + + /** + * Create the stream for the request with the context options + * + * @param array $params Parameters of the stream + * + * @return StreamInterface + */ + protected function createStream(array $params) + { + $http_response_header = null; + $url = $this->url; + $context = $this->context; + $fp = $this->createResource(function () use ($context, $url, &$http_response_header) { + return fopen((string) $url, 'r', false, $context); + }); + + // Determine the class to instantiate + $className = isset($params['stream_class']) ? $params['stream_class'] : __NAMESPACE__ . '\\Stream'; + + /** @var $stream StreamInterface */ + $stream = new $className($fp); + + // Track the response headers of the request + if (isset($http_response_header)) { + $this->lastResponseHeaders = $http_response_header; + $this->processResponseHeaders($stream); + } + + return $stream; + } + + /** + * Process response headers + * + * @param StreamInterface $stream + */ + protected function processResponseHeaders(StreamInterface $stream) + { + // Set the size on the stream if it was returned in the response + foreach ($this->lastResponseHeaders as $header) { + if (($pos = stripos($header, 'Content-Length:')) === 0) { + $stream->setSize(trim(substr($header, 15))); + } + } + } + + /** + * Create a resource and check to ensure it was created successfully + * + * @param callable $callback Closure to invoke that must return a valid resource + * + * @return resource + * @throws RuntimeException on error + */ + protected function createResource($callback) + { + // Turn off error reporting while we try to initiate the request + $level = error_reporting(0); + $resource = call_user_func($callback); + error_reporting($level); + + // If the resource could not be created, then grab the last error and throw an exception + if (false === $resource) { + $message = 'Error creating resource. '; + foreach (error_get_last() as $key => $value) { + $message .= "[{$key}] {$value} "; + } + throw new RuntimeException(trim($message)); + } + + return $resource; + } +} diff --git a/core/vendor/guzzle/stream/Guzzle/Stream/Stream.php b/core/vendor/guzzle/stream/Guzzle/Stream/Stream.php index 3b8b364..299f3b3 100644 --- a/core/vendor/guzzle/stream/Guzzle/Stream/Stream.php +++ b/core/vendor/guzzle/stream/Guzzle/Stream/Stream.php @@ -16,40 +16,33 @@ class Stream implements StreamInterface const IS_WRITABLE = 'is_writable'; const SEEKABLE = 'seekable'; - /** - * @var resource Stream resource - */ + /** @var resource Stream resource */ protected $stream; - /** - * @var int Size of the stream contents in bytes - */ + /** @var int Size of the stream contents in bytes */ protected $size; - /** - * @var array Stream cached data - */ + /** @var array Stream cached data */ protected $cache = array(); - /** - * @var array Hash table of readable and writeable stream types for fast lookups - */ + /** @var array Custom stream data */ + protected $customData = array(); + + /** @var array Hash table of readable and writeable stream types for fast lookups */ protected static $readWriteHash = array( 'read' => array( 'r' => true, 'w+' => true, 'r+' => true, 'x+' => true, 'c+' => true, 'rb' => true, 'w+b' => true, 'r+b' => true, 'x+b' => true, 'c+b' => true, - 'rt' => true, 'w+t' => true, 'r+t' => true, 'x+t' => true, 'c+t' => true + 'rt' => true, 'w+t' => true, 'r+t' => true, 'x+t' => true, 'c+t' => true, 'a+' => true ), 'write' => array( 'w' => true, 'w+' => true, 'rw' => true, 'r+' => true, 'x+' => true, 'c+' => true, - 'w+b' => true, 'r+b' => true, 'x+b' => true, 'c+b' => true, - 'w+t' => true, 'r+t' => true, 'x+t' => true, 'c+t' => true + 'wb' => true, 'w+b' => true, 'r+b' => true, 'x+b' => true, 'c+b' => true, + 'w+t' => true, 'r+t' => true, 'x+t' => true, 'c+t' => true, 'a' => true, 'a+' => true ) ); /** - * Construct a new Stream - * * @param resource $stream Stream resource to wrap * @param int $size Size of the stream in bytes. Only pass if the size cannot be obtained from the stream. * @@ -65,14 +58,9 @@ public function __construct($stream, $size = null) */ public function __destruct() { - if (is_resource($this->stream)) { - fclose($this->stream); - } + $this->close(); } - /** - * {@inheritdoc} - */ public function __toString() { if (!$this->isReadable() || (!$this->isSeekable() && $this->isConsumed())) { @@ -86,6 +74,15 @@ public function __toString() return $body; } + public function close() + { + if (is_resource($this->stream)) { + fclose($this->stream); + } + $this->cache[self::IS_READABLE] = false; + $this->cache[self::IS_WRITABLE] = false; + } + /** * Calculate a hash of a Stream * @@ -103,7 +100,7 @@ public static function getHash(StreamInterface $stream, $algo, $rawOutput = fals } $ctx = hash_init($algo); - while ($data = $stream->read(1024)) { + while ($data = $stream->read(8192)) { hash_update($ctx, $data); } @@ -113,9 +110,6 @@ public static function getHash(StreamInterface $stream, $algo, $rawOutput = fals return $out; } - /** - * {@inheritdoc} - */ public function getMetaData($key = null) { $meta = stream_get_meta_data($this->stream); @@ -123,17 +117,11 @@ public function getMetaData($key = null) return !$key ? $meta : (array_key_exists($key, $meta) ? $meta[$key] : null); } - /** - * {@inheritdoc} - */ public function getStream() { return $this->stream; } - /** - * {@inheritdoc} - */ public function setStream($stream, $size = null) { if (!is_resource($stream)) { @@ -147,106 +135,91 @@ public function setStream($stream, $size = null) return $this; } - /** - * {@inheritdoc} - */ + public function detachStream() + { + $this->stream = null; + + return $this; + } + public function getWrapper() { return $this->cache[self::WRAPPER_TYPE]; } - /** - * {@inheritdoc} - */ public function getWrapperData() { return $this->getMetaData('wrapper_data') ?: array(); } - /** - * {@inheritdoc} - */ public function getStreamType() { return $this->cache[self::STREAM_TYPE]; } - /** - * {@inheritdoc} - */ public function getUri() { return $this->cache['uri']; } - /** - * {@inheritdoc} - */ public function getSize() { if ($this->size !== null) { return $this->size; } - // If the stream is a file based stream and local, then check the filesize - if ($this->isLocal() && $this->getWrapper() == 'plainfile' && $this->getUri() && file_exists($this->getUri())) { - return filesize($this->getUri()); - } - - // Only get the size based on the content if the the stream is readable and seekable - if (!$this->cache[self::IS_READABLE] || !$this->cache[self::SEEKABLE]) { - return false; - } else { + // If the stream is a file based stream and local, then use fstat + clearstatcache(true, $this->cache['uri']); + $stats = fstat($this->stream); + if (isset($stats['size'])) { + $this->size = $stats['size']; + return $this->size; + } elseif ($this->cache[self::IS_READABLE] && $this->cache[self::SEEKABLE]) { + // Only get the size based on the content if the the stream is readable and seekable $pos = $this->ftell(); $this->size = strlen((string) $this); $this->seek($pos); return $this->size; } + + return false; } - /** - * {@inheritdoc} - */ public function isReadable() { return $this->cache[self::IS_READABLE]; } - /** - * {@inheritdoc} - */ + public function isRepeatable() + { + return $this->cache[self::IS_READABLE] && $this->cache[self::SEEKABLE]; + } + public function isWritable() { return $this->cache[self::IS_WRITABLE]; } - /** - * {@inheritdoc} - */ public function isConsumed() { return feof($this->stream); } - /** - * {@inheritdoc} - */ + public function feof() + { + return $this->isConsumed(); + } + public function isLocal() { return $this->cache[self::IS_LOCAL]; } - /** - * {@inheritdoc} - */ public function isSeekable() { return $this->cache[self::SEEKABLE]; } - /** - * {@inheritdoc} - */ public function setSize($size) { $this->size = $size; @@ -254,61 +227,65 @@ public function setSize($size) return $this; } - /** - * {@inheritdoc} - */ public function seek($offset, $whence = SEEK_SET) { return $this->cache[self::SEEKABLE] ? fseek($this->stream, $offset, $whence) === 0 : false; } - /** - * {@inheritdoc} - */ public function read($length) { return $this->cache[self::IS_READABLE] ? fread($this->stream, $length) : false; } - /** - * {@inheritdoc} - */ public function write($string) { if (!$this->cache[self::IS_WRITABLE]) { return 0; } - $bytes = fwrite($this->stream, $string); - $this->size += $bytes; + // We can't know the size after writing anything + $this->size = null; - return $bytes; + return fwrite($this->stream, $string); } - /** - * {@inheritdoc} - */ public function ftell() { return ftell($this->stream); } - /** - * {@inheritdoc} - */ public function rewind() { return $this->seek(0); } + public function readLine($maxLength = null) + { + if (!$this->cache[self::IS_READABLE]) { + return false; + } else { + return $maxLength ? fgets($this->getStream(), $maxLength) : fgets($this->getStream()); + } + } + + public function setCustomData($key, $value) + { + $this->customData[$key] = $value; + + return $this; + } + + public function getCustomData($key) + { + return isset($this->customData[$key]) ? $this->customData[$key] : null; + } + /** * Reprocess stream metadata */ protected function rebuildCache() { $this->cache = stream_get_meta_data($this->stream); - $this->cache[self::STREAM_TYPE] = strtolower($this->cache[self::STREAM_TYPE]); - $this->cache[self::WRAPPER_TYPE] = strtolower($this->cache[self::WRAPPER_TYPE]); $this->cache[self::IS_LOCAL] = stream_is_local($this->stream); $this->cache[self::IS_READABLE] = isset(self::$readWriteHash['read'][$this->cache['mode']]); $this->cache[self::IS_WRITABLE] = isset(self::$readWriteHash['write'][$this->cache['mode']]); diff --git a/core/vendor/guzzle/stream/Guzzle/Stream/StreamInterface.php b/core/vendor/guzzle/stream/Guzzle/Stream/StreamInterface.php index 6972189..6d7dc37 100644 --- a/core/vendor/guzzle/stream/Guzzle/Stream/StreamInterface.php +++ b/core/vendor/guzzle/stream/Guzzle/Stream/StreamInterface.php @@ -15,6 +15,11 @@ public function __toString(); /** + * Close the underlying stream + */ + public function close(); + + /** * Get stream metadata * * @param string $key Specific metadata to retrieve @@ -41,6 +46,13 @@ public function getStream(); public function setStream($stream, $size = null); /** + * Detach the current stream resource + * + * @return self + */ + public function detachStream(); + + /** * Get the stream wrapper type * * @return string @@ -50,7 +62,7 @@ public function getWrapper(); /** * Wrapper specific data attached to this stream. * - * @return string + * @return array */ public function getWrapperData(); @@ -83,6 +95,13 @@ public function getSize(); public function isReadable(); /** + * Check if the stream is repeatable + * + * @return bool + */ + public function isRepeatable(); + + /** * Check if the stream is writable * * @return bool @@ -97,6 +116,13 @@ public function isWritable(); public function isConsumed(); /** + * Alias of isConsumed + * + * @return bool + */ + public function feof(); + + /** * Check if the stream is a local stream vs a remote stream * * @return bool @@ -115,7 +141,7 @@ public function isSeekable(); * * @param int $size Size of the stream contents in bytes * - * @return Stream + * @return self */ public function setSize($size); @@ -161,4 +187,32 @@ public function ftell(); * @return bool Returns true on success or false on failure */ public function rewind(); + + /** + * Read a line from the stream up to the maximum allowed buffer length + * + * @param int $maxLength Maximum buffer length + * + * @return string|bool + */ + public function readLine($maxLength = null); + + /** + * Set custom data on the stream + * + * @param string $key Key to set + * @param mixed $value Value to set + * + * @return self + */ + public function setCustomData($key, $value); + + /** + * Get custom data from the stream + * + * @param string $key Key to retrieve + * + * @return null|mixed + */ + public function getCustomData($key); } diff --git a/core/vendor/guzzle/stream/Guzzle/Stream/StreamRequestFactoryInterface.php b/core/vendor/guzzle/stream/Guzzle/Stream/StreamRequestFactoryInterface.php new file mode 100644 index 0000000..d00e622 --- /dev/null +++ b/core/vendor/guzzle/stream/Guzzle/Stream/StreamRequestFactoryInterface.php @@ -0,0 +1,24 @@ +=5.3.2", "guzzle/common": "self.version" }, + "suggest": { + "guzzle/http": "To convert Guzzle request objects to PHP streams" + }, "autoload": { "psr-0": { "Guzzle\\Stream": "" } }, "target-dir": "Guzzle/Stream", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-master": "3.7-dev" } } }