From 28674b1e3065bb344813d72e13f6b68f23410481 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 10 Jun 2019 13:49:36 +0200 Subject: [PATCH] [HttpClient] add HttplugClient for compat with libs that need httplug v1 or v2 --- composer.json | 1 + src/Symfony/Component/HttpClient/CHANGELOG.md | 2 +- .../Component/HttpClient/HttplugClient.php | 120 ++++++++++++++++++ .../HttpClient/Tests/HttplugClientTest.php | 72 +++++++++++ .../Component/HttpClient/composer.json | 2 + 5 files changed, 196 insertions(+), 1 deletion(-) create mode 100644 src/Symfony/Component/HttpClient/HttplugClient.php create mode 100644 src/Symfony/Component/HttpClient/Tests/HttplugClientTest.php diff --git a/composer.json b/composer.json index c1cdc5ca183ab..59ac37563495a 100644 --- a/composer.json +++ b/composer.json @@ -111,6 +111,7 @@ "monolog/monolog": "~1.11", "nyholm/psr7": "^1.0", "ocramius/proxy-manager": "^2.1", + "php-http/httplug": "^1.0|^2.0", "predis/predis": "~1.1", "psr/http-client": "^1.0", "psr/simple-cache": "^1.0", diff --git a/src/Symfony/Component/HttpClient/CHANGELOG.md b/src/Symfony/Component/HttpClient/CHANGELOG.md index bd11e9ef0d64c..b2f900bf39b96 100644 --- a/src/Symfony/Component/HttpClient/CHANGELOG.md +++ b/src/Symfony/Component/HttpClient/CHANGELOG.md @@ -5,7 +5,7 @@ CHANGELOG ----- * made `Psr18Client` implement relevant PSR-17 factories - * added `$response->cancel()` + * added `HttplugClient` 4.3.0 ----- diff --git a/src/Symfony/Component/HttpClient/HttplugClient.php b/src/Symfony/Component/HttpClient/HttplugClient.php new file mode 100644 index 0000000000000..6c612ce13ceb2 --- /dev/null +++ b/src/Symfony/Component/HttpClient/HttplugClient.php @@ -0,0 +1,120 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient; + +use Http\Client\Exception\NetworkException; +use Http\Client\Exception\RequestException; +use Http\Client\HttpClient; +use Http\Message\RequestFactory; +use Http\Message\StreamFactory; +use Http\Message\UriFactory; +use Psr\Http\Client\ClientInterface; +use Psr\Http\Client\NetworkExceptionInterface; +use Psr\Http\Client\RequestExceptionInterface; +use Psr\Http\Message\RequestInterface; +use Psr\Http\Message\ResponseFactoryInterface; +use Psr\Http\Message\ResponseInterface; +use Psr\Http\Message\StreamFactoryInterface; +use Psr\Http\Message\StreamInterface; +use Psr\Http\Message\UriInterface; +use Symfony\Contracts\HttpClient\HttpClientInterface; + +if (!interface_exists(HttpClient::class)) { + throw new \LogicException('You cannot use "Symfony\Component\HttpClient\HttplugClient" as the "php-http/httplug" package is not installed. Try running "composer require php-http/httplug".'); +} + +if (!interface_exists(ClientInterface::class)) { + throw new \LogicException('You cannot use "Symfony\Component\HttpClient\HttplugClient" as the "psr/http-client" package is not installed. Try running "composer require psr/http-client".'); +} + +if (!interface_exists(RequestFactory::class)) { + throw new \LogicException('You cannot use "Symfony\Component\HttpClient\HttplugClient" as the "php-http/message-factory" package is not installed. Try running "composer require nyholm/psr7".'); +} + +/** + * An adapter to turn a Symfony HttpClientInterface into an Httplug client. + * + * Run "composer require psr/http-client" to install the base ClientInterface. Run + * "composer require nyholm/psr7" to install an efficient implementation of response + * and stream factories with flex-provided autowiring aliases. + * + * @author Nicolas Grekas + */ +final class HttplugClient implements HttpClient, RequestFactory, StreamFactory, UriFactory +{ + private $client; + + public function __construct(HttpClientInterface $client = null, ResponseFactoryInterface $responseFactory = null, StreamFactoryInterface $streamFactory = null) + { + $this->client = new Psr18Client($client, $responseFactory, $streamFactory); + } + + /** + * {@inheritdoc} + */ + public function sendRequest(RequestInterface $request): ResponseInterface + { + try { + return $this->client->sendRequest($request); + } catch (RequestExceptionInterface $e) { + throw new RequestException($e->getMessage(), $request, $e); + } catch (NetworkExceptionInterface $e) { + throw new NetworkException($e->getMessage(), $request, $e); + } + } + + /** + * {@inheritdoc} + */ + public function createRequest($method, $uri, array $headers = [], $body = null, $protocolVersion = '1.1'): RequestInterface + { + $request = $this->client + ->createRequest($method, $uri) + ->withProtocolVersion($protocolVersion) + ->withBody($this->createStream($body)) + ; + + foreach ($headers as $name => $value) { + $request = $request->withAddedHeader($name, $value); + } + + return $request; + } + + /** + * {@inheritdoc} + */ + public function createStream($body = null): StreamInterface + { + if ($body instanceof StreamInterface) { + return $body; + } + + if (\is_string($body ?? '')) { + return $this->client->createStream($body ?? ''); + } + + if (\is_resource($body)) { + return $this->client->createStreamFromResource($body); + } + + throw new \InvalidArgumentException(sprintf('%s() expects string, resource or StreamInterface, %s given.', __METHOD__, \gettype($body))); + } + + /** + * {@inheritdoc} + */ + public function createUri($uri = ''): UriInterface + { + return $uri instanceof UriInterface ? $uri : $this->client->createUri($uri); + } +} diff --git a/src/Symfony/Component/HttpClient/Tests/HttplugClientTest.php b/src/Symfony/Component/HttpClient/Tests/HttplugClientTest.php new file mode 100644 index 0000000000000..4f3e92d3e1ccf --- /dev/null +++ b/src/Symfony/Component/HttpClient/Tests/HttplugClientTest.php @@ -0,0 +1,72 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient\Tests; + +use Http\Client\Exception\NetworkException; +use Http\Client\Exception\RequestException; +use PHPUnit\Framework\TestCase; +use Symfony\Component\HttpClient\HttplugClient; +use Symfony\Component\HttpClient\NativeHttpClient; +use Symfony\Contracts\HttpClient\Test\TestHttpServer; + +class HttplugClientTest extends TestCase +{ + private static $server; + + public static function setUpBeforeClass() + { + TestHttpServer::start(); + } + + public function testSendRequest() + { + $client = new HttplugClient(new NativeHttpClient()); + + $response = $client->sendRequest($client->createRequest('GET', 'http://localhost:8057')); + + $this->assertSame(200, $response->getStatusCode()); + $this->assertSame('application/json', $response->getHeaderLine('content-type')); + + $body = json_decode((string) $response->getBody(), true); + + $this->assertSame('HTTP/1.1', $body['SERVER_PROTOCOL']); + } + + public function testPostRequest() + { + $client = new HttplugClient(new NativeHttpClient()); + + $request = $client->createRequest('POST', 'http://localhost:8057/post') + ->withBody($client->createStream('foo=0123456789')); + + $response = $client->sendRequest($request); + $body = json_decode((string) $response->getBody(), true); + + $this->assertSame(['foo' => '0123456789', 'REQUEST_METHOD' => 'POST'], $body); + } + + public function testNetworkException() + { + $client = new HttplugClient(new NativeHttpClient()); + + $this->expectException(NetworkException::class); + $client->sendRequest($client->createRequest('GET', 'http://localhost:8058')); + } + + public function testRequestException() + { + $client = new HttplugClient(new NativeHttpClient()); + + $this->expectException(RequestException::class); + $client->sendRequest($client->createRequest('BAD.METHOD', 'http://localhost:8057')); + } +} diff --git a/src/Symfony/Component/HttpClient/composer.json b/src/Symfony/Component/HttpClient/composer.json index 98dd63d85e2b7..561061087ca69 100644 --- a/src/Symfony/Component/HttpClient/composer.json +++ b/src/Symfony/Component/HttpClient/composer.json @@ -15,6 +15,7 @@ } ], "provide": { + "php-http/client-implementation": "*", "psr/http-client-implementation": "1.0", "symfony/http-client-implementation": "1.1" }, @@ -26,6 +27,7 @@ }, "require-dev": { "nyholm/psr7": "^1.0", + "php-http/httplug": "^1.0|^2.0", "psr/http-client": "^1.0", "symfony/http-kernel": "^4.3|^5.0", "symfony/process": "^4.2|^5.0" pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy