.gitignore000064400000000316151742730640006545 0ustar00# Ingore common cruft .DS_STORE coverage # Ignore binary files guzzle.phar guzzle-min.phar # Ignore potentially sensitive phpunit file phpunit.xml # Ignore composer generated files composer.lock vendor/ .travis.yml000064400000000425151742730640006667 0ustar00language: php php: - 5.3 - 5.4 before_script: - wget --quiet http://getcomposer.org/composer.phar - php composer.phar install --install-suggests - cp phpunit.xml.dist phpunit.xml - ~/.nvm/nvm.sh run default tests/Guzzle/Tests/Http/server.js & script: sudo phpunit LICENSE000064400000002126151742730640005563 0ustar00Copyright (c) 2011 Michael Dowling, https://github.com/mtdowling Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.README.md000064400000011645151742730640006043 0ustar00Guzzle, PHP HTTP client and webservice framework ================================================ Guzzle is a game changer in the world of PHP HTTP clients. Guzzle allows you to truly reap the benefits of the HTTP/1.1 spec. No other library makes it easier to manage persistent connections or send requests in parallel.

In addition to taking the pain out of HTTP, Guzzle provides a lightweight framework for creating web service clients. Most web service clients follow a specific pattern: create a client class, create methods for each action, create and execute a cURL handle, parse the response, implement error handling, and return the result. Guzzle takes the redundancy out of this process and gives you the tools you need to quickly build a web service client. Start truly consuming HTTP with Guzzle. - [Download the phar](http://guzzlephp.org/guzzle.phar) and include it in your project ([minimal phar](http://guzzlephp.org/guzzle-min.phar)) - Docs: [www.guzzlephp.org](http://www.guzzlephp.org/) - Forum: https://groups.google.com/forum/?hl=en#!forum/guzzle - IRC: [#guzzlephp](irc://irc.freenode.net/#guzzlephp) channel on irc.freenode.net [![Build Status](https://secure.travis-ci.org/guzzle/guzzle.png)](http://travis-ci.org/guzzle/guzzle) Features -------- - Supports GET, HEAD, POST, DELETE, PUT, and OPTIONS - Allows full access to request and response headers - Persistent connections are implicitly managed by Guzzle, resulting in huge performance benefits - Send requests in parallel - Cookie sessions can be maintained between requests using the CookiePlugin - Allows custom entity bodies to be sent in PUT and POST requests, including sending data from a PHP stream - Responses can be cached and served from cache using the caching reverse proxy plugin - Failed requests can be retried using truncated exponential backoff - Entity bodies can be validated automatically using Content-MD5 headers - All data sent over the wire can be logged using the LogPlugin - Automatically requests compressed data and automatically decompresses data - Subject/Observer signal slot system for unobtrusively modifying request behavior - Supports all of the features of libcurl including authentication, redirects, SSL, proxies, etc - Web service client framework for building future-proof interfaces to web services HTTP basics ----------- ```php '***' )); // Issue a path using a relative URL to the client's base URL // Sends to http://www.example.com/api/v1/key/***/users $request = $client->get('users'); $response = $request->send(); // Relative URL that overwrites the path of the base URL $request = $client->get('/test/123.php?a=b'); // Issue a head request on the base URL $response = $client->head()->send(); // Delete user 123 $response = $client->delete('users/123')->send(); // Send a PUT request with custom headers $response = $client->put('upload/text', array( 'X-Header' => 'My Header' ), 'body of the request')->send(); // Send a PUT request using the contents of a PHP stream as the body // Send using an absolute URL (overrides the base URL) $response = $client->put('http://www.example.com/upload', array( 'X-Header' => 'My Header' ), fopen('http://www.test.com/', 'r')); // Create a POST request with a file upload (notice the @ symbol): $request = $client->post('http://localhost:8983/solr/update', null, array ( 'custom_field' => 'my value', 'file' => '@/path/to/documents.xml' )); // Create a POST request and add the POST files manually $request = $client->post('http://localhost:8983/solr/update') ->addPostFiles(array( 'file' => '/path/to/documents.xml' )); // Responses are objects echo $response->getStatusCode() . ' ' . $response->getReasonPhrase() . "\n"; // Requests and responses can be cast to a string to show the raw HTTP message echo $request . "\n\n" . $response; // Create a request based on an HTTP message $request = RequestFactory::fromMessage( "PUT / HTTP/1.1\r\n" . "Host: test.com:8081\r\n" . "Content-Type: text/plain" "Transfer-Encoding: chunked\r\n" . "\r\n" . "this is the body" ); ``` Send requests in parallel ------------------------- ```php send(array( $client->get('users'), $client->head('messages/123'), $client->delete('orders/123') )); } catch (Guzzle\Common\ExceptionCollection $e) { echo "The following requests encountered an exception: \n"; foreach ($e as $exception) { echo $exception->getRequest() . "\n" . $exception->getMessage() . "\n"; } } ``` Testing Guzzle -------------- Here's how to install Guzzle from source to run the unit tests: ``` git clone git@github.com:guzzle/guzzle.git cd guzzle composer.phar install --install-suggests cp phpunit.xml.dist phpunit.xml phpunit ``` autoload.php000064400000002033151742730640007074 0ustar00 'phar://' . __FILE__ . '/src', 'Symfony\\Component\\Validator' => 'phar://' . __FILE__ . '/vendor/symfony/validator', 'Symfony\\Component\\EventDispatcher' => 'phar://' . __FILE__ . '/vendor/symfony/event-dispatcher', 'Doctrine' => 'phar://' . __FILE__ . '/vendor/doctrine/common/lib', 'Monolog' => 'phar://' . __FILE__ . '/vendor/monolog/monolog/src' ); if (DIRECTORY_SEPARATOR == '/') { require_once 'phar://' . __FILE__ . '/vendor/symfony/class-loader/Symfony/Component/ClassLoader/UniversalClassLoader.php'; } else { require_once 'phar://' . __FILE__ . '\\vendor\\symfony\\class-loader\\Symfony\\Component\\ClassLoader\\UniversalClassLoader.php'; $namespaces = array_filter($namespaces, function($namespace) { return str_replace('phar:\\\\', 'phar://', str_replace('/', '\\', $namespace)); }); } $classLoader = new Symfony\Component\ClassLoader\UniversalClassLoader(); $classLoader->registerNamespaces($namespaces); $classLoader->register(); __HALT_COMPILER();build.xml000064400000003340151742730640006376 0ustar00 composer.json000064400000004342151742730640007302 0ustar00{ "name": "guzzle/guzzle", "type": "library", "description": "Guzzle is a PHP HTTP client library and framework for building RESTful web service clients", "keywords": ["framework", "http", "rest", "web service"], "homepage": "http://www.guzzlephp.org/", "license": "MIT", "authors": [{ "name": "Michael Dowling", "email": "mtdowling@gmail.com", "homepage": "https://github.com/mtdowling" }, { "name": "Guzzle Community", "homepage": "https://github.com/guzzle/guzzle/contributors" }], "repositories": { "zend-log": { "package": { "name": "zend/zend-log", "version": "2.0.0", "autoload": { "psr-0": { "Zend\\Log": "" } }, "target-dir": "Zend/Log", "dist": { "url": "https://github.com/KnpLabs/zend-log/zipball/master", "type": "zip" }, "source": { "url": "https://github.com/KnpLabs/zend-log.git", "type": "git", "reference": "master" } } }, "zend-cache": { "package": { "name": "zend/zend-cache", "version": "2.0.0", "autoload": { "psr-0": { "Zend\\Cache": "" } }, "target-dir": "Zend/Cache", "dist": { "url": "https://github.com/KnpLabs/zend-cache/zipball/master", "type": "zip" }, "source": { "url": "https://github.com/KnpLabs/zend-cache.git", "type": "git", "reference": "master" } } } }, "require": { "php": ">=5.3.2", "ext-curl": "*", "symfony/event-dispatcher": "*", "symfony/validator": "*" }, "suggest": { "symfony/class-loader": "*", "doctrine/common": "*", "monolog/monolog": "*", "zend/zend-cache": "*", "zend/zend-log": "*" }, "autoload": { "psr-0": { "Guzzle\\Tests": "tests/", "Guzzle": "src/" } } }phpunit.xml.dist000064400000001553151742730640007734 0ustar00 ./tests/Guzzle/Tests ./src/Guzzle ./src/Guzzle ./src/Guzzle/Http/HttpException.php src/Guzzle/Common/AbstractHasDispatcher.php000064400000002126151742730640014774 0ustar00eventDispatcher = $eventDispatcher; return $this; } /** * {@inheritdoc} */ public function getEventDispatcher() { if (!$this->eventDispatcher) { $this->eventDispatcher = new EventDispatcher(); } return $this->eventDispatcher; } /** * {@inheritdoc} */ public function dispatch($eventName, array $context = array()) { $this->getEventDispatcher()->dispatch($eventName, new Event($context)); } }src/Guzzle/Common/Cache/AbstractCacheAdapter.php000064400000000433151742730640015560 0ustar00cache; } }src/Guzzle/Common/Cache/CacheAdapterInterface.php000064400000003103151742730640015712 0ustar00 infinite lifeTime). * * @return bool TRUE if the entry was successfully stored in the cache, * FALSE otherwise. */ function save($id, $data, $lifeTime = false); }src/Guzzle/Common/Cache/DoctrineCacheAdapter.php000064400000001557151742730640015574 0ustar00cache = $cache; } /** * {@inheritdoc} */ public function contains($id) { return $this->cache->contains($id); } /** * {@inheritdoc} */ public function delete($id) { return $this->cache->delete($id); } /** * {@inheritdoc} */ public function fetch($id) { return $this->cache->fetch($id); } /** * {@inheritdoc} */ public function save($id, $data, $lifeTime = false) { return $this->cache->save($id, $data, $lifeTime); } }src/Guzzle/Common/Cache/ZendCacheAdapter.php000064400000002042151742730640014713 0ustar00cache = $cache; } /** * {@inheritdoc} */ public function contains($id) { return $this->cache->test($id); } /** * {@inheritdoc} */ public function delete($id) { return $this->cache->remove($id); } /** * {@inheritdoc} */ public function fetch($id) { return $this->cache->load($id); } /** * {@inheritdoc} */ public function save($id, $data, $lifeTime = false) { return $this->cache->save($data, $id, array(), $lifeTime); } }src/Guzzle/Common/Collection.php000064400000026443151742730640012671 0ustar00data = $data ?: array(); } /** * Convert the object to a string * * @return string */ public function __toString() { return __CLASS__ . '@' . spl_object_hash($this); } /** * 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) { if (!array_key_exists($key, $this->data)) { $this->data[$key] = $value; } else { if (!is_array($this->data[$key])) { $this->data[$key] = array( $this->data[$key], $value ); } else { $this->data[$key][] = $value; } } return $this; } /** * Removes all key value pairs * * @return Collection */ public function clear() { $this->data = array(); return $this; } /** * Return the number of keys * * @return integer */ public function count() { return count($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. * * @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 object * * @return Collection */ public function filter(\Closure $closure, $static = true) { $collection = ($static) ? new static() : new self(); foreach ($this->data as $key => $value) { if ($closure($key, $value)) { $collection->add($key, $value); } } return $collection; } /** * Get an iterator object * * @return array */ public function getIterator() { return new \ArrayIterator($this->data); } /** * Get a specific key value. * * @param string $key Key to retrieve. $key can be a string or a * regular expression. * @param mixed $default (optional) If the key is not found, set this * value to specify a default * @param int $match (optional) Bitwise match setting: * 0 - Exact match * 1 - Case insensitive match * 2 - Regular expression match * * @return mixed|null Value of the key or NULL */ public function get($key, $default = null, $match = self::MATCH_EXACT) { if ($match == self::MATCH_EXACT) { if (array_key_exists($key, $this->data)) { return $this->data[$key]; } } else if ($match == self::MATCH_IGNORE_CASE) { foreach ($this->data as $k => $value) { if (strcasecmp($k, $key) === 0) { return $value; } } } else if ($match == self::MATCH_REGEX) { foreach ($this->data as $k => $value) { if (preg_match($key, $k)) { return $value; } } } return $default; } /** * Get all or a subset of matching key value pairs * * @param array|string|int $keys (optional) Pass an array of keys to * retrieve only a particular subset of kvp. * @param int $match (optional) Bitwise key match setting: * 0 - Exact match * 1 - Case insensitive match * 2 - Regular expression match * * @return array Returns an array of all key value pairs if no $keys array * is specified, or an array of only the key value pairs matching the * values in the $keys array. */ public function getAll($keys = null, $match = false) { if (!$keys) { return $this->data; } $matches = array(); $allKeys = $this->getKeys(); foreach ((array) $keys as $expression) { if ($match == self::MATCH_EXACT) { if (in_array($expression, $allKeys)) { $matches[$expression] = $this->data[$expression]; } } else if ($match == self::MATCH_IGNORE_CASE) { foreach ($allKeys as $key) { if (strcasecmp($expression, $key) === 0) { $matches[$key] = $this->data[$key]; } } } else if ($match == self::MATCH_REGEX) { foreach ($allKeys as $key) { if (preg_match($expression, $key)) { $matches[$key] = $this->data[$key]; } } } } return $matches; } /** * Get all or a subset of matching keys * * @param string $regexp (optional) Pass a regular expression to return * only keys matching the expression. * * @return array Returns an array of matching keys */ public function getKeys($regexp = null) { $keys = array_keys($this->data); // If a regular expression was set, filter the keys if ($regexp) { $keys = array_filter($keys, function($key) use ($regexp) { return preg_match($regexp, $key); }); } return $keys; } /** * Returns whether or not the specified key is present. * * @param string $key The key for which to check the existence. * @param int $match (optional) Bitwise key match setting: * 0 - Exact match * 1 - Case insensitive match * 2 - Regular expression match * * @return int|string Returns the key value if the key is present or FALSE * if the key is not. Use === matching to check if false. */ public function hasKey($key, $match = self::MATCH_EXACT) { if ($match == self::MATCH_EXACT) { if (array_key_exists($key, $this->data)) { return $key; } } else if ($match == self::MATCH_IGNORE_CASE) { foreach (array_keys($this->data) as $k) { if (strcasecmp($k, $key) === 0) { return $k; } } } else if ($match == self::MATCH_REGEX) { foreach (array_keys($this->data) as $k) { if (preg_match($key, $k)) { return $k; } } } return false; } /** * Checks if any keys contains a certain value * * @param string $value Value to search for * * @return mixed Returns the key if the value was found FALSE if * the value was not found. */ public function hasValue($value) { return array_search($value, $this->data); } /** * 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 Closure $closure Closure to apply * @param array $context (optional) 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 object * * @return Collection */ public function map(\Closure $closure, array $context = array(), $static = true) { $collection = $static ? new static() : new self(); foreach ($this as $key => $value) { $collection->add($key, $closure($key, $value, $context)); } return $collection; } /** * Add and merge in a Collection or array of key value pair data. * * Invalid $data arguments will silently fail. * * @param Collection|array $data Associative array of key value pair data * * @return Collection Returns a reference to the object. */ public function merge($data) { if ($data instanceof self) { $data = $data->getAll(); } else if (!is_array($data)) { return $this; } if (count($data)) { if (!count($this->data)) { $this->data = $data; } else { foreach ($data as $key => $value) { $this->add($key, $value); } } } return $this; } /** * ArrayAccess implementation of offsetExists() * * @see hasKey() */ public function offsetExists($offset) { return $this->hasKey($offset) !== false; } /** * ArrayAccess implementation of offsetGet() * * @see get() */ public function offsetGet($offset) { return $this->get($offset); } /** * ArrayAccess implementation of offsetGet() * * @see set() */ public function offsetSet($offset, $value) { return $this->set($offset, $value); } /** * ArrayAccess implementation of offsetUnset() * * @see remove() */ public function offsetUnset($offset) { return $this->remove($offset); } /** * Remove a specific key value pair * * @param array|string $key A key, regexp, or array of keys to remove * @param int $match (optional) Bitwise key match setting: * 0 - Exact match * 1 - Case insensitive match * 2 - Regular expression match * * @return Collection Returns a reference to the object */ public function remove($key, $match = self::MATCH_EXACT) { foreach ((array) $key as $k) { if (false !== $matched = $this->hasKey($k, $match)) { unset($this->data[$matched]); } } return $this; } /** * 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) { $this->data = $data; return $this; } /** * 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) { $this->data[$key] = $value; return $this; } }src/Guzzle/Common/Event.php000064400000002300151742730640011641 0ustar00context = $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; } /** * {@inheritdoc} */ public function offsetSet($offset, $value) { $this->context[$offset] = $value; } /** * {@inheritdoc} */ public function offsetExists($offset) { return array_key_exists($offset, $this->context); } /** * {@inheritdoc} */ public function offsetUnset($offset) { unset($this->context[$offset]); } }src/Guzzle/Common/ExceptionCollection.php000064400000002364151742730640014544 0ustar00exceptions[] = $exception; } } else if ($e instanceof \Exception) { $this->exceptions[] = $e; } $this->message = implode("\n", array_map(function($e) { return $e->getMessage(); }, $this->exceptions)); return $this; } /** * Get the total number of request exceptions * * @return int */ public function count() { return count($this->exceptions); } /** * Allows array-like iteration over the request exceptions * * @return ArrayIterator */ public function getIterator() { return new \ArrayIterator($this->exceptions); } }src/Guzzle/Common/GuzzleExceptionInterface.php000064400000000143151742730640015543 0ustar00log; } }src/Guzzle/Common/Log/ClosureLogAdapter.php000064400000001261151742730640014665 0ustar00log = $logObject; } /** * {@inheritdoc} */ public function log($message, $priority = LOG_INFO, $extras = null) { call_user_func($this->log, $message, $priority, $extras); } }src/Guzzle/Common/Log/LogAdapterInterface.php000064400000002000151742730640015141 0ustar00log = $logObject; } /** * {@inheritdoc} */ public function log($message, $priority = LOG_INFO, $extras = null) { $this->log->addRecord($priority, $message); } }src/Guzzle/Common/Log/ZendLogAdapter.php000064400000001177151742730640014157 0ustar00log = $logObject; } /** * {@inheritdoc} */ public function log($message, $priority = LOG_INFO, $extras = null) { $this->log->log($message, $priority, $extras); } }src/Guzzle/Common/NullObject.php000064400000001371151742730640012630 0ustar00size = $size; $this->stream = $stream; $this->rebuildCache(); } /** * Closes the stream when the helper is destructed */ public function __destruct() { if (is_resource($this->stream)) { fclose($this->stream); } } /** * Reprocess stream metadata */ protected function rebuildCache() { $meta = stream_get_meta_data($this->stream); $this->cache['wrapper_type'] = isset($meta['wrapper_type']) ? strtolower($meta['wrapper_type']) : ''; $this->cache['mode'] = isset($meta['mode']) ? $meta['mode'] : ''; $this->cache['seekable'] = isset($meta['seekable']) ? $meta['seekable'] : false; $this->cache['uri'] = isset($meta['uri']) ? $meta['uri'] : ''; $this->cache['type'] = isset($meta['stream_type']) ? strtolower($meta['stream_type']) : ''; $this->cache['is_local'] = stream_is_local($this->stream); $this->cache['is_readable'] = in_array(str_replace('b', '', $this->cache['mode']), array('r', 'w+', 'r+', 'x+', 'c+')); $this->cache['is_writable'] = str_replace('b', '', $this->cache['mode']) != 'r'; } /** * Convert the stream to a string if the stream is readable and the stream * is seekable. This logic is enforced to ensure that outputting the stream * as a string does not affect an actual cURL request using non-repeatable * streams. * * @return string */ public function __toString() { if (!$this->isReadable() || (!$this->isSeekable() && $this->isConsumed())) { return ''; } $body = stream_get_contents($this->stream, -1, 0); $this->seek(0); return $body; } /** * Get stream metadata * * @param string $key (optional) Specific metdata to retrieve * * @return array|mixed|null */ public function getMetaData($key = null) { $meta = stream_get_meta_data($this->stream); return !$key ? $meta : (array_key_exists($key, $meta) ? $meta[$key] : null); } /** * Get the stream resource * * @return resource */ public function getStream() { return $this->stream; } /** * Get the stream wrapper type * * @return string */ public function getWrapper() { return $this->cache['wrapper_type']; } /** * Wrapper specific data attached to this stream. * * @return string */ public function getWrapperData() { return $this->getMetaData('wrapper_data') ?: array(); } /** * Get a label describing the underlying implementation of the stream * * @return string */ public function getStreamType() { return $this->cache['type']; } /** * Get the URI/filename associated with this stream * * @return string */ public function getUri() { return $this->cache['uri']; } /** * Get the size of the stream if able * * @return int|false */ 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 so as to not interfere with actually reading the data if (!$this->isReadable() || !$this->isSeekable()) { return false; } else { $size = strlen((string) $this); $this->seek(0); return $size; } } /** * Check if the stream is readable * * @return bool */ public function isReadable() { return $this->cache['is_readable']; } /** * Check if the stream is writable * * @return bool */ public function isWritable() { return $this->cache['is_writable']; } /** * Check if the stream has been consumed * * @return bool */ public function isConsumed() { return feof($this->stream); } /** * Check if the stream is a local stream vs a remote stream * * @return bool */ public function isLocal() { return $this->cache['is_local']; } /** * Check if the string is repeatable * * @return bool */ public function isSeekable() { return $this->cache['seekable']; } /** * Specify the size of the stream in bytes * * @param int $size Size of the stream contents in bytes * * @return Stream */ public function setSize($size) { $this->size = $size; return $this; } /** * Seek to a position in the stream * * @param int $offset Stream offset * @param int $whence (optional) Where the offset is applied * * @return bool Returns TRUE on success or FALSE on failure * @see http://www.php.net/manual/en/function.fseek.php */ public function seek($offset, $whence = SEEK_SET) { return $this->isSeekable() ? fseek($this->stream, $offset, $whence) === 0 : false; } /** * Read data from the stream * * @param int $length Up to length number of bytes read. * * @return string|bool Returns the data read from the stream or FALSE on * failure or EOF */ public function read($length) { return $this->isReadable() ? fread($this->stream, $length) : false; } /** * Write data to the stream * * @param string $string The string that is to be written. * * @return int|bool Returns the number of bytes written to the stream on * success or FALSE on failure. */ public function write($string) { return $this->isWritable() ? fwrite($this->stream, $string) : false; } }src/Guzzle/Common/XmlElement.php000064400000004231151742730640012637 0ustar00asXML(); } /** * Extended addChild method - supports appending another Element * * @param string|Element $name * * @param string|SimpleXMLElement $value XML data to add * @param string $namespace Namespace of the element * * @return Element */ public function addChild($name, $value = null, $namespace = null) { // If this is not a SimpleXMLElement, then add normally if (!($name instanceof \SimpleXMLElement)) { return parent::addChild($name, $value, $namespace); } $nodeName = $name->getName(); // If the parent node has no children, then cast to a string and add if (!count($name->children())) { return parent::addChild($nodeName, (string) $name, $namespace); } $e = $this->addChild($nodeName); // Add parent attributes to the newly added child node foreach ($name->attributes() as $key => $value) { $e->addAttribute((string) $key, (string) $value); } // Add the children of the parent node foreach ($name->children() as $child) { $childEle = $e->addChild($child); $attributes = $childEle->attributes($namespace); foreach ($child->attributes() as $key => $val) { if (!isset($attributes->{$key})) { $childEle->addAttribute((string) $key, (string) $val); } } } return $e; } /** * Output formatted XML string * * @return string */ public function asFormattedXml() { $doc = new \DOMDocument(); $doc->preserveWhiteSpace = false; $doc->formatOutput = true; $doc->loadXML($this->asXML()); return $doc->saveXML(); } }src/Guzzle/Guzzle.php000064400000006253151742730640010623 0ustar00get(trim($matches[1])); }, $input ); } /** * Reset the cached internal state */ public static function reset() { self::$cache = array(); } }src/Guzzle/Http/Client.php000064400000027124151742730640011500 0ustar00setConfig($config ?: new Collection()); $this->setBaseUrl($baseUrl); } /** * Cast to a string */ public function __toString() { return spl_object_hash($this); } /** * 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 Client */ public final function setConfig($config) { // Set the configuration object if ($config instanceof Collection) { $this->config = $config; } else if (is_array($config)) { $this->config = new Collection($config); } else { throw new \InvalidArgumentException( 'Config must be an array or Collection' ); } return $this; } /** * Get a configuration setting or all of the configuration settings * * @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 */ public final function getConfig($key = false) { return $key ? $this->config->get($key) : $this->config; } /** * Inject configuration values into a formatted string with {{param}} as a * parameter delimiter (replace param with the configuration value name) * * @param string $string String to inject config values into * * @return string */ public final function inject($string) { return Guzzle::inject($string, $this->getConfig()); } /** * Create and return a new {@see RequestInterface} configured for the client * * @param string $method (optional) HTTP method. Defaults to GET * @param string $uri (optional) Resource URI. 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 * querystring as well. * @param array|Collection $headers (optional) HTTP headers * @param string|resource|array|EntityBody $body (optional) Entity body of * request (POST/PUT) or response (GET) * * @return RequestInterface */ public function createRequest($method = RequestInterface::GET, $uri = null, $headers = null, $body = null) { if (!$uri) { $url = $this->getBaseUrl(); } else if (strpos($uri, 'http') === 0) { // Use absolute URLs as-is $url = $this->inject($uri); } else { $url = Url::factory($this->getBaseUrl())->combine($this->inject($uri)); } return $this->prepareRequest( RequestFactory::create($method, (string) $url, $headers, $body) ); } /** * 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 * * @return RequestInterface */ public function prepareRequest(RequestInterface $request) { $request->setClient($this); if ($this->userAgent) { $request->setHeader('User-Agent', $this->userAgent); } foreach ($this->getConfig()->getAll() as $key => $value) { // Add any curl options that might in the config to the request if (strpos($key, 'curl.') === 0) { $curlOption = str_replace('curl.', '', $key); if (defined($curlOption)) { $curlValue = defined($value) ? constant($value) : $value; $request->getCurlOptions()->set(constant($curlOption), $curlValue); } } // Add any cache options from the config to the request // Add any curl options that might in the config to the request if (strpos($key, 'cache.') === 0) { $request->getParams()->set($key, $value); } } // Attach client observers to the request $request->setEventDispatcher(clone $this->getEventDispatcher()); $this->dispatch('client.create_request', array( 'client' => $this, 'request' => $request )); return $request; } /** * Get the base service endpoint URL with configuration options injected * into the configuration setting. * * @param bool $inject (optional) Set to FALSE to get the raw base URL * * @return string|null */ public function getBaseUrl($inject = true) { return $inject ? $this->inject($this->baseUrl) : $this->baseUrl; } /** * Set the base service endpoint URL * * @param string $url The base service endpoint URL of the webservice * * @return Client */ public function setBaseUrl($url) { $this->baseUrl = $url; return $this; } /** * Set the name of your application and application version that will be * appended to the User-Agent header of all reqeusts. * * @param string $userAgent User agent string * @param bool $includeDefault (optional) Set to TRUE to append the default * Guzzle user agent * * @return Client */ public function setUserAgent($userAgent, $includeDefault = false) { $this->userAgent = $userAgent; if ($includeDefault) { $this->userAgent .= ' ' . Guzzle::getDefaultUserAgent(); } return $this; } /** * Create a GET request for the client * * @param string $path (optional) Resource URI of the request. Use an * absolute path to override the base path, or a relative path to append * @param array|Collection $headers (optional) HTTP headers * @param string|resource|array|EntityBody $body (optional) Where to store * the response entity body * * @return Request */ public final function get($path = null, $headers = null, $body = null) { return $this->createRequest('GET', $path, $headers, $body); } /** * Create a HEAD request for the client * * @param string $uri (optional) Resource URI of the request. Use an * absolute path to override the base path, or a relative path to append * @param array|Collection $headers (optional) HTTP headers * * @return Request */ public final function head($uri = null, $headers = null) { return $this->createRequest('HEAD', $uri, $headers); } /** * Create a DELETE request for the client * * @param string $uri (optional) Resource URI of the request. Use an * absolute path to override the base path, or a relative path to append * @param array|Collection $headers (optional) HTTP headers * * @return Request */ public final function delete($uri = null, $headers = null) { return $this->createRequest('DELETE', $uri, $headers); } /** * Create a PUT request for the client * * @param string $uri (optional) Resource URI of the request. Use an * absolute path to override the base path, or a relative path to append * @param array|Collection $headers (optional) HTTP headers * @param string|resource|array|EntityBody $body Body to send in the request * * @return EntityEnclosingRequest */ public final function put($uri = null, $headers = null, $body = null) { return $this->createRequest('PUT', $uri, $headers, $body); } /** * Create a POST request for the client * * @param string $uri (optional) Resource URI of the request. Use an absolute path to * override the base path, or a relative path to append it. * @param array|Collection $headers (optional) HTTP headers * @param array|Collection|string|EntityBody $postBody (optional) 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 reference a file. * * @return EntityEnclosingRequest */ public final function post($uri = null, $headers = null, $postBody = null) { return $this->createRequest('POST', $uri, $headers, $postBody); } /** * Create an OPTIONS request for the client * * @param string $uri (optional) Resource URI of the request. Use an * absolute path to override the base path, or relative path to append * * @return Request */ public final function options($uri = null) { return $this->createRequest('OPTIONS', $uri); } /** * Sends a single request or an array of requests in parallel * * @param array $requests Request(s) to send * * @return array Returns the response(s) */ public function send($requests) { $curlMulti = $this->getCurlMulti(); $multipleRequests = is_array($requests); $requests = $multipleRequests ? $requests : array($requests); foreach ($requests as $request) { $curlMulti->add($request); } try { $curlMulti->send(); } catch (ExceptionCollection $e) { throw $multipleRequests ? $e : $e->getIterator()->offsetGet(0); } return !$multipleRequests ? end($requests)->getResponse() : array_map(function($request) { return $request->getResponse(); }, $requests); } /** * Set a curl multi object to be used internally by the client for * transferring requests. * * @param CurlMultiInterface $curlMulti Mulit object * * @return Client */ public function setCurlMulti(CurlMultiInterface $curlMulti) { $this->curlMulti = $curlMulti; return $this; } /** * Get the curl multi object used with the client * * @return CurlMultiInterface */ public function getCurlMulti() { if (!$this->curlMulti) { $this->curlMulti = CurlMulti::getInstance(); } return $this->curlMulti; } }src/Guzzle/Http/ClientInterface.php000064400000015255151742730640013323 0ustar00add($key, urldecode($value)); } } return new self($data->getAll()); } /** * {@inheritdoc} */ public function __construct(array $data = null) { parent::__construct($data); $this->setFieldSeparator(';') ->setPrefix('') ->setValueSeparator('=') ->setEncodeFields(false) ->setEncodeValues(false) ->setAggregateFunction(function($key, $value, $encodeFields = false, $encodeValues = false) { $value = array_unique($value); return array( (($encodeFields) ? rawurlencode($key) : $key) => (($encodeValues) ? array_map('rawurlencode', $value) : $value) ); }); } }src/Guzzle/Http/CookieJar/ArrayCookieJar.php000064400000022320151742730640014766 0ustar00getCookies($domain, $path, $name, false, false); return $this->prune(function($cookie) use ($cookies) { return !in_array($cookie, $cookies, true); }); } /** * Discard all temporary cookies. * * Scans for all cookies in the jar with either no expire field or a * true discard flag. To be called when the user agent shuts down according * to RFC 2965. * * @return int Returns the number of deleted cookies */ public function clearTemporary() { return $this->prune(function($cookie) { return (!$cookie['discard'] && $cookie['expires']); }); } /** * Delete any expired cookies * * @return int Returns the number of deleted cookies */ public function deleteExpired() { $ctime = time(); return $this->prune(function($cookie) use ($ctime) { return (!$cookie['expires'] || $ctime < $cookie['expires']); }); } /** * Get all of the matching cookies * * @param string $domain (optional) Domain of the cookie * @param string $path (optional) Path of the cookie * @param string $name (optional) Name of the cookie * @param bool $skipDiscardables (optional) Set to TRUE to skip cookies with * the Discard attribute. * @param bool $skipExpired (optional) Set to FALSE to include expired * * @return array Returns an array of arrays. Each array contains the * following keys: * * domain (string) - Domain of the cookie * path (string) - Path of the cookie * cookie (array) - Array of cookie name, value (e.g. array('name', '123') * max_age (int) - Lifetime of the cookie in seconds * expires (int) - The UNIX timestamp when the cookie expires * version (int) - Version of the cookie specification. RFC 2965 is 1 * secure (bool) - Whether or not this is a secure cookie * discard (bool) - Whether or not this is a discardable cookie * comment (string) - How the cookie is intended to be used * comment_url (str)- URL with info on how it will be used * port (string) - CSV list of ports * http_only (bool) - HTTP only cookie */ public function getCookies($domain = null, $path = null, $name = null, $skipDiscardable = false, $skipExpired = true) { $ctime = time(); $ret = array_values(array_filter($this->cookies, function($cookie) use ($domain, $path, $name, $skipDiscardable, $skipExpired, $ctime) { // Make sure the cookie is not expired if ($skipExpired && $cookie['expires'] && $ctime > $cookie['expires']) { return false; } $domain = strtolower($domain); $cookie['domain'] = strtolower($cookie['domain']); // Normalize the domain value $domainMatch = false; if ($domain && $cookie['domain']) { if ($domain == $cookie['domain']) { $domainMatch = true; } else if ($cookie['domain'][0] == '.') { $domainMatch = preg_match('/' . preg_quote($cookie['domain']) . '$/i', $domain); } } // Check cookie name matches $nameMatch = $name && $cookie['cookie'][0] == $name; if (!$domain || $domainMatch) { if (!$path || !strcasecmp($path, $cookie['path']) || 0 === stripos($path, $cookie['path'])) { if (!$name || $nameMatch) { if (!$skipDiscardable || !$cookie['discard']) { return true; } } } } return false; })); return $ret; } /** * Save a cookie * * @parm array $cookieData Cookie information, including the following: * domain (string, required) - Domain of the cookie * path (string, required) - Path of the cookie * cookie - Array of cookie name (0) and value (1) * max_age (int, required) - Lifetime of the cookie in seconds * version (int) - Version of the cookie specification. Default is 0. RFC 2965 is 1 * secure (bool) - If it is a secure cookie * discard (bool) - If it is a discardable cookie * comment (string) - How the cookie is intended to be used * comment_url (str) - URL with info on how it will be used * port (string) - CSV list of ports * http_only (bool) - HTTP only cookie * * @return ArrayCookieJar */ public function save(array $cookieData) { if (!isset($cookieData['domain'])) { throw new \InvalidArgumentException('Cookies require a domain'); } if (!isset($cookieData['cookie']) || !is_array($cookieData['cookie'])) { throw new \InvalidArgumentException('Cookies require a names and values'); } // Extract the expires value and turn it into a UNIX timestamp if needed $cookieData['expires'] = isset($cookieData['expires']) ? (is_numeric($cookieData['expires']) ? $cookieData['expires'] : strtotime($cookieData['expires'])) : null; $cookieData['path'] = isset($cookieData['path']) ? $cookieData['path'] : '/'; $cookieData['max_age'] = isset($cookieData['max_age']) ? $cookieData['max_age'] : 0; $cookieData['comment'] = isset($cookieData['comment']) ? $cookieData['comment'] : null; $cookieData['comment_url'] = isset($cookieData['comment_url']) ? $cookieData['comment_url'] : null; $cookieData['port'] = isset($cookieData['port']) ? $cookieData['port'] : array(); $cookieData['version'] = isset($cookieData['version']) ? $cookieData['version'] : null; $cookieData['secure'] = array_key_exists('secure', $cookieData) ? $cookieData['secure'] : null; $cookieData['discard'] = array_key_exists('discard', $cookieData) ? $cookieData['discard'] : null; $cookieData['http_only'] = array_key_exists('http_only', $cookieData) ? $cookieData['http_only'] : false; // Calculate the expires date if (!$cookieData['expires'] && $cookieData['max_age']) { $cookieData['expires'] = time() + (int) $cookieData['max_age']; } $alreadyPresent = false; $keys = array('path', 'max_age', 'domain', 'http_only', 'port', 'secure'); foreach ($this->cookies as $i => $cookie) { // Check the regular comparison fields foreach ($keys as $k) { if ($cookie[$k] != $cookieData[$k]) { continue 2; } } // Is it a different cookie value name? if ($cookie['cookie'][0] != $cookieData['cookie'][0]) { continue; } // The previously set cookie is a discard cookie and this one is not // so allow the new cookie to be set if (!$cookieData['discard'] && $cookie['discard']) { unset($this->cookies[$i]); continue; } // If the new cookie's expiration is further into the future, then // replace the old cookie if ($cookieData['expires'] > $cookie['expires']) { unset($this->cookies[$i]); continue; } $alreadyPresent = true; break; } if (!$alreadyPresent) { $this->cookies[] = $cookieData; } return $this; } /** * Prune the cookies using a callback function * * @param Closure $callback Callback function * * @return int Returns the number of removed cookies */ protected function prune(\Closure $callback) { $originalCount = count($this->cookies); $this->cookies = array_filter($this->cookies, $callback); return $originalCount - count($this->cookies); } }src/Guzzle/Http/CookieJar/CookieJarInterface.php000064400000007511151742730640015615 0ustar00file = $cookieFile; $this->load(); } /** * Saves the file when shutting down */ public function __destruct() { $this->persist(); } /** * Save the contents of the data array to the file * * @throws HttpException if the file cannot be found or created */ protected function persist() { $handle = fopen($this->file, 'w+'); // @codeCoverageIgnoreStart if ($handle === false) { throw new HttpException('Unable to open file ' . $this->file); } // @codeCoverageIgnoreEnd fwrite($handle, json_encode($this->getCookies(null, null, null, true, true))); fclose($handle); } /** * Load the contents of the json formatted file into the data array and * discard the unsaved state of the jar object */ protected function load() { $handle = fopen($this->file, 'c+'); // @codeCoverageIgnoreStart if ($handle === false) { throw new HttpException('Unable to open file ' . $this->file); } // @codeCoverageIgnoreEnd $json = ''; while ($data = fread($handle, 8096)) { $json .= $data; } fclose($handle); $this->cookies = $json ? json_decode($json, true) : array(); } }src/Guzzle/Http/Curl/CurlException.php000064400000001520151742730640013743 0ustar00curlError = $error; $this->curlErrorNo = $number; return $this; } /** * Get the associated cURL error message * * @return string */ public function getError() { return $this->curlError; } /** * Get the associated cURL error number * * @return int */ public function getErrorNo() { return $this->curlErrorNo; } }src/Guzzle/Http/Curl/CurlHandle.php000064400000021105151742730640013201 0ustar00 $request->getUrl(), CURLOPT_CUSTOMREQUEST => $request->getMethod(), CURLOPT_CONNECTTIMEOUT => 10, // Connect timeout in seconds CURLOPT_RETURNTRANSFER => false, // Streaming the return, so no need CURLOPT_HEADER => false, // Retrieve the received headers CURLOPT_USERAGENT => $request->getHeader('User-Agent', Guzzle::getDefaultUserAgent()), CURLOPT_ENCODING => '', // Supports all encodings CURLOPT_PORT => $request->getPort(), CURLOPT_HTTP_VERSION => $request->getProtocolVersion(true), CURLOPT_NOPROGRESS => false, CURLOPT_STDERR => fopen('php://temp', 'r+'), CURLOPT_VERBOSE => true, CURLOPT_HTTPHEADER => array(), CURLOPT_WRITEFUNCTION => function($curl, $write) use ($request) { $request->dispatch('curl.callback.write', array( 'request' => $request, 'write' => $write )); return $request->getResponse()->getBody()->write($write); }, CURLOPT_HEADERFUNCTION => function($curl, $header) use ($request) { return $request->receiveResponseHeader($header); }, CURLOPT_READFUNCTION => function($ch, $fd, $length) use ($request) { $read = ($request->getBody()) ? $request->getBody()->read($length) : 0; if ($read) { $request->dispatch('curl.callback.read', array( 'request' => $request, 'read' => $read )); } return $read === false || $read === 0 ? '' : $read; }, CURLOPT_PROGRESSFUNCTION => function($downloadSize, $downloaded, $uploadSize, $uploaded) use ($request) { $request->dispatch('curl.callback.progress', array( 'request' => $request, 'download_size' => $downloadSize, 'downloaded' => $downloaded, 'upload_size' => $uploadSize, 'uploaded' => $uploaded )); } ); // @codeCoverageIgnoreStart if (Guzzle::getCurlInfo('follow_location')) { $curlOptions[CURLOPT_FOLLOWLOCATION] = true; $curlOptions[CURLOPT_MAXREDIRS] = 5; } // @codeCoverageIgnoreEnd // Specify settings according to the HTTP method switch ($request->getMethod()) { case 'GET': $curlOptions[CURLOPT_HTTPGET] = true; unset($curlOptions[CURLOPT_READFUNCTION]); break; case 'HEAD': $curlOptions[CURLOPT_NOBODY] = true; unset($curlOptions[CURLOPT_READFUNCTION]); break; case 'POST': $curlOptions[CURLOPT_POST] = true; if (!$request->getBody()) { unset($curlOptions[CURLOPT_READFUNCTION]); } break; case 'PUT': $curlOptions[CURLOPT_UPLOAD] = true; if ($request->getBody()) { $curlOptions[CURLOPT_INFILESIZE] = $request->getHeader('Content-Length') ?: -1; } break; } // Add any custom headers to the request foreach ($request->getHeaders() as $key => $value) { if ($key && $value !== '') { $curlOptions[CURLOPT_HTTPHEADER][] = $key . ': ' . $value; } } // Set custom cURL options foreach ($request->getCurlOptions() as $key => $value) { $curlOptions[$key] = $value; } // Apply the options to the cURL handle. curl_setopt_array($handle, $curlOptions); $request->getParams()->set('curl.last_options', $curlOptions); return new self($handle, $curlOptions); } /** * Construct a new CurlHandle object that wraps a cURL handle * * @param resource $handle Configured cURL handle resource * @param Collection|array $options Curl options to use with the handle * * @throws InvalidArgumentException */ public function __construct($handle, $options) { if (!is_resource($handle)) { throw new \InvalidArgumentException('Invalid handle provided'); } if (is_array($options)) { $this->options = new Collection($options); } else if ($options instanceof Collection) { $this->options = $options; } else { throw new \InvalidArgumentException('Expected array or Collection'); } $this->handle = $handle; } /** * Destructor */ public function __destruct() { $this->close(); } /** * Close the curl handle */ public function close() { if (is_resource($this->handle)) { curl_close($this->handle); } $this->handle = null; } /** * Check if the handle is available and still OK * * @return bool */ public function isAvailable() { return is_resource($this->handle) && false != curl_getinfo($this->handle, CURLINFO_EFFECTIVE_URL); } /** * Get the last error that occurred on the cURL handle * * @return string */ public function getError() { return $this->isAvailable() ? curl_error($this->handle) : ''; } /** * Get the last error number that occurred on the cURL handle * * @return int */ public function getErrorNo() { if ($this->errorNo) { return $this->errorNo; } return $this->isAvailable() ? curl_errno($this->handle) : 0; } /** * Set the curl error number * * @param int $error Error number to set * * @return CurlHandle */ public function setErrorNo($error) { $this->errorNo = $error; return $this; } /** * Get cURL curl_getinfo data * * @param int $option (optional) Option to retrieve. Pass null to retrieve * retrieve all data as an array or pass a CURLINFO_* constant * * @return array|mixed */ public function getInfo($option = null) { if (!is_resource($this->handle)) { return null; } if (null !== $option) { return curl_getinfo($this->handle, $option) ?: null; } return curl_getinfo($this->handle) ?: array(); } /** * Get the stderr output * * @param bool $asResource (optional) Set to TRUE to get an fopen resource * * @return string|resource|null */ public function getStderr($asResource = false) { $stderr = $this->getOptions()->get(CURLOPT_STDERR); if (!$stderr) { return null; } if ($asResource) { return $stderr; } fseek($stderr, 0); $e = stream_get_contents($stderr); fseek($stderr, 0, SEEK_END); return $e; } /** * Get the URL that this handle is connecting to * * @return Url */ public function getUrl() { return Url::factory($this->options->get(CURLOPT_URL)); } /** * Get the wrapped curl handle * * @return handle|null Returns the cURL handle or null if it was closed */ public function getHandle() { return $this->handle && $this->isAvailable() ? $this->handle : null; } /** * Get the cURL setopt options of the handle. Changing values in the return * object will have no effect on the curl handle after it is created. * * @return Collection */ public function getOptions() { return $this->options; } }src/Guzzle/Http/Curl/CurlMulti.php000064400000036612151742730640013111 0ustar00multiHandle = curl_multi_init(); } /** * {@inheritdoc} */ public function __destruct() { if (is_resource($this->multiHandle)) { curl_multi_close($this->multiHandle); } } /** * Adds a request to the next scope (or batch or requests to be sent). If * a request is added using async, then the request is added to the current * scope. This means that the request will be sent and polled if requests * are currently being sent, or that the request will be sent in the next * send operation. * {@inheritdoc} */ public function add(RequestInterface $request, $async = false) { $scope = $async ? $this->scope : $this->scope + 1; if (!isset($this->requests[$scope])) { $this->requests[$scope] = array(); } $this->requests[$scope][] = $request; $this->dispatch(self::ADD_REQUEST, array( 'request' => $request )); if ($this->state == self::STATE_SENDING) { $this->beforeSend($request); } return $this; } /** * {@inheritdoc} */ public function all() { $requests = array(); foreach ($this->requests as $scopedRequests) { $requests = array_merge($requests, $scopedRequests); } return $requests; } /** * {@inheritdoc} */ public function getState() { return $this->state; } /** * {@inheritdoc} */ public function remove(RequestInterface $request) { // If currently sending a requests, then we need to remove a // curl easy handle from the curl multi handle if ($this->state == self::STATE_SENDING && $this->multiHandle) { $handle = $this->getRequestHandle($request) ?: $request->getParams('curl_handle'); if ($handle instanceof CurlHandle && $handle->getHandle()) { curl_multi_remove_handle($this->multiHandle, $handle->getHandle()); $handle->close(); unset($this->handles[spl_object_hash($request)]); } } foreach ($this->requests as $scope => $scopedRequests) { foreach ($scopedRequests as $i => $scopedRequest) { if ($scopedRequest === $request) { unset($this->requests[$scope][$i]); } } } $this->dispatch(self::REMOVE_REQUEST, array( 'request' => $request )); return $this; } /** * {@inheritdoc} */ public function reset($hard = false) { // Remove each request foreach ($this->all() as $request) { $this->remove($request); } $this->requests = $this->exceptions = array(); $this->state = self::STATE_IDLE; $this->scope = -1; if ($hard) { curl_multi_close($this->multiHandle); $this->multiHandle = curl_multi_init(); } } /** * {@inheritdoc} */ public function send() { $this->scope++; // Don't prepare for sending again if send() is called while sending if ($this->state != self::STATE_SENDING) { $requests = $this->all(); // Any exceptions thrown from this event should break the entire // flow of sending requests in parallel to prevent weird errors $this->dispatch(self::BEFORE_SEND, array( 'requests' => $requests )); $this->state = self::STATE_SENDING; foreach ($requests as $request) { if ($request->getState() != RequestInterface::STATE_TRANSFER) { $this->beforeSend($request); } } } try { $this->perform(); } catch (\Exception $e) { $this->exceptions[] = $e; } $this->scope--; // Don't re-complete if another scope already completed the transfers if ($this->state !== self::STATE_COMPLETE) { $this->state = self::STATE_COMPLETE; $this->dispatch(self::COMPLETE); $this->state = self::STATE_IDLE; } if (!empty($this->exceptions)) { $collection = new ExceptionCollection('Errors during multi transfer'); while ($e = array_shift($this->exceptions)) { $collection->add($e); } $this->reset(); throw $collection; } } /** * {@inheritdoc} */ public function count() { return count($this->all()); } /** * Prepare for sending * * @param RequestInterface $request Request to prepare */ 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) { // Requests might decide they don't need to be sent just before // transfer (e.g. CachePlugin) $this->remove($request); } else if ($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 curl_multi_add_handle($this->multiHandle, $this->createCurlHandle($request)->getHandle()); } } catch (\Exception $e) { $this->removeErroredRequest($request, $e); } } /** * Create a curl handle for a request * * @param RequestInterface $request Request * * @return CurlHandle */ protected function createCurlHandle(RequestInterface $request) { $wrapper = CurlHandle::factory($request); $this->handles[spl_object_hash($request)] = $wrapper; $request->getParams()->set('curl_handle', $wrapper); return $wrapper; } /** * Get the data from the multi handle */ protected function perform() { $active = $failedSelects = 0; $pendingRequests = !$this->scope ? $this->count() : !empty($this->requests[$this->scope]); while ($pendingRequests) { while ($mrc = curl_multi_exec($this->multiHandle, $active) == CURLM_CALL_MULTI_PERFORM); // @codeCoverageIgnoreStart if ($mrc != CURLM_OK) { throw new CurlException('curl_multi_exec returned ' . $mrc); } // @codeCoverageIgnoreEnd // Get messages from curl handles while ($done = curl_multi_info_read($this->multiHandle)) { $this->dispatch('curl_multi.message', $done); foreach ($this->all() as $request) { $handle = $this->getRequestHandle($request); if ($handle && $handle->getHandle() === $done['handle']) { try { $this->processResponse($request, $handle, $done); } catch (\Exception $e) { $this->removeErroredRequest($request, $e); } break; } } } // Notify each request as polling and handled queued responses $scopedPolling = $this->scope <= 0 ? $this->all() : $this->requests[$this->scope]; $pendingRequests = !empty($scopedPolling); foreach ($scopedPolling as $request) { $request->dispatch(self::POLLING_REQUEST, array( 'curl_multi' => $this, 'request' => $request )); } if ($pendingRequests) { if (!$active) { // Requests are not actually pending a cURL select call, so // we need to delay in order to prevent eating too much CPU usleep(30000); } else { $select = curl_multi_select($this->multiHandle, 0.3); // Select up to 25 times for a total of 7.5 seconds if (!$select && $this->scope > 0 && ++$failedSelects > 25) { // There are cases where curl is waiting on a return // value from a parent scope in order to remove a curl // handle. This check will defer to a parent scope for // handling the rest of the connection transfer. // @codeCoverageIgnoreStart break; // @codeCoverageIgnoreEnd } } } } } /** * Remove a request that encountered an exception * * @param RequestInterface $request Request to remove * @param Exception $e Exception encountered */ protected function removeErroredRequest(RequestInterface $request, \Exception $e) { $request->setState(RequestInterface::STATE_ERROR); $this->remove($request); $this->dispatch(self::MULTI_EXCEPTION, array( 'exception' => $e, 'all_exceptions' => $this->exceptions )); $this->exceptions[] = $e; } /** * Check for errors and fix headers of a request based on a curl response * * @param RequestInterface $request Request to process * @param CurlHandle $handle Curl handle object * @param array $curl Curl message returned from curl_multi_info_read * * @throws CurlException on Curl error */ protected function processResponse(RequestInterface $request, CurlHandle $handle, array $curl) { // Check for errors on the handle if (CURLE_OK != $curl['result']) { $handle->setErrorNo($curl['result']); $e = new CurlException('[curl] ' . $handle->getErrorNo() . ': ' . $handle->getError() . ' [url] ' . $handle->getUrl() . ' [info] ' . var_export($handle->getInfo(), true) . ' [debug] ' . $handle->getStderr()); $e->setRequest($request) ->setError($handle->getError(), $handle->getErrorNo()); $handle->close(); throw $e; } // Set the transfer stats on the response $log = $handle->getStderr(); if (null !== $log) { $request->getResponse()->setInfo(array_merge(array( 'stderr' => $log ), $handle->getInfo())); // Parse the cURL stderr output for outgoing requests $headers = ''; fseek($handle->getStderr(true), 0); while (($line = fgets($handle->getStderr(true))) !== false) { if ($line && $line[0] == '>') { $headers = substr(trim($line), 2) . "\r\n"; while (($line = fgets($handle->getStderr(true))) !== false) { if ($line[0] == '*' || $line[0] == '<') { break; } else { $headers .= trim($line) . "\r\n"; } } } } // Add request headers to the request exactly as they were sent if ($headers) { $parsed = RequestFactory::parseMessage($headers); if (!empty($parsed['headers'])) { $request->setHeaders(array()); foreach ($parsed['headers'] as $name => $value) { $request->setHeader($name, $value); } } if (!empty($parsed['protocol_version'])) { $request->setProtocolVersion($parsed['protocol_version']); } } } $request->setState(RequestInterface::STATE_COMPLETE); if ($request->getState() != RequestInterface::STATE_TRANSFER) { $this->remove($request); } } /** * Get the curl handle associated with a request * * @param RequestInterface $request Request * * @return CurlHandle|null */ private function getRequestHandle(RequestInterface $request) { $hash = spl_object_hash($request); return isset($this->handles[$hash]) ? $this->handles[$hash] : null; } }src/Guzzle/Http/Curl/CurlMultiInterface.php000064400000004042151742730640014722 0ustar00handleCompression($filter); $this->contentEncoding = $result ? $filter : false; return $result; } /** * Uncompress a deflated string. Once uncompressed, the uncompressed * string is then used as the wrapped stream. * * @param string $filter (optional) De-compression filter * * @return bool Returns TRUE on success or FALSE on failure */ public function uncompress($filter = 'zlib.inflate') { $offsetStart = 0; // When inflating gzipped data, the first 10 bytes must be stripped // if a gzip header is present if ($filter == 'zlib.inflate') { // @codeCoverageIgnoreStart if (!$this->isReadable() || ($this->isConsumed() && !$this->isSeekable())) { return false; } // @codeCoverageIgnoreEnd $this->seek(0); if (fread($this->stream, 3) == "\x1f\x8b\x08") { $offsetStart = 10; } } $this->contentEncoding = false; return $this->handleCompression($filter, $offsetStart); } /** * Get the Content-Length of the entity body if possible (alias of getSize) * * @return int|false */ public function getContentLength() { return $this->getSize(); } /** * Guess the Content-Type or return the default application/octet-stream * * @return string * @see http://www.php.net/manual/en/function.finfo-open.php */ public function getContentType() { if (!class_exists('finfo', false) || !($this->isLocal() && $this->getWrapper() == 'plainfile' && file_exists($this->getUri()))) { return 'application/octet-stream'; } $finfo = new \finfo(FILEINFO_MIME_TYPE); return $finfo->file($this->getUri()); } /** * Get an MD5 checksum of the stream's contents * * @param bool $rawOutput (optional) Whether or not to use raw output * @param bool $base64Encode (optional) whether or not to base64 encode * raw output (only if raw output is true) * * @return bool|string Returns an MD5 string on success or FALSE on failure */ public function getContentMd5($rawOutput = false, $base64Encode = false) { if (!$this->seek(0)) { return false; } $ctx = hash_init('md5'); while ($data = $this->read(1024)) { hash_update($ctx, $data); } $out = hash_final($ctx, (bool) $rawOutput); $this->seek(0); return ((bool) $base64Encode && (bool) $rawOutput) ? base64_encode($out) : $out; } /** * Set the type of encoding stream that was used on the entity body * * @param string $streamFilterContentEncoding Stream filter used * * @return EntityBody */ public function setStreamFilterContentEncoding($streamFilterContentEncoding) { $this->contentEncoding = $streamFilterContentEncoding; return $this; } /** * Get the Content-Encoding of the EntityBody * * @return bool|string */ public function getContentEncoding() { return strtr($this->contentEncoding, array( 'zlib.deflate' => 'gzip', 'bzip2.compress' => 'compress' )) ?: false; } /** * Handles compression or uncompression of stream data * * @param $filter Name of the filter to use (zlib.deflate or zlib.inflate) * @param int $offsetStart (optional) Number of bytes to skip from start * * @return bool Returns TRUE on success or FALSE on failure */ protected function handleCompression($filter, $offsetStart = null) { // @codeCoverageIgnoreStart if (!$this->isReadable() || ($this->isConsumed() && !$this->isSeekable())) { return false; } // @codeCoverageIgnoreEnd $handle = fopen('php://temp', 'r+'); $filter = @stream_filter_append($handle, $filter, STREAM_FILTER_WRITE); if (!$filter) { return false; } // Seek to the beginning of the stream if possible $this->seek(0); if ($offsetStart) { fread($this->stream, $offsetStart); } while ($data = fread($this->stream, 8096)) { fwrite($handle, $data); } fclose($this->stream); $this->stream = $handle; stream_filter_remove($filter); $stat = fstat($this->stream); $this->size = $stat['size']; $this->rebuildCache(); $this->seek(0); return true; } }src/Guzzle/Http/HttpException.php000064400000000226151742730640013052 0ustar00params; } /** * Add and merge in an array of HTTP headers. * * @param array $headers Associative array of header data. * * @return AbstractMessage */ public function addHeaders(array $headers) { $this->headers->merge($headers); $this->changedHeader('set', array_keys($headers)); return $this; } /** * Retrieve an HTTP header by name * * @param string $header Header to retrieve. * @param mixed $default (optional) If the header is not found, the passed * $default value will be returned * @param int $match (optional) Match mode: * 0 - Exact match * 1 - Case insensitive match * 2 - Regular expression match * * @return string|null Returns the matching HTTP header value or NULL if the * header is not found */ public function getHeader($header, $default = null, $match = Collection::MATCH_EXACT) { return $this->headers->get($header, $default, $match); } /** * Get all or all matching headers. * * @param array $names (optional) Pass an array of header names to retrieve * only a particular subset of headers. * @param int $match (optional) Match mode * * @see AbstractMessage::getHeader * @return Collection Returns a collection of all headers if no $headers * array is specified, or a Collection of only the headers matching * the headers in the $headers array. */ public function getHeaders(array $headers = null, $match = Collection::MATCH_EXACT) { if (!$headers) { return clone $this->headers; } else { return new Collection($this->headers->getAll($headers, $match)); } } /** * Get a tokenized header as a Collection * * @param string $header Header to retrieve * @param string $token (optional) Token separator * @param int $match (optional) Match mode * * @return Collection|null */ public function getTokenizedHeader($header, $token = ';', $match = Collection::MATCH_EXACT) { $value = $this->getHeader($header, $match); if (!$value) { return null; } $data = new Collection(); foreach ((array) $value 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])); } } } return $data->map(function($key, $value) { return is_array($value) ? array_unique($value) : $value; }); } /** * 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 (optional) Token delimiter * * @return AbstractMessage * @throws InvalidArgumentException if data is not an array or Collection */ 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)); } /** * Check if the specified header is present. * * @param string $header The header to check. * @param int $match (optional) Match mode * * @see AbstractMessage::getHeader * @return bool|mixed Returns TRUE or FALSE if the header is present and using exact matching * Returns the matching header or FALSE if no match found and using regex or case * insensitive matching */ public function hasHeader($header, $match = Collection::MATCH_EXACT) { return $match == Collection::MATCH_EXACT ? false !== $this->headers->hasKey($header, $match) : $this->headers->hasKey($header, $match); } /** * Remove a specific HTTP header. * * @param string $header HTTP header to remove. * @param int $match (optional) Bitwise match setting * * @see AbstractMessage::getHeader * @return AbstractMessage */ public function removeHeader($header, $match = Collection::MATCH_EXACT) { $this->headers->remove($header, $match); $this->changedHeader('remove', $header); return $this; } /** * Set an HTTP header * * @param string $header Name of the header to set. * @param mixed $value Value to set. * * @return AbstractMessage */ public function setHeader($header, $value) { $this->headers->set($header, $value); $this->changedHeader('set', $header); return $this; } /** * Overwrite all HTTP headers with the supplied array of headers * * @param array $headers Associative array of header data. * * @return AbstractMessage */ public function setHeaders(array $headers) { $this->changedHeader('set', $this->getHeaders()->getKeys()); $this->headers->replace($headers); return $this; } /** * Get a Cache-Control directive from the message * * @param string $directive Directive to retrieve * * @return null|string */ public function getCacheControlDirective($directive) { return isset($this->cacheControl[$directive]) ? $this->cacheControl[$directive] : null; } /** * Check if the message has a Cache-Control directive * * @param string $directive Directive to check * * @return bool */ public function hasCacheControlDirective($directive) { return isset($this->cacheControl[$directive]); } /** * Add a Cache-Control directive on the message * * @param string $directive Directive to set * @param bool|string $value (optional) Value to set * * @return AbstractMessage */ public function addCacheControlDirective($directive, $value = true) { $this->cacheControl[$directive] = $value; $this->rebuildCacheControlDirective(); return $this; } /** * Remove a Cache-Control directive from the message * * @param string $directive Directive to remove * * @return AbstractMessage */ public function removeCacheControlDirective($directive) { if (array_key_exists($directive, $this->cacheControl)) { unset($this->cacheControl[$directive]); $this->rebuildCacheControlDirective(); } return $this; } /** * Check to see if the modified headers need to reset any of the managed * headers like cache-control * * @param string $action One of set or remove * @param string|array $keyOrArray Header or headers that changed */ protected function changedHeader($action, $keyOrArray) { if (in_array('Cache-Control', (array) $keyOrArray)) { $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) { if ($value === true) { $cacheControl[] = $key; } else { $cacheControl[] = $key . '=' . $value; } } $this->headers->set('Cache-Control', implode(', ', $cacheControl)); } }src/Guzzle/Http/Message/BadResponseException.php000064400000001163151742730640015725 0ustar00response = $response; } /** * Get the response that caused the exception * * @return Response */ public function getResponse() { return $this->response; } }src/Guzzle/Http/Message/EntityEnclosingRequest.php000064400000014330151742730640016330 0ustar00postFields = new QueryString(); $this->postFields->setPrefix(''); parent::__construct($method, $url, $headers); $this->setHeader('Expect', '100-Continue'); } /** * Get the HTTP request as a string * * @return string */ public function __toString() { return parent::__toString() . (count($this->getPostFields()) ? $this->postFields : $this->body); } /** * Set the body of the request * * @param string|resource|EntityBody $body Body to use in the entity body * of the request * @param string $contentType (optional) Content-Type to set. Leave null * to use an existing Content-Type or to guess the Content-Type * @param bool $tryChunkedTransfer (optional) Set to TRUE to try to use * Tranfer-Encoding chunked * * @return EntityEnclosingRequest * @throws RequestException if the protocol is < 1.1 and Content-Length can * not be determined */ public function setBody($body, $contentType = null, $tryChunkedTransfer = false) { $this->body = EntityBody::factory($body); $this->removeHeader('Content-Length'); if ($contentType) { $this->setHeader('Content-Type', $contentType); } else { $this->removeHeader('Content-Type'); } 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 && !is_bool($size)) { $this->setHeader('Content-Length', $size); } else if ('1.1' == $this->protocolVersion) { $this->setHeader('Transfer-Encoding', 'chunked'); } else { throw new RequestException('Cannot determine entity body ' . 'size and cannot use chunked Transfer-Encoding when ' . 'using HTTP/' . $this->protocolVersion ); } } return $this; } /** * Get the body of the request if set * * @return EntityBody|null */ public function getBody() { return $this->body; } /** * Get a POST field from the request * * @param string $field Field to retrive * * @return mixed|null */ public function getPostField($field) { return $this->postFields->get($field); } /** * Get the post fields that will be used in the request * * @return array */ public function getPostFields() { return $this->postFields->getAll(); } /** * Returns an associative array of POST field names and file paths * * @return array */ public function getPostFiles() { return $this->postFields->filter(function($key, $value) { return $value && $value[0] == '@'; })->map(function($key, $value) { return str_replace('@', '', $value); })->getAll(); } /** * Add POST fields to use in the request * * @param QueryString|array $fields POST fields * * @return EntityEnclosingRequest */ public function addPostFields($fields) { $this->postFields->merge($fields); $this->processPostFields(); return $this; } /** * Set a POST field value * * @param string $key Key to set * @param string $value Value to set * * @return EntityEnclosingRequest */ public function setPostField($key, $value) { $this->postFields->set($key, $value); $this->processPostFields(); return $this; } /** * Add POST files to use in the upload * * @param array $files An array of filenames to POST * * @return EntityEnclosingRequest * @throws BodyException if the file cannot be read */ public function addPostFiles(array $files) { foreach ((array) $files as $key => $file) { if (is_numeric($key)) { $key = 'file'; } $found = ($file[0] == '@') ? is_readable(substr($file, 1)) : is_readable($file); if (!$found) { throw new RequestException('File cannot be opened for reading: ' . $file); } if ($file[0] != '@') { $file = '@' . $file; } $this->postFields->add($key, $file); } $this->processPostFields(); return $this; } /** * Remove a POST field or file by name * * @param string $field Name of the POST field or file to remove * * @return EntityEnclosingRequest */ public function removePostField($field) { $this->postFields->remove($field); $this->processPostFields(); return $this; } /** * Determine what type of request should be sent based on post fields */ protected function processPostFields() { if (0 == count($this->getPostFiles())) { $this->setHeader('Content-Type', 'application/x-www-form-urlencoded'); $this->getCurlOptions()->set(CURLOPT_POSTFIELDS, (string) $this->postFields); } else { $this->setHeader('Content-Type', 'multipart/form-data'); $this->postFields->setEncodeFields(false)->setEncodeValues(false); $this->getCurlOptions()->set(CURLOPT_POSTFIELDS, $this->postFields->getAll()); } } }src/Guzzle/Http/Message/EntityEnclosingRequestInterface.php000064400000004617151742730640020160 0ustar00method = strtoupper($method); $this->headers = new Collection(); $this->curlOptions = new Collection(); $this->params = new Collection(); $this->setUrl($url); if ($headers) { foreach ($headers as $key => $value) { if ($key == 'Host') { $this->removeHeader($key); } $this->setHeader($key, $value); } } if (!$this->hasHeader('User-Agent', true)) { $this->setHeader('User-Agent', Guzzle::getDefaultUserAgent()); } $this->cookie = Cookie::factory($this->getHeader('Cookie')); $this->setState(self::STATE_NEW); } /** * Clone the request object, leaving off any response that was received */ public function __clone() { if ($this->eventDispatcher) { $this->eventDispatcher = clone $this->eventDispatcher; } $this->curlOptions = clone $this->curlOptions; $this->params = clone $this->params; $this->url = clone $this->url; $this->headers = clone $this->headers; $this->response = $this->responseBody = null; $this->params->remove('curl_handle') ->remove('queued_response') ->remove('curl_multi'); $this->setState(RequestInterface::STATE_NEW); } /** * Get the HTTP request as a string * * @return string */ public function __toString() { return $this->getRawHeaders() . "\r\n\r\n"; } /** * Default method that will throw exceptions if an unsuccessful response * is received. * * @param Event $event Received * @throws BadResponseException if the response is not successful */ public static function onRequestError(Event $event) { $e = new BadResponseException('Unsuccessful response | ' . implode(' | ', array( '[status code] ' . $event['response']->getStatusCode(), '[reason phrase] ' . $event['response']->getReasonPhrase(), '[url] ' . $event['request']->getUrl(), '[request] ' . (string) $event['request'], '[response] ' . (string) $event['response'] ))); $e->setResponse($event['response']); $e->setRequest($event['request']); $event['request']->dispatch('request.exception', array( 'request' => $event['request'], 'response' => $event['response'], 'exception' => $e )); throw $e; } /** * Set the client used to transport the request * * @param ClientInterface $client * * @return Request */ public function setClient(ClientInterface $client) { $this->client = $client; return $this; } /** * Get the client used to transport the request * * @return ClientInterface $client */ public function getClient() { return $this->client; } /** * Get the raw message headers as a string * * @return string */ public function getRawHeaders() { $raw = $this->method . ' ' . $this->getResourceUri(); $protocolVersion = $this->protocolVersion ?: '1.1'; $raw = trim($raw) . ' ' . strtoupper(str_replace('https', 'http', $this->url->getScheme())) . '/' . $protocolVersion . "\r\n"; foreach ($this->headers as $key => $value) { $raw .= $key . ': ' . $value . "\r\n"; } return rtrim($raw, "\r\n"); } /** * 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 Request */ public function setUrl($url) { if (is_string($url)) { $this->url = Url::factory($url); } else if ($url instanceof Url) { $this->url = $url; } else { throw new \InvalidArgumentException('Invalid URL sent to ' . __METHOD__); } $this->setHost($this->url->getHost()); $this->setPort($this->url->getPort()); if ($this->url->getUsername() && $this->url->getPassword()) { $this->setAuth($this->url->getUsername(), $this->url->getPassword()); } // Remove the auth info from the URL $this->url->setUsername(null); $this->url->setPassword(null); return $this; } /** * Send the request * * @return Response * @throws RequestException on a request error */ public function send() { if (!$this->client) { throw new \RuntimeException('A client must be set on the request'); } return $this->client->send($this); } /** * Get the previously received {@see Response} or NULL if the request has * not been sent * * @return Response|null */ public function getResponse() { return $this->response; } /** * Get the collection of key value pairs that will be used as the query * string in the request * * @param bool $asString (optional) Set to TRUE to get the query as string * * @return QueryString|string */ public function getQuery($asString = false) { return $asString ? (string) $this->url->getQuery() : $this->url->getQuery(); } /** * Get the HTTP method of the request * * @return string */ public function getMethod() { return $this->method; } /** * Get the URI scheme of the request (http, https, ftp, etc) * * @return string */ public function getScheme() { return $this->url->getScheme(); } /** * Set the URI scheme of the request (http, https, ftp, etc) * * @param string $scheme Scheme to set * * @return Request */ public function setScheme($scheme) { $this->url->setScheme($scheme); return $this; } /** * Get the host of the request * * @return string */ public function getHost() { return $this->url->getHost(); } /** * Set the host of the request. * * @param string $host Host to set (e.g. www.yahoo.com, www.yahoo.com) * * @return Request */ public function setHost($host) { $parts = explode(':', $host); $this->url->setHost($parts[0]); if (isset($parts[1])) { $this->setPort($parts[1]); } else { $this->headers->set('Host', $host); } return $this; } /** * Get the HTTP protocol version of the request * * @param bool $curlValue (optional) Set to TRUE to retrieve the cURL value * for the HTTP protocol version * * @return string|int */ public function getProtocolVersion($curlValue = false) { if (!$curlValue) { return $this->protocolVersion; } else { return $this->protocolVersion === '1.0' ? CURL_HTTP_VERSION_1_0 : CURL_HTTP_VERSION_1_1; } } /** * 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 Request */ public function setProtocolVersion($protocol) { $this->protocolVersion = $protocol; return $this; } /** * Get the path of the request (e.g. '/', '/index.html') * * @return string */ public function getPath() { return $this->url->getPath(); } /** * Set the path of the request (e.g. '/', '/index.html') * * @param string|array $path Path to set or array of segments to implode * * @return Request */ public function setPath($path) { $this->url->setPath($path); return $this; } /** * Get the port that the request will be sent on if it has been set * * @return int|null */ public function getPort() { return $this->url->getPort(); } /** * Set the port that the request will be sent on * * @param int $port Port number to set * * @return Request */ public function setPort($port) { $this->url->setPort($port); // Include the port in the Host header if it is not the default port // for the scheme of the URL if (($this->url->getScheme() == 'http' && $port != 80) || ($this->url->getScheme() == 'https' && $port != 443)) { $this->headers->set('Host', $this->url->getHost() . ':' . $port); } else { $this->headers->set('Host', $this->url->getHost()); } return $this; } /** * Get the username to pass in the URL if set * * @return string|null */ public function getUsername() { return $this->username; } /** * Get the password to pass in the URL if set * * @return string|null */ public function getPassword() { return $this->password; } /** * Set HTTP authorization parameters * * @param string|false $user (optional) User name or false disable authentication * @param string $password (optional) Password * @param string $scheme (optional) Curl authentication scheme to use * * @return Request * * @see http://www.ietf.org/rfc/rfc2617.txt * @throws RequestException */ public function setAuth($user, $password = '', $scheme = CURLAUTH_BASIC) { // If we got false or null, disable authentication if (!$user || !$password) { $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; } /** * Get the URI of the request (e.g. '/', '/index.html', '/index.html?q=1) * This is the path plus the query string, fragment * * @return string */ public function getResourceUri() { $url = $this->url->getPath(); $query = (string) $this->url->getQuery(); if ($query) { $url .= $query; } return $url; } /** * Get the full URL of the request (e.g. 'http://www.guzzle-project.com/') * * scheme://username:password@domain:port/path?query_string#fragment * * @return string */ public function getUrl() { return (string) $this->url; } /** * Get the state of the request. One of 'complete', 'sending', 'new' * * @return string */ public function getState() { return $this->state; } /** * Set the state of the request * * @param string $state State of the request (complete, sending, or new) * * @return Request */ public function setState($state) { $this->state = $state; if ($this->state == self::STATE_NEW) { $this->responseBody = $this->response = null; } else if ($this->state == self::STATE_COMPLETE) { $this->processResponse(); } return $this; } /** * Get the cURL options that will be applied when the cURL handle is created * * @return Collection */ public function getCurlOptions() { return $this->curlOptions; } /** * Method to receive HTTP response headers as they are retrieved * * @param string $data Header data. * * @return integer Returns the size of the data. */ public function receiveResponseHeader($data) { $this->state = self::STATE_TRANSFER; $length = strlen($data); // Normalize line endings $data = preg_replace("/([^\r])(\n)\b/", "$1\r\n", $data); if (preg_match('/^\HTTP\/1\.[0|1]\s\d{3}\s.+$/', $data)) { $previousResponse = $this->response; list($dummy, $code, $status) = explode(' ', str_replace("\r\n", '', $data), 3); $this->response = new Response($code, null, $this->getResponseBody()); $this->response->setStatus($code, $status)->setRequest($this); $this->dispatch('request.receive.status_line', array( 'line' => $data, 'status_code' => $code, 'reason_phrase' => $status, 'previous_response' => $previousResponse )); } else if ($length > 2) { list($header, $value) = array_map('trim', explode(':', trim($data), 2)); $this->response->addHeaders(array( $header => $value )); $this->dispatch('request.receive.header', array( 'header' => $header, 'value' => $value ), true); } return $length; } /** * Manually set a response for the request. * * 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. * * @param Response $response Response object to set * @param bool $queued (optional) Set to TRUE to keep the request in a stat * of not having been sent, but queue the response for send() * * @return Request Returns a reference to the object. */ public function setResponse(Response $response, $queued = false) { $response->setRequest($this); if (!$queued) { $this->getParams()->remove('queued_response'); $this->response = $response; $this->responseBody = $response->getBody(); $this->processResponse(); } else { $this->getParams()->set('queued_response', $response); } $this->dispatch('request.set_response', $this->getEventArray()); return $this; } /** * Set the EntityBody that will hold the 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. * * @param EntityBody $body Response body object * * @return Request */ public function setResponseBody(EntityBody $body) { $this->responseBody = $body; return $this; } /** * Determine if the response body is repeatable (readable + seekable) * * @return bool */ public function isResponseBodyRepeatable() { return !$this->responseBody ? true : $this->responseBody->isSeekable() && $this->responseBody->isReadable(); } /** * Get an array of Cookies or a specific cookie from the request * * @param string $name (optional) Cookie to retrieve * * @return null|string|Cookie Returns null if not found by name, a Cookie * object if no $name is supplied, or the cookie value by name if found * If a Cookie object is returned, changes to the cookie object does * not modify the request's cookies. You will need to set the cookie * back on the request after modifying the object. */ public function getCookie($name = null) { return !$name ? clone $this->cookie : $this->cookie->get($name); } /** * Set the Cookie header using an array or Cookie object * * @param array|Cookie $cookies Cookie data to set on the request * * @return Request */ public function setCookie($cookies) { if ($cookies instanceof Cookie) { $this->cookie = $cookies; } else if (is_array($cookies)) { $this->cookie->replace($cookies); } else { throw new \InvalidArgumentException('Invalid cookie data'); } $this->headers->set('Cookie', (string) $this->cookie); return $this; } /** * Add a Cookie value by name to the Cookie header * * @param string $name Name of the cookie to add * @param string $value Value to set * * @return Request */ public function addCookie($name, $value) { $this->cookie->add($name, $value); $this->headers->set('Cookie', (string) $this->cookie); return $this; } /** * Remove the cookie header or a specific cookie value by name * * @param string $name (optional) Cookie to remove by name. If no value is * provided, the entire Cookie header is removed from the request * * @return Request */ public function removeCookie($name = null) { $this->cookie->remove($name); $this->headers->set('Cookie', (string) $this->cookie); return $this; } /** * Returns whether or not the response served to the request can be cached * * @return bool */ 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; $this->eventDispatcher->addListener('request.error', array(__CLASS__, 'onRequestError'), -255); return $this; } /** * {@inheritdoc} */ public function getEventDispatcher() { if (!$this->eventDispatcher) { $this->setEventDispatcher(new EventDispatcher()); } return $this->eventDispatcher; } /** * {@inheritdoc} */ public function dispatch($eventName, array $context = array()) { $context['request'] = $this; $this->getEventDispatcher()->dispatch($eventName, new Event($context)); } /** * {@inheritdoc} */ protected function changedHeader($action, $keyOrArray) { $keys = (array) $keyOrArray; parent::changedHeader($action, $keys); if (in_array('Cookie', $keys)) { if ($action == 'set') { $this->cookie = Cookie::factory($this->getHeader('Cookie')); } else { $this->cookie->clear(); } } if (in_array('Host', $keys)) { $parts = explode(':', $this->getHeader('Host')); $this->url->setHost($parts[0]); $this->setPort(!empty($parts[1]) ? $parts[1] : ($this->url->getScheme() == 'https' ? 443 : 80)); } } /** * Get the EntityBody that will store the received response entity body * * @return EntityBody */ 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 */ protected function getEventArray() { return array( 'request' => $this, 'response' => $this->response ); } /** * Process a received response * * @throws BadResponseException on unsuccessful responses */ protected function processResponse() { // 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'); } else if (!$this->response) { // If no response, then processResponse shouldn't have been called $e = new RequestException('Error completing request'); $e->setRequest($this); throw $e; } $this->state = self::STATE_COMPLETE; // A request was sent, but we don't know if we'll send more or if the // final response will be a successful response $this->dispatch('request.sent', $this->getEventArray()); // Some response processors will remove the response or reset the state // (example: ExponentialBackoffPlugin) if ($this->state == RequestInterface::STATE_COMPLETE) { // The request completed, so the HTTP transaction is complete $this->dispatch('request.complete', $this->getEventArray()); // If the response is bad, allow listeners to modify it or throw // exceptions. You can change the response by modifying the Event // object in your listeners or calling setResponse() on the request if ($this->response->isError()) { $event = new Event($this->getEventArray()); $this->getEventDispatcher()->dispatch('request.error', $event); // Allow events of request.error to quietly change the response if ($event['response'] !== $this->response) { $this->response = $event['response']; } } // If a successful response was received, dispatch an event if ($this->response->isSuccessful()) { $this->dispatch('request.success', $this->getEventArray()); } } return $this; } }src/Guzzle/Http/Message/RequestException.php000064400000001272151742730640015151 0ustar00request = $request; return $this; } /** * Get the request that caused the exception * * @return RequestInterface */ public function getRequest() { return $this->request; } }src/Guzzle/Http/Message/RequestFactory.php000064400000020215151742730640014620 0ustar00GET|POST|PUT|HEAD|DELETE|TRACE|OPTIONS)\s+(?P/.*)\s+(?P\w+)/(?P\d\.\d)\s*$#i', $line, $matches)) { $method = strtoupper($matches['method']); $protocol = strtoupper($matches['protocol']); $path = $matches['path']; $version = $matches['version']; $scheme = 'http'; } else if (strpos($line, ':')) { list($key, $value) = explode(':', $line, 2); $key = trim($key); // Normalize standard HTTP headers if (in_array(strtolower($key), self::$requestHeaders)) { $key = trim(str_replace(' ', '-', ucwords(str_replace('-', ' ', $key)))); } $headers[$key] = trim($value); } } // Check if a body is present in the message $body = isset($parts[1]) ? $parts[1] : null; // Check for the Host header $host = isset($headers['Host']) ? $headers['Host'] : ''; if (strpos($host, ':')) { list($host, $port) = array_map('trim', explode(':', $host)); if ($port == 443) { $scheme = 'https'; } } else { $port = ''; } // Check for basic authorization $auth = isset($headers['Authorization']) ? $headers['Authorization'] : ''; if ($auth) { list($type, $data) = explode(' ', $auth); if (strtolower($type) == 'basic') { $data = base64_decode($data); list($user, $pass) = explode(':', $data); } } // Check if a query is present $qpos = strpos($path, '?'); if ($qpos) { $query = substr($path, $qpos); $path = substr($path, 0, $qpos); } return array( 'method' => $method, 'protocol' => $protocol, 'protocol_version' => $version, 'parts' => array( 'scheme' => $scheme, 'host' => $host, 'port' => $port, 'user' => $user, 'pass' => $pass, 'path' => $path, 'query' => $query ), 'headers' => $headers, 'body' => $body ); } /** * Create a new request based on an HTTP message * * @param string $message HTTP message as a string * * @return RequestInterface */ public static function fromMessage($message) { $parsed = self::parseMessage($message); if (!$parsed) { return false; } return self::fromParts( $parsed['method'], $parsed['parts'], $parsed['headers'], $parsed['body'], $parsed['protocol'], $parsed['protocol_version'] ); } /** * Create a request from URL parts as returned from parse_url() * * @param string $method HTTP method (GET, POST, PUT, HEAD, DELETE, etc) * * @param array $parts URL parts containing the same keys as parse_url() * # scheme - e.g. http * # host - e.g. www.guzzle-project.com * # port - e.g. 80 * # user - e.g. michael * # pass - e.g. rocks * # path - e.g. / OR /index.html * # query - after the question mark ? * * @param array|Collection $headers (optional) HTTP headers * @param string|resource|array|EntityBody $body Body to send in the request * @param string $protocol (optional) Protocol (HTTP, SPYDY, etc) * @param string $protocolVersion (optional) 1.0, 1.1, etc * * @return RequestInterface */ public static function fromParts($method, array $parts, $headers = null, $body = null, $protocol = 'HTTP', $protocolVersion = '1.1') { return self::create($method, Url::buildUrl($parts, true), $headers, $body) ->setProtocolVersion($protocolVersion); } /** * Create a new request based on the HTTP method * * @param string $method HTTP method (GET, POST, PUT, HEAD, DELETE, etc) * @param string $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. * @param array|Collection $headers (optional) HTTP headers * @param string|resource|array|EntityBody $body Body to send in the request * * @return RequestInterface */ public static function create($method, $url, $headers = null, $body = null) { if ($method != 'POST' && $method != 'PUT') { $c = static::$requestClass; $request = new $c($method, $url, $headers); if ($body) { $request->setResponseBody(EntityBody::factory($body)); } } else { $c = static::$entityEnclosingRequestClass; $request = new $c($method, $url, $headers); if ($body) { if ($method == 'POST' && (is_array($body) || $body instanceof Collection)) { $request->addPostFields($body); } else if (is_resource($body) || $body instanceof EntityBody) { $request->setBody($body, $request->getHeader('Content-Type')); } else { $request->setBody((string) $body, $request->getHeader('Content-Type')); } } } return $request; } }src/Guzzle/Http/Message/RequestInterface.php000064400000022045151742730640015114 0ustar00 'Continue', 101 => 'Switching Protocols', 200 => 'OK', 201 => 'Created', 202 => 'Accepted', 203 => 'Non-Authoritative Information', 204 => 'No Content', 205 => 'Reset Content', 206 => 'Partial Content', 300 => 'Multiple Choices', 301 => 'Moved Permanently', 302 => 'Found', 303 => 'See Other', 304 => 'Not Modified', 305 => 'Use Proxy', 307 => 'Temporary Redirect', 400 => 'Bad Request', 401 => 'Unauthorized', 402 => 'Payment Required', 403 => 'Forbidden', 404 => 'Not Found', 405 => 'Method Not Allowed', 406 => 'Not Acceptable', 407 => 'Proxy Authentication Required', 408 => 'Request Timeout', 409 => 'Conflict', 410 => 'Gone', 411 => 'Length Required', 412 => 'Precondition Failed', 413 => 'Request Entity Too Large', 414 => 'Request-URI Too Long', 415 => 'Unsupported Media Type', 416 => 'Requested Range Not Satisfiable', 417 => 'Expectation Failed', 500 => 'Internal Server Error', 501 => 'Not Implemented', 502 => 'Bad Gateway', 503 => 'Service Unavailable', 504 => 'Gateway Timeout', 505 => 'HTTP Version Not Supported', ); /** * @var EntityBody The response body */ protected $body; /** * @var string The reason phrase of the response (human readable code) */ protected $reasonPhrase; /** * @var string The status code of the response */ protected $statusCode; /** * @var string Response protocol */ protected $protocol = 'HTTP'; /** * @var array Information about the request */ protected $info = array(); /** * @var RequestInterface Request object that may or may not be set */ protected $request = null; /** * @var array Cacheable response codes (see RFC 2616:13.4) */ protected $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 * @throws HttpException if an empty $message is provided */ public static function factory($message) { if (!$message) { throw new HttpException('No response message provided to factory'); } // Normalize line endings $message = preg_replace("/([^\r])(\n)\b/", "$1\r\n", $message); $protocol = $code = $status = ''; $parts = explode("\r\n\r\n", $message, 2); $headers = new Collection(); foreach (array_values(array_filter(explode("\r\n", $parts[0]))) as $i => $line) { // Remove newlines from headers $line = implode(' ', explode("\n", $line)); if ($i === 0) { // Check the status line list($protocol, $code, $status) = array_map('trim', explode(' ', $line, 3)); } else if (strpos($line, ':')) { // Add a header list($key, $value) = array_map('trim', explode(':', $line, 2)); $headers->add($key, $value); } } $body = null; if (isset($parts[1]) && $parts[1] != "\n") { $body = EntityBody::factory(trim($parts[1])); // Always set the appropriate Content-Length if Content-Legnth $headers['Content-Length'] = $body->getSize(); } $response = new self(trim($code), $headers, $body); $response->setProtocol($protocol) ->setStatus($code, $status); return $response; } /** * Construct the response * * @param string $statusCode The response status code (e.g. 200, 404, etc) * @param Collection|array $headers (optional) The response headers * @param string|EntityBody $body (optional) The body of the response * * @throws BadResponseException if an invalid response code is given */ public function __construct($statusCode, $headers = null, $body = null) { if (!array_key_exists($statusCode, self::$statusTexts)) { throw new BadResponseException( 'Invalid response code: ' . $statusCode ); } $this->setStatus($statusCode); $this->body = $body ?: EntityBody::factory(); $this->headers = new Collection(); $this->params = new Collection(); if ($headers) { if (!is_array($headers) && !($headers instanceof Collection)) { throw new BadResponseException('Invalid headers argument received'); } else { foreach ($headers as $key => $value) { $this->setHeader($key, $value); } } } $this->body = EntityBody::factory($body ?: ''); } /** * Convert the response object to a string * * @return string */ public function __toString() { return $this->getMessage(); } /** * Get the response entity body * * @param bool $asString Set to TRUE to return a string of the body rather * than a full body object * * @return EntityBody|string */ public function getBody($asString = false) { return $asString ? (string) $this->body : $this->body; } /** * Set the protocol and protocol version of the response * * @param string $protocol Response protocol and version (e.g. HTTP/1.1) * * @return Response */ public function setProtocol($protocol) { list($this->protocol, $this->protocolVersion) = array_map('trim', explode('/', $protocol, 2)); return $this; } /** * Get the protocol used for the response (e.g. HTTP) * * @return string */ public function getProtocol() { return $this->protocol ?: 'HTTP'; } /** * Get the HTTP protocol version * * @return string */ public function getProtocolVersion() { return $this->protocolVersion ?: '1.1'; } /** * Get a cURL transfer information * * @param string $key (optional) A single statistic to check * * @return array|string|null Returns all stats if no key is set, a single * stat if a key is set, or null if a key is set and not found * @link http://www.php.net/manual/en/function.curl-getinfo.php */ public function getInfo($key = null) { if ($key === null) { return $this->info; } else if (array_key_exists($key, $this->info)) { return $this->info[$key]; } else { return null; } } /** * Set the transfer information * * @param array $info Array of cURL transfer stats * * @return Response */ public function setInfo(array $info) { $this->info = $info; return $this; } /** * Set the response status * * @param int $statusCode Response status code to set * @param string $reasonPhrase (optional) Response reason phrase * * @return Response * @throws BadResponseException when an invalid response code is received */ public function setStatus($statusCode, $reasonPhrase = '') { $statusCode = (int) trim($statusCode); if (!array_key_exists($statusCode, self::$statusTexts)) { throw new BadResponseException('Invalid response code: ' . $statusCode); } $this->statusCode = $statusCode; $this->reasonPhrase = $reasonPhrase ? $reasonPhrase : self::$statusTexts[$statusCode]; return $this; } /** * Get the response status code * * @return integer */ public function getStatusCode() { return $this->statusCode; } /** * Get the entire response as a string * * @return string */ public function getMessage() { $message = $this->getRawHeaders(); // Only include the body in the message if the size is < 2MB $size = $this->body->getSize(); if ($size < 2097152) { $message .= (string) $this->body; } return $message; } /** * Get the the raw message headers as a string * * @return string */ public function getRawHeaders() { $headers = 'HTTP/1.1 ' . $this->statusCode . ' ' . $this->reasonPhrase . "\r\n"; foreach ($this->headers as $key => $value) { foreach ((array) $value as $v) { $headers .= $key . ': ' . $v . "\r\n"; } } return $headers . "\r\n"; } /** * Get the request object that is associated with this response * * @return null|Request\Request */ public function getRequest() { return $this->request; } /** * Get the response reason phrase- a human readable version of the numeric * status code * * @return string */ public function getReasonPhrase() { return $this->reasonPhrase; } /** * Get the Accept-Ranges HTTP header * * @return string|integer Returns what partial content range types this * server supports. */ public function getAcceptRanges() { return $this->headers->get('/^Accept-*Ranges$/i', null, Collection::MATCH_REGEX); } /** * Get the Age HTTP header * * @param bool $headerOnly (optional) 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. */ public function getAge($headerOnly = false) { $age = $this->headers->get('Age', null, Collection::MATCH_IGNORE_CASE); if (!$headerOnly && $age === null && $this->getDate()) { $age = time() - strtotime($this->getDate()); } return $age; } /** * Get the Allow HTTP header * * @return string|null Returns valid actions for a specified resource. To * be used for a 405 Method not allowed. */ public function getAllow() { return $this->headers->get('Allow', null, Collection::MATCH_IGNORE_CASE); } /** * Check if an HTTP method is allowed by checking the Allow response header * * @param string $method Method to check * * @return bool */ public function isMethodAllowed($method) { $allow = $this->getAllow(); if (!$allow) { return false; } else { return false !== array_search( strtoupper($method), array_map('trim', array_map('strtoupper', explode(',', $allow))) ); } } /** * Get the Cache-Control HTTP header * * @return string|null Returns a string that tells all caching mechanisms * from server to client whether they may cache this object. */ public function getCacheControl() { return $this->headers->get('/^Cache-*Control$/i', null, Collection::MATCH_REGEX); } /** * Get the Connection HTTP header * * @return string */ public function getConnection() { return $this->headers->get('Connection', null, Collection::MATCH_IGNORE_CASE); } /** * Get the Content-Encoding HTTP header * * @return string|null Returns the type of encoding used on the data. One * of compress, deflate, gzip, identity. */ public function getContentEncoding() { return $this->headers->get('/^Content-*Encoding$/i', null, Collection::MATCH_REGEX); } /** * Get the Content-Language HTTP header * * @return string|null Returns the language the content is in. */ public function getContentLanguage() { return $this->headers->get('/^Content-*Language$/i', null, Collection::MATCH_REGEX); } /** * Get the Content-Length HTTP header * * @return integer Returns the length of the response body in bytes */ public function getContentLength() { return $this->headers->get('/^Content-*Length$/i', null, Collection::MATCH_REGEX); } /** * Get the Content-Location HTTP header * * @return string|null Returns an alternate location for the returned data * (e.g /index.htm) */ public function getContentLocation() { return $this->headers->get('/^Content-*Location$/i', null, Collection::MATCH_REGEX); } /** * Get the Content-Disposition HTTP header * * @return string|null Returns the Content-Disposition header */ public function getContentDisposition() { return $this->headers->get('/^Content-*Disposition$/i', null, Collection::MATCH_REGEX); } /** * Get the Content-MD5 HTTP header * * @return string|null Returns a Base64-encoded binary MD5 sum of the * content of the response. */ public function getContentMd5() { return $this->headers->get('/^Content-*MD5$/i', null, Collection::MATCH_REGEX); } /** * Get the Content-Range HTTP header * * @return string Returns where in a full body message this partial message * belongs (e.g. bytes 21010-47021/47022). */ public function getContentRange() { return $this->headers->get('/^Content-*Range$/i', null, Collection::MATCH_REGEX); } /** * Get the Content-Type HTTP header * * @return string Returns the mime type of this content. */ public function getContentType() { return $this->headers->get('/^Content-*Type$/i', null, Collection::MATCH_REGEX); } /** * Checks if the Content-Type is of a certain type. This is useful if the * Content-Type header contains charset information and you need to know if * the Content-Type matches a particular type. * * @param string $type Content type to check against * * @return bool */ public function isContentType($type) { return stripos($this->getContentType(), $type) !== false; } /** * Get the Date HTTP header * * @return string|null Returns the date and time that the message was sent. */ public function getDate() { return $this->headers->get('Date', null, Collection::MATCH_IGNORE_CASE); } /** * Get the ETag HTTP header * * @return string|null Returns an identifier for a specific version of a * resource, often a Message digest. */ public function getEtag() { $etag = $this->headers->get('ETag', null, Collection::MATCH_IGNORE_CASE); return $etag ? str_replace('"', '', $etag) : null; } /** * Get the Expires HTTP header * * @return string|null Returns the date/time after which the response is * considered stale. */ public function getExpires() { return $this->headers->get('Expires', null, Collection::MATCH_IGNORE_CASE); } /** * Get the Last-Modified HTTP header * * @return string|null Returns the last modified date for the requested * object, in RFC 2822 format (e.g. Tue, 15 Nov 1994 12:45:26 GMT) */ public function getLastModified() { return $this->headers->get('/^Last-*Modified$/i', null, Collection::MATCH_REGEX); } /** * Get the Location HTTP header * * @return string|null Used in redirection, or when a new resource has been * created. (e.g. http://www.w3.org/pub/WWW/People.html) */ public function getLocation() { return $this->headers->get('Location', null, Collection::MATCH_IGNORE_CASE); } /** * Get the Pragma HTTP header * * @return string|null Returns the implementation-specific headers that may * have various effects anywhere along the request-response chain. */ public function getPragma() { return $this->headers->get('Pragma', null, Collection::MATCH_IGNORE_CASE); } /** * Get the Proxy-Authenticate HTTP header * * @return string|null Authentication to access the proxy (e.g. Basic) */ public function getProxyAuthenticate() { return $this->headers->get('/^Proxy-*Authenticate$/i', null, Collection::MATCH_REGEX); } /** * Get the Retry-After HTTP header * * @return integer|null If an entity is temporarily unavailable, this * instructs the client to try again after a specified period of time. */ public function getRetryAfter() { return $this->headers->get('/^Retry-*After$/i', null, Collection::MATCH_REGEX); } /** * Get the Server HTTP header * * @return string|null A name for the server */ public function getServer() { return $this->headers->get('Server', null, Collection::MATCH_IGNORE_CASE); } /** * Get the Set-Cookie HTTP header * * @return string|null An HTTP cookie. */ public function getSetCookie() { return $this->headers->get('/^Set-*Cookie2*$/i', null, Collection::MATCH_REGEX); } /** * Get the Trailer HTTP header * * @return string|null The Trailer general field value indicates that the * given set of header fields is present in the trailer of a message * encoded with chunked transfer-coding. */ public function getTrailer() { return $this->headers->get('Trailer', null, Collection::MATCH_IGNORE_CASE); } /** * 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 */ public function getTransferEncoding() { return $this->headers->get('/^Transfer\-*Encoding$/i', null, Collection::MATCH_REGEX); } /** * Get the Vary HTTP header * * @return string|null Tells downstream proxies how to match future request * headers to decide whether the cached response can be used rather * than requesting a fresh one from the origin server. */ public function getVary() { return $this->headers->get('Vary', null, Collection::MATCH_IGNORE_CASE); } /** * 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->headers->get('Via', null, Collection::MATCH_IGNORE_CASE); } /** * Get the Warning HTTP header * * @return string|null A general warning about possible problems with the * entity body. (e.g. 199 Miscellaneous warning) */ public function getWarning() { return $this->headers->get('Warning', null, Collection::MATCH_IGNORE_CASE); } /** * 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->headers->get('/^WWW-*Authenticate$/i', null, Collection::MATCH_REGEX); } /** * Checks if HTTP Status code is a Client Error (4xx) * * @return bool */ public function isClientError() { return substr(strval($this->statusCode), 0, 1) == '4'; } /** * Checks if HTTP Status code is Server OR Client Error (4xx or 5xx) * * @return boolean */ public function isError() { return $this->isClientError() || $this->isServerError(); } /** * Checks if HTTP Status code is Information (1xx) * * @return bool */ public function isInformational() { return substr(strval($this->statusCode), 0, 1) == '1'; } /** * Checks if HTTP Status code is a Redirect (3xx) * * @return bool */ public function isRedirect() { return substr(strval($this->statusCode), 0, 1) == '3'; } /** * Checks if HTTP Status code is Server Error (5xx) * * @return bool */ public function isServerError() { return substr(strval($this->statusCode), 0, 1) == '5'; } /** * Checks if HTTP Status code is Successful (2xx | 304) * * @return bool */ public function isSuccessful() { return substr(strval($this->statusCode), 0, 1) == '2' || $this->statusCode == '304'; } /** * Set the request object associated with the response * * @param RequestInterface 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 * * @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)) { return false; } // Make sure a valid body was returned and can be cached if ((!$this->getBody()->isReadable() || !$this->getBody()->isSeekable()) && ($this->getContentLength() > 0 || $this->getTransferEncoding() == 'chunked')) { return false; } // Never cache no-store resources (this is a private cache, so private // can be cached) if ($this->hasCacheControlDirective('no-store')) { return false; } // HTTPS responses must send a Cache-Control: public value for caching if ($this->getRequest() && $this->getRequest()->getScheme() == 'https' && !$this->hasCacheControlDirective('public')) { return false; } return $this->isFresh() || $this->getFreshness() === null || $this->canValidate(); } /** * Gets the number of seconds from the current time in which this response * is still considered fresh as specified in RFC 2616-13 * * @return int|null Returns the number of seconds */ 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 ($this->getHeader('Expires')) { return strtotime($this->getExpires()) - time(); } return null; } /** * 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. * * @return bool|null */ public function isFresh() { $fresh = $this->getFreshness(); return $fresh === null ? null : $this->getFreshness() > 0; } /** * Check if the response can be validated against the origin server using * a conditional GET request. * * @return bool */ public function canValidate() { return $this->getEtag() || $this->getLastModified(); } /** * Get the freshness of the response by returning the difference of the * maximum lifetime of the response and the age of the response * (max-age - age). * * Freshness values less than 0 mean that the response is no longer fresh * and is ABS(freshness) seconds expired. Freshness values of greater than * zer0 is the number of seconds until the response is no longer fresh. * A NULL result means that no freshness information is available. * * @return int */ public function getFreshness() { $maxAge = $this->getMaxAge(); $age = $this->getAge(); return $maxAge && $age ? ($maxAge - $age) : null; } }src/Guzzle/Http/Plugin/BasicAuthPlugin.php000064400000001705151742730640014537 0ustar00username = $username; $this->password = $password; } /** * {@inheritdoc} */ public static function getSubscribedEvents() { return array('client.create_request' => array('onRequestCreate', 255)); } /** * Add basic auth * * @param Event $event */ public function onRequestCreate(Event $event) { $event['request']->setAuth($this->username, $this->password); } }src/Guzzle/Http/Plugin/BatchQueuePlugin.php000064400000005646151742730640014732 0ustar000 to automatically flush * the queue when the number of requests is > $autoFlushCount */ public function __construct($autoFlushCount = 0) { $this->autoFlushCount = $autoFlushCount; } /** * {@inheritdoc} */ public static function getSubscribedEvents() { return array( 'client.create_request' => array('onRequestCreate', -255), 'request.before_send' => array('onRequestBeforeSend', 255), 'flush' => array('flush', -255) ); } /** * Get a count of the requests in queue * * @return int */ public function count() { return count($this->queue); } /** * Remove a request from the queue * * @param RequestInterface $request Request to remove * * @return BatchQueuePlugin */ public function removeRequest(RequestInterface $request) { $this->queue = array_filter($this->queue, function($r) use ($request) { return $r !== $request; }); return $this; } /** * Add request to the queue * * @param Event $event */ public function onRequestCreate(Event $event) { $this->queue[] = $event['request']; if ($this->autoFlushCount && count($this->queue) >= $this->autoFlushCount) { $this->flush(); } } /** * Ensures that queued requests that get sent outside of the context * of the batch plugin get removed from the queue * * @param Event $event */ public function onRequestBeforeSend(Event $event) { $this->removeRequest($event['request']); } /** * Flush the queue * * @param Event $event */ public function flush() { $multis = array(); // Prepare each request for their respective curl multi objects while ($request = array_shift($this->queue)) { $multi = $request->getClient()->getCurlMulti(); $multi->add($request, true); if (!in_array($multi, $multis)) { $multis[] = $multi; } } foreach ($multis as $multi) { $multi->send(); } } }src/Guzzle/Http/Plugin/CachePlugin.php000064400000033730151742730640013702 0ustar00adapter = $adapter; $this->serialize = (bool) $serialize; $this->defaultLifetime = (int) $defaultLifetime; } /** * {@inheritdoc} */ public static function getSubscribedEvents() { return array( 'request.before_send' => array('onRequestBeforeSend', -255), 'request.sent' => array('onRequestSent', 255) ); } /** * Get the cache adapter object * * @return CacheAdapter */ public function getCacheAdapter() { return $this->adapter; } /** * Calculate the hash key of a request object * * @param RequestInterface $request Request to hash * @param string $raw Set to TRUE to retrieve the un-encoded string for debugging * * @return string */ public function getCacheKey(RequestInterface $request, $raw = false) { // See if the key has already been calculated $key = $request->getParams()->get('cache.key'); // Always recalculate when using the raw option if (!$key || $raw) { // Generate the start of the key $key = $request->getScheme() . '_' . $request->getHost() . $request->getPath(); $filterHeaders = array('Cache-Control'); $filterQuery = array(); // Check to see how and if the key should be filtered foreach (explode(';', $request->getParams()->get('cache.key_filter')) as $part) { $pieces = array_map('trim', explode('=', $part)); if (isset($pieces[1])) { $remove = array_map('trim', explode(',', $pieces[1])); if ($pieces[0] == 'header') { $filterHeaders = array_merge($filterHeaders, $remove); } else if ($pieces[0] == 'query') { $filterQuery = array_merge($filterQuery, $remove); } } } // Use the filtered query string $queryString = (string) $request->getQuery()->filter(function($key, $value) use ($filterQuery) { return !in_array($key, $filterQuery); }); // Use the filtered headers $headerString = http_build_query($request->getHeaders()->filter(function($key, $value) use ($filterHeaders) { return !in_array($key, $filterHeaders); })->getAll()); if ($raw) { $key = strtolower('gz_' . $key . $queryString . '_' . $headerString); } else { $key = strtolower('gz_' . md5($key . $queryString . '_' . $headerString)); $request->getParams()->set('cache.key', $key); } } return $key; } /** * Check if a response in cache will satisfy the request before sending * * @param Event $event */ public function onRequestBeforeSend(Event $event) { $request = $event['request']; // This request is being prepared $key = spl_object_hash($request); $hashKey = $this->getCacheKey($request); $this->cached[$key] = $hashKey; $cachedData = $this->getCacheAdapter()->fetch($hashKey); // If the cached data was found, then make the request into a // manually set request if ($cachedData) { if ($this->serialize) { $cachedData = unserialize($cachedData); } unset($this->cached[$key]); $response = new Response($cachedData['c'], $cachedData['h'], $cachedData['b']); $response->setHeader('Age', time() - strtotime($response->getDate() ?: 'now')); $response->setHeader('X-Guzzle-Cache', $hashKey); // Validate that the response satisfies the request if ($this->canResponseSatisfyRequest($request, $response)) { $request->setResponse($response); } } } /** * If possible, store a response in cache after sending * * @param Event $event */ public function onRequestSent(Event $event) { $request = $event['request']; $response = $event['response']; if ($response->canCache()) { // The request is complete and now processing the response $key = spl_object_hash($request); if (isset($this->cached[$key])) { if ($response->isSuccessful()) { if ($request->getParams()->get('cache.override_ttl')) { $lifetime = $request->getParams()->get('cache.override_ttl'); $response->setHeader('X-Guzzle-Ttl', $lifetime); } else { $lifetime = $response->getMaxAge(); } $this->saveCache($this->cached[$key], $response, $lifetime); } // Remove the hashed placeholder from the parameters object unset($this->cached[$key]); } } } /** * Revalidate a cached response * * @param RequestInterface $request Request to revalidate * @param Response $response Response to revalidate * * @return bool */ public function revalidate(RequestInterface $request, Response $response) { $revalidate = clone $request; $revalidate->getEventDispatcher()->removeSubscriber($this); $revalidate->removeHeader('Pragma') ->removeHeader('Cache-Control') ->setHeader('If-Modified-Since', $response->getDate()); if ($response->getEtag()) { $revalidate->setHeader('If-None-Match', '"' . $response->getEtag() . '"'); } try { $validateResponse = $revalidate->send(); if ($validateResponse->getStatusCode() == 200) { // The server does not support validation, so use this response $request->setResponse($validateResponse); // Store this response in cache if possible if ($validateResponse->canCache()) { $this->saveCache($this->getCacheKey($request), $validateResponse, $validateResponse->getMaxAge()); } return false; } if ($validateResponse->getStatusCode() == 304) { // Make sure that this response has the same ETage if ($validateResponse->getEtag() != $response->getEtag()) { return false; } // Replace cached headers with any of these headers from the // origin server that might be more up to date $modified = false; foreach (array('Date', 'Expires', 'Cache-Control', 'ETag', 'Last-Modified') as $name) { if ($validateResponse->hasHeader($name)) { $modified = true; $response->setHeader($name, $validateResponse->getHeader($name)); } } // Store the updated response in cache if ($modified && $response->canCache()) { $this->saveCache($this->getCacheKey($request), $response, $response->getMaxAge()); } return true; } } catch (BadResponseException $e) { // 404 errors mean the resource no longer exists, so remove from // cache, and prevent an additional request by throwing the exception if ($e->getResponse()->getStatusCode() == 404) { $this->getCacheAdapter()->delete($this->getCacheKey($request)); throw $e; } } // Other exceptions encountered in the revalidation request are ignored // in hopes that sending a request to the origin server will fix it return false; } /** * Check if a cache response satisfies a request's caching constraints * * @param RequestInterface $request Request to validate * @param Response $response Response to validate * * @return bool */ public function canResponseSatisfyRequest(RequestInterface $request, Response $response) { $maxAge = null; $responseAge = $response->getAge(); // Check the request's max-age header against the age of the response if ($request->hasCacheControlDirective('max-age') && $responseAge > $request->getCacheControlDirective('max-age')) { return false; } // Check the response's max-age header if ($response->isFresh() === false) { $maxStale = $request->getCacheControlDirective('max-stale'); if (null !== $maxStale) { if ($maxStale !== true && $response->getFreshness() < (-1 * $maxStale)) { return false; } } else if ($responseAge > $response->getCacheControlDirective('max-age')) { return false; } } // Only revalidate GET requests if ($request->getMethod() == RequestInterface::GET) { // Check if the response must be validated against the origin server if ($request->getHeader('Pragma') == 'no-cache' || $request->hasCacheControlDirective('no-cache') || $request->hasCacheControlDirective('must-revalidate') || $response->hasCacheControlDirective('must-revalidate') || $response->hasCacheControlDirective('no-cache')) { // no-cache: When no parameters are present, always revalidate // When parameters are present in no-cache and the request includes // those same parameters, then the response must re-validate // I'll need an example of what fields look like in order to // implement a smarter version of no-cache // Requests can decline to revalidate against the origin server // by setting the cache.revalidate param to one of: // never - To never revalidate and always contact the origin server // skip - To skip revalidation and just use what is in cache switch ($request->getParams()->get('cache.revalidate')) { case 'never': return false; case 'skip': return true; } return $this->revalidate($request, $response); } } return true; } /** * Save data to the cache adapter * * @param string $key The cache key * @param Response $response The response to cache * @param int $lifetime (optional) Amount of seconds to cache * * @return int Returns the lifetime of the cached data */ protected function saveCache($key, Response $response, $lifetime = null) { $lifetime = $lifetime ?: $this->defaultLifetime; // If the data is cacheable, then save it to the cache adapter if ($lifetime) { // Remove excluded headers from the response (see RFC 2616:13.5.1) foreach ($this->excludeResponseHeaders as $header) { $response->removeHeader($header); } // Add a Date header to the response if none is set (for validation) if (!$response->getDate()) { $response->setHeader('Date', Guzzle::getHttpDate('now')); } $data = array( 'c' => $response->getStatusCode(), 'h' => $response->getHeaders(), 'b' => $response->getBody(true) ); if ($this->serialize) { $data = serialize($data); } $this->getCacheAdapter()->save($key, $data, $lifetime); } return $lifetime; } }src/Guzzle/Http/Plugin/CookiePlugin.php000064400000026623151742730640014113 0ustar00jar = $storage; } /** * Clears temporary cookies */ public function __destruct() { $this->clearTemporaryCookies(); } /** * {@inheritdoc} */ public static function getSubscribedEvents() { return array( 'request.before_send' => array('onRequestBeforeSend', 100), 'request.sent' => array('onRequestSent', 100), 'request.receive.status_line' => 'onRequestReceiveStatusLine' ); } /** * Parse a cookie string as set in a Set-Cookie HTTP header and return data * about the cookie * * @param string $cookie Cookie header value to parse * @param RequestInterface $request (optional) Used to get path and domain * when not using Cookie-2 * @param bool $decode (optional) Set to FALSE to not urldecode the values * * @return array|bool Returns FALSE on failure or returns an array of * arrays, with each of the sub arrays including: * domain (string) - Domain of the cookie * path (string) - Path of the cookie * cookies (array) - Associative array of cookie names and values * max_age (int) - Lifetime of the cookie in seconds * version (int) - Version of the cookie specification. RFC 2965 is 1 * secure (bool) - Whether or not this is a secure cookie * discard (bool) - Whether or not this is a discardable cookie * custom (string) - Custom cookie data array * comment (string) - How the cookie is intended to be used * comment_url (str)- URL that contains info on how it will be used * port (array|str) - Array of ports or null * http_only (bool) - HTTP only cookie */ public static function parseCookie($cookie, RequestInterface $request = null, $decode = true) { if (!$cookie) { return false; } // Explode the cookie string using a series of semicolons $pieces = array_filter(array_map('trim', explode(';', $cookie))); // The name of the cookie (first kvp) must include an equal sign. if (!strpos($pieces[0], '=')) { return false; } // Map cookie values into snake_case values and use these regexp's to find data $parts = array( 'domain' => '/^Domain$/i', 'path' => '/^Path$/i', 'max_age' => '/^Max(\-|_)Age$/i', 'expires' => '/^Expires$/i', 'version' => '/^Version$/i', 'secure' => '/^Secure$/i', 'port' => '/^Port$/i', 'discard' => '/^Discard$/i', 'comment' => '/^Comment$/i', 'comment_url' => '/^Comment(\-|_)Url$/i', 'http_only' => '/^HttpOnly$/i' ); // Create the default return array $data = array_fill_keys(array_keys($parts), null); $data['cookies'] = array(); $data['data'] = array(); $data['path'] = '/'; $data['http_only'] = false; // Add the default domain and path using the request reference // These values are overridden if using Set-Cookie2 cookie values. if ($request) { $data['domain'] = $request->getHost(); $data['path'] = $request->getPath(); } $foundCookies = $foundNonCookies = 0; // Add the cookie pieces into the parsed data array foreach ($pieces as $part) { $avPair = array_map('trim', explode('=', $part, 2)); $key = $avPair[0]; if (count($avPair) === 1) { // Matches secure, httpOnly, etc... $value = true; } else { $value = isset($avPair[1]) ? $avPair[1] : ''; // Remove wrapping quotes if (strpos($value, '"') === 0) { $value = substr($value, 1); } if (substr($value, -1, 1) == '"') { $value = substr($value, 0, -1); } } // Check if the key is in the cookie pieces $found = false; $needle = strtolower($key); if ($foundCookies) { foreach ($parts as $mapValue => $regex) { if (preg_match($regex, $needle)) { $key = $needle = $mapValue; $found = true; break; } } } // Decode the value if $decode is TRUE $value = ($decode && $value && !is_bool($value)) ? urldecode($value) : $value; if (0 == $foundCookies || !$found) { // If cookies have not yet been retrieved, or this value was // not found in the cookie pieces array, treat as a cookie // IF non-cookies have been parsed, then this isn't a cookie, // but it's cookie data. Cookies must be first, followed by data. if ($foundNonCookies == 0) { $data['cookies'][] = $key . ($value ? ('=' . $value) : ''); $foundCookies++; } else { $data['data'][$key] = $value; } } else { if ($key == 'port') { $value = array_map('trim', explode(',', $value)); } $data[$key] = $value; $foundNonCookies++; } } // Calculate the expires date if (!$data['expires'] && $data['max_age']) { $data['expires'] = time() + (int)$data['max_age']; } return $data; } /** * Add cookies to a request based on the destination of the request and * the cookies stored in the storage backend. Any previously set cookies * will be removed. * * @param RequestInterface $request Request to add cookies to. If the * request object already has a cookie header, then no further cookies * will be added. * * @return array Returns an array of the cookies that were added */ public function addCookies(RequestInterface $request) { $request->removeHeader('Cookie'); // Find cookies that match this request $cookies = $this->jar->getCookies($request->getHost(), $request->getPath()); $match = false; if ($cookies) { foreach ($cookies as $cookie) { $match = true; // If a port restriction is set, validate the port if (!empty($cookie['port'])) { if (!in_array($request->getPort(), $cookie['port'])) { $match = false; } } // Validate the secure flag if ($cookie['secure']) { if ($request->getScheme() != 'https') { $match = false; } } // If this request is eligible for the cookie, then merge it in if ($match) { $request->addCookie($cookie['cookie'][0], isset($cookie['cookie'][1]) ? $cookie['cookie'][1] : null); } } } return $match && $cookies ? $cookies : array(); } /** * Extracts cookies from an HTTP Response object, looking for Set-Cookie: * and Set-Cookie2: headers and persists them to the cookie storage. * * @param Response $response */ public function extractCookies(Response $response) { if (!$cookie = $response->getSetCookie()) { return array(); } $cookieData = array(); foreach ((array) $cookie as $c) { $cdata = self::parseCookie($c, $response->getRequest()); //@codeCoverageIgnoreStart if (!$cdata) { continue; } //@codeCoverageIgnoreEnd $cookies = array(); // Break up cookie v2 into multiple cookies if (count($cdata['cookies']) == 1) { $cdata['cookie'] = explode('=', $cdata['cookies'][0], 2); unset($cdata['cookies']); $cookies = array($cdata); } else { foreach ($cdata['cookies'] as $cookie) { $row = $cdata; unset($row['cookies']); $row['cookie'] = explode('=', $cookie, 2); $cookies[] = $row; } } if (count($cookies)) { foreach ($cookies as &$c) { $this->jar->save($c); $cookieData[] = $c; } } } return $cookieData; } /** * Clear cookies currently held in the Cookie storage. * * Invoking this method without arguments will empty the whole Cookie * storage. If given a $domain argument only cookies belonging to that * domain will be removed. If given a $domain and $path argument, cookies * belonging to the specified path within that domain are removed. If given * all three arguments, then the cookie with the specified name, path and * domain is removed. * * @param string $domain (optional) Set to clear only cookies matching a domain * @param string $path (optional) Set to clear only cookies matching a domain and path * @param string $name (optional) Set to clear only cookies matching a domain, path, and name * * @return int Returns the number of deleted cookies */ public function clearCookies($domain = null, $path = null, $name = null) { return $this->jar->clear(str_replace(array('http://', 'https://'), '', $domain), $path, $name); } /** * Discard all temporary cookies. * * Scans for all cookies in the storage with either no expire field or a * true discard flag. To be called when the user agent shuts down according * to RFC 2965. * * @return int Returns the number of deleted cookies */ public function clearTemporaryCookies() { return $this->jar->clearTemporary(); } /** * Add cookies before a request is sent * * @param Event $event */ public function onRequestBeforeSend(Event $event) { $this->addCookies($event['request']); } /** * Extract cookies from a sent request * * @param Event $event */ public function onRequestSent(Event $event) { $this->extractCookies($event['response']); } /** * Extract cookies from a redirect response * * @param Event $event */ public function onRequestReceiveStatusLine(Event $event) { if ($event['previous_response']) { $this->extractCookies($event['previous_response']); } } }src/Guzzle/Http/Plugin/ExponentialBackoffPlugin.php000064400000011646151742730640016443 0ustar00setMaxRetries($maxRetries); $this->failureCodes = $failureCodes ?: array(500, 503); $this->delayClosure = $delayClosure ?: array($this, 'calculateWait'); $this->state = new Collection(); } /** * {@inheritdoc} */ public static function getSubscribedEvents() { return array( 'request.sent' => 'onRequestSent', CurlMultiInterface::POLLING_REQUEST => 'onRequestPoll' ); } /** * Set the maximum number of retries the plugin should use before failing * the request * * @param integer $maxRetries The maximum number of retries. * * @return ExponentialBackoffPlugin */ public function setMaxRetries($maxRetries) { $this->maxRetries = max(0, (int) $maxRetries); return $this; } /** * Get the maximum number of retries the plugin will attempt * * @return integer */ public function getMaxRetries() { return $this->maxRetries; } /** * Get the HTTP response codes that should be retried using truncated * exponential backoff * * @return array */ public function getFailureCodes() { return $this->failureCodes; } /** * Set the HTTP response codes that should be retried using truncated * exponential backoff * * @param array $codes Array of HTTP response codes * * @return ExponentialBackoffPlugin */ public function setFailureCodes(array $codes) { $this->failureCodes = $codes; return $this; } /** * Determine how long to wait using truncated exponential backoff * * @param int $retries Number of retries so far * * @return int */ public function calculateWait($retries) { return (int) pow(2, $retries); } /** * Called when a request has been sent * * @param Event $event */ public function onRequestSent(Event $event) { $request = $event['request']; // Called when the request has been sent and isn't finished processing $key = spl_object_hash($request); if (in_array($request->getResponse()->getStatusCode(), $this->failureCodes)) { // If this request has been retried too many times, then throw an exception $this->state[$key] = $this->state[$key] + 1; if ($this->state[$key] <= $this->maxRetries) { // Calculate how long to wait until the request should be retried $delay = (int) call_user_func($this->delayClosure, $this->state[$key]); // Send the request again $request->setState(RequestInterface::STATE_TRANSFER); $request->getParams()->set(self::DELAY_PARAM, time() + $delay); } } } /** * Called when a request is polling in the curl mutli object * * @param Event $event */ public function onRequestPoll(Event $event) { $request = $event['request']; $delay = $request->getParams()->get(self::DELAY_PARAM); // If the duration of the delay has passed, retry the request using the pool if ($delay && time() >= $delay) { // Remove the request from the pool and then add it back again $multi = $event['curl_multi']; $multi->remove($request); $multi->add($request, true); $request->getParams()->remove(self::DELAY_PARAM); } } }src/Guzzle/Http/Plugin/HistoryPlugin.php000064400000005153151742730640014336 0ustar00 'onRequestComplete'); } /** * Add a request to the history * * @param RequestInterface $request Request to add * * @return HistoryPlugin */ public function add(RequestInterface $request) { if ($request->getResponse()) { $this->requests[] = $request; if (count($this->requests) > $this->getlimit()) { array_shift($this->requests); } } return $this; } /** * Set the max number of requests to store * * @param int $limit Limit * * @return HistoryPlugin */ public function setLimit($limit) { $this->limit = (int) $limit; return $this; } /** * Get the request limit * * @return int */ public function getLimit() { return $this->limit; } /** * Get the requests in the history * * @return ArrayIterator */ public function getIterator() { return new \ArrayIterator($this->requests); } /** * Get the number of requests in the history * * @return int */ public function count() { return count($this->requests); } /** * Get the last request sent * * @return RequestInterface */ public function getLastRequest() { return end($this->requests); } /** * Get the last response in the history * * @return Response */ public function getLastResponse() { return $this->getLastRequest()->getResponse(); } /** * Clears the history * * @return HistoryPlugin */ public function clear() { $this->requests = array(); return $this; } /** * {@inheritdoc} */ public function onRequestComplete(Event $event) { $this->add($event['request']); } }src/Guzzle/Http/Plugin/LogPlugin.php000064400000021331151742730640013412 0ustar00logAdapter = $logAdapter; $this->hostname = gethostname(); $this->setSettings($settings); } /** * {@inheritdoc} */ public static function getSubscribedEvents() { return array( 'curl.callback.write' => array('onCurlWrite', 255), 'curl.callback.read' => array('onCurlRead', 255), 'request.before_send' => array('onRequestBeforeSend', 255), 'request.complete' => array('onRequestComplete', 255) ); } /** * Change the log settings of the plugin * * @param int $settings (optional) Bitwise settings to control what's logged * * @return LogPlugin */ public function setSettings($settings) { $this->settings = $settings; return $this; } /** * Get the log adapter object * * @return LogAdapterInterface */ public function getLogAdapter() { return $this->logAdapter; } /** * Event triggered when curl data is read from a request * * @param Event $event */ public function onCurlRead(Event $event) { // Stream the request body to the log if the body is not repeatable $request = $event['request']; if ($request->getParams()->get('request_wire')) { $request->getParams()->get('request_wire')->write($event['read']); } } /** * Event triggered when curl data is written to a response * * @param Event $event */ public function onCurlWrite(Event $event) { // Stream the response body to the log if the body is not repeatable $request = $event['request']; if ($request->getParams()->get('response_wire')) { $request->getParams()->get('response_wire')->write($event['write']); } } /** * Called before a request is sent * * @param Event $event */ public function onRequestBeforeSend(Event $event) { $request = $event['request']; // We need to make special handling for content wiring and // non-repeatable streams. if ($this->settings & self::LOG_BODY) { if ($request instanceof EntityEnclosingRequestInterface) { if ($request->getBody() && (!$request->getBody()->isSeekable() || !$request->getBody()->isReadable())) { // The body of the request cannot be recalled so // logging the content of the request will need to // be streamed using updates $request->getParams()->set('request_wire', EntityBody::factory()); } } if (!$request->isResponseBodyRepeatable()) { // The body of the response cannot be recalled so // logging the content of the response will need to // be streamed using updates $request->getParams()->set('response_wire', EntityBody::factory()); } } } /** * Triggers the actual log write when a request completes * * @param Event $event */ public function onRequestComplete(Event $event) { $this->log($event['request'], $event['response']); } /** * Log a message based on a request and response * * @param RequestInterface $request Request to log * @param Response $response (optional) Response to log */ private function log(RequestInterface $request, Response $response = null) { $priority = $response && !$response->isSuccessful() ? LOG_ERR : LOG_DEBUG; $message = ''; if ($this->settings & self::LOG_CONTEXT) { // Log common contextual information $message = $request->getHost() . ' - "' . $request->getMethod() . ' ' . $request->getResourceUri() . ' ' . strtoupper($request->getScheme()) . '/' . $request->getProtocolVersion() . '"'; // If a response is set, then log additional contextual information if ($response) { $message .= sprintf(' - %s %s - %s %s %s', $response->getStatusCode(), $response->getContentLength() ?: 0, $response->getInfo('total_time'), $response->getInfo('speed_upload'), $response->getInfo('speed_download') ); } } // Check if we are logging anything that will come from cURL if ($request->getParams()->get('curl_handle') && ($this->settings & self::LOG_DEBUG || $this->settings & self::LOG_HEADERS || $this->settings & self::LOG_BODY)) { // If context logging too, then add a new line for cleaner messages if ($this->settings & self::LOG_CONTEXT) { $message .= "\n"; } // Filter cURL's verbose output based on config settings $handle = $request->getParams()->get('curl_handle'); if ($handle instanceof CurlHandle) { $stderr = $handle->getStderr(true); rewind($stderr); $addedBody = false; while ($line = fgets($stderr)) { $first = $line[0]; // * - Debug | < - Downstream | > - Upstream if ($line[0] == '*' && $this->settings & self::LOG_DEBUG) { $message .= $line; } else if ($this->settings & self::LOG_HEADERS) { $message .= $line; } // Add the request body if needed if ($this->settings & self::LOG_BODY) { if (trim($line) == '' && !$addedBody && $request instanceof EntityEnclosingRequestInterface) { $message .= $request->getParams()->get('request_wire') ? (string) $request->getParams()->get('request_wire') . "\r\n" : (string) $request->getBody() . "\r\n"; $addedBody = true; } } } } // Log the response body if the response is available if ($this->settings & self::LOG_BODY && $response) { $message .= $request->getParams()->get('response_wire') ? (string) $request->getParams()->get('response_wire') : $response->getBody(true); } } // Send the log message to the adapter, adding a category and host $this->logAdapter->log(trim($message), $priority, array( 'category' => 'guzzle.request', 'host' => $this->hostname )); } }src/Guzzle/Http/Plugin/Md5ValidatorPlugin.php000064400000006576151742730640015202 0ustar00contentLengthCutoff = $contentLengthCutoff; $this->contentEncoded = $contentEncoded; } /** * {@inheritdoc} */ public static function getSubscribedEvents() { return array('request.complete' => array('onRequestComplete', 255)); } /** * {@inheritdoc} * @throws UnexpectedValueException */ public function onRequestComplete(Event $event) { $response = $event['response']; $contentMd5 = $response->getContentMd5(); if (!$contentMd5) { return; } $contentEncoding = $response->getContentEncoding(); if ($contentEncoding && !$this->contentEncoded) { return false; } // Make sure that the request's size is under the cutoff size $size = $response->getContentLength() ?: $response->getBody()->getSize(); if (!$size || $size > $this->contentLengthCutoff) { return; } if (!$contentEncoding) { $hash = $response->getBody()->getContentMd5(); } else if ($contentEncoding == 'gzip') { $response->getBody()->compress('zlib.deflate'); $hash = $response->getBody()->getContentMd5(); $response->getBody()->uncompress(); } else if ($contentEncoding == 'compress') { $response->getBody()->compress('bzip2.compress'); $hash = $response->getBody()->getContentMd5(); $response->getBody()->uncompress(); } else { return; } if ($contentMd5 !== $hash) { throw new \UnexpectedValueException(sprintf( 'The response entity body may have been ' . 'modified over the wire. The Content-MD5 ' . 'received (%s) did not match the calculated ' . 'MD5 hash (%s).', $contentMd5, $hash )); } } }src/Guzzle/Http/Plugin/MockPlugin.php000064400000010525151742730640013565 0ustar00temporary = $temporary; if ($responses) { foreach ($responses as $response) { $this->addResponse($response); } } } /** * {@inheritdoc} */ public static function getSubscribedEvents() { return array('client.create_request' => 'onRequestCreate'); } /** * {@inheritdoc} */ public static function getAllEvents() { return array('mock.request'); } /** * Get a mock response from a file * * @param string $file File to retreive a mock response from * * @return Response * @throws InvalidArgumentException if the file is not found */ public static function getMockFile($path) { if (!file_exists($path)) { throw new \InvalidArgumentException('Unable to open mock file: ' . $path); } $parts = explode("\n\n", file_get_contents($path), 2); // Convert \n to \r\n in headers $data = isset($parts[1]) ? str_replace("\n", "\r\n", $parts[0]) . "\r\n\r\n" . $parts[1] : $parts[0]; return Response::factory($data); } /** * Returns the number of remaining mock responses * * @return int */ public function count() { return count($this->queue); } /** * Add a response to the end of the queue * * @param string|Response $response Response object or path to response file * * @return MockPlugin * @throws InvalidArgumentException if a string or Response is not passed */ public function addResponse($response) { if (!($response instanceof Response)) { if (!is_string($response)) { throw new \InvalidArgumentException('Invalid response'); } $response = self::getMockFile($response); } $this->queue[] = $response; return $this; } /** * Clear the queue * * @return MockPlugin */ public function clearQueue() { $this->queue = array(); return $this; } /** * Returns an array of mock responses remaining in the queue * * @return array */ public function getQueue() { return $this->queue; } /** * Check if this is a temporary plugin * * @return bool */ public function isTemporary() { return $this->temporary; } /** * Get a response from the front of the list and add it to a request * * @param RequestInterface $request Request to mock * * @return MockPlugin */ public function dequeue(RequestInterface $request) { $this->dispatch('mock.request', array( 'plugin' => $this, 'request' => $request )); $request->setResponse(array_shift($this->queue), true); return $this; } /** * Called when a request completes * * @param Event $event */ public function onRequestCreate(Event $event) { if (!empty($this->queue)) { $request = $event['request']; $this->dequeue($request); // Detach the filter from the client so it's a one-time use if ($this->temporary && empty($this->queue) && $request->getClient()) { $request->getClient()->getEventDispatcher()->removeSubscriber($this); } } } }src/Guzzle/Http/Plugin/OauthPlugin.php000064400000012543151742730640013756 0ustar00config = Inspector::prepareConfig($config, array( 'version' => '1.0', 'consumer_key' => 'anonymous', 'consumer_secret' => 'anonymous', 'signature_method' => 'HMAC-SHA1', 'signature_callback' => function($stringToSign, $key) { return hash_hmac('sha1', $stringToSign, $key, true); } ), array( 'signature_method', 'signature_callback', 'version', 'consumer_key', 'consumer_secret', 'token', 'token_secret' )); } /** * {@inheritdoc} */ public static function getSubscribedEvents() { return array( 'request.before_send' => array('onRequestBeforeSend', -1000) ); } /** * Request before-send event handler * * @param Event $event Event received */ public function onRequestBeforeSend(Event $event) { $timestamp = $event['timestamp'] ?: time(); // Build Authorization header $authString = 'OAuth '; foreach(array( 'oauth_consumer_key' => $this->config['consumer_key'], 'oauth_nonce' => sha1($timestamp), 'oauth_signature' => $this->getSignature($event['request'], $timestamp), 'oauth_signature_method' => $this->config['signature_method'], 'oauth_timestamp' => $timestamp, 'oauth_token' => $this->config['token'], 'oauth_version' => $this->config['version'], ) as $key => $val) { $authString .= $key . '="' . urlencode($val) . '", '; } // Add Authorization header $event['request']->setHeader('Authorization', substr($authString, 0, -2)); } /** * Calculate signature for request * * @param RequestInterface $request Request to generate a signature for * @param int $timestamp Timestamp to use for nonce * * @return string */ public function getSignature(RequestInterface $request, $timestamp) { $string = $this->getStringToSign($request, $timestamp); $key = urlencode($this->config['consumer_secret']) . '&' . urlencode($this->config['token_secret']); return base64_encode(call_user_func($this->config['signature_callback'], $string, $key)); } /** * Calculate string to sign * * @param RequestInterface $request Request to generate a signature for * @param int $timestamp Timestamp to use for nonce * * @return string */ public function getStringToSign(RequestInterface $request, $timestamp) { $params = new Collection(array( 'oauth_consumer_key' => $this->config['consumer_key'], 'oauth_nonce' => sha1($timestamp), 'oauth_signature_method' => $this->config['signature_method'], 'oauth_timestamp' => $timestamp, 'oauth_token' => $this->config['token'], 'oauth_version' => $this->config['version'] )); // Add query string parameters $params->merge($request->getQuery()); // Add POST fields to signing string if ($request instanceof EntityEnclosingRequestInterface && $request->getHeader('Content-Type') == 'application/x-www-form-urlencoded') { $params->merge($request->getPostFields()); } // Sort params $params = $params->getAll(); ksort($params); // Build signing string from combined params $parameterString = array(); foreach ($params as $key => $values) { $key = rawurlencode($key); $values = (array) $values; sort($values); foreach ($values as $value) { if (is_bool($value)) { $value = $value ? 'true' : 'false'; } $parameterString[] = $key . '=' . rawurlencode($value); } } $url = Url::factory($request->getUrl())->setQuery('')->setFragment(''); return strtoupper($request->getMethod()) . '&' . rawurlencode($url) . '&' . rawurlencode(implode('&', $parameterString)); } }src/Guzzle/Http/QueryString.php000064400000020331151742730640012547 0ustar00data)) { return ''; } $queryString = $this->prefix; $firstValue = true; foreach ($this->encodeData($this->data, $this->encodeFields, $this->encodeValues) as $name => $value) { $value = $value !== null ? (array) $value : array(false); foreach ($value as $v) { if (!$firstValue) { $queryString .= $this->fieldSeparator; } $queryString .= $name; if (is_string($v)) { $queryString .= $this->valueSeparator . $v; } $firstValue = false; } } return $queryString; } /** * Aggregate multi-valued parameters by joining the values using a comma * * * $queryString = new \Guzzle\Http\QueryString(); * $queryString->setAggregator($queryString->aggregateUsingComma); * $queryString->replace(array( * 'value' => array(1, 2, 3) * )); * * echo $queryString; // outputs: ?value=1,2,3 * * * @param string $key The name of the query string parameter * @param array $values The values of the parameter * @param bool $encodeFields (optional) Set to TRUE to encode field names * @param bool $encodeValues (optional) Set to TRUE to encode values * * @return array Returns an array of the combined values */ public function aggregateUsingComma($key, $value, $encodeFields = false, $encodeValues = false) { return array( (($encodeFields) ? rawurlencode($key) : $key) => (($encodeValues) ? implode(',', array_map('rawurlencode', $value)) : implode(',', $value)) ); } /** * Get the query string field separator * * @return string */ public function getFieldSeparator() { return $this->fieldSeparator; } /** * Get the query string prefix * * @return string */ public function getPrefix() { return $this->prefix; } /** * Get the query string value separator * * @return string */ public function getValueSeparator() { return $this->valueSeparator; } /** * Returns whether or not field names are being urlencoded when converting * the query string object to a string * * @return bool */ public function isEncodingFields() { return $this->encodeFields; } /** * Returns whether or not values are being urlencoded when converting * the query string object to a string * * @return bool */ public function isEncodingValues() { return $this->encodeValues; } /** * Provide a function for combining multi-valued query string parameters * into a single or multiple fields * * @param callback|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 * * @see \Guzzle\Http\QueryString::aggregateUsingComma() */ public function setAggregateFunction($callback) { $this->aggregator = $callback; } /** * Set whether or not field names should be urlencoded when converting * the query string object to a string * * @param bool $encode Set to TRUE to encode field names, FALSE to not * encode field names * * @return QueryString */ public function setEncodeFields($encode) { $this->encodeFields = $encode; return $this; } /** * Set whether or not field values should be urlencoded when converting * the query string object to a string * * @param bool $encode Set to TRUE to encode field values, FALSE to not * encode field values * * @return QueryString */ public function setEncodeValues($encode) { $this->encodeValues = $encode; return $this; } /** * Set the query string separator * * @param string $separator The query string separator that will separate * fields * * @return QueryString */ public function setFieldSeparator($separator) { $this->fieldSeparator = $separator; return $this; } /** * 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 */ public function setValueSeparator($separator) { $this->valueSeparator = $separator; return $this; } /** * Returns an array of url encoded field names and values * * @return array */ public function urlEncode() { return $this->encodeData($this->data, $this->encodeFields, $this->encodeValues); } /** * Url encode parameter data. * * 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 array $data The data to encode * @param bool $encodeFields (optional) Toggle URL encoding of fields * @param bool $encodeValues (optional) Toggle URL encoding of values * * @return array Returns an array of encoded values and keys */ protected function encodeData(array $data, $encodeFields = true, $encodeValues = true) { $temp = array(); foreach($data as $key => &$value) { if (is_array($value)) { $encoded = $this->encodeData($value, $encodeFields, $encodeValues); if ($this->aggregator !== null) { $temp = array_merge($temp, call_user_func_array($this->aggregator, array($key, $value, $encodeFields, $encodeValues))); } else { foreach ($encoded as $i => $v) { $i = (!is_numeric($i)) ? 0 : $i; if ($encodeFields) { $k = rawurlencode($key) . "[{$i}]"; } else { $k = "{$key}[{$i}]"; } $temp[$k] = $v; } } } else { if ($encodeValues && is_string($value) || is_numeric($value)) { $value = rawurlencode($value); } if ($encodeFields) { $temp[rawurlencode($key)] = $value; } else { $temp[$key] = $value; } } } return $temp; } }src/Guzzle/Http/Url.php000064400000027215151742730640011025 0ustar00scheme = $scheme; $this->host = $host; $this->port = $port; $this->username = $username; $this->password = $password; $this->fragment = $fragment; $this->setQuery($query ?: new QueryString()); if ($path) { $this->setPath($path); } } /** * Clone the URL */ public function __clone() { $this->query = clone $this->query; } /** * Returns the URL as a URL string * * @return string */ public function __toString() { return self::buildUrl($this->getParts()); } /** * Get the parts of the URL as an array * * @return array */ public function getParts() { return array( 'scheme' => $this->scheme, 'user' => $this->username, 'pass' => $this->password, 'host' => $this->host, 'port' => $this->port, 'path' => $this->getPath(), 'query' => (string) $this->query, 'fragment' => $this->fragment, 'query_prefix' => $this->query->getPrefix() ); } /** * Set the host of the request. * * @param string $host Host to set (e.g. www.yahoo.com, yahoo.com) * * @return Url */ public function setHost($host) { $this->host = $host; return $this; } /** * Get the host part of the URL * * @return string */ public function getHost() { return $this->host; } /** * Set the scheme part of the URL (http, https, ftp, etc) * * @param string $scheme Scheme to set * * @return Url */ public function setScheme($scheme) { $this->scheme = $scheme; return $this; } /** * Get the scheme part of the URL * * @return string */ public function getScheme() { return $this->scheme; } /** * Set the port part of the URL * * @param int $port Port to set * * @return Url */ public function setPort($port) { $this->port = $port; return $this; } /** * Get the port part of the URl. Will return the default port for a given * scheme if a port has not explicitly been set. * * @return int|null */ public function getPort() { if ($this->port) { return $this->port; } else if ($this->scheme == 'http') { return 80; } else if ($this->scheme == 'https') { return 443; } return null; } /** * Set the path part of the URL * * @param array|string $path Path string or array of path segments * * @return Url */ public function setPath($path) { if (is_array($path)) { $this->path = '/' . implode('/', $path); } else { $this->path = $path; if ($this->path != '*' && substr($this->path, 0, 1) != '/') { $this->path = '/' . $path; } } return $this; } /** * Add a relative path to the currently set path * * @param string $relativePath Relative path to add * * @return Url */ public function addPath($relativePath) { if (!$relativePath || $relativePath == '/') { return $this; } // Add a leading slash if needed if ($relativePath[0] != '/') { $relativePath = '/' . $relativePath; } return $this->setPath(str_replace('//', '/', $this->getPath() . $relativePath)); } /** * Get the path part of the URL * * @return string */ public function getPath() { return $this->path ?: '/'; } /** * Get the path segments of the URL as an array * * @return array */ public function getPathSegments() { return array_slice(explode('/', $this->path), 1); } /** * Set the password part of the URL * * @param string $password Password to set * * @return Url */ public function setPassword($password) { $this->password = $password; return $this; } /** * Get the password part of the URL * * @return null|string */ public function getPassword() { return $this->password; } /** * Set the username part of the URL * * @param string $username Username to set * * @return Url */ public function setUsername($username) { $this->username = $username; return $this; } /** * Get the username part of the URl * * @return null|string */ public function getUsername() { return $this->username; } /** * Get the query part of the URL as a QueryString object * * @return QueryString */ public function getQuery() { return $this->query; } /** * Set the query part of the URL * * @param QueryString|string|array $query Query to set * * @return Url */ public function setQuery($query) { if (is_string($query)) { $output = null; parse_str($query, $output); $this->query = new QueryString($output); } else if (is_array($query)) { $this->query = new QueryString($query); } else if ($query instanceof QueryString) { $this->query = $query; } return $this; } /** * Get the fragment part of the URL * * @return null|string */ public function getFragment() { return $this->fragment; } /** * Set the fragment part of the URL * * @param string $fragment Fragment to set * * @return Url */ public function setFragment($fragment) { $this->fragment = $fragment; return $this; } /** * Check if this is an absolute URL * * @return bool */ public function isAbsolute() { return $this->scheme && $this->host; } /** * Combine the URL with another URL. Every part of the second URL supercede * the current URL if that part is specified. * * @param string $url Relative URL to combine with * * @return Url * @throws InvalidArgumentException */ public function combine($url) { $absolutePath = $url[0] == '/'; $url = self::factory($url); if ($url->getScheme()) { $this->scheme = $url->getScheme(); } if ($url->getHost()) { $this->host = $url->getHost(); } if ($url->getPort()) { $this->port = $url->getPort(); } if ($url->getUsername()) { $this->username = $url->getUsername(); } if ($url->getPassword()) { $this->password = $url->getPassword(); } if ($url->getFragment()) { $this->fragment = $url->getFragment(); } if ($absolutePath) { // Replace the current URL and query if set if ($url->getPath()) { $this->path = $url->getPath(); } if (count($url->getQuery())) { $this->query = clone $url->getQuery(); } } else { // Append to the current path and query string if ($url->getPath()) { $this->addPath($url->getPath()); } if ($url->getQuery()) { $this->query->merge($url->getQuery()); } } return $this; } }src/Guzzle/Service/Client.php000064400000013137151742730640012160 0ustar00serviceDescription && $this->serviceDescription->hasCommand($name)) { $command = $this->serviceDescription->createCommand($name, $args); } // Check if a concrete command exists using inflection if (!$command) { // Determine the class to instantiate based on the namespace of the // current client and the default location of commands $prefix = $this->getConfig('command.prefix'); if (!$prefix) { // The prefix can be specified in a factory method and is cached $prefix = implode('\\', array_slice(explode('\\', get_class($this)), 0, -1)) . '\\Command\\'; $this->getConfig()->set('command.prefix', $prefix); } $class = $prefix . str_replace(' ', '\\', ucwords(str_replace('.', ' ', Inflector::camel($name)))); // Create the concrete command if it exists if (class_exists($class)) { $command = new $class($args); } } if (!$command) { throw new \InvalidArgumentException("$name command could not be found"); } $command->setClient($this); $this->dispatch('client.command.create', array( 'client' => $this, 'command' => $command )); return $command; } /** * Execute a command and return the response * * @param CommandInterface|CommandSet|array $command Command or set to execute * * @return mixed Returns the result of the executed command's * {@see CommandInterface::getResult} method if a CommandInterface is * passed, or the CommandSet itself if a CommandSet is passed * @throws InvalidArgumentException if an invalid command is passed * @throws Command\CommandSetException if a set contains commands associated * with other clients */ public function execute($command) { if ($command instanceof CommandInterface) { $command->setClient($this)->prepare(); $this->dispatch('command.before_send', array( 'command' => $command )); $command->getRequest()->send(); $this->dispatch('command.after_send', array( 'command' => $command )); return $command->getResult(); } else if ($command instanceof CommandSet) { foreach ($command as $c) { if ($c->getClient() && $c->getClient() !== $this) { throw new Command\CommandSetException( 'Attempting to run a mixed-Client CommandSet from a ' . 'Client context. Run the set using CommandSet::execute() ' ); } $c->setClient($this); } return $command->execute(); } else if (is_array($command)) { return $this->execute(new CommandSet($command)); } throw new \InvalidArgumentException('Invalid command sent to ' . __METHOD__); } /** * Set the service description of the client * * @param ServiceDescription $description Service description that describes * all of the commands and information of the client * * @return Client */ public function setDescription(ServiceDescription $service) { $this->serviceDescription = $service; return $this; } /** * Get the service description of the client * * @return ServiceDescription|NullObject */ public function getDescription() { return $this->serviceDescription ?: new NullObject(); } }src/Guzzle/Service/ClientInterface.php000064400000004622151742730640014000 0ustar00apiCommand = $apiCommand; Inspector::getInstance()->validateConfig($apiCommand->getParams(), $this, false); } else { Inspector::getInstance()->validateClass(get_class($this), $this, false); } if (!$this->get('headers') instanceof Collection) { $this->set('headers', new Collection((array) $this->get('headers'))); } $this->init(); } /** * Get the short form name of the command * * @return string */ public function getName() { if ($this->apiCommand) { return $this->apiCommand->getName(); } else { // Determine the name of the command based on the relation to the // client that executes the command $parts = explode('\\', get_class($this)); while (array_shift($parts) !== 'Command'); return implode('.', array_map(array('Guzzle\\Service\\Inflector', 'snake'), $parts)); } } /** * Get the API command information about the command * * @return ApiCommand|NullObject */ public function getApiCommand() { return $this->apiCommand ?: new NullObject(); } /** * Execute the command * * @return Command * @throws RuntimeException if a client has not been associated with the command */ public function execute() { if (!$this->client) { throw new \RuntimeException('A Client object must be associated with the command before it can be executed from the context of the command.'); } $this->client->execute($this); return $this; } /** * Get the client object that will execute the command * * @return ClientInterface|null */ public function getClient() { return $this->client; } /** * Set the client objec that will execute the command * * @param ClientInterface $client The client objec that will execute the command * * @return Command */ public function setClient(ClientInterface $client) { $this->client = $client; return $this; } /** * Get the request object associated with the command * * @return RequestInterface * @throws RuntimeException if the command has not been executed */ public function getRequest() { if (!$this->request) { throw new \RuntimeException('The command must be prepared before retrieving the request'); } return $this->request; } /** * Get the response object associated with the command * * @return Response * @throws RuntimeException if the command has not been executed */ public function getResponse() { if (!$this->isExecuted()) { throw new \RuntimeException('The command must be executed before retrieving the response'); } return $this->request->getResponse(); } /** * Get the result of the command * * @return Response By default, commands return a Response * object unless overridden in a subclass * @throws RuntimeException if the command has not been executed */ public function getResult() { if (!$this->isExecuted()) { throw new \RuntimeException('The command must be executed before retrieving the result'); } if (null === $this->result) { $this->process(); } return $this->result; } /** * Returns TRUE if the command has been prepared for executing * * @return bool */ public function isPrepared() { return $this->request !== null; } /** * Returns TRUE if the command has been executed * * @return bool */ public function isExecuted() { return $this->request !== null && $this->request->getState() == 'complete'; } /** * Prepare the command for executing and create a request object. * * @return RequestInterface Returns the generated request * @throws RuntimeException if a client object has not been set previously * or in the prepare() */ public function prepare() { if (!$this->isPrepared()) { if (!$this->client) { throw new \RuntimeException('A Client object must be associated with the command before it can be prepared.'); } // Fail on missing required arguments if ($this->apiCommand) { Inspector::getInstance()->validateConfig($this->apiCommand->getParams(), $this, true); } else { Inspector::getInstance()->validateClass(get_class($this), $this, true); } $this->build(); // Add custom request headers set on the command $headers = $this->get('headers'); if ($headers && $headers instanceof Collection) { foreach ($headers as $key => $value) { $this->request->setHeader($key, $value); } } } return $this->getRequest(); } /** * Get the object that manages the request headers that will be set on any * outbound requests from the command * * @return Collection */ public function getRequestHeaders() { return $this->get('headers', new Collection()); } /** * Initialize the command (hook to be implemented in subclasses) */ protected function init() {} /** * Create the request object that will carry out the command */ abstract protected function build(); /** * Create the result of the command after the request has been completed. * * Sets the result as the response by default. If the response is an XML * document, this will set the result as a SimpleXMLElement. If the XML * response is invalid, the result will remain the Response, not XML. * If an application/json response is received, the result will automat- * ically become an array. */ protected function process() { $this->result = $this->getRequest()->getResponse(); // Is the body an JSON document? If so, set the result to be an array if (stripos($this->result->getContentType(), 'application/json') !== false) { $body = trim($this->result->getBody(true)); if ($body) { $this->result = json_decode($body, true); } } else if (preg_match('/^\s*(text\/xml|application\/xml).*$/', $this->result->getContentType())) { // Is the body an XML document? If so, set the result to be a SimpleXMLElement // If the body is available, then parse the XML $body = trim($this->result->getBody(true)); if ($body) { // Silently allow parsing the XML to fail try { $xml = new \SimpleXMLElement($body); $this->result = $xml; } catch (\Exception $e) {} } } } }src/Guzzle/Service/Command/ClosureCommand.php000064400000002252151742730640015227 0ustar00get('closure')) { throw new \InvalidArgumentException('A closure must be passed in the parameters array'); } } /** * {@inheritdoc} * * @throws UnexpectedValueException If the closure does not return a request */ protected function build() { $closure = $this->get('closure'); $this->request = $closure($this, $this->apiCommand); if (!$this->request || !$this->request instanceof RequestInterface) { throw new \UnexpectedValueException('Closure command did not return a RequestInterface object'); } } }src/Guzzle/Service/Command/CommandInterface.php000064400000005624151742730640015521 0ustar00addCommand($command); } } /** * Add a command to the set * * @param CommandInterface $command Command object to add to the command set * * @return CommandSet */ public function addCommand(CommandInterface $command) { $this->commands[] = $command; return $this; } /** * Implements Countable * * @return int */ public function count() { return count($this->commands); } /** * Execute the command set * * @return CommandSet * @throws CommandSetException if any of the commands do not have an associated * {@see ClientInterface} object */ public function execute() { // Keep a list of all commands with no client $invalid = array_filter($this->commands, function($command) { return !$command->getClient(); }); // If any commands do not have a client, then throw an exception if (count($invalid)) { $e = new CommandSetException('Commands found with no associated client'); $e->setCommands($invalid); throw $e; } // Execute all batched commands in parallel if (count($this->commands)) { $multis = array(); // Prepare each request and send out client notifications foreach ($this->commands as $command) { $request = $command->prepare(); $request->getParams()->set('command', $command); $request->getEventDispatcher()->addListener('request.complete', array($this, 'update'), -99999); $command->getClient()->dispatch('command.before_send', array( 'command' => $command )); $command->getClient()->getCurlMulti()->add($command->getRequest(), true); if (!in_array($command->getClient()->getCurlMulti(), $multis)) { $multis[] = $command->getClient()->getCurlMulti(); } } foreach ($multis as $multi) { $multi->send(); } } return $this; } /** * Implements IteratorAggregate * * @return ArrayIterator */ public function getIterator() { return new \ArrayIterator($this->commands); } /** * Get all of the attached commands * * @return array */ public function getCommands() { return $this->commands; } /** * Check if the set contains a specific command * * @param string|CommandInterface $command Command object class name or * concrete CommandInterface object * * @return bool */ public function hasCommand($command) { return (bool) (count(array_filter($this->commands, function($value) use ($command) { return is_string($command) ? ($value instanceof $command) : ($value === $command); })) > 0); } /** * Remove a command from the set * * @param string|CommandInterface $command The command object or command * class name to remove * * @return CommandSet */ public function removeCommand($command) { $this->commands = array_values(array_filter($this->commands, function($value) use ($command) { return is_string($command) ? !($value instanceof $command) : ($value !== $command); })); return $this; } /** * Trigger the result of the command to be created as commands complete and * make sure the command isn't going to send more requests * * {@inheritdoc} */ public function update(Event $event) { $request = $event['request']; $command = $request->getParams()->get('command'); if ($command && $command->isExecuted()) { $request = $event['request']; $request->getEventDispatcher()->removeListener('request.complete', $this); $request->getParams()->remove('command'); // Force the result to be processed $command->getResult(); $command->getClient()->dispatch('command.after_send', array( 'command' => $command )); } } }src/Guzzle/Service/Command/CommandSetException.php000064400000001212151742730640016220 0ustar00invalidCommands; } /** * Set the invalid commands in the CommandSet * * @param array $commands Array of Command objects */ public function setCommands(array $commands) { $this->invalidCommands = $commands; } }src/Guzzle/Service/Command/DynamicCommand.php000064400000006114151742730640015200 0ustar00apiCommand) { throw new \InvalidArgumentException('An API command must be passed'); } } /** * {@inheritdoc} */ protected function build() { // Get the path values and use the client config settings $pathValues = $this->getClient()->getConfig(); $foundPath = false; foreach ($this->apiCommand->getParams() as $name => $arg) { if ($arg->get('location') == 'path') { $pathValues->set($name, $arg->get('prepend') . $this->get($name) . $arg->get('append')); $foundPath = true; } } // Build a custom URL if there are path values if ($foundPath) { $path = str_replace('//', '', Guzzle::inject($this->apiCommand->getPath(), $pathValues)); } else { $path = $this->apiCommand->getPath(); } if (!$path) { $url = $this->getClient()->getBaseUrl(); } else { $url = Url::factory($this->getClient()->getBaseUrl()); $url->combine($path); $url = (string) $url; } // Inject path and base_url values into the URL $this->request = $this->getClient()->createRequest($this->apiCommand->getMethod(), $url); // Add arguments to the request using the location attribute foreach ($this->apiCommand->getParams() as $name => $arg) { if ($this->get($name)) { // Check that a location is set $location = $arg->get('location') ?: 'query'; if ($location == 'path' || $location == 'data') { continue; } if ($location) { // Create the value based on prepend and append settings $value = $arg->get('prepend') . $this->get($name) . $arg->get('append'); // Determine the location and key setting location[:key] $parts = explode(':', $location); $place = $parts[0]; // If a key is specified (using location:key), use it $key = isset($parts[1]) ? $parts[1] : $name; // Add the parameter to the request switch ($place) { case 'body': $this->request->setBody(EntityBody::factory($value)); break; case 'header': $this->request->setHeader($key, $value); break; case 'query': $this->request->getQuery()->set($key, $value); break; } } } } } }src/Guzzle/Service/Description/ApiCommand.php000064400000010131151742730640015224 0ustar00config = $config; $this->config['name'] = isset($config['name']) ? trim($config['name']) : ''; $this->config['doc'] = isset($config['doc']) ? trim($config['doc']) : ''; $this->config['method'] = isset($config['method']) ? trim($config['method']) : ''; $this->config['path'] = isset($config['path']) ? trim($config['path']) : ''; $this->config['class'] = isset($config['class']) ? trim($config['class']) : 'Guzzle\\Service\\Command\\DynamicCommand'; if (isset($config['params']) && is_array($config['params'])) { foreach ($config['params'] as $paramName => $param) { $this->params[$paramName] = $param instanceof Collection ? $param : new Collection($param); } } } /** * Get as an array * * @return true */ public function getData() { return array_merge($this->config, array( 'params' => $this->params )); } /** * Get the params of the command * * @return array */ public function getParams() { return $this->params; } /** * Get a single parameter of the command * * @param string $param Parameter to retrieve by name * * @return Collection|null */ public function getParam($param) { return isset($this->params[$param]) ? $this->params[$param] : null; } /** * Get the HTTP method of the command * * @return string */ public function getMethod() { return $this->config['method']; } /** * Get the concrete command class that implements this command * * @return string */ public function getConcreteClass() { return $this->config['class']; } /** * Get the name of the command * * @return string */ public function getName() { return $this->config['name']; } /** * Get the documentation for the command * * @return string */ public function getDoc() { return $this->config['doc']; } /** * Get the path routing information to append to the path of the generated * request * * @return string */ public function getPath() { return $this->config['path']; } }src/Guzzle/Service/Description/ApiCommandFactory.php000064400000000574151742730640016566 0ustar00getConcreteClass(); return new $class($args, $command); } }src/Guzzle/Service/Description/CommandFactoryInterface.php000064400000001064151742730640017750 0ustar00 $type) { $default = array(); if (!isset($type['class'])) { throw new \RuntimeException('Custom types require a class attribute'); } foreach ($type as $key => $value) { if ($key != 'name' && $key != 'class') { $default[$key] = $value; } } Inspector::getInstance()->registerConstraint($name, $type['class'], $default); } } $commands = array(); if (!empty($data['commands'])) { foreach ($data['commands'] as $name => $command) { $name = $command['name'] = isset($command['name']) ? $command['name'] : $name; // Extend other commands if (!empty($command['extends'])) { if (empty($commands[$command['extends']])) { throw new \RuntimeException($name . ' extends missing command ' . $command['extends']); } $params = array_merge($commands[$command['extends']]->getParams(), !empty($command['params']) ? $command['params'] : array()); $command = array_merge($commands[$command['extends']]->getData(), $command); $command['params'] = $params; } // Use the default class $command['class'] = isset($command['class']) ? str_replace('.', '\\', $command['class']) : self::DEFAULT_COMMAND_CLASS; $commands[$name] = new ApiCommand($command); } } return new self($commands); } /** * Create a new ServiceDescription * * @param array $commands (optional) Array of {@see ApiCommand} objects * @param CommandFactoryInterface (optional) Command factory to build * dynamic commands. Uses the ApiCommandFactory by default. */ public function __construct(array $commands = array(), CommandFactoryInterface $commandFactory = null) { $this->commands = $commands; $this->commandFactory = $commandFactory ?: new ApiCommandFactory(); } /** * Get the API commands of the service * * @return array Returns an array of ApiCommand objects */ public function getCommands() { return $this->commands; } /** * Check if the service has a command by name * * @param string $name Name of the command to check * * @return bool */ public function hasCommand($name) { return array_key_exists($name, $this->commands); } /** * Get an API command by name * * @param string $name Name of the command * * @return ApiCommand|NullObject Returns an ApiCommand on success or a * NullObject on error */ public function getCommand($name) { return $this->hasCommand($name) ? $this->commands[$name] : new NullObject(); } /** * Create a webservice command based on the service document * * @param string $command Name of the command to retrieve * @param array $args (optional) Arguments to pass to the command * * @return Command\CommandInterface * @throws InvalidArgumentException if the command was not found in the service doc */ public function createCommand($name, array $args = array()) { if (!$this->hasCommand($name)) { throw new \InvalidArgumentException($name . ' command not found'); } return $this->commandFactory->createCommand($this->getCommand($name), $args); } }src/Guzzle/Service/Description/XmlDescriptionBuilder.php000064400000005605151742730640017501 0ustar00 array(), 'commands' => array() ); // Handle XML includes $includes = $xml->includes->include; if ($includes) { foreach ($includes as $includeFile) { $path = (string) $includeFile->attributes()->path; if ($path[0] != DIRECTORY_SEPARATOR) { $path = dirname($file) . DIRECTORY_SEPARATOR . $path; } $data = array_merge_recursive(self::parseXmlFile($path), $data); } } // Register any custom type definitions $types = $xml->types->type; if ($types) { foreach ($types as $type) { $attr = $type->attributes(); $name = (string) $attr->name; $data['types'][$name] = array(); foreach ($attr as $key => $value) { $data['types'][$name][(string) $key] = (string) $value; } } } // Parse the commands in the XML doc $commands = $xml->commands->command; if ($commands) { foreach ($commands as $command) { $attr = $command->attributes(); $name = (string) $attr->name; $data['commands'][$name] = array( 'params' => array() ); foreach ($attr as $key => $value) { $data['commands'][$name][(string) $key] = (string) $value; } $data['commands'][$name]['doc'] = (string) $command->doc; foreach ($command->param as $param) { $attr = $param->attributes(); $paramName = (string) $attr['name']; $data['commands'][$name]['params'][$paramName] = array(); foreach ($attr as $pk => $pv) { $pv = (string) $pk == 'required' ? (string) $pv === 'true' : (string) $pv; $data['commands'][$name]['params'][$paramName][(string) $pk] = (string) $pv; } } } } return $data; } /** * {@inheritdoc} */ public static function build($filename) { return ServiceDescription::factory(self::parseXmlFile($filename)); } }src/Guzzle/Service/Inflector.php000064400000003575151742730640012674 0ustar00 array(), 'camel' => array() ); /** * Converts strings from camel case to snake case * (e.g. CamelCase camel_case). * * @param string $word Word to convert to snake case * * @return string */ public static function snake($word) { if (isset(self::$cache['snake'][$word])) { return self::$cache['snake'][$word]; } self::pruneCache('snake'); return self::$cache['snake'][$word] = strtolower($word) == $word ? $word : strtolower(preg_replace('/(.)([A-Z])/', "$1_$2", $word)); } /** * Converts strings from snake_case to upper CamelCase * * @param string $word Value to convert into upper CamelCase * * @return string */ public static function camel($word) { if (isset(self::$cache['camel'][$word])) { return self::$cache['camel'][$word]; } self::pruneCache('camel'); return self::$cache['camel'][$word] = str_replace(' ', '', ucwords(strtr($word, '_-', ' '))); } /** * Prune one of the caches * * @param string $cache Name of the cache to prune */ private static function pruneCache($cache) { if (count(self::$cache[$cache]) == self::MAX_ENTRIES_PER_CACHE) { self::$cache[$cache] = array_slice(self::$cache[$cache], self::MAX_ENTRIES_PER_CACHE * 0.1); } } }src/Guzzle/Service/Inspector.php000064400000031346151742730640012712 0ustar00constraints = array( 'blank' => array($base . 'Blank', null), 'not_blank' => array($base . 'NotBlank', null), 'integer' => array($base . 'Type', array('type' => 'integer')), 'float' => array($base . 'Type', array('type' => 'float')), 'string' => array($base . 'Type', array('type' => 'string')), 'date' => array($base . 'Date', null), 'date_time' => array($base . 'DateTime', null), 'time' => array($base . 'Time', null), 'boolean' => array($base . 'Choice', array('choices' => array('true', 'false', '0', '1'))), 'country' => array($base . 'Country', null), 'email' => array($base . 'Email', null), 'ip' => array($base . 'Ip', null), 'language' => array($base . 'Language', null), 'locale' => array($base . 'Locale', null), 'url' => array($base . 'Url', null), 'file' => array($base . 'File', null), 'image' => array($base . 'Image', null), 'class' => array($base . 'Type', null), 'type' => array($base . 'Type', null), 'choice' => array($base . 'Choice', null), 'enum' => array($base . 'Choice', null), 'regex' => array($base . 'Regex', null) ); } /** * Get an instance of the Inspector * * @return Reflection */ public static function getInstance() { // @codeCoverageIgnoreStart if (!self::$instance) { self::$instance = new self(); } // @codeCoverageIgnoreEnd return self::$instance; } /** * Validate and prepare configuration parameters * * @param array $config Configuration values to apply. * @param array $defaults (optional) Default parameters * @param array $required (optional) Required parameter names * * @return Collection * @throws InvalidArgumentException if a parameter is missing */ public static function prepareConfig(array $config = null, $defaults = null, $required = null) { $collection = new Collection((array) $defaults); foreach ((array) $config as $key => $value) { $collection->set($key, $value); } foreach ((array) $required as $key) { if ($collection->hasKey($key) === false) { throw new \InvalidArgumentException( "Config must contain a '{$key}' key" ); } } return $collection; } /** * Set the validator to use with the inspector * * @param Validator $validator * * @return Inspector */ public function setValidator(Validator $validator) { $this->validator = $validator; return $this; } /** * Get the validator associated with the inspector. A default validator * will be created if none has already been associated * * @return Validator */ public function getValidator() { if (!$this->validator) { $this->validator = new Validator(new ClassMetadataFactory(new StaticMethodLoader()), new ConstraintValidatorFactory()); } return $this->validator; } /** * Get an array of the registered constraints by name * * @return array */ public function getRegisteredConstraints() { return array_map(function($constraint) { return $constraint[0]; }, $this->constraints); } /** * Register a constraint class with a special name * * @param string $name Name of the constraint to register * @param string $class Name of the class or object to use when filtering by this name * @param array $default Default values to pass to the constraint * * @return Inspector */ public function registerConstraint($name, $class, array $default = array()) { $this->constraints[$name] = array($class, $default); } /** * Get the Guzzle arguments from a DocBlock * * @param string $doc DocBlock to parse * * @return array Returns an associative array of the parsed docblock params */ public function parseDocBlock($doc) { $matches = array(); // Get all of the @guzzle annotations from the class preg_match_all('/' . self::GUZZLE_ANNOTATION . '\s+([A-Za-z0-9_\-\.]+)\s*([A-Za-z0-9]+=".+")*/', $doc, $matches); if (empty($matches[1])) { return array(); } $params = array(); foreach ($matches[1] as $index => $match) { // Add the matched argument to the array keys $params[$match] = array(); if (isset($matches[2])) { // Break up the argument attributes by closing quote foreach (explode('" ', $matches[2][$index]) as $part) { $attrs = array(); // Find the attribute and attribute value preg_match('/([A-Za-z0-9]+)="(.+)"*/', $part, $attrs); if (isset($attrs[1]) && isset($attrs[0])) { // Sanitize the strings if ($attrs[2][strlen($attrs[2]) - 1] == '"') { $attrs[2] = substr($attrs[2], 0, strlen($attrs[2]) - 1); } $params[$match][$attrs[1]] = $attrs[2]; } } } } return $params; } /** * Validates that a class has all of the required configuration settings * * @param string $class Name of the class to use to retrieve args * @param Collection $config Configuration settings * @param bool $strict (optional) Set to FALSE to allow missing required fields * * @return array|bool Returns an array of errors or TRUE on success * * @throws InvalidArgumentException if any args are missing and $strict is TRUE */ public function validateClass($className, Collection $config, $strict = true) { if (!isset($this->cache[$className])) { $reflection = new \ReflectionClass($className); $this->cache[$className] = $this->parseDocBlock($reflection->getDocComment()); } return $this->validateConfig($this->cache[$className], $config, $strict); } /** * Validates that all required args are included in a config object, * and if not, throws an InvalidArgumentException with a helpful error message. Adds * default args to the passed config object if the parameter was not * set in the config object. * * @param array $params Params to validate * @param Collection $config Configuration settings * @param bool $strict (optional) Set to FALSE to allow missing required fields * * @return array|bool Returns an array of errors or TRUE on success * * @throws InvalidArgumentException if any args are missing and $strict is TRUE */ public function validateConfig(array $params, Collection $config, $strict = true) { $errors = array(); foreach ($params as $name => $arg) { $arg = ($arg instanceof Collection) ? $arg : (is_array($arg) ? new Collection($arg) : new Collection()); // Set the default value if it is not set if ($arg->get('static') || ($arg->get('default') && !$config->get($name))) { $check = $arg->get('static', $arg->get('default')); if ($check === 'true') { $config->set($name, true); } else if ($check == 'false') { $config->set($name, false); } else { $config->set($name, $check); } } // Inject configuration information into the config value if (is_scalar($config->get($name)) && strpos($config->get($name), '{{') !== false) { $config->set($name, Guzzle::inject($config->get($name), $config)); } // Ensure that required arguments are set if ($arg->get('required') && !$config->get($name)) { $errors[] = 'Requires that the ' . $name . ' argument be supplied.' . ($arg->get('doc') ? ' (' . $arg->get('doc') . ').' : ''); continue; } // Skip further validation if the arg is not set if ($config->hasKey($name) === false) { continue; } // Ensure that the correct data type is being used if ($arg->get('type')) { $constraint = $this->getConstraint($arg->get('type')); $result = $this->getValidator()->validateValue($config->get($name), $constraint); if ($result && count($result)) { $errors = array_merge($errors, array_map(function($message) { return $message->getMessage(); }, $result->getIterator()->getArrayCopy())); } } // Run the value through attached filters if ($filters = $arg->get('filters')) { foreach (explode(',', $filters) as $filter) { if (strpos($filter, '::')) { $config->set($name, call_user_func(explode('::', $filter), $config->get($name))); } else { $config->set($name, call_user_func($filter, $config->get($name))); } } } // Check the length values if ($arg->get('min_length') && strlen($config->get($name)) < $arg->get('min_length')) { $errors[] = 'Requires that the ' . $name . ' argument be >= ' . $arg->get('min_length') . ' characters.'; } if ($arg->get('max_length') && strlen($config->get($name)) > $arg->get('max_length')) { $errors[] = 'Requires that the ' . $name . ' argument be <= ' . $arg->get('max_length') . ' characters.'; } } if (empty($errors)) { return true; } else if ($strict) { throw new \InvalidArgumentException('Validation errors: ' . implode("\n", $errors)); } return $errors; } /** * Get a constraint by name: e.g. "type:Guzzle\Common\Collection" * * @param string $name Name of the constraint to retrieve * * @return Contraint */ public function getConstraint($name) { $parts = array_map('trim', explode(':', $name, 2)); $name = $parts[0]; if (!isset($this->constraints[$name])) { throw new \InvalidArgumentException($name . ' has not been registered'); } if (!empty($parts[1])) { $args = strpos($parts[1], ',') ? str_getcsv($parts[1], ',', "'") : $parts[1]; } else { $args = $this->constraints[$name][1]; } $class = $this->constraints[$name][0]; return new $class($args); } }src/Guzzle/Service/ResourceIterator.php000064400000016036151742730640014244 0ustar00 *
  • page_size => Max number of results to retrieve per request.
  • *
  • resources => Initial resources to associate with the iterator.
  • *
  • next_token => The value used to mark the beginning of a subsequent result set.
  • * */ public function __construct(ClientInterface $client, array $data) { $this->client = $client; $this->data = $data; $this->limit = array_key_exists('limit', $data) ? $data['limit'] : -1; $this->pageSize = array_key_exists('page_size', $data) ? $data['page_size'] : false; $this->resourceList = array_key_exists('resources', $data) ? $data['resources'] : array(); $this->nextToken = array_key_exists('next_token', $data) ? $data['next_token'] : false; $this->retrievedCount = count($this->resourceList); $this->onLoad(); } /** * Get all of the resources as an array (be careful as this could issue a * large number of requests if no limit is specified) * * @param bool $rewind (optional) By default, rewind() will be called * * @return array */ public function toArray($rewind = true) { if ($rewind) { $this->rewind(); } return iterator_to_array($this, false); } /** * Return the current element. * * @return mixed Returns the current element. */ public function current() { return $this->current; } /** * Return the total number of items that have been retrieved thus far. * * Implements Countable * * @return string Returns the total number of items retrieved. */ public function count() { return $this->retrievedCount; } /** * Return the total number of items that have been iterated thus far. * * @return string Returns the total number of items iterated. */ public function getPosition() { return $this->pos; } /** * Return the key of the current element. * * @return string Returns the current key. */ public function key() { // @codeCoverageIgnoreStart return $this->currentIndex; // @codeCoverageIgnoreEnd } /** * Rewind the Iterator to the first element. */ public function rewind() { $this->currentIndex = -1; $this->pos = -1; $this->resourceList = $this->data['resources']; $this->nextToken = $this->data['next_token']; $this->retrievedCount = count($this->resourceList); $this->next(); } /** * Check if there is a current element after calls to rewind() or next(). * * @return bool Returns TRUE if the current element is valid or FALSE */ public function valid() { return isset($this->resourceList) && $this->current && ($this->pos < $this->limit || $this->limit == -1) && ($this->currentIndex < count($this->resourceList) || $this->nextToken); } /** * Move forward to next element and may trigger subsequent requests */ public function next() { $this->pos++; if (!isset($this->resourceList) || ++$this->currentIndex >= count($this->resourceList) && $this->nextToken && ($this->limit == -1 || $this->pos < $this->limit)) { $this->dispatch('resource_iterator.before_send', array( 'iterator' => $this, 'resources' => $this->resourceList )); $this->sendRequest(); $this->dispatch('resource_iterator.after_send', array( 'iterator' => $this, 'resources' => $this->resourceList )); } $this->current = (array_key_exists($this->currentIndex, $this->resourceList)) ? $this->resourceList[$this->currentIndex] : null; } /** * Retrieve the NextToken that can be used in other iterators. * * @return string Returns a NextToken */ public function getNextToken() { return $this->nextToken; } /** * Send a request to retrieve the next page of results. * Hook for sublasses to implement. */ abstract protected function sendRequest(); /** * Returns the value that should be specified for the page size for * a request that will maintain any hard limits, but still honor the * specified pageSize if the number of items retrieved + pageSize < hard * limit * * @return int Returns the page size of the next request. */ protected function calculatePageSize() { if ($this->limit == -1) { return $this->pageSize; } else if ($this->pos + $this->pageSize > $this->limit) { return $this->limit - $this->pos; } // @codeCoverageIgnoreStart return $this->pageSize; // @codeCoverageIgnoreEnd } /** * Called when the iterator is constructed. * * Hook for sub-classes to implement. */ protected function onLoad() {} }src/Guzzle/Service/ResourceIteratorApplyBatched.php000064400000006517151742730640016530 0ustar00iterator = $iterator; $this->callback = $callback; } /** * Apply the callback to the contents of the resource iterator * * Calling this method dispatches four events: * * # before_apply -- Before adding a resource to a batch. Context is the resource * # after_apply -- After adding the resource to a batch. Context is the resource * # before_batch -- Before a batch request is sent if one is sent. Context is an array of resources * # after_batch -- After a batch request is sent if one is sent. Context is an array of resources * * @return integer Returns the number of resources iterated */ public function apply($perBatch = 20) { if ($this->iterated == 0) { $batched = array(); foreach ($this->iterator as $resource) { $batched[] = $resource; if (count($batched) >= $perBatch) { $this->applyBatch($batched); $batched = array(); } $this->iterated++; } if (count($batched)) { $this->applyBatch($batched); } } return $this->iterated; } /** * Get the total number of batches sent * * @return int */ public function getBatchCount() { return $this->batches; } /** * Get the total number of iterated resources * * @return int */ public function getIteratedCount() { return $this->iterated; } /** * Apply the callback to a collection of resources * * @param array $batch */ private function applyBatch(array $batch) { $this->batches++; $this->dispatch('iterator_batch.before_batch', array( 'iterator' => $this, 'batch' => $batch )); call_user_func_array($this->callback, array( $this->iterator, $batch )); $this->dispatch('iterator_batch.after_batch', array( 'iterator' => $this, 'batch' => $batch )); } }src/Guzzle/Service/ServiceBuilder.php000064400000015170151742730640013650 0ustar00clients->client as $client) { $row = array(); foreach ($client->param as $param) { $row[(string) $param->attributes()->name] = (string) $param->attributes()->value; } $config[(string) $client->attributes()->name] = array( 'class' => (string) $client->attributes()->class, 'extends' => (string) $client->attributes()->extends, 'params' => $row ); } } // Validate the configuration and handle extensions foreach ($config as $name => &$client) { $client['params'] = isset($client['params']) ? $client['params'] : array(); // Check if this client builder extends another client if (!empty($client['extends'])) { // Make sure that the service it's extending has been defined if (!isset($config[$client['extends']])) { throw new \LogicException($name . ' is trying to extend a non-existent service: ' . $client['extends']); } $client['class'] = empty($client['class']) ? $config[$client['extends']]['class'] : $client['class']; $client['params'] = array_merge($config[$client['extends']]['params'], $client['params']); } $client['class'] = str_replace('.', '\\', $client['class']); } return new self($config); } /** * Construct a new service builder * * @param array $serviceBuilderConfig Service configuration settings: * name => Name of the service * class => Builder class used to create clients using dot notation (Guzzle.Service.Aws.S3builder or Guzzle.Service.Builder.DefaultBuilder) * params => array of key value pair configuration settings for the builder */ public function __construct(array $serviceBuilderConfig) { $this->builderConfig = $serviceBuilderConfig; } /** * Magic method to allow serialization to support caching * * @return array */ public function __sleep() { return array('builderConfig'); } /** * Get a client using a registered builder * * @param $name Name of the registered client to retrieve * @param bool $throwAway (optional) Set to TRUE to not store the client * for later retrieval from the ServiceBuilder * * @return ClientInterface * @throws InvalidArgumentException when a client cannot be found by name */ public function get($name, $throwAway = false) { if (!isset($this->builderConfig[$name])) { throw new \InvalidArgumentException('No client is registered as ' . $name); } if (!$throwAway && isset($this->clients[$name])) { return $this->clients[$name]; } // Convert references to the actual client foreach ($this->builderConfig[$name]['params'] as $k => &$v) { if (0 === strpos($v, '{{') && strlen($v) - 2 == strpos($v, '}}')) { $v = $this->get(trim(substr($v, 2, -2))); } } $client = call_user_func( array($this->builderConfig[$name]['class'], 'factory'), $this->builderConfig[$name]['params'] ); if (!$throwAway) { $this->clients[$name] = $client; } return $client; } /** * Register a client by name with the service builder * * @param string $offset Name of the client to register * @param ClientInterface $value Client to register */ public function offsetSet($offset, $value) { $this->builderConfig[$offset] = $value; } /** * Remove a registered client by name * * @param string $offset Client to remove by name */ public function offsetUnset($offset) { unset($this->builderConfig[$offset]); } /** * Check if a client is registered with the service builder by name * * @param string $offset Name to check to see if a client exists * * @return bool */ public function offsetExists($offset) { return isset($this->builderConfig[$offset]); } /** * Get a registered client by name * * @param string $offset Registered client name to retrieve * * @return ClientInterface */ public function offsetGet($offset) { return $this->get($offset); } }tests/Guzzle/Tests/Common/AbstractHasDispatcherTest.php000064400000003516151742730640017315 0ustar00assertEquals(array(), AbstractHasDispatcher::getAllEvents()); } /** * @covers Guzzle\Common\AbstractHasDispatcher::setEventDispatcher * @covers Guzzle\Common\AbstractHasDispatcher::getEventDispatcher */ public function testAllowsDispatcherToBeInjected() { $d = new EventDispatcher(); $mock = $this->getMockForAbstractClass('Guzzle\Common\AbstractHasDispatcher'); $this->assertSame($mock, $mock->setEventDispatcher($d)); $this->assertSame($d, $mock->getEventDispatcher()); } /** * @covers Guzzle\Common\AbstractHasDispatcher::getEventDispatcher */ public function testCreatesDefaultEventDispatcherIfNeeded() { $mock = $this->getMockForAbstractClass('Guzzle\Common\AbstractHasDispatcher'); $this->assertInstanceOf('Symfony\Component\EventDispatcher\EventDispatcher', $mock->getEventDispatcher()); } /** * @covers Guzzle\Common\AbstractHasDispatcher::dispatch */ public function testHelperDispatchesEvents() { $data = array(); $mock = $this->getMockForAbstractClass('Guzzle\Common\AbstractHasDispatcher'); $mock->getEventDispatcher()->addListener('test', function(Event $e) use (&$data) { $data = $e->getIterator()->getArrayCopy(); }); $mock->dispatch('test', array( 'param' => 'abc' )); $this->assertEquals(array( 'param' => 'abc', ), $data); } }tests/Guzzle/Tests/Common/Cache/CacheAdapterTest.php000064400000004060151742730640016411 0ustar00cache = new ArrayCache(); $this->adapter = new DoctrineCacheAdapter($this->cache); } /** * Cleans up the environment after running a test. */ protected function tearDown() { $this->adapter = null; $this->cache = null; parent::tearDown(); } /** * @covers \Guzzle\Common\Cache\AbstractCacheAdapter::getCacheObject */ public function testGetCacheObject() { $this->assertEquals($this->cache, $this->adapter->getCacheObject()); } /** * @covers \Guzzle\Common\Cache\DoctrineCacheAdapter::save */ public function testSave() { $this->assertTrue($this->adapter->save('test', 'data', 1000)); } /** * @covers \Guzzle\Common\Cache\DoctrineCacheAdapter::fetch */ public function testFetch() { $this->assertTrue($this->adapter->save('test', 'data', 1000)); $this->assertEquals('data', $this->adapter->fetch('test')); } /** * @covers \Guzzle\Common\Cache\DoctrineCacheAdapter::contains */ public function testContains() { $this->assertTrue($this->adapter->save('test', 'data', 1000)); $this->assertTrue($this->adapter->contains('test')); } /** * @covers \Guzzle\Common\Cache\DoctrineCacheAdapter::delete */ public function testDelete() { $this->assertTrue($this->adapter->save('test', 'data', 1000)); $this->assertTrue($this->adapter->delete('test')); $this->assertFalse($this->adapter->contains('test')); } }tests/Guzzle/Tests/Common/Cache/ZendCacheAdapterTest.php000064400000002524151742730640017235 0ustar00cache = new TestBackend(); $this->adapter = new ZendCacheAdapter($this->cache); } /** * Cleans up the environment after running a test. */ protected function tearDown() { $this->adapter = null; $this->cache = null; parent::tearDown(); } /** * @covers Guzzle\Common\Cache\ZendCacheAdapter * @expectedException InvalidArgumentException */ public function testEnforcesType() { $adapter = new ZendCacheAdapter('fud'); } /** * @covers Guzzle\Common\Cache\ZendCacheAdapter */ public function testAll() { $this->assertTrue($this->adapter->save('id', 'data')); $this->assertTrue($this->adapter->delete('id', 'data')); $this->assertEquals('foo', $this->adapter->fetch('id')); $this->assertEquals('123456', $this->adapter->contains('id')); } }tests/Guzzle/Tests/Common/CollectionTest.php000064400000032703151742730640015202 0ustar00coll = new Collection(); } /** * @covers Guzzle\Common\Collection::__construct */ public function testConstructorCanBeCalledWithNoParams() { $this->coll = new Collection(); $p = $this->coll->getAll(); $this->assertEmpty($p, '-> Collection must be empty when no data is passed'); } /** * @covers Guzzle\Common\Collection::__construct * @covers Guzzle\Common\Collection::getAll */ public function testConstructorCanBeCalledWithParams() { $testData = array( 'test' => 'value', 'test_2' => 'value2' ); $this->coll = new Collection($testData); $this->assertEquals($this->coll->getAll(), $testData, '-> getAll() must return the data passed in the constructor'); } /** * @covers Guzzle\Common\Collection::__toString */ public function testCollectionCanBeConvertingIntoString() { $data = new Collection(); $this->assertEquals('Guzzle\Common\Collection@' . spl_object_hash($data), (string)$data, '-> __toString() must represent the collection'); } /** * Test the IteratorAggregate implementation of theCollection object * * @covers Guzzle\Common\Collection::getIterator */ public function testImplementsIteratorAggregate() { $this->coll->set('key', 'value'); $this->assertInstanceOf('ArrayIterator', $this->coll->getIterator()); $this->assertEquals(1, count($this->coll)); $total = 0; foreach ($this->coll as $key => $value) { $this->assertEquals('key', $key); $this->assertEquals('value', $value); $total++; } $this->assertEquals(1, $total); } /** * @covers Guzzle\Common\Collection::add */ public function testCanAddValuesToExistingKeysByUsingArray() { $this->coll->add('test', 'value1'); $this->assertEquals($this->coll->getAll(), array('test' => 'value1')); $this->coll->add('test', 'value2'); $this->assertEquals($this->coll->getAll(), array('test' => array('value1', 'value2'))); $this->coll->add('test', 'value3'); $this->assertEquals($this->coll->getAll(), array('test' => array('value1', 'value2', 'value3'))); } /** * @covers Guzzle\Common\Collection::merge * @covers Guzzle\Common\Collection::getAll */ public function testHandlesMergingInDisparateDataSources() { $params = array( 'test' => 'value1', 'test2' => 'value2', 'test3' => array('value3', 'value4') ); $this->coll->merge($params); $this->assertEquals($this->coll->getAll(), $params); // Pass an invalid value and expect the same unaltered object $this->assertEquals($this->coll->merge(false), $this->coll); // Pass the same object to itself $this->assertEquals($this->coll->merge($this->coll), $this->coll); } /** * @covers Guzzle\Common\Collection::clear * @covers Guzzle\Common\Collection::remove */ public function testCanClearAllDataOrSpecificKeys() { $this->coll->merge(array( 'test' => 'value1', 'test2' => 'value2' )); // Clear a specific parameter by name $this->coll->remove('test'); $this->assertEquals($this->coll->getAll(), array( 'test2' => 'value2' )); // Clear all parameters $this->coll->clear(); $this->assertEquals($this->coll->getAll(), array()); } /** * @covers Guzzle\Common\Collection::get * @covers Guzzle\Common\Collection::getAll */ public function testGetsValuesByKey() { $this->assertNull($this->coll->get('test')); $this->coll->add('test', 'value'); $this->assertEquals('value', $this->coll->get('test')); $this->coll->set('test2', 'v2'); $this->coll->set('test3', 'v3'); $this->assertEquals(array( 'test' => 'value', 'test2' => 'v2' ), $this->coll->getAll(array('test', 'test2'))); } /** * @covers Guzzle\Common\Collection::getKeys * @covers Guzzle\Common\Collection::remove */ public function testProvidesKeys() { $this->assertEquals(array(), $this->coll->getKeys()); $this->coll->merge(array( 'test1' => 'value1', 'test2' => 'value2' )); $this->assertEquals(array('test1', 'test2'), $this->coll->getKeys()); // Returns the cached array previously returned $this->assertEquals(array('test1', 'test2'), $this->coll->getKeys()); $this->coll->remove('test1'); $this->assertEquals(array('test2'), $this->coll->getKeys()); $this->coll->add('test3', 'value3'); $this->assertEquals(array('test2', 'test3'), $this->coll->getKeys()); // Test the regex matching capabilities $this->assertEquals(array('test2'), $this->coll->getKeys('/test[0-2]/')); } /** * @covers Guzzle\Common\Collection::hasKey */ public function testChecksIfHasKey() { $this->assertFalse($this->coll->hasKey('test')); $this->coll->add('test', 'value'); $this->assertEquals('test', $this->coll->hasKey('test')); $this->coll->add('test2', 'value2'); $this->assertEquals('test', $this->coll->hasKey('test')); $this->assertEquals('test2', $this->coll->hasKey('test2')); $this->assertFalse($this->coll->hasKey('testing')); $this->coll->set('ab-c', '123'); $this->assertEquals('ab-c', $this->coll->hasKey('/[a-c]{2}\-c/', Collection::MATCH_REGEX)); $this->assertFalse($this->coll->hasKey('/[A-C]{2}\-c/', Collection::MATCH_REGEX)); $this->assertEquals('ab-c', $this->coll->hasKey('AB-C', Collection::MATCH_IGNORE_CASE)); $this->assertFalse($this->coll->hasKey('A-C', Collection::MATCH_IGNORE_CASE)); $this->assertEquals(false, $this->coll->hasKey('AB-C', 'junk')); } /** * @covers Guzzle\Common\Collection::hasValue */ public function testChecksIfHasValue() { $this->assertFalse($this->coll->hasValue('value')); $this->coll->add('test', 'value'); $this->assertEquals('test', $this->coll->hasValue('value')); $this->coll->add('test2', 'value2'); $this->assertEquals('test', $this->coll->hasValue('value')); $this->assertEquals('test2', $this->coll->hasValue('value2')); $this->assertFalse($this->coll->hasValue('val')); } /** * @covers Guzzle\Common\Collection::get * @covers Guzzle\Common\Collection::set * @covers Guzzle\Common\Collection::add */ public function testCanGetKeyValueByRegexMatch() { $this->coll->set('Testing-Key', 'value'); $this->coll->add('Testing-Name', 'value2'); $this->assertNull($this->coll->get('testing')); $this->assertEquals('value', $this->coll->get('/testing-Key/i', null, Collection::MATCH_REGEX)); $this->assertNull($this->coll->get('/testing-[A-Za-z]+/', null, Collection::MATCH_REGEX)); // Retrieves the first matching parameter $this->assertEquals('value', $this->coll->get('/testing-[A-Za-z]+/i', null, Collection::MATCH_REGEX)); $this->assertEquals('value2', $this->coll->get('/Testing-[Na-z]+/', null, Collection::MATCH_REGEX)); } /** * @covers Guzzle\Common\Collection::getAll */ public function testCanGetAllKeysMatchingRegex() { $this->coll->add('Testing-Key', 'value'); $this->coll->add('Testing-Name', 'value2'); $this->assertEquals(array(), $this->coll->getAll(array('testing'))); $this->assertEquals(array( 'Testing-Key' => 'value' ), $this->coll->getAll('/testing-Key/i', Collection::MATCH_REGEX)); $this->assertEquals(array( 'Testing-Name' => 'value2' ), $this->coll->getAll('/[T|t]esting-N[a-z]+/', Collection::MATCH_REGEX)); $this->assertEquals(array( 'Testing-Key' => 'value', 'Testing-Name' => 'value2' ), $this->coll->getAll(array('/testing-Key/i', '/Testing-[Na-z]+/'), Collection::MATCH_REGEX)); } /** * @covers Guzzle\Common\Collection::get */ public function testCanGetValuesByKeyIgnoringCase() { $this->coll->add('tEsT', 'value'); $this->assertNull($this->coll->get('test')); $this->assertEquals('value', $this->coll->get('test', null, true)); $this->assertEquals('default', $this->coll->get('foo', 'default', true)); } /** * @covers Guzzle\Common\Collection::getAll */ public function testCanGetAllValuesByArrayIgnoringCase() { $this->coll->add('foo', 'bar'); $this->coll->add('tEsT', 'value'); $this->coll->add('tesTing', 'v2'); $this->coll->add('key', 'v3'); $this->assertNull($this->coll->get('test')); $this->assertEquals(array( 'foo' => 'bar', 'tEsT' => 'value', 'tesTing' => 'v2' ), $this->coll->getAll(array( 'foo', 'test', 'testing' ), true)); } /** * @covers Guzzle\Common\Collection::count */ public function testImplementsCount() { $data = new Collection(); $this->assertEquals(0, $data->count()); $data->add('key', 'value'); $this->assertEquals(1, count($data)); $data->add('key', 'value2'); $this->assertEquals(1, count($data)); $data->add('key_2', 'value3'); $this->assertEquals(2, count($data)); } /** * @covers Guzzle\Common\Collection::merge */ public function testAddParamsByMerging() { $params = array( 'test' => 'value1', 'test2' => 'value2', 'test3' => array('value3', 'value4') ); // Add some parameters $this->coll->merge($params); // Add more parameters by merging them in $this->coll->merge(array( 'test' => 'another', 'different_key' => 'new value' )); $this->assertEquals(array( 'test' => array('value1', 'another'), 'test2' => 'value2', 'test3' => array('value3', 'value4'), 'different_key' => 'new value' ), $this->coll->getAll()); } /** * @covers Guzzle\Common\Collection::filter */ public function testAllowsFunctionalFilter() { $this->coll->merge(array( 'fruit' => 'apple', 'number' => 'ten', 'prepositions' => array('about', 'above', 'across', 'after'), 'same_number' => 'ten' )); $filtered = $this->coll->filter(function($key, $value) { return $value == 'ten'; }); $this->assertNotEquals($filtered, $this->coll); $this->assertEquals(array( 'number' => 'ten', 'same_number' => 'ten' ), $filtered->getAll()); } /** * @covers Guzzle\Common\Collection::map */ public function testAllowsFunctionalMapping() { $this->coll->merge(array( 'number_1' => 1, 'number_2' => 2, 'number_3' => 3 )); $mapped = $this->coll->map(function($key, $value) { return $value * $value; }); $this->assertNotEquals($mapped, $this->coll); $this->assertEquals(array( 'number_1' => 1, 'number_2' => 4, 'number_3' => 9 ), $mapped->getAll()); } /** * @covers Guzzle\Common\Collection::offsetGet * @covers Guzzle\Common\Collection::offsetSet * @covers Guzzle\Common\Collection::offsetUnset * @covers Guzzle\Common\Collection::offsetExists */ public function testImplementsArrayAccess() { $this->coll->merge(array( 'k1' => 'v1', 'k2' => 'v2' )); $this->assertTrue($this->coll->offsetExists('k1')); $this->assertFalse($this->coll->offsetExists('Krull')); $this->coll->offsetSet('k3', 'v3'); $this->assertEquals('v3', $this->coll->offsetGet('k3')); $this->assertEquals('v3', $this->coll->get('k3')); $this->coll->offsetUnset('k1'); $this->assertFalse($this->coll->offsetExists('k1')); } /** * @covers Guzzle\Common\Collection::filter * @covers Guzzle\Common\Collection::map */ public function testUsesStaticWhenCreatingNew() { $qs = new QueryString(array( 'a' => 'b', 'c' => 'd' )); $this->assertInstanceOf('Guzzle\\Http\\QueryString', $qs->map(function($a, $b) {})); $this->assertInstanceOf('Guzzle\\Common\\Collection', $qs->map(function($a, $b) {}, array(), false)); $this->assertInstanceOf('Guzzle\\Http\\QueryString', $qs->filter(function($a, $b) {})); $this->assertInstanceOf('Guzzle\\Common\\Collection', $qs->filter(function($a, $b) {}, false)); } /** * @covers Guzzle\Common\Collection::replace */ public function testCanReplaceAllData() { $this->assertSame($this->coll, $this->coll->replace(array( 'a' => '123' ))); $this->assertEquals(array( 'a' => '123' ), $this->coll->getAll()); } }tests/Guzzle/Tests/Common/EventTest.php000064400000002771151742730640014172 0ustar00 '123', 'other' => '456', 'event' => 'test.notify' )); } /** * @covers Guzzle\Common\Event::__construct */ public function testAllowsParameterInjection() { $event = new Event(array( 'test' => '123' )); $this->assertEquals('123', $event['test']); } /** * @covers Guzzle\Common\Event::offsetGet * @covers Guzzle\Common\Event::offsetSet * @covers Guzzle\Common\Event::offsetUnset * @covers Guzzle\Common\Event::offsetExists */ public function testImplementsArrayAccess() { $event = $this->getEvent(); $this->assertEquals('123', $event['test']); $this->assertNull($event['foobar']); $this->assertTrue($event->offsetExists('test')); $this->assertFalse($event->offsetExists('foobar')); unset($event['test']); $this->assertFalse($event->offsetExists('test')); $event['test'] = 'new'; $this->assertEquals('new', $event['test']); } /** * @covers Guzzle\Common\Event::getIterator */ public function testImplementsIteratorAggregate() { $event = $this->getEvent(); $this->assertInstanceOf('ArrayIterator', $event->getIterator()); } }tests/Guzzle/Tests/Common/ExceptionCollectionTest.php000064400000002272151742730640017057 0ustar00getExceptions(); $e->add($exceptions[0]); $e->add($exceptions[1]); $this->assertEquals("Test\nTesting", $e->getMessage()); } public function testActsAsArray() { $e = new ExceptionCollection(); $exceptions = $this->getExceptions(); $e->add($exceptions[0]); $e->add($exceptions[1]); $this->assertEquals(2, count($e)); $this->assertEquals($exceptions, $e->getIterator()->getArrayCopy()); } public function testCanAddSelf() { $e1 = new ExceptionCollection(); $e1->add(new \Exception("Test")); $e2 = new ExceptionCollection(); $e2->add(new \Exception("Test 2")); $e1->add($e2); $this->assertEquals("Test\nTest 2", $e1->getMessage()); } }tests/Guzzle/Tests/Common/Log/ClosureLogAdapterTest.php000064400000002007151742730640017201 0ustar00adapter = new ClosureLogAdapter(function($message, $priority, $extras = null) use ($that) { $that->modified = array($message, $priority, $extras); }); $this->adapter->log('test', \LOG_NOTICE, 'localhost'); $this->assertEquals(array('test', \LOG_NOTICE, 'localhost'), $this->modified); } /** * @covers \Guzzle\Common\Log\ClosureLogAdapter * @expectedException InvalidArgumentException */ public function testThrowsExceptionWhenNotCallable() { $abc = 123; $this->adapter = new ClosureLogAdapter($abc); } }tests/Guzzle/Tests/Common/Log/MonologLogAdapterTest.php000064400000002034151742730640017177 0ustar00pushHandler(new TestHandler()); $adapter = new MonologLogAdapter($log); // Throws an exception $this->adapter = new MonologLogAdapter(new \stdClass()); } /** * @covers Guzzle\Common\Log\MonologLogAdapter::log */ public function testLogsMessagesToAdaptedObject() { $log = new Logger('test'); $handler = new TestHandler(); $log->pushHandler($handler); $adapter = new MonologLogAdapter($log); $adapter->log('test!', Logger::INFO); $this->assertTrue($handler->hasInfoRecords()); } } tests/Guzzle/Tests/Common/Log/ZendLogAdapterTest.php000064400000003647151742730640016500 0ustar00log = new Logger(new Stream('php://output')); $this->adapter = new ZendLogAdapter($this->log); } /** * @covers Guzzle\Common\Log\AbstractLogAdapter::__construct * @expectedException InvalidArgumentException */ public function testEnforcesType() { // A successful construction $this->adapter = new ZendLogAdapter($this->log, new Collection()); // Throws an exception $this->adapter = new ZendLogAdapter(new \stdClass()); } /** * @covers Guzzle\Common\Log\ZendLogAdapter::log * @outputBuffering enabled */ public function testLogsMessagesToAdaptedObject() { // Test without a priority $this->adapter->log('test', \LOG_NOTICE, 'guzzle.common.log.adapter.zend_log_adapter', 'localhost'); $this->assertEquals(1, substr_count(ob_get_contents(), 'test')); // Test with a priority $this->adapter->log('test', \LOG_ALERT); $this->assertEquals(2, substr_count(ob_get_contents(), 'test')); } /** * @covers Guzzle\Common\Log\AbstractLogAdapter::getLogObject */ public function testExposesAdaptedLogObject() { $this->assertEquals($this->log, $this->adapter->getLogObject()); } }tests/Guzzle/Tests/Common/NullObjectTest.php000064400000001771151742730640015151 0ustar00assertNull($nullObject->isItNull()); isset($nullObject->isNull); $this->assertNull($nullObject->isNull); $nullObject->isNull = 10; unset($nullObject->isNull); $this->assertNull($nullObject->offsetGet('a')); $nullObject['a'] = '123'; $this->assertFalse(isset($nullObject['a'])); $this->assertNull($nullObject['a']); $this->assertNull($nullObject->offsetUnset('a')); $this->assertNull($nullObject->count()); $this->assertNull($nullObject->key()); $this->assertNull($nullObject->next()); $this->assertNull($nullObject->rewind()); $this->assertNull($nullObject->valid()); $this->assertNull($nullObject->current()); } }tests/Guzzle/Tests/Common/StreamTest.php000064400000011605151742730640014340 0ustar00assertEquals($handle, $stream->getStream()); $this->assertTrue($stream->isReadable()); $this->assertTrue($stream->isWritable()); $this->assertTrue($stream->isLocal()); $this->assertTrue($stream->isSeekable()); $this->assertEquals('php', $stream->getWrapper()); $this->assertEquals('temp', $stream->getStreamType()); $this->assertEquals(4, $stream->getSize()); $this->assertEquals('php://temp', $stream->getUri()); $this->assertEquals(array(), $stream->getWrapperData()); $this->assertFalse($stream->isConsumed()); unset($stream); } /** * @covers Guzzle\Common\Stream::__destruct */ public function testStreamClosesHandleOnDestruct() { $handle = fopen('php://temp', 'r'); $stream = new Stream($handle); unset($stream); $this->assertFalse(is_resource($handle)); } /** * @covers Guzzle\Common\Stream::__toString */ public function testConvertsToString() { $handle = fopen('php://temp', 'w+'); fwrite($handle, 'data'); $stream = new Stream($handle); $this->assertEquals('data', (string)$stream); unset($stream); $handle = fopen(__DIR__ . '/../TestData/FileBody.txt', 'w'); $stream = new Stream($handle); $this->assertEquals('', (string)$stream); unset($stream); } /** * @covers Guzzle\Common\Stream::isConsumed */ public function testIsConsumed() { $handle = fopen('php://temp', 'w+'); fwrite($handle, 'data'); $stream = new Stream($handle); $this->assertFalse($stream->isConsumed()); $stream->read(4); $this->assertTrue($stream->isConsumed()); } /** * @covers Guzzle\Common\Stream::setSize * @covers Guzzle\Common\Stream::getSize */ public function testAllowsSettingManualSize() { $handle = fopen('php://temp', 'w+'); fwrite($handle, 'data'); $stream = new Stream($handle); $stream->setSize(10); $this->assertEquals(10, $stream->getSize()); unset($stream); } /** * @covers Guzzle\Common\Stream::read * @covers Guzzle\Common\Stream::write * @covers Guzzle\Common\Stream::seek * @covers Guzzle\Common\Stream::isReadable * @covers Guzzle\Common\Stream::isSeekable */ public function testWrapsStream() { $handle = fopen('php://temp', 'w+'); fwrite($handle, 'data'); $stream = new Stream($handle); $this->assertTrue($stream->isSeekable()); $this->assertTrue($stream->isReadable()); $this->assertTrue($stream->seek(0)); $this->assertEquals('da', $stream->read(2)); $this->assertEquals('ta', $stream->read(2)); $this->assertTrue($stream->seek(0)); $this->assertEquals('data', $stream->read(4)); $stream->write('_appended'); $stream->seek(0); $this->assertEquals('data_appended', $stream->read(13)); } /** * @covers Guzzle\Common\Stream::getSize * @covers Guzzle\Common\Stream::__construct */ public function testGetSize() { $size = filesize(__DIR__ . '/../../../bootstrap.php'); $handle = fopen(__DIR__ . '/../../../bootstrap.php', 'r'); $stream = new Stream($handle); $this->assertEquals($handle, $stream->getStream()); $this->assertEquals($size, $stream->getSize()); $this->assertEquals($size, $stream->getSize()); unset($stream); // Make sure that false is returned when the size cannot be determined $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Lenght: 0\r\n\r\n"); $handle = fopen('http://localhost:' . $this->getServer()->getPort(), 'r'); $stream = new Stream($handle); $this->assertEquals(false, $stream->getSize()); unset($stream); } /** * @covers Guzzle\Common\Stream::getMetaData */ public function testAbstractsMetaData() { $handle = fopen(__DIR__ . '/../../../bootstrap.php', 'r'); $stream = new Stream($handle); $this->assertEquals('plainfile', $stream->getMetaData('wrapper_type')); $this->assertEquals(null, $stream->getMetaData('wrapper_data')); $this->assertInternalType('array', $stream->getMetaData()); } }tests/Guzzle/Tests/Common/XmlElementTest.php000064400000004133151742730640015155 0ustar00'), 'Foo', '' . PHP_EOL . '' . PHP_EOL), array(new XmlElement(''), new XmlElement(''), '' . PHP_EOL . '' . PHP_EOL), array(new XmlElement(''), new XmlElement('123'), '' . PHP_EOL . '123' . PHP_EOL), array(new XmlElement(''), new XmlElement('123'), '' . PHP_EOL . '123' . PHP_EOL), array(new XmlElement(''), new XmlElement('123'), '' . PHP_EOL . '123' . PHP_EOL) ); } /** * @covers \Guzzle\Common\XmlElement::addChild * @dataProvider addElementProvider */ public function testAddsChildElementsUsingStringsOrSimpleXmlElements($orig, $add, $result) { $orig->addChild($add); $this->assertEquals($result, $orig->__toString()); } /** * @covers \Guzzle\Common\XmlElement::asFormattedXml */ public function testDisplaysXmlDataAsFormattedXmlString() { $elem = new XmlElement(''); $expected = '' . PHP_EOL . '' . PHP_EOL; $this->assertEquals($expected, $elem->asFormattedXml()); } /** * @covers \Guzzle\Common\XmlElement::__toString */ public function testAddsToStringMethodToSimpleXmlElement() { $elem = new XmlElement(''); $expected = '' . PHP_EOL . '' . PHP_EOL; $this->assertEquals($expected, $elem->__toString()); } }tests/Guzzle/Tests/GuzzleTest.php000064400000005430151742730640013134 0ustar00assertEquals($agent, Guzzle::getDefaultUserAgent()); // Get it from cache this time $this->assertEquals($agent, Guzzle::getDefaultUserAgent()); } /** * @covers Guzzle\Guzzle::getHttpDate */ public function testGetHttpDate() { $fmt = 'D, d M Y H:i:s \G\M\T'; $this->assertEquals(gmdate($fmt), Guzzle::getHttpDate('now')); $this->assertEquals(gmdate($fmt), Guzzle::getHttpDate(strtotime('now'))); $this->assertEquals(gmdate($fmt, strtotime('+1 day')), Guzzle::getHttpDate('+1 day')); } public function dataProvider() { return array( array('this_is_a_test', '{{ a }}_is_a_{{ b }}', array( 'a' => 'this', 'b' => 'test' )), array('this_is_a_test', '{{abc}}_is_a_{{ 0 }}', array( 'abc' => 'this', 0 => 'test' )), array('this_is_a_test', '{{ abc }}_is_{{ not_found }}a_{{ 0 }}', array( 'abc' => 'this', 0 => 'test' )), array('this_is_a_test', 'this_is_a_test', array( 'abc' => 'this' )), array('_is_a_', '{{ abc }}_is_{{ not_found }}a_{{ 0 }}', array()), ); } /** * @covers Guzzle\Guzzle::inject * @dataProvider dataProvider */ public function testInjectsConfigData($output, $input, $config) { $this->assertEquals($output, Guzzle::inject($input, new Collection($config))); } /** * @covers Guzzle\Guzzle::getCurlInfo */ public function testCachesCurlInfo() { Guzzle::reset(); $c = curl_version(); $info = Guzzle::getCurlInfo(); $this->assertInternalType('array', $info); $this->assertEquals(false, Guzzle::getCurlInfo('ewfewfewfe')); $this->assertEquals($c['version'], Guzzle::getCurlInfo('version')); $this->assertSame(Guzzle::getCurlInfo(), $info); } /** * @covers Guzzle\Guzzle::getCurlInfo * @covers Guzzle\Guzzle::reset */ public function testDeterminesIfCurlCanFollowLocation() { Guzzle::reset(); if (!ini_get('open_basedir')) { $this->assertTrue(Guzzle::getCurlInfo('follow_location')); } else { $this->assertFalse(Guzzle::getCurlInfo('follow_location')); } } }tests/Guzzle/Tests/GuzzleTestCase.php000064400000013655151742730640013740 0ustar00isRunning()) { self::$server->flush(); } else { self::$server->start(); } } catch (\Exception $e) { fwrite(STDERR, $e->getMessage()); } } return self::$server; } /** * Set the service builder to use for tests * * @param ServiceBuilder $builder Service builder */ public static function setServiceBuilder(ServiceBuilder $builder) { self::$serviceBuilder = $builder; } /** * Get a service builder object that can be used throughout the service tests * * @return ServiceBuilder */ public function getServiceBuilder() { if (!self::$serviceBuilder) { throw new RuntimeException('No service builder has been set via setServiceBuilder()'); } return self::$serviceBuilder; } /** * Check if an event dispatcher has a subscriber * * @param HasDispatcherInterface $dispatcher * @param EventSubscriberInterface $subscriber * * @return bool */ protected function hasSubscriber(HasDispatcherInterface $dispatcher, EventSubscriberInterface $subscriber) { $class = get_class($subscriber); $all = array_keys(call_user_func(array($class, 'getSubscribedEvents'))); foreach ($all as $i => $event) { foreach ($dispatcher->getEventDispatcher()->getListeners($event) as $e) { if ($e[0] === $subscriber) { unset($all[$i]); break; } } } return count($all) == 0; } /** * Get a wildcard observer for an event dispatcher * * @param HasEventDispatcherInterface $hasEvent * * @return MockObserver */ public function getWildcardObserver(HasDispatcherInterface $hasDispatcher) { $class = get_class($hasDispatcher); $o = new MockObserver(); $events = call_user_func(array($class, 'getAllEvents')); foreach ($events as $event) { $hasDispatcher->getEventDispatcher()->addListener($event, array($o, 'update')); } return $o; } /** * Set the mock response base path * * @param string $path Path to mock response folder * * @return GuzzleTestCase */ public static function setMockBasePath($path) { self::$mockBasePath = $path; } /** * Mark a request as being mocked * * @param RequestInterface $request */ public function addMockedRequest(RequestInterface $request) { $this->requests[] = $request; return $this; } /** * Get all of the mocked requests * * @return array */ public function getMockedRequests() { return $this->requests; } /** * Get a mock response for a client by mock file name * * @param string $path Relative path to the mock response file * * @return Response */ public function getMockResponse($path) { return MockPlugin::getMockFile(self::$mockBasePath . DIRECTORY_SEPARATOR . $path); } /** * Set a mock response from a mock file on the next client request. * * This method assumes that mock response files are located under the * Command/Mock/ directory of the Service being tested * (e.g. Unfuddle/Command/Mock/). A mock response is added to the next * request sent by the client. * * @param Client $client Client object to modify * @param string $paths Path to files within the Mock folder of the service */ public function setMockResponse(Client $client, $paths) { $this->requests = array(); $that = $this; $mock = new MockPlugin(null, true); $mock->getEventDispatcher()->addListener('mock.request', function(Event $event) use ($that) { $that->addMockedRequest($event['request']); }); foreach ((array) $paths as $path) { $mock->addResponse($this->getMockResponse($path)); } $client->getEventDispatcher()->addSubscriber($mock); } /** * Check if an array of HTTP headers matches another array of HTTP headers * while taking * into account as a wildcard for header values * * @param array $actual Actual HTTP header array * @param array $expected Expected HTTP headers (allows wildcard values) * * @return array|false Returns an array of the differences or FALSE if none */ public function compareHttpHeaders(array $expected, array $actual) { $differences = array(); foreach ($actual as $key => $value) { if (!isset($expected[$key]) || ($expected[$key] != '*' && $actual[$key] != $expected[$key])) { $differences[$key] = $value; } } return empty($differences) ? false : $differences; } }tests/Guzzle/Tests/Http/ClientTest.php000064400000035306151742730640014016 0ustar00assertEquals('http://www.google.com/', $client->getBaseUrl()); $this->assertSame($client, $client->setConfig(array( 'test' => '123' ))); $this->assertEquals(array('test' => '123'), $client->getConfig()->getAll()); $this->assertEquals('123', $client->getConfig('test')); $this->assertSame($client, $client->setBaseUrl('http://www.test.com/{{test}}')); $this->assertEquals('http://www.test.com/123', $client->getBaseUrl()); $this->assertEquals('http://www.test.com/{{test}}', $client->getBaseUrl(false)); try { $client->setConfig(false); } catch (\InvalidArgumentException $e) { } } /** * @covers Guzzle\Http\Client::getAllEvents */ public function testDescribesEvents() { $this->assertEquals(array('client.create_request'), Client::getAllEvents()); } /** * @covers Guzzle\Http\Client::__toString */ public function testConvertsToString() { $client = new Client(); $hash = spl_object_hash($client); $this->assertEquals($hash, (string) $client); } /** * @covers Guzzle\Http\Client::__construct */ public function testConstructorCanAcceptConfig() { $client = new Client('http://www.test.com/', array( 'data' => '123' )); $this->assertEquals('123', $client->getConfig('data')); } /** * @covers Guzzle\Http\Client::setConfig */ public function testCanUseCollectionAsConfig() { $client = new Client('http://www.google.com/'); $client->setConfig(new Collection(array( 'api' => 'v1', 'key' => 'value', 'base_url' => 'http://www.google.com/' ))); $this->assertEquals('v1', $client->getConfig('api')); } /** * @covers Guzzle\Http\Client */ public function testInjectConfig() { $client = new Client('http://www.google.com/'); $client->setConfig(array( 'api' => 'v1', 'key' => 'value', 'foo' => 'bar' )); $this->assertEquals('Testing...api/v1/key/value', $client->inject('Testing...api/{{api}}/key/{{key}}')); // Make sure that the client properly validates and injects config $this->assertEquals('bar', $client->getConfig('foo')); } /** * @covers Guzzle\Http\Client::__construct * @covers Guzzle\Http\Client::createRequest */ public function testClientAttachersObserversToRequests() { $this->getServer()->flush(); $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"); $client = new Client($this->getServer()->getUrl()); $logPlugin = $this->getLogPlugin(); $client->getEventDispatcher()->addSubscriber($logPlugin); // Get a request from the client and ensure the the observer was // attached to the new request $request = $client->createRequest(); $this->assertTrue($this->hasSubscriber($request, $logPlugin)); } /** * @covers Guzzle\Http\Client::getBaseUrl * @covers Guzzle\Http\Client::setBaseUrl */ public function testClientReturnsValidBaseUrls() { $client = new Client('http://www.{{foo}}.{{data}}/', array( 'data' => '123', 'foo' => 'bar' )); $this->assertEquals('http://www.bar.123/', $client->getBaseUrl()); $client->setBaseUrl('http://www.google.com/'); $this->assertEquals('http://www.google.com/', $client->getBaseUrl()); } /** * @covers Guzzle\Http\Client::setUserAgent * @covers Guzzle\Http\Client::createRequest * @covers Guzzle\Http\Client::prepareRequest */ public function testSetsUserAgent() { $client = new Client('http://www.test.com/', array( 'api' => 'v1' )); $this->assertSame($client, $client->setUserAgent('Test/1.0Ab', true)); $this->assertEquals('Test/1.0Ab ' . Guzzle::getDefaultUserAgent(), $client->get()->getHeader('User-Agent')); $client->setUserAgent('Test/1.0Ab'); $this->assertEquals('Test/1.0Ab', $client->get()->getHeader('User-Agent')); } /** * @covers Guzzle\Http\Client::createRequest * @covers Guzzle\Http\Client::prepareRequest */ public function testClientAddsCurlOptionsToRequests() { $client = new Client('http://www.test.com/', array( 'api' => 'v1', // Adds the option using the curl values 'curl.CURLOPT_HTTPAUTH' => 'CURLAUTH_DIGEST', 'curl.abc' => 'not added' )); $request = $client->createRequest(); $options = $request->getCurlOptions(); $this->assertEquals(CURLAUTH_DIGEST, $options->get(CURLOPT_HTTPAUTH)); $this->assertNull($options->get('curl.abc')); } /** * @covers Guzzle\Http\Client::createRequest * @covers Guzzle\Http\Client::prepareRequest */ public function testClientAddsCacheKeyFiltersToRequests() { $client = new Client('http://www.test.com/', array( 'api' => 'v1', 'cache.key_filter' => 'query=Date' )); $request = $client->createRequest(); $this->assertEquals('query=Date', $request->getParams()->get('cache.key_filter')); } /** * @covers Guzzle\Http\Client::prepareRequest */ public function testPreparesRequestsNotCreatedByTheClient() { $exp = new ExponentialBackoffPlugin(); $client = new Client($this->getServer()->getUrl()); $client->getEventDispatcher()->addSubscriber($exp); $request = RequestFactory::create('GET', $client->getBaseUrl()); $this->assertSame($request, $client->prepareRequest($request)); $this->assertTrue($this->hasSubscriber($request, $exp)); } public function urlProvider() { $u = $this->getServer()->getUrl() . 'base/'; $u2 = $this->getServer()->getUrl() . 'base?z=1'; return array( array($u, '', $u), array($u, 'relative/path/to/resource', $u . 'relative/path/to/resource'), array($u, 'relative/path/to/resource?a=b&c=d', $u . 'relative/path/to/resource?a=b&c=d'), array($u, '/absolute/path/to/resource', $this->getServer()->getUrl() . 'absolute/path/to/resource'), array($u, '/absolute/path/to/resource?a=b&c=d', $this->getServer()->getUrl() . 'absolute/path/to/resource?a=b&c=d'), array($u2, '/absolute/path/to/resource?a=b&c=d', $this->getServer()->getUrl() . 'absolute/path/to/resource?a=b&c=d'), array($u2, 'relative/path/to/resource', $this->getServer()->getUrl() . 'base/relative/path/to/resource?z=1'), array($u2, 'relative/path/to/resource?another=query', $this->getServer()->getUrl() . 'base/relative/path/to/resource?z=1&another=query') ); } /** * @dataProvider urlProvider * @covers Guzzle\Http\Client::createRequest */ public function testBuildsRelativeUrls($baseUrl, $url, $result) { $client = new Client($baseUrl); $this->assertEquals($client->get($url)->getUrl(), $result); } /** * @covers Guzzle\Http\Client */ public function testAllowsConfigsToBeChangedAndInjectedInBaseUrl() { $client = new Client('http://{{a}}/{{b}}'); $this->assertEquals('http:///', $client->getBaseUrl()); $this->assertEquals('http://{{a}}/{{b}}', $client->getBaseUrl(false)); $client->setConfig(array( 'a' => 'test.com', 'b' => 'index.html' )); $this->assertEquals('http://test.com/index.html', $client->getBaseUrl()); } /** * @covers Guzzle\Http\Client::createRequest */ public function testCreatesRequestsWithDefaultValues() { $client = new Client($this->getServer()->getUrl() . 'base'); // Create a GET request $request = $client->createRequest(); $this->assertEquals('GET', $request->getMethod()); $this->assertEquals($client->getBaseUrl(), $request->getUrl()); // Create a DELETE request $request = $client->createRequest('DELETE'); $this->assertEquals('DELETE', $request->getMethod()); $this->assertEquals($client->getBaseUrl(), $request->getUrl()); // Create a HEAD request with custom headers $request = $client->createRequest('HEAD', 'http://www.test.com/'); $this->assertEquals('HEAD', $request->getMethod()); $this->assertEquals('http://www.test.com/', $request->getUrl()); // Create a PUT request $request = $client->createRequest('PUT'); $this->assertEquals('PUT', $request->getMethod()); // Create a PUT request with injected config $client->getConfig()->set('a', 1)->set('b', 2); $request = $client->createRequest('PUT', '/path/{{a}}?q={{b}}'); $this->assertEquals($request->getUrl(), $this->getServer()->getUrl() . 'path/1?q=2'); } /** * @covers Guzzle\Http\Client::get * @covers Guzzle\Http\Client::delete * @covers Guzzle\Http\Client::head * @covers Guzzle\Http\Client::put * @covers Guzzle\Http\Client::post * @covers Guzzle\Http\Client::options */ public function testClientHasHelperMethodsForCreatingRequests() { $url = $this->getServer()->getUrl(); $client = new Client($url . 'base'); $this->assertEquals('GET', $client->get()->getMethod()); $this->assertEquals('PUT', $client->put()->getMethod()); $this->assertEquals('POST', $client->post()->getMethod()); $this->assertEquals('HEAD', $client->head()->getMethod()); $this->assertEquals('DELETE', $client->delete()->getMethod()); $this->assertEquals('OPTIONS', $client->options()->getMethod()); $this->assertEquals($url . 'base/abc', $client->get('abc')->getUrl()); $this->assertEquals($url . 'zxy', $client->put('/zxy')->getUrl()); $this->assertEquals($url . 'zxy?a=b', $client->post('/zxy?a=b')->getUrl()); $this->assertEquals($url . 'base?a=b', $client->head('?a=b')->getUrl()); $this->assertEquals($url . 'base?a=b', $client->delete('/base?a=b')->getUrl()); } /** * @covers Guzzle\Http\Client::createRequest */ public function testClientInjectsConfigsIntoUrls() { $client = new Client('http://www.test.com/api/v1', array( 'test' => '123' )); $request = $client->get('relative/{{test}}'); $this->assertEquals('http://www.test.com/api/v1/relative/123', $request->getUrl()); } /** * @covers Guzzle\Http\Client */ public function testAllowsEmptyBaseUrl() { $client = new Client(); $request = $client->get('http://www.google.com/'); $this->assertEquals('http://www.google.com/', $request->getUrl()); $request->setResponse(new Response(200), true); $request->send(); } /** * @covers Guzzle\Http\Client::send * @covers Guzzle\Http\Client::setCurlMulti * @covers Guzzle\Http\Client::getCurlMulti */ public function testAllowsCustomCurlMultiObjects() { $mock = $this->getMock('Guzzle\\Http\\Curl\\CurlMulti', array('add', 'send')); $mock->expects($this->once()) ->method('add'); $mock->expects($this->once()) ->method('send'); $client = new Client(); $client->setCurlMulti($mock); $request = $client->get(); $request->setResponse(new Response(200), true); $client->send($request); } /** * @covers Guzzle\Http\Client::send */ public function testClientSendsMultipleRequests() { $client = new Client($this->getServer()->getUrl()); $mock = new MockPlugin(); $responses = array( new Response(200), new Response(201), new Response(202) ); $mock->addResponse($responses[0]); $mock->addResponse($responses[1]); $mock->addResponse($responses[2]); $client->getEventDispatcher()->addSubscriber($mock); $requests = array( $client->get(), $client->head(), $client->put('/', null, 'test') ); $this->assertEquals(array( $responses[0], $responses[1], $responses[2] ), $client->send($requests)); } /** * @covers Guzzle\Http\Client::send */ public function testClientSendsSingleRequest() { $client = new Client($this->getServer()->getUrl()); $mock = new MockPlugin(); $response = new Response(200); $mock->addResponse($response); $client->getEventDispatcher()->addSubscriber($mock); $this->assertEquals($response, $client->send($client->get())); } /** * @covers Guzzle\Http\Client::send * @expectedException Guzzle\Http\Message\BadResponseException */ public function testClientThrowsExceptionForSingleRequest() { $client = new Client($this->getServer()->getUrl()); $mock = new MockPlugin(); $response = new Response(404); $mock->addResponse($response); $client->getEventDispatcher()->addSubscriber($mock); $client->send($client->get()); } /** * @covers Guzzle\Http\Client::send * @expectedException Guzzle\Common\ExceptionCollection */ public function testClientThrowsExceptionForMultipleRequests() { $client = new Client($this->getServer()->getUrl()); $mock = new MockPlugin(); $mock->addResponse(new Response(200)); $mock->addResponse(new Response(404)); $client->getEventDispatcher()->addSubscriber($mock); $client->send(array($client->get(), $client->head())); } }tests/Guzzle/Tests/Http/CookieJar/ArrayCookieJarTest.php000064400000027305151742730640017313 0ustar00jar = new ArrayCookieJar(); } /** * Add values to the cookiejar */ public static function addCookies(CookieJarInterface $jar) { $jar->save(array( 'cookie' => array('foo', 'bar'), 'domain' => 'example.com', 'path' => '/', 'max_age' => '86400', 'port' => array(80, 8080), 'version' => '1', 'secure' => true ))->save(array( 'cookie' => array('baz', 'foobar'), 'domain' => 'example.com', 'path' => '/', 'max_age' => '86400', 'port' => array(80, 8080), 'version' => '1', 'secure' => true ))->save(array( 'cookie' => array('test', '123'), 'domain' => 'www.foobar.com', 'path' => '/path/', 'discard' => true ))->save(array( 'domain' => '.y.example.com', 'path' => '/acme/', 'cookie' => array('muppet', 'cookie_monster'), 'comment' => 'Comment goes here...', 'expires' => Guzzle::getHttpDate('+1 day') ))->save(array( 'domain' => '.example.com', 'path' => '/test/acme/', 'cookie' => array('googoo', 'gaga'), 'max_age' => 1500, 'version' => 2 )); } /** * Provides test data for cookie jar retrieval */ public function getCookiesDataProvider() { return array( array(array('foo', 'baz', 'test', 'muppet', 'googoo'), '', '', '', false), array(array('foo', 'baz', 'muppet', 'googoo'), '', '', '', true), array(array('googoo'), 'www.example.com', '', '', false), array(array('muppet', 'googoo'), 'test.y.example.com', '', '', false), array(array('foo', 'baz'), 'example.com', '', '', false), array(array('muppet'), 'x.y.example.com', '/acme/', '', false), array(array('muppet'), 'x.y.example.com', '/acme/test/', '', false), array(array('googoo'), 'x.y.example.com', '/test/acme/test/', '', false), array(array('foo', 'baz'), 'example.com', '', '', false), array(array('baz'), 'example.com', '', 'baz', false), ); } /** * @covers Guzzle\Http\CookieJar\ArrayCookieJar */ public function testStoresAndRetrievesCookies() { $j = $this->jar; $this->assertSame($j, $j->save(array( 'cookie' => array('foo', 'bar'), 'domain' => '.example.com', 'path' => '/', 'max_age' => '86400', 'port' => array(80, 8080), 'version' => '1', 'secure' => true ))); $this->assertSame($j, $j->save(array( 'cookie' => array('baz', 'foobar'), 'domain' => '.example.com', 'path' => '/', 'max_age' => '86400', 'port' => array(80, 8080), 'version' => '1', 'secure' => true ))); $this->assertSame($j, $j->save(array( 'cookie' => array('test', '123'), 'domain' => 'www.foobar.com', 'path' => '/path/' ))); $this->assertEquals(array( array ( 'cookie' => array('foo', 'bar'), 'domain' => '.example.com', 'path' => '/', 'max_age' => '86400', 'port' => array(80, 8080), 'version' => '1', 'secure' => true, 'expires' => time() + 86400, 'comment' => NULL, 'comment_url' => NULL, 'discard' => NULL, 'http_only' => false ), array ( 'cookie' => array('baz', 'foobar'), 'domain' => '.example.com', 'path' => '/', 'max_age' => '86400', 'port' => array( 0 => 80, 1 => 8080, ), 'version' => '1', 'secure' => true, 'expires' => time() + 86400, 'comment' => NULL, 'comment_url' => NULL, 'discard' => NULL, 'http_only' => false ), array ( 'cookie' => array('test' , '123'), 'domain' => 'www.foobar.com', 'path' => '/path/', 'max_age' => 0, 'comment' => NULL, 'comment_url' => NULL, 'port' => array (), 'secure' => NULL, 'expires' => null, 'discard' => NULL, 'version' => null, 'http_only' => false ), ), $j->getCookies()); } /** * Checks if cookies (by name) are present in a cookieJar * * @param array $cookies Cookies from the cookie jar * @param array $names Names to check for * * @return true */ protected function hasCookies(array $cookies, array $names) { $remaining = $names; $extra = array(); foreach ($cookies as $cookie) { $match = false; foreach ($remaining as $ri => $c) { if ($cookie['cookie'][0] == $c) { unset($remaining[$ri]); $match = true; } } if (!$match) { $extra[] = $cookie['cookie'][0] . '=' . $cookie['cookie'][1]; } } $this->assertTrue(count($remaining) == 0 && count($extra) == 0, 'Unmatched: ' . implode(', ', $remaining) . ' | Extra: ' . implode(', ', $extra)); } /** * @covers Guzzle\Http\CookieJar\ArrayCookieJar * @dataProvider getCookiesDataProvider */ public function testGetCookies(array $matches, $domain = null, $path = null, $name = null, $skipDiscardable = false) { self::addCookies($this->jar); $cookies = $this->jar->getCookies($domain, $path, $name, $skipDiscardable); $this->hasCookies($cookies, $matches); } /** * @covers Guzzle\Http\CookieJar\ArrayCookieJar */ public function testClearsTemporaryCookies() { self::addCookies($this->jar); $this->assertEquals(1, $this->jar->clearTemporary()); $this->hasCookies($this->jar->getCookies(), array('foo', 'baz', 'muppet', 'googoo')); // Doesn't clear anything out because nothing is temporary $this->assertEquals(0, $this->jar->clearTemporary()); // Add an expired cookie $this->jar->save(array( 'cookie' => array('data', 'abc'), 'domain' => '.example.com' )); // Filters out expired cookies $this->hasCookies($this->jar->getCookies(), array('foo', 'baz', 'muppet', 'googoo', 'data')); // Removes the expired cookie $this->assertEquals(1, $this->jar->clearTemporary()); $this->hasCookies($this->jar->getCookies(), array('foo', 'baz', 'muppet', 'googoo')); } /** * @covers Guzzle\Http\CookieJar\ArrayCookieJar */ public function testClearsExpiredCookies() { self::addCookies($this->jar); $this->assertEquals(0, $this->jar->deleteExpired()); // Add an expired cookie $this->jar->save(array( 'cookie' => array('data', 'abc'), 'expires' => Guzzle::getHttpDate('-1 day'), 'domain' => '.example.com' )); // Filters out expired cookies $this->hasCookies($this->jar->getCookies(), array('foo', 'baz', 'test', 'muppet', 'googoo')); $this->assertEquals(1, $this->jar->deleteExpired()); $this->assertEquals(0, $this->jar->deleteExpired()); } /** * @covers Guzzle\Http\CookieJar\ArrayCookieJar * @expectedException InvalidArgumentException * @expectedExceptionMessage Cookies require a domain */ public function testValidatesDomainWhenSaving() { $this->jar->save(array()); } /** * @covers Guzzle\Http\CookieJar\ArrayCookieJar * @expectedException InvalidArgumentException * @expectedExceptionMessage Cookies require a names and values */ public function testValidatesCookiesArePresentWhenSaving() { $this->jar->save(array( 'domain' => '.test.com' )); } /** * Provides test data for cookie jar clearing */ public function clearCookiesDataProvider() { return array( array(array(), 4, '', '', '', ''), array(array('test', 'muppet', 'googoo'), 1, 'example.com', '', ''), array(array('foo', 'baz', 'test'), 2, 'a.y.example.com', '', ''), array(array('foo', 'baz', 'test', 'googoo'), 1, 'a.y.example.com', '/acme/', ''), // Removes only baz from the cookie that contains two values array(array('test', 'muppet', 'googoo', 'foo'), 1, 'example.com', '/', 'baz'), array(array('foo', 'baz', 'test', 'muppet'), 1, 'www.example.com', '/test/acme/', '') ); } /** * @covers Guzzle\Http\CookieJar\ArrayCookieJar * @dataProvider clearCookiesDataProvider */ public function testClearsCookies($matches, $total, $domain, $path, $name) { self::addCookies($this->jar); $this->jar->clear($domain, $path, $name); $this->hasCookies($this->jar->getCookies(null, null, null, null, false, true), $matches); } /** * @covers Guzzle\Http\CookieJar\ArrayCookieJar */ public function testDoesNotAddDuplicates() { $this->jar->clear(); $this->assertEquals(0, count($this->jar->getCookies())); $data = array( 'cookie' => array('foo', 'bar'), 'domain' => '.example.com', 'path' => '/', 'max_age' => '86400', 'port' => array(80, 8080), 'version' => '1', 'secure' => true ); $this->jar->save($data); $this->jar->save($data); $this->assertEquals(1, count($this->jar->getCookies())); } /** * @covers Guzzle\Http\CookieJar\ArrayCookieJar */ public function testOverwritesCookiesThatAreOlderOrDiscardable() { $this->jar->clear(); $t = time() + 1000; $data = array( 'cookie' => array('foo', 'bar'), 'domain' => '.example.com', 'path' => '/', 'max_age' => '86400', 'port' => array(80, 8080), 'version' => '1', 'secure' => true, 'discard' => true, 'expires' => $t ); // Make sure that the discard cookie is overridden with the non-discard $this->jar->save($data); unset($data['discard']); $this->jar->save($data); $this->assertEquals(1, count($this->jar->getCookies())); $c = $this->jar->getCookies(); $this->assertEquals(false, $c[0]['discard']); $this->assertEquals($t, $c[0]['expires']); // Make sure it doesn't duplicate the cookie $this->jar->save($data); $this->assertEquals(1, count($this->jar->getCookies())); // Make sure the more future-ful expiration date supercedes the other $data['expires'] = time() + 2000; $this->jar->save($data); $this->assertEquals(1, count($this->jar->getCookies())); $c = $this->jar->getCookies(); $this->assertNotEquals($t, $c[0]['expires']); } }tests/Guzzle/Tests/Http/CookieJar/FileCookieJarTest.php000064400000004712151742730640017111 0ustar00file = tempnam('/tmp', 'file-cookies'); $this->jar = new FileCookieJar($this->file); } /** * Add values to the cookiejar */ protected function addCookies() { $this->jar->save(array( 'cookie' => array('foo', 'bar'), 'domain' => 'example.com', 'path' => '/', 'max_age' => '86400', 'port' => array(80, 8080), 'version' => '1', 'secure' => true ))->save(array( 'cookie' => array('test', '123'), 'domain' => 'www.foobar.com', 'path' => '/path/', 'discard' => true ))->save(array( 'domain' => '.y.example.com', 'path' => '/acme/', 'cookie' => array('muppet', 'cookie_monster'), 'comment' => 'Comment goes here...', 'expires' => Guzzle::getHttpDate('+1 day') ))->save(array( 'domain' => '.example.com', 'path' => '/test/acme/', 'cookie' => array('googoo', 'gaga'), 'max_age' => 1500, 'version' => 2 )); } /** * @covers Guzzle\Http\CookieJar\FileCookieJar */ public function testLoadsFromFileFile() { unset($this->jar); $this->jar = new FileCookieJar($this->file); $this->assertEquals(array(), $this->jar->getCookies()); unlink($this->file); } /** * @covers Guzzle\Http\CookieJar\FileCookieJar */ public function testPersistsToFileFile() { unset($this->jar); $this->jar = new FileCookieJar($this->file); $this->addCookies(); $this->assertEquals(4, count($this->jar->getCookies())); unset($this->jar); // Make sure it wrote to the file $contents = file_get_contents($this->file); $this->assertNotEmpty($contents); // Load the jar from the file $jar = new FileCookieJar($this->file); // Weeds out temporary and session cookies $this->assertEquals(3, count($jar->getCookies())); unset($jar); unlink($this->file); } }tests/Guzzle/Tests/Http/CookieTest.php000064400000003726151742730640014012 0ustar00 'value' )), array('name=value;name2=value 2', array( 'name' => 'value', 'name2' => 'value 2' )), array('name=value;name2=x=y&a=b', array( 'name' => 'value', 'name2' => 'x=y&a=b' )), ); } /** * @covers Guzzle\Http\Cookie::factory * @dataProvider provider */ public function testFactoryBuildsCookiesFromCookieStrings($cookieString, array $data) { $jar = Cookie::factory($cookieString); $this->assertEquals($data, $jar->getAll()); } /** * @covers Guzzle\Http\Cookie::__construct */ public function testConstructorSetsDefaults() { $jar = new Cookie(); $this->assertEquals(';', $jar->getFieldSeparator()); $this->assertEquals('=', $jar->getValueSeparator()); $this->assertEquals(false, $jar->isEncodingFields()); $this->assertEquals(false, $jar->isEncodingValues()); $this->assertEquals('', $jar->getPrefix()); } /** * @covers Guzzle\Http\QueryString::__toString * @dataProvider provider */ public function testConvertsToString($cookieString) { $cookie = Cookie::factory($cookieString); $this->assertEquals($cookieString, (string) $cookie); } /** * @covers Guzzle\Http\QueryString * @covers Guzzle\Http\Cookie */ public function testAggregatesMultipleCookieValues() { $cookie = Cookie::factory('name=a;name=b'); $this->assertEquals(array('a', 'b'), $cookie->get('name')); $this->assertEquals('name=a;name=b', (string) $cookie); } }tests/Guzzle/Tests/Http/Curl/CurlExceptionTest.php000064400000001022151742730640016255 0ustar00assertNull($e->getError()); $this->assertNull($e->getErrorNo()); $this->assertSame($e, $e->setError('test', 12)); $this->assertEquals('test', $e->getError()); $this->assertEquals(12, $e->getErrorNo()); } }tests/Guzzle/Tests/Http/Curl/CurlHandleTest.php000064400000044401151742730640015522 0ustar00getServer()->getUrl()); try { $ha = new CurlHandle($h, false); $this->fail('Expected InvalidArgumentException'); } catch (\InvalidArgumentException $e) { } $ha = new CurlHandle($h, array( CURLOPT_URL => $this->getServer()->getUrl() )); $this->assertEquals($this->getServer()->getUrl(), $ha->getOptions()->get(CURLOPT_URL)); $ha = new CurlHandle($h, new Collection(array( CURLOPT_URL => $this->getServer()->getUrl() ))); $this->assertEquals($this->getServer()->getUrl(), $ha->getOptions()->get(CURLOPT_URL)); } /** * @covers Guzzle\Http\Curl\CurlHandle::__construct * @covers Guzzle\Http\Curl\CurlHandle::getHandle * @covers Guzzle\Http\Curl\CurlHandle::getUrl * @covers Guzzle\Http\Curl\CurlHandle::getOptions */ public function testConstructorInitializesObject() { $handle = curl_init($this->getServer()->getUrl()); $h = new CurlHandle($handle, array( CURLOPT_URL => $this->getServer()->getUrl() )); $this->assertSame($handle, $h->getHandle()); $this->assertInstanceOf('Guzzle\\Http\\Url', $h->getUrl()); $this->assertEquals($this->getServer()->getUrl(), (string) $h->getUrl()); $this->assertEquals($this->getServer()->getUrl(), $h->getOptions()->get(CURLOPT_URL)); } /** * @covers Guzzle\Http\Curl\CurlHandle::getStderr */ public function testStoresStdErr() { $h = CurlHandle::factory(RequestFactory::create('GET', 'http://test.com')); $this->assertEquals($h->getStderr(true), $h->getOptions()->get(CURLOPT_STDERR)); $this->assertInternalType('resource', $h->getStderr(true)); $this->assertInternalType('string', $h->getStderr(false)); $r = $h->getStderr(true); fwrite($r, 'test'); $this->assertEquals('test', $h->getStderr(false)); } /** * @covers Guzzle\Http\Curl\CurlHandle::setErrorNo * @covers Guzzle\Http\Curl\CurlHandle::getErrorNo */ public function testStoresCurlErrorNumber() { $h = new CurlHandle(curl_init('http://test.com'), array(CURLOPT_URL => 'http://test.com')); $this->assertEquals(CURLE_OK, $h->getErrorNo()); $h->setErrorNo(CURLE_OPERATION_TIMEOUTED); $this->assertEquals(CURLE_OPERATION_TIMEOUTED, $h->getErrorNo()); } /** * @covers Guzzle\Http\Curl\CurlHandle::getStderr */ public function testAccountsForMissingStdErr() { $handle = curl_init('http://www.test.com/'); $h = new CurlHandle($handle, array( CURLOPT_URL => 'http://www.test.com/' )); $this->assertNull($h->getStderr(false)); } /** * @covers Guzzle\Http\Curl\CurlHandle::isAvailable */ public function testDeterminesIfResourceIsAvailable() { $handle = curl_init($this->getServer()->getUrl()); $h = new CurlHandle($handle, array()); $this->assertTrue($h->isAvailable()); // Mess it up by closing the handle curl_close($handle); $this->assertFalse($h->isAvailable()); // Mess it up by unsetting the handle $handle = null; $this->assertFalse($h->isAvailable()); } /** * @covers Guzzle\Http\Curl\CurlHandle::getError * @covers Guzzle\Http\Curl\CurlHandle::getErrorNo * @covers Guzzle\Http\Curl\CurlHandle::getInfo */ public function testWrapsErrorsAndInfo() { if (!defined('CURLOPT_TIMEOUT_MS')) { $this->markTestSkipped('Update curl'); } $handle = curl_init($this->getServer()->getUrl()); curl_setopt($handle, CURLOPT_TIMEOUT_MS, 1); $h = new CurlHandle($handle, array( CURLOPT_TIMEOUT_MS => 1 )); @curl_exec($handle); $this->assertEquals('Timeout was reached', $h->getError()); $this->assertEquals(CURLE_OPERATION_TIMEOUTED, $h->getErrorNo()); $this->assertEquals($this->getServer()->getUrl(), $h->getInfo(CURLINFO_EFFECTIVE_URL)); $this->assertInternalType('array', $h->getInfo()); curl_close($handle); $this->assertEquals(null, $h->getInfo('url')); } /** * @covers Guzzle\Http\Curl\CurlHandle::getOptions */ public function testWrapsCurlOptions() { $handle = curl_init($this->getServer()->getUrl()); $h = new CurlHandle($handle, array( CURLOPT_AUTOREFERER => true, CURLOPT_BUFFERSIZE => 1024 )); $this->assertEquals(true, $h->getOptions()->get(CURLOPT_AUTOREFERER)); $this->assertEquals(1024, $h->getOptions()->get(CURLOPT_BUFFERSIZE)); } /** * Data provider for factory tests * * @return array */ public function dataProvider() { $postBody = new QueryString(array( 'file' => '@' . __DIR__ . '/../../../../../phpunit.xml' )); $qs = new QueryString(array( 'x' => 'y', 'z' => 'a' )); $userAgent = Guzzle::getDefaultUserAgent(); $auth = base64_encode('michael:123'); return array( array('GET', 'http://www.google.com/', null, null, array( CURLOPT_RETURNTRANSFER => 0, CURLOPT_HEADER => 0, CURLOPT_FOLLOWLOCATION => 1, CURLOPT_MAXREDIRS => 5, CURLOPT_CONNECTTIMEOUT => 10, CURLOPT_USERAGENT => $userAgent, CURLOPT_WRITEFUNCTION => 'callback', CURLOPT_HEADERFUNCTION => 'callback', CURLOPT_PROGRESSFUNCTION => 'callback', CURLOPT_NOPROGRESS => 0, CURLOPT_ENCODING => '', CURLOPT_HTTPHEADER => array('Host: www.google.com', 'User-Agent: ' . $userAgent), )), // Test that custom request methods can be used array('TRACE', 'http://www.google.com/', null, null, array( CURLOPT_CUSTOMREQUEST => 'TRACE' )), array('GET', 'http://127.0.0.1:8080', null, null, array( CURLOPT_RETURNTRANSFER => 0, CURLOPT_HEADER => 0, CURLOPT_FOLLOWLOCATION => 1, CURLOPT_MAXREDIRS => 5, CURLOPT_CONNECTTIMEOUT => 10, CURLOPT_USERAGENT => $userAgent, CURLOPT_WRITEFUNCTION => 'callback', CURLOPT_HEADERFUNCTION => 'callback', CURLOPT_PROGRESSFUNCTION => 'callback', CURLOPT_NOPROGRESS => 0, CURLOPT_ENCODING => '', CURLOPT_PORT => 8080, CURLOPT_HTTPHEADER => array('Host: 127.0.0.1:8080', 'User-Agent: ' . $userAgent), )), array('HEAD', 'http://www.google.com/', null, null, array( CURLOPT_RETURNTRANSFER => 0, CURLOPT_HEADER => 0, CURLOPT_FOLLOWLOCATION => 1, CURLOPT_MAXREDIRS => 5, CURLOPT_CONNECTTIMEOUT => 10, CURLOPT_USERAGENT => $userAgent, CURLOPT_WRITEFUNCTION => 'callback', CURLOPT_HEADERFUNCTION => 'callback', CURLOPT_PROGRESSFUNCTION => 'callback', CURLOPT_NOPROGRESS => 0, CURLOPT_ENCODING => '', CURLOPT_HTTPHEADER => array('Host: www.google.com', 'User-Agent: ' . $userAgent), CURLOPT_CUSTOMREQUEST => 'HEAD', CURLOPT_NOBODY => 1 )), array('GET', 'https://michael:123@www.guzzle-project.com/index.html?q=2', null, null, array( CURLOPT_RETURNTRANSFER => 0, CURLOPT_HEADER => 0, CURLOPT_FOLLOWLOCATION => 1, CURLOPT_MAXREDIRS => 5, CURLOPT_CONNECTTIMEOUT => 10, CURLOPT_USERAGENT => $userAgent, CURLOPT_WRITEFUNCTION => 'callback', CURLOPT_HEADERFUNCTION => 'callback', CURLOPT_PROGRESSFUNCTION => 'callback', CURLOPT_NOPROGRESS => 0, CURLOPT_ENCODING => '', CURLOPT_HTTPHEADER => array( 'Host: www.guzzle-project.com', 'Authorization: Basic ' . $auth, 'User-Agent: ' . $userAgent ), CURLOPT_PORT => 443 )), array('GET', 'http://www.guzzle-project.com:8080/', array( 'X-Test-Data' => 'Guzzle' ), null, array( CURLOPT_RETURNTRANSFER => 0, CURLOPT_HEADER => 0, CURLOPT_FOLLOWLOCATION => 1, CURLOPT_MAXREDIRS => 5, CURLOPT_CONNECTTIMEOUT => 10, CURLOPT_USERAGENT => $userAgent, CURLOPT_WRITEFUNCTION => 'callback', CURLOPT_HEADERFUNCTION => 'callback', CURLOPT_PROGRESSFUNCTION => 'callback', CURLOPT_NOPROGRESS => 0, CURLOPT_ENCODING => '', CURLOPT_HTTPHEADER => array('Host: www.guzzle-project.com:8080', 'X-Test-Data: Guzzle', 'User-Agent: ' . $userAgent), CURLOPT_PORT => 8080 )), array('POST', 'http://www.guzzle-project.com/post.php', null, $qs, array( CURLOPT_RETURNTRANSFER => 0, CURLOPT_HEADER => 0, CURLOPT_FOLLOWLOCATION => 1, CURLOPT_MAXREDIRS => 5, CURLOPT_CONNECTTIMEOUT => 10, CURLOPT_USERAGENT => $userAgent, CURLOPT_WRITEFUNCTION => 'callback', CURLOPT_HEADERFUNCTION => 'callback', CURLOPT_PROGRESSFUNCTION => 'callback', CURLOPT_NOPROGRESS => 0, CURLOPT_ENCODING => '', CURLOPT_POSTFIELDS => 'x=y&z=a', CURLOPT_HTTPHEADER => array ( 'Host: www.guzzle-project.com', 'User-Agent: ' . $userAgent, 'Expect: 100-Continue', 'Content-Type: application/x-www-form-urlencoded' ) )), array('PUT', 'http://www.guzzle-project.com/put.php', null, EntityBody::factory(fopen(__DIR__ . '/../../../../../phpunit.xml', 'r+')), array( CURLOPT_RETURNTRANSFER => 0, CURLOPT_HEADER => 0, CURLOPT_FOLLOWLOCATION => 1, CURLOPT_MAXREDIRS => 5, CURLOPT_CONNECTTIMEOUT => 10, CURLOPT_USERAGENT => $userAgent, CURLOPT_WRITEFUNCTION => 'callback', CURLOPT_HEADERFUNCTION => 'callback', CURLOPT_READFUNCTION => 'callback', CURLOPT_PROGRESSFUNCTION => 'callback', CURLOPT_NOPROGRESS => 0, CURLOPT_ENCODING => '', CURLOPT_HTTPHEADER => array ( 'Host: www.guzzle-project.com', 'User-Agent: ' . $userAgent, 'Expect: 100-Continue', 'Content-Length: ' . filesize(__DIR__ . '/../../../../../phpunit.xml') ) )), array('POST', 'http://www.guzzle-project.com/post.php', null, array( 'a' => '2' ), array( CURLOPT_RETURNTRANSFER => 0, CURLOPT_HEADER => 0, CURLOPT_FOLLOWLOCATION => 1, CURLOPT_MAXREDIRS => 5, CURLOPT_CONNECTTIMEOUT => 10, CURLOPT_USERAGENT => $userAgent, CURLOPT_WRITEFUNCTION => 'callback', CURLOPT_HEADERFUNCTION => 'callback', CURLOPT_PROGRESSFUNCTION => 'callback', CURLOPT_NOPROGRESS => 0, CURLOPT_ENCODING => '', CURLOPT_POST => 1, CURLOPT_POSTFIELDS => 'a=2', CURLOPT_HTTPHEADER => array ( 'Host: www.guzzle-project.com', 'User-Agent: ' . $userAgent, 'Expect: 100-Continue', 'Content-Type: application/x-www-form-urlencoded' ) )), array('POST', 'http://www.guzzle-project.com/post.php', null, array( 'x' => 'y' ), array( CURLOPT_RETURNTRANSFER => 0, CURLOPT_HEADER => 0, CURLOPT_FOLLOWLOCATION => 1, CURLOPT_MAXREDIRS => 5, CURLOPT_CONNECTTIMEOUT => 10, CURLOPT_USERAGENT => $userAgent, CURLOPT_WRITEFUNCTION => 'callback', CURLOPT_HEADERFUNCTION => 'callback', CURLOPT_PROGRESSFUNCTION => 'callback', CURLOPT_NOPROGRESS => 0, CURLOPT_ENCODING => '', CURLOPT_POST => 1, CURLOPT_POSTFIELDS => 'x=y', CURLOPT_HTTPHEADER => array ( 'Host: www.guzzle-project.com', 'User-Agent: ' . $userAgent, 'Expect: 100-Continue', 'Content-Type: application/x-www-form-urlencoded' ) )), array('POST', 'http://www.guzzle-project.com/post.php', null, $postBody, array( CURLOPT_RETURNTRANSFER => 0, CURLOPT_HEADER => 0, CURLOPT_FOLLOWLOCATION => 1, CURLOPT_MAXREDIRS => 5, CURLOPT_CONNECTTIMEOUT => 10, CURLOPT_USERAGENT => $userAgent, CURLOPT_WRITEFUNCTION => 'callback', CURLOPT_HEADERFUNCTION => 'callback', CURLOPT_PROGRESSFUNCTION => 'callback', CURLOPT_NOPROGRESS => 0, CURLOPT_ENCODING => '', CURLOPT_POST => 1, CURLOPT_POSTFIELDS => array( 'file' => '@' . __DIR__ . '/../../../../../phpunit.xml' ), CURLOPT_HTTPHEADER => array ( 'Host: www.guzzle-project.com', 'User-Agent: ' . $userAgent, 'Expect: 100-Continue', 'Content-Type: multipart/form-data' ) )), ); } /** * @covers Guzzle\Http\Curl\CurlHandle::factory * @dataProvider dataProvider */ public function testFactoryCreatesCurlBasedOnRequest($method, $url, $headers, $body, $options) { $request = RequestFactory::create($method, $url, $headers, $body); $handle = CurlHandle::factory($request); $this->assertInstanceOf('Guzzle\\Http\\Curl\\CurlHandle', $handle); $o = $request->getParams()->get('curl.last_options'); $check = 0; foreach ($options as $key => $value) { $check++; $this->assertArrayHasKey($key, $o, '-> Check number ' . $check); if ($key != CURLOPT_HTTPHEADER && $key != CURLOPT_POSTFIELDS && (is_array($o[$key])) || $o[$key] instanceof \Closure) { $this->assertEquals('callback', $value, '-> Check number ' . $check); } else { $this->assertTrue($value == $o[$key], '-> Check number ' . $check . ' - ' . var_export($value, true) . ' != ' . var_export($o[$key], true)); } } $request = null; } /** * @covers Guzzle\Http\Curl\CurlHandle */ public function testFactoryUsesSpecifiedProtocol() { $request = RequestFactory::create('GET', 'http://www.guzzle-project.com/'); $request->setProtocolVersion('1.1'); $handle = CurlHandle::factory($request); $options = $request->getParams()->get('curl.last_options'); $this->assertEquals(CURL_HTTP_VERSION_1_1, $options[CURLOPT_HTTP_VERSION]); } /** * @covers Guzzle\Http\Curl\CurlHandle */ public function testUploadsPutData() { $this->getServer()->flush(); $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 2\r\n\r\nhi"); $request = RequestFactory::create('PUT', $this->getServer()->getUrl()); $request->setClient(new Client()); $request->setBody(EntityBody::factory('test'), 'text/plain', false); $o = $this->getWildcardObserver($request); $request->send(); // Make sure that the events were dispatched $this->assertTrue($o->has('curl.callback.read')); $this->assertTrue($o->has('curl.callback.write')); $this->assertTrue($o->has('curl.callback.progress')); // Make sure that the data was sent through the event $this->assertEquals('test', $o->getData('curl.callback.read', 'read')); $this->assertEquals('hi', $o->getData('curl.callback.write', 'write')); // Ensure that the request was received exactly as intended $r = $this->getServer()->getReceivedRequests(true); $this->assertEquals((string) $request, (string) $r[0]); } /** * @covers Guzzle\Http\Curl\CurlHandle */ public function testSendsPostRequests() { $this->getServer()->flush(); $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 2\r\n\r\nhi"); // Create a new request using the same connection and POST $request = RequestFactory::create('POST', $this->getServer()->getUrl()); $request->setClient(new Client()); $request->addPostFields(array( 'a' => 'b', 'c' => 'ay! ~This is a test, isn\'t it?' )); $request->send(); // Make sure that the request was sent correctly $r = $this->getServer()->getReceivedRequests(true); $this->assertEquals((string) $request, (string) $r[0]); } }tests/Guzzle/Tests/Http/Curl/CurlMultiTest.php000064400000042424151742730640015424 0ustar00updates = new Collection(); $this->multi = new MockMulti(); $this->mock = $this->getWildcardObserver($this->multi); } /** * @covers Guzzle\Http\Curl\CurlMulti::getInstance */ public function testReturnsCachedInstance() { $c = CurlMulti::getInstance(); $this->assertInstanceOf('Guzzle\\Http\\Curl\\CurlMultiInterface', $c); $this->assertSame($c, CurlMulti::getInstance()); } /** * @covers Guzzle\Http\Curl\CurlMulti::__construct * @covers Guzzle\Http\Curl\CurlMulti::__destruct */ public function testConstructorCreateMultiHandle() { $this->assertInternalType('resource', $this->multi->getHandle()); $this->assertEquals('curl_multi', get_resource_type($this->multi->getHandle())); } /** * @covers Guzzle\Http\Curl\CurlMulti::__destruct */ public function testDestructorClosesMultiHandle() { $handle = $this->multi->getHandle(); $this->multi->__destruct(); $this->assertFalse(is_resource($handle)); } /** * @covers Guzzle\Http\Curl\curlMulti::add * @covers Guzzle\Http\Curl\curlMulti::all * @covers Guzzle\Http\Curl\curlMulti::count */ public function testRequestsCanBeAddedAndCounted() { $multi = new CurlMulti(); $mock = $this->getWildcardObserver($multi); $request1 = new Request('GET', 'http://www.google.com/'); $multi->add($request1); $this->assertEquals(array($request1), $multi->all()); $request2 = new Request('POST', 'http://www.google.com/'); $multi->add($request2); $this->assertEquals(array($request1, $request2), $multi->all()); $this->assertEquals(2, count($multi)); $this->assertTrue($mock->has(CurlMulti::ADD_REQUEST)); $this->assertFalse($mock->has(CurlMulti::REMOVE_REQUEST)); $this->assertFalse($mock->has(CurlMulti::POLLING)); $this->assertFalse($mock->has(CurlMulti::COMPLETE)); } /** * @covers Guzzle\Http\Curl\CurlMulti::remove * @covers Guzzle\Http\Curl\CurlMulti::all */ public function testRequestsCanBeRemoved() { $request1 = new Request('GET', 'http://www.google.com/'); $this->multi->add($request1); $request2 = new Request('PUT', 'http://www.google.com/'); $this->multi->add($request2); $this->assertEquals(array($request1, $request2), $this->multi->all()); $this->assertSame($this->multi, $this->multi->remove($request1)); $this->assertEquals(array($request2), $this->multi->all()); } /** * @covers Guzzle\Http\Curl\CurlMulti::reset */ public function testsResetRemovesRequestsAndResetsState() { $request1 = new Request('GET', 'http://www.google.com/'); $this->multi->add($request1); $this->multi->reset(); $this->assertEquals(array(), $this->multi->all()); $this->assertEquals('idle', $this->multi->getState()); } /** * @covers Guzzle\Http\Curl\CurlMulti::send * @covers Guzzle\Http\Curl\CurlMulti::getState */ public function testSendsRequestsInParallel() { $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 4\r\n\r\nBody"); $this->assertEquals('idle', $this->multi->getState()); $request = new Request('GET', $this->getServer()->getUrl()); $this->multi->add($request); $this->multi->send(); $this->assertEquals('idle', $this->multi->getState()); $this->assertTrue($this->mock->has(CurlMulti::ADD_REQUEST)); $this->assertTrue($this->mock->has(CurlMulti::COMPLETE)); $this->assertEquals('Body', $request->getResponse()->getBody()->__toString()); // Sending it again will not do anything because there are no requests $this->multi->send(); } /** * @covers Guzzle\Http\Curl\CurlMulti::send */ public function testSendsRequestsThroughCurl() { $this->getServer()->enqueue(array( "HTTP/1.1 204 No content\r\n" . "Content-Length: 0\r\n" . "Server: Jetty(6.1.3)\r\n\r\n", "HTTP/1.1 200 OK\r\n" . "Content-Type: text/html; charset=utf-8\r\n" . "Content-Length: 4\r\n" . "Server: Jetty(6.1.3)\r\n\r\n" . "\r\n" . "data" )); $request1 = new Request('GET', $this->getServer()->getUrl()); $mock1 = $this->getWildcardObserver($request1); $request2 = new Request('GET', $this->getServer()->getUrl()); $mock2 = $this->getWildcardObserver($request2); $this->multi->add($request1); $this->multi->add($request2); $this->multi->send(); $response1 = $request1->getResponse(); $response2 = $request2->getResponse(); $this->assertInstanceOf('Guzzle\\Http\\Message\\Response', $response1); $this->assertInstanceOf('Guzzle\\Http\\Message\\Response', $response2); $this->assertTrue($response1->getBody(true) == 'data' || $response2->getBody(true) == 'data'); $this->assertTrue($response1->getBody(true) == '' || $response2->getBody(true) == ''); $this->assertTrue($response1->getStatusCode() == '204' || $response2->getStatusCode() == '204'); $this->assertNotEquals((string) $response1, (string) $response2); $this->assertTrue($mock1->has('request.before_send')); $this->assertTrue($mock2->has('request.before_send')); } /** * @covers Guzzle\Http\Curl\CurlMulti::send */ public function testSendsThroughCurlAndAggregatesRequestExceptions() { $this->getServer()->enqueue(array( "HTTP/1.1 200 OK\r\n" . "Content-Type: text/html; charset=utf-8\r\n" . "Content-Length: 4\r\n" . "Server: Jetty(6.1.3)\r\n" . "\r\n" . "data", "HTTP/1.1 204 No content\r\n" . "Content-Length: 0\r\n" . "Server: Jetty(6.1.3)\r\n" . "\r\n", "HTTP/1.1 404 Not Found\r\n" . "Content-Length: 0\r\n" . "\r\n" )); $request1 = new Request('GET', $this->getServer()->getUrl()); $request2 = new Request('HEAD', $this->getServer()->getUrl()); $request3 = new Request('GET', $this->getServer()->getUrl()); $this->multi->add($request1); $this->multi->add($request2); $this->multi->add($request3); try { $this->multi->send(); $this->fail('ExceptionCollection not thrown when aggregating request exceptions'); } catch (ExceptionCollection $e) { $this->assertInstanceOf('ArrayIterator', $e->getIterator()); $this->assertEquals(1, count($e)); $exceptions = $e->getIterator(); $response1 = $request1->getResponse(); $response2 = $request2->getResponse(); $response3 = $request3->getResponse(); $this->assertNotEquals((string) $response1, (string) $response2); $this->assertNotEquals((string) $response3, (string) $response1); $this->assertInstanceOf('Guzzle\\Http\\Message\\Response', $response1); $this->assertInstanceOf('Guzzle\\Http\\Message\\Response', $response2); $this->assertInstanceOf('Guzzle\\Http\\Message\\Response', $response3); $failed = $exceptions[0]->getResponse(); $this->assertEquals(404, $failed->getStatusCode()); $this->assertEquals(1, count($e)); // Test the IteratorAggregate functionality foreach ($e as $excep) { $this->assertEquals($failed, $excep->getResponse()); } } } /** * @covers Guzzle\Http\Curl\CurlMulti::send * @covers Guzzle\Http\Curl\CurlMulti::processResponse */ public function testCurlErrorsAreCaught() { $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"); try { $request = RequestFactory::create('GET', 'http://127.0.0.1:9876/'); $request->setClient(new Client()); $request->getCurlOptions()->set(CURLOPT_FRESH_CONNECT, true); $request->getCurlOptions()->set(CURLOPT_TIMEOUT, 0); $request->getCurlOptions()->set(CURLOPT_CONNECTTIMEOUT, 1); $request->send(); $this->fail('CurlException not thrown'); } catch (CurlException $e) { $m = $e->getMessage(); $this->assertContains('[curl] 7:', $m); $this->assertContains('[url] http://127.0.0.1:9876/', $m); $this->assertContains('[debug] ', $m); $this->assertContains('[info] array (', $m); $this->assertContains('Connection refused', $m); } } /** * @covers Guzzle\Http\Curl\CurlMulti */ public function testRemovesQueuedRequests() { $request = RequestFactory::create('GET', 'http://127.0.0.1:9876/'); $request->setClient(new Client()); $request->setResponse(new Response(200), true); $this->multi->add($request); $this->multi->send(); $this->assertTrue($this->mock->has(CurlMulti::ADD_REQUEST)); $this->assertTrue($this->mock->has(CurlMulti::POLLING) === false); $this->assertTrue($this->mock->has(CurlMulti::COMPLETE) !== false); } /** * @covers Guzzle\Http\Curl\CurlMulti */ public function testRemovesQueuedRequestsAddedInTransit() { $this->getServer()->flush(); $this->getServer()->enqueue(array( "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n" )); $client = new Client($this->getServer()->getUrl()); $r = $client->get(); $r->getEventDispatcher()->addListener('request.receive.status_line', function(Event $event) use ($client) { // Create a request using a queued response $request = $client->get()->setResponse(new Response(200), true); $request->send(); }); $r->send(); $this->assertEquals(1, count($this->getServer()->getReceivedRequests(false))); } /** * @covers Guzzle\Http\Curl\CurlMulti */ public function testProperlyBlocksBasedOnRequestsInScope() { $this->getServer()->flush(); $this->getServer()->enqueue(array( "HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\ntest1", "HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\ntest2", "HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\ntest3", "HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\ntest4", "HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\ntest5", "HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\ntest6", "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n", "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n" )); $client = new Client($this->getServer()->getUrl()); $requests = array( $client->get(), $client->get(), $client->get() ); $callback = function(Event $event) use ($client) { $client->getConfig()->set('called', $client->getConfig('called') + 1); $request = $client->get(); if ($client->getConfig('called') <= 2) { $request->getEventDispatcher()->addListener('request.complete', function(Event $event) use ($client) { $client->head()->send(); }); } $request->send(); }; $requests[0]->getEventDispatcher()->addListener('request.complete', $callback); $requests[1]->getEventDispatcher()->addListener('request.complete', $callback); $requests[2]->getEventDispatcher()->addListener('request.complete', $callback); $client->send($requests); $this->assertEquals(8, count($this->getServer()->getReceivedRequests(false))); } /** * @covers Guzzle\Http\Curl\CurlMulti * @expectedException RuntimeException * @expectedExceptionMessage Testing! */ public function testCatchesExceptionsBeforeSendingCurlMulti() { $client = new Client($this->getServer()->getUrl()); $multi = new CurlMulti(); $client->setCurlMulti($multi); $multi->getEventDispatcher()->addListener(CurlMulti::BEFORE_SEND, function() { throw new \RuntimeException('Testing!'); }); $client->get()->send(); } /** * @covers Guzzle\Http\Curl\CurlMulti * @covers Guzzle\Http\Curl\CurlMulti::removeErroredRequest * @expectedException Guzzle\Common\ExceptionCollection * @expectedExceptionMessage Thrown before sending! */ public function testCatchesExceptionsBeforeSendingRequests() { $client = new Client($this->getServer()->getUrl()); $request = $client->get(); $request->getEventDispatcher()->addListener('request.before_send', function() { throw new \RuntimeException('Thrown before sending!'); }); $client->send(array($request)); } /** * @covers Guzzle\Http\Curl\CurlMulti * @covers Guzzle\Http\Curl\CurlMulti::removeErroredRequest * @expectedException Guzzle\Http\Message\BadResponseException */ public function testCatchesExceptionsWhenRemovingQueuedRequests() { $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"); $client = new Client($this->getServer()->getUrl()); $r = $client->get(); $r->getEventDispatcher()->addListener('request.sent', function() use ($client) { // Create a request using a queued response $client->get()->setResponse(new Response(404), true)->send(); }); $r->send(); } /** * @covers Guzzle\Http\Curl\CurlMulti * @covers Guzzle\Http\Curl\CurlMulti::removeErroredRequest * @expectedException Guzzle\Http\Message\BadResponseException */ public function testCatchesExceptionsWhenRemovingQueuedRequestsBeforeSending() { $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"); $client = new Client($this->getServer()->getUrl()); $r = $client->get(); $r->getEventDispatcher()->addListener('request.before_send', function() use ($client) { // Create a request using a queued response $client->get()->setResponse(new Response(404), true)->send(); }); $r->send(); } /** * @covers Guzzle\Http\Curl\CurlMulti::send * @covers Guzzle\Http\Curl\CurlMulti::removeErroredRequest * @expectedException Guzzle\Common\ExceptionCollection * @expectedExceptionMessage test */ public function testCatchesRandomExceptionsThrownDuringPerform() { $client = new Client($this->getServer()->getUrl()); $multi = $this->getMock('Guzzle\\Http\\Curl\\CurlMulti', array('perform')); $multi->expects($this->once()) ->method('perform') ->will($this->throwException(new \Exception('test'))); $multi->add($client->get()); $multi->send(); } /** * @covers Guzzle\Http\Curl\CurlMulti::send */ public function testDoesNotSendRequestsDecliningToBeSent() { $this->getServer()->flush(); $client = new Client($this->getServer()->getUrl()); $request = $client->get(); $request->getEventDispatcher()->addListener('request.before_send', function(Event $event) { $event['request']->setResponse(new Response(200)); }); $multi = new CurlMulti(); $multi->add($request); $multi->send(); $this->assertEquals(0, count($this->getServer()->getReceivedRequests(false))); } /** * @covers Guzzle\Http\Curl\CurlMulti::reset * */ public function testHardResetReopensMultiHandle() { $this->getServer()->enqueue(array( "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n", "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n" )); $client = new Client($this->getServer()->getUrl()); $message = ''; $plugin = new LogPlugin(new ClosureLogAdapter(function($msg) use (&$message) { $message .= $msg . "\n"; }), LogPlugin::LOG_VERBOSE); $client->getEventDispatcher()->addSubscriber($plugin); $request = $client->get(); $multi = new CurlMulti(); $multi->add($request); $multi->send(); $multi->reset(true); $multi->add($request); $multi->send(); $this->assertNotContains('Re-using existing connection', $message); } }tests/Guzzle/Tests/Http/EntityBodyTest.php000064400000013247151742730640014672 0ustar00assertEquals('data', (string)$body); $this->assertEquals(4, $body->getContentLength()); $this->assertEquals('php', $body->getWrapper()); $this->assertEquals('temp', $body->getStreamType()); $handle = fopen(__DIR__ . '/../../../../phpunit.xml', 'r'); if (!$handle) { $this->fail('Could not open test file'); } $body = EntityBody::factory($handle); $this->assertEquals(__DIR__ . '/../../../../phpunit.xml', $body->getUri()); $this->assertTrue($body->isLocal()); $this->assertEquals(__DIR__ . '/../../../../phpunit.xml', $body->getUri()); $this->assertEquals(filesize(__DIR__ . '/../../../../phpunit.xml'), $body->getContentLength()); // make sure that a body will return as the same object $this->assertTrue($body === EntityBody::factory($body)); } /** * @covers Guzzle\Http\EntityBody::factory */ public function testFactoryCreatesTempStreamByDefault() { $body = EntityBody::factory(''); $this->assertEquals('php', $body->getWrapper()); $this->assertEquals('temp', $body->getStreamType()); $body = EntityBody::factory(); $this->assertEquals('php', $body->getWrapper()); $this->assertEquals('temp', $body->getStreamType()); } /** * @covers Guzzle\Http\EntityBody::compress * @covers Guzzle\Http\EntityBody::uncompress * @covers Guzzle\Http\EntityBody::getContentEncoding * @covers Guzzle\Http\EntityBody::setStreamFilterContentEncoding * @covers Guzzle\Http\EntityBody::handleCompression * @covers Guzzle\Http\EntityBody::getContentLength */ public function testHandlesCompression() { $body = EntityBody::factory('testing 123...testing 123'); $this->assertFalse($body->getContentEncoding(), '-> getContentEncoding() must initially return FALSE'); $size = $body->getContentLength(); $body->compress(); $this->assertEquals('gzip', $body->getContentEncoding(), '-> getContentEncoding() must return the correct encoding after compressing'); $this->assertEquals(gzdeflate('testing 123...testing 123'), (string) $body); $this->assertTrue($body->getContentLength() < $size); $this->assertTrue($body->uncompress()); $this->assertEquals('testing 123...testing 123', (string) $body); $this->assertFalse($body->getContentEncoding(), '-> getContentEncoding() must reset to FALSE'); if (in_array('bzip2.*', stream_get_filters())) { $this->assertTrue($body->compress('bzip2.compress')); $this->assertEquals('compress', $body->getContentEncoding(), '-> compress() must set \'compress\' as the Content-Encoding'); } $this->assertFalse($body->compress('non-existent'), '-> compress() must return false when a non-existent stream filter is used'); // Release the body unset($body); // Use gzip compression on the initial content. This will include a // gzip header which will need to be stripped when deflating the stream $body = EntityBody::factory(gzencode('test')); $this->assertSame($body, $body->setStreamFilterContentEncoding('zlib.deflate')); $this->assertTrue($body->uncompress('zlib.inflate')); $this->assertEquals('test', (string)$body); unset($body); // Test using a very long string $largeString = ''; for ($i = 0; $i < 25000; $i++) { $largeString .= chr(rand(33, 126)); } $body = EntityBody::factory($largeString); $this->assertEquals($largeString, (string)$body); $this->assertTrue($body->compress()); $this->assertNotEquals($largeString, (string)$body); $compressed = (string)$body; $this->assertTrue($body->uncompress()); $this->assertEquals($largeString, (string)$body); $this->assertEquals($compressed, gzdeflate($largeString)); $body = EntityBody::factory(fopen(__DIR__ . '/../TestData/compress_test', 'w')); $this->assertFalse($body->compress()); unset($body); unlink(__DIR__ . '/../TestData/compress_test'); } /** * @covers Guzzle\Http\EntityBody::getContentType */ public function testDeterminesContentType() { // Test using a string/temp stream $body = EntityBody::factory('testing 123...testing 123'); $this->assertEquals('application/octet-stream', $body->getContentType()); // Use a local file $body = EntityBody::factory(fopen(__FILE__, 'r')); $this->assertEquals('text/x-php', $body->getContentType()); } /** * @covers Guzzle\Http\EntityBody::getContentMd5 */ public function testCreatesMd5Checksum() { $body = EntityBody::factory('testing 123...testing 123'); $this->assertEquals(md5('testing 123...testing 123'), $body->getContentMd5()); $server = $this->getServer()->enqueue( "HTTP/1.1 200 OK" . "\r\n" . "Content-Length: 3" . "\r\n\r\n" . "abc" ); $body = EntityBody::factory(fopen($this->getServer()->getUrl(), 'r')); $this->assertFalse($body->getContentMd5()); } }tests/Guzzle/Tests/Http/Message/AbstractMessageTest.php000064400000016073151742730640017234 0ustar00request = new Request('GET', 'http://www.guzzle-project.com/'); } /** * @covers Guzzle\Http\Message\AbstractMessage::getParams */ public function testGetParams() { $this->assertInstanceOf('Guzzle\\Common\\Collection', $this->request->getParams()); } /** * @covers Guzzle\Http\Message\AbstractMessage::addHeaders */ public function testAddHeaders() { $this->request->setHeader('A', 'B'); $this->assertEquals($this->request, $this->request->addHeaders(array( 'X-Data' => '123' ))); $this->assertTrue($this->request->hasHeader('X-Data') !== false); $this->assertTrue($this->request->hasHeader('A') !== false); } /** * @covers Guzzle\Http\Message\AbstractMessage::getHeaders */ public function testGetHeader() { $this->request->setHeader('Test', '123'); $this->assertEquals('123', $this->request->getHeader('Test')); } /** * @covers Guzzle\Http\Message\AbstractMessage::getHeaders * @covers Guzzle\Http\Message\AbstractMessage::setHeaders */ public function testGetHeaders() { $this->assertEquals($this->request, $this->request->setHeaders(array( 'a' => 'b', 'c' => 'd' ))); $this->assertEquals(array( 'a' => 'b', 'c' => 'd' ), $this->request->getHeaders()->getAll()); $this->assertEquals(array( 'a' => 'b' ), $this->request->getHeaders(array('a'))->getAll()); } /** * @covers Guzzle\Http\Message\AbstractMessage::hasHeader */ public function testHasHeader() { $this->assertFalse($this->request->hasHeader('Foo')); $this->request->setHeader('Foo', 'Bar'); $this->assertEquals(true, $this->request->hasHeader('Foo')); } /** * @covers Guzzle\Http\Message\AbstractMessage::hasHeader */ public function testHasHeaderSearch() { $this->assertFalse($this->request->hasHeader('Foo')); $this->request->setHeader('Foo', 'Bar'); $this->assertEquals('Foo', $this->request->hasHeader('Foo', 1)); $this->assertEquals('Foo', $this->request->hasHeader('/Foo/', 2)); $this->assertEquals(false, $this->request->hasHeader('bar', 1)); } /** * @covers Guzzle\Http\Message\AbstractMessage::removeHeader * @covers Guzzle\Http\Message\AbstractMessage::setHeader */ public function testRemoveHeader() { $this->request->setHeader('Foo', 'Bar'); $this->assertEquals(true, $this->request->hasHeader('Foo')); $this->request->removeHeader('Foo'); $this->assertFalse($this->request->hasHeader('Foo')); } /** * @covers Guzzle\Http\Message\AbstractMessage */ public function testHoldsCacheControlDirectives() { $r = $this->request; // Set a directive using a header $r->setHeader('Cache-Control', 'max-age=100'); $this->assertEquals(100, $r->getCacheControlDirective('max-age')); // Set a header using the directive and check that the header was updated $this->assertSame($r, $r->addCacheControlDirective('max-age', 80)); $this->assertEquals(80, $r->getCacheControlDirective('max-age')); $this->assertEquals('max-age=80', $r->getHeader('Cache-Control')); // Remove the directive $this->assertEquals($r, $r->removeCacheControlDirective('max-age')); $this->assertEquals('', $r->getHeader('Cache-Control')); $this->assertEquals(null, $r->getCacheControlDirective('max-age')); // Remove a non-existent directive $this->assertEquals($r, $r->removeCacheControlDirective('max-age')); // Has directive $this->assertFalse($r->hasCacheControlDirective('max-age')); $r->addCacheControlDirective('must-revalidate'); $this->assertTrue($r->hasCacheControlDirective('must-revalidate')); // Make sure that it works with multiple Cache-Control headers $r->setHeader('Cache-Control', 'must-revalidate, max-age=100'); $r->addHeaders(array( 'Cache-Control' => 'no-cache' )); $this->assertEquals(true, $r->getCacheControlDirective('no-cache')); $this->assertEquals(true, $r->getCacheControlDirective('must-revalidate')); $this->assertEquals(100, $r->getCacheControlDirective('max-age')); } public function tokenizedHeaderProvider() { return array( array('ISO-8859-1,utf-8;q=0.7,*;q=0.7"', ';', array( 'ISO-8859-1,utf-8', 'q' => array('0.7,*', '0.7"') )), array('gzip,deflate', ',', array('gzip', 'deflate')), array('en-us,en;q=0.5', ';', array( 'en-us,en', 'q' => '0.5' )) ); } /** * @covers Guzzle\Http\Message\AbstractMessage::getTokenizedHeader * @dataProvider tokenizedHeaderProvider */ public function testConvertsTokenizedHeadersToArray($string, $token, $result) { $r = $this->request; $r->setHeader('test', $string); $this->assertEquals($result, $r->getTokenizedHeader('test', $token)->getAll()); } /** * @covers Guzzle\Http\Message\AbstractMessage::setTokenizedHeader * @dataProvider tokenizedHeaderProvider */ public function testConvertsArrayToTokenizedHeader($string, $token, $result) { $r = $this->request; $r->setTokenizedHeader('test', $result, $token); $this->assertEquals($string, $r->getHeader('test')); } /** * @covers Guzzle\Http\Message\AbstractMessage::setTokenizedHeader * @expectedException InvalidArgumentException */ public function testTokenizedHeaderMustBeArrayToSet() { $r = $this->request; $r->setTokenizedHeader('test', false); } /** * @covers Guzzle\Http\Message\AbstractMessage::getTokenizedHeader */ public function testReturnsNullWhenTokenizedHeaderNotFound() { $r = $this->request; $this->assertNull($r->getTokenizedHeader('foo')); } /** * @covers Guzzle\Http\Message\AbstractMessage::getTokenizedHeader */ public function testMultipleTokenizedHeadersAreCombined() { $r = Response::factory( "HTTP/1.1 200 OK\r\n" . "test: ISO-8859-1,utf-8;q=0.7,*;q=0.7\"\r\n" . "test: foo;q=123,*;q=456;q=0.7\"\r\n" . "Content-Length: 0\r\n\r\n" ); $this->assertEquals(array( 0 => 'ISO-8859-1,utf-8', 'q' => array('0.7,*', '0.7"', '123,*', '456'), 2 => 'foo' ), $r->getTokenizedHeader('test')->getAll()); } }tests/Guzzle/Tests/Http/Message/EntityEnclosingRequestTest.php000064400000030416151742730640020650 0ustar00 '123' )); $this->assertEquals('123', $request->getHeader('X-Test')); $this->assertEquals('100-Continue', $request->getHeader('Expect')); } /** * @covers Guzzle\Http\Message\EntityEnclosingRequest::__toString * @covers Guzzle\Http\Message\EntityEnclosingRequest::addPostFields */ public function testRequestIncludesBodyInMessage() { $request = RequestFactory::create('PUT', 'http://www.guzzle-project.com/', null, 'data'); $this->assertEquals("PUT / HTTP/1.1\r\n" . "Host: www.guzzle-project.com\r\n" . "User-Agent: " . Guzzle::getDefaultUserAgent() . "\r\n" . "Expect: 100-Continue\r\n" . "Content-Length: 4\r\n\r\n" . "data", (string) $request); } /** * @covers Guzzle\Http\Message\EntityEnclosingRequest::__toString * @covers Guzzle\Http\Message\EntityEnclosingRequest::addPostFields */ public function testAddsPostFieldsAndSetsContentLength() { $request = RequestFactory::create('POST', 'http://www.guzzle-project.com/', null, array( 'data' => '123' )); $this->assertEquals("POST / HTTP/1.1\r\n" . "Host: www.guzzle-project.com\r\n" . "User-Agent: " . Guzzle::getDefaultUserAgent() . "\r\n" . "Expect: 100-Continue\r\n" . "Content-Type: application/x-www-form-urlencoded\r\n\r\n" . "data=123", (string) $request); } /** * @covers Guzzle\Http\Message\EntityEnclosingRequest::__toString * @covers Guzzle\Http\Message\EntityEnclosingRequest::addPostFiles * @covers Guzzle\Http\Message\EntityEnclosingRequest::addPostFields */ public function testAddsPostFilesAndSetsContentType() { $request = RequestFactory::create('POST', 'http://www.test.com/') ->addPostFiles(array( 'file' => __FILE__ ))->addPostFields(array( 'a' => 'b' )); $message = (string) $request; $this->assertEquals('multipart/form-data', $request->getHeader('Content-Type')); } /** * @covers Guzzle\Http\Message\EntityEnclosingRequest::processPostFields */ public function testRequestBodyContainsPostFiles() { $request = RequestFactory::create('POST', 'http://www.test.com/'); $request->addPostFields(array( 'test' => '123' )); $this->assertContains("\r\n\r\ntest=123", (string) $request); } /** * @covers Guzzle\Http\Message\EntityEnclosingRequest::processPostFields */ public function testRequestBodyAddsContentLength() { $request = RequestFactory::create('PUT', 'http://www.test.com/'); $request->setBody(EntityBody::factory('test')); $this->assertEquals(4, $request->getHeader('Content-Length')); } /** * Tests using a Transfer-Encoding chunked entity body already set * @covers Guzzle\Http\Message\EntityEnclosingRequest::processPostFields * @covers Guzzle\Http\Message\EntityEnclosingRequest::setBody */ public function testRequestBodyDoesNotUseContentLengthWhenChunked() { $request = RequestFactory::create('PUT', 'http://www.test.com/'); $request->setBody(EntityBody::factory('test'), null, true); $this->assertNull($request->getHeader('Content-Length')); } /** * Tests using a Transfer-Encoding chunked entity body with undeterminable size * @covers Guzzle\Http\Message\EntityEnclosingRequest::processPostFields */ public function testUsesChunkedTranserEncodingWhenBodyLengthNotAvailable() { $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 4\r\n\r\nData"); $request = RequestFactory::create('PUT', 'http://www.test.com/'); $request->setBody(EntityBody::factory(fopen($this->getServer()->getUrl(), 'r'))); $this->assertNull($request->getHeader('Content-Length')); $this->assertEquals('chunked', $request->getHeader('Transfer-Encoding')); } /** * Tests making sure HTTP/1.0 has a Content-Length header * @covers Guzzle\Http\Message\EntityEnclosingRequest::processPostFields * @expectedException Guzzle\Http\Message\RequestException */ public function testContentLengthIsSetWithHttp1() { $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 4\r\n\r\nData"); $request = RequestFactory::create('PUT', 'http://www.test.com/'); $request->setProtocolVersion('1.0'); $request->setBody(EntityBody::factory(fopen($this->getServer()->getUrl(), 'r'))); } /** * @covers Guzzle\Http\Message\EntityEnclosingRequest::getBody * @covers Guzzle\Http\Message\EntityEnclosingRequest::setBody */ public function testRequestHasMutableBody() { $request = RequestFactory::create('PUT', 'http://www.guzzle-project.com/', null, 'data'); $body = $request->getBody(); $this->assertInstanceOf('Guzzle\\Http\\EntityBody', $body); $this->assertSame($body, $request->getBody()); $newBody = EntityBody::factory('foobar'); $request->setBody($newBody); $this->assertEquals('foobar', (string) $request->getBody()); $this->assertSame($newBody, $request->getBody()); } /** * @covers Guzzle\Http\Message\EntityEnclosingRequest::addPostFields * @covers Guzzle\Http\Message\EntityEnclosingRequest::getPostFields * @covers Guzzle\Http\Message\EntityEnclosingRequest::getPostFiles */ public function testSetPostFields() { $request = RequestFactory::create('POST', 'http://www.guzzle-project.com/'); $this->assertInternalType('array', $request->getPostFields()); $fields = new QueryString(array( 'a' => 'b' )); $request->addPostFields($fields); $this->assertEquals($fields->getAll(), $request->getPostFields()); $this->assertEquals(array(), $request->getPostFiles()); } /** * @covers Guzzle\Http\Message\EntityEnclosingRequest::getPostFiles * @covers Guzzle\Http\Message\EntityEnclosingRequest::addPostFiles */ public function testSetPostFiles() { $request = RequestFactory::create('POST', $this->getServer()->getUrl()) ->setClient(new Client()) ->addPostFiles(array(__FILE__)) ->addPostFields(array( 'test' => 'abc' )); $this->assertEquals(array( 'file' => '@' . __FILE__, 'test' => 'abc' ), $request->getPostFields()); $this->assertEquals(array( 'file' => __FILE__ ), $request->getPostFiles()); $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"); $request->send(); $this->assertNotNull($request->getHeader('Content-Length')); $this->assertContains('multipart/form-data; boundary=', $request->getHeader('Content-Type'), '-> cURL must add the boundary'); } /** * @covers Guzzle\Http\Message\EntityEnclosingRequest::addPostFiles * @expectedException Guzzle\Http\Message\RequestException */ public function testSetPostFilesThrowsExceptionWhenFileIsNotFound() { $request = RequestFactory::create('POST', 'http://www.guzzle-project.com/') ->addPostFiles(array( 'file' => 'filenotfound.ini' )); } /** * @covers Guzzle\Http\Message\EntityEnclosingRequest::setPostField * @covers Guzzle\Http\Message\EntityEnclosingRequest::processPostFields */ public function testPostRequestsUseApplicationXwwwForUrlEncodedForArrays() { $request = RequestFactory::create('POST', 'http://www.guzzle-project.com/'); $request->setPostField('a', 'b'); $this->assertContains("\r\n\r\na=b", (string) $request); $this->assertEquals('application/x-www-form-urlencoded', $request->getHeader('Content-Type')); } /** * @covers Guzzle\Http\Message\EntityEnclosingRequest::processPostFields */ public function testProcessMethodAddsPostCurlOptions() { $request = RequestFactory::create('POST', 'http://www.guzzle-project.com/'); $request->setPostField('a', 'b'); $this->assertEquals('application/x-www-form-urlencoded', $request->getHeader('Content-Type')); $this->assertEquals('a=b', $request->getCurlOptions()->get(CURLOPT_POSTFIELDS)); } /** * @covers Guzzle\Http\Message\EntityEnclosingRequest::processPostFields */ public function testPostRequestsUseMultipartFormDataWithFiles() { $request = RequestFactory::create('POST', 'http://www.guzzle-project.com/'); $request->addPostFiles(array('file' => __FILE__)); $this->assertEquals('multipart/form-data', $request->getHeader('Content-Type')); $this->assertEquals(array('file' => '@' . __FILE__), $request->getCurlOptions()->get(CURLOPT_POSTFIELDS)); } /** * @covers Guzzle\Http\Message\EntityEnclosingRequest::setBody * @covers Guzzle\Http\Message\EntityEnclosingRequest::processPostFields */ public function testCanSendMultipleRequestsUsingASingleRequestObject() { $this->getServer()->flush(); $this->getServer()->enqueue(array( "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n", "HTTP/1.1 201 Created\r\nContent-Length: 0\r\n\r\n", )); // Send the first request $request = RequestFactory::create('PUT', $this->getServer()->getUrl()) ->setBody('test') ->setClient(new Client()); $request->send(); $this->assertEquals(200, $request->getResponse()->getStatusCode()); // Send the second request $request->setBody('abcdefg', 'application/json', false); $request->send(); $this->assertEquals(201, $request->getResponse()->getStatusCode()); // Ensure that the same request was sent twice with different bodies $requests = $this->getServer()->getReceivedRequests(true); $this->assertEquals(2, count($requests)); $this->assertEquals(4, $requests[0]->getHeader('Content-Length')); $this->assertEquals(7, $requests[1]->getHeader('Content-Length')); } /** * @covers Guzzle\Http\Message\EntityEnclosingRequest::getPostField * @covers Guzzle\Http\Message\EntityEnclosingRequest::removePostField */ public function testRemovingPostFieldRebuildsPostFields() { $request = new EntityEnclosingRequest('POST', 'http://test.com'); $request->setPostField('test', 'value'); $request->removePostField('test'); $this->assertNull($request->getPostField('test')); } /** * @covers Guzzle\Http\Message\EntityEnclosingRequest::setBody */ public function testUsesChunkedTransferWhenBodyLengthCannotBeDetermined() { $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"); $request = new EntityEnclosingRequest('PUT', 'http://test.com/'); $request->setBody(fopen($this->getServer()->getUrl(), 'r')); $this->assertEquals('chunked', $request->getHeader('Transfer-Encoding')); } /** * @covers Guzzle\Http\Message\EntityEnclosingRequest::setBody * @expectedException Guzzle\Http\Message\RequestException */ public function testThrowsExceptionWhenContentLengthCannotBeDeterminedAndUsingHttp1() { $request = new EntityEnclosingRequest('PUT', 'http://test.com/'); $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"); $request->setProtocolVersion('1.0'); $request->setBody(fopen($this->getServer()->getUrl(), 'r')); } }tests/Guzzle/Tests/Http/Message/ExceptionTest.php000064400000001616151742730640016117 0ustar00setRequest($request); $this->assertEquals($request, $e->getRequest()); } /** * @covers Guzzle\Http\Message\BadResponseException */ public function testBadResponseException() { $e = new BadResponseException('Message'); $response = new Response(200); $e->setResponse($response); $this->assertEquals($response, $e->getResponse()); } }tests/Guzzle/Tests/Http/Message/RequestFactoryTest.php000064400000030246151742730640017142 0ustar00assertInstanceOf('Guzzle\\Http\\Message\\MessageInterface', $request); $this->assertInstanceOf('Guzzle\\Http\\Message\\RequestInterface', $request); $this->assertInstanceOf('Guzzle\\Http\\Message\\Request', $request); $this->assertEquals('GET', $request->getMethod()); $this->assertEquals('http', $request->getScheme()); $this->assertEquals('http://www.google.com/', $request->getUrl()); $this->assertEquals('www.google.com', $request->getHost()); $this->assertEquals('/', $request->getPath()); $this->assertEquals('/', $request->getResourceUri()); // Create a GET request with a custom receiving body $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"); $b = EntityBody::factory(); $request = RequestFactory::create('GET', $this->getServer()->getUrl(), null, $b); $request->setClient(new Client()); $response = $request->send(); $this->assertSame($b, $response->getBody()); } /** * @covers Guzzle\Http\Message\RequestFactory::create */ public function testCreatesPutRequests() { // Test using a string $request = RequestFactory::create('PUT', 'http://www.google.com/path?q=1&v=2', null, 'Data'); $this->assertInstanceOf('Guzzle\\Http\\Message\\EntityEnclosingRequest', $request); $this->assertEquals('PUT', $request->getMethod()); $this->assertEquals('http', $request->getScheme()); $this->assertEquals('http://www.google.com/path?q=1&v=2', $request->getUrl()); $this->assertEquals('www.google.com', $request->getHost()); $this->assertEquals('/path', $request->getPath()); $this->assertEquals('/path?q=1&v=2', $request->getResourceUri()); $this->assertInstanceOf('Guzzle\\Http\\EntityBody', $request->getBody()); $this->assertEquals('Data', (string) $request->getBody()); unset($request); // Test using an EntityBody $request = RequestFactory::create('PUT', 'http://www.google.com/path?q=1&v=2', null, EntityBody::factory('Data')); $this->assertInstanceOf('Guzzle\\Http\\Message\\EntityEnclosingRequest', $request); $this->assertEquals('Data', (string) $request->getBody()); // Test using a resource $resource = fopen('php://temp', 'w+'); fwrite($resource, 'Data'); $request = RequestFactory::create('PUT', 'http://www.google.com/path?q=1&v=2', null, $resource); $this->assertInstanceOf('Guzzle\\Http\\Message\\EntityEnclosingRequest', $request); $this->assertEquals('Data', (string) $request->getBody()); // Test using an object that can be cast as a string $request = RequestFactory::create('PUT', 'http://www.google.com/path?q=1&v=2', null, Url::factory('http://www.example.com/')); $this->assertInstanceOf('Guzzle\\Http\\Message\\EntityEnclosingRequest', $request); $this->assertEquals('http://www.example.com/', (string) $request->getBody()); } /** * @covers Guzzle\Http\Message\RequestFactory::create */ public function testCreatesHeadAndDeleteRequests() { $request = RequestFactory::create('DELETE', 'http://www.test.com/'); $this->assertEquals('DELETE', $request->getMethod()); $request = RequestFactory::create('HEAD', 'http://www.test.com/'); $this->assertEquals('HEAD', $request->getMethod()); } /** * @covers Guzzle\Http\Message\RequestFactory::create */ public function testCreatesOptionsRequests() { $request = RequestFactory::create('OPTIONS', 'http://www.example.com/'); $this->assertEquals('OPTIONS', $request->getMethod()); $this->assertInstanceOf('Guzzle\\Http\\Message\\Request', $request); } /** * @covers Guzzle\Http\Message\RequestFactory::create */ public function testCreatesNewPutRequestWithBody() { $request = RequestFactory::create('PUT', 'http://www.google.com/path?q=1&v=2', null, 'Data'); $this->assertEquals('Data', (string) $request->getBody()); } /** * @covers Guzzle\Http\Message\RequestFactory::create */ public function testCreatesNewPostRequestWithFields() { // Use an array $request = RequestFactory::create('POST', 'http://www.google.com/path?q=1&v=2', null, array( 'a' => 'b' )); $this->assertEquals(array('a' => 'b'), $request->getPostFields()); unset($request); // Use a collection $request = RequestFactory::create('POST', 'http://www.google.com/path?q=1&v=2', null, new Collection(array( 'a' => 'b' ))); $this->assertEquals(array('a' => 'b'), $request->getPostFields()); // Use a QueryString $request = RequestFactory::create('POST', 'http://www.google.com/path?q=1&v=2', null, new QueryString(array( 'a' => 'b' ))); $this->assertEquals(array('a' => 'b'), $request->getPostFields()); $request = RequestFactory::create('POST', 'http://www.test.com/', null, array( 'a' => 'b', 'file' => '@' . __FILE__ )); $this->assertEquals(array( 'a' => 'b', 'file' => '@' . __FILE__ ), $request->getPostFields()); $this->assertEquals(array( 'file' => __FILE__ ), $request->getPostFiles()); } /** * @covers Guzzle\Http\Message\RequestFactory::fromParts * @covers Guzzle\Http\Message\RequestFactory::create */ public function testCreatesFromParts() { $parts = parse_url('http://michael:123@www.google.com:8080/path?q=1&v=2'); $request = RequestFactory::fromParts('PUT', $parts, null, 'Data'); $this->assertInstanceOf('Guzzle\\Http\\Message\\EntityEnclosingRequest', $request); $this->assertEquals('PUT', $request->getMethod()); $this->assertEquals('http', $request->getScheme()); $this->assertEquals('http://www.google.com:8080/path?q=1&v=2', $request->getUrl()); $this->assertEquals('www.google.com', $request->getHost()); $this->assertEquals('www.google.com:8080', $request->getHeader('Host')); $this->assertEquals('/path', $request->getPath()); $this->assertEquals('/path?q=1&v=2', $request->getResourceUri()); $this->assertInstanceOf('Guzzle\\Http\\EntityBody', $request->getBody()); $this->assertEquals('Data', (string)$request->getBody()); $this->assertEquals('michael', $request->getUsername()); $this->assertEquals('123', $request->getPassword()); $this->assertEquals('8080', $request->getPort()); $this->assertEquals(array( 'scheme' => 'http', 'host' => 'www.google.com', 'port' => 8080, 'path' => '/path', 'query' => 'q=1&v=2', ), parse_url($request->getUrl())); } /** * @covers Guzzle\Http\Message\RequestFactory::parseMessage * @covers Guzzle\Http\Message\RequestFactory::fromMessage * @covers Guzzle\Http\Message\RequestFactory::create */ public function testCreatesFromMessage() { $auth = base64_encode('michael:123'); $message = "PUT /path?q=1&v=2 HTTP/1.1\r\nHost: www.google.com:8080\r\nContent-Length: 4\r\nAuthorization: Basic {$auth}\r\n\r\nData"; $request = RequestFactory::fromMessage($message); $this->assertInstanceOf('Guzzle\\Http\\Message\\EntityEnclosingRequest', $request); $this->assertEquals('PUT', $request->getMethod()); $this->assertEquals('http', $request->getScheme()); $this->assertEquals('http://www.google.com:8080/path?q=1&v=2', $request->getUrl()); $this->assertEquals('www.google.com', $request->getHost()); $this->assertEquals('www.google.com:8080', $request->getHeader('Host')); $this->assertEquals('/path', $request->getPath()); $this->assertEquals('/path?q=1&v=2', $request->getResourceUri()); $this->assertInstanceOf('Guzzle\\Http\\EntityBody', $request->getBody()); $this->assertEquals('Data', (string)$request->getBody()); $this->assertEquals('michael', $request->getUsername()); $this->assertEquals('123', $request->getPassword()); $this->assertEquals('8080', $request->getPort()); // Test passing a blank message returns false $this->assertFalse($request = RequestFactory::fromMessage('')); // Test passing a url with no port $message = "PUT /path?q=1&v=2 HTTP/1.1\r\nHost: www.google.com\r\nContent-Length: 4\r\nAuthorization: Basic {$auth}\r\n\r\nData"; $request = RequestFactory::fromMessage($message); $this->assertInstanceOf('Guzzle\\Http\\Message\\EntityEnclosingRequest', $request); $this->assertEquals('PUT', $request->getMethod()); $this->assertEquals('http', $request->getScheme()); $this->assertEquals('http://www.google.com/path?q=1&v=2', $request->getUrl()); $this->assertEquals('www.google.com', $request->getHost()); $this->assertEquals('/path', $request->getPath()); $this->assertEquals('/path?q=1&v=2', $request->getResourceUri()); $this->assertInstanceOf('Guzzle\\Http\\EntityBody', $request->getBody()); $this->assertEquals('Data', (string)$request->getBody()); $this->assertEquals('michael', $request->getUsername()); $this->assertEquals('123', $request->getPassword()); $this->assertEquals(80, $request->getPort()); } /** * @covers Guzzle\Http\Message\RequestFactory::create */ public function testCreatesNewTraceRequest() { $request = RequestFactory::create('TRACE', 'http://www.google.com/'); $this->assertFalse($request instanceof \Guzzle\Http\Message\EntityEnclosingRequest); $this->assertEquals('TRACE', $request->getMethod()); } /** * @covers Guzzle\Http\Message\RequestFactory::parseMessage */ public function testParsesMessages() { $parts = RequestFactory::parseMessage( "get /testing?q=10&f=3 http/1.1\r\n" . "host: localhost:443\n" . "authorization: basic bWljaGFlbDoxMjM=\r\n\r\n" ); $this->assertEquals('GET', $parts['method']); $this->assertEquals('HTTP', $parts['protocol']); $this->assertEquals('1.1', $parts['protocol_version']); $this->assertEquals('https', $parts['parts']['scheme']); $this->assertEquals('localhost', $parts['parts']['host']); $this->assertEquals('443', $parts['parts']['port']); $this->assertEquals('michael', $parts['parts']['user']); $this->assertEquals('123', $parts['parts']['pass']); $this->assertEquals('/testing', $parts['parts']['path']); $this->assertEquals('?q=10&f=3', $parts['parts']['query']); $this->assertEquals(array( 'Host' => 'localhost:443', 'Authorization' => 'basic bWljaGFlbDoxMjM=' ), $parts['headers']); $this->assertEquals('', $parts['body']); $parts = RequestFactory::parseMessage( "get / spydy/1.0\r\n" ); $this->assertEquals('GET', $parts['method']); $this->assertEquals('SPYDY', $parts['protocol']); $this->assertEquals('1.0', $parts['protocol_version']); $this->assertEquals('http', $parts['parts']['scheme']); $this->assertEquals('', $parts['parts']['host']); $this->assertEquals('', $parts['parts']['port']); $this->assertEquals('', $parts['parts']['user']); $this->assertEquals('', $parts['parts']['pass']); $this->assertEquals('/', $parts['parts']['path']); $this->assertEquals('', $parts['parts']['query']); $this->assertEquals(array(), $parts['headers']); $this->assertEquals('', $parts['body']); } }tests/Guzzle/Tests/Http/Message/RequestTest.php000064400000072223151742730640015613 0ustar00client = new Client($this->getServer()->getUrl()); $this->request = $this->client->get(); } public function tearDown() { unset($this->request); unset($this->client); } /** * @covers Guzzle\Http\Message\Request::__construct */ public function testConstructorBuildsRequestWithArrayHeaders() { // Test passing an array of headers $request = new Request('GET', 'http://www.guzzle-project.com/', array( 'foo' => 'bar' )); $this->assertEquals('GET', $request->getMethod()); $this->assertEquals('http://www.guzzle-project.com/', $request->getUrl()); $this->assertEquals('bar', $request->getHeader('foo')); } /** * @covers Guzzle\Http\Message\Request::getAllEvents */ public function testDescribesEvents() { $this->assertInternalType('array', Request::getAllEvents()); } /** * @covers Guzzle\Http\Message\Request::__construct */ public function testConstructorBuildsRequestWithCollectionHeaders() { $request = new Request('GET', 'http://www.guzzle-project.com/', new Collection(array( 'foo' => 'bar' ))); $this->assertEquals('bar', $request->getHeader('foo')); } /** * @covers Guzzle\Http\Message\Request::__construct */ public function testConstructorBuildsRequestWithNoHeaders() { $request = new Request('GET', 'http://www.guzzle-project.com/', null); $this->assertFalse($request->hasHeader('foo')); } /** * @covers Guzzle\Http\Message\Request::__toString * @covers Guzzle\Http\Message\Request::getRawHeaders */ public function testRequestsCanBeConvertedToRawMessageStrings() { $auth = base64_encode('michael:123'); $message = "PUT /path?q=1&v=2 HTTP/1.1\r\n" . "Host: www.google.com\r\n" . "Authorization: Basic {$auth}\r\n" . "User-Agent: " . Guzzle::getDefaultUserAgent() . "\r\n" . "Expect: 100-Continue\r\n" . "Content-Length: 4\r\n\r\nData"; $request = RequestFactory::create('PUT', 'http://www.google.com/path?q=1&v=2', array( 'Authorization' => 'Basic ' . $auth ), 'Data'); $this->assertEquals($message, $request->__toString()); } /** * Add authorization after the fact and see that it was put in the message * * @covers Guzzle\Http\Message\Request::__toString * @covers Guzzle\Http\Message\Request::getRawHeaders */ public function testRequestStringsIncludeAuth() { $auth = base64_encode('michael:123'); $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"); $request = RequestFactory::create('PUT', $this->getServer()->getUrl(), null, 'Data') ->setClient($this->client) ->setAuth('michael', '123', CURLAUTH_BASIC); $request->send(); $this->assertContains('Authorization: Basic ' . $auth, (string) $request); } /** * @covers Guzzle\Http\Message\Request::getEventDispatcher */ public function testGetEventDispatcher() { $d = $this->request->getEventDispatcher(); $this->assertInstanceOf('Symfony\\Component\\EventDispatcher\\EventDispatcherInterface', $d); $this->assertEquals($d, $this->request->getEventDispatcher()); } /** * @covers Guzzle\Http\Message\Request::getClient * @covers Guzzle\Http\Message\Request::setClient */ public function testRequestsManageClients() { $request = new Request('GET', 'http://test.com'); $this->assertNull($request->getClient()); $request->setClient($this->client); $this->assertSame($this->client, $request->getClient()); } /** * @covers Guzzle\Http\Message\Request::send * @expectedException RuntimeException * @expectedExceptionMessage A client must be set on the request */ public function testRequestsRequireClients() { $request = new Request('GET', 'http://test.com'); $request->send(); } /** * @covers Guzzle\Http\Message\Request::send * @covers Guzzle\Http\Message\Request::getResponse * @covers Guzzle\Http\Message\Request::setResponse * @covers Guzzle\Http\Message\Request::processResponse * @covers Guzzle\Http\Message\Request::getResponseBody */ public function testSend() { $response = new Response(200, array( 'Content-Length' => 3 ), 'abc'); $this->request->setResponse($response, true); $r = $this->request->send(); $this->assertSame($response, $r); $this->assertInstanceOf('Guzzle\\Http\\Message\\Response', $this->request->getResponse()); $this->assertSame($r, $this->request->getResponse()); $this->assertEquals('complete', $this->request->getState()); } /** * @covers Guzzle\Http\Message\Request::getResponse * @covers Guzzle\Http\Message\Request::setResponse * @covers Guzzle\Http\Message\Request::processResponse * @covers Guzzle\Http\Message\Request::getResponseBody */ public function testGetResponse() { $this->assertNull($this->request->getResponse()); $response = new Response(200, array( 'Content-Length' => 3 ), 'abc'); $this->request->setResponse($response); $this->assertEquals($response, $this->request->getResponse()); $request = new Request('GET', 'http://www.google.com/'); $request->setResponse($response, true); $request->setState(RequestInterface::STATE_COMPLETE); $requestResponse = $request->getResponse(); $this->assertEquals($response, $requestResponse); // Try again, making sure it's still the same response $this->assertEquals($requestResponse, $request->getResponse()); $response = new Response(204); $request = new Request('GET', 'http://www.google.com/'); $request->setResponse($response, true); $request->setState('complete'); $requestResponse = $request->getResponse(); $this->assertEquals($response, $requestResponse); $this->assertInstanceOf('Guzzle\\Http\\EntityBody', $response->getBody()); } /** * @covers Guzzle\Http\Message\Request::getResponse * @covers Guzzle\Http\Message\Request::processResponse * @covers Guzzle\Http\Message\Request::getResponseBody */ public function testRequestThrowsExceptionOnBadResponse() { $response = new Response(404, array( 'Content-Length' => 3 ), 'abc'); $request = new Request('GET', 'http://www.google.com/'); $request->setClient($this->client); try { $request->setResponse($response, true); $request->send(); $this->fail('Expected exception not thrown'); } catch (BadResponseException $e) { $this->assertInstanceOf('Guzzle\\Http\\Message\\RequestInterface', $e->getRequest()); $this->assertInstanceOf('Guzzle\\Http\\Message\\Response', $e->getResponse()); $message = "Unsuccessful response | [status code] 404 | " . "[reason phrase] Not Found | [url] http://www.google.com/ | " . "[request] GET / HTTP/1.1\r\nHost: www.google.com\r\n" . "User-Agent: " . Guzzle::getDefaultUserAgent() . "\r\n\r\n" . " | [response] HTTP/1.1 404 Not Found\r\nContent-Length: 3" . "\r\n\r\nabc"; $this->assertEquals($message, $e->getMessage()); } } /** * @covers Guzzle\Http\Message\Request::getQuery */ public function testManagesQuery() { $this->assertInstanceOf('Guzzle\\Http\\QueryString', $this->request->getQuery()); $this->request->getQuery()->set('test', '123'); $this->assertEquals('?test=123', $this->request->getQuery(true)); } /** * @covers Guzzle\Http\Message\Request::getMethod */ public function testRequestHasMethod() { $this->assertEquals('GET', $this->request->getMethod()); } /** * @covers Guzzle\Http\Message\Request::getScheme * @covers Guzzle\Http\Message\Request::setScheme */ public function testRequestHasScheme() { $this->assertEquals('http', $this->request->getScheme()); $this->assertEquals($this->request, $this->request->setScheme('https')); $this->assertEquals('https', $this->request->getScheme()); } /** * @covers Guzzle\Http\Message\Request::getHost * @covers Guzzle\Http\Message\Request::setHost */ public function testRequestHasHost() { $this->assertEquals('127.0.0.1', $this->request->getHost()); $this->assertEquals('127.0.0.1:8124', $this->request->getHeader('Host')); $this->assertSame($this->request, $this->request->setHost('www2.google.com')); $this->assertEquals('www2.google.com', $this->request->getHost()); $this->assertEquals('www2.google.com', $this->request->getHeader('Host')); $this->assertSame($this->request, $this->request->setHost('www.test.com:8081')); $this->assertEquals('www.test.com', $this->request->getHost()); $this->assertEquals(8081, $this->request->getPort()); } /** * @covers Guzzle\Http\Message\Request::getProtocolVersion * @covers Guzzle\Http\Message\Request::setProtocolVersion */ public function testRequestHasProtocol() { $this->assertEquals('1.1', $this->request->getProtocolVersion()); $this->assertEquals($this->request, $this->request->setProtocolVersion('1.1')); $this->assertEquals('1.1', $this->request->getProtocolVersion()); $this->assertEquals($this->request, $this->request->setProtocolVersion('1.0')); $this->assertEquals('1.0', $this->request->getProtocolVersion()); } /** * @covers Guzzle\Http\Message\Request::getPath * @covers Guzzle\Http\Message\Request::setPath */ public function testRequestHasPath() { $this->assertEquals('/', $this->request->getPath()); $this->assertEquals($this->request, $this->request->setPath('/index.html')); $this->assertEquals('/index.html', $this->request->getPath()); $this->assertEquals($this->request, $this->request->setPath('index.html')); $this->assertEquals('/index.html', $this->request->getPath()); } /** * @covers Guzzle\Http\Message\Request::getPort * @covers Guzzle\Http\Message\Request::setPort */ public function testRequestHasPort() { $this->assertEquals(8124, $this->request->getPort()); $this->assertEquals('127.0.0.1:8124', $this->request->getHeader('Host')); $this->assertEquals($this->request, $this->request->setPort('8080')); $this->assertEquals('8080', $this->request->getPort()); $this->assertEquals('127.0.0.1:8080', $this->request->getHeader('Host')); $this->request->setPort(80); $this->assertEquals('127.0.0.1', $this->request->getHeader('Host')); } /** * @covers Guzzle\Http\Message\Request::getUsername * @covers Guzzle\Http\Message\Request::getPassword * @covers Guzzle\Http\Message\Request::setAuth */ public function testRequestHandlesAuthorization() { // Uninitialized auth $this->assertEquals(null, $this->request->getUsername()); $this->assertEquals(null, $this->request->getPassword()); // Set an auth $this->assertSame($this->request, $this->request->setAuth('michael', '123')); $this->assertEquals('michael', $this->request->getUsername()); $this->assertEquals('123', $this->request->getPassword()); // Remove the auth $this->request->setAuth(false); $this->assertEquals(null, $this->request->getUsername()); $this->assertEquals(null, $this->request->getPassword()); // Make sure that the cURL based auth works too $request = new Request('GET', $this->getServer()->getUrl()); $request->setAuth('michael', 'password', CURLAUTH_DIGEST); $this->assertEquals('michael:password', $request->getCurlOptions()->get(CURLOPT_USERPWD)); $this->assertEquals(CURLAUTH_DIGEST, $request->getCurlOptions()->get(CURLOPT_HTTPAUTH)); } /** * @covers Guzzle\Http\Message\Request::getResourceUri */ public function testGetResourceUri() { $this->assertEquals('/', $this->request->getResourceUri()); $this->request->setPath('/index.html'); $this->assertEquals('/index.html', $this->request->getResourceUri()); $this->request->getQuery()->add('v', '1'); $this->assertEquals('/index.html?v=1', $this->request->getResourceUri()); } /** * @covers Guzzle\Http\Message\Request::getUrl * @covers Guzzle\Http\Message\Request::setUrl */ public function testRequestHasMutableUrl() { $url = 'http://www.test.com:8081/path?q=123#fragment'; $u = Url::factory($url); $this->assertSame($this->request, $this->request->setUrl($url)); $this->assertEquals($url, $this->request->getUrl()); $this->assertSame($this->request, $this->request->setUrl($u)); $this->assertEquals($url, $this->request->getUrl()); try { $this->request->setUrl(10); $this->fail('Expected exception not thrown'); } catch (\InvalidArgumentException $e) { } } /** * @covers Guzzle\Http\Message\Request::setState * @covers Guzzle\Http\Message\Request::getState */ public function testRequestHasState() { $this->assertEquals(RequestInterface::STATE_NEW, $this->request->getState()); $this->request->setState(RequestInterface::STATE_TRANSFER); $this->assertEquals(RequestInterface::STATE_TRANSFER, $this->request->getState()); } /** * @covers Guzzle\Http\Message\Request::setResponse * @covers Guzzle\Http\Message\Request::getResponse * @covers Guzzle\Http\Message\Request::getState */ public function testSetManualResponse() { $response = new Response(200, array( 'Date' => 'Sat, 16 Oct 2010 17:27:14 GMT', 'Expires' => '-1', 'Cache-Control' => 'private, max-age=0', 'Content-Type' => 'text/html; charset=ISO-8859-1', ), 'response body'); $this->assertSame($this->request, $this->request->setResponse($response), '-> setResponse() must use a fluent interface'); $this->assertEquals('complete', $this->request->getState(), '-> setResponse() must change the state of the request to complete'); $this->assertSame($response, $this->request->getResponse(), '-> setResponse() must set the exact same response that was passed in to it'); } /** * @covers Guzzle\Http\Message\Request::setResponseBody */ public function testRequestCanHaveManuallySetResponseBody() { $file = __DIR__ . '/../../TestData/temp.out'; if (file_exists($file)) { unlink($file); } $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 4\r\n\r\ndata"); $request = RequestFactory::create('GET', $this->getServer()->getUrl()); $request->setClient($this->client); $request->setResponseBody(EntityBody::factory(fopen($file, 'w+'))); $request->send(); $this->assertTrue(file_exists($file)); unlink($file); $this->assertEquals('data', $request->getResponse()->getBody(true)); } /** * @covers Guzzle\Http\Message\Request::isResponseBodyRepeatable */ public function testDeterminesIfResponseBodyRepeatable() { // The default stream created for responses is seekable $request = RequestFactory::create('GET', 'http://localhost:' . $this->getServer()->getPort()); $this->assertTrue($request->isResponseBodyRepeatable()); // This should return false because an HTTP stream is not seekable $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 4\r\n\r\ndata"); $request->setResponseBody(EntityBody::factory(fopen($this->getServer()->getUrl(), true))); $this->assertFalse($request->isResponseBodyRepeatable()); } /** * @covers Guzzle\Http\Message\Request::canCache */ public function testDeterminesIfCanCacheRequest() { $this->assertTrue(RequestFactory::fromMessage( "GET / HTTP/1.1\r\nHost: www.test.com\r\nCache-Control: no-cache, max-age=120\r\n\r\n" )->canCache()); $this->assertTrue(RequestFactory::fromMessage( "HEAD / HTTP/1.1\r\nHost: www.test.com\r\nCache-Control: no-cache, max-age=120\r\n\r\n" )->canCache()); $this->assertFalse(RequestFactory::fromMessage( "HEAD / HTTP/1.1\r\nHost: www.test.com\r\nCache-Control: no-cache, max-age=120, no-store\r\n\r\n" )->canCache()); $this->assertFalse(RequestFactory::fromMessage( "POST / HTTP/1.1\r\nHost: www.test.com\r\n\r\n" )->canCache()); $this->assertFalse(RequestFactory::fromMessage( "PUT / HTTP/1.1\r\nHost: www.test.com\r\nCache-Control: no-cache, max-age=120\r\n\r\n" )->canCache()); } /** * @covers Guzzle\Http\Message\Request */ public function testHoldsCookies() { $cookie = $this->request->getCookie(); $this->assertInstanceOf('Guzzle\\Http\\Cookie', $this->request->getCookie()); // Ensure that the cookie will not affect the request $this->assertNull($this->request->getCookie('test')); $cookie->set('test', 'abc'); $this->assertNull($this->request->getCookie('test')); // Set a cookie $this->assertSame($this->request, $this->request->addCookie('test', 'abc')); $this->assertEquals('abc', $this->request->getCookie('test')); // Unset the cookies by setting the Cookie header to null $this->request->setHeader('Cookie', null); $this->assertNull($this->request->getCookie('test')); // Set and remove a cookie $this->assertSame($this->request, $this->request->addCookie('test', 'abc')); $this->assertEquals('abc', $this->request->getCookie('test')); $this->assertSame($this->request, $this->request->removeCookie('test')); $this->assertNull($this->request->getCookie('test')); // Remove the cookie header $this->assertSame($this->request, $this->request->addCookie('test', 'abc')); $this->request->removeHeader('Cookie'); $this->assertEquals('', (string)$this->request->getCookie()); // Set the cookie using a cookie object $this->assertSame($this->request, $this->request->setCookie($cookie)); $this->assertEquals($cookie->getAll(), $this->request->getCookie()->getAll()); // Set the cookie using an array $this->assertSame($this->request, $this->request->setCookie(array( 'test' => 'def' ))); $this->assertEquals(array( 'test' => 'def' ), $this->request->getCookie()->getAll()); // Test using an invalid value try { $this->request->setCookie('a'); $this->fail('Did not throw expected exception when passing invalid value'); } catch (\InvalidArgumentException $e) { } } /** * @covers Guzzle\Http\Message\Request::processResponse * @expectedException Guzzle\Http\Message\RequestException * @expectedExceptionMessage Error completing request */ public function testRequestThrowsExceptionWhenSetToCompleteWithNoResponse() { $this->request->setState(RequestInterface::STATE_COMPLETE); } /** * @covers Guzzle\Http\Message\Request::__clone */ public function testClonedRequestsUseNewInternalState() { $p = new ExponentialBackoffPlugin(); $this->request->getEventDispatcher()->addSubscriber($p); $r = clone $this->request; $this->assertEquals(RequestInterface::STATE_NEW, $r->getState()); $this->assertNotSame($r->getQuery(), $this->request->getQuery()); $this->assertNotSame($r->getCurlOptions(), $this->request->getCurlOptions()); $this->assertNotSame($r->getEventDispatcher(), $this->request->getEventDispatcher()); $this->assertNotSame($r->getHeaders(), $this->request->getHeaders()); $this->assertNotSame($r->getParams(), $this->request->getParams()); $this->assertNull($r->getParams()->get('queued_response')); $this->assertTrue($this->request->getEventDispatcher()->hasListeners('request.sent')); } /** * @covers Guzzle\Http\Message\Request::changedHeader * @covers Guzzle\Http\Message\Request::setHeader */ public function testCatchesAllHostHeaderChanges() { // Tests setting using headers $this->request->setHeader('Host', 'www.abc.com'); $this->assertEquals('www.abc.com', $this->request->getHost()); $this->assertEquals('www.abc.com', $this->request->getHeader('Host')); $this->assertEquals(80, $this->request->getPort()); // Tests setting using setHost() $this->request->setHost('abc.com'); $this->assertEquals('abc.com', $this->request->getHost()); $this->assertEquals('abc.com', $this->request->getHeader('Host')); $this->assertEquals(80, $this->request->getPort()); // Tests setting with a port $this->request->setHost('abc.com:8081'); $this->assertEquals('abc.com', $this->request->getHost()); $this->assertEquals('abc.com:8081', $this->request->getHeader('Host')); $this->assertEquals(8081, $this->request->getPort()); // Tests setting with a port using the Host header $this->request->setHeader('Host', 'solr.com:8983'); $this->assertEquals('solr.com', $this->request->getHost()); $this->assertEquals('solr.com:8983', $this->request->getHeader('Host')); $this->assertEquals(8983, $this->request->getPort()); // Tests setting with an inferred 443 port using the Host header $this->request->setScheme('https'); $this->request->setHeader('Host', 'solr.com'); $this->assertEquals('solr.com', $this->request->getHost()); $this->assertEquals('solr.com', $this->request->getHeader('Host')); $this->assertEquals(443, $this->request->getPort()); } /** * @covers Guzzle\Http\Message\Request::setUrl */ public function testRecognizesBasicAuthCredentialsInUrls() { $this->request->setUrl('http://michael:test@test.com/'); $this->assertEquals('michael', $this->request->getUsername()); $this->assertEquals('test', $this->request->getPassword()); } /** * This test launches a dummy Guzzle\Http\Server\Server object that listens * for incoming requests. The server allows us to test how cURL sends * requests and receives responses. We can validate the request structure * and whether or not the response was interpreted correctly. * * @covers Guzzle\Http\Message\Request */ public function testRequestCanBeSentUsingCurl() { $this->getServer()->flush(); $this->getServer()->enqueue(array( "HTTP/1.1 200 OK\r\nContent-Length: 4\r\nExpires: Thu, 01 Dec 1994 16:00:00 GMT\r\nConnection: close\r\n\r\ndata", "HTTP/1.1 200 OK\r\nContent-Length: 4\r\nExpires: Thu, 01 Dec 1994 16:00:00 GMT\r\nConnection: close\r\n\r\ndata", "HTTP/1.1 404 Not Found\r\nContent-Encoding: application/xml\r\nContent-Length: 48\r\n\r\nFile not found" )); $request = RequestFactory::create('GET', $this->getServer()->getUrl()); $request->setClient($this->client); $response = $request->send(); $this->assertEquals('data', $response->getBody(true)); $this->assertEquals(200, (int) $response->getStatusCode()); $this->assertEquals('OK', $response->getReasonPhrase()); $this->assertEquals(4, $response->getContentLength()); $this->assertEquals('Thu, 01 Dec 1994 16:00:00 GMT', $response->getExpires()); // Test that the same handle can be sent twice without setting state to new $response2 = $request->send(); $this->assertNotSame($response, $response2); try { $request = RequestFactory::create('GET', $this->getServer()->getUrl() . 'index.html'); $request->setClient($this->client); $response = $request->send(); $this->fail('Request did not receive a 404 response'); } catch (BadResponseException $e) { } $requests = $this->getServer()->getReceivedRequests(true); $messages = $this->getServer()->getReceivedRequests(false); $port = $this->getServer()->getPort(); $userAgent = Guzzle::getDefaultUserAgent(); $this->assertEquals('127.0.0.1:' . $port, $requests[0]->getHeader('Host')); $this->assertEquals('127.0.0.1:' . $port, $requests[1]->getHeader('Host')); $this->assertEquals('127.0.0.1:' . $port, $requests[2]->getHeader('Host')); $this->assertEquals('/', $requests[0]->getPath()); $this->assertEquals('/', $requests[1]->getPath()); $this->assertEquals('/index.html', $requests[2]->getPath()); $parts = explode("\r\n", $messages[0]); $this->assertEquals('GET / HTTP/1.1', $parts[0]); $parts = explode("\r\n", $messages[1]); $this->assertEquals('GET / HTTP/1.1', $parts[0]); $parts = explode("\r\n", $messages[2]); $this->assertEquals('GET /index.html HTTP/1.1', $parts[0]); } /** * @covers Guzzle\Http\Message\Request::onRequestError */ public function testThrowsExceptionsWhenUnsuccessfulResponseIsReceivedByDefault() { $this->getServer()->flush(); $this->getServer()->enqueue("HTTP/1.1 404 Not found\r\nContent-Length: 0\r\n\r\n"); try { $request = $this->client->get('/index.html'); $response = $request->send(); $this->fail('Request did not receive a 404 response'); } catch (BadResponseException $e) { $this->assertContains('Unsuccessful response ', $e->getMessage()); $this->assertContains('[status code] 404 | [reason phrase] Not found | [url] http://127.0.0.1:8124/index.html | [request] GET /index.html HTTP/1.1', $e->getMessage()); $this->assertContains('Host: 127.0.0.1:8124', $e->getMessage()); $this->assertContains(" | [response] HTTP/1.1 404 Not found", $e->getMessage()); } } /** * @covers Guzzle\Http\Message\Request::onRequestError */ public function testCanShortCircuitErrorHandling() { $request = $this->request; $response = new Response(404); $request->setResponse($response, true); $out = ''; $that = $this; $request->getEventDispatcher()->addListener('request.error', function($event) use (&$out, $that) { $out .= $event['request'] . "\n" . $event['response'] . "\n"; $event->stopPropagation(); }); $request->send(); $this->assertContains((string) $request, $out); $this->assertContains((string) $request->getResponse(), $out); $this->assertSame($response, $request->getResponse()); } /** * @covers Guzzle\Http\Message\Request::processResponse * @covers Guzzle\Http\Message\Request::onRequestError */ public function testCanOverrideUnsuccessfulResponses() { $this->getServer()->flush(); $this->getServer()->enqueue(array( "HTTP/1.1 404 NOT FOUND\r\n" . "Content-Length: 0\r\n" . "\r\n", "HTTP/1.1 200 OK\r\n" . "Content-Length: 0\r\n" . "\r\n" )); $newResponse = null; $request = $this->request; $request->getEventDispatcher()->addListener('request.error', function($event) use (&$newResponse) { if ($event['response']->getStatusCode() == 404) { $newRequest = clone $event['request']; $newResponse = $newRequest->send(); // Override the original response and bypass additional response processing $event['response'] = $newResponse; // Call $event['request']->setResponse($newResponse); to re-apply events $event->stopPropagation(); } }); $request->send(); $this->assertEquals(200, $request->getResponse()->getStatusCode()); $this->assertSame($newResponse, $request->getResponse()); $this->assertEquals(2, count($this->getServer()->getReceivedRequests())); } }tests/Guzzle/Tests/Http/Message/ResponseTest.php000064400000061553151742730640015765 0ustar00response = new Response(200, new Collection(array( 'Accept-Ranges' => 'bytes', 'Age' => '12', 'Allow' => 'GET, HEAD', 'Cache-Control' => 'no-cache', 'Content-Encoding' => 'gzip', 'Content-Language' => 'da', 'Content-Length' => '348', 'Content-Location' => '/index.htm', 'Content-Disposition' => 'attachment; filename=fname.ext', 'Content-MD5' => 'Q2hlY2sgSW50ZWdyaXR5IQ==', 'Content-Range' => 'bytes 21010-47021/47022', 'Content-Type' => 'text/html; charset=utf-8', 'Date' => 'Tue, 15 Nov 1994 08:12:31 GMT', 'ETag' => '737060cd8c284d8af7ad3082f209582d', 'Expires' => 'Thu, 01 Dec 1994 16:00:00 GMT', 'Last-Modified' => 'Tue, 15 Nov 1994 12:45:26 GMT', 'Location' => 'http://www.w3.org/pub/WWW/People.html', 'Pragma' => 'no-cache', 'Proxy-Authenticate' => 'Basic', 'Retry-After' => '120', 'Server' => 'Apache/1.3.27 (Unix) (Red-Hat/Linux)', 'Set-Cookie' => 'UserID=JohnDoe; Max-Age=3600; Version=1', 'Trailer' => 'Max-Forwards', 'Transfer-Encoding' => 'chunked', 'Vary' => '*', 'Via' => '1.0 fred, 1.1 nowhere.com (Apache/1.1)', 'Warning' => '199 Miscellaneous warning', 'WWW-Authenticate' => 'Basic' )), 'body'); } /** * @covers Guzzle\Http\Message\Response::__construct */ public function testConstructor() { $params = new Collection(); $body = EntityBody::factory(''); $response = new Response(200, $params, $body); $this->assertEquals(200, $response->getStatusCode()); $this->assertEquals($body, $response->getBody()); $this->assertEquals($params, $response->getHeaders()); $this->assertEquals('OK', $response->getReasonPhrase()); $this->assertEquals("HTTP/1.1 200 OK\r\n\r\n", $response->getRawHeaders()); // Make sure Content-Length is set automatically $response = new Response(200, $params); $this->assertEquals("HTTP/1.1 200 OK\r\n\r\n", $response->getRawHeaders()); // Pass bodies to the response $response = new Response(200, null, 'data'); $this->assertInstanceOf('Guzzle\\Http\\EntityBody', $response->getBody()); $response = new Response(200, null, EntityBody::factory('data')); $this->assertInstanceOf('Guzzle\\Http\\EntityBody', $response->getBody()); $this->assertEquals('data', $response->getBody(true)); // Make sure the proper exception is thrown try { $response = new Response(200, null, array('foo' => 'bar')); $this->fail('Response did not throw exception when passing invalid body'); } catch (HttpException $e) { } // Make sure the proper exception is thrown when sending invalid code try { $response = new Response(2); $this->fail('Response did not throw exception when passing invalid $code'); } catch (BadResponseException $e) { } // Make sure the proper exception is thrown when sending invalid headers try { $response = new Response(200, 'adidas'); $this->fail('Response did not throw exception when passing invalid $headers'); } catch (BadResponseException $e) { } } /** * @covers Guzzle\Http\Message\Response::__toString */ public function test__toString() { $response = new Response(200); $this->assertEquals("HTTP/1.1 200 OK\r\n\r\n", (string)$response); // Add another header $response = new Response(200, array( 'X-Test' => 'Guzzle' )); $this->assertEquals("HTTP/1.1 200 OK\r\nX-Test: Guzzle\r\n\r\n", (string)$response); $response = new Response(200, array( 'Content-Length' => 4 ), 'test'); $this->assertEquals("HTTP/1.1 200 OK\r\nContent-Length: 4\r\n\r\ntest", (string)$response); } /** * @covers Guzzle\Http\Message\Response::factory */ public function testFactory() { $response = Response::factory("HTTP/1.1 200 OK\r\nContent-Length: 4\r\n\r\ntest"); $this->assertEquals(200, $response->getStatusCode()); $this->assertEquals('OK', $response->getReasonPhrase()); $this->assertEquals(4, $response->getContentLength()); $this->assertEquals('test', $response->getBody(true)); // Make sure that automatic Content-Length works $response = Response::factory("HTTP/1.1 200 OK\r\nContent-Length: x\r\n\r\ntest"); $this->assertEquals(4, $response->getContentLength()); $this->assertEquals('test', $response->getBody(true)); } /** * @covers Guzzle\Http\Message\Response::factory * @expectedException Guzzle\Http\HttpException */ public function testFactoryRequiresMessage() { $response = Response::factory(''); } /** * @covers Guzzle\Http\Message\Response::getBody */ public function testGetBody() { $body = EntityBody::factory(''); $response = new Response(403, new Collection(), $body); $this->assertEquals($body, $response->getBody()); } /** * @covers Guzzle\Http\Message\Response::getStatusCode */ public function testManagesStatusCode() { $response = new Response(403); $this->assertEquals(403, $response->getStatusCode()); } /** * @covers Guzzle\Http\Message\Response::getMessage */ public function testGetMessage() { $response = new Response(200, new Collection(array( 'Content-Length' => 4 )), 'body'); $this->assertEquals("HTTP/1.1 200 OK\r\nContent-Length: 4\r\n\r\nbody", $response->getMessage()); } /** * @covers Guzzle\Http\Message\Response::getRawHeaders */ public function testGetRawHeaders() { $response = new Response(200, new Collection(array( 'Keep-Alive' => 155, 'User-Agent' => 'Guzzle', 'Content-Length' => 4 )), 'body'); $this->assertEquals("HTTP/1.1 200 OK\r\nKeep-Alive: 155\r\nUser-Agent: Guzzle\r\nContent-Length: 4\r\n\r\n", $response->getRawHeaders()); } /** * @covers Guzzle\Http\Message\Response::getRequest */ public function testGetRequest() { $response = new Response(200, new Collection(), 'body'); $this->assertNull($response->getRequest()); $request = new \Guzzle\Http\Message\Request('GET', 'http://www.guzzle-project.com/'); $response->setRequest($request); $this->assertEquals($request, $response->getRequest()); } /** * @covers Guzzle\Http\Message\Response::getReasonPhrase * @covers Guzzle\Http\Message\Response::setStatus */ public function testHandlesStatusAndStatusCodes() { $response = new Response(200, new Collection(), 'body'); $this->assertEquals('OK', $response->getReasonPhrase()); $this->assertSame($response, $response->setStatus(204)); $this->assertEquals('No Content', $response->getReasonPhrase()); $this->assertEquals(204, $response->getStatusCode()); $this->assertSame($response, $response->setStatus(204, 'Testing!')); $this->assertEquals('Testing!', $response->getReasonPhrase()); $this->assertEquals(204, $response->getStatusCode()); try { $response->setStatus(2000); $this->fail('Did not throw expected exception when setting an invalid status'); } catch (BadResponseException $e) { } } /** * @covers Guzzle\Http\Message\Response::isClientError */ public function testIsClientError() { $response = new Response(403); $this->assertTrue($response->isClientError()); $response = new Response(200); $this->assertFalse($response->isClientError()); } /** * @covers Guzzle\Http\Message\Response::isError */ public function testIsError() { $response = new Response(403); $this->assertTrue($response->isError()); $response = new Response(200); $this->assertFalse($response->isError()); $response = new Response(500); $this->assertTrue($response->isError()); } /** * @covers Guzzle\Http\Message\Response::isInformational */ public function testIsInformational() { $response = new Response(100); $this->assertTrue($response->isInformational()); $response = new Response(200); $this->assertFalse($response->isInformational()); } /** * @covers Guzzle\Http\Message\Response::isRedirect */ public function testIsRedirect() { $response = new Response(301); $this->assertTrue($response->isRedirect()); $response = new Response(200); $this->assertFalse($response->isRedirect()); } /** * @covers Guzzle\Http\Message\Response::isServerError */ public function testIsServerError() { $response = new Response(500); $this->assertTrue($response->isServerError()); $response = new Response(400); $this->assertFalse($response->isServerError()); } /** * @covers Guzzle\Http\Message\Response::isSuccessful */ public function testIsSuccessful() { $response = new Response(200); $this->assertTrue($response->isSuccessful()); $response = new Response(403); $this->assertFalse($response->isSuccessful()); } /** * @covers Guzzle\Http\Message\Response::setRequest */ public function testSetRequest() { $response = new Response(200); $this->assertNull($response->getRequest()); $r = new \Guzzle\Http\Message\Request('GET', 'http://www.guzzle-project.com/'); $response->setRequest($r); $this->assertEquals($r, $response->getRequest()); } /** * @covers Guzzle\Http\Message\Response::getAcceptRanges */ public function testGetAcceptRanges() { $this->assertEquals('bytes', $this->response->getAcceptRanges()); } /** * @covers Guzzle\Http\Message\Response::getAge */ public function testGetAge() { $this->assertEquals(12, $this->response->getAge(false)); $this->assertEquals(12, $this->response->getAge(true)); $this->response->removeHeader('Age'); $this->response->removeHeader('Date'); $this->assertNull($this->response->getAge()); $this->response->setHeader('Date', Guzzle::getHttpDate(strtotime('-1 minute'))); // If the test runs slowly, still pass with a +5 second allowance $this->assertTrue($this->response->getAge() - 60 <= 5); $this->assertNull($this->response->getAge(true)); } /** * @covers Guzzle\Http\Message\Response::getAllow */ public function testGetAllow() { $this->assertEquals('GET, HEAD', $this->response->getAllow()); } /** * @covers Guzzle\Http\Message\Response::getCacheControl */ public function testGetCacheControl() { $this->assertEquals('no-cache', $this->response->getCacheControl()); } /** * @covers Guzzle\Http\Message\Response::getContentEncoding */ public function testGetContentEncoding() { $this->assertEquals('gzip', $this->response->getContentEncoding()); } /** * @covers Guzzle\Http\Message\Response::getContentLanguage */ public function testGetContentLanguage() { $this->assertEquals('da', $this->response->getContentLanguage()); } /** * @covers Guzzle\Http\Message\Response::getContentLength */ public function testGetContentLength() { $this->assertEquals('348', $this->response->getContentLength()); } /** * @covers Guzzle\Http\Message\Response::getContentLocation */ public function testGetContentLocation() { $this->assertEquals('/index.htm', $this->response->getContentLocation()); } /** * @covers Guzzle\Http\Message\Response::getContentDisposition */ public function testGetContentDisposition() { $this->assertEquals('attachment; filename=fname.ext', $this->response->getContentDisposition()); } /** * @covers Guzzle\Http\Message\Response::getContentMd5 */ public function testGetContentMd5() { $this->assertEquals('Q2hlY2sgSW50ZWdyaXR5IQ==', $this->response->getContentMd5()); } /** * @covers Guzzle\Http\Message\Response::getContentRange */ public function testGetContentRange() { $this->assertEquals('bytes 21010-47021/47022', $this->response->getContentRange()); } /** * @covers Guzzle\Http\Message\Response::getContentType */ public function testGetContentType() { $this->assertEquals('text/html; charset=utf-8', $this->response->getContentType()); } /** * @covers Guzzle\Http\Message\Response::getDate */ public function testGetDate() { $this->assertEquals('Tue, 15 Nov 1994 08:12:31 GMT', $this->response->getDate()); } /** * @covers Guzzle\Http\Message\Response::getEtag */ public function testGetEtag() { $this->assertEquals('737060cd8c284d8af7ad3082f209582d', $this->response->getEtag()); } /** * @covers Guzzle\Http\Message\Response::getExpires */ public function testGetExpires() { $this->assertEquals('Thu, 01 Dec 1994 16:00:00 GMT', $this->response->getExpires()); } /** * @covers Guzzle\Http\Message\Response::getLastModified */ public function testGetLastModified() { $this->assertEquals('Tue, 15 Nov 1994 12:45:26 GMT', $this->response->getLastModified()); } /** * @covers Guzzle\Http\Message\Response::getLocation */ public function testGetLocation() { $this->assertEquals('http://www.w3.org/pub/WWW/People.html', $this->response->getLocation()); } /** * @covers Guzzle\Http\Message\Response::getPragma */ public function testGetPragma() { $this->assertEquals('no-cache', $this->response->getPragma()); } /** * @covers Guzzle\Http\Message\Response::getProxyAuthenticate */ public function testGetProxyAuthenticate() { $this->assertEquals('Basic', $this->response->getProxyAuthenticate()); } /** * @covers Guzzle\Http\Message\Response::getRetryAfter */ public function testGetRetryAfter() { $this->assertEquals('120', $this->response->getRetryAfter()); } /** * @covers Guzzle\Http\Message\Response::getServer */ public function testGetServer() { $this->assertEquals('Apache/1.3.27 (Unix) (Red-Hat/Linux)', $this->response->getServer()); } /** * @covers Guzzle\Http\Message\Response::getSetCookie */ public function testGetSetCookie() { $this->assertEquals('UserID=JohnDoe; Max-Age=3600; Version=1', $this->response->getSetCookie()); } /** * @covers Guzzle\Http\Message\Response::getTrailer */ public function testGetTrailer() { $this->assertEquals('Max-Forwards', $this->response->getTrailer()); } /** * @covers Guzzle\Http\Message\Response::getTransferEncoding */ public function testGetTransferEncoding() { $this->assertEquals('chunked', $this->response->getTransferEncoding()); } /** * @covers Guzzle\Http\Message\Response::getVary */ public function testGetVary() { $this->assertEquals('*', $this->response->getVary()); } /** * @covers Guzzle\Http\Message\Response::getVia */ public function testReturnsViaHeader() { $this->assertEquals('1.0 fred, 1.1 nowhere.com (Apache/1.1)', $this->response->getVia()); } /** * @covers Guzzle\Http\Message\Response::getWarning */ public function testGetWarning() { $this->assertEquals('199 Miscellaneous warning', $this->response->getWarning()); } /** * @covers Guzzle\Http\Message\Response::getWwwAuthenticate */ public function testReturnsWwwAuthenticateHeader() { $this->assertEquals('Basic', $this->response->getWwwAuthenticate()); } /** * @covers Guzzle\Http\Message\Response::getConnection */ public function testReturnsConnectionHeader() { $this->assertEquals(null, $this->response->getConnection()); $this->response->setHeader('Connection', 'close'); $this->assertEquals('close', $this->response->getConnection()); } /** * @covers Guzzle\Http\Message\Response::getHeader */ public function testReturnsHeaders() { $this->assertEquals('Basic', $this->response->getHeader('WWW-Authenticate', null, true)); $this->assertEquals('chunked', $this->response->getHeader('Transfer-Encoding', null, false)); } /** * @covers Guzzle\Http\Message\Response::setInfo * @covers Guzzle\Http\Message\Response::getInfo */ public function testHasTransferInfo() { $stats = array ( 'url' => 'http://www.google.com/', 'content_type' => 'text/html; charset=ISO-8859-1', 'http_code' => 200, 'header_size' => 606, 'request_size' => 53, 'filetime' => -1, 'ssl_verify_result' => 0, 'redirect_count' => 0, 'total_time' => 0.093284, 'namelookup_time' => 0.001349, 'connect_time' => 0.01635, 'pretransfer_time' => 0.016358, 'size_upload' => 0, 'size_download' => 10330, 'speed_download' => 110737, 'speed_upload' => 0, 'download_content_length' => -1, 'upload_content_length' => 0, 'starttransfer_time' => 0.07066, 'redirect_time' => 0, ); // Uninitialized state $this->assertNull($this->response->getInfo('url')); $this->assertEquals(array(), $this->response->getInfo()); // Set the stats $this->response->setInfo($stats); $this->assertEquals($stats, $this->response->getInfo()); $this->assertEquals(606, $this->response->getInfo('header_size')); $this->assertNull($this->response->getInfo('does_not_exist')); } /** * @return Response */ private function getResponse($code, array $headers = null, EntityBody $body = null) { return new Response($code, $headers, $body); } /** * @covers Guzzle\Http\Message\Response::canCache */ public function testDeterminesIfItCanBeCached() { $this->assertTrue($this->getResponse(200)->canCache()); $this->assertTrue($this->getResponse(410)->canCache()); $this->assertFalse($this->getResponse(404)->canCache()); $this->assertTrue($this->getResponse(200, array( 'Cache-Control' => 'public' ))->canCache()); // This has the no-store directive $this->assertFalse($this->getResponse(200, array( 'Cache-Control' => 'private, no-store' ))->canCache()); // The body cannot be read, so it cannot be cached $tmp = tempnam('/tmp', 'not-readable'); $resource = fopen($tmp, 'w'); $this->assertFalse($this->getResponse(200, array( 'Transfer-Encoding' => 'chunked' ), EntityBody::factory($resource, 10))->canCache()); unlink($tmp); // The body is 0 length, cannot be read, so it can be cached $tmp = tempnam('/tmp', 'not-readable'); $resource = fopen($tmp, 'w'); $this->assertTrue($this->getResponse(200, array(array( 'Content-Length' => 0 )), EntityBody::factory($resource, 0))->canCache()); unlink($tmp); // When an HTTPS request is sent and the Cache-Control directive does // not include a 'public' value, then the response is not to be cached $request = RequestFactory::create('GET', 'https://www.test.com/'); $response = new Response(200); $response->setRequest($request); $this->assertFalse($response->canCache()); // This response can be cache because it is public $response->setHeader('Cache-Control', 'public'); $this->assertTrue($response->canCache()); } /** * @covers Guzzle\Http\Message\Response::getMaxAge */ public function testDeterminesResponseMaxAge() { $this->assertEquals(null, $this->getResponse(200)->getMaxAge()); // Uses the response's s-maxage $this->assertEquals(140, $this->getResponse(200, array( 'Cache-Control' => 's-maxage=140' ))->getMaxAge()); // Uses the response's max-age $this->assertEquals(120, $this->getResponse(200, array( 'Cache-Control' => 'max-age=120' ))->getMaxAge()); // Uses the response's max-age $this->assertEquals(120, $this->getResponse(200, array( 'Cache-Control' => 'max-age=120', 'Expires' => Guzzle::getHttpDate('+1 day') ))->getMaxAge()); // Uses the Expires date $this->assertGreaterThanOrEqual(82400, $this->getResponse(200, array( 'Expires' => Guzzle::getHttpDate('+1 day') ))->getMaxAge()); // Uses the Expires date $this->assertGreaterThanOrEqual(82400, $this->getResponse(200, array( 'Expires' => Guzzle::getHttpDate('+1 day') ))->getMaxAge()); } /** * @covers Guzzle\Http\Message\Response::canValidate */ public function testDeterminesIfItCanValidate() { $response = new Response(200); $this->assertFalse($response->canValidate()); $response->setHeader('ETag', '123'); $this->assertTrue($response->canValidate()); $response->removeHeader('ETag'); $this->assertFalse($response->canValidate()); $response->setHeader('Last-Modified', '123'); $this->assertTrue($response->canValidate()); } /** * @covers Guzzle\Http\Message\Response::getFreshness * @covers Guzzle\Http\Message\Response::isFresh */ public function testCalculatesFreshness() { $response = new Response(200); $this->assertNull($response->isFresh()); $this->assertNull($response->getFreshness()); $response->addCacheControlDirective('max-age', 120); $response->setHeader('Age', 100); $this->assertEquals(20, $response->getFreshness()); $this->assertTrue($response->isFresh()); $response->setHeader('Age', 150); $this->assertEquals(-30, $response->getFreshness()); $this->assertFalse($response->isFresh()); } /** * @covers Guzzle\Http\Message\Response::setProtocol * @covers Guzzle\Http\Message\Response::getProtocol * @covers Guzzle\Http\Message\Response::getProtocolVersion */ public function testHandlesProtocols() { $this->assertSame($this->response, $this->response->setProtocol('HTTP/1.0')); $this->assertEquals('HTTP', $this->response->getProtocol()); $this->assertEquals('1.0', $this->response->getProtocolVersion()); } /** * @covers Guzzle\Http\Message\Response::isContentType */ public function testComparesContentType() { $response = new Response(200, array( 'Content-Type' => 'text/html; charset=ISO-8859-4' )); $this->assertTrue($response->isContentType('text/html')); $this->assertTrue($response->isContentType('TExT/html')); $this->assertTrue($response->isContentType('charset=ISO-8859-4')); $this->assertFalse($response->isContentType('application/xml')); } /** * @covers Guzzle\Http\Message\Response::isMethodAllowed */ public function testResponseDeterminesIfMethodIsAllowedBaseOnAllowHeader() { $response = new Response(200, array( 'Allow' => 'OPTIONS, POST, deletE,GET' )); $this->assertTrue($response->isMethodAllowed('get')); $this->assertTrue($response->isMethodAllowed('GET')); $this->assertTrue($response->isMethodAllowed('options')); $this->assertTrue($response->isMethodAllowed('post')); $this->assertTrue($response->isMethodAllowed('Delete')); $this->assertFalse($response->isMethodAllowed('put')); $this->assertFalse($response->isMethodAllowed('PUT')); $response = new Response(200); $this->assertFalse($response->isMethodAllowed('get')); } }tests/Guzzle/Tests/Http/Plugin/BasicAuthPluginTest.php000064400000001167151742730640017056 0ustar00getEventDispatcher()->addSubscriber($plugin); $request = $client->get('/'); $this->assertEquals('michael', $request->getUsername()); $this->assertEquals('test', $request->getPassword()); } }tests/Guzzle/Tests/Http/Plugin/BatchQueuePluginTest.php000064400000014126151742730640017240 0ustar00assertArrayHasKey('flush', $events); $this->assertArrayHasKey('client.create_request', $events); $this->assertArrayHasKey('request.before_send', $events); } /** * @covers Guzzle\Http\Plugin\BatchQueuePlugin::count * @covers Guzzle\Http\Plugin\BatchQueuePlugin::onRequestCreate */ public function testAddsRequestToQueue() { $plugin = new BatchQueuePlugin(); $this->assertEquals(0, count($plugin)); $client = new Client('http://test.com/'); $request = $client->get('/'); $event = new Event(array( 'request' => $request )); $plugin->onRequestCreate($event); $this->assertEquals(1, count($plugin)); } /** * @covers Guzzle\Http\Plugin\BatchQueuePlugin::removeRequest * @covers Guzzle\Http\Plugin\BatchQueuePlugin::onRequestBeforeSend */ public function testRemovesRequestsWhenTheyAreSentOutOfContext() { $plugin = new BatchQueuePlugin(); $client = new Client('http://test.com/'); // Create an event to use for our notifications $event = new Event(array( 'request' => $client->get('/') )); // Add a request to the queue $plugin->onRequestCreate($event); $this->assertEquals(1, count($plugin)); // Fake that the request is being sent outside of the queue $plugin->onRequestBeforeSend($event); // Ensure that the request is no longer queued $this->assertEquals(0, count($plugin)); } /** * @covers Guzzle\Http\Plugin\BatchQueuePlugin::flush */ public function testFlushSendsRequestsInQueue() { $this->getServer()->flush(); $plugin = new BatchQueuePlugin(); $client = new Client($this->getServer()->getUrl()); // Create some test requests $requests = array( $client->get('/'), $client->get('/') ); // Add the requests to the batch queue foreach ($requests as $request) { $plugin->onRequestCreate(new Event(array( 'request' => $request ))); $responses[] = new Response(200); } // Queue the test responses on node.js $this->getServer()->enqueue($responses); // Explicitly call flush to send the queued requests $plugin->flush(); $this->assertEquals(count($requests), count($this->getServer()->getReceivedRequests())); $this->assertEquals(0, count($plugin)); } /** * @covers Guzzle\Http\Plugin\BatchQueuePlugin::__construct * @covers Guzzle\Http\Plugin\BatchQueuePlugin::onRequestCreate */ public function testImplicitlyFlushesRequests() { $this->getServer()->flush(); $plugin = new BatchQueuePlugin(2); $client = new Client($this->getServer()->getUrl()); $this->getServer()->enqueue(array( new Response(200), new Response(200), new Response(200) )); $plugin->onRequestCreate(new Event(array( 'request' => $client->get('/') ))); $plugin->onRequestCreate(new Event(array( 'request' => $client->get('/') ))); $this->assertEquals(0, count($plugin)); $this->assertEquals(2, count($this->getServer()->getReceivedRequests())); $plugin->onRequestCreate(new Event(array( 'request' => $client->get('/') ))); $this->assertEquals(1, count($plugin)); } /** * @covers Guzzle\Http\Plugin\BatchQueuePlugin::onRequestCreate * @covers Guzzle\Http\Plugin\BatchQueuePlugin::onRequestBeforeSend */ public function testWorksUsingEvents() { // Queue up some test responses $this->getServer()->flush(); $this->getServer()->enqueue(array( new Response(200), new Response(200), new Response(200) )); $plugin = new BatchQueuePlugin(2); $client = new Client($this->getServer()->getUrl()); $client->getEventDispatcher()->addSubscriber($plugin); $client->get('/'); $client->get('/'); // Ensure that the requests were sent implicitly $this->assertEquals(0, count($plugin)); $this->assertEquals(2, count($this->getServer()->getReceivedRequests())); // Add a single request and ensure that it is in queue and not sent $client->get('/'); $this->assertEquals(1, count($plugin)); $this->assertEquals(2, count($this->getServer()->getReceivedRequests())); // Explicitly flush the queued requests $client->dispatch('flush'); $this->assertEquals(0, count($plugin)); $this->assertEquals(3, count($this->getServer()->getReceivedRequests())); } /** * @covers Guzzle\Http\Plugin\BatchQueuePlugin::flush */ public function testWorksWithMockResponses() { $this->getServer()->flush(); $mock = new MockPlugin(array( new Response(200), new Response(201) )); $plugin = new BatchQueuePlugin(); $client = new Client($this->getServer()->getUrl()); $client->getEventDispatcher()->addSubscriber($plugin); $client->getEventDispatcher()->addSubscriber($mock); $request1 = $client->get('/'); $request2 = $client->get('/'); $plugin->flush(); $this->assertEquals(0, count($plugin)); $this->assertEquals(0, count($this->getServer()->getReceivedRequests())); $this->assertEquals(200, $request1->getResponse()->getStatusCode()); $this->assertEquals(201, $request2->getResponse()->getStatusCode()); } }tests/Guzzle/Tests/Http/Plugin/CachePluginTest.php000064400000041063151742730640016215 0ustar00cache = new ArrayCache(); $this->adapter = new DoctrineCacheAdapter($this->cache); } /** * @covers Guzzle\Http\Plugin\CachePlugin::__construct * @covers Guzzle\Http\Plugin\CachePlugin::getCacheAdapter */ public function testConstructorSetsValues() { $plugin = new CachePlugin($this->adapter, true, true, 1200); $this->assertEquals($this->adapter, $plugin->getCacheAdapter()); } /** * @covers Guzzle\Http\Plugin\CachePlugin::onRequestSent * @covers Guzzle\Http\Plugin\CachePlugin::onRequestBeforeSend * @covers Guzzle\Http\Plugin\CachePlugin::saveCache * @covers Guzzle\Http\Plugin\CachePlugin::getCacheKey * @covers Guzzle\Http\Plugin\CachePlugin::canResponseSatisfyRequest */ public function testSavesResponsesInCache() { // Send a 200 OK script to the testing server $this->getServer()->enqueue(array( "HTTP/1.1 200 OK\r\nContent-Length: 4\r\n\r\ndata", "HTTP/1.1 200 OK\r\nContent-Length: 4\r\n\r\ntest" )); // Create a new Cache plugin $plugin = new CachePlugin($this->adapter, true); $client = new Client($this->getServer()->getUrl()); $client->setCurlMulti(new \Guzzle\Http\Curl\CurlMulti()); $client->getEventDispatcher()->addSubscriber($plugin); $request = $client->get(); $request->send(); // Calculate the cache key like the cache plugin does $key = $plugin->getCacheKey($request); // Make sure that the cache plugin set the request in cache $this->assertNotNull($this->adapter->fetch($key)); // Clear out the requests stored on the server to make sure we didn't send a new request $this->getServer()->flush(); // Test that the request is set manually // The test server has no more script data, so if it actually sends a // request it will fail the test. $this->assertEquals($key, $plugin->getCacheKey($request)); $request->setState('new'); $request->send(); $this->assertEquals('data', $request->getResponse()->getBody(true)); // Make sure a request wasn't sent $this->assertEquals(0, count($this->getServer()->getReceivedRequests(false))); } /** * @covers Guzzle\Http\Plugin\CachePlugin::onRequestSent * @covers Guzzle\Http\Plugin\CachePlugin::onRequestBeforeSend * @covers Guzzle\Http\Plugin\CachePlugin::saveCache */ public function testSkipsNonReadableResponseBodies() { // Send a 200 OK script to the testing server $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 4\r\n\r\ndata"); // Create a new Cache plugin $plugin = new CachePlugin($this->adapter, true); $client = new Client($this->getServer()->getUrl()); $client->getEventDispatcher()->addSubscriber($plugin); // Create a new request using the Cache plugin $request = $client->get(); // Create a temp file that is not readable $tempFile = tempnam('/tmp', 'temp_stream_data'); // Set the non-readable stream as the response body so that it can't be cached $request->setResponseBody(EntityBody::factory( fopen($tempFile, 'w') )); $request->send(); // Calculate the cache key like the cache plugin does $key = $plugin->getCacheKey($request); // Make sure that the cache plugin set the request in cache $this->assertFalse($this->adapter->fetch($key)); } public function cacheKeyDataProvider() { $r = array( array('', 'gz_http_www.test.com/path?q=abc_host=www.test.com&date=123', 'http://www.test.com/path?q=abc', "Host: www.test.com\r\nDate: 123"), array('query = q', 'gz_http_www.test.com/path_host=www.test.com&date=123', 'http://www.test.com/path?q=abc', "Host: www.test.com\r\nDate: 123"), array('query=q; header=Date;', 'gz_http_www.test.com/path_host=www.test.com', 'http://www.test.com/path?q=abc', "Host: www.test.com\r\nDate: 123"), array('query=a, q; header=Date, Host;', 'gz_http_www.test.com/path_', 'http://www.test.com/path?q=abc&a=123', "Host: www.test.com\r\nDate: 123"), ); return $r; } /** * @covers Guzzle\Http\Plugin\CachePlugin::getCacheKey * @dataProvider cacheKeyDataProvider */ public function testCreatesCacheKeysUsingFilters($filter, $key, $url, $headers = null) { // Create a new Cache plugin $plugin = new CachePlugin($this->adapter, true); // Generate the header array $h = null; if ($headers) { $h = array(); foreach (explode("\r\n", $headers) as $header) { list($k, $v) = explode(': ', $header); $h[$k] = $v; } } // Create the request $request = RequestFactory::create('GET', $url, $h); $request->getParams()->set('cache.key_filter', $filter); $request->removeHeader('User-Agent'); $this->assertEquals($key, $plugin->getCacheKey($request, true)); // Make sure that the encoded request is returned when $raw is false $this->assertNotEquals($key, $plugin->getCacheKey($request)); } /** * @covers Guzzle\Http\Plugin\CachePlugin::getCacheKey */ public function testCreatesEncodedKeys() { $plugin = new CachePlugin($this->adapter, true); $request = RequestFactory::fromMessage( "GET / HTTP/1.1\r\nHost: www.test.com\r\nCache-Control: no-cache, no-store, max-age=120" ); $key = $plugin->getCacheKey($request); $this->assertEquals(1, preg_match('/^gz_[a-z0-9]{32}$/', $key)); // Make sure that the same value is returned in a subsequent call $this->assertEquals($key, $plugin->getCacheKey($request)); } /** * @covers Guzzle\Http\Plugin\CachePlugin::onRequestSent * @covers Guzzle\Http\Plugin\CachePlugin::onRequestBeforeSend * @covers Guzzle\Http\Plugin\CachePlugin::saveCache */ public function testRequestsCanOverrideTtlUsingCacheParam() { $plugin = new CachePlugin($this->adapter, true); $client = new Client($this->getServer()->getUrl()); $client->getEventDispatcher()->addSubscriber($plugin); $request = $client->get('http://www.test.com/'); $request->getParams()->set('cache.override_ttl', 1000); $request->setResponse(Response::factory("HTTP/1.1 200 OK\r\nCache-Control: max-age=100\r\nContent-Length: 4\r\n\r\nData"), true); $request->send(); $request2 = $client->get('http://www.test.com/'); $response = $request2->send(); $this->assertEquals(1000, $response->getHeader('X-Guzzle-Ttl')); } /** * @covers Guzzle\Http\Plugin\CachePlugin::canResponseSatisfyRequest * @covers Guzzle\Http\Plugin\CachePlugin::onRequestSent * @covers Guzzle\Http\Plugin\CachePlugin::onRequestBeforeSend * @covers Guzzle\Http\Plugin\CachePlugin::saveCache */ public function testRequestsCanAcceptStaleResponses() { $server = $this->getServer(); $client = new Client($this->getServer()->getUrl()); $plugin = new CachePlugin($this->adapter, true); $client->getEventDispatcher()->addSubscriber($plugin); $request = $client->get('test'); // Cache this response for 1000 seconds if it is cacheable $request->getParams()->set('cache.override_ttl', 1000); $request->setResponse(Response::factory("HTTP/1.1 200 OK\r\nExpires: " . Guzzle::getHttpDate('-1 second') . "\r\nContent-Length: 4\r\n\r\nData"), true); $request->send(); sleep(1); // Accept responses that are up to 100 seconds expired $request2 = $client->get('test'); $request2->addCacheControlDirective('max-stale', 100); $response = $request2->send(); $this->assertEquals(1000, $response->getHeader('X-Guzzle-Ttl')); // Accepts any stale response $request3 = $client->get('test'); $request3->addCacheControlDirective('max-stale'); $response = $request3->send(); $this->assertEquals(1000, $response->getHeader('X-Guzzle-Ttl')); // Will not accept the stale cached entry $server->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 4\r\n\r\nData"); $request4 = $client->get('test'); $request4->addCacheControlDirective('max-stale', 0); $response = $request4->send(); $this->assertEquals("HTTP/1.1 200 OK\r\nContent-Length: 4\r\n\r\nData", $this->removeKeepAlive((string) $response)); } /** * @covers Guzzle\Http\Plugin\CachePlugin::canResponseSatisfyRequest */ public function testChecksIfResponseCanSatisfyRequest() { $plugin = new CachePlugin($this->adapter, true); // Send some responses to the test server for cache validation $server = $this->getServer(); // No restrictions $request = RequestFactory::create('GET', $server->getUrl()); $response = new Response(200, array('Date' => Guzzle::getHttpDate('now'))); $this->assertTrue($plugin->canResponseSatisfyRequest($request, $response)); // Request max-age is less than response age $request = RequestFactory::create('GET', $server->getUrl()); $request->addCacheControlDirective('max-age', 100); $response = new Response(200, array('Age' => 10)); $this->assertTrue($plugin->canResponseSatisfyRequest($request, $response)); // Request must have something fresher than 200 seconds $response->setHeader('Date', Guzzle::getHttpDate('-200 days')); $response->removeHeader('Age'); $request->setHeader('Cache-Control', 'max-age=200'); $this->assertFalse($plugin->canResponseSatisfyRequest($request, $response)); // Response says it's too old $request->removeHeader('Cache-Control'); $response->setHeader('Cache-Control', 'max-age=86400'); $this->assertFalse($plugin->canResponseSatisfyRequest($request, $response)); // Response is OK $response->setHeader('Date', Guzzle::getHttpDate('-1 hour')); $this->assertTrue($plugin->canResponseSatisfyRequest($request, $response)); } /** * Data provider to test cache revalidation * * @return array */ public function cacheRevalidationDataProvider() { return array( // Forces revalidation that passes array( true, "Pragma: no-cache\r\n\r\n", "HTTP/1.1 200 OK\r\nDate: " . Guzzle::getHttpDate('-100 hours') . "\r\nContent-Length: 4\r\n\r\nData", "HTTP/1.1 304 NOT MODIFIED\r\nCache-Control: max-age=2000000\r\n\r\n", ), // Forces revalidation that overwrites what is in cache array( false, "\r\n\r\n", "HTTP/1.1 200 OK\r\nCache-Control: must-revalidate, no-cache\r\nDate: " . Guzzle::getHttpDate('-10 hours') . "\r\nContent-Length: 4\r\n\r\nData", "HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\nDatas", "HTTP/1.1 200 OK\r\nContent-Length: 5\r\nDate: " . Guzzle::getHttpDate('now') . "\r\n\r\nDatas" ), // Must get a fresh copy because the request is declining revalidation array( false, "\r\n\r\n", "HTTP/1.1 200 OK\r\nCache-Control: no-cache\r\nDate: " . Guzzle::getHttpDate('-3 hours') . "\r\nContent-Length: 4\r\n\r\nData", null, null, 'never' ), // Skips revalidation because the request is accepting the cached copy array( true, "\r\n\r\n", "HTTP/1.1 200 OK\r\nCache-Control: no-cache\r\nDate: " . Guzzle::getHttpDate('-3 hours') . "\r\nContent-Length: 4\r\n\r\nData", null, null, 'skip' ), // Throws an exception during revalidation array( false, "\r\n\r\n", "HTTP/1.1 200 OK\r\nCache-Control: no-cache\r\nDate: " . Guzzle::getHttpDate('-3 hours') . "\r\n\r\nData", "HTTP/1.1 500 INTERNAL SERVER ERROR\r\nContent-Length: 0\r\n\r\n" ), // ETag mismatch array( false, "\r\n\r\n", "HTTP/1.1 200 OK\r\nCache-Control: no-cache\r\nETag: \"123\"\r\nDate: " . Guzzle::getHttpDate('-10 hours') . "\r\n\r\nData", "HTTP/1.1 304 NOT MODIFIED\r\nETag: \"123456\"\r\n\r\n", ), ); } /** * @covers Guzzle\Http\Plugin\CachePlugin::canResponseSatisfyRequest * @covers Guzzle\Http\Plugin\CachePlugin::revalidate * @dataProvider cacheRevalidationDataProvider */ public function testRevalidatesResponsesAgainstOriginServer($can, $request, $response, $validate = null, $result = null, $param = null) { // Send some responses to the test server for cache validation $server = $this->getServer(); $server->flush(); if ($validate) { $server->enqueue($validate); } $request = RequestFactory::fromMessage("GET / HTTP/1.1\r\nHost: 127.0.0.1:" . $server->getPort() . "\r\n" . $request); $response = Response::factory($response); $request->setClient(new Client()); if ($param) { $request->getParams()->set('cache.revalidate', $param); } $plugin = new CachePlugin($this->adapter, true); $this->assertEquals($can, $plugin->canResponseSatisfyRequest($request, $response), '-> ' . $request . "\n" . $response); if ($result) { // Get rid of dates $this->assertEquals( preg_replace('/(Date:\s)(.*)(\r\n)/', '$1$3', (string) $result), preg_replace('/(Date:\s)(.*)(\r\n)/', '$1$3', (string) $request->getResponse()) ); } if ($validate) { $this->assertEquals(1, count($server->getReceivedRequests())); } } /** * @covers Guzzle\Http\Plugin\CachePlugin */ public function testCachesResponsesAndHijacksRequestsWhenApplicable() { $server = $this->getServer(); $server->enqueue("HTTP/1.1 200 OK\r\nCache-Control: max-age=1000\r\nContent-Length: 4\r\n\r\nData"); $plugin = new CachePlugin($this->adapter, true); $client = new Client($server->getUrl()); $client->getEventDispatcher()->addSubscriber($plugin); $request = $client->get(); $request->getCurlOptions()->set(\CURLOPT_TIMEOUT, 2); $request2 = $client->get(); $request2->getCurlOptions()->set(\CURLOPT_TIMEOUT, 2); $request->send(); $request2->send(); $this->assertEquals(true, $request2->getResponse()->hasHeader('X-Guzzle-Cache')); } /** * @covers Guzzle\Http\Plugin\CachePlugin::revalidate * @expectedException Guzzle\Http\Message\BadResponseException */ public function testRemovesMissingEntitesFromCacheWhenRevalidating() { $server = $this->getServer(); $server->enqueue(array( "HTTP/1.1 200 OK\r\nCache-Control: max-age=1000, no-cache\r\nContent-Length: 4\r\n\r\nData", "HTTP/1.1 404 NOT FOUND\r\nContent-Length: 0\r\n\r\n" )); $plugin = new CachePlugin($this->adapter, true); $client = new Client($server->getUrl()); $client->getEventDispatcher()->addSubscriber($plugin); $request1 = $client->get('/'); $request1->send(); $this->assertTrue($this->cache->contains($plugin->getCacheKey($request1))); $client->get('/')->send(); } }tests/Guzzle/Tests/Http/Plugin/CookiePluginTest.php000064400000055154151742730640016431 0ustar00storage = new ArrayCookieJar(); $this->plugin = new CookiePlugin($this->storage); } /** * Provides the parsed information from a cookie * * @return array */ public function cookieParserDataProvider() { return array( array( 'ASIHTTPRequestTestCookie=This+is+the+value; expires=Sat, 26-Jul-2008 17:00:42 GMT; path=/tests; domain=allseeing-i.com; PHPSESSID=6c951590e7a9359bcedde25cda73e43c; path=/";', array( 'domain' => 'allseeing-i.com', 'path' => '/', 'data' => array( 'PHPSESSID' => '6c951590e7a9359bcedde25cda73e43c' ), 'max_age' => NULL, 'expires' => 'Sat, 26-Jul-2008 17:00:42 GMT', 'version' => NULL, 'secure' => NULL, 'discard' => NULL, 'port' => NULL, 'cookies' => array( 'ASIHTTPRequestTestCookie=This is the value' ), 'comment' => null, 'comment_url' => null, 'http_only' => false ) ), array('', false), array('foo', false), // Test setting a blank value for a cookie array(array( 'foo=', 'foo =', 'foo =;', 'foo= ;', 'foo =', 'foo= '), array( 'cookies' => array( 'foo' ), 'data' => array(), 'discard' => null, 'domain' => null, 'expires' => null, 'max_age' => null, 'path' => '/', 'port' => null, 'secure' => null, 'version' => null, 'comment' => null, 'comment_url' => null, 'http_only' => false ) ), // Test setting a value and removing quotes array(array( 'foo=1', 'foo =1', 'foo =1;', 'foo=1 ;', 'foo =1', 'foo= 1', 'foo = 1 ;', 'foo="1"', 'foo="1";', 'foo= "1";'), array( 'cookies' => array( 'foo=1' ), 'data' => array(), 'discard' => null, 'domain' => null, 'expires' => null, 'max_age' => null, 'path' => '/', 'port' => null, 'secure' => null, 'version' => null, 'comment' => null, 'comment_url' => null, 'http_only' => false ) ), // Test setting multiple values array(array( 'foo=1; bar=2', 'foo =1; bar = "2"', 'foo=1; bar=2'), array( 'cookies' => array( 'foo=1', 'bar=2' ), 'data' => array(), 'discard' => null, 'domain' => null, 'expires' => null, 'max_age' => null, 'path' => '/', 'port' => null, 'secure' => null, 'version' => null, 'comment' => null, 'comment_url' => null, 'http_only' => false ) ), // Tests getting the domain and path from a reference request array(array( 'foo=1; port="80,8081"; httponly', 'foo=1; port="80,8081"; domain=www.test.com; HttpOnly;', 'foo=1; ; domain=www.test.com; path=/path/; port="80,8081"; HttpOnly;'), array( 'cookies' => array( 'foo=1' ), 'data' => array(), 'discard' => null, 'domain' => 'www.test.com', 'expires' => null, 'max_age' => null, 'path' => '/path/', 'port' => array('80', '8081'), 'secure' => null, 'version' => null, 'comment' => null, 'comment_url' => null, 'http_only' => true ), 'http://www.test.com/path/' ), // Some of the following tests are based on http://framework.zend.com/svn/framework/standard/trunk/tests/Zend/Http/CookieTest.php array( 'justacookie=foo; domain=example.com', array( 'cookies' => array( 'justacookie=foo' ), 'domain' => 'example.com', 'path' => '', 'data' => array(), 'discard' => null, 'expires' => null, 'max_age' => null, 'path' => '/', 'port' => null, 'secure' => null, 'version' => null, 'comment' => null, 'comment_url' => null, 'http_only' => false ) ), array( 'expires=tomorrow; secure; path=/Space Out/; expires=Tue, 21-Nov-2006 08:33:44 GMT; domain=.example.com', array( 'cookies' => array( 'expires=tomorrow' ), 'domain' => '.example.com', 'path' => '/Space Out/', 'expires' => 'Tue, 21-Nov-2006 08:33:44 GMT', 'data' => array(), 'discard' => null, 'port' => null, 'secure' => true, 'version' => null, 'max_age' => null, 'comment' => null, 'comment_url' => null, 'http_only' => false ) ), array( 'domain=unittests; expires=Tue, 21-Nov-2006 08:33:44 GMT; domain=example.com; path=/some value/', array( 'cookies' => array( 'domain=unittests' ), 'domain' => 'example.com', 'path' => '/some value/', 'expires' => 'Tue, 21-Nov-2006 08:33:44 GMT', 'secure' => false, 'data' => array(), 'discard' => null, 'max_age' => null, 'port' => null, 'version' => null, 'comment' => null, 'comment_url' => null, 'http_only' => false ) ), array( 'path=indexAction; path=/; domain=.foo.com; expires=Tue, 21-Nov-2006 08:33:44 GMT', array( 'cookies' => array( 'path=indexAction' ), 'domain' => '.foo.com', 'path' => '/', 'expires' => 'Tue, 21-Nov-2006 08:33:44 GMT', 'secure' => false, 'data' => array(), 'discard' => null, 'max_age' => null, 'port' => null, 'version' => null, 'comment' => null, 'comment_url' => null, 'http_only' => false ) ), array( 'secure=sha1; secure; SECURE; domain=some.really.deep.domain.com; version=1; Max-Age=86400', array( 'cookies' => array( 'secure=sha1' ), 'domain' => 'some.really.deep.domain.com', 'path' => '/', 'secure' => true, 'data' => array(), 'discard' => null, 'expires' => time() + 86400, 'max_age' => 86400, 'port' => null, 'version' => 1, 'comment' => null, 'comment_url' => null, 'http_only' => false ) ), array( 'PHPSESSID=123456789+abcd%2Cef; secure; discard; domain=.localdomain; path=/foo/baz; expires=Tue, 21-Nov-2006 08:33:44 GMT;', array( 'cookies' => array( 'PHPSESSID=123456789 abcd,ef' ), 'domain' => '.localdomain', 'path' => '/foo/baz', 'expires' => 'Tue, 21-Nov-2006 08:33:44 GMT', 'secure' => true, 'data' => array(), 'discard' => true, 'max_age' => null, 'port' => null, 'version' => null, 'comment' => null, 'comment_url' => null, 'http_only' => false ) ), ); } /** * @dataProvider cookieParserDataProvider * @covers Guzzle\Http\Plugin\CookiePlugin */ public function testParseCookie($cookie, $parsed, $url = null) { $request = null; if ($url) { $request = RequestFactory::create('GET', $url); } foreach ((array) $cookie as $c) { $p = CookiePlugin::parseCookie($c, $request); // Remove expires values from the assertion if they are relatively equal if ($p['expires'] != $parsed['expires']) { if (abs($p['expires'] - $parsed['expires']) < 20) { unset($p['expires']); unset($parsed['expires']); } } if (is_array($parsed)) { foreach ($parsed as $key => $value) { $this->assertEquals($parsed[$key], $p[$key], 'Comparing ' . $key); } foreach ($p as $key => $value) { $this->assertEquals($p[$key], $parsed[$key], 'Comparing ' . $key); } } else { $this->assertEquals($parsed, $p); } } } /** * @covers Guzzle\Http\Plugin\CookiePlugin */ public function testClearsCookiesWhenShuttingDown() { $this->storage->save(array( 'domain' => '.example.com', 'cookie' => array('a', '123') )); $this->assertEquals(1, count($this->storage->getCookies())); unset($this->plugin); $this->assertEquals(0, count($this->storage->getCookies())); } /** * @covers Guzzle\Http\Plugin\CookiePlugin */ public function testClearsTemporaryCookies() { $this->storage->save(array( 'domain' => '.example.com', 'cookie' => array('a', '123') )); $this->assertEquals(1, count($this->storage->getCookies())); $this->plugin->clearTemporaryCookies(); $this->assertEquals(0, count($this->storage->getCookies())); } /** * @covers Guzzle\Http\Plugin\CookiePlugin */ public function testClearsCookies() { $this->assertSame($this->storage, $this->storage->save(array( 'domain' => '.example.com', 'cookie' => array('a', '123') ))); $this->assertSame($this->storage, $this->storage->save(array( 'domain' => 'example.com', 'cookie' => array('b', '123') ))); $this->assertEquals(2, count($this->storage->getCookies())); $this->assertEquals(1, $this->plugin->clearCookies('http://example.com')); $this->assertEquals(1, count($this->storage->getCookies())); } /** * @covers Guzzle\Http\Plugin\CookiePlugin */ public function testExtractsAndStoresCookies() { $cookie = array( array( 'domain' => '.example.com', 'path' => '/', 'max_age' => '86400', 'expires' => time() + 86400, 'version' => '1', 'secure' => true, 'port' => array('80', '8081'), 'discard' => true, 'comment' => NULL, 'comment_url' => NULL, 'http_only' => false, 'data' => array(), 'cookie' => array('a', 'b') ), array ( 'domain' => '.example.com', 'path' => '/', 'max_age' => '86400', 'expires' => time() + 86400, 'version' => '1', 'secure' => true, 'port' => array('80','8081'), 'discard' => true, 'comment' => NULL, 'comment_url' => NULL, 'http_only' => false, 'data' => array(), 'cookie' => array ('c', 'd') ), ); $response = Response::factory("HTTP/1.1 200 OK\r\nSet-Cookie: a=b; c=d; port=\"80,8081\"; version=1; Max-Age=86400; domain=.example.com; discard; secure;\r\n\r\n"); $result = $this->plugin->extractCookies($response); $this->assertTrue(abs($result[0]['expires'] - $cookie[0]['expires']) < 10, 'Cookie #1 expires dates are too different: ' . $result[0]['expires'] . ' vs ' . $cookie[0]['expires']); $this->assertTrue(abs($result[1]['expires'] - $cookie[1]['expires']) < 10, 'Cookie #2 expires dates are too different: ' . $result[1]['expires'] . ' vs ' . $cookie[1]['expires']); unset($cookie[0]['expires']); unset($cookie[1]['expires']); unset($result[0]['expires']); unset($result[1]['expires']); $this->assertEquals($cookie, $result); $this->assertEquals(2, count($this->storage->getCookies())); $result = $this->storage->getCookies(); unset($result[0]['expires']); unset($result[1]['expires']); $this->assertEquals($cookie, $result); // Clear out the currently held cookies $this->assertEquals(2, $this->storage->clear()); $this->assertEquals(0, count($this->storage->getCookies())); // Create a new request, attach the cookie plugin, set a mock response $request = new Request('GET', 'http://www.example.com/'); $request->setClient(new Client()); $request->getEventDispatcher()->addSubscriber($this->plugin); $request->setResponse($response, true); $request->send(); // Assert that the plugin caught the cookies in the response $this->assertEquals(2, count($this->storage->getCookies())); } /** * @covers Guzzle\Http\Plugin\CookiePlugin */ public function testAddsCookiesToRequests() { ArrayCookieJarTest::addCookies($this->storage); $this->storage->save(array( 'domain' => '.y.example.com', 'path' => '/acme/', 'cookie' => array('secure', 'sec'), 'expires' => Guzzle::getHttpDate('+1 day'), 'secure' => true )); // Add a cookie that is only set on a specific port, so it wont be // added to the following requests $this->storage->save(array( 'domain' => '.y.example.com', 'path' => '/acme/', 'cookie' => array('test', 'port'), 'expires' => Guzzle::getHttpDate('+1 day'), 'secure' => false, 'port' => array(8192) )); $request1 = new Request('GET', 'https://a.y.example.com/acme/'); $request1->setClient(new Client()); $request2 = new Request('GET', 'https://a.y.example.com/acme/'); $request2->setClient(new Client()); $request3 = new Request('GET', 'http://a.y.example.com/acme/'); $request3->setClient(new Client()); $request4 = new Request('GET', 'http://a.y.example.com/acme/'); $request4->setClient(new Client()); $request1->getEventDispatcher()->addSubscriber($this->plugin); $request2->getEventDispatcher()->addSubscriber($this->plugin); $request3->getEventDispatcher()->addSubscriber($this->plugin); $request4->getEventDispatcher()->addSubscriber($this->plugin); // Set a secure cookie $response1 = Response::factory("HTTP/1.1 200 OK\r\nSet-Cookie: a=b; c=d; Max-Age=86400; domain=.example.com; secure;\r\n\r\n"); // Set a regular cookie $response2 = Response::factory("HTTP/1.1 200 OK\r\nSet-Cookie: e=f h; discard; domain=.example.com;\r\n\r\n"); $response3 = Response::factory("HTTP/1.1 200 OK\r\n\r\n"); $request1->setResponse($response1, true); $request2->setResponse($response2, true); $request3->setResponse($response3, true); $request1->send(); $request2->send(); $request3->send(); $this->assertEquals('muppet=cookie_monster;secure=sec', (string) $request1->getCookie()); $this->assertEquals('muppet=cookie_monster;secure=sec;a=b;c=d', (string) $request2->getCookie()); $this->assertEquals('muppet=cookie_monster;e=f h', (string) $request3->getCookie()); // Clear the e=f h temporary cookie $this->plugin->clearTemporaryCookies(); $request4->setResponse($response3, true); $request4->send(); $this->assertEquals('muppet=cookie_monster', (string) $request4->getCookie()); } /** * @covers Guzzle\Http\Plugin\CookiePlugin */ public function testExtractsMultipleCookies() { $this->plugin->clearCookies(); $response = Response::factory( "HTTP/1.1 200 OK\r\n" . "Set-Cookie: IU=deleted; expires=Wed, 03-Mar-2010 02:17:39 GMT; path=/; domain=127.0.0.1\r\n" . "Set-Cookie: PH=deleted; expires=Wed, 03-Mar-2010 02:17:39 GMT; path=/; domain=127.0.0.1\r\n" . "Set-Cookie: fpc=d=.Hm.yh4.1XmJWjJfs4orLQzKzPImxklQoxXSHOZATHUSEFciRueW_7704iYUtsXNEXq0M92Px2glMdWypmJ7HIQl6XIUvrZimWjQ3vIdeuRbI.FNQMAfcxu_XN1zSx7l.AcPdKL6guHc2V7hIQFhnjRW0rxm2oHY1P4bGQxFNz7f.tHm12ZD3DbdMDiDy7TBXsuP4DM-&v=2; expires=Fri, 02-Mar-2019 02:17:40 GMT; path=/; domain=127.0.0.1\r\n" . "Set-Cookie: FPCK3=AgBNbvoQAGpGEABZLRAAbFsQAF1tEABkDhAAeO0=; expires=Sat, 02-Apr-2019 02:17:40 GMT; path=/; domain=127.0.0.1\r\n" . "Set-Cookie: CH=deleted; expires=Wed, 03-Mar-2010 02:17:39 GMT; path=/; domain=127.0.0.1\r\n" . "Set-Cookie: CH=AgBNbvoQAAEcEAApuhAAMJcQADQvEAAvGxAALe0QAD6uEAATwhAAC1AQAC8t; expires=Sat, 02-Apr-2019 02:17:40 GMT; path=/; domain=127.0.0.1\r\n" . "Set-Cookie: fpt=d=_e2d6jLXesxx4AoiC0W7W3YktnpITDTHoJ6vNxF7TU6JEep6Y5BFk7Z9NgHmhiXoB7jGV4uR_GBQtSDOLjflKBUVZ6UgnGmDztoj4GREK30jm1qDgReyhPv7iWaN8e8ZLpUKXtPioOzQekGha1xR8ZqGR25GT7aYQpcxaaY.2ATjTpbm7HmX8tlBIte6mYMwFpIh_krxtofGPH3R337E_aNF3illhunC5SK6I0IfZvHzBXCoxu9fjH6e0IHzyOBY656YMUIElQiDkSd8werkBIRE6LJi6YU8AWgitEpMLisOIQSkqyGiahcPFt_fsD8DmIX2YAdSeVE0KycIqd0Z9aM7mdJ3xNQ4dmOOfcZ83dDrZ.4hvuKN2jB2FQDKuxEjTVO4DmiCCSyYgcs2wh0Lc3RODVKzqAZNMTYltWMELw9JdUyDFD3EGT3ZCnH8NQ6f_AAWffyj92ZMLYfWJnXHSG.DTKlVHj.IsihVT73QzrfoMFIs&v=1; path=/; domain=127.0.0.1\r\n" . "Set-Cookie: fpps=deleted; expires=Wed, 03-Mar-2010 02:17:39 GMT; path=/; domain=127.0.0.1\r\n" . "Set-Cookie: fpc_s=d=ng6sEJk.1XnLUt1pfJ2kiUon07QEppAUuwW3nk0tYwcHMQ1CijnSGVZHfgvWSXQxE5eW_1hjvDAA4Nu0CSSn2xk9_.DOkKI_fZLLLUrm0hJ41VMbSUTrklw.u5IlTM5JCeK_PDjSjZNkvHMbNYziu8vwd8fMnbecf9bSo3eDDv1boowyLFk_9mnGYBeSI4U86mnm.mnfOHMARxzL6BVMTAblIAml65cR486SHzPVO6KNYvkqh8zP3m0hVIkRaPhzvDjQkDG28HCbMjq745QR2FcCmI4TNJbk7EtJmsBrlL8wvVyX5DiBmP9W990-&v=2; path=/; domain=127.0.0.1\r\n" . "Content-Length: 0\r\n\r\n" ); $this->getServer()->enqueue(array( (string) $response, "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\rn" )); $request = RequestFactory::create('GET', $this->getServer()->getUrl()); $request->getEventDispatcher()->addSubscriber($this->plugin); $request->setClient(new Client()); $request->send(); $this->assertNull($request->getHeader('Cookie')); $request->setState('new'); $request->send(); $this->assertNotNull($request->getHeader('Cookie')); // Doesn't send expired cookies $this->assertEmpty($request->getCookie('IU')); $this->assertEmpty($request->getCookie('PH')); $this->assertNotEmpty($request->getCookie('fpc')); $this->assertNotEmpty($request->getCookie('FPCK3')); $this->assertNotEmpty($request->getCookie('CH')); $this->assertNotEmpty($request->getCookie('fpt')); $this->assertNotEmpty($request->getCookie('fpc_s')); $this->assertNotEmpty($request->getCookie('CH')); $this->assertNotEmpty($request->getCookie('CH')); $this->assertEquals(9, count($this->plugin->extractCookies($response))); } /** * @covers Guzzle\Http\Plugin\CookiePlugin::onRequestSent * @covers Guzzle\Http\Plugin\CookiePlugin::onRequestReceiveStatusLine * @covers Guzzle\Http\Plugin\CookiePlugin::onRequestBeforeSend */ public function testCookiesAreExtractedFromRedirectResponses() { $this->getServer()->enqueue(array( "HTTP/1.1 302 Moved Temporarily\r\n" . "Set-Cookie: test=583551; expires=Wednesday, 23-Mar-2050 19:49:45 GMT; path=/\r\n" . "Location: /redirect\r\n\r\n", "HTTP/1.1 200 OK\r\n" . "Content-Length: 0\r\n\r\n", "HTTP/1.1 200 OK\r\n" . "Content-Length: 0\r\n\r\n" )); $client = new Client($this->getServer()->getUrl()); $client->getEventDispatcher()->addSubscriber($this->plugin); $request = $client->get(); $request->send(); $request = $client->get(); $request->send(); $this->assertEquals('test=583551', $request->getHeader('Cookie')); } }tests/Guzzle/Tests/Http/Plugin/ExponentialBackoffTest.php000064400000012564151742730640017601 0ustar00assertEquals(2, $plugin->getMaxRetries()); $this->assertEquals(array(500, 503, 502), $plugin->getFailureCodes()); // You can specify any codes you want... Probably not a good idea though $plugin->setFailureCodes(array(200, 204)); $this->assertEquals(array(200, 204), $plugin->getFailureCodes()); } /** * @covers Guzzle\Http\Plugin\ExponentialBackoffPlugin::calculateWait */ public function testCalculateWait() { $plugin = new ExponentialBackoffPlugin(2); $this->assertEquals(1, $plugin->calculateWait(0)); $this->assertEquals(2, $plugin->calculateWait(1)); $this->assertEquals(4, $plugin->calculateWait(2)); $this->assertEquals(8, $plugin->calculateWait(3)); $this->assertEquals(16, $plugin->calculateWait(4)); } /** * @covers Guzzle\Http\Plugin\ExponentialBackoffPlugin */ public function testRetriesRequests() { // Create a script to return several 500 and 503 response codes $this->getServer()->flush(); $this->getServer()->enqueue(array( "HTTP/1.1 500 Internal Server Error\r\nContent-Length: 0\r\n\r\n", "HTTP/1.1 500 Internal Server Error\r\nContent-Length: 0\r\n\r\n", "HTTP/1.1 200 OK\r\nContent-Length: 4\r\n\r\ndata" )); // Clear out other requests that have been received by the server $this->getServer()->flush(); $plugin = new ExponentialBackoffPlugin(2, null, array($this, 'delayClosure')); $client = new Client($this->getServer()->getUrl()); $client->getEventDispatcher()->addSubscriber($plugin); $request = $client->get(); $request->send(); // Make sure it eventually completed successfully $this->assertEquals(200, $request->getResponse()->getStatusCode()); $this->assertEquals('OK', $request->getResponse()->getReasonPhrase()); $this->assertEquals('data', $request->getResponse()->getBody(true)); // Check that three requests were made to retry this request $this->assertEquals(3, count($this->getServer()->getReceivedRequests(false))); } /** * @covers Guzzle\Http\Plugin\ExponentialBackoffPlugin::onRequestSent * @covers Guzzle\Http\Plugin\ExponentialBackoffPlugin::onRequestPoll * @covers Guzzle\Http\Message\Request * @expectedException Guzzle\Http\Message\BadResponseException */ public function testAllowsFailureOnMaxRetries() { $this->getServer()->flush(); $this->getServer()->enqueue(array( "HTTP/1.1 500 Internal Server Error\r\nContent-Length: 0\r\n\r\n", "HTTP/1.1 500 Internal Server Error\r\nContent-Length: 0\r\n\r\n", "HTTP/1.1 500 Internal Server Error\r\nContent-Length: 0\r\n\r\n" )); $plugin = new ExponentialBackoffPlugin(2, null, array($this, 'delayClosure')); $client = new Client($this->getServer()->getUrl()); $client->getEventDispatcher()->addSubscriber($plugin); $request = $client->get(); // This will fail because the plugin isn't retrying the request because // the max number of retries is exceeded (1 > 0) $request->send(); } /** * @covers Guzzle\Http\Plugin\ExponentialBackoffPlugin::onRequestSent * @covers Guzzle\Http\Plugin\ExponentialBackoffPlugin::onRequestPoll * @covers Guzzle\Http\Curl\CurlMulti */ public function testRetriesPooledRequestsUsingDelayAndPollingEvent() { $this->getServer()->flush(); $this->getServer()->enqueue(array( "HTTP/1.1 500 Internal Server Error\r\nContent-Length: 0\r\n\r\n", "HTTP/1.1 200 OK\r\nContent-Length: 4\r\n\r\ndata" )); // Need to sleep for one second to make sure that the polling works // correctly in the observer $plugin = new ExponentialBackoffPlugin(1, null, function($r) { return 1; }); $client = new Client($this->getServer()->getUrl()); $client->getEventDispatcher()->addSubscriber($plugin); $request = $client->get(); $request->send(); // Make sure it eventually completed successfully $this->assertEquals('data', $request->getResponse()->getBody(true)); // Check that two requests were made to retry this request $this->assertEquals(2, count($this->getServer()->getReceivedRequests(false))); } }tests/Guzzle/Tests/Http/Plugin/HistoryPluginTest.php000064400000007772151742730640016664 0ustar00get(); $requests[$i]->setResponse(new Response(200), true); $requests[$i]->send(); $h->add($requests[$i]); } return $requests; } /** * @covers Guzzle\Http\Plugin\HistoryPlugin::getSubscribedEvents */ public function testDescribesSubscribedEvents() { $this->assertInternalType('array', HistoryPlugin::getSubscribedEvents()); } /** * @covers Guzzle\Http\Plugin\HistoryPlugin::getLimit * @covers Guzzle\Http\Plugin\HistoryPlugin::setLimit */ public function testMaintainsLimitValue() { $h = new HistoryPlugin(); $this->assertSame($h, $h->setLimit(10)); $this->assertEquals(10, $h->getLimit()); } /** * @covers Guzzle\Http\Plugin\HistoryPlugin::add * @covers Guzzle\Http\Plugin\HistoryPlugin::count * @covers Guzzle\Http\Plugin\HistoryPlugin::getIterator */ public function testAddsRequests() { $h = new HistoryPlugin(); $requests = $this->addRequests($h, 1); $this->assertEquals(1, count($h)); $i = $h->getIterator(); $this->assertEquals(1, count($i)); $this->assertEquals($requests[0], $i[0]); } /** * @covers Guzzle\Http\Plugin\HistoryPlugin::add */ public function testIgnoresUnsentRequests() { $h = new HistoryPlugin(); $request = RequestFactory::create('GET', 'http://localhost/'); $h->add($request); $this->assertEquals(0, count($h)); } /** * @covers Guzzle\Http\Plugin\HistoryPlugin::add * @depends testAddsRequests */ public function testMaintainsLimit() { $h = new HistoryPlugin(); $h->setLimit(2); $requests = $this->addRequests($h, 3); $this->assertEquals(2, count($h)); $i = 0; foreach ($h as $request) { if ($i > 0) { $this->assertSame($requests[$i], $request); } } } /** * @covers Guzzle\Http\Plugin\HistoryPlugin::getLastRequest */ public function testReturnsLastRequest() { $h = new HistoryPlugin(); $requests = $this->addRequests($h, 5); $this->assertSame(end($requests), $h->getLastRequest()); } /** * @covers Guzzle\Http\Plugin\HistoryPlugin::getLastResponse */ public function testReturnsLastResponse() { $h = new HistoryPlugin(); $requests = $this->addRequests($h, 5); $this->assertSame(end($requests)->getResponse(), $h->getLastResponse()); } /** * @covers Guzzle\Http\Plugin\HistoryPlugin::clear */ public function testClearsHistory() { $h = new HistoryPlugin(); $requests = $this->addRequests($h, 5); $this->assertEquals(5, count($h)); $h->clear(); $this->assertEquals(0, count($h)); } /** * @covers Guzzle\Http\Plugin\HistoryPlugin::onRequestComplete * @depends testAddsRequests */ public function testUpdatesAddRequests() { $h = new HistoryPlugin(); $client = new Client('http://localhost/'); $client->getEventDispatcher()->addSubscriber($h); $request = $client->get(); $request->setResponse(new Response(200), true); $request->send(); $this->assertSame($request, $h->getLastRequest()); } }tests/Guzzle/Tests/Http/Plugin/LogPluginTest.php000064400000025662151742730640015742 0ustar00logAdapter = new ClosureLogAdapter( function($message, $priority, $extras = null) { echo $message . ' - ' . $priority . ' ' . implode(', ', (array) $extras) . "\n"; } ); $this->plugin = new LogPlugin($this->logAdapter); $this->client = new Client($this->getServer()->getUrl()); $this->client->getEventDispatcher()->addSubscriber($this->plugin); } /** * Parse a log message into parts * * @param string $message Message to parse * * @return array */ private function parseMessage($message) { $p = explode(' - ', $message, 4); $parts['host'] = trim($p[0]); $parts['request'] = str_replace('"', '', $p[1]); list($parts['code'], $parts['size']) = explode(' ', $p[2]); list($parts['time'], $parts['up'], $parts['down']) = explode(' ', $p[3]); $parts['extra'] = isset($p[4]) ? $p[4] : null; return $parts; } /** * @covers Guzzle\Http\Plugin\LogPlugin::__construct * @covers Guzzle\Http\Plugin\LogPlugin::getLogAdapter */ public function testPluginHasLogAdapter() { $plugin = new LogPlugin($this->logAdapter); $this->assertEquals($this->logAdapter, $plugin->getLogAdapter()); } public function testLogsRequestAndResponseContext() { $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"); $request = $this->client->get(); ob_start(); $request->send(); $message = ob_get_clean(); $parts = $this->parseMessage($message); $this->assertEquals('127.0.0.1', $parts['host']); $this->assertEquals('GET / HTTP/1.1', $parts['request']); $this->assertEquals(200, $parts['code']); $this->assertEquals(0, $parts['size']); $this->assertContains('127.0.0.1 - "GET / HTTP/1.1" - 200 0 - ', $message); $this->assertContains('7 guzzle.request', $message); } public function testLogsRequestAndResponseWireHeaders() { $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 4\r\n\r\ndata"); $client = new Client($this->getServer()->getUrl()); $plugin = new LogPlugin($this->logAdapter, LogPlugin::LOG_CONTEXT | LogPlugin::LOG_HEADERS); $client->getEventDispatcher()->addSubscriber($plugin); $request = $client->get(); ob_start(); $request->send(); $message = ob_get_clean(); // Make sure the context was logged $this->assertContains('127.0.0.1 - "GET / HTTP/1.1" - 200 4 - ', $message); $this->assertContains('7 guzzle.request', $message); // Check that the headers were logged $this->assertContains("GET / HTTP/1.1\r\n", $message); $this->assertContains("User-Agent: " . Guzzle::getDefaultUserAgent(), $message); $this->assertContains("Accept: */*\r\n", $message); $this->assertContains("Accept-Encoding: deflate, gzip", $message); $this->assertContains("Host: 127.0.0.1:", $message); // Make sure the response headers are present with a line between the request and response $this->assertContains("\n< HTTP/1.1 200 OK\r\n< Content-Length: 4", $message); } public function testLogsRequestAndResponseWireContentAndHeaders() { $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 4\r\n\r\ndata"); $client = new Client($this->getServer()->getUrl()); $plugin = new LogPlugin($this->logAdapter, LogPlugin::LOG_CONTEXT | LogPlugin::LOG_HEADERS | LogPlugin::LOG_BODY); $client->getEventDispatcher()->addSubscriber($plugin); $request = $client->put('', null, EntityBody::factory('send')); ob_start(); $request->send(); $message = ob_get_clean(); // Make sure the context was logged $this->assertContains('127.0.0.1 - "PUT / HTTP/1.1" - 200 4 - ', $message); // Check that the headers were logged $this->assertContains("PUT / HTTP/1.1\r\n", $message); $this->assertContains("User-Agent: " . Guzzle::getDefaultUserAgent(), $message); $this->assertContains("Content-Length: 4", $message); // Make sure the response headers are present with a line between the request and response $this->assertContains("\n< HTTP/1.1 200 OK\r\n< Content-Length: 4", $message); // Request payload $this->assertContains("\r\nsend", $message); // Response body $this->assertContains("data", $message); } public function testLogsRequestAndResponseWireContentAndHeadersNonStreamable() { $client = new Client($this->getServer()->getUrl()); $plugin = new LogPlugin($this->logAdapter, LogPlugin::LOG_CONTEXT | LogPlugin::LOG_HEADERS | LogPlugin::LOG_BODY); $client->getEventDispatcher()->addSubscriber($plugin); $request = $client->put(); // Send the response from the dummy server as the request body $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 4\r\n\r\nsend"); $stream = fopen($this->getServer()->getUrl(), 'r'); $request->setBody(EntityBody::factory($stream, 4)); $tmpFile = tempnam('/tmp', 'testLogsRequestAndResponseWireContentAndHeadersNonStreamable'); $request->setResponseBody(EntityBody::factory(fopen($tmpFile, 'w'))); $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 8\r\n\r\nresponse"); ob_start(); $request->send(); $message = ob_get_clean(); // Make sure the context was logged $this->assertContains('127.0.0.1 - "PUT / HTTP/1.1" - 200 8 - ', $message); // Check that the headers were logged $this->assertContains("PUT / HTTP/1.1\r\n", $message); $this->assertContains("User-Agent: " . Guzzle::getDefaultUserAgent(), $message); $this->assertContains("Content-Length: 4", $message); // Request payload $this->assertContains("\r\nsend", $message); // Make sure the response headers are present with a line between the request and response $this->assertContains("\n< HTTP/1.1 200 OK\r\n< Content-Length: 8", $message); // Response body $this->assertContains("\nresponse", $message); unlink($tmpFile); } public function testLogsWhenExceptionsAreThrown() { $client = new Client($this->getServer()->getUrl()); $plugin = new LogPlugin($this->logAdapter, LogPlugin::LOG_VERBOSE); $client->getEventDispatcher()->addSubscriber($plugin); $request = $client->get(); $this->getServer()->enqueue("HTTP/1.1 404 Not Found\r\nContent-Length: 0\r\n\r\n"); ob_start(); try { $request->send(); $this->fail('Exception for 404 was not thrown'); } catch (\Exception $e) {} $message = ob_get_clean(); $this->assertContains('127.0.0.1 - "GET / HTTP/1.1" - 404 0 - ', $message); $this->assertContains("GET / HTTP/1.1\r\n", $message); $this->assertContains("User-Agent: " . Guzzle::getDefaultUserAgent(), $message); $this->assertContains("\n< HTTP/1.1 404 Not Found\r\n< Content-Length: 0", $message); } /** * Data provider to test log verbosity * * @return array */ public function verbosityProvider() { $u = str_replace('http://', '', substr($this->getServer()->getUrl(), 0, -1)); return array( array(LogPlugin::LOG_CONTEXT, "GET /abc HTTP/1.1\r\nHost: $u\r\n\r\n"), array(LogPlugin::LOG_CONTEXT | LogPlugin::LOG_DEBUG, "GET /abc HTTP/1.1\r\nHost: $u\r\n\r\n"), array(LogPlugin::LOG_CONTEXT | LogPlugin::LOG_DEBUG | LogPlugin::LOG_HEADERS, "GET /abc HTTP/1.1\r\nHost: $u\r\n\r\n"), array(LogPlugin::LOG_CONTEXT | LogPlugin::LOG_DEBUG | LogPlugin::LOG_HEADERS | LogPlugin::LOG_BODY, "GET /abc HTTP/1.1\r\nHost: $u\r\n\r\n"), array(LogPlugin::LOG_VERBOSE, "GET /abc HTTP/1.1\r\nHost: $u\r\n\r\n"), array(LogPlugin::LOG_HEADERS, "GET /abc HTTP/1.1\r\nHost: $u\r\n\r\n"), array(LogPlugin::LOG_CONTEXT, "PUT /abc HTTP/1.1\r\nHost: $u\r\nContent-Length: 4\r\n\r\ndata"), array(LogPlugin::LOG_VERBOSE, "PUT /abc HTTP/1.1\r\nHost: $u\r\nContent-Length: 4\r\n\r\ndata"), ); } /** * @dataProvider verbosityProvider */ public function testLogsTransactionsAtDifferentLevels($level, $request) { $client = new Client(); $request = RequestFactory::fromMessage($request); $request->setClient($client); $plugin = new LogPlugin(new ClosureLogAdapter( function($message, $priority, $extras = null) { echo $message . "\n"; } ), $level); $request->getEventDispatcher()->addSubscriber($plugin); $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 4\r\n\r\nresp"); ob_start(); $request->send(); $gen = ob_get_clean(); $parts = explode("\n", trim($gen), 2); // Check if the context was properly logged if ($level & LogPlugin::LOG_CONTEXT) { $this->assertContains('127.0.0.1 - "' . $request->getMethod() . ' /', $gen); } // Check if the line count is 1 when just logging the context if ($level == LogPlugin::LOG_CONTEXT) { $this->assertEquals(1, count($parts)); return; } // Check if debug information is being logged if ($level & LogPlugin::LOG_DEBUG) { $this->assertContains("\n* Connected to 127.0.0.1 (127.0.0.1) port", $gen); } // Check if the headers are being properly logged if ($level & LogPlugin::LOG_HEADERS) { $this->assertContains("> " . $request->getMethod() . " /abc HTTP/1.1", $gen); // Ensure headers following the request line are logged $this->assertContains("Accept: */*", $gen); // Ensure the response headers are being logged $this->assertContains("< HTTP/1.1 200 OK\r\n< Content-Length: 4", $gen); } // Check if the body of the request and response are being logged if ($level & LogPlugin::LOG_BODY) { if ($request instanceof EntityEnclosingRequest) { $this->assertContains("\r\n\r\n" . $request->getBody(true), $gen); } $this->assertContains("\nresp", $gen); } } }tests/Guzzle/Tests/Http/Plugin/Md5ValidatorPluginTest.php000064400000010132151742730640017476 0ustar00getEventDispatcher()->addSubscriber($plugin); $body = 'abc'; $hash = md5($body); $response = new Response(200, array( 'Content-MD5' => $hash, 'Content-Length' => 3 ), 'abc'); $request->dispatch('request.complete', array( 'response' => $response )); // Try again with no Content-MD5 $response->removeHeader('Content-MD5'); $request->dispatch('request.complete', array( 'response' => $response )); } /** * @covers Guzzle\Http\Plugin\Md5ValidatorPlugin * @expectedException UnexpectedValueException */ public function testThrowsExceptionOnInvalidMd5() { $plugin = new Md5ValidatorPlugin(); $request = RequestFactory::create('GET', 'http://www.test.com/'); $request->getEventDispatcher()->addSubscriber($plugin); $request->dispatch('request.complete', array( 'response' => new Response(200, array( 'Content-MD5' => 'foobar', 'Content-Length' => 3 ), 'abc') )); } /** * @covers Guzzle\Http\Plugin\Md5ValidatorPlugin */ public function testSkipsWhenContentLengthIsTooLarge() { $plugin = new Md5ValidatorPlugin(false, 1); $request = RequestFactory::create('GET', 'http://www.test.com/'); $request->getEventDispatcher()->addSubscriber($plugin); $request->dispatch('request.complete', array( 'response' => new Response(200, array( 'Content-MD5' => 'foobar', 'Content-Length' => 3 ), 'abc') )); } /** * @covers Guzzle\Http\Plugin\Md5ValidatorPlugin */ public function testProperlyValidatesWhenUsingContentEncoding() { $plugin = new Md5ValidatorPlugin(true); $request = RequestFactory::create('GET', 'http://www.test.com/'); $request->getEventDispatcher()->addSubscriber($plugin); // Content-MD5 is the MD5 hash of the canonical content after all // content-encoding has been applied. Because cURL will automaticall // decompress entity bodies, we need to re-compress it to calculate. $body = EntityBody::factory('abc'); $body->compress(); $hash = $body->getContentMd5(); $body->uncompress(); $response = new Response(200, array( 'Content-MD5' => $hash, 'Content-Encoding' => 'gzip' ), 'abc'); $request->dispatch('request.complete', array( 'response' => $response )); $this->assertEquals('abc', $response->getBody(true)); // Try again with an unknown encoding $response = new Response(200, array( 'Content-MD5' => $hash, 'Content-Encoding' => 'foobar' ), 'abc'); $request->dispatch('request.complete', array( 'response' => $response )); // Try again with compress $body->compress('bzip2.compress'); $response = new Response(200, array( 'Content-MD5' => $body->getContentMd5(), 'Content-Encoding' => 'compress' ), 'abc'); $request->dispatch('request.complete', array( 'response' => $response )); // Try again with encoding and disabled content-encoding checks $request->getEventDispatcher()->removeSubscriber($plugin); $plugin = new Md5ValidatorPlugin(false); $request->getEventDispatcher()->addSubscriber($plugin); $request->dispatch('request.complete', array( 'response' => $response )); } }tests/Guzzle/Tests/Http/Plugin/MockPluginTest.php000064400000013001151742730640016072 0ustar00assertInternalType('array', MockPlugin::getSubscribedEvents()); } /** * @covers Guzzle\Http\Plugin\MockPlugin::getAllEvents */ public function testDescribesEvents() { $this->assertInternalType('array', MockPlugin::getAllEvents()); } /** * @covers Guzzle\Http\Plugin\MockPlugin::__construct * @covers Guzzle\Http\Plugin\MockPlugin::isTemporary */ public function testCanBeTemporary() { $plugin = new MockPlugin(); $this->assertFalse($plugin->isTemporary()); $plugin = new MockPlugin(null, true); $this->assertTrue($plugin->isTemporary()); } /** * @covers Guzzle\Http\Plugin\MockPlugin::count */ public function testIsCountable() { $plugin = new MockPlugin(); $plugin->addResponse(Response::factory("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n")); $this->assertEquals(1, count($plugin)); } /** * @covers Guzzle\Http\Plugin\MockPlugin::clearQueue * @depends testIsCountable */ public function testCanClearQueue() { $plugin = new MockPlugin(); $plugin->addResponse(Response::factory("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n")); $plugin->clearQueue(); $this->assertEquals(0, count($plugin)); } /** * @covers Guzzle\Http\Plugin\MockPlugin::getQueue */ public function testCanInspectQueue() { $plugin = new MockPlugin(); $this->assertInternalType('array', $plugin->getQueue()); $plugin->addResponse(Response::factory("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n")); $queue = $plugin->getQueue(); $this->assertInternalType('array', $queue); $this->assertEquals(1, count($queue)); } /** * @covers Guzzle\Http\Plugin\MockPlugin::getMockFile */ public function testRetrievesResponsesFromFiles() { $response = MockPlugin::getMockFile(__DIR__ . '/../../TestData/mock_response'); $this->assertInstanceOf('Guzzle\\Http\\Message\\Response', $response); $this->assertEquals(200, $response->getStatusCode()); } /** * @covers Guzzle\Http\Plugin\MockPlugin::getMockFile * @expectedException InvalidArgumentException */ public function testThrowsExcpetionWhenResponseFileIsNotFound() { MockPlugin::getMockFile('missing/filename'); } /** * @covers Guzzle\Http\Plugin\MockPlugin::addResponse * @expectedException InvalidArgumentException */ public function testInvalidResponsesThrowAnException() { $p = new MockPlugin(); $p->addResponse($this); } /** * @covers Guzzle\Http\Plugin\MockPlugin::addResponse */ public function testAddsResponseObjectsToQueue() { $p = new MockPlugin(); $response = Response::factory("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"); $p->addResponse($response); $this->assertEquals(array($response), $p->getQueue()); } /** * @covers Guzzle\Http\Plugin\MockPlugin::addResponse */ public function testAddsResponseFilesToQueue() { $p = new MockPlugin(); $p->addResponse(__DIR__ . '/../../TestData/mock_response'); $this->assertEquals(1, count($p)); } /** * @covers Guzzle\Http\Plugin\MockPlugin::onRequestCreate * @covers Guzzle\Http\Plugin\MockPlugin::addResponse * @covers Guzzle\Http\Plugin\MockPlugin::dequeue * @depends testAddsResponseFilesToQueue */ public function testAddsMockResponseToRequestFromClient() { $p = new MockPlugin(); $response = MockPlugin::getMockFile(__DIR__ . '/../../TestData/mock_response'); $p->addResponse($response); $client = new Client('http://localhost:123/'); $client->getEventDispatcher()->addSubscriber($p, 9999); $request = $client->get(); $request->send(); $this->assertSame($response, $request->getResponse()); $this->assertEquals(0, count($p)); } /** * @covers Guzzle\Http\Plugin\MockPlugin::onRequestCreate * @depends testAddsResponseFilesToQueue */ public function testUpdateIgnoresWhenEmpty() { $p = new MockPlugin(); $p->onRequestCreate(new Event()); } /** * @covers Guzzle\Http\Plugin\MockPlugin::onRequestCreate * @covers Guzzle\Http\Plugin\MockPlugin::dequeue * @depends testAddsMockResponseToRequestFromClient */ public function testDetachesTemporaryWhenEmpty() { $p = new MockPlugin(null, true); $p->addResponse(MockPlugin::getMockFile(__DIR__ . '/../../TestData/mock_response')); $client = new Client('http://localhost:123/'); $client->getEventDispatcher()->addSubscriber($p, 9999); $request = $client->get(); $request->send(); $this->assertFalse($this->hasSubscriber($client, $p)); } /** * @covers Guzzle\Http\Plugin\MockPlugin::__construct */ public function testLoadsResponsesFromConstructor() { $p = new MockPlugin(array(new Response(200))); $this->assertEquals(1, $p->count()); } }tests/Guzzle/Tests/Http/Plugin/OauthPluginTest.php000064400000013115151742730640016267 0ustar00 'foo', 'consumer_secret' => 'bar', 'token' => 'count', 'token_secret' => 'dracula' ); protected function getRequest() { return RequestFactory::create('POST', 'http://www.test.com/path?a=b&c=d', null, array( 'e' => 'f' )); } /** * @covers Guzzle\Http\Plugin\OauthPlugin::getSubscribedEvents */ public function testSubscribesToEvents() { $events = OauthPlugin::getSubscribedEvents(); $this->assertArrayHasKey('request.before_send', $events); } /** * @covers Guzzle\Http\Plugin\OauthPlugin::__construct */ public function testAcceptsConfigurationData() { $p = new OauthPlugin($this->config); // Access the config object $class = new \ReflectionClass($p); $property = $class->getProperty('config'); $property->setAccessible(true); $config = $property->getValue($p); $this->assertEquals('foo', $config['consumer_key']); $this->assertEquals('bar', $config['consumer_secret']); $this->assertEquals('count', $config['token']); $this->assertEquals('dracula', $config['token_secret']); $this->assertEquals('1.0', $config['version']); $this->assertEquals('HMAC-SHA1', $config['signature_method']); } /** * @covers Guzzle\Http\Plugin\OauthPlugin::getStringToSign */ public function testCreatesStringToSignFromPostRequest() { $p = new OauthPlugin($this->config); $request = $this->getRequest(); $this->assertEquals( // Method and URL 'POST&http%3A%2F%2Fwww.test.com%2Fpath%23' . // Sorted parameters from query string and body '&a%3Db%26c%3Dd%26e%3Df%26oauth_consumer_key%3Dfoo' . '%26oauth_nonce%3D29443585e9f85f23306198f7eae8d870c46c53ad%26' . 'oauth_signature_method%3DHMAC-SHA1' . '%26oauth_timestamp%3D' . self::TIMESTAMP . '%26oauth_token%3Dcount%26oauth_version%3D1.0', $p->getStringToSign($request, self::TIMESTAMP) ); } /** * @covers Guzzle\Http\Plugin\OauthPlugin::getStringToSign */ public function testCreatesStringToSignFromPostRequestWithCustomContentType() { $p = new OauthPlugin($this->config); $request = $this->getRequest(); $request->setHeader('Content-Type', 'Foo'); $this->assertEquals( // Method and URL 'POST&http%3A%2F%2Fwww.test.com%2Fpath%23' . // Sorted parameters from query string and body '&a%3Db%26c%3Dd%26oauth_consumer_key%3Dfoo' . '%26oauth_nonce%3D29443585e9f85f23306198f7eae8d870c46c53ad%26' . 'oauth_signature_method%3DHMAC-SHA1' . '%26oauth_timestamp%3D' . self::TIMESTAMP . '%26oauth_token%3Dcount%26oauth_version%3D1.0', $p->getStringToSign($request, self::TIMESTAMP) ); } /** * @covers Guzzle\Http\Plugin\OauthPlugin::getStringToSign * @depends testCreatesStringToSignFromPostRequest */ public function testConvertsBooleansToStrings() { $p = new OauthPlugin($this->config); $request = $this->getRequest(); $request->getQuery()->set('a', true); $request->getQuery()->set('c', false); $this->assertContains('&a%3Dtrue%26c%3Dfalse', $p->getStringToSign($request, self::TIMESTAMP)); } /** * @covers Guzzle\Http\Plugin\OauthPlugin::getSignature * @depends testCreatesStringToSignFromPostRequest */ public function testSignsStrings() { $p = new OauthPlugin(array_merge($this->config, array( 'signature_callback' => function($string, $key) { return "_{$string}|{$key}_"; } ))); $request = $this->getRequest(); $sig = $p->getSignature($request, self::TIMESTAMP); $this->assertEquals( '_POST&http%3A%2F%2Fwww.test.com%2Fpath%23&a%3Db%26c%3Dd%26e%3Df%26oauth_consumer_key%3Dfoo' . '%26oauth_nonce%3D29443585e9f85f23306198f7eae8d870c46c53ad%26oauth_signature_method%3DHMAC-SHA1' . '%26oauth_timestamp%3D' . self::TIMESTAMP . '%26oauth_token%3Dcount%26oauth_version%3D1.0|' . 'bar&dracula_', base64_decode($sig) ); } /** * @covers Guzzle\Http\Plugin\OauthPlugin::onRequestBeforeSend * @covers Guzzle\Http\Plugin\OauthPlugin::__construct */ public function testSignsOauthRequests() { $p = new OauthPlugin($this->config); $event = new Event(array( 'request' => $this->getRequest(), 'timestamp' => self::TIMESTAMP )); $p->onRequestBeforeSend($event); $this->assertTrue($event['request']->hasHeader('Authorization')); $this->assertEquals('OAuth oauth_consumer_key="foo", ' . 'oauth_nonce="29443585e9f85f23306198f7eae8d870c46c53ad", ' . 'oauth_signature="IvVzcqLU%2Fk2zzoC7gBRfSnDkMdQ%3D", ' . 'oauth_signature_method="HMAC-SHA1", ' . 'oauth_timestamp="' . self::TIMESTAMP . '", ' . 'oauth_token="count", ' . 'oauth_version="1.0"', $event['request']->getHeader('Authorization') ); } }tests/Guzzle/Tests/Http/QueryStringTest.php000064400000011721151742730640015067 0ustar00q = new QueryString(); } /** * @covers \Guzzle\Http\QueryString::getFieldSeparator */ public function testGetFieldSeparator() { $this->assertEquals('&', $this->q->getFieldSeparator()); } /** * @covers \Guzzle\Http\QueryString::getPrefix */ public function testGetPrefix() { $this->assertEquals('?', $this->q->getPrefix()); } /** * @covers \Guzzle\Http\QueryString::getValueSeparator */ public function testGetValueSeparator() { $this->assertEquals('=', $this->q->getValueSeparator()); } /** * @covers \Guzzle\Http\QueryString::isEncodingFields * @covers \Guzzle\Http\QueryString::setEncodeFields */ public function testIsEncodingFields() { $this->assertTrue($this->q->isEncodingFields()); $this->assertEquals($this->q, $this->q->setEncodeFields(false)); $this->assertFalse($this->q->isEncodingFields()); } /** * @covers \Guzzle\Http\QueryString::isEncodingValues * @covers \Guzzle\Http\QueryString::setEncodeValues */ public function testIsEncodingValues() { $this->assertTrue($this->q->isEncodingValues()); $this->assertEquals($this->q, $this->q->setEncodeValues(false)); $this->assertFalse($this->q->isEncodingValues()); } /** * @covers \Guzzle\Http\QueryString::setFieldSeparator * @covers \Guzzle\Http\QueryString::setFieldSeparator */ public function testSetFieldSeparator() { $this->assertEquals($this->q, $this->q->setFieldSeparator('/')); $this->assertEquals('/', $this->q->getFieldSeparator()); } /** * @covers \Guzzle\Http\QueryString::setPrefix * @covers \Guzzle\Http\QueryString::getPrefix */ public function testSetPrefix() { $this->assertEquals($this->q, $this->q->setPrefix('')); $this->assertEquals('', $this->q->getPrefix()); } /** * @covers \Guzzle\Http\QueryString::setValueSeparator * @covers \Guzzle\Http\QueryString::getValueSeparator */ public function testSetValueSeparator() { $this->assertEquals($this->q, $this->q->setValueSeparator('/')); $this->assertEquals('/', $this->q->getValueSeparator()); } /** * @covers \Guzzle\Http\QueryString::urlEncode * @covers \Guzzle\Http\QueryString::encodeData * @covers \Guzzle\Http\QueryString::replace */ public function testUrlEncode() { $params = array( 'test' => 'value', 'test 2' => 'this is a test?', 'test3' => array('v1', 'v2', 'v3') ); $encoded = array( 'test' => 'value', rawurlencode('test 2') => rawurlencode('this is a test?'), 'test3[0]' => 'v1', 'test3[1]' => 'v2', 'test3[2]' => 'v3' ); $this->q->replace($params); $this->assertEquals($encoded, $this->q->urlEncode()); // Disable field encoding $testData = array( 'test 2' => 'this is a test' ); $this->q->replace($testData); $this->q->setEncodeFields(false); $this->assertEquals(array( 'test 2' => rawurlencode('this is a test') ), $this->q->urlEncode()); // Disable encoding of both fields and values $this->q->setEncodeValues(false); $this->assertEquals($testData, $this->q->urlEncode()); } /** * @covers \Guzzle\Http\QueryString * @covers \Guzzle\Http\QueryString::__toString * @covers \Guzzle\Http\QueryString::setEncodeFields * @covers \Guzzle\Http\QueryString::replace * @covers \Guzzle\Http\QueryString::setAggregateFunction * @covers \Guzzle\Http\QueryString::encodeData */ public function testToString() { // Check with no parameters $this->assertEquals('', $this->q->__toString()); $params = array( 'test' => 'value', 'test 2' => 'this is a test?', 'test3' => array( 'v1', 'v2', 'v3' ) ); $this->q->replace($params); $this->assertEquals('?test=value&test%202=this%20is%20a%20test%3F&test3[0]=v1&test3[1]=v2&test3[2]=v3', $this->q->__toString()); $this->q->setEncodeFields(false); $this->q->setEncodeValues(false); $this->assertEquals('?test=value&test 2=this is a test?&test3[0]=v1&test3[1]=v2&test3[2]=v3', $this->q->__toString()); // Use an alternative aggregator $this->q->setAggregateFunction(array($this->q, 'aggregateUsingComma')); $this->assertEquals('?test=value&test 2=this is a test?&test3=v1,v2,v3', $this->q->__toString()); } }tests/Guzzle/Tests/Http/Server.php000064400000015266151742730640013211 0ustar00port = $port ?: self::DEFAULT_PORT; $this->client = new Client($this->getUrl()); } /** * Destructor to safely shutdown the node.js server if it is still running * * @codeCoverageIgnore */ public function __destruct() { // Only shut the server down if the object knows it started the server if ($this->running) { try { $this->stop(); } catch (\Exception $e) { } } } /** * Flush the received requests from the server * * @return bool Returns TRUE on success or FALSE on failure * @throws HttpException */ public function flush() { if (!$this->isRunning()) { return false; } return $this->client->delete('guzzle-server/requests') ->send()->getStatusCode() == 200; } /** * Queue an array of responses or a single response on the server. * * Any currently queued responses will be overwritten. Subsequent requests * on the server will return queued responses in FIFO order. * * @param array|Response $responses A single or array of Responses to queue * * @return bool Returns TRUE on success or FALSE on failure * @throws HttpException */ public function enqueue($responses) { $data = array(); foreach ((array) $responses as $response) { // Create the response object from a string if (is_string($response)) { $response = Response::factory($response); } else if (!($response instanceof Response)) { throw new HttpException( 'Responses must be strings or implement Response' ); } $data[] = array( 'statusCode' => $response->getStatusCode(), 'reasonPhrase' => $response->getReasonPhrase(), 'headers' => $response->getHeaders()->getAll(), 'body' => $response->getBody(true) ); } $request = $this->client->put('guzzle-server/responses', null, json_encode($data)); $response = $request->send(); return $response->getStatusCode() == 200; } /** * Check if the server is running * * @return bool */ public function isRunning() { if ($this->running) { return true; } else { $fp = @fsockopen('127.0.0.1', $this->port, $errno, $errstr, 1); if (!$fp) { return false; } else { fclose($fp); return true; } } } /** * Get the URL to the server * * @return string */ public function getUrl() { return 'http://127.0.0.1:' . $this->getPort() . '/'; } /** * Get the port that the server is listening on * * @return int */ public function getPort() { return $this->port; } /** * Get all of the received requests * * @param bool $hydrate (optional) Set to TRUE to turn the messages into * actual {@see RequestInterface} objects. If $hydrate is FALSE, * requests will be returned as strings. * * @return array * @throws HttpException */ public function getReceivedRequests($hydrate = false) { $data = array(); if ($this->isRunning()) { $response = $this->client->get('guzzle-server/requests')->send(); $data = array_filter(explode(self::REQUEST_DELIMITER, $response->getBody(true))); if ($hydrate) { $data = array_map(function($message) { return RequestFactory::fromMessage($message); }, $data); } } return $data; } /** * Start running the node.js server in the background */ public function start() { if (!$this->isRunning()) { exec('node ' . __DIR__ . \DIRECTORY_SEPARATOR . 'server.js ' . $this->port . ' >> /tmp/server.log 2>&1 &'); // Shut the server down when the script exits unexpectedly register_shutdown_function(array($this, 'stop')); // Wait at most 5 seconds for the server the setup before proceeding $start = time(); while (!$this->isRunning() && time() - $start < 5); // @codeCoverageIgnoreStart if (!$this->isRunning()) { throw new HttpException( 'Unable to contact server.js. Have you installed node.js ' . 'v0.5.0+? The node.js executable, node, must also be in ' . 'your path.' ); } // @codeCoverageIgnoreEnd } $this->running = true; } /** * Stop running the node.js server * * @return bool Returns TRUE on success or FALSE on failure * @throws HttpException */ public function stop() { if (!$this->isRunning()) { return false; } $this->running = false; return $this->client->delete('guzzle-server')->send() ->getStatusCode() == 200; } }tests/Guzzle/Tests/Http/UrlTest.php000064400000017705151742730640013345 0ustar00assertEquals($url, Url::buildUrl($parts)); } /** * @covers Guzzle\Http\Url::getPort */ public function testPortIsDeterminedFromScheme() { $this->assertEquals(80, Url::factory('http://www.test.com/')->getPort()); $this->assertEquals(443, Url::factory('https://www.test.com/')->getPort()); $this->assertEquals(null, Url::factory('ftp://www.test.com/')->getPort()); $this->assertEquals(8192, Url::factory('http://www.test.com:8192/')->getPort()); } /** * @covers Guzzle\Http\Url::__clone */ public function testCloneCreatesNewInternalObjects() { $u1 = Url::factory('http://www.test.com/'); $u2 = clone $u1; $this->assertNotSame($u1->getQuery(), $u2->getQuery()); } /** * @covers Guzzle\Http\Url::__construct * @covers Guzzle\Http\Url::factory * @covers Guzzle\Http\Url::__toString * @covers Guzzle\Http\Url::isAbsolute */ public function testValidatesUrlPartsInFactory() { $url = Url::factory('/index.php'); $this->assertEquals('/index.php', (string) $url); $this->assertFalse($url->isAbsolute()); $url = 'http://michael:test@test.com:80/path/123?q=abc#test'; $u = Url::factory($url); $this->assertEquals('http://michael:test@test.com/path/123?q=abc#test', (string) $u); $this->assertTrue($u->isAbsolute()); } /** * @covers Guzzle\Http\Url */ public function testUrlStoresParts() { $url = Url::factory('http://test:pass@www.test.com:8081/path/path2/?a=1&b=2#fragment'); $this->assertEquals('http', $url->getScheme()); $this->assertEquals('test', $url->getUsername()); $this->assertEquals('pass', $url->getPassword()); $this->assertEquals('www.test.com', $url->getHost()); $this->assertEquals(8081, $url->getPort()); $this->assertEquals('/path/path2/', $url->getPath()); $this->assertEquals('?a=1&b=2', (string)$url->getQuery()); $this->assertEquals('fragment', $url->getFragment()); $this->assertEquals(array( 'fragment' => 'fragment', 'host' => 'www.test.com', 'pass' => 'pass', 'path' => '/path/path2/', 'port' => 8081, 'query' => '?a=1&b=2', 'query_prefix' => '?', 'scheme' => 'http', 'user' => 'test' ), $url->getParts()); } /** * @covers Guzzle\Http\Url::setPath * @covers Guzzle\Http\Url::getPath * @covers Guzzle\Http\Url::getPathSegments * @covers Guzzle\Http\Url::buildUrl */ public function testHandlesPathsCorrectly() { $url = Url::factory('http://www.test.com'); $this->assertEquals('/', $url->getPath()); $url->setPath('test'); $this->assertEquals('/test', $url->getPath()); $url->setPath('/test/123/abc'); $this->assertEquals(array('test', '123', 'abc'), $url->getPathSegments()); $parts = parse_url('http://www.test.com/test'); $parts['path'] = ''; $this->assertEquals('http://www.test.com/', Url::buildUrl($parts)); $parts['path'] = 'test'; $this->assertEquals('http://www.test.com/test', Url::buildUrl($parts)); } /** * @covers Guzzle\Http\Url::addPath */ public function testAddsToPath() { // Does nothing here $this->assertEquals('http://e.com/base?a=1', (string) Url::factory('http://e.com/base?a=1')->addPath(false)); $this->assertEquals('http://e.com/base?a=1', (string) Url::factory('http://e.com/base?a=1')->addPath('')); $this->assertEquals('http://e.com/base?a=1', (string) Url::factory('http://e.com/base?a=1')->addPath('/')); $this->assertEquals('http://e.com/base/relative?a=1', (string) Url::factory('http://e.com/base?a=1')->addPath('relative')); $this->assertEquals('http://e.com/base/relative?a=1', (string) Url::factory('http://e.com/base?a=1')->addPath('/relative')); } /** * URL combination data provider * * @return array */ public function urlCombineDataProvider() { return array( array('http://www.example.com/', 'http://www.example.com/', 'http://www.example.com/'), array('http://www.example.com/path', '/absolute', 'http://www.example.com/absolute'), array('http://www.example.com/path', '/absolute?q=2', 'http://www.example.com/absolute?q=2'), array('http://www.example.com/path', 'more', 'http://www.example.com/path/more'), array('http://www.example.com/path', 'more?q=1', 'http://www.example.com/path/more?q=1'), array('http://www.example.com/', '?q=1', 'http://www.example.com/?q=1'), array('http://www.example.com/path', 'http://test.com', 'http://test.com/path'), array('http://www.example.com:8080/path', 'http://test.com', 'http://test.com/path'), array('http://www.example.com:8080/path', '?q=2#abc', 'http://www.example.com:8080/path?q=2#abc'), array('http://u:a@www.example.com/path', 'test', 'http://u:a@www.example.com/path/test'), array('http://www.example.com/path', 'http://u:a@www.example.com/', 'http://u:a@www.example.com/path'), array('/path?q=2', 'http://www.test.com/', 'http://www.test.com/path?q=2'), ); } /** * @covers Guzzle\Http\Url::combine * @dataProvider urlCombineDataProvider */ public function testCombinesUrls($a, $b, $c) { $this->assertEquals($c, (string) Url::factory($a)->combine($b)); } /** * @covers Guzzle\Http\Url */ public function testHasGettersAndSetters() { $url = Url::factory('http://www.test.com/'); $this->assertEquals('example.com', $url->setHost('example.com')->getHost()); $this->assertEquals('8080', $url->setPort(8080)->getPort()); $this->assertEquals('/foo/bar', $url->setPath(array('foo', 'bar'))->getPath()); $this->assertEquals('a', $url->setPassword('a')->getPassword()); $this->assertEquals('b', $url->setUsername('b')->getUsername()); $this->assertEquals('abc', $url->setFragment('abc')->getFragment()); $this->assertEquals('https', $url->setScheme('https')->getScheme()); $this->assertEquals('?a=123', (string) $url->setQuery('a=123')->getQuery()); $this->assertEquals('https://b:a@example.com:8080/foo/bar?a=123#abc', (string)$url); $this->assertEquals('?b=boo', (string) $url->setQuery(new QueryString(array( 'b' => 'boo' )))->getQuery()); $this->assertEquals('https://b:a@example.com:8080/foo/bar?b=boo#abc', (string)$url); } /** * @covers Guzzle\Http\Url::setQuery */ public function testSetQueryAcceptsArray() { $url = Url::factory('http://www.test.com'); $url->setQuery(array('a' => 'b')); $this->assertEquals('http://www.test.com/?a=b', (string) $url); } }tests/Guzzle/Tests/Http/server.js000064400000012052151742730640013064 0ustar00/** * Guzzle node.js test server to return queued responses to HTTP requests and * expose a RESTful API for enqueueing responses and retrieving the requests * that have been received. * * - Delete all requests that have been received: * DELETE /guzzle-server/requests * Host: 127.0.0.1:8124 * * - Enqueue responses * PUT /guzzle-server/responses * Host: 127.0.0.1:8124 * * [{ "statusCode": 200, "reasonPhrase": "OK", "headers": {}, "body": "" }] * * - Get the recevied requests * GET /guzzle-server/requests * Host: 127.0.0.1:8124 * * - Shutdown the server * DELETE /guzzle-server * Host: 127.0.0.1:8124 * * @package Guzzle PHP * @license See the LICENSE file that was distributed with this source code. */ var http = require("http"); /** * Guzzle node.js server * @class */ var GuzzleServer = function(port) { this.port = port; this.log = log; this.responses = []; this.requests = []; var that = this; /** * Handle a Guzzle Server control request * @param (String) request HTTP request as a string * @param (ServerRequest) req Received server request * @param (ServerResponse) res Outgoing server response */ var controlRequest = function(request, req, res) { if (req.method == "DELETE") { if (req.url == "/guzzle-server/requests") { // Clear the received requests that.requests = []; res.writeHead(200, "OK", { "Content-Length": 0 }); res.end(); if (this.log) { console.log("Flushing requests"); } } else if (req.url == "/guzzle-server") { // Shutdown the server res.writeHead(200, "OK", { "Content-Length": 0, "Connection": "close" }); res.end(); if (this.log) { console.log("Shutting down"); } that.server.close(); } } else if (req.method == "GET") { if (req.url === "/guzzle-server/requests") { // Get received requests var data = that.requests.join("\n----[request]\n"); res.writeHead(200, "OK", { "Content-Length": data.length }); res.end(data); if (this.log) { console.log("Sending receiving requests"); } } } else if (req.method == "PUT") { if (req.url == "/guzzle-server/responses") { // Received respones to queue that.responses = eval("(" + request.split("\r\n\r\n")[1] + ")"); if (this.log) { console.log("Adding respones:"); console.log(that.responses); } res.writeHead(200, "OK", { "Content-Length": 0 }); res.end(); } } }; /** * Received a complete request * @param (String) request HTTP request as a string * @param (ServerRequest) req Received server request * @param (ServerResponse) res Outgoing server response */ var receivedRequest = function(request, req, res) { if (req.url.indexOf("/guzzle-server") === 0) { controlRequest(request, req, res); } else { var response = that.responses.shift(); res.writeHead(response.statusCode, response.reasonPhrase, response.headers); res.end(response.body); that.requests.push(request); } }; /** * Start the node.js Guzzle server */ this.start = function() { that.server = http.createServer(function(req, res) { // If this is not a control request and no responses are in queue, return 500 response if (req.url.indexOf("/guzzle-server") == -1 && !that.responses.length) { res.writeHead(500); res.end("No responses in queue"); return; } // Begin building the request message as a string var request = req.method + " " + req.url + " HTTP/" + req.httpVersion + "\r\n"; // Add the request headers for (var i in req.headers) { request += i + ": " + req.headers[i] + "\r\n"; } request += "\r\n"; // Receive each chunk of the request body req.addListener("data", function(chunk) { request += chunk; }); // Called when the request completes req.addListener("end", function() { receivedRequest(request, req, res); }); }); that.server.listen(port, "127.0.0.1"); if (this.log) { console.log("Server running at http://127.0.0.1:8124/"); } }; }; // Get the port from the arguments port = process.argv.length >= 3 ? process.argv[2] : 8124; log = process.argv.length >= 4 ? process.argv[3] : false; // Start the server server = new GuzzleServer(port, log); server.start();tests/Guzzle/Tests/Mock/MockMulti.php000064400000000253151742730640013607 0ustar00multiHandle; } }tests/Guzzle/Tests/Mock/MockObserver.php000064400000002666151742730640014316 0ustar00events as $event) { if ($event->getName() == $eventName) { return true; } } return false; } public function getLastEvent() { return end($this->events); } public function count() { return count($this->events); } public function getGrouped() { $events = array(); foreach ($this->events as $event) { if (!isset($events[$event->getName()])) { $events[$event->getName()] = array(); } $events[$event->getName()][] = $event; } return $events; } public function getData($event, $key, $occurence = 0) { $grouped = $this->getGrouped(); if (isset($grouped[$event])) { return $grouped[$event][$occurence][$key]; } return null; } /** * {@inheritdoc} */ public function update(Event $event) { $this->events[] = $event; } }tests/Guzzle/Tests/Mock/MockSubject.php000064400000000147151742730640014116 0ustar00serviceTest = new ServiceDescription(array( 'test_command' => new ApiCommand(array( 'doc' => 'documentationForCommand', 'method' => 'DELETE', 'class' => 'Guzzle\\Tests\\Service\\Mock\\Command\\MockCommand', 'args' => array( 'bucket' => array( 'required' => true ), 'key' => array( 'required' => true ) ) )) )); $this->service = XmlDescriptionBuilder::build(__DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'TestData' . DIRECTORY_SEPARATOR . 'test_service.xml'); } /** * @covers Guzzle\Service\Client::factory */ public function testFactoryCreatesClient() { $client = Client::factory(array( 'base_url' => 'http://www.test.com/', 'test' => '123' )); $this->assertEquals('http://www.test.com/', $client->getBaseUrl()); $this->assertEquals('123', $client->getConfig('test')); } /** * @covers Guzzle\Service\Client::getAllEvents */ public function testDescribesEvents() { $this->assertInternalType('array', Client::getAllEvents()); } /** * @covers Guzzle\Service\Client::execute */ public function testExecutesCommands() { $this->getServer()->flush(); $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"); $client = new Client($this->getServer()->getUrl()); $cmd = new MockCommand(); $client->execute($cmd); $this->assertInstanceOf('Guzzle\\Http\\Message\\Response', $cmd->getResponse()); $this->assertInstanceOf('Guzzle\\Http\\Message\\Response', $cmd->getResult()); $this->assertEquals(1, count($this->getServer()->getReceivedRequests(false))); } /** * @covers Guzzle\Service\Client::execute */ public function testExecutesCommandsWithArray() { $client = new Client('http://www.test.com/'); $client->getEventDispatcher()->addSubscriber(new MockPlugin(array( new \Guzzle\Http\Message\Response(200), new \Guzzle\Http\Message\Response(200) ))); // Create a command set and a command $set = array(new MockCommand(), new MockCommand()); $client->execute($set); // Make sure it sent $this->assertTrue($set[0]->isExecuted()); $this->assertTrue($set[1]->isExecuted()); } /** * @covers Guzzle\Service\Client::execute * @expectedException Guzzle\Service\Command\CommandSetException */ public function testThrowsExceptionWhenExecutingMixedClientCommandSets() { $client = new Client('http://www.test.com/'); $otherClient = new Client('http://www.test-123.com/'); // Create a command set and a command $set = new CommandSet(); $cmd = new MockCommand(); $set->addCommand($cmd); // Associate the other client with the command $cmd->setClient($otherClient); // Send the set with the wrong client, causing an exception $client->execute($set); } /** * @covers Guzzle\Service\Client::execute * @expectedException InvalidArgumentException */ public function testThrowsExceptionWhenExecutingInvalidCommandSets() { $client = new Client('http://www.test.com/'); $client->execute(new \stdClass()); } /** * @covers Guzzle\Service\Client::execute */ public function testExecutesCommandSets() { $client = new Client('http://www.test.com/'); $client->getEventDispatcher()->addSubscriber(new MockPlugin(array( new \Guzzle\Http\Message\Response(200) ))); // Create a command set and a command $set = new CommandSet(); $cmd = new MockCommand(); $set->addCommand($cmd); $this->assertSame($set, $client->execute($set)); // Make sure it sent $this->assertTrue($cmd->isExecuted()); $this->assertTrue($cmd->isPrepared()); $this->assertEquals(200, $cmd->getResponse()->getStatusCode()); } /** * @covers Guzzle\Service\Client::getCommand * @expectedException InvalidArgumentException */ public function testThrowsExceptionWhenNoCommandFactoryIsSetAndGettingCommand() { $client = new Client($this->getServer()->getUrl()); $client->getCommand('test'); } /** * @covers Guzzle\Service\Client::getCommand * @covers Guzzle\Service\Client::getDescription * @covers Guzzle\Service\Client::setDescription */ public function testRetrievesCommandsFromConcreteAndService() { $client = new Mock\MockClient('http://www.example.com/'); $this->assertSame($client, $client->setDescription($this->serviceTest)); $this->assertSame($this->serviceTest, $client->getDescription()); // Creates service commands $this->assertInstanceOf('Guzzle\\Tests\\Service\\Mock\\Command\\MockCommand', $client->getCommand('test_command')); // Creates concrete commands $this->assertInstanceOf('Guzzle\\Tests\\Service\\Mock\\Command\\OtherCommand', $client->getCommand('other_command')); } public function testCreatesCommandsFromServiceDescriptions() { $this->getServer()->enqueue( "HTTP/1.1 200 OK\r\n" . "Content-Length: 0\r\n\r\n" ); $client = new Mock\MockClient($this->getServer()->getUrl()); $client->setDescription($this->service); $command = $client->getCommand('trends.location', array( 'woeid' => 123, 'acl' => '123' )); $client->execute($command); $this->assertEquals('/trends/123', $command->getRequest()->getPath()); } }tests/Guzzle/Tests/Service/Command/AbstractCommandTest.php000064400000001073151742730640017673 0ustar00setDescription($service); return $client; } }tests/Guzzle/Tests/Service/Command/ClosureCommandTest.php000064400000003336151742730640017550 0ustar00 function($command, $api) { $command->set('testing', '123'); $request = RequestFactory::create('GET', 'http://www.test.com/'); return $request; } )); $client = $this->getServiceBuilder()->get('mock'); $c->setClient($client)->prepare(); $this->assertEquals('123', $c->get('testing')); $this->assertEquals('http://www.test.com/', $c->getRequest()->getUrl()); } /** * @covers Guzzle\Service\Command\ClosureCommand * @expectedException UnexpectedValueException * @expectedExceptionMessage Closure command did not return a RequestInterface object */ public function testMustReturnRequest() { $c = new ClosureCommand(array( 'closure' => function($command, $api) { return false; } )); $client = $this->getServiceBuilder()->get('mock'); $c->setClient($client)->prepare(); } }tests/Guzzle/Tests/Service/Command/CommandSetTest.php000064400000013427151742730640016671 0ustar00assertTrue($commandSet->hasCommand($cmd)); } /** * @covers Guzzle\Service\Command\CommandSet::hasCommand * @covers Guzzle\Service\Command\CommandSet::addCommand * @covers Guzzle\Service\Command\CommandSet::removeCommand * @covers Guzzle\Service\Command\CommandSet::getCommands * @covers Guzzle\Service\Command\CommandSet::count * @covers Guzzle\Service\Command\CommandSet::getIterator */ public function testAllowsCommandManipulationAndIntrospection() { $commandSet = new CommandSet(); // Check when no commands are set $this->assertEquals(array(), $commandSet->getCommands()); // Create some mock commands $command1 = new MockCommand(); $command2 = new MockCommand(); // Check the fluent interface $this->assertEquals($commandSet, $commandSet->addCommand($command1)); $commandSet->addCommand($command2); // Check that the commands are registered and findable $this->assertTrue($commandSet->hasCommand($command1)); $this->assertTrue($commandSet->hasCommand($command2)); $this->assertTrue($commandSet->hasCommand('Guzzle\\Tests\\Service\\Mock\\Command\\MockCommand')); // Test that the Countable interface is working $this->assertEquals(2, count($commandSet)); // Test that the IteratorAggregate interface is working $this->assertInstanceOf('ArrayIterator', $commandSet->getIterator()); $this->assertEquals(2, count($commandSet->getIterator())); $this->assertEquals(array($command1, $command2), $commandSet->getCommands()); // Remove the command by object $commandSet->removeCommand($command1); $this->assertFalse($commandSet->hasCommand($command1)); $this->assertTrue($commandSet->hasCommand($command2)); // Remove the command by class $commandSet->removeCommand('Guzzle\\Tests\\Service\\Mock\\Command\\MockCommand'); $this->assertFalse($commandSet->hasCommand($command2)); } /** * @covers Guzzle\Service\Command\CommandSet::execute * @covers Guzzle\Service\Command\CommandSetException */ public function testThrowsExceptionWhenAnyCommandHasNoClient() { $cmd = new MockCommand; $commandSet = new CommandSet(array($cmd)); try { $commandSet->execute(); $this->fail('CommandSetException not thrown when a command did not have a client'); } catch (\Guzzle\Service\Command\CommandSetException $e) { $this->assertEquals(array($cmd), $e->getCommands()); } } /** * @covers Guzzle\Service\Command\CommandSet::execute * @covers Guzzle\Service\Command\CommandSet::update */ public function testExecutesCommands() { $client = $this->getClient(); $observer = $this->getWildcardObserver($client); // Create a Mock response $response = new Response(200, array( 'Content-Type' => 'application/xml' ), '123'); $client->getEventDispatcher()->addSubscriber(new MockPlugin(array( $response, $response, $response ))); $command1 = new MockCommand(); $command1->setClient($client); $command2 = new MockCommand(); $command2->setClient($client); $command3 = new MockCommand(); $command3->setClient($client); $commandSet = new CommandSet(array($command1, $command2, $command3)); $commandSet->execute(); $this->assertTrue($command1->isExecuted()); $this->assertTrue($command1->isPrepared()); $this->assertTrue($command2->isExecuted()); $this->assertTrue($command2->isPrepared()); $this->assertTrue($command3->isExecuted()); $this->assertTrue($command3->isPrepared()); $this->assertEquals($response, $command1->getResponse()); $this->assertEquals($response, $command2->getResponse()); $grouped = $observer->getGrouped(); $this->assertEquals(3, count($grouped['command.before_send'])); $this->assertEquals(3, count($grouped['command.after_send'])); // make sure the command set was detached as a listener on the request $listeners = $command1->getRequest()->getEventDispatcher()->getListeners('request.complete'); $this->assertFalse(in_array($commandSet, $listeners)); // make sure that the command reference was removed $this->assertFalse($command1->getRequest()->getParams()->hasKey('command')); // Make sure that the command.after_send events are staggered, meaning they happened as requests completed $lastEvent = ''; foreach ($observer->events as $e) { if ($lastEvent == 'command.after_send' && $e == 'command.after_send') { $this->fail('Not completing commands as they complete: ' . var_export($observer->events, true)); } $lastEvent = $e; } } }tests/Guzzle/Tests/Service/Command/CommandTest.php000064400000020361151742730640016210 0ustar00assertEquals('123', $command->get('test')); $this->assertFalse($command->isPrepared()); $this->assertFalse($command->isExecuted()); } /** * @covers Guzzle\Service\Command\AbstractCommand::getName */ public function testDeterminesShortName() { $api = new ApiCommand(array( 'name' => 'foobar' )); $command = new MockCommand(array(), $api); $this->assertEquals('foobar', $command->getName()); $command = new MockCommand(); $this->assertEquals('mock_command', $command->getName()); $command = new Sub(); $this->assertEquals('sub.sub', $command->getName()); } /** * @covers Guzzle\Service\Command\AbstractCommand::getRequest * @expectedException RuntimeException */ public function testGetRequestThrowsExceptionBeforePreparation() { $command = new MockCommand(); $command->getRequest(); } /** * @covers Guzzle\Service\Command\AbstractCommand::getResponse * @expectedException RuntimeException */ public function testGetResponseThrowsExceptionBeforePreparation() { $command = new MockCommand(); $command->getResponse(); } /** * @covers Guzzle\Service\Command\AbstractCommand::getResult * @expectedException RuntimeException */ public function testGetResultThrowsExceptionBeforePreparation() { $command = new MockCommand(); $command->getResult(); } /** * @covers Guzzle\Service\Command\AbstractCommand::setClient * @covers Guzzle\Service\Command\AbstractCommand::getClient * @covers Guzzle\Service\Command\AbstractCommand::prepare * @covers Guzzle\Service\Command\AbstractCommand::isPrepared */ public function testSetClient() { $command = new MockCommand(); $client = $this->getClient(); $command->setClient($client); $this->assertEquals($client, $command->getClient()); unset($client); unset($command); $command = new MockCommand(); $client = $this->getClient(); $command->setClient($client)->prepare(); $this->assertEquals($client, $command->getClient()); $this->assertTrue($command->isPrepared()); } /** * @covers Guzzle\Service\Command\AbstractCommand::execute * @covers Guzzle\Service\Command\AbstractCommand::setClient * @covers Guzzle\Service\Command\AbstractCommand::getRequest * @covers Guzzle\Service\Command\AbstractCommand::getResponse * @covers Guzzle\Service\Command\AbstractCommand::getResult * @covers Guzzle\Service\Command\AbstractCommand::prepare * @covers Guzzle\Service\Command\AbstractCommand::process * @covers Guzzle\Service\Command\AbstractCommand::prepare * @covers Guzzle\Service\Client::execute */ public function testExecute() { $client = $this->getClient(); $response = new \Guzzle\Http\Message\Response(200, array( 'Content-Type' => 'application/xml' ), '123'); // Set a mock response $client->getEventDispatcher()->addSubscriber(new MockPlugin(array( $response ))); $command = new MockCommand(); $this->assertSame($command, $command->setClient($client)); $this->assertSame($command, $command->execute()); // Implicitly calls prepare $this->assertTrue($command->isPrepared()); $this->assertTrue($command->isExecuted()); $this->assertSame($response, $command->getResponse()); $this->assertInstanceOf('Guzzle\\Http\\Message\\Request', $command->getRequest()); // Make sure that the result was automatically set to a SimpleXMLElement $this->assertInstanceOf('SimpleXMLElement', $command->getResult()); $this->assertEquals('123', (string)$command->getResult()->data); } /** * @covers Guzzle\Service\Command\AbstractCommand::process */ public function testConvertsJsonResponsesToArray() { $client = $this->getClient(); $client->getEventDispatcher()->addSubscriber(new MockPlugin(array( new \Guzzle\Http\Message\Response(200, array( 'Content-Type' => 'application/json' ), '{ "key": "Hi!" }' ) ))); $command = new MockCommand(); $command->setClient($client); $command->execute(); $this->assertEquals(array( 'key' => 'Hi!' ), $command->getResult()); } /** * @covers Guzzle\Service\Command\AbstractCommand::process */ public function testProcessResponseIsNotXml() { $client = $this->getClient(); $client->getEventDispatcher()->addSubscriber(new MockPlugin(array( new Response(200, array( 'Content-Type' => 'application/octect-stream' ), 'abc,def,ghi') ))); $command = new MockCommand(); $client->execute($command); // Make sure that the result was not converted to XML $this->assertFalse($command->getResult() instanceof \SimpleXMLElement); } /** * @covers Guzzle\Service\Command\AbstractCommand::execute * @expectedException RuntimeException */ public function testExecuteThrowsExceptionWhenNoClientIsSet() { $command = new MockCommand(); $command->execute(); } /** * @covers Guzzle\Service\Command\AbstractCommand::prepare * @expectedException RuntimeException */ public function testPrepareThrowsExceptionWhenNoClientIsSet() { $command = new MockCommand(); $command->prepare(); } /** * @covers Guzzle\Service\Command\AbstractCommand::prepare * @covers Guzzle\Service\Command\AbstractCommand::getRequestHeaders */ public function testCommandsAllowsCustomRequestHeaders() { $command = new MockCommand(); $command->getRequestHeaders()->set('test', '123'); $this->assertInstanceOf('Guzzle\Common\Collection', $command->getRequestHeaders()); $this->assertEquals('123', $command->getRequestHeaders()->get('test')); $command->setClient($this->getClient())->prepare(); $this->assertEquals('123', $command->getRequest()->getHeaders()->get('test')); } /** * @covers Guzzle\Service\Command\AbstractCommand::__construct */ public function testCommandsAllowsCustomRequestHeadersAsArray() { $command = new MockCommand(array( 'headers' => array( 'Foo' => 'Bar' ) )); $this->assertInstanceOf('Guzzle\Common\Collection', $command->getRequestHeaders()); $this->assertEquals('Bar', $command->getRequestHeaders()->get('Foo')); } /** * @covers Guzzle\Service\Command\AbstractCommand */ public function testCommandsUsesApiCommand() { $api = new ApiCommand(array( 'name' => 'foobar', 'method' => 'POST', 'class' => 'Guzzle\\Tests\\Service\\Mock\\Command\\MockCommand', 'params' => array( 'test' => array( 'default' => '123', 'type' => 'string' ) ))); $command = new MockCommand(array(), $api); $this->assertSame($api, $command->getApiCommand()); $command->setClient($this->getClient())->prepare(); $this->assertEquals('123', $command->get('test')); $this->assertSame($api, $command->getApiCommand($api)); } }tests/Guzzle/Tests/Service/Command/DynamicCommandTest.php000064400000016624151742730640017524 0ustar00service = new ServiceDescription( array( 'test_command' => new ApiCommand(array( 'doc' => 'documentationForCommand', 'method' => 'HEAD', 'path' => '/{{key}}', 'params' => array( 'bucket' => array( 'required' => true, 'append' => '.', 'location' => 'path' ), 'key' => array( 'location' => 'path', 'prepend' => '/' ), 'acl' => array( 'location' => 'query' ), 'meta' => array( 'location' => 'header:X-Amz-Meta', 'append' => ':meta' ) ) )), 'body' => new ApiCommand(array( 'doc' => 'doc', 'method' => 'PUT', 'params' => array( 'b' => array( 'required' => true, 'prepend' => 'begin_body::', 'append' => '::end_body', 'location' => 'body' ), 'q' => array( 'location' => 'query:test' ), 'h' => array( 'location' => 'header:X-Custom' ), 'i' => array( 'static' => 'test', 'location' => 'query' ), // Data locations means the argument is just a placeholder for data // that can be referenced by other arguments 'data' => array( 'location' => 'data' ) ) )), 'concrete' => new ApiCommand(array( 'class' => 'Guzzle\\Tests\\Service\\Mock\\Command\\MockCommand', 'params' => array() )) ) ); } /** * @covers Guzzle\Service\Command\DynamicCommand * @expectedException InvalidArgumentException */ public function testRequiresApiCommand() { $command = new DynamicCommand(); } /** * @covers Guzzle\Service\Command\DynamicCommand */ public function testBuildsUsingPathParametersAndAppendSlashPrepend() { $client = new Client('http://www.example.com/'); $client->setDescription($this->service); $command = $this->service->createCommand('test_command', array( 'bucket' => 'test', 'key' => 'key' )); $request = $command->setClient($client)->prepare(); // Ensure that the path values were injected into the path and base_url $this->assertEquals('/key', $request->getPath()); $this->assertEquals('www.example.com', $request->getHost()); // Check the complete request $this->assertEquals( "HEAD /key HTTP/1.1\r\n" . "Host: www.example.com\r\n" . "User-Agent: " . Guzzle::getDefaultUserAgent() . "\r\n" . "\r\n", (string) $request); } /** * @covers Guzzle\Service\Command\DynamicCommand * @expectedException InvalidArgumentException */ public function testValidatesArgs() { $client = new Client('http://www.fragilerock.com/'); $client->setDescription($this->service); $command = $this->service->createCommand('test_command', array()); $client->execute($command); } /** * @covers Guzzle\Service\Command\DynamicCommand */ public function testUsesDifferentLocations() { $client = new Client('http://www.tazmania.com/'); $command = $this->service->createCommand('body', array( 'b' => 'my-data', 'q' => 'abc', 'h' => 'haha' )); $request = $command->setClient($client)->prepare(); $this->assertEquals( "PUT /?test=abc&i=test HTTP/1.1\r\n" . "Host: www.tazmania.com\r\n" . "User-Agent: " . Guzzle::getDefaultUserAgent() . "\r\n" . "Expect: 100-Continue\r\n" . "Content-Length: 29\r\n" . "X-Custom: haha\r\n" . "\r\n" . "begin_body::my-data::end_body", (string) $request); unset($command); unset($request); $command = $this->service->createCommand('body', array( 'b' => 'my-data', 'q' => 'abc', 'h' => 'haha', 'i' => 'does not change the value because it\'s static' )); $request = $command->setClient($client)->prepare(); $this->assertEquals( "PUT /?test=abc&i=test HTTP/1.1\r\n" . "Host: www.tazmania.com\r\n" . "User-Agent: " . Guzzle::getDefaultUserAgent() . "\r\n" . "Expect: 100-Continue\r\n" . "Content-Length: 29\r\n" . "X-Custom: haha\r\n" . "\r\n" . "begin_body::my-data::end_body", (string) $request); } /** * @covers Guzzle\Service\Command\DynamicCommand::build */ public function testBuildsConcreteCommands() { $c = $this->service->createCommand('concrete'); $this->assertEquals('Guzzle\\Tests\\Service\\Mock\\Command\\MockCommand', get_class($c)); } /** * @covers Guzzle\Service\Command\DynamicCommand::build */ public function testUsesAbsolutePaths() { $service = new ServiceDescription( array( 'test_path' => new ApiCommand(array( 'method' => 'GET', 'path' => '/test', )) ) ); $client = new Client('http://www.test.com/'); $client->setDescription($service); $command = $client->getCommand('test_path'); $request = $command->prepare(); $this->assertEquals('/test', $request->getPath()); } /** * @covers Guzzle\Service\Command\DynamicCommand::build */ public function testUsesRelativePaths() { $service = new ServiceDescription( array( 'test_path' => new ApiCommand(array( 'method' => 'GET', 'path' => 'test/abc', )) ) ); $client = new Client('http://www.test.com/api/v2'); $client->setDescription($service); $command = $client->getCommand('test_path'); $request = $command->prepare(); $this->assertEquals('/api/v2/test/abc', $request->getPath()); } }tests/Guzzle/Tests/Service/Description/ApiCommandFactoryTest.php000064400000001545151742730640021102 0ustar00 'foo', 'method' => 'GET', 'path' => '/', 'class' => 'Guzzle\\Service\\Command\\DynamicCommand' )); $factory = new ApiCommandFactory(); $command = $factory->createCommand($apiCommand, array( 'param' => 'value' )); $this->assertInstanceOf('Guzzle\\Service\\Command\\DynamicCommand', $command); $this->assertEquals('value', $command->get('param')); } }tests/Guzzle/Tests/Service/Description/ApiCommandTest.php000064400000005667151742730640017563 0ustar00 'test', 'doc' => 'doc', 'method' => 'POST', 'path' => '/api/v1', 'params' => array( 'key' => array( 'required' => 'true', 'type' => 'string', 'max_length' => 10 ), 'key_2' => array( 'required' => 'true', 'type' => 'integer', 'default' => 10 ) ) )); $this->assertEquals('test', $c->getName()); $this->assertEquals('doc', $c->getDoc()); $this->assertEquals('POST', $c->getMethod()); $this->assertEquals('/api/v1', $c->getPath()); $this->assertEquals('Guzzle\\Service\\Command\\DynamicCommand', $c->getConcreteClass()); $this->assertEquals(array( 'key' => new Collection(array( 'required' => 'true', 'type' => 'string', 'max_length' => 10 )), 'key_2' => new Collection(array( 'required' => 'true', 'type' => 'integer', 'default' => 10 )) ), $c->getParams()); $this->assertEquals(new Collection(array( 'required' => 'true', 'type' => 'integer', 'default' => 10 )), $c->getParam('key_2')); $this->assertNull($c->getParam('afefwef')); } /** * @covers Guzzle\Service\Description\ApiCommand::__construct */ public function testAllowsConcreteCommands() { $c = new ApiCommand(array( 'name' => 'test', 'class' => 'Guzzle\\Service\\Command\ClosureCommand', 'params' => array( 'p' => new Collection(array( 'name' => 'foo' )) ) )); $this->assertEquals('Guzzle\\Service\\Command\ClosureCommand', $c->getConcreteClass()); } /** * @covers Guzzle\Service\Description\ApiCommand::getData */ public function testConvertsToArray() { $data = array( 'name' => 'test', 'class' => 'Guzzle\\Service\\Command\ClosureCommand', 'doc' => 'test', 'method' => 'PUT', 'path' => '/', 'params' => array( 'p' => new Collection(array( 'name' => 'foo' )) ) ); $c = new ApiCommand($data); $this->assertEquals($data, $c->getData()); } }tests/Guzzle/Tests/Service/Description/JsonDescriptionBuilderTest.php000064400000001733151742730640022165 0ustar00assertTrue($description->hasCommand('test')); $test = $description->getCommand('test'); $this->assertEquals('/path', $test->getPath()); $test = $description->getCommand('concrete'); $this->assertEquals('/abstract', $test->getPath()); } }tests/Guzzle/Tests/Service/Description/ServiceDescriptionTest.php000064400000011036151742730640021342 0ustar00 array( 'abstract' => array( 'method' => 'GET', 'params' => array( 'test' => array( 'type' => 'string', 'required' => true ) ) ), 'abstract2' => array( 'path' => '/test', 'extends' => 'abstract' ), 'concrete' => array( 'extends' => 'abstract2' ) ) )); $c = $d->getCommand('concrete'); $this->assertEquals('/test', $c->getPath()); $this->assertEquals('GET', $c->getMethod()); $params = $c->getParams(); $param = $params['test']; $this->assertEquals('string', $param['type']); $this->assertTrue($param['required']); } /** * @covers Guzzle\Service\Description\ServiceDescription::factory * @expectedException RuntimeException */ public function testThrowsExceptionWhenExtendingMissingCommand() { ServiceDescription::factory(array( 'commands' => array( 'concrete' => array( 'extends' => 'missing' ) ) )); } /** * @covers Guzzle\Service\Description\ServiceDescription::factory */ public function testRegistersCustomTypes() { ServiceDescription::factory(array( 'types' => array( 'slug' => array( 'class' => 'Symfony\\Component\\Validator\\Constraints\\Regex', 'pattern' => '/[0-9a-zA-z_\-]+/' ) ) )); $regex = Inspector::getInstance()->getConstraint('slug'); $this->assertInstanceOf('Symfony\\Component\\Validator\\Constraints\\Regex', $regex); $this->assertEquals('/[0-9a-zA-z_\-]+/', $regex->pattern); } /** * @covers Guzzle\Service\Description\ServiceDescription::factory * @expectedException RuntimeException * @expectedExceptionMessage Custom types require a class attribute */ public function testCustomTypesRequireClassAttribute() { ServiceDescription::factory(array( 'types' => array( 'slug' => array() ) )); } /** * @covers Guzzle\Service\Description\ServiceDescription * @covers Guzzle\Service\Description\ServiceDescription::__construct * @covers Guzzle\Service\Description\ServiceDescription::getCommands * @covers Guzzle\Service\Description\ServiceDescription::getCommand */ public function testConstructor() { $service = new ServiceDescription(array( 'test_command' => new ApiCommand(array( 'doc' => 'documentationForCommand', 'method' => 'DELETE', 'class' => 'Guzzle\\Tests\\Service\\Mock\\Command\\MockCommand', 'params' => array( 'bucket' => array( 'required' => true ), 'key' => array( 'required' => true ) ) )) )); $this->assertEquals(1, count($service->getCommands())); $this->assertFalse($service->hasCommand('foobar')); $this->assertTrue($service->hasCommand('test_command')); $c = $service->createCommand('test_command', array( 'bucket' => '123', 'key' => 'abc' )); $this->assertInstanceOf('Guzzle\\Tests\\Service\\Mock\\Command\\MockCommand', $c); $this->assertEquals('123', $c->get('bucket')); $this->assertEquals('abc', $c->get('key')); try { $service->createCommand('foobar', array()); $this->fail('Expected exception not thrown'); } catch (\InvalidArgumentException $e) { $this->assertEquals('foobar command not found', $e->getMessage()); } } }tests/Guzzle/Tests/Service/Description/XmlDescriptionBuilderTest.php000064400000005322151742730640022012 0ustar00assertTrue($service->hasCommand('search')); $this->assertTrue($service->hasCommand('test')); $this->assertTrue($service->hasCommand('trends.location')); $this->assertTrue($service->hasCommand('geo.id')); $this->assertInstanceOf('Guzzle\\Service\\Description\\ApiCommand', $service->getCommand('search')); $this->assertInternalType('array', $service->getCommands()); $this->assertEquals(7, count($service->getCommands())); $this->assertInstanceOf('Guzzle\\Common\\NullObject', $service->getCommand('missing')); $command = $service->getCommand('test'); $this->assertInstanceOf('Guzzle\\Service\\Description\\ApiCommand', $command); $this->assertEquals('test', $command->getName()); $this->assertInternalType('array', $command->getParams()); $this->assertEquals(array( 'name' => 'bucket', 'required' => true, 'location' => 'path', 'doc' => 'Bucket location' ), $command->getParam('bucket')->getAll()); $this->assertEquals('DELETE', $command->getMethod()); $this->assertEquals('{{ bucket }}/{{ key }}{{ format }}', $command->getPath()); $this->assertEquals('Documentation', $command->getDoc()); $this->assertArrayHasKey('custom_filter', Inspector::getInstance()->getRegisteredConstraints()); } /** * @covers Guzzle\Service\Description\XmlDescriptionBuilder */ public function testCanExtendOtherFiles() { $service = XmlDescriptionBuilder::build(__DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'TestData' . DIRECTORY_SEPARATOR . 'test_service.xml'); $command = $service->getCommand('concrete'); $this->assertEquals('/test', $command->getPath()); } }tests/Guzzle/Tests/Service/InflectorTest.php000064400000004777151742730640015216 0ustar00assertEquals('camel_case', Inflector::snake('camelCase')); $this->assertEquals('camel_case', Inflector::snake('CamelCase')); $this->assertEquals('camel_case_words', Inflector::snake('CamelCaseWords')); $this->assertEquals('camel_case_words', Inflector::snake('CamelCase_words')); $this->assertEquals('test', Inflector::snake('test')); $this->assertEquals('test', Inflector::snake('test')); $this->assertEquals('expect100_continue', Inflector::snake('Expect100Continue')); } public function testCamel() { $this->assertEquals('CamelCase', Inflector::camel('camel_case')); $this->assertEquals('CamelCaseWords', Inflector::camel('camel_case_words')); $this->assertEquals('Test', Inflector::camel('test')); $this->assertEquals('Expect100Continue', ucfirst(Inflector::camel('expect100_continue'))); // Get from cache $this->assertEquals('Test', Inflector::camel('test', false)); } public function testProtectsAgainstCacheOverflow() { $perCachePurge = Inflector::MAX_ENTRIES_PER_CACHE * 0.1; $cached = Inflector::getCache(); $currentSnake = count($cached['snake']); $currentCamel = count($cached['camel']); unset($cached); // Fill each cache with garbage, then make sure it flushes out cached // entries and maintains a cache cap while (++$currentSnake < Inflector::MAX_ENTRIES_PER_CACHE + 1) { Inflector::snake(uniqid()); } while (++$currentCamel < Inflector::MAX_ENTRIES_PER_CACHE + 1) { Inflector::camel(uniqid()); } $cached = Inflector::getCache(); $this->assertEquals(Inflector::MAX_ENTRIES_PER_CACHE, count($cached['snake'])); $this->assertEquals(Inflector::MAX_ENTRIES_PER_CACHE, count($cached['camel'])); unset($cached); // Add another element to each cache to remove 10% of the cache Inflector::snake(uniqid()); Inflector::camel(uniqid()); $cached = Inflector::getCache(); $this->assertEquals(Inflector::MAX_ENTRIES_PER_CACHE - $perCachePurge + 1, count($cached['snake'])); $this->assertEquals(Inflector::MAX_ENTRIES_PER_CACHE - $perCachePurge + 1, count($cached['camel'])); } }tests/Guzzle/Tests/Service/InspectorTest.php000064400000025132151742730640015223 0ustar00validateClass(__CLASS__, new Collection()); } /** * @cover Guzzle\Service\Inspector::__constructor */ public function testRegistersDefaultFilters() { $inspector = new Inspector(); $this->assertNotEmpty($inspector->getRegisteredConstraints()); } /** * @covers Guzzle\Service\Inspector::getValidator */ public function testCreatesDefaultValidator() { $inspector = new Inspector(); $this->assertInstanceOf('Symfony\Component\Validator\Validator', $inspector->getValidator()); } /** * @covers Guzzle\Service\Inspector::setValidator */ public function testAllowsValidatorInjection() { $inspector = new Inspector(); $default = $inspector->getValidator(); $validator = new Validator(new ClassMetadataFactory(new StaticMethodLoader()), new ConstraintValidatorFactory()); $inspector->setValidator($validator); $this->assertSame($validator, $inspector->getValidator()); $this->assertNotSame($default, $inspector->getValidator()); } /** * @covers Guzzle\Service\Inspector::prepareConfig */ public function testPreparesConfig() { $c = Inspector::prepareConfig(array( 'a' => '123', 'base_url' => 'http://www.test.com/' ), array( 'a' => 'xyz', 'b' => 'lol' ), array('a')); $this->assertInstanceOf('Guzzle\Common\Collection', $c); $this->assertEquals(array( 'a' => '123', 'b' => 'lol', 'base_url' => 'http://www.test.com/' ), $c->getAll()); try { $c = Inspector::prepareConfig(null, null, array('a')); $this->fail('Exception not throw when missing config'); } catch (\InvalidArgumentException $e) { } } /** * @covers Guzzle\Service\Inspector */ public function testAddsDefaultAndInjectsConfigs() { $col = new Collection(array( 'username' => 'user', 'string' => 'test', 'float' => 1.23 )); Inspector::getInstance()->validateClass(__CLASS__, $col); $this->assertEquals(false, $col->get('bool_2')); $this->assertEquals('user_test_', $col->get('dynamic')); $this->assertEquals(1.23, $col->get('float')); } /** * @covers Guzzle\Service\Inspector::validateClass * @expectedException InvalidArgumentException */ public function testValidatesTypeHints() { Inspector::getInstance()->validateClass(__CLASS__, new Collection(array( 'test' => 'uh oh', 'username' => 'test' ))); } /** * @covers Guzzle\Service\Inspector::validateClass * @covers Guzzle\Service\Inspector::validateConfig */ public function testConvertsBooleanDefaults() { $c = new Collection(array( 'test' => $this, 'username' => 'test' )); Inspector::getInstance()->validateClass(__CLASS__, $c); $this->assertTrue($c->get('bool_1')); $this->assertFalse($c->get('bool_2')); } /** * @covers Guzzle\Service\Inspector */ public function testInspectsClassArgs() { $doc = <<parseDocBlock($doc); $this->assertEquals(array( 'required' => 'true', 'doc' => 'API username', 'type' => 'string' ), $params['username']); $this->assertEquals(array( 'required' => 'true', 'default' => 'v1', 'doc' => 'API version', 'type' => "choice:'v1','v2',v3" ), $params['api_version']); $this->assertEquals(array( 'required' => 'true', 'default' => 'https', 'doc' => 'HTTP protocol (http or https)', 'type' => 'string' ), $params['protocol']); $this->assertEquals(array( 'required' => 'true', 'default' => '{{ protocol }}://{{ subdomain }}.unfuddle.com/api/{{ api_version }}/', 'doc' => 'Unfuddle API base URL', 'type' => 'string' ), $params['base_url']); $this->assertEquals(array( 'type' => "type:object" ), $params['class']); $config = new Collection(array( 'username' => 'test', 'password' => 'pass', 'subdomain' => 'sub', 'api_version' => 'v2' )); Inspector::getInstance()->validateConfig($params, $config); // make sure the configs were injected $this->assertEquals('https://sub.unfuddle.com/api/v2/', $config->get('base_url')); try { Inspector::getInstance()->validateConfig($params, new Collection(array( 'base_url' => '', 'username' => '', 'password' => '', 'class' => '123', 'api_version' => 'v10' ))); $this->fail('Expected exception not thrown when params are invalid'); } catch (\InvalidArgumentException $e) { $this->assertEquals("Validation errors: Requires that the username argument be supplied. (API username). Requires that the password argument be supplied. (API password). Requires that the subdomain argument be supplied. (Unfuddle project subdomain). The value you selected is not a valid choice This value should be of type object", $e->getMessage()); } } /** * @covers Guzzle\Service\Inspector::registerConstraint * @covers Guzzle\Service\Inspector::getConstraint * @covers Guzzle\Service\Inspector::getRegisteredConstraints */ public function testRegistersCustomConstraints() { $constraintClass = 'Symfony\\Component\\Validator\\Constraints\\Ip'; Inspector::getInstance()->registerConstraint('mock', $constraintClass); Inspector::getInstance()->registerConstraint('mock_2', $constraintClass, array( 'version' => '4' )); $this->assertArrayHasKey('mock', Inspector::getInstance()->getRegisteredConstraints()); $this->assertArrayHasKey('mock_2', Inspector::getInstance()->getRegisteredConstraints()); $this->assertInstanceOf($constraintClass, Inspector::getInstance()->getConstraint('mock')); $this->assertInstanceOf($constraintClass, Inspector::getInstance()->getConstraint('mock_2')); $this->assertEquals('4', Inspector::getInstance()->getConstraint('mock_2')->version); $validating = new Collection(array( 'data' => '192.168.16.121', 'test' => '10.1.1.0' )); $this->assertTrue(Inspector::getInstance()->validateConfig(array( 'data' => array( 'type' => 'mock' ), 'test' => array( 'type' => 'mock_2' ) ), $validating, false)); } /** * @covers Guzzle\Service\Inspector * @expectedException InvalidArgumentException */ public function testChecksFilterValidity() { Inspector::getInstance()->validateConfig(array( 'data' => array( 'type' => 'invalid' ) ), new Collection(array( 'data' => 'false' ))); } /** * @covers Guzzle\Service\Inspector */ public function testValidatesArgs() { $config = new Collection(array( 'data' => 123, 'min' => 'a', 'max' => 'aaa' )); $result = Inspector::getInstance()->validateConfig(array( 'data' => array( 'type' => 'string' ), 'min' => array( 'type' => 'string', 'min_length' => 2 ), 'max' => array( 'type' => 'string', 'max_length' => 2 ) ), $config, false); $this->assertEquals("This value should be of type string Requires that the min argument be >= 2 characters. Requires that the max argument be <= 2 characters.", implode("\n", $result)); } /** * @covers Guzzle\Service\Inspector::parseDocBlock */ public function testVerifiesGuzzleAnnotations() { $this->assertEquals( array(), Inspector::getInstance()->parseDocBlock('testing') ); } /** * @covers Guzzle\Service\Inspector::validateConfig */ public function testRunsValuesThroughFilters() { $data = new Collection(array( 'username' => 'TEST', 'test_function' => 'foo' )); Inspector::getInstance()->validateClass(__CLASS__, $data); $this->assertEquals('test', $data->get('username')); $this->assertEquals('FOO', $data->get('test_function')); } }tests/Guzzle/Tests/Service/Mock/Command/MockCommand.php000064400000000624151742730640017053 0ustar00request = $this->client->createRequest(); } }tests/Guzzle/Tests/Service/Mock/Command/OtherCommand.php000064400000000644151742730640017245 0ustar00request = $this->client->getRequest('HEAD'); } }tests/Guzzle/Tests/Service/Mock/Command/Sub/Sub.php000064400000000254151742730640016144 0ustar00 '{{scheme}}://127.0.0.1:8124/{{api_version}}/{{subdomain}}', 'scheme' => 'http', 'api_version' => 'v1' ), array('username', 'password', 'subdomain')); return new self($config->get('base_url'), $config); } }tests/Guzzle/Tests/Service/Mock/MockInflector.php000064400000000574151742730640016050 0ustar00client->createRequest(); $request->getQuery()->set('count', $this->calculatePageSize()); $data = json_decode($request->send()->getBody(true), true); $this->resourceList = $data['resources']; $this->nextToken = $data['next_token']; $this->retrievedCount += count($this->data['resources']); $this->currentIndex = 0; } }tests/Guzzle/Tests/Service/ResourceIteratorApplyBatchedTest.php000064400000004402151742730640021034 0ustar00assertInternalType('array', ResourceIteratorApplyBatched::getAllEvents()); } /** * @covers Guzzle\Service\ResourceIteratorApplyBatched */ public function testSendsRequestsForNextSetOfResources() { $this->getServer()->flush(); $this->getServer()->enqueue(array( "HTTP/1.1 200 OK\r\nContent-Length: 52\r\n\r\n{ \"next_token\": \"g\", \"resources\": [\"d\", \"e\", \"f\"] }", "HTTP/1.1 200 OK\r\nContent-Length: 52\r\n\r\n{ \"next_token\": \"j\", \"resources\": [\"g\", \"h\", \"i\"] }", "HTTP/1.1 200 OK\r\nContent-Length: 41\r\n\r\n{ \"next_token\": \"\", \"resources\": [\"j\"] }", )); $ri = new MockResourceIterator($this->getServiceBuilder()->get('mock'), array( 'page_size' => 3, 'resources' => array('a', 'b', 'c'), 'next_token' => 'd' )); $received = array(); $apply = new ResourceIteratorApplyBatched($ri, function(ResourceIterator $i, array $batch) use (&$received) { $received[] = $batch; }); $apply->apply(3); $requests = $this->getServer()->getReceivedRequests(true); $this->assertEquals(3, count($requests)); $this->assertEquals(3, $requests[0]->getQuery()->get('count')); $this->assertEquals(3, $requests[1]->getQuery()->get('count')); $this->assertEquals(3, $requests[2]->getQuery()->get('count')); $this->assertEquals(array('a', 'b', 'c'), array_values($received[0])); $this->assertEquals(array('d', 'e', 'f'), array_values($received[1])); $this->assertEquals(array('g', 'h', 'i'), array_values($received[2])); $this->assertEquals(array('j'), array_values($received[3])); $this->assertEquals(4, $apply->getBatchCount()); $this->assertEquals(10, $apply->getIteratedCount()); } }tests/Guzzle/Tests/Service/ResourceIteratorTest.php000064400000011243151742730640016554 0ustar00assertInternalType('array', ResourceIterator::getAllEvents()); } /** * @covers Guzzle\Service\ResourceIterator */ public function testConstructorConfiguresDefaults() { $ri = $this->getMockForAbstractClass('Guzzle\\Service\\ResourceIterator', array( $this->getServiceBuilder()->get('mock'), array( 'limit' => 10, 'page_size' => 3, 'resources' => array('a', 'b', 'c'), 'next_token' => 'd' ) ), 'MockIterator'); $this->assertEquals('d', $ri->getNextToken()); $this->assertEquals(array('a', 'b', 'c'), $ri->toArray()); $ri->rewind(); $this->assertEquals('a', $ri->current()); $ri->next(); $this->assertEquals('b', $ri->current()); $ri->next(); $this->assertEquals('c', $ri->current()); // It ran out $ri->next(); $this->assertEquals('', $ri->current()); $this->assertEquals(3, count($ri)); $this->assertEquals(3, $ri->getPosition()); // Rewind works? $ri->rewind(); $this->assertEquals('a', $ri->current()); $ri->next(); $this->assertEquals('b', $ri->current()); $ri->next(); $this->assertEquals('c', $ri->current()); } /** * @covers Guzzle\Service\ResourceIterator */ public function testSendsRequestsForNextSetOfResources() { $this->getServer()->flush(); $this->getServer()->enqueue(array( "HTTP/1.1 200 OK\r\nContent-Length: 52\r\n\r\n{ \"next_token\": \"g\", \"resources\": [\"d\", \"e\", \"f\"] }", "HTTP/1.1 200 OK\r\nContent-Length: 52\r\n\r\n{ \"next_token\": \"j\", \"resources\": [\"g\", \"h\", \"i\"] }", "HTTP/1.1 200 OK\r\nContent-Length: 41\r\n\r\n{ \"next_token\": \"\", \"resources\": [\"j\"] }", )); $ri = new MockResourceIterator($this->getServiceBuilder()->get('mock'), array( 'page_size' => 3, 'resources' => array('a', 'b', 'c'), 'next_token' => 'd' )); $this->assertEquals(array('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'), $ri->toArray()); $requests = $this->getServer()->getReceivedRequests(true); $this->assertEquals(3, count($requests)); $this->assertEquals(3, $requests[0]->getQuery()->get('count')); $this->assertEquals(3, $requests[1]->getQuery()->get('count')); $this->assertEquals(3, $requests[2]->getQuery()->get('count')); // Reset and resend $this->getServer()->flush(); $this->getServer()->enqueue(array( "HTTP/1.1 200 OK\r\nContent-Length: 52\r\n\r\n{ \"next_token\": \"g\", \"resources\": [\"d\", \"e\", \"f\"] }", "HTTP/1.1 200 OK\r\nContent-Length: 52\r\n\r\n{ \"next_token\": \"j\", \"resources\": [\"g\", \"h\", \"i\"] }", "HTTP/1.1 200 OK\r\nContent-Length: 41\r\n\r\n{ \"next_token\": \"\", \"resources\": [\"j\"] }", )); $d = array(); reset($ri); foreach ($ri as $data) { $d[] = $data; } $this->assertEquals(array('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'), $d); } /** * @covers Guzzle\Service\ResourceIterator */ public function testCalculatesPageSize() { $this->getServer()->flush(); $this->getServer()->enqueue(array( "HTTP/1.1 200 OK\r\nContent-Length: 52\r\n\r\n{ \"next_token\": \"g\", \"resources\": [\"d\", \"e\", \"f\"] }", "HTTP/1.1 200 OK\r\nContent-Length: 52\r\n\r\n{ \"next_token\": \"j\", \"resources\": [\"g\", \"h\", \"i\"] }", "HTTP/1.1 200 OK\r\nContent-Length: 52\r\n\r\n{ \"next_token\": \"j\", \"resources\": [\"g\", \"h\"] }" )); $ri = new MockResourceIterator($this->getServiceBuilder()->get('mock'), array( 'page_size' => 3, 'limit' => 8, 'resources' => array('a', 'b', 'c'), 'next_token' => 'd' )); $this->assertEquals(array('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'), $ri->toArray()); $requests = $this->getServer()->getReceivedRequests(true); $this->assertEquals(2, count($requests)); $this->assertEquals(3, $requests[0]->getQuery()->get('count')); $this->assertEquals(2, $requests[1]->getQuery()->get('count')); } }tests/Guzzle/Tests/Service/ServiceBuilderTest.php000064400000026430151742730640016166 0ustar00 array( 'class' => 'Guzzle\\Tests\\Service\\Mock\\MockClient', 'params' => array( 'username' => 'michael', 'password' => 'testing123', 'subdomain' => 'michael', ), ), 'billy.mock' => array( 'class' => 'Guzzle\\Tests\\Service\\Mock\\MockClient', 'params' => array( 'username' => 'billy', 'password' => 'passw0rd', 'subdomain' => 'billy', ), ), 'billy.testing' => array( 'extends' => 'billy.mock', 'params' => array( 'subdomain' => 'test.billy', ), ), 'missing_params' => array( 'extends' => 'billy.mock' ) ); public function __construct() { $this->xmlConfig = << EOT; $this->tempFile = tempnam('/tmp', 'config.xml'); file_put_contents($this->tempFile, $this->xmlConfig); } public function __destruct() { if (is_file($this->tempFile)) { unlink($this->tempFile); } } /** * @covers Guzzle\Service\ServiceBuilder::__sleep */ public function testAllowsSerialization() { $builder = ServiceBuilder::factory($this->tempFile, 'xml'); $cached = unserialize(serialize($builder)); $this->assertEquals($cached, $builder); } /** * @covers Guzzle\Service\ServiceBuilder::factory */ public function testCanBeCreatedUsingAnXmlFile() { $builder = ServiceBuilder::factory($this->tempFile, 'xml'); $c = $builder->get('michael.mock'); $this->assertInstanceOf('Guzzle\\Tests\\Service\\Mock\\MockClient', $c); } /** * @covers Guzzle\Service\ServiceBuilder::factory * @expectedException RuntimeException * @expectedExceptionMessage Unable to open foobarfile */ public function testFactoryEnsuresItCanOpenFile() { ServiceBuilder::factory('foobarfile'); } /** * @covers Guzzle\Service\ServiceBuilder::factory */ public function testFactoryCanBuildServicesThatExtendOtherServices() { $s = ServiceBuilder::factory($this->tempFile, 'xml'); $s = $s->get('billy.testing'); $this->assertEquals('test.billy', $s->getConfig('subdomain')); $this->assertEquals('billy', $s->getConfig('username')); } /** * @covers Guzzle\Service\ServiceBuilder::factory */ public function testFactoryThrowsExceptionWhenBuilderExtendsNonExistentBuilder() { $xml = '' . "\n" . ''; $tempFile = tempnam('/tmp', 'config.xml'); file_put_contents($tempFile, $xml); try { ServiceBuilder::factory($tempFile, 'xml'); unlink($tempFile); $this->fail('Test did not throw ServiceException'); } catch (\LogicException $e) { $this->assertEquals('invalid is trying to extend a non-existent service: missing', $e->getMessage()); } unlink($tempFile); } /** * @covers Guzzle\Service\ServiceBuilder::get * @expectedException InvalidArgumentException * @expectedExceptionMessage No client is registered as foobar */ public function testThrowsExceptionWhenGettingInvalidClient() { ServiceBuilder::factory($this->tempFile, 'xml')->get('foobar'); } /** * @covers Guzzle\Service\ServiceBuilder::get */ public function testStoresClientCopy() { $builder = ServiceBuilder::factory($this->tempFile, 'xml'); $client = $builder->get('michael.mock'); $this->assertInstanceOf('Guzzle\\Tests\\Service\\Mock\\MockClient', $client); $this->assertEquals('http://127.0.0.1:8124/v1/michael', $client->getBaseUrl()); $this->assertEquals($client, $builder->get('michael.mock')); // Get another client but throw this one away $client2 = $builder->get('billy.mock', true); $this->assertInstanceOf('Guzzle\\Tests\\Service\\Mock\\MockClient', $client2); $this->assertEquals('http://127.0.0.1:8124/v1/billy', $client2->getBaseUrl()); // Make sure the original client is still there and set $this->assertTrue($client === $builder->get('michael.mock')); // Create a new billy.mock client that is stored $client3 = $builder->get('billy.mock'); // Make sure that the stored billy.mock client is equal to the other stored client $this->assertTrue($client3 === $builder->get('billy.mock')); // Make sure that this client is not equal to the previous throwaway client $this->assertFalse($client2 === $builder->get('billy.mock')); } /** * @covers Guzzle\Service\ServiceBuilder */ public function testBuildersPassOptionsThroughToClients() { $s = new ServiceBuilder(array( 'michael.mock' => array( 'class' => 'Guzzle\\Tests\\Service\\Mock\\MockClient', 'params' => array( 'base_url' => 'http://www.test.com/', 'subdomain' => 'michael', 'password' => 'test', 'username' => 'michael', 'curl.curlopt_proxyport' => 8080 ) ) )); $c = $s->get('michael.mock'); $this->assertEquals(8080, $c->getConfig('curl.curlopt_proxyport')); } /** * @covers Guzzle\Service\ServiceBuilder */ public function testUsesTheDefaultBuilderWhenNoBuilderIsSpecified() { $s = new ServiceBuilder(array( 'michael.mock' => array( 'class' => 'Guzzle\\Tests\\Service\\Mock\\MockClient', 'params' => array( 'base_url' => 'http://www.test.com/', 'subdomain' => 'michael', 'password' => 'test', 'username' => 'michael', 'curl.curlopt_proxyport' => 8080 ) ) )); $c = $s->get('michael.mock'); $this->assertInstanceOf('Guzzle\\Tests\\Service\\Mock\\MockClient', $c); } /** * @covers Guzzle\Service\ServiceBuilder::offsetSet * @covers Guzzle\Service\ServiceBuilder::offsetGet * @covers Guzzle\Service\ServiceBuilder::offsetUnset * @covers Guzzle\Service\ServiceBuilder::offsetExists */ public function testUsedAsArray() { $b = ServiceBuilder::factory($this->tempFile, 'xml'); $this->assertTrue($b->offsetExists('michael.mock')); $this->assertFalse($b->offsetExists('not_there')); $this->assertInstanceOf('Guzzle\\Service\\Client', $b['michael.mock']); unset($b['michael.mock']); $this->assertFalse($b->offsetExists('michael.mock')); $b['michael.mock'] = new Client('http://www.test.com/'); $this->assertInstanceOf('Guzzle\\Service\\Client', $b['michael.mock']); } /** * @covers Guzzle\Service\ServiceBuilder::factory */ public function testFactoryCanCreateFromXml() { $b = ServiceBuilder::factory(new \SimpleXMLElement($this->xmlConfig)); $this->assertTrue($b->offsetExists('michael.mock')); $this->assertTrue($b->offsetExists('billy.mock')); $this->assertTrue($b->offsetExists('billy.testing')); } /** * @covers Guzzle\Service\ServiceBuilder::factory */ public function testFactoryCanCreateFromJson() { $tmp = sys_get_temp_dir() . '/test.js'; file_put_contents($tmp, json_encode($this->arrayData)); $b = ServiceBuilder::factory($tmp); unlink($tmp); $s = $b->get('billy.testing'); $this->assertEquals('test.billy', $s->getConfig('subdomain')); $this->assertEquals('billy', $s->getConfig('username')); } /** * @covers Guzzle\Service\ServiceBuilder::factory */ public function testFactoryCanCreateFromArray() { $b = ServiceBuilder::factory($this->arrayData); $s = $b->get('billy.testing'); $this->assertEquals('test.billy', $s->getConfig('subdomain')); $this->assertEquals('billy', $s->getConfig('username')); } /** * @covers Guzzle\Service\ServiceBuilder::factory * @expectedException RuntimeException * @expectedExceptionMessage Unknown file type abc */ public function testFactoryValidatesFileExtension() { $tmp = sys_get_temp_dir() . '/test.abc'; file_put_contents($tmp, 'data'); try { ServiceBuilder::factory($tmp); } catch (\RuntimeException $e) { unlink($tmp); throw $e; } } /** * @covers Guzzle\Service\ServiceBuilder::factory * @expectedException InvalidArgumentException * @expectedExceptionMessage Must pass a file name, array, or SimpleXMLElement */ public function testFactoryValidatesObjectTypes() { ServiceBuilder::factory(new \stdClass()); } /** * @covers Guzzle\Service\ServiceBuilder::factory */ public function testFactoryDoesNotRequireParams() { $b = ServiceBuilder::factory($this->arrayData); $s = $b->get('missing_params'); $this->assertEquals('billy', $s->getConfig('username')); } /** * @covers Guzzle\Service\ServiceBuilder */ public function testBuilderAllowsReferencesBetweenClients() { $builder = ServiceBuilder::factory(array( 'a' => array( 'class' => 'Guzzle\\Tests\\Service\\Mock\\MockClient', 'params' => array( 'other_client' => '{{ b }}', 'username' => 'x', 'password' => 'y', 'subdomain' => 'z' ) ), 'b' => array( 'class' => 'Guzzle\\Tests\\Service\\Mock\\MockClient', 'params' => array( 'username' => '1', 'password' => '2', 'subdomain' => '3' ) ) )); $client = $builder['a']; $this->assertEquals('x', $client->getConfig('username')); $this->assertSame($builder['b'], $client->getConfig('other_client')); $this->assertEquals('1', $builder['b']->getConfig('username')); } }tests/Guzzle/Tests/TestData/FileBody.txt000075500000000000151742730640014241 0ustar00tests/Guzzle/Tests/TestData/mock_response000064400000000043151742730640014601 0ustar00HTTP/1.1 200 OK Content-Length: 0 tests/Guzzle/Tests/TestData/services.xml000064400000003352151742730640014362 0ustar00 tests/Guzzle/Tests/TestData/test.tar.gz000064400000000002151742730640014110 0ustar00tests/Guzzle/Tests/TestData/test.tar.gz.cpgz000064400000000200151742730640015052 0ustar00‹307Ad`b`nj ¤ÍÍ@¤�‘ XÔ"ihhjll`j ¤Á|#$�z 覘™˜`˜fˆl𱑠ØBC3„N#=ý’Ôâ½’Ä"½ô*fL³‘­F†ØE�‘8!AŽž>®AŠŠŠ #íb«§tests/Guzzle/Tests/TestData/test_service.json000064400000000321151742730640015400 0ustar00{ "includes": [ "test_service2.json" ], "types": {}, "commands": { "test": { "path": "/path" }, "concrete": { "extends": "abstract" } } }tests/Guzzle/Tests/TestData/test_service.xml000064400000004755151742730640015246 0ustar00 Documentation tests/Guzzle/Tests/TestData/test_service2.json000064400000000133151742730640015463 0ustar00{ "commands": { "abstract": { "path": "/abstract" } } }tests/Guzzle/Tests/TestData/test_service2.xml000064400000000226151742730640015315 0ustar00 tests/bootstrap.php000064400000001655151742730640010454 0ustar00