Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Breaking / Potentially breaking changes:

    1. Adopting a marker interface for Guzzle exceptions.
        A. All exceptions emitted from Guzzle are now wrapped with a Guzzle namespaced exception.
        B. Guzzle\Common\GuzzleExceptionInterface was renamed to Guzzle\Common\GuzzleException
        C. Guzzle\Common\ExceptionCollection was renamed to Guzzle\Common\Exception\ExceptionCollection
    2. Using Header objects for Request and Response objects
        A. When you call $request->getHeader('X'), you will get back a Guzzle\Http\Message\Header object that contains all of the headers that case insensitively match.  This object can be cast to a string or iterated like an array.  You can pass true in the second argument to retrieve the header as a string.
        B. Removing the old Guzzle\Common\Collection based searching arguments from most of the request and response header methods.  All retrievals are case-insensitive and return Header objects.
    3. Changing the two headers added by the cache plugin to just one header with key and ttl.
    4. Changing Guzzle\Http\Message\Response::factory() to fromMessage().
    5. Removing the NullObject return value from ServiceDescriptions and instead simply returning null

New Features / enhancements:

    1. Adding Guzzle\Http\Message\AbstractMessage::addHeaders()
    2. Making it simpler to create service descriptions using a unified factory method that delegates to other factories.
    3. Better handling of ports and hosts in Guzzle\Http\Url

Note: This is a noisy diff because I'm removing trailing whitespace and adding a new line at the end of each source file.
  • Loading branch information...
commit c0dc85de35725eeefe600f9ff24a1001863b2cfc 1 parent cbf125f
@mtdowling mtdowling authored
Showing with 1,528 additions and 916 deletions.
  1. +1 −1  LICENSE
  2. +1 −1  README.md
  3. +1 −1  build.xml
  4. +1 −1  phar-stub-min.php
  5. +1 −1  phar-stub.php
  6. +11 −0 phpunit.xml.dist
  7. +1 −1  src/Guzzle/Common/AbstractHasDispatcher.php
  8. +1 −1  src/Guzzle/Common/Cache/AbstractCacheAdapter.php
  9. +15 −8 src/Guzzle/Common/Cache/CacheAdapterFactory.php
  10. +1 −1  src/Guzzle/Common/Cache/CacheAdapterInterface.php
  11. +4 −2 src/Guzzle/Common/Cache/ClosureCacheAdapter.php
  12. +1 −1  src/Guzzle/Common/Cache/DoctrineCacheAdapter.php
  13. +1 −1  src/Guzzle/Common/Cache/Zf1CacheAdapter.php
  14. +1 −1  src/Guzzle/Common/Cache/Zf2CacheAdapter.php
  15. +1 −1  src/Guzzle/Common/Collection.php
  16. +1 −1  src/Guzzle/Common/Event.php
  17. +7 −0 src/Guzzle/Common/Exception/BadMethodCallException.php
  18. +5 −3 src/Guzzle/Common/{ → Exception}/ExceptionCollection.php
  19. +7 −0 src/Guzzle/Common/Exception/InvalidArgumentException.php
  20. +7 −0 src/Guzzle/Common/Exception/RuntimeException.php
  21. +7 −0 src/Guzzle/Common/Exception/UnexpectedValueException.php
  22. +1 −3 src/Guzzle/Common/{GuzzleExceptionInterface.php → GuzzleException.php}
  23. +8 −8 src/Guzzle/Common/HasDispatcherInterface.php
  24. +1 −1  src/Guzzle/Common/Log/AbstractLogAdapter.php
  25. +4 −2 src/Guzzle/Common/Log/ClosureLogAdapter.php
  26. +1 −1  src/Guzzle/Common/Log/LogAdapterInterface.php
  27. +1 −1  src/Guzzle/Common/Log/MonologLogAdapter.php
  28. +1 −1  src/Guzzle/Common/Log/Zf1LogAdapter.php
  29. +1 −1  src/Guzzle/Common/Log/Zf2LogAdapter.php
  30. +1 −1  src/Guzzle/Common/NullObject.php
  31. +4 −2 src/Guzzle/Common/Stream.php
  32. +1 −1  src/Guzzle/Common/XmlElement.php
  33. +1 −1  src/Guzzle/Guzzle.php
  34. +7 −6 src/Guzzle/Http/Client.php
  35. +1 −1  src/Guzzle/Http/ClientInterface.php
  36. +1 −1  src/Guzzle/Http/Cookie.php
  37. +4 −3 src/Guzzle/Http/CookieJar/ArrayCookieJar.php
  38. +1 −1  src/Guzzle/Http/CookieJar/CookieJarInterface.php
  39. +1 −1  src/Guzzle/Http/CookieJar/FileCookieJar.php
  40. +11 −12 src/Guzzle/Http/Curl/CurlHandle.php
  41. +10 −9 src/Guzzle/Http/Curl/CurlMulti.php
  42. +2 −2 src/Guzzle/Http/Curl/CurlMultiInterface.php
  43. +4 −3 src/Guzzle/Http/EntityBody.php
  44. +4 −2 src/Guzzle/Http/{Message → Exception}/BadResponseException.php
  45. +2 −4 src/Guzzle/Http/{Curl → Exception}/CurlException.php
  46. +5 −3 src/Guzzle/Http/{Message → Exception}/RequestException.php
  47. +4 −4 src/Guzzle/Http/HttpException.php
  48. +159 −114 src/Guzzle/Http/Message/AbstractMessage.php
  49. +3 −2 src/Guzzle/Http/Message/EntityEnclosingRequest.php
  50. +2 −2 src/Guzzle/Http/Message/EntityEnclosingRequestInterface.php
  51. +207 −0 src/Guzzle/Http/Message/Header.php
  52. +33 −34 src/Guzzle/Http/Message/MessageInterface.php
  53. +41 −47 src/Guzzle/Http/Message/Request.php
  54. +7 −14 src/Guzzle/Http/Message/RequestFactory.php
  55. +1 −1  src/Guzzle/Http/Message/RequestFactoryInterface.php
  56. +1 −1  src/Guzzle/Http/Message/RequestInterface.php
  57. +66 −69 src/Guzzle/Http/Message/Response.php
  58. +1 −1  src/Guzzle/Http/Plugin/BatchQueuePlugin.php
  59. +11 −5 src/Guzzle/Http/Plugin/CachePlugin.php
  60. +2 −2 src/Guzzle/Http/Plugin/CookiePlugin.php
  61. +2 −2 src/Guzzle/Http/Plugin/CurlAuthPlugin.php
  62. +1 −1  src/Guzzle/Http/Plugin/ExponentialBackoffPlugin.php
  63. +1 −1  src/Guzzle/Http/Plugin/HistoryPlugin.php
  64. +1 −1  src/Guzzle/Http/Plugin/LogPlugin.php
  65. +3 −2 src/Guzzle/Http/Plugin/Md5ValidatorPlugin.php
  66. +5 −4 src/Guzzle/Http/Plugin/MockPlugin.php
  67. +1 −1  src/Guzzle/Http/Plugin/OauthPlugin.php
  68. +3 −3 src/Guzzle/Http/QueryString.php
  69. +1 −1  src/Guzzle/Http/UriTemplate.php
  70. +8 −2 src/Guzzle/Http/Url.php
  71. +11 −8 src/Guzzle/Service/Client.php
  72. +4 −3 src/Guzzle/Service/ClientInterface.php
  73. +13 −12 src/Guzzle/Service/Command/AbstractCommand.php
  74. +5 −3 src/Guzzle/Service/Command/ClosureCommand.php
  75. +7 −6 src/Guzzle/Service/Command/CommandInterface.php
  76. +2 −1  src/Guzzle/Service/Command/CommandSet.php
  77. +3 −2 src/Guzzle/Service/Command/DynamicCommand.php
  78. +3 −2 src/Guzzle/Service/Command/Factory/AliasFactory.php
  79. +1 −1  src/Guzzle/Service/Command/Factory/CompositeFactory.php
  80. +1 −1  src/Guzzle/Service/Command/Factory/ConcreteClassFactory.php
  81. +1 −1  src/Guzzle/Service/Command/Factory/FactoryInterface.php
  82. +1 −1  src/Guzzle/Service/Command/Factory/MapFactory.php
  83. +1 −1  src/Guzzle/Service/Command/Factory/ServiceDescriptionFactory.php
  84. +1 −1  src/Guzzle/Service/Description/ApiCommand.php
  85. +54 −0 src/Guzzle/Service/Description/ArrayDescriptionBuilder.php
  86. +1 −1  src/Guzzle/Service/Description/DescriptionBuilderInterface.php
  87. +4 −2 src/Guzzle/Service/Description/JsonDescriptionBuilder.php
  88. +16 −43 src/Guzzle/Service/Description/ServiceDescription.php
  89. +6 −2 src/Guzzle/Service/Description/XmlDescriptionBuilder.php
  90. +5 −0 src/Guzzle/Service/Exception/ClientNotFoundException.php
  91. +7 −0 src/Guzzle/Service/Exception/CommandException.php
  92. +2 −2 src/Guzzle/Service/{Command → Exception}/CommandSetException.php
  93. +7 −0 src/Guzzle/Service/Exception/DescriptionBuilderException.php
  94. +7 −0 src/Guzzle/Service/Exception/ServiceBuilderException.php
  95. +5 −0 src/Guzzle/Service/Exception/ServiceNotFoundException.php
  96. +7 −0 src/Guzzle/Service/Exception/ValidationException.php
  97. +1 −1  src/Guzzle/Service/Inflector.php
  98. +9 −7 src/Guzzle/Service/Inspector.php
  99. +1 −1  src/Guzzle/Service/ResourceIterator.php
  100. +1 −1  src/Guzzle/Service/ResourceIteratorApplyBatched.php
  101. +13 −9 src/Guzzle/Service/ServiceBuilder.php
  102. +1 −1  tests/Guzzle/Tests/Common/AbstractHasDispatcherTest.php
  103. +13 −1 tests/Guzzle/Tests/Common/Cache/CacheAdapterFactoryTest.php
  104. +1 −1  tests/Guzzle/Tests/Common/Cache/CacheAdapterTest.php
  105. +1 −1  tests/Guzzle/Tests/Common/Cache/ClosureCacheAdapterTest.php
  106. +1 −1  tests/Guzzle/Tests/Common/Cache/Zf1CacheAdapterTest.php
  107. +1 −1  tests/Guzzle/Tests/Common/Cache/Zf2CacheAdapterTest.php
  108. +3 −3 tests/Guzzle/Tests/Common/CollectionTest.php
  109. +1 −1  tests/Guzzle/Tests/Common/EventTest.php
  110. +3 −3 tests/Guzzle/Tests/Common/{ → Exception}/ExceptionCollectionTest.php
  111. +1 −1  tests/Guzzle/Tests/Common/Log/ClosureLogAdapterTest.php
  112. +1 −1  tests/Guzzle/Tests/Common/Log/MonologLogAdapterTest.php
  113. +1 −1  tests/Guzzle/Tests/Common/Log/Zf1LogAdapterTest.php
  114. +1 −1  tests/Guzzle/Tests/Common/Log/Zf2LogAdapterTest.php
  115. +1 −1  tests/Guzzle/Tests/Common/NullObjectTest.php
  116. +1 −1  tests/Guzzle/Tests/Common/StreamTest.php
  117. +1 −1  tests/Guzzle/Tests/Common/XmlElementTest.php
  118. +1 −1  tests/Guzzle/Tests/GuzzleTest.php
  119. +7 −5 tests/Guzzle/Tests/GuzzleTestCase.php
  120. +3 −3 tests/Guzzle/Tests/Http/ClientTest.php
  121. +1 −1  tests/Guzzle/Tests/Http/CookieJar/ArrayCookieJarTest.php
  122. +1 −1  tests/Guzzle/Tests/Http/CookieJar/FileCookieJarTest.php
  123. +1 −1  tests/Guzzle/Tests/Http/CookieTest.php
  124. +22 −22 tests/Guzzle/Tests/Http/Curl/CurlHandleTest.php
  125. +12 −12 tests/Guzzle/Tests/Http/Curl/CurlMultiTest.php
  126. +2 −2 tests/Guzzle/Tests/Http/EntityBodyTest.php
  127. +4 −4 tests/Guzzle/Tests/Http/{Curl → Exception}/CurlExceptionTest.php
  128. +6 −6 tests/Guzzle/Tests/Http/{Message → Exception}/ExceptionTest.php
  129. +114 −105 tests/Guzzle/Tests/Http/Message/AbstractMessageTest.php
  130. +8 −8 tests/Guzzle/Tests/Http/Message/EntityEnclosingRequestTest.php
  131. +103 −0 tests/Guzzle/Tests/Http/Message/HeaderTest.php
  132. +25 −5 tests/Guzzle/Tests/Http/Message/RequestFactoryTest.php
  133. +17 −14 tests/Guzzle/Tests/Http/Message/RequestTest.php
  134. +23 −17 tests/Guzzle/Tests/Http/Message/ResponseTest.php
  135. +1 −1  tests/Guzzle/Tests/Http/Plugin/BatchQueuePluginTest.php
  136. +17 −11 tests/Guzzle/Tests/Http/Plugin/CachePluginTest.php
  137. +6 −6 tests/Guzzle/Tests/Http/Plugin/CookiePluginTest.php
  138. +1 −1  tests/Guzzle/Tests/Http/Plugin/CurlAuthPluginTest.php
  139. +2 −2 tests/Guzzle/Tests/Http/Plugin/ExponentialBackoffTest.php
  140. +1 −1  tests/Guzzle/Tests/Http/Plugin/HistoryPluginTest.php
  141. +1 −1  tests/Guzzle/Tests/Http/Plugin/LogPluginTest.php
  142. +1 −1  tests/Guzzle/Tests/Http/Plugin/Md5ValidatorPluginTest.php
  143. +5 −5 tests/Guzzle/Tests/Http/Plugin/MockPluginTest.php
  144. +1 −1  tests/Guzzle/Tests/Http/Plugin/OauthPluginTest.php
  145. +1 −1  tests/Guzzle/Tests/Http/QueryStringTest.php
  146. +5 −5 tests/Guzzle/Tests/Http/Server.php
  147. +1 −1  tests/Guzzle/Tests/Http/UriTemplateTest.php
  148. +12 −1 tests/Guzzle/Tests/Http/UrlTest.php
  149. +1 −1  tests/Guzzle/Tests/Http/server.js
  150. +11 −0 tests/Guzzle/Tests/Mock/ExceptionMock.php
  151. +1 −1  tests/Guzzle/Tests/Mock/MockMulti.php
  152. +1 −1  tests/Guzzle/Tests/Mock/MockObserver.php
  153. +1 −1  tests/Guzzle/Tests/Mock/MockSubject.php
  154. +3 −3 tests/Guzzle/Tests/Service/ClientTest.php
  155. +1 −1  tests/Guzzle/Tests/Service/Command/AbstractCommandTest.php
  156. +1 −1  tests/Guzzle/Tests/Service/Command/ClosureCommandTest.php
  157. +3 −3 tests/Guzzle/Tests/Service/Command/CommandSetTest.php
  158. +2 −2 tests/Guzzle/Tests/Service/Command/CommandTest.php
  159. +2 −2 tests/Guzzle/Tests/Service/Command/DynamicCommandTest.php
  160. +1 −1  tests/Guzzle/Tests/Service/Command/Factory/AliasFactoryTest.php
  161. +1 −1  tests/Guzzle/Tests/Service/Command/Factory/CompositeFactoryTest.php
  162. +1 −1  tests/Guzzle/Tests/Service/Command/Factory/ConcreteClassFactoryTest.php
  163. +1 −1  tests/Guzzle/Tests/Service/Command/Factory/MapFactoryTest.php
  164. +1 −1  tests/Guzzle/Tests/Service/Command/Factory/ServiceDescriptionFactoryTest.php
  165. +1 −1  tests/Guzzle/Tests/Service/Description/ApiCommandTest.php
  166. +96 −0 tests/Guzzle/Tests/Service/Description/ArrayDescriptionBuilderTest.php
  167. +2 −2 tests/Guzzle/Tests/Service/Description/JsonDescriptionBuilderTest.php
  168. +10 −74 tests/Guzzle/Tests/Service/Description/ServiceDescriptionTest.php
  169. +3 −3 tests/Guzzle/Tests/Service/Description/XmlDescriptionBuilderTest.php
  170. +1 −1  tests/Guzzle/Tests/Service/InflectorTest.php
  171. +7 −6 tests/Guzzle/Tests/Service/InspectorTest.php
  172. +1 −1  tests/Guzzle/Tests/Service/Mock/Command/MockCommand.php
  173. +1 −1  tests/Guzzle/Tests/Service/Mock/Command/OtherCommand.php
  174. +1 −1  tests/Guzzle/Tests/Service/Mock/Command/Sub/Sub.php
  175. +1 −1  tests/Guzzle/Tests/Service/Mock/MockClient.php
  176. +1 −1  tests/Guzzle/Tests/Service/Mock/MockInflector.php
  177. +1 −1  tests/Guzzle/Tests/Service/Mock/MockResourceIterator.php
  178. +1 −1  tests/Guzzle/Tests/Service/ResourceIteratorApplyBatchedTest.php
  179. +1 −1  tests/Guzzle/Tests/Service/ResourceIteratorTest.php
  180. +6 −5 tests/Guzzle/Tests/Service/ServiceBuilderTest.php
  181. +2 −2 tests/Guzzle/Tests/TestData/services.xml
  182. BIN  tests/Guzzle/Tests/TestData/test.tar.gz
  183. BIN  tests/Guzzle/Tests/TestData/test.tar.gz.cpgz
  184. +1 −1  tests/Guzzle/Tests/TestData/test_service.json
  185. +1 −1  tests/Guzzle/Tests/TestData/test_service.xml
  186. +1 −1  tests/Guzzle/Tests/TestData/test_service2.json
  187. +1 −1  tests/Guzzle/Tests/TestData/test_service2.xml
  188. +1 −1  tests/bootstrap.php
View
2  LICENSE
@@ -16,4 +16,4 @@ 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.
+THE SOFTWARE.
View
2  README.md
@@ -111,7 +111,7 @@ try {
$client->head('messages/123'),
$client->delete('orders/123')
));
-} catch (Guzzle\Common\ExceptionCollection $e) {
+} catch (Guzzle\Common\Exception\ExceptionCollection $e) {
echo "The following requests encountered an exception: \n";
foreach ($e as $exception) {
echo $exception->getRequest() . "\n" . $exception->getMessage() . "\n";
View
2  build.xml
@@ -63,4 +63,4 @@
</else>
</if>
</target>
-</project>
+</project>
View
2  phar-stub-min.php
@@ -1,2 +1,2 @@
<?php
-__HALT_COMPILER();
+__HALT_COMPILER();
View
2  phar-stub.php
@@ -12,4 +12,4 @@
));
$classLoader->register();
-__HALT_COMPILER();
+__HALT_COMPILER();
View
11 phpunit.xml.dist
@@ -20,7 +20,18 @@
<directory suffix=".php">./src/Guzzle</directory>
<exclude>
<directory suffix="Interface.php">./src/Guzzle</directory>
+ <file>./src/Guzzle/Common/GuzzleException.php</file>
<file>./src/Guzzle/Http/HttpException.php</file>
+ <file>./src/Guzzle/Common/Exception/BadMethodCallException.php</file>
+ <file>./src/Guzzle/Common/Exception/InvalidArgumentException.php</file>
+ <file>./src/Guzzle/Common/Exception/RuntimeException.php</file>
+ <file>./src/Guzzle/Common/Exception/UnexpectedValueException.php</file>
+ <file>./src/Guzzle/Service/Exception/ClientNotFoundException.php</file>
+ <file>./src/Guzzle/Service/Exception/CommandException.php</file>
+ <file>./src/Guzzle/Service/Exception/DescriptionBuilderException.php</file>
+ <file>./src/Guzzle/Service/Exception/ServiceBuilderException.php</file>
+ <file>./src/Guzzle/Service/Exception/ServiceNotFoundException.php</file>
+ <file>./src/Guzzle/Service/Exception/ValidationException.php</file>
</exclude>
</whitelist>
</filter>
View
2  src/Guzzle/Common/AbstractHasDispatcher.php
@@ -52,4 +52,4 @@ public function dispatch($eventName, array $context = array())
{
$this->getEventDispatcher()->dispatch($eventName, new Event($context));
}
-}
+}
View
2  src/Guzzle/Common/Cache/AbstractCacheAdapter.php
@@ -16,4 +16,4 @@ public function getCacheObject()
{
return $this->cache;
}
-}
+}
View
23 src/Guzzle/Common/Cache/CacheAdapterFactory.php
@@ -2,6 +2,9 @@
namespace Guzzle\Common\Cache;
+use Guzzle\Common\Exception\InvalidArgumentException;
+use Guzzle\Common\Exception\RuntimeException;
+
/**
* Generates cache adapters and cache providers objects using an array of
* configuration data. This can be useful for creating cache adapters
@@ -21,12 +24,12 @@ public static function factory(array $config)
foreach (array('cache.adapter', 'cache.provider') as $required) {
// Validate that the required parameters were set
if (!isset($config[$required])) {
- throw new \InvalidArgumentException("{$required} is a required CacheAdapterFactory option");
+ throw new InvalidArgumentException("{$required} is a required CacheAdapterFactory option");
}
// Ensure that the cache adapter and provider are actual classes
if (is_string($config[$required]) && !class_exists($config[$required])) {
- throw new \InvalidArgumentException("{$config[$required]} is not a valid class for {$required}");
+ throw new InvalidArgumentException("{$config[$required]} is not a valid class for {$required}");
}
}
@@ -56,11 +59,15 @@ public static function factory(array $config)
*/
protected static function createObject($className, array $args = null)
{
- if (!$args) {
- return new $className;
- } else {
- $c = new \ReflectionClass($className);
- return $c->newInstanceArgs($args);
+ try {
+ if (!$args) {
+ return new $className;
+ } else {
+ $c = new \ReflectionClass($className);
+ return $c->newInstanceArgs($args);
+ }
+ } catch (\Exception $e) {
+ throw new RuntimeException($e->getMessage(), $e->getCode(), $e);
}
}
-}
+}
View
2  src/Guzzle/Common/Cache/CacheAdapterInterface.php
@@ -58,4 +58,4 @@ function fetch($id, array $options = null);
* FALSE otherwise.
*/
function save($id, $data, $lifeTime = false, array $options = null);
-}
+}
View
6 src/Guzzle/Common/Cache/ClosureCacheAdapter.php
@@ -2,6 +2,8 @@
namespace Guzzle\Common\Cache;
+use Guzzle\Common\Exception\InvalidArgumentException;
+
/**
* Cache adapter that defers to closures for implementation
*/
@@ -28,7 +30,7 @@ public function __construct(array $callables)
// Validate each key to ensure it exists and is callable
foreach (array('contains', 'delete', 'fetch', 'save') as $key) {
if (!array_key_exists($key, $callables) || !is_callable($callables[$key])) {
- throw new \InvalidArgumentException(
+ throw new InvalidArgumentException(
"callables must contain a callable $key key");
}
}
@@ -67,4 +69,4 @@ public function save($id, $data, $lifeTime = false, array $options = null)
{
return call_user_func($this->callables['save'], $id, $data, $lifeTime, $options);
}
-}
+}
View
2  src/Guzzle/Common/Cache/DoctrineCacheAdapter.php
@@ -50,4 +50,4 @@ public function save($id, $data, $lifeTime = false, array $options = null)
{
return $this->cache->save($id, $data, $lifeTime);
}
-}
+}
View
2  src/Guzzle/Common/Cache/Zf1CacheAdapter.php
@@ -48,4 +48,4 @@ public function save($id, $data, $lifeTime = false, array $options = null)
{
return $this->cache->save($data, $id, array(), $lifeTime);
}
-}
+}
View
2  src/Guzzle/Common/Cache/Zf2CacheAdapter.php
@@ -79,4 +79,4 @@ public function save($id, $data, $lifeTime = false, array $options = null)
'ttl' => $lifeTime
)));
}
-}
+}
View
2  src/Guzzle/Common/Collection.php
@@ -417,4 +417,4 @@ public function set($key, $value)
return $this;
}
-}
+}
View
2  src/Guzzle/Common/Event.php
@@ -63,4 +63,4 @@ public function offsetUnset($offset)
{
unset($this->context[$offset]);
}
-}
+}
View
7 src/Guzzle/Common/Exception/BadMethodCallException.php
@@ -0,0 +1,7 @@
+<?php
+
+namespace Guzzle\Common\Exception;
+
+use Guzzle\Common\GuzzleException;
+
+class BadMethodCallException extends \BadMethodCallException implements GuzzleException {}
View
8 src/Guzzle/Common/ExceptionCollection.php → src/Guzzle/Common/Exception/ExceptionCollection.php
@@ -1,11 +1,13 @@
<?php
-namespace Guzzle\Common;
+namespace Guzzle\Common\Exception;
+
+use Guzzle\Common\GuzzleException;
/**
* Collection of exceptions
*/
-class ExceptionCollection extends \Exception implements GuzzleExceptionInterface, \IteratorAggregate, \Countable
+class ExceptionCollection extends \Exception implements GuzzleException, \IteratorAggregate, \Countable
{
/**
* @var array Array of Exceptions
@@ -55,4 +57,4 @@ public function getIterator()
{
return new \ArrayIterator($this->exceptions);
}
-}
+}
View
7 src/Guzzle/Common/Exception/InvalidArgumentException.php
@@ -0,0 +1,7 @@
+<?php
+
+namespace Guzzle\Common\Exception;
+
+use Guzzle\Common\GuzzleException;
+
+class InvalidArgumentException extends \InvalidArgumentException implements GuzzleException {}
View
7 src/Guzzle/Common/Exception/RuntimeException.php
@@ -0,0 +1,7 @@
+<?php
+
+namespace Guzzle\Common\Exception;
+
+use Guzzle\Common\GuzzleException;
+
+class RuntimeException extends \RuntimeException implements GuzzleException {}
View
7 src/Guzzle/Common/Exception/UnexpectedValueException.php
@@ -0,0 +1,7 @@
+<?php
+
+namespace Guzzle\Common\Exception;
+
+use Guzzle\Common\GuzzleException;
+
+class UnexpectedValueException extends \UnexpectedValueException implements GuzzleException {}
View
4 src/Guzzle/Common/GuzzleExceptionInterface.php → src/Guzzle/Common/GuzzleException.php
@@ -5,6 +5,4 @@
/**
* Guzzle exception
*/
-interface GuzzleExceptionInterface
-{
-}
+interface GuzzleException {}
View
16 src/Guzzle/Common/HasDispatcherInterface.php
@@ -5,22 +5,22 @@
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
/**
- * Holds an event dispatcher
+ * Holds an event dispatcher
*/
interface HasDispatcherInterface
{
/**
* Get a list of all of the events emitted from the class
- *
- * @return array
+ *
+ * @return array
*/
static function getAllEvents();
-
+
/**
* Set the EventDispatcher of the request
*
* @param EventDispatcherInterface $eventDispatcher
- *
+ *
* @return HasDispatcherInterface
*/
function setEventDispatcher(EventDispatcherInterface $eventDispatcher);
@@ -31,12 +31,12 @@ function setEventDispatcher(EventDispatcherInterface $eventDispatcher);
* @return EventDispatcherInterface
*/
function getEventDispatcher();
-
+
/**
* Helper to dispatch Guzzle events and set the event name on the event
- *
+ *
* @param $eventName Name of the event to dispatch
* @param array $context Context of the event
*/
function dispatch($eventName, array $context = array());
-}
+}
View
2  src/Guzzle/Common/Log/AbstractLogAdapter.php
@@ -18,4 +18,4 @@ public function getLogObject()
{
return $this->log;
}
-}
+}
View
6 src/Guzzle/Common/Log/ClosureLogAdapter.php
@@ -2,6 +2,8 @@
namespace Guzzle\Common\Log;
+use Guzzle\Common\Exception\InvalidArgumentException;
+
/**
* Allows Closures to be called when messages are logged. Closures combined
* with filtering can trigger application events based on log messages.
@@ -14,7 +16,7 @@ class ClosureLogAdapter extends AbstractLogAdapter
public function __construct($logObject)
{
if (!is_callable($logObject)) {
- throw new \InvalidArgumentException('Object must be callable');
+ throw new InvalidArgumentException('Object must be callable');
}
$this->log = $logObject;
@@ -27,4 +29,4 @@ public function log($message, $priority = LOG_INFO, $extras = null)
{
call_user_func($this->log, $message, $priority, $extras);
}
-}
+}
View
2  src/Guzzle/Common/Log/LogAdapterInterface.php
@@ -17,4 +17,4 @@
* @param mixed $extras (optional) Extra information to log in event
*/
function log($message, $priority = LOG_INFO, $extras = null);
-}
+}
View
2  src/Guzzle/Common/Log/MonologLogAdapter.php
@@ -38,4 +38,4 @@ public function log($message, $priority = LOG_INFO, $extras = null)
{
$this->log->addRecord(self::$mapping[$priority], $message);
}
-}
+}
View
2  src/Guzzle/Common/Log/Zf1LogAdapter.php
@@ -22,4 +22,4 @@ public function log($message, $priority = LOG_INFO, $extras = null)
{
$this->log->log($message, $priority, $extras);
}
-}
+}
View
2  src/Guzzle/Common/Log/Zf2LogAdapter.php
@@ -24,4 +24,4 @@ public function log($message, $priority = LOG_INFO, $extras = null)
{
$this->log->log($message, $priority, $extras);
}
-}
+}
View
2  src/Guzzle/Common/NullObject.php
@@ -22,4 +22,4 @@ public function key() {}
public function next() {}
public function rewind() {}
public function valid() {}
-}
+}
View
6 src/Guzzle/Common/Stream.php
@@ -2,6 +2,8 @@
namespace Guzzle\Common;
+use Guzzle\Common\Exception\InvalidArgumentException;
+
/**
* OO interface to PHP streams
*/
@@ -34,7 +36,7 @@ class Stream
public function __construct($stream, $size = null)
{
if (!is_resource($stream)) {
- throw new \InvalidArgumentException('Stream must be a resource');
+ throw new InvalidArgumentException('Stream must be a resource');
}
$this->size = $size;
@@ -279,4 +281,4 @@ public function write($string)
{
return $this->isWritable() ? fwrite($this->stream, $string) : false;
}
-}
+}
View
2  src/Guzzle/Common/XmlElement.php
@@ -79,4 +79,4 @@ public function asFormattedXml()
return $doc->saveXML();
}
-}
+}
View
2  src/Guzzle/Guzzle.php
@@ -104,4 +104,4 @@ public static function reset()
{
self::$cache = array();
}
-}
+}
View
13 src/Guzzle/Http/Client.php
@@ -3,9 +3,10 @@
namespace Guzzle\Http;
use Guzzle\Guzzle;
-use Guzzle\Common\AbstractHasDispatcher;
-use Guzzle\Common\ExceptionCollection;
use Guzzle\Common\Collection;
+use Guzzle\Common\AbstractHasDispatcher;
+use Guzzle\Common\Exception\ExceptionCollection;
+use Guzzle\Common\Exception\InvalidArgumentException;
use Guzzle\Http\Url;
use Guzzle\Http\UriTemplate;
use Guzzle\Http\EntityBody;
@@ -98,7 +99,7 @@ public function __toString()
} else if (is_array($config)) {
$this->config = new Collection($config);
} else {
- throw new \InvalidArgumentException(
+ throw new InvalidArgumentException(
'Config must be an array or Collection'
);
}
@@ -144,7 +145,7 @@ public function setDefaultHeaders($headers)
} else if (is_array($headers)) {
$this->defaultHeaders = new Collection($headers);
} else {
- throw new \InvalidArgumentException('Headers must be an array or Collection');
+ throw new InvalidArgumentException('Headers must be an array or Collection');
}
return $this;
@@ -222,7 +223,7 @@ public function createRequest($method = RequestInterface::GET, $uri = null, $hea
$templateVars = null;
} else {
if (count($uri) != 2 || !is_array($uri[1])) {
- throw new \InvalidArgumentException('You must provide a URI'
+ throw new InvalidArgumentException('You must provide a URI'
. ' template followed by an array of template variables'
. ' when using an array for a URI template');
}
@@ -536,4 +537,4 @@ public function setRequestFactory(RequestFactoryInterface $factory)
return $this;
}
-}
+}
View
2  src/Guzzle/Http/ClientInterface.php
@@ -250,4 +250,4 @@ function setCurlMulti(CurlMultiInterface $curlMulti);
* @return ClientInterface
*/
function setRequestFactory(RequestFactoryInterface $factory);
-}
+}
View
2  src/Guzzle/Http/Cookie.php
@@ -53,4 +53,4 @@ public function __construct(array $data = null)
);
});
}
-}
+}
View
7 src/Guzzle/Http/CookieJar/ArrayCookieJar.php
@@ -3,6 +3,7 @@
namespace Guzzle\Http\CookieJar;
use Guzzle\Common\Collection;
+use Guzzle\Common\Exception\InvalidArgumentException;
/**
* Cookie jar that stores cookies an an array
@@ -155,11 +156,11 @@ public function getCookies($domain = null, $path = null, $name = null, $skipDisc
public function save(array $cookieData)
{
if (!isset($cookieData['domain'])) {
- throw new \InvalidArgumentException('Cookies require a 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');
+ throw new InvalidArgumentException('Cookies require a names and values');
}
$cookieData = array_merge(array(
@@ -255,4 +256,4 @@ protected function prune(\Closure $callback)
return $originalCount - count($this->cookies);
}
-}
+}
View
2  src/Guzzle/Http/CookieJar/CookieJarInterface.php
@@ -90,4 +90,4 @@ function getCookies($domain = null, $path = null, $name = null, $skipDiscardable
* @return CookieJarInterface
*/
function save(array $cookieData);
-}
+}
View
2  src/Guzzle/Http/CookieJar/FileCookieJar.php
@@ -75,4 +75,4 @@ protected function load()
$this->cookies = $json ? json_decode($json, true) : array();
}
-}
+}
View
23 src/Guzzle/Http/Curl/CurlHandle.php
@@ -3,6 +3,7 @@
namespace Guzzle\Http\Curl;
use Guzzle\Guzzle;
+use Guzzle\Common\Exception\InvalidArgumentException;
use Guzzle\Common\Collection;
use Guzzle\Http\Message\RequestInterface;
use Guzzle\Http\Message\EntityEnclosingRequestInterface;
@@ -46,7 +47,7 @@ public static function factory(RequestInterface $request)
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_USERAGENT => (string) $request->getHeader('User-Agent'),
CURLOPT_ENCODING => '', // Supports all encodings
CURLOPT_PORT => $request->getPort(),
CURLOPT_HTTP_VERSION => $request->getProtocolVersion(true),
@@ -87,7 +88,7 @@ public static function factory(RequestInterface $request)
}
// @codeCoverageIgnoreEnd
- $headers = $request->getHeaders();
+ $headers = $request->getHeaders()->getAll();
// Specify settings according to the HTTP method
switch ($request->getMethod()) {
@@ -106,7 +107,7 @@ public static function factory(RequestInterface $request)
$curlOptions[CURLOPT_UPLOAD] = true;
if ($request->hasHeader('Content-Length')) {
unset($headers['Content-Length']);
- $curlOptions[CURLOPT_INFILESIZE] = $request->getHeader('Content-Length');
+ $curlOptions[CURLOPT_INFILESIZE] = (int) (string) $request->getHeader('Content-Length');
}
break;
@@ -149,14 +150,12 @@ public static function factory(RequestInterface $request)
$curlOptions[$key] = $value;
}
- // Add any custom headers to the request. Empty headers will not be
- // added. Headers explicitly set to NULL _will_ be added.
+ // Add any custom headers to the request. Emtpy headers will cause curl to
+ // not send the header at all.
foreach ($headers as $key => $value) {
- if ($value === null) {
- $curlOptions[CURLOPT_HTTPHEADER][] = "{$key}:";
- } else if ($key) {
+ if ($key) {
foreach ((array) $value as $val) {
- $curlOptions[CURLOPT_HTTPHEADER][] = "{$key}: {$val}";
+ $curlOptions[CURLOPT_HTTPHEADER][] = trim("{$key}: {$val}");
}
}
}
@@ -191,14 +190,14 @@ public static function factory(RequestInterface $request)
public function __construct($handle, $options)
{
if (!is_resource($handle)) {
- throw new \InvalidArgumentException('Invalid handle provided');
+ 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');
+ throw new InvalidArgumentException('Expected array or Collection');
}
$this->handle = $handle;
}
@@ -346,4 +345,4 @@ public function getOptions()
{
return $this->options;
}
-}
+}
View
19 src/Guzzle/Http/Curl/CurlMulti.php
@@ -3,10 +3,11 @@
namespace Guzzle\Http\Curl;
use Guzzle\Common\AbstractHasDispatcher;
-use Guzzle\Common\ExceptionCollection;
+use Guzzle\Common\Exception\ExceptionCollection;
+use Guzzle\Http\Exception\CurlException;
use Guzzle\Http\Message\RequestInterface;
use Guzzle\Http\Message\RequestFactory;
-use Guzzle\Http\Message\RequestException;
+use Guzzle\Http\Exception\RequestException;
/**
* Send {@see RequestInterface} objects in parallel using curl_multi
@@ -495,7 +496,7 @@ private function getRequestHandle(RequestInterface $request)
return isset($this->handles[$hash]) ? $this->handles[$hash] : null;
}
-
+
/**
* Throw an exception for a cURL multi response if needed
*
@@ -507,16 +508,16 @@ private function checkCurlResult($code)
if ($code <= 0) {
return;
}
-
+
if (isset($this->multiErrors[$code])) {
$message = "cURL error: {$code} ({$this->multiErrors[$code][0]}): cURL message: {$this->multiErrors[$code][1]}";
} else {
$message = 'Unexpected cURL error: ' . $code;
}
-
+
throw new CurlException($message);
}
-
+
/**
* Create the new cURL multi handle with error checking
*/
@@ -525,13 +526,13 @@ private function createMutliHandle()
if ($this->multiHandle && is_resource($this->multiHandle)) {
curl_multi_close($this->multiHandle);
}
-
+
$this->multiHandle = curl_multi_init();
-
+
// @codeCoverageIgnoreStart
if ($this->multiHandle === false) {
throw new CurlException('Unable to create multi handle');
}
// @codeCoverageIgnoreEnd
}
-}
+}
View
4 src/Guzzle/Http/Curl/CurlMultiInterface.php
@@ -3,7 +3,7 @@
namespace Guzzle\Http\Curl;
use Guzzle\Common\HasDispatcherInterface;
-use Guzzle\Common\ExceptionCollection;
+use Guzzle\Common\Exception\ExceptionCollection;
use Guzzle\Http\Message\RequestInterface;
/**
@@ -74,4 +74,4 @@ function reset($hard = false);
* transfer.
*/
function send();
-}
+}
View
7 src/Guzzle/Http/EntityBody.php
@@ -3,6 +3,7 @@
namespace Guzzle\Http;
use Guzzle\Common\Stream;
+use Guzzle\Common\Exception\InvalidArgumentException;
/**
* Entity body used with an HTTP request or response
@@ -21,7 +22,7 @@ class EntityBody extends Stream
* @param int $size (optional) Size of the data contained in the resource
*
* @return EntityBody
- * @throws HttpException if the $resource arg is not a resource or string
+ * @throws InvalidArgumentException if the $resource arg is not a resource or string
*/
public static function factory($resource = '', $size = null)
{
@@ -36,7 +37,7 @@ public static function factory($resource = '', $size = null)
return $resource;
}
- throw new HttpException('Invalid resource type');
+ throw new InvalidArgumentException('Invalid resource type');
}
/**
@@ -210,4 +211,4 @@ protected function handleCompression($filter, $offsetStart = null)
return true;
}
-}
+}
View
6 src/Guzzle/Http/Message/BadResponseException.php → src/Guzzle/Http/Exception/BadResponseException.php
@@ -1,6 +1,8 @@
<?php
-namespace Guzzle\Http\Message;
+namespace Guzzle\Http\Exception;
+
+use Guzzle\Http\Message\Response;
/**
* Http request exception thrown when a bad response is received
@@ -31,4 +33,4 @@ public function getResponse()
{
return $this->response;
}
-}
+}
View
6 src/Guzzle/Http/Curl/CurlException.php → src/Guzzle/Http/Exception/CurlException.php
@@ -1,8 +1,6 @@
<?php
-namespace Guzzle\Http\Curl;
-
-use Guzzle\Http\Message\BadResponseException;
+namespace Guzzle\Http\Exception;
/**
* cURL request exception
@@ -45,4 +43,4 @@ public function getErrorNo()
{
return $this->curlErrorNo;
}
-}
+}
View
8 src/Guzzle/Http/Message/RequestException.php → src/Guzzle/Http/Exception/RequestException.php
@@ -1,13 +1,15 @@
<?php
-namespace Guzzle\Http\Message;
+namespace Guzzle\Http\Exception;
+use Guzzle\Common\Exception\RuntimeException;
+use Guzzle\Http\Message\RequestInterface;
use Guzzle\Http\HttpException;
/**
* Http request exception
*/
-class RequestException extends HttpException
+class RequestException extends RuntimeException implements HttpException
{
/**
* @var RequestInterface
@@ -37,4 +39,4 @@ public function getRequest()
{
return $this->request;
}
-}
+}
View
8 src/Guzzle/Http/HttpException.php
@@ -2,9 +2,9 @@
namespace Guzzle\Http;
+use Guzzle\Common\GuzzleException;
+
/**
- * Http exception
+ * Http exception interface
*/
-class HttpException extends \Exception implements \Guzzle\Common\GuzzleExceptionInterface
-{
-}
+interface HttpException extends GuzzleException {}
View
273 src/Guzzle/Http/Message/AbstractMessage.php
@@ -3,6 +3,7 @@
namespace Guzzle\Http\Message;
use Guzzle\Common\Collection;
+use Guzzle\Common\Exception\InvalidArgumentException;
/**
* HTTP messages consist of request messages that request data from a server,
@@ -11,9 +12,9 @@
abstract class AbstractMessage implements MessageInterface
{
/**
- * @var Collection Collection of HTTP headers
+ * @var array HTTP headers
*/
- protected $headers;
+ protected $headers = array();
/**
* @var Collection Custom message parameters that are extendable by plugins
@@ -42,6 +43,27 @@ public function getParams()
}
/**
+ * Add a header to an existing collection of headers.
+ *
+ * @param string $header Header name to add
+ * @param string $value Value of the header
+ *
+ * @return AbstractMessage
+ */
+ public function addHeader($header, $value)
+ {
+ $key = strtolower($header);
+ if (!isset($this->headers[$key])) {
+ $this->headers[$key] = new Header($header, $value);
+ } else {
+ $this->headers[$key]->add($value, $header);
+ }
+ $this->changedHeader('set', $key);
+
+ return $this;
+ }
+
+ /**
* Add and merge in an array of HTTP headers.
*
* @param array $headers Associative array of header data.
@@ -50,197 +72,201 @@ public function getParams()
*/
public function addHeaders(array $headers)
{
- // Special handling for case-insensitive keys
foreach ($headers as $key => $value) {
- $current = $this->headers->get($key);
- if (null === $current) {
- // Simply add the headers=
- $this->headers->set($key, $value);
- } else if (is_array($current)) {
- // Merge in sub arrays as needed
- $current[] = $value;
- $this->headers->set($key, $current);
- } else {
- // use the default add functionality
- $this->headers->add($key, $value);
- }
+ $this->addHeader($key, $value);
}
- $this->changedHeader('set', array_keys($headers));
-
return $this;
}
/**
- * Retrieve an HTTP header by name
+ * Retrieve an HTTP header by name. Performs a case-insensitive search of
+ * all headers.
*
* @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
+ * @param bool $string (optional) Set to true to get the header as a string
*
- * @return string|array|null Returns the matching HTTP header value or NULL if the
- * header is not found. If multiple headers are present for the header, then
- * an associative array is returned
+ * @return string|Header|null Returns NULL if no matching header is found.
+ * Returns a string if $string is set to TRUE. Returns a Header object
+ * if a matching header is found.
*/
- public function getHeader($header, $default = null, $match = Collection::MATCH_IGNORE_CASE)
+ public function getHeader($header, $string = false)
{
- $headers = $this->headers->getAll(array($header), $match);
- if (!$headers) {
- return $default;
- } else if (count($headers) > 1) {
- return $headers;
- } else {
- return end($headers);
+ $key = strtolower($header);
+ if (!isset($this->headers[$key])) {
+ return null;
}
+
+ return $string ? (string) $this->headers[$key] : $this->headers[$key];
}
/**
* 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
+ * only a particular subset of headers.
*
- * @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.
+ * @return Collection Returns a {@see 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_IGNORE_CASE)
+ public function getHeaders(array $names = null)
{
- if (!$headers) {
- return clone $this->headers;
- } else {
- return new Collection($this->headers->getAll($headers, $match));
+ if (!$names) {
+ $names = array_keys($this->headers);
+ }
+
+ $result = array();
+ foreach ($names as $name) {
+ if ($this->hasHeader($name)) {
+ $values = $this->getHeader($name);
+ foreach ($values->raw() as $key => $value) {
+ $result[$key] = $value;
+ }
+ }
}
+
+ return new Collection($result);
}
/**
- * Get a tokenized header as a Collection
+ * Set an HTTP header
*
- * @param string $header Header to retrieve
- * @param string $token (optional) Token separator
- * @param int $match (optional) Match mode
+ * @param string $header Name of the header to set.
+ * @param mixed $value Value to set.
*
- * @return Collection|null
+ * @return AbstractMessage
*/
- public function getTokenizedHeader($header, $token = ';', $match = Collection::MATCH_IGNORE_CASE)
+ public function setHeader($header, $value)
{
- $value = $this->getHeader($header, null, $match);
- if (!$value) {
- return null;
- }
+ // Remove any existing header
+ $key = strtolower($header);
+ unset($this->headers[$key]);
- $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]));
- }
+ if ($value instanceof Header) {
+ $this->headers[$key] = $value;
+ } else {
+ // Allow for 0, '', and NULL to be set
+ if (!$value) {
+ $value = array($value);
}
+ $this->headers[$key] = new Header($header, $value);
}
+ $this->changedHeader('set', $key);
- return $data->map(function($key, $value) {
- return is_array($value) ? array_unique($value) : $value;
- });
+ return $this;
}
/**
- * Set a tokenized header on the request that implodes a Collection of data
- * into a string separated by a token
+ * Overwrite all HTTP headers with the supplied array of headers
*
- * @param string $header Header to set
- * @param array|Collection $data Header data
- * @param string $token (optional) Token delimiter
+ * @param array $headers Associative array of header data.
*
* @return AbstractMessage
- * @throws InvalidArgumentException if data is not an array or Collection
*/
- public function setTokenizedHeader($header, $data, $token = ';')
+ public function setHeaders(array $headers)
{
- 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;
- }
+ // Get the keys that are changing
+ $changed = array_keys($this->headers);
+ // Erase the old headers
+ $this->headers = array();
+ // Add the new headers
+ foreach ($headers as $key => $value) {
+ $changed[] = $key;
+ $this->addHeader($key, $value);
}
+ // Notify of the changed headers
+ $this->changedHeader('set', array_map('strtolower', array_unique($changed)));
- return $this->setHeader($header, implode($token, $values));
+ return $this;
}
/**
* 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
+ * @return bool Returns TRUE or FALSE if the header is present
*/
- public function hasHeader($header, $match = Collection::MATCH_IGNORE_CASE)
+ public function hasHeader($header)
{
- return false !== $this->headers->hasKey($header, $match);
+ return array_key_exists(strtolower($header), $this->headers);
}
/**
* 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_IGNORE_CASE)
+ public function removeHeader($header)
{
- $this->headers->remove($header, $match);
- $this->changedHeader('remove', $header);
+ $key = strtolower($header);
+ unset($this->headers[$key]);
+ $this->changedHeader('remove', $key);
return $this;
}
/**
- * Set an HTTP header
+ * Get a tokenized header as a Collection
*
- * @param string $header Name of the header to set.
- * @param mixed $value Value to set.
+ * @param string $header Header to retrieve
+ * @param string $token (optional) Token separator
*
- * @return AbstractMessage
+ * @return Collection|null Returns a Collection object containing the
+ * tokenized values if the header was found. Returns NULL otherwise.
*/
- public function setHeader($header, $value)
+ public function getTokenizedHeader($header, $token = ';')
{
- // Remove any existing header
- $this->removeHeader($header);
- $this->headers->set($header, $value);
- $this->changedHeader('set', $header);
+ if (!$this->hasHeader($header)) {
+ return null;
+ }
- return $this;
+ $data = new Collection();
+
+ foreach ($this->getHeader($header) as $singleValue) {
+ foreach (explode($token, $singleValue) as $kvp) {
+ $parts = explode('=', $kvp, 2);
+ if (!isset($parts[1])) {
+ $data[count($data)] = trim($parts[0]);
+ } else {
+ $data->add(trim($parts[0]), trim($parts[1]));
+ }
+ }
+ }
+
+ return $data->map(function($key, $value) {
+ return is_array($value) ? array_unique($value) : $value;
+ });
}
/**
- * Overwrite all HTTP headers with the supplied array of headers
+ * Set a tokenized header on the request that implodes a Collection of data
+ * into a string separated by a token
*
- * @param array $headers Associative array of header data.
+ * @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 setHeaders(array $headers)
+ public function setTokenizedHeader($header, $data, $token = ';')
{
- $this->changedHeader('set', $this->getHeaders()->getKeys());
- $this->headers->replace($headers);
+ if (!($data instanceof Collection) && !is_array($data)) {
+ throw new InvalidArgumentException('Data must be a Collection or array');
+ }
- return $this;
+ $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));
}
/**
@@ -309,7 +335,7 @@ public function removeCacheControlDirective($directive)
*/
protected function changedHeader($action, $keyOrArray)
{
- if (in_array('Cache-Control', (array) $keyOrArray)) {
+ if (in_array('cache-control', (array) $keyOrArray)) {
$this->parseCacheControlDirective();
}
}
@@ -344,6 +370,25 @@ private function rebuildCacheControlDirective()
}
}
- $this->headers->set('Cache-Control', implode(', ', $cacheControl));
+ $this->headers['cache-control'] = new Header('Cache-Control', implode(', ', $cacheControl));
+ }
+
+ /**
+ * Get headers as a string
+ *
+ * @return string
+ */
+ protected function getHeaderString()
+ {
+ $headers = '';
+ foreach ($this->headers as $key => $value) {
+ foreach ($value->raw() as $k => $v) {
+ foreach ($v as $vv) {
+ $headers .= "{$k}: {$vv}\r\n";
+ }
+ }
+ }
+
+ return $headers;
}
-}
+}
View
5 src/Guzzle/Http/Message/EntityEnclosingRequest.php
@@ -5,6 +5,7 @@
use Guzzle\Common\Collection;
use Guzzle\Http\EntityBody;
use Guzzle\Http\QueryString;
+use Guzzle\Http\Exception\RequestException;
/**
* HTTP request that sends an entity-body in the request message (POST, PUT)
@@ -63,7 +64,7 @@ public function setBody($body, $contentType = null, $tryChunkedTransfer = false)
$this->setHeader('Expect', '100-Continue');
if ($contentType) {
- $this->setHeader('Content-Type', $contentType);
+ $this->setHeader('Content-Type', (string) $contentType);
}
if ($tryChunkedTransfer) {
@@ -228,4 +229,4 @@ protected function processPostFields()
$this->getCurlOptions()->set(CURLOPT_POSTFIELDS, $this->postFields->getAll());
}
}
-}
+}
View
4 src/Guzzle/Http/Message/EntityEnclosingRequestInterface.php
@@ -74,7 +74,7 @@ function addPostFields($fields);
* @return EntityEnclosingRequestInterface
*/
function setPostField($key, $value);
-
+
/**
* Add POST files to use in the upload
*
@@ -93,4 +93,4 @@ function addPostFiles(array $files);
* @return EntityEnclosingRequestInterface
*/
function removePostField($field);
-}
+}
View
207 src/Guzzle/Http/Message/Header.php
@@ -0,0 +1,207 @@
+<?php
+
+namespace Guzzle\Http\Message;
+
+/**
+ * Represents a header and all of the values stored by that header
+ */
+class Header implements \IteratorAggregate, \Countable
+{
+ protected $values = array();
+ protected $header;
+ protected $glue = ', ';
+
+ /**
+ * Construct a new header object
+ *
+ * @param string $header Name of the header
+ * @param string $values Values of the header
+ * @param string $glue Glue used to combine multiple values into a string
+ */
+ public function __construct($header, $values = array(), $glue = ', ')
+ {
+ $this->header = $header;
+ $this->glue = $glue;
+
+ if (null !== $values) {
+ foreach ((array) $values as $key => $value) {
+ if (is_numeric($key)) {
+ $key = $header;
+ }
+ if ($value === null) {
+ $this->add($value, $key);
+ } else {
+ foreach ((array) $value as $v) {
+ $this->add($v, $key);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Convert the header to a string
+ *
+ * @return string
+ */
+ public function __toString()
+ {
+ return implode($this->glue, $this->toArray());
+ }
+
+ /**
+ * Add a value to the list of header values
+ *
+ * @param string $value Value to add
+ * @param string $header (optional) The exact header casing to add with.
+ * Defaults to the name of the header.
+ *
+ * @return Header
+ */
+ public function add($value, $header = null)
+ {
+ $header = $header ?: $this->getName();
+
+ if (!$this->hasExactHeader($header)) {
+ $this->values[$header] = array();
+ }
+ $this->values[$header][] = $value;
+
+ return $this;
+ }
+
+ /**
+ * Get the name of the header
+ *
+ * @return string
+ */
+ public function getName()
+ {
+ return $this->header;
+ }
+
+ /**
+ * Change the glue used to implode the values
+ *
+ * @param string $glue Glue used to implode multiple values
+ *
+ * @return Header
+ */
+ public function setGlue($glue)
+ {
+ $this->glue = $glue;
+
+ return $this;
+ }
+
+ /**
+ * Get the glue used to implode multiple values into a string
+ *
+ * @return string
+ */
+ public function getGlue()
+ {
+ return $this->glue;
+ }
+
+ /**
+ * Normalize the header into a single standard header with an array of values
+ *
+ * @return Header
+ */
+ public function normalize()
+ {
+ $this->values = array(
+ $this->getName() => $this->toArray()
+ );
+
+ return $this;
+ }
+
+ /**
+ * Check if a particular case variation is present in the header
+ * Example: A header exists on a message for 'Foo', and 'foo'. The Header
+ * object will contain all of the values of 'Foo' and all of the values of
+ * 'foo'. You can use this method to check to see if a header was set
+ * using 'foo' (true), 'Foo' (true), 'FOO' (false), etc.
+ *
+ * @param string $header Exact header to check for
+ *
+ * @return bool
+ */
+ public function hasExactHeader($header)
+ {
+ return array_key_exists($header, $this->values);
+ }
+
+ /**
+ * Check if the collection of headers has a particular value
+ *
+ * @param string $searchValue Value to search for
+ * @param bool $caseInsensitive (optional) Set to TRUE to use a case
+ * insensitive search
+ *
+ * @return bool
+ */
+ public function hasValue($searchValue, $caseInsensitive = false)
+ {
+ foreach ($this->getIterator() as $value) {
+ if ($caseInsensitive && !strcasecmp($value, $searchValue)) {
+ return true;
+ } elseif ($value == $searchValue) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Get all of the header values as a flat array
+ *
+ * @return array
+ */
+ public function toArray()
+ {
+ return $this->getIterator()->getArrayCopy();
+ }
+
+ /**
+ * Get the raw data array of the headers. This array is represented as an
+ * associative array of the various cases that might be stored in the
+ * header and an array of values associated with each case variation.
+ *
+ * @return array
+ */
+ public function raw()
+ {
+ return $this->values;
+ }
+
+ /**
+ * Returns the total number of header values
+ *
+ * @return int
+ */
+ public function count()
+ {
+ return count($this->getIterator());
+ }
+
+ /**
+ * Get an iterator that can be used to easily iterate over each header value
+ *
+ * @return ArrayIterator
+ */
+ public function getIterator()
+ {
+ $result = array();
+ foreach ($this->values as $values) {
+ foreach ($values as $value) {
+ $result[] = $value;
+ }
+ }
+
+ return new \ArrayIterator($result);
+ }
+}
View
67 src/Guzzle/Http/Message/MessageInterface.php
@@ -10,14 +10,23 @@
interface MessageInterface
{
/**
- * Get application and plugin specific parameters set on the message. The
- * return object is a reference to the internal object.
+ * Get application and plugin specific parameters set on the message.
*
* @return Collection
*/
function getParams();
/**
+ * Add a header to an existing collection of headers.
+ *
+ * @param string $header Header name to add
+ * @param string $value Value of the header
+ *
+ * @return MessageInterface
+ */
+ function addHeader($header, $value);
+
+ /**
* Add and merge in an array of HTTP headers.
*
* @param array $headers Associative array of header data.
@@ -27,36 +36,32 @@ function getParams();
function addHeaders(array $headers);
/**
- * Retrieve an HTTP header by name
+ * Retrieve an HTTP header by name. Performs a case-insensitive search of
+ * all headers.
*
* @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
+ * @param bool $string (optional) Set to true to get the header as a string
*
- * @return string|array|null Returns the matching HTTP header value or NULL if the
- * header is not found. If multiple headers are present for the header, then
- * an associative array is returned
+ * @return string|Header|null Returns NULL if no matching header is found.
+ * Returns a string if $string is set to TRUE. Returns a Header object
+ * if a matching header is found.
*/
- function getHeader($header, $default = null, $match = Collection::MATCH_IGNORE_CASE);
+ function getHeader($header, $string = false);
/**
* 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
+ * @param string $token (optional) Token separator
*
- * @return Collection|null
+ * @return Collection|null Returns a Collection object containing the
+ * tokenized values if the header was found. Returns NULL otherwise.
*/
- function getTokenizedHeader($header, $token = ';', $match = Collection::MATCH_IGNORE_CASE);
+ function getTokenizedHeader($header, $token = ';');
/**
* Set a tokenized header on the request that implodes a Collection of data
- * into a string separated by a token
+ * into a string separated by a token.
*
* @param string $header Header to set
* @param array|Collection $data Header data
@@ -71,43 +76,37 @@ function setTokenizedHeader($header, $data, $token = ';');
* 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
+ * only a particular subset of headers.
*
- * @see MessageInterface::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.
+ * @return Collection Returns a {@see Collection} of all headers if no
+ * $headers array is specified, or a Collection of only the headers
+ * matching the headers in the $headers array.
*/
- function getHeaders(array $headers = null, $match = Collection::MATCH_IGNORE_CASE);
+ function getHeaders(array $headers = null);
/**
* Check if the specified header is present.
*
* @param string $header The header to check.
- * @param int $match (optional) Match mode
*
- * @see MessageInterface::getHeader
- * @return bool|mixed Returns TRUE or FALSE if the header is present
+ * @return bool Returns TRUE or FALSE if the header is present
*/
- function hasHeader($header, $match = Collection::MATCH_IGNORE_CASE);
+ function hasHeader($header);
/**
* Remove a specific HTTP header.
*
* @param string $header HTTP header to remove.
- * @param int $match (optional) Bitwise match setting
*
- * @see MessageInterface::getHeader
* @return MessageInterface
*/
- function removeHeader($header, $match = Collection::MATCH_IGNORE_CASE);
+ function removeHeader($header);
/**
* Set an HTTP header
*
* @param string $header Name of the header to set.
- * @param mixed $value Value to set.
+ * @param mixed $value Value to set.
*
* @return MessageInterface
*/
@@ -165,4 +164,4 @@ function addCacheControlDirective($directive, $value);
* @return MessageInterface
*/
function removeCacheControlDirective($directive);
-}
+}
View
88 src/Guzzle/Http/Message/Request.php
@@ -5,8 +5,12 @@
use Guzzle\Guzzle;
use Guzzle\Common\Event;
use Guzzle\Common\Collection;
+use Guzzle\Common\Exception\InvalidArgumentException;
+use Guzzle\Common\Exception\RuntimeException;
+use Guzzle\Http\Exception\RequestException;
+use Guzzle\Http\Exception\CurlException;
+use Guzzle\Http\Exception\BadResponseException;
use Guzzle\Http\ClientInterface;
-use Guzzle\Http\CurlException;
use Guzzle\Http\QueryString;
use Guzzle\Http\Cookie;
use Guzzle\Http\EntityBody;
@@ -116,7 +120,6 @@ public static function getAllEvents()
public function __construct($method, $url, $headers = array())
{
$this->method = strtoupper($method);
- $this->headers = new Collection();
$this->curlOptions = new Collection();
$this->params = new Collection();
$this->setUrl($url);
@@ -126,10 +129,12 @@ public function __construct($method, $url, $headers = array())
foreach ($headers as $key => $value) {
$lkey = strtolower($key);
// Deal with collisions with Host and Authorization
- if ($lkey != 'host' && $lkey != 'authorization') {
- $this->addHeaders(array($key => $value));
- } else {
+ if ($lkey == 'host' || $lkey == 'authorization') {
$this->setHeader($key, $value);
+ } else {
+ foreach ((array) $value as $v) {
+ $this->addHeader($key, $v);
+ }
}
}
}
@@ -153,7 +158,14 @@ public function __clone()
$this->curlOptions = clone $this->curlOptions;
$this->params = clone $this->params;
$this->url = clone $this->url;
- $this->headers = clone $this->headers;
+
+ // Get a clone of the headers
+ $headers = array();
+ foreach ($this->headers as $k => $v) {
+ $headers[$k] = clone $v;
+ }
+ $this->headers = $headers;
+
$this->response = $this->responseBody = null;
$this->params->remove('curl_handle')
->remove('queued_response')
@@ -231,10 +243,7 @@ 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";
- }
+ $raw .= $this->getHeaderString();
return rtrim($raw, "\r\n");
}