8
8
use Http \Client \HttpAsyncClient ;
9
9
use Http \Client \HttpClient ;
10
10
use Http \Discovery \MessageFactoryDiscovery ;
11
+ use Http \Discovery \Psr17FactoryDiscovery ;
11
12
use Http \Discovery \StreamFactoryDiscovery ;
12
13
use Http \Promise \Promise ;
13
14
use Psr \Http \Message \RequestInterface ;
17
18
use Symfony \Component \OptionsResolver \OptionsResolver ;
18
19
19
20
/**
20
- * PSR-7 compatible cURL based HTTP client .
21
+ * PSR-18 and HTTPlug Async client based on lib-curl .
21
22
*
22
23
* @license http://opensource.org/licenses/MIT MIT
23
24
* @author Михаил Красильников <[email protected] >
@@ -34,7 +35,7 @@ class Client implements HttpClient, HttpAsyncClient
34
35
*
35
36
* @var array
36
37
*/
37
- private $ options ;
38
+ private $ curlOptions ;
38
39
39
40
/**
40
41
* PSR-17 response factory.
@@ -65,25 +66,19 @@ class Client implements HttpClient, HttpAsyncClient
65
66
private $ multiRunner ;
66
67
67
68
/**
68
- * Construct client.
69
- *
70
69
* @param ResponseFactoryInterface|null $responseFactory PSR-17 HTTP response factory.
71
70
* @param StreamFactoryInterface|null $streamFactory PSR-17 HTTP stream factory.
72
71
* @param array $options cURL options {@link http://php.net/curl_setopt}
73
72
*
74
73
* @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
79
74
*/
80
75
public function __construct (
81
76
ResponseFactoryInterface $ responseFactory = null ,
82
77
StreamFactoryInterface $ streamFactory = null ,
83
78
array $ options = []
84
79
) {
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 ();
87
82
$ resolver = new OptionsResolver ();
88
83
$ resolver ->setDefaults (
89
84
[
@@ -99,7 +94,7 @@ public function __construct(
99
94
// Make sure that we accept everything that is in the options.
100
95
$ resolver ->setDefined (array_keys ($ options ));
101
96
102
- $ this ->options = $ resolver ->resolve ($ options );
97
+ $ this ->curlOptions = $ resolver ->resolve ($ options );
103
98
}
104
99
105
100
/**
@@ -113,11 +108,7 @@ public function __destruct()
113
108
}
114
109
115
110
/**
116
- * Sends a PSR-7 request and returns a PSR-7 response.
117
- *
118
- * @param RequestInterface $request
119
- *
120
- * @return ResponseInterface
111
+ * {@inheritdoc}
121
112
*
122
113
* @throws \Http\Client\Exception\NetworkException In case of network problems
123
114
* @throws \Http\Client\Exception\RequestException On invalid request
@@ -164,11 +155,7 @@ public function sendRequest(RequestInterface $request): ResponseInterface
164
155
}
165
156
166
157
/**
167
- * Sends a PSR-7 request in an asynchronous way.
168
- *
169
- * @param RequestInterface $request
170
- *
171
- * @return Promise
158
+ * {@inheritdoc}
172
159
*
173
160
* @throws \Http\Client\Exception\RequestException On invalid request
174
161
* @throws \InvalidArgumentException For invalid header names or values
@@ -198,36 +185,31 @@ public function sendAsyncRequest(RequestInterface $request)
198
185
/**
199
186
* Update cURL options for this request and hook in the response builder.
200
187
*
201
- * @param RequestInterface $request
202
- * @param ResponseBuilder $responseBuilder
203
- *
204
188
* @throws \Http\Client\Exception\RequestException On invalid request
205
189
* @throws \InvalidArgumentException For invalid header names or values
206
190
* @throws \RuntimeException If can not read body
207
- *
208
- * @return array
209
191
*/
210
- private function prepareRequestOptions (RequestInterface $ request , ResponseBuilder $ responseBuilder )
192
+ private function prepareRequestOptions (RequestInterface $ request , ResponseBuilder $ responseBuilder ): array
211
193
{
212
- $ options = $ this ->options ;
194
+ $ curlOptions = $ this ->curlOptions ;
213
195
214
196
try {
215
- $ options [CURLOPT_HTTP_VERSION ]
197
+ $ curlOptions [CURLOPT_HTTP_VERSION ]
216
198
= $ this ->getProtocolVersion ($ request ->getProtocolVersion ());
217
199
} catch (\UnexpectedValueException $ e ) {
218
200
throw new Exception \RequestException ($ e ->getMessage (), $ request );
219
201
}
220
- $ options [CURLOPT_URL ] = (string ) $ request ->getUri ();
202
+ $ curlOptions [CURLOPT_URL ] = (string ) $ request ->getUri ();
221
203
222
- $ options = $ this ->addRequestBodyOptions ($ request , $ options );
204
+ $ curlOptions = $ this ->addRequestBodyOptions ($ request , $ curlOptions );
223
205
224
- $ options [CURLOPT_HTTPHEADER ] = $ this ->createHeaders ($ request , $ options );
206
+ $ curlOptions [CURLOPT_HTTPHEADER ] = $ this ->createHeaders ($ request , $ curlOptions );
225
207
226
208
if ($ request ->getUri ()->getUserInfo ()) {
227
- $ options [CURLOPT_USERPWD ] = $ request ->getUri ()->getUserInfo ();
209
+ $ curlOptions [CURLOPT_USERPWD ] = $ request ->getUri ()->getUserInfo ();
228
210
}
229
211
230
- $ options [CURLOPT_HEADERFUNCTION ] = function ($ ch , $ data ) use ($ responseBuilder ) {
212
+ $ curlOptions [CURLOPT_HEADERFUNCTION ] = function ($ ch , $ data ) use ($ responseBuilder ) {
231
213
$ str = trim ($ data );
232
214
if ('' !== $ str ) {
233
215
if (strpos (strtolower ($ str ), 'http/ ' ) === 0 ) {
@@ -240,21 +222,17 @@ private function prepareRequestOptions(RequestInterface $request, ResponseBuilde
240
222
return strlen ($ data );
241
223
};
242
224
243
- $ options [CURLOPT_WRITEFUNCTION ] = function ($ ch , $ data ) use ($ responseBuilder ) {
225
+ $ curlOptions [CURLOPT_WRITEFUNCTION ] = function ($ ch , $ data ) use ($ responseBuilder ) {
244
226
return $ responseBuilder ->getResponse ()->getBody ()->write ($ data );
245
227
};
246
228
247
- return $ options ;
229
+ return $ curlOptions ;
248
230
}
249
231
250
232
/**
251
233
* Return cURL constant for specified HTTP version.
252
234
*
253
- * @param string $requestVersion
254
- *
255
235
* @throws \UnexpectedValueException If unsupported version requested
256
- *
257
- * @return int
258
236
*/
259
237
private function getProtocolVersion (string $ requestVersion ): int
260
238
{
@@ -275,13 +253,8 @@ private function getProtocolVersion(string $requestVersion): int
275
253
276
254
/**
277
255
* Add request body related cURL options.
278
- *
279
- * @param RequestInterface $request
280
- * @param array $options
281
- *
282
- * @return array
283
256
*/
284
- private function addRequestBodyOptions (RequestInterface $ request , array $ options ): array
257
+ private function addRequestBodyOptions (RequestInterface $ request , array $ curlOptions ): array
285
258
{
286
259
/*
287
260
* Some HTTP methods cannot have payload:
@@ -302,40 +275,37 @@ private function addRequestBodyOptions(RequestInterface $request, array $options
302
275
// Message has non empty body.
303
276
if (null === $ bodySize || $ bodySize > 1024 * 1024 ) {
304
277
// Avoid full loading large or unknown size body into memory
305
- $ options [CURLOPT_UPLOAD ] = true ;
278
+ $ curlOptions [CURLOPT_UPLOAD ] = true ;
306
279
if (null !== $ bodySize ) {
307
- $ options [CURLOPT_INFILESIZE ] = $ bodySize ;
280
+ $ curlOptions [CURLOPT_INFILESIZE ] = $ bodySize ;
308
281
}
309
- $ options [CURLOPT_READFUNCTION ] = function ($ ch , $ fd , $ length ) use ($ body ) {
282
+ $ curlOptions [CURLOPT_READFUNCTION ] = function ($ ch , $ fd , $ length ) use ($ body ) {
310
283
return $ body ->read ($ length );
311
284
};
312
285
} else {
313
286
// Small body can be loaded into memory
314
- $ options [CURLOPT_POSTFIELDS ] = (string ) $ body ;
287
+ $ curlOptions [CURLOPT_POSTFIELDS ] = (string ) $ body ;
315
288
}
316
289
}
317
290
}
318
291
319
292
if ($ request ->getMethod () === 'HEAD ' ) {
320
293
// This will set HTTP method to "HEAD".
321
- $ options [CURLOPT_NOBODY ] = true ;
294
+ $ curlOptions [CURLOPT_NOBODY ] = true ;
322
295
} elseif ($ request ->getMethod () !== 'GET ' ) {
323
296
// GET is a default method. Other methods should be specified explicitly.
324
- $ options [CURLOPT_CUSTOMREQUEST ] = $ request ->getMethod ();
297
+ $ curlOptions [CURLOPT_CUSTOMREQUEST ] = $ request ->getMethod ();
325
298
}
326
299
327
- return $ options ;
300
+ return $ curlOptions ;
328
301
}
329
302
330
303
/**
331
304
* Create headers array for CURLOPT_HTTPHEADER.
332
305
*
333
- * @param RequestInterface $request
334
- * @param array $options cURL options
335
- *
336
306
* @return string[]
337
307
*/
338
- private function createHeaders (RequestInterface $ request , array $ options ): array
308
+ private function createHeaders (RequestInterface $ request , array $ curlOptions ): array
339
309
{
340
310
$ curlHeaders = [];
341
311
$ headers = $ request ->getHeaders ();
@@ -346,10 +316,10 @@ private function createHeaders(RequestInterface $request, array $options): array
346
316
continue ;
347
317
}
348
318
if ('content-length ' === $ header ) {
349
- if (array_key_exists (CURLOPT_POSTFIELDS , $ options )) {
319
+ if (array_key_exists (CURLOPT_POSTFIELDS , $ curlOptions )) {
350
320
// 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 )) {
353
323
// Else if there is no body, forcing "Content-length" to 0
354
324
$ values = [0 ];
355
325
}
@@ -367,11 +337,6 @@ private function createHeaders(RequestInterface $request, array $options): array
367
337
return $ curlHeaders ;
368
338
}
369
339
370
- /**
371
- * Create new ResponseBuilder instance.
372
- *
373
- * @return ResponseBuilder
374
- */
375
340
private function createResponseBuilder (): ResponseBuilder
376
341
{
377
342
$ body = $ this ->streamFactory ->createStreamFromFile ('php://temp ' , 'w+b ' );
0 commit comments