diff --git a/CHANGELOG.md b/CHANGELOG.md index eb86564..233e4d0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Change Log +## 1.0.1 - 2016-01-29 + +### Changed + + - Set the correct header for the Content-Length when in chunked mode. + +## 1.0.0 - 2016-01-28 + ### Added - New Header plugins (see the documentation) @@ -13,6 +21,7 @@ - Decoder plugin no longer sends accept header for encodings that require gzip if gzip is not available + ## 0.1.0 - 2016-01-13 ### Added diff --git a/README.md b/README.md index 604df27..ec184d8 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ $ composer require php-http/plugins ## Documentation -Please see the [official documentation](http://docs.php-http.org). +Please see the [official documentation](http://docs.php-http.org/en/latest/plugins/index.html). ## Testing @@ -38,8 +38,7 @@ Please see our [contributing guide](http://docs.php-http.org/en/latest/developme ## Security -If you discover any security related issues, please contact us at [security@httplug.io](mailto:security@httplug.io) -or [security@php-http.org](mailto:security@php-http.org). +If you discover any security related issues, please contact us at [security@php-http.org](mailto:security@php-http.org). ## License diff --git a/composer.json b/composer.json index 9b5f744..bdfbafb 100644 --- a/composer.json +++ b/composer.json @@ -13,9 +13,7 @@ "require": { "php": ">=5.4", "php-http/httplug": "^1.0", - "php-http/message-factory": "^1.0", - "psr/log": "^1.0", - "psr/cache": "^1.0", + "php-http/message-factory": "^1.0.2", "php-http/client-common": "^1.0", "php-http/message": "^1.0", "symfony/options-resolver": "^2.6|^3.0" @@ -23,7 +21,13 @@ "require-dev": { "symfony/stopwatch": "^2.3", "phpspec/phpspec": "^2.4", - "henrikbjorn/phpspec-code-coverage" : "^1.0" + "henrikbjorn/phpspec-code-coverage" : "^1.0", + "psr/log": "^1.0", + "psr/cache": "^1.0" + }, + "conflict": { + "psr/log": ">=2.0.0", + "psr/cache": ">=2.0.0" }, "autoload": { "psr-4": { @@ -46,9 +50,7 @@ }, "extra": { "branch-alias": { - "dev-master": "0.2-dev" + "dev-master": "1.0-dev" } - }, - "prefer-stable": true, - "minimum-stability": "dev" + } } diff --git a/spec/ContentLengthPluginSpec.php b/spec/ContentLengthPluginSpec.php index 18bf1e0..0fa463f 100644 --- a/spec/ContentLengthPluginSpec.php +++ b/spec/ContentLengthPluginSpec.php @@ -37,6 +37,7 @@ function it_streams_chunked_if_no_size(RequestInterface $request, StreamInterfac $stream->getSize()->shouldBeCalled()->willReturn(null); $request->withBody(Argument::type('Http\Message\Encoding\ChunkStream'))->shouldBeCalled()->willReturn($request); + $request->withAddedHeader('Transfer-Encoding', 'chunked')->shouldBeCalled()->willReturn($request); $this->handleRequest($request, function () {}, function () {}); } diff --git a/spec/CookiePluginSpec.php b/spec/CookiePluginSpec.php index 15c3102..d0c40e2 100644 --- a/spec/CookiePluginSpec.php +++ b/spec/CookiePluginSpec.php @@ -2,15 +2,15 @@ namespace spec\Http\Client\Plugin; -use Http\Promise\FulfilledPromise; use Http\Message\Cookie; use Http\Message\CookieJar; +use Http\Promise\FulfilledPromise; use Http\Promise\Promise; +use PhpSpec\ObjectBehavior; +use Prophecy\Argument; use Psr\Http\Message\RequestInterface; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\UriInterface; -use PhpSpec\ObjectBehavior; -use Prophecy\Argument; class CookiePluginSpec extends ObjectBehavior { @@ -146,7 +146,7 @@ function it_saves_cookie(RequestInterface $request, ResponseInterface $response, $response->hasHeader('Set-Cookie')->willReturn(true); $response->getHeader('Set-Cookie')->willReturn([ - 'cookie=value', + 'cookie=value; expires=Tuesday, 31-Mar-99 07:42:12 GMT; Max-Age=60; path=/; domain=test.com; secure; HttpOnly' ]); $request->getUri()->willReturn($uri); @@ -157,4 +157,24 @@ function it_saves_cookie(RequestInterface $request, ResponseInterface $response, $promise->shouldHaveType('Http\Promise\Promise'); $promise->wait()->shouldReturnAnInstanceOf('Psr\Http\Message\ResponseInterface'); } + + function it_throws_exception_on_invalid_expires_date(RequestInterface $request, ResponseInterface $response, UriInterface $uri) + { + $next = function () use ($response) { + return new FulfilledPromise($response->getWrappedObject()); + }; + + $response->hasHeader('Set-Cookie')->willReturn(true); + $response->getHeader('Set-Cookie')->willReturn([ + 'cookie=value; expires=i-am-an-invalid-date;' + ]); + + $request->getUri()->willReturn($uri); + $uri->getHost()->willReturn('test.com'); + $uri->getPath()->willReturn('/'); + + $promise = $this->handleRequest($request, $next, function () {}); + $promise->shouldReturnAnInstanceOf('Http\Promise\RejectedPromise'); + $promise->shouldThrow('Http\Client\Exception\TransferException')->duringWait(); + } } diff --git a/src/ContentLengthPlugin.php b/src/ContentLengthPlugin.php index 843f524..068d65e 100644 --- a/src/ContentLengthPlugin.php +++ b/src/ContentLengthPlugin.php @@ -24,6 +24,7 @@ public function handleRequest(RequestInterface $request, callable $next, callabl if (null === $stream->getSize()) { $stream = new ChunkStream($stream); $request = $request->withBody($stream); + $request = $request->withAddedHeader('Transfer-Encoding', 'chunked'); } else { $request = $request->withHeader('Content-Length', $stream->getSize()); } diff --git a/src/CookiePlugin.php b/src/CookiePlugin.php index 71b56b2..6e222ab 100644 --- a/src/CookiePlugin.php +++ b/src/CookiePlugin.php @@ -2,6 +2,7 @@ namespace Http\Client\Plugin; +use Http\Client\Exception\TransferException; use Http\Message\Cookie; use Http\Message\CookieJar; use Psr\Http\Message\RequestInterface; @@ -86,6 +87,8 @@ public function handleRequest(RequestInterface $request, callable $next, callabl * @param $setCookie * * @return Cookie|null + * + * @throws \Http\Client\Exception\TransferException */ private function createCookie(RequestInterface $request, $setCookie) { @@ -97,7 +100,8 @@ private function createCookie(RequestInterface $request, $setCookie) list($name, $cookieValue) = $this->createValueKey(array_shift($parts)); - $expires = 0; + $maxAge = null; + $expires = null; $domain = $request->getUri()->getHost(); $path = $request->getUri()->getPath(); $secure = false; @@ -109,11 +113,22 @@ private function createCookie(RequestInterface $request, $setCookie) switch (strtolower($key)) { case 'expires': - $expires = \DateTime::createFromFormat(DATE_COOKIE, $value); + $expires = \DateTime::createFromFormat(\DateTime::COOKIE, $value); + + if (true !== ($expires instanceof \DateTime)) { + throw new TransferException( + sprintf( + 'Cookie header `%s` expires value `%s` could not be converted to date', + $name, + $value + ) + ); + } + break; case 'max-age': - $expires = (new \DateTime())->add(new \DateInterval('PT'.(int) $value.'S')); + $maxAge = (int) $value; break; case 'domain': @@ -134,7 +149,7 @@ private function createCookie(RequestInterface $request, $setCookie) } } - return new Cookie($name, $cookieValue, $expires, $domain, $path, $secure, $httpOnly); + return new Cookie($name, $cookieValue, $maxAge, $domain, $path, $secure, $httpOnly, $expires); } /**