Skip to content

Commit beb803a

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

12 files changed

+77
-187
lines changed

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
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

Lines changed: 2 additions & 2 deletions
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

Lines changed: 30 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use Http\Client\HttpAsyncClient;
99
use Http\Client\HttpClient;
1010
use Http\Discovery\MessageFactoryDiscovery;
11+
use Http\Discovery\Psr17FactoryDiscovery;
1112
use Http\Discovery\StreamFactoryDiscovery;
1213
use Http\Promise\Promise;
1314
use Psr\Http\Message\RequestInterface;
@@ -17,7 +18,7 @@
1718
use Symfony\Component\OptionsResolver\OptionsResolver;
1819

1920
/**
20-
* PSR-7 compatible cURL based HTTP client.
21+
* PSR-18 and HTTPlug Async client based on lib-curl.
2122
*
2223
* @license http://opensource.org/licenses/MIT MIT
2324
* @author Михаил Красильников <[email protected]>
@@ -34,7 +35,7 @@ class Client implements HttpClient, HttpAsyncClient
3435
*
3536
* @var array
3637
*/
37-
private $options;
38+
private $curlOptions;
3839

3940
/**
4041
* PSR-17 response factory.
@@ -65,25 +66,19 @@ class Client implements HttpClient, HttpAsyncClient
6566
private $multiRunner;
6667

6768
/**
68-
* Construct client.
69-
*
7069
* @param ResponseFactoryInterface|null $responseFactory PSR-17 HTTP response factory.
7170
* @param StreamFactoryInterface|null $streamFactory PSR-17 HTTP stream factory.
7271
* @param array $options cURL options {@link http://php.net/curl_setopt}
7372
*
7473
* @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
7974
*/
8075
public function __construct(
8176
ResponseFactoryInterface $responseFactory = null,
8277
StreamFactoryInterface $streamFactory = null,
8378
array $options = []
8479
) {
85-
$this->responseFactory = $responseFactory; // FIXME ?: MessageFactoryDiscovery::find();
86-
$this->streamFactory = $streamFactory; // FIXME ?: StreamFactoryDiscovery::find();
80+
$this->responseFactory = $responseFactory ?: Psr17FactoryDiscovery::findResponseFactory();
81+
$this->streamFactory = $streamFactory ?: Psr17FactoryDiscovery::findStreamFactory();
8782
$resolver = new OptionsResolver();
8883
$resolver->setDefaults(
8984
[
@@ -99,7 +94,7 @@ public function __construct(
9994
// Make sure that we accept everything that is in the options.
10095
$resolver->setDefined(array_keys($options));
10196

102-
$this->options = $resolver->resolve($options);
97+
$this->curlOptions = $resolver->resolve($options);
10398
}
10499

105100
/**
@@ -113,11 +108,7 @@ public function __destruct()
113108
}
114109

115110
/**
116-
* Sends a PSR-7 request and returns a PSR-7 response.
117-
*
118-
* @param RequestInterface $request
119-
*
120-
* @return ResponseInterface
111+
* {@inheritdoc}
121112
*
122113
* @throws \Http\Client\Exception\NetworkException In case of network problems
123114
* @throws \Http\Client\Exception\RequestException On invalid request
@@ -164,11 +155,7 @@ public function sendRequest(RequestInterface $request): ResponseInterface
164155
}
165156

166157
/**
167-
* Sends a PSR-7 request in an asynchronous way.
168-
*
169-
* @param RequestInterface $request
170-
*
171-
* @return Promise
158+
* {@inheritdoc}
172159
*
173160
* @throws \Http\Client\Exception\RequestException On invalid request
174161
* @throws \InvalidArgumentException For invalid header names or values
@@ -198,36 +185,31 @@ public function sendAsyncRequest(RequestInterface $request)
198185
/**
199186
* Update cURL options for this request and hook in the response builder.
200187
*
201-
* @param RequestInterface $request
202-
* @param ResponseBuilder $responseBuilder
203-
*
204188
* @throws \Http\Client\Exception\RequestException On invalid request
205189
* @throws \InvalidArgumentException For invalid header names or values
206190
* @throws \RuntimeException If can not read body
207-
*
208-
* @return array
209191
*/
210-
private function prepareRequestOptions(RequestInterface $request, ResponseBuilder $responseBuilder)
192+
private function prepareRequestOptions(RequestInterface $request, ResponseBuilder $responseBuilder): array
211193
{
212-
$options = $this->options;
194+
$curlOptions = $this->curlOptions;
213195

214196
try {
215-
$options[CURLOPT_HTTP_VERSION]
197+
$curlOptions[CURLOPT_HTTP_VERSION]
216198
= $this->getProtocolVersion($request->getProtocolVersion());
217199
} catch (\UnexpectedValueException $e) {
218200
throw new Exception\RequestException($e->getMessage(), $request);
219201
}
220-
$options[CURLOPT_URL] = (string) $request->getUri();
202+
$curlOptions[CURLOPT_URL] = (string) $request->getUri();
221203

222-
$options = $this->addRequestBodyOptions($request, $options);
204+
$curlOptions = $this->addRequestBodyOptions($request, $curlOptions);
223205

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

226208
if ($request->getUri()->getUserInfo()) {
227-
$options[CURLOPT_USERPWD] = $request->getUri()->getUserInfo();
209+
$curlOptions[CURLOPT_USERPWD] = $request->getUri()->getUserInfo();
228210
}
229211

230-
$options[CURLOPT_HEADERFUNCTION] = function ($ch, $data) use ($responseBuilder) {
212+
$curlOptions[CURLOPT_HEADERFUNCTION] = function ($ch, $data) use ($responseBuilder) {
231213
$str = trim($data);
232214
if ('' !== $str) {
233215
if (strpos(strtolower($str), 'http/') === 0) {
@@ -240,21 +222,17 @@ private function prepareRequestOptions(RequestInterface $request, ResponseBuilde
240222
return strlen($data);
241223
};
242224

243-
$options[CURLOPT_WRITEFUNCTION] = function ($ch, $data) use ($responseBuilder) {
225+
$curlOptions[CURLOPT_WRITEFUNCTION] = function ($ch, $data) use ($responseBuilder) {
244226
return $responseBuilder->getResponse()->getBody()->write($data);
245227
};
246228

247-
return $options;
229+
return $curlOptions;
248230
}
249231

250232
/**
251233
* Return cURL constant for specified HTTP version.
252234
*
253-
* @param string $requestVersion
254-
*
255235
* @throws \UnexpectedValueException If unsupported version requested
256-
*
257-
* @return int
258236
*/
259237
private function getProtocolVersion(string $requestVersion): int
260238
{
@@ -275,13 +253,8 @@ private function getProtocolVersion(string $requestVersion): int
275253

276254
/**
277255
* Add request body related cURL options.
278-
*
279-
* @param RequestInterface $request
280-
* @param array $options
281-
*
282-
* @return array
283256
*/
284-
private function addRequestBodyOptions(RequestInterface $request, array $options): array
257+
private function addRequestBodyOptions(RequestInterface $request, array $curlOptions): array
285258
{
286259
/*
287260
* Some HTTP methods cannot have payload:
@@ -302,40 +275,37 @@ private function addRequestBodyOptions(RequestInterface $request, array $options
302275
// Message has non empty body.
303276
if (null === $bodySize || $bodySize > 1024 * 1024) {
304277
// Avoid full loading large or unknown size body into memory
305-
$options[CURLOPT_UPLOAD] = true;
278+
$curlOptions[CURLOPT_UPLOAD] = true;
306279
if (null !== $bodySize) {
307-
$options[CURLOPT_INFILESIZE] = $bodySize;
280+
$curlOptions[CURLOPT_INFILESIZE] = $bodySize;
308281
}
309-
$options[CURLOPT_READFUNCTION] = function ($ch, $fd, $length) use ($body) {
282+
$curlOptions[CURLOPT_READFUNCTION] = function ($ch, $fd, $length) use ($body) {
310283
return $body->read($length);
311284
};
312285
} else {
313286
// Small body can be loaded into memory
314-
$options[CURLOPT_POSTFIELDS] = (string) $body;
287+
$curlOptions[CURLOPT_POSTFIELDS] = (string) $body;
315288
}
316289
}
317290
}
318291

319292
if ($request->getMethod() === 'HEAD') {
320293
// This will set HTTP method to "HEAD".
321-
$options[CURLOPT_NOBODY] = true;
294+
$curlOptions[CURLOPT_NOBODY] = true;
322295
} elseif ($request->getMethod() !== 'GET') {
323296
// GET is a default method. Other methods should be specified explicitly.
324-
$options[CURLOPT_CUSTOMREQUEST] = $request->getMethod();
297+
$curlOptions[CURLOPT_CUSTOMREQUEST] = $request->getMethod();
325298
}
326299

327-
return $options;
300+
return $curlOptions;
328301
}
329302

330303
/**
331304
* Create headers array for CURLOPT_HTTPHEADER.
332305
*
333-
* @param RequestInterface $request
334-
* @param array $options cURL options
335-
*
336306
* @return string[]
337307
*/
338-
private function createHeaders(RequestInterface $request, array $options): array
308+
private function createHeaders(RequestInterface $request, array $curlOptions): array
339309
{
340310
$curlHeaders = [];
341311
$headers = $request->getHeaders();
@@ -346,10 +316,10 @@ private function createHeaders(RequestInterface $request, array $options): array
346316
continue;
347317
}
348318
if ('content-length' === $header) {
349-
if (array_key_exists(CURLOPT_POSTFIELDS, $options)) {
319+
if (array_key_exists(CURLOPT_POSTFIELDS, $curlOptions)) {
350320
// Small body content length can be calculated here.
351-
$values = [strlen($options[CURLOPT_POSTFIELDS])];
352-
} elseif (!array_key_exists(CURLOPT_READFUNCTION, $options)) {
321+
$values = [strlen($curlOptions[CURLOPT_POSTFIELDS])];
322+
} elseif (!array_key_exists(CURLOPT_READFUNCTION, $curlOptions)) {
353323
// Else if there is no body, forcing "Content-length" to 0
354324
$values = [0];
355325
}
@@ -367,11 +337,6 @@ private function createHeaders(RequestInterface $request, array $options): array
367337
return $curlHeaders;
368338
}
369339

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

tests/Functional/HttpAsyncClientDiactorosTest.php

Lines changed: 2 additions & 4 deletions
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

Lines changed: 2 additions & 4 deletions
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

Lines changed: 15 additions & 25 deletions
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)