From 89ff8c2feec2a1786d8e2008c9b6e1ed52d480ae Mon Sep 17 00:00:00 2001 From: Lee Boynton Date: Wed, 6 Jul 2016 10:23:04 +0100 Subject: [PATCH] Add support for using Buzz\Browser instance (fixes #2) This change allows instances of Buzz\Browser to be used in the adapater, which is what people generally use with Buzz. Also allow any instance implementing Buzz's ClientInterface to be used, such as the curl implementation. Note that: - MultiCurl does not work at this time as it needs to be flushed to send requests. - The Curl client does not apply request bodies to certain request methods such as GET, HEAD and TRACE. In order to inform users about this, we throw an exception if the Curl client is being used, and we're trying to send a request body with one of these methods. --- composer.json | 1 + src/Client.php | 57 ++++++++++++++++++++-- tests/BrowserHttpAdapterTest.php | 20 ++++++++ tests/CurlHttpAdapterTest.php | 61 ++++++++++++++++++++++++ tests/DefaultHttpAdapterTest.php | 15 ++++++ tests/FileGetContentsHttpAdapterTest.php | 5 +- tests/InvalidHttpAdapterTest.php | 35 ++++++++++++++ 7 files changed, 188 insertions(+), 6 deletions(-) create mode 100644 tests/BrowserHttpAdapterTest.php create mode 100644 tests/CurlHttpAdapterTest.php create mode 100644 tests/DefaultHttpAdapterTest.php create mode 100644 tests/InvalidHttpAdapterTest.php diff --git a/composer.json b/composer.json index 57e7797..40e2488 100644 --- a/composer.json +++ b/composer.json @@ -17,6 +17,7 @@ "php-http/discovery": "^0.9" }, "require-dev": { + "ext-curl": "*", "php-http/adapter-integration-tests": "^0.3", "php-http/client-common": "^1.0", "guzzlehttp/psr7": "^1.2", diff --git a/src/Client.php b/src/Client.php index 5fb27d7..be92f83 100644 --- a/src/Client.php +++ b/src/Client.php @@ -2,10 +2,13 @@ namespace Http\Adapter\Buzz; +use Buzz\Browser; use Buzz\Client\ClientInterface; +use Buzz\Client\Curl; use Buzz\Client\FileGetContents; use Buzz\Exception as BuzzException; use Buzz\Message\Request as BuzzRequest; +use Buzz\Message\RequestInterface as BuzzRequestInterface; use Buzz\Message\Response as BuzzResponse; use Http\Client\HttpClient; use Http\Discovery\MessageFactoryDiscovery; @@ -30,13 +33,28 @@ class Client implements HttpClient private $messageFactory; /** - * @param FileGetContents|null $client - * @param MessageFactory|null $messageFactory + * @param ClientInterface|Browser|null $client + * @param MessageFactory|null $messageFactory */ - public function __construct(FileGetContents $client = null, MessageFactory $messageFactory = null) + public function __construct($client = null, MessageFactory $messageFactory = null) { - $this->client = $client ?: new FileGetContents(); - $this->client->setMaxRedirects(0); + $this->client = $client; + + if ($this->client === null) { + $this->client = new FileGetContents(); + $this->client->setMaxRedirects(0); + } + + if ((!$this->client instanceof ClientInterface) && (!$this->client instanceof Browser)) { + throw new \InvalidArgumentException( + sprintf( + 'The client passed to the Buzz adapter must either implement %s or be an instance of %s. You passed %s.', + ClientInterface::class, + Browser::class, + is_object($client) ? get_class($client) : gettype($client) + ) + ); + } $this->messageFactory = $messageFactory ?: MessageFactoryDiscovery::find(); } @@ -46,6 +64,8 @@ public function __construct(FileGetContents $client = null, MessageFactory $mess */ public function sendRequest(RequestInterface $request) { + $this->assertRequestHasValidBody($request); + $buzzRequest = $this->createRequest($request); try { @@ -133,4 +153,31 @@ private function getBuzzHeaders(BuzzResponse $response) return $headers; } + + /** + * Assert that the request has a valid body based on the request method. + * + * @param RequestInterface $request + */ + private function assertRequestHasValidBody(RequestInterface $request) + { + $validMethods = [ + BuzzRequestInterface::METHOD_POST, + BuzzRequestInterface::METHOD_PUT, + BuzzRequestInterface::METHOD_DELETE, + BuzzRequestInterface::METHOD_PATCH, + BuzzRequestInterface::METHOD_OPTIONS, + ]; + + // The Buzz Curl client does not send request bodies for request methods such as GET, HEAD and TRACE. Instead of + // silently ignoring the request body in these cases, throw an exception to make users aware. + if ($this->client instanceof Curl && + $request->getBody()->getSize() && + !in_array(strtoupper($request->getMethod()), $validMethods, true) + ) { + throw new \InvalidArgumentException( + sprintf('%s does not support %s requests with a body', Curl::class, $request->getMethod()) + ); + } + } } diff --git a/tests/BrowserHttpAdapterTest.php b/tests/BrowserHttpAdapterTest.php new file mode 100644 index 0000000..8dd3013 --- /dev/null +++ b/tests/BrowserHttpAdapterTest.php @@ -0,0 +1,20 @@ +getClient()->setMaxRedirects(0); + + return $browser; + } +} diff --git a/tests/CurlHttpAdapterTest.php b/tests/CurlHttpAdapterTest.php new file mode 100644 index 0000000..e437fd6 --- /dev/null +++ b/tests/CurlHttpAdapterTest.php @@ -0,0 +1,61 @@ +setMaxRedirects(0); + + return $curl; + } + + /** + * @dataProvider requestProvider + * @group integration + */ + public function testSendRequest($method, $uri, array $headers, $body) + { + $validMethods = [ + BuzzRequestInterface::METHOD_POST, + BuzzRequestInterface::METHOD_PUT, + BuzzRequestInterface::METHOD_DELETE, + BuzzRequestInterface::METHOD_PATCH, + BuzzRequestInterface::METHOD_OPTIONS, + ]; + + if (!in_array($method, $validMethods, true) && $body) { + $this->setExpectedException( + \InvalidArgumentException::class, + sprintf('Buzz\Client\Curl does not support %s requests with a body', $method) + ); + } + + parent::testSendRequest($method, $uri, $headers, $body); + } + + /** + * @dataProvider requestWithOutcomeProvider + * @group integration + */ + public function testSendRequestWithOutcome($uriAndOutcome, $protocolVersion, array $headers, $body) + { + if ($body && $protocolVersion === '1.1') { + $this->setExpectedException( + \InvalidArgumentException::class, + 'Buzz\Client\Curl does not support GET requests with a body' + ); + } + + parent::testSendRequestWithOutcome($uriAndOutcome, $protocolVersion, $headers, $body); + } +} diff --git a/tests/DefaultHttpAdapterTest.php b/tests/DefaultHttpAdapterTest.php new file mode 100644 index 0000000..2ef75e1 --- /dev/null +++ b/tests/DefaultHttpAdapterTest.php @@ -0,0 +1,15 @@ +setMaxRedirects(0); + + return $fileGetContents; } } diff --git a/tests/InvalidHttpAdapterTest.php b/tests/InvalidHttpAdapterTest.php new file mode 100644 index 0000000..18b15b5 --- /dev/null +++ b/tests/InvalidHttpAdapterTest.php @@ -0,0 +1,35 @@ +