Skip to content

Commit dd13842

Browse files
committed
cleanup for PSR-17
1 parent a561739 commit dd13842

12 files changed

+77
-190
lines changed

CHANGELOG.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
# Change Log
22

3-
## Unreleased
3+
## 2.0.0 - Unreleased
44

5+
- Client expects PSR-17 ResponseFactoryInterface and StreamFactoryInterface rather than Httplug factories.
56
- Allow cURL options to overwrite our default spec-compliant default configuration
67

78
## 1.7.1 - 2018-03-36

composer.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "php-http/curl-client",
3-
"description": "PSR-18 cURL client",
3+
"description": "PSR-18 and HTTPlug Async client with cURL",
44
"license": "MIT",
55
"keywords": [
66
"curl",
@@ -19,7 +19,7 @@
1919
"require": {
2020
"php": "^7.1",
2121
"ext-curl": "*",
22-
"php-http/discovery": "^1.0",
22+
"php-http/discovery": "^1.6",
2323
"php-http/httplug": "^2.0",
2424
"php-http/message": "^1.2",
2525
"psr/http-client": "^1.0",

src/Client.php

+30-68
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,15 @@
77
use Http\Client\Exception;
88
use Http\Client\HttpAsyncClient;
99
use Http\Client\HttpClient;
10-
use Http\Discovery\MessageFactoryDiscovery;
11-
use Http\Discovery\StreamFactoryDiscovery;
12-
use Http\Promise\Promise;
10+
use Http\Discovery\Psr17FactoryDiscovery;
1311
use Psr\Http\Message\RequestInterface;
1412
use Psr\Http\Message\ResponseFactoryInterface;
1513
use Psr\Http\Message\ResponseInterface;
1614
use Psr\Http\Message\StreamFactoryInterface;
1715
use Symfony\Component\OptionsResolver\OptionsResolver;
1816

1917
/**
20-
* PSR-7 compatible cURL based HTTP client.
18+
* PSR-18 and HTTPlug Async client based on lib-curl.
2119
*
2220
* @license http://opensource.org/licenses/MIT MIT
2321
* @author Михаил Красильников <[email protected]>
@@ -34,7 +32,7 @@ class Client implements HttpClient, HttpAsyncClient
3432
*
3533
* @var array
3634
*/
37-
private $options;
35+
private $curlOptions;
3836

3937
/**
4038
* PSR-17 response factory.
@@ -65,25 +63,19 @@ class Client implements HttpClient, HttpAsyncClient
6563
private $multiRunner;
6664

6765
/**
68-
* Construct client.
69-
*
7066
* @param ResponseFactoryInterface|null $responseFactory PSR-17 HTTP response factory.
7167
* @param StreamFactoryInterface|null $streamFactory PSR-17 HTTP stream factory.
7268
* @param array $options cURL options {@link http://php.net/curl_setopt}
7369
*
7470
* @throws \Http\Discovery\Exception\NotFoundException If factory discovery failed
75-
*
76-
* @since x.x $messageFactory changed to PSR-17 ResponseFactoryInterface $responseFactory.
77-
* @since x.x $streamFactory type changed to PSR-17 StreamFactoryInterface.
78-
* @since 1.0
7971
*/
8072
public function __construct(
8173
ResponseFactoryInterface $responseFactory = null,
8274
StreamFactoryInterface $streamFactory = null,
8375
array $options = []
8476
) {
85-
$this->responseFactory = $responseFactory; // FIXME ?: MessageFactoryDiscovery::find();
86-
$this->streamFactory = $streamFactory; // FIXME ?: StreamFactoryDiscovery::find();
77+
$this->responseFactory = $responseFactory ?: Psr17FactoryDiscovery::findResponseFactory();
78+
$this->streamFactory = $streamFactory ?: Psr17FactoryDiscovery::findStreamFactory();
8779
$resolver = new OptionsResolver();
8880
$resolver->setDefaults(
8981
[
@@ -99,7 +91,7 @@ public function __construct(
9991
// Make sure that we accept everything that is in the options.
10092
$resolver->setDefined(array_keys($options));
10193

102-
$this->options = $resolver->resolve($options);
94+
$this->curlOptions = $resolver->resolve($options);
10395
}
10496

10597
/**
@@ -113,11 +105,7 @@ public function __destruct()
113105
}
114106

115107
/**
116-
* Sends a PSR-7 request and returns a PSR-7 response.
117-
*
118-
* @param RequestInterface $request
119-
*
120-
* @return ResponseInterface
108+
* {@inheritdoc}
121109
*
122110
* @throws \Http\Client\Exception\NetworkException In case of network problems
123111
* @throws \Http\Client\Exception\RequestException On invalid request
@@ -164,11 +152,7 @@ public function sendRequest(RequestInterface $request): ResponseInterface
164152
}
165153

166154
/**
167-
* Sends a PSR-7 request in an asynchronous way.
168-
*
169-
* @param RequestInterface $request
170-
*
171-
* @return Promise
155+
* {@inheritdoc}
172156
*
173157
* @throws \Http\Client\Exception\RequestException On invalid request
174158
* @throws \InvalidArgumentException For invalid header names or values
@@ -198,36 +182,31 @@ public function sendAsyncRequest(RequestInterface $request)
198182
/**
199183
* Update cURL options for this request and hook in the response builder.
200184
*
201-
* @param RequestInterface $request
202-
* @param ResponseBuilder $responseBuilder
203-
*
204185
* @throws \Http\Client\Exception\RequestException On invalid request
205186
* @throws \InvalidArgumentException For invalid header names or values
206187
* @throws \RuntimeException If can not read body
207-
*
208-
* @return array
209188
*/
210-
private function prepareRequestOptions(RequestInterface $request, ResponseBuilder $responseBuilder)
189+
private function prepareRequestOptions(RequestInterface $request, ResponseBuilder $responseBuilder): array
211190
{
212-
$options = $this->options;
191+
$curlOptions = $this->curlOptions;
213192

214193
try {
215-
$options[CURLOPT_HTTP_VERSION]
194+
$curlOptions[CURLOPT_HTTP_VERSION]
216195
= $this->getProtocolVersion($request->getProtocolVersion());
217196
} catch (\UnexpectedValueException $e) {
218197
throw new Exception\RequestException($e->getMessage(), $request);
219198
}
220-
$options[CURLOPT_URL] = (string) $request->getUri();
199+
$curlOptions[CURLOPT_URL] = (string) $request->getUri();
221200

222-
$options = $this->addRequestBodyOptions($request, $options);
201+
$curlOptions = $this->addRequestBodyOptions($request, $curlOptions);
223202

224-
$options[CURLOPT_HTTPHEADER] = $this->createHeaders($request, $options);
203+
$curlOptions[CURLOPT_HTTPHEADER] = $this->createHeaders($request, $curlOptions);
225204

226205
if ($request->getUri()->getUserInfo()) {
227-
$options[CURLOPT_USERPWD] = $request->getUri()->getUserInfo();
206+
$curlOptions[CURLOPT_USERPWD] = $request->getUri()->getUserInfo();
228207
}
229208

230-
$options[CURLOPT_HEADERFUNCTION] = function ($ch, $data) use ($responseBuilder) {
209+
$curlOptions[CURLOPT_HEADERFUNCTION] = function ($ch, $data) use ($responseBuilder) {
231210
$str = trim($data);
232211
if ('' !== $str) {
233212
if (strpos(strtolower($str), 'http/') === 0) {
@@ -240,21 +219,17 @@ private function prepareRequestOptions(RequestInterface $request, ResponseBuilde
240219
return strlen($data);
241220
};
242221

243-
$options[CURLOPT_WRITEFUNCTION] = function ($ch, $data) use ($responseBuilder) {
222+
$curlOptions[CURLOPT_WRITEFUNCTION] = function ($ch, $data) use ($responseBuilder) {
244223
return $responseBuilder->getResponse()->getBody()->write($data);
245224
};
246225

247-
return $options;
226+
return $curlOptions;
248227
}
249228

250229
/**
251230
* Return cURL constant for specified HTTP version.
252231
*
253-
* @param string $requestVersion
254-
*
255232
* @throws \UnexpectedValueException If unsupported version requested
256-
*
257-
* @return int
258233
*/
259234
private function getProtocolVersion(string $requestVersion): int
260235
{
@@ -275,13 +250,8 @@ private function getProtocolVersion(string $requestVersion): int
275250

276251
/**
277252
* Add request body related cURL options.
278-
*
279-
* @param RequestInterface $request
280-
* @param array $options
281-
*
282-
* @return array
283253
*/
284-
private function addRequestBodyOptions(RequestInterface $request, array $options): array
254+
private function addRequestBodyOptions(RequestInterface $request, array $curlOptions): array
285255
{
286256
/*
287257
* Some HTTP methods cannot have payload:
@@ -302,40 +272,37 @@ private function addRequestBodyOptions(RequestInterface $request, array $options
302272
// Message has non empty body.
303273
if (null === $bodySize || $bodySize > 1024 * 1024) {
304274
// Avoid full loading large or unknown size body into memory
305-
$options[CURLOPT_UPLOAD] = true;
275+
$curlOptions[CURLOPT_UPLOAD] = true;
306276
if (null !== $bodySize) {
307-
$options[CURLOPT_INFILESIZE] = $bodySize;
277+
$curlOptions[CURLOPT_INFILESIZE] = $bodySize;
308278
}
309-
$options[CURLOPT_READFUNCTION] = function ($ch, $fd, $length) use ($body) {
279+
$curlOptions[CURLOPT_READFUNCTION] = function ($ch, $fd, $length) use ($body) {
310280
return $body->read($length);
311281
};
312282
} else {
313283
// Small body can be loaded into memory
314-
$options[CURLOPT_POSTFIELDS] = (string) $body;
284+
$curlOptions[CURLOPT_POSTFIELDS] = (string) $body;
315285
}
316286
}
317287
}
318288

319289
if ($request->getMethod() === 'HEAD') {
320290
// This will set HTTP method to "HEAD".
321-
$options[CURLOPT_NOBODY] = true;
291+
$curlOptions[CURLOPT_NOBODY] = true;
322292
} elseif ($request->getMethod() !== 'GET') {
323293
// GET is a default method. Other methods should be specified explicitly.
324-
$options[CURLOPT_CUSTOMREQUEST] = $request->getMethod();
294+
$curlOptions[CURLOPT_CUSTOMREQUEST] = $request->getMethod();
325295
}
326296

327-
return $options;
297+
return $curlOptions;
328298
}
329299

330300
/**
331301
* Create headers array for CURLOPT_HTTPHEADER.
332302
*
333-
* @param RequestInterface $request
334-
* @param array $options cURL options
335-
*
336303
* @return string[]
337304
*/
338-
private function createHeaders(RequestInterface $request, array $options): array
305+
private function createHeaders(RequestInterface $request, array $curlOptions): array
339306
{
340307
$curlHeaders = [];
341308
$headers = $request->getHeaders();
@@ -346,10 +313,10 @@ private function createHeaders(RequestInterface $request, array $options): array
346313
continue;
347314
}
348315
if ('content-length' === $header) {
349-
if (array_key_exists(CURLOPT_POSTFIELDS, $options)) {
316+
if (array_key_exists(CURLOPT_POSTFIELDS, $curlOptions)) {
350317
// Small body content length can be calculated here.
351-
$values = [strlen($options[CURLOPT_POSTFIELDS])];
352-
} elseif (!array_key_exists(CURLOPT_READFUNCTION, $options)) {
318+
$values = [strlen($curlOptions[CURLOPT_POSTFIELDS])];
319+
} elseif (!array_key_exists(CURLOPT_READFUNCTION, $curlOptions)) {
353320
// Else if there is no body, forcing "Content-length" to 0
354321
$values = [0];
355322
}
@@ -367,11 +334,6 @@ private function createHeaders(RequestInterface $request, array $options): array
367334
return $curlHeaders;
368335
}
369336

370-
/**
371-
* Create new ResponseBuilder instance.
372-
*
373-
* @return ResponseBuilder
374-
*/
375337
private function createResponseBuilder(): ResponseBuilder
376338
{
377339
$body = $this->streamFactory->createStreamFromFile('php://temp', 'w+b');

tests/Functional/HttpAsyncClientDiactorosTest.php

+2-4
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,12 @@
1010
use Zend\Diactoros\StreamFactory;
1111

1212
/**
13-
* Testing asynchronous requests with Zend Diactoros factories.
13+
* @covers \Http\Client\Curl\Client
1414
*/
1515
class HttpAsyncClientDiactorosTest extends HttpAsyncClientTestCase
1616
{
1717
/**
18-
* Create asynchronous HTTP client for tests.
19-
*
20-
* @return HttpAsyncClient
18+
* {@inheritdoc}
2119
*/
2220
protected function createHttpAsyncClient(): HttpAsyncClient
2321
{

tests/Functional/HttpAsyncClientGuzzleTest.php

+2-4
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,12 @@
1010
use Http\Message\StreamFactory\GuzzleStreamFactory;
1111

1212
/**
13-
* Tests for Http\Client\Curl\Client.
13+
* @covers \Http\Client\Curl\Client
1414
*/
1515
class HttpAsyncClientGuzzleTest extends HttpAsyncClientTestCase
1616
{
1717
/**
18-
* Create asynchronious HTTP client for tests.
19-
*
20-
* @return HttpAsyncClient
18+
* {@inheritdoc}
2119
*/
2220
protected function createHttpAsyncClient(): HttpAsyncClient
2321
{

tests/Functional/HttpAsyncClientTestCase.php

+15-25
Original file line numberDiff line numberDiff line change
@@ -12,52 +12,42 @@
1212
abstract class HttpAsyncClientTestCase extends HttpAsyncClientTest
1313
{
1414
/**
15-
* TODO Summary.
16-
*
17-
* @param string $method HTTP method.
18-
* @param string $uri Request URI.
19-
* @param array $headers HTTP headers.
20-
* @param string $body Request body.
15+
* {@inheritdoc}
2116
*
2217
* @dataProvider requestProvider
2318
*/
24-
public function testAsyncSendRequest($method, $uri, array $headers, $body): void
19+
public function testAsyncSendRequest($httpMethod, $uri, array $httpHeaders, $requestBody): void
2520
{
26-
if ($body !== null && in_array($method, ['GET', 'HEAD', 'TRACE'], true)) {
27-
self::markTestSkipped('cURL can not send body using '.$method);
21+
if ($requestBody !== null && in_array($httpMethod, ['GET', 'HEAD', 'TRACE'], true)) {
22+
self::markTestSkipped('cURL can not send body using '.$httpMethod);
2823
}
2924
parent::testAsyncSendRequest(
30-
$method,
25+
$httpMethod,
3126
$uri,
32-
$headers,
33-
$body
27+
$httpHeaders,
28+
$requestBody
3429
);
3530
}
3631

3732
/**
38-
* TODO Summary.
39-
*
40-
* @param array $uriAndOutcome TODO ???
41-
* @param string $protocolVersion HTTP version.
42-
* @param array $headers HTTP headers.
43-
* @param string $body Request body.
33+
* {@inheritdoc}
4434
*
4535
* @dataProvider requestWithOutcomeProvider
4636
*/
4737
public function testSendAsyncRequestWithOutcome(
4838
$uriAndOutcome,
49-
$protocolVersion,
50-
array $headers,
51-
$body
39+
$httpVersion,
40+
array $httpHeaders,
41+
$requestBody
5242
): void {
53-
if ( $body !== null) {
43+
if ( $requestBody !== null) {
5444
self::markTestSkipped('cURL can not send body using GET');
5545
}
5646
parent::testSendAsyncRequestWithOutcome(
5747
$uriAndOutcome,
58-
$protocolVersion,
59-
$headers,
60-
$body
48+
$httpVersion,
49+
$httpHeaders,
50+
$requestBody
6151
);
6252
}
6353
}

0 commit comments

Comments
 (0)