7
7
use Http \Client \Exception ;
8
8
use Http \Client \HttpAsyncClient ;
9
9
use Http \Client \HttpClient ;
10
+ use Http \Discovery \Exception \NotFoundException ;
10
11
use Http \Discovery \Psr17FactoryDiscovery ;
12
+ use Http \Promise \Promise ;
11
13
use Psr \Http \Message \RequestInterface ;
12
14
use Psr \Http \Message \ResponseFactoryInterface ;
13
15
use Psr \Http \Message \ResponseInterface ;
@@ -63,11 +65,16 @@ class Client implements HttpClient, HttpAsyncClient
63
65
private $ multiRunner ;
64
66
65
67
/**
68
+ * Create HTTP client.
69
+ *
66
70
* @param ResponseFactoryInterface|null $responseFactory PSR-17 HTTP response factory.
67
71
* @param StreamFactoryInterface|null $streamFactory PSR-17 HTTP stream factory.
68
- * @param array $options cURL options {@link http://php.net/curl_setopt}
72
+ * @param array $options cURL options
73
+ * {@link http://php.net/curl_setopt}.
74
+ *
75
+ * @throws NotFoundException If factory discovery failed.
69
76
*
70
- * @throws \Http\Discovery\Exception\NotFoundException If factory discovery failed
77
+ * @since 2.0 Accepts PSR-17 factories instead of HTTPlug ones.
71
78
*/
72
79
public function __construct (
73
80
ResponseFactoryInterface $ responseFactory = null ,
@@ -81,11 +88,21 @@ public function __construct(
81
88
[
82
89
CURLOPT_HEADER => false ,
83
90
CURLOPT_RETURNTRANSFER => false ,
84
- CURLOPT_FOLLOWLOCATION => false ,
91
+ CURLOPT_FOLLOWLOCATION => false
85
92
]
86
93
);
87
- $ resolver ->setAllowedValues (CURLOPT_HEADER , [false ]); // our parsing will fail if this is set to true
88
- $ resolver ->setAllowedValues (CURLOPT_RETURNTRANSFER , [false ]); // our parsing will fail if this is set to true
94
+
95
+ // Our parsing will fail if this is set to true.
96
+ $ resolver ->setAllowedValues (
97
+ CURLOPT_HEADER ,
98
+ [false ]
99
+ );
100
+
101
+ // Our parsing will fail if this is set to true.
102
+ $ resolver ->setAllowedValues (
103
+ CURLOPT_RETURNTRANSFER ,
104
+ [false ]
105
+ );
89
106
90
107
// We do not know what everything curl supports and might support in the future.
91
108
// Make sure that we accept everything that is in the options.
@@ -105,12 +122,16 @@ public function __destruct()
105
122
}
106
123
107
124
/**
108
- * {@inheritdoc}
125
+ * Sends a PSR-7 request and returns a PSR-7 response.
126
+ *
127
+ * @param RequestInterface $request
109
128
*
110
- * @throws \Http\Client\Exception\NetworkException In case of network problems
111
- * @throws \Http\Client\Exception\RequestException On invalid request
112
- * @throws \InvalidArgumentException For invalid header names or values
113
- * @throws \RuntimeException If creating the body stream fails
129
+ * @return ResponseInterface
130
+ *
131
+ * @throws \InvalidArgumentException For invalid header names or values.
132
+ * @throws \RuntimeException If creating the body stream fails.
133
+ * @throws Exception\NetworkException In case of network problems.
134
+ * @throws Exception\RequestException On invalid request.
114
135
*
115
136
* @since 1.6 \UnexpectedValueException replaced with RequestException
116
137
* @since 1.6 Throw NetworkException on network errors
@@ -152,42 +173,37 @@ public function sendRequest(RequestInterface $request): ResponseInterface
152
173
}
153
174
154
175
/**
155
- * {@inheritdoc}
156
- *
157
- * @throws \Http\Client\Exception\RequestException On invalid request
158
- * @throws \InvalidArgumentException For invalid header names or values
159
- * @throws \RuntimeException If creating the body stream fails
176
+ * Create builder to use for building response object.
160
177
*
161
- * @since 1.6 \UnexpectedValueException replaced with RequestException
162
- * @since 1.0
178
+ * @return ResponseBuilder
163
179
*/
164
- public function sendAsyncRequest ( RequestInterface $ request )
180
+ private function createResponseBuilder (): ResponseBuilder
165
181
{
166
- if (!$ this ->multiRunner instanceof MultiRunner) {
167
- $ this ->multiRunner = new MultiRunner ();
168
- }
169
-
170
- $ handle = curl_init ();
171
- $ responseBuilder = $ this ->createResponseBuilder ();
172
- $ requestOptions = $ this ->prepareRequestOptions ($ request , $ responseBuilder );
173
- curl_setopt_array ($ handle , $ requestOptions );
182
+ $ body = $ this ->streamFactory ->createStreamFromFile ('php://temp ' , 'w+b ' );
174
183
175
- $ core = new PromiseCore ( $ request , $ handle , $ responseBuilder );
176
- $ promise = new CurlPromise ( $ core , $ this -> multiRunner );
177
- $ this -> multiRunner -> add ( $ core );
184
+ $ response = $ this -> responseFactory
185
+ -> createResponse ( 200 )
186
+ -> withBody ( $ body );
178
187
179
- return $ promise ;
188
+ return new ResponseBuilder ( $ response ) ;
180
189
}
181
190
182
191
/**
183
- * Update cURL options for this request and hook in the response builder.
192
+ * Update cURL options for given request and hook in the response builder.
193
+ *
194
+ * @param RequestInterface $request Request on which to create options.
195
+ * @param ResponseBuilder $responseBuilder Builder to use for building response.
184
196
*
185
- * @throws \Http\Client\Exception\RequestException On invalid request
186
- * @throws \InvalidArgumentException For invalid header names or values
187
- * @throws \RuntimeException If can not read body
197
+ * @return array cURL options based on request.
198
+ *
199
+ * @throws \InvalidArgumentException For invalid header names or values.
200
+ * @throws \RuntimeException If can not read body.
201
+ * @throws Exception\RequestException On invalid request.
188
202
*/
189
- private function prepareRequestOptions (RequestInterface $ request , ResponseBuilder $ responseBuilder ): array
190
- {
203
+ private function prepareRequestOptions (
204
+ RequestInterface $ request ,
205
+ ResponseBuilder $ responseBuilder
206
+ ): array {
191
207
$ curlOptions = $ this ->curlOptions ;
192
208
193
209
try {
@@ -196,7 +212,7 @@ private function prepareRequestOptions(RequestInterface $request, ResponseBuilde
196
212
} catch (\UnexpectedValueException $ e ) {
197
213
throw new Exception \RequestException ($ e ->getMessage (), $ request );
198
214
}
199
- $ curlOptions [CURLOPT_URL ] = (string ) $ request ->getUri ();
215
+ $ curlOptions [CURLOPT_URL ] = (string )$ request ->getUri ();
200
216
201
217
$ curlOptions = $ this ->addRequestBodyOptions ($ request , $ curlOptions );
202
218
@@ -209,7 +225,7 @@ private function prepareRequestOptions(RequestInterface $request, ResponseBuilde
209
225
$ curlOptions [CURLOPT_HEADERFUNCTION ] = function ($ ch , $ data ) use ($ responseBuilder ) {
210
226
$ str = trim ($ data );
211
227
if ('' !== $ str ) {
212
- if (strpos ( strtolower ( $ str) , 'http/ ' ) === 0 ) {
228
+ if (stripos ( $ str , 'http/ ' ) === 0 ) {
213
229
$ responseBuilder ->setStatus ($ str )->getResponse ();
214
230
} else {
215
231
$ responseBuilder ->addHeader ($ str );
@@ -229,7 +245,11 @@ private function prepareRequestOptions(RequestInterface $request, ResponseBuilde
229
245
/**
230
246
* Return cURL constant for specified HTTP version.
231
247
*
232
- * @throws \UnexpectedValueException If unsupported version requested
248
+ * @param string $requestVersion HTTP version ("1.0", "1.1" or "2.0").
249
+ *
250
+ * @return int Respective CURL_HTTP_VERSION_x_x constant.
251
+ *
252
+ * @throws \UnexpectedValueException If unsupported version requested.
233
253
*/
234
254
private function getProtocolVersion (string $ requestVersion ): int
235
255
{
@@ -250,6 +270,11 @@ private function getProtocolVersion(string $requestVersion): int
250
270
251
271
/**
252
272
* Add request body related cURL options.
273
+ *
274
+ * @param RequestInterface $request Request on which to create options.
275
+ * @param array $curlOptions Options created by prepareRequestOptions().
276
+ *
277
+ * @return array cURL options based on request.
253
278
*/
254
279
private function addRequestBodyOptions (RequestInterface $ request , array $ curlOptions ): array
255
280
{
@@ -281,7 +306,7 @@ private function addRequestBodyOptions(RequestInterface $request, array $curlOpt
281
306
};
282
307
} else {
283
308
// Small body can be loaded into memory
284
- $ curlOptions [CURLOPT_POSTFIELDS ] = (string ) $ body ;
309
+ $ curlOptions [CURLOPT_POSTFIELDS ] = (string )$ body ;
285
310
}
286
311
}
287
312
}
@@ -300,6 +325,9 @@ private function addRequestBodyOptions(RequestInterface $request, array $curlOpt
300
325
/**
301
326
* Create headers array for CURLOPT_HTTPHEADER.
302
327
*
328
+ * @param RequestInterface $request Request on which to create headers.
329
+ * @param array $curlOptions Options created by prepareRequestOptions().
330
+ *
303
331
* @return string[]
304
332
*/
305
333
private function createHeaders (RequestInterface $ request , array $ curlOptions ): array
@@ -322,7 +350,7 @@ private function createHeaders(RequestInterface $request, array $curlOptions): a
322
350
}
323
351
}
324
352
foreach ($ values as $ value ) {
325
- $ curlHeaders [] = $ name. ': ' . $ value ;
353
+ $ curlHeaders [] = $ name . ': ' . $ value ;
326
354
}
327
355
}
328
356
/*
@@ -334,14 +362,37 @@ private function createHeaders(RequestInterface $request, array $curlOptions): a
334
362
return $ curlHeaders ;
335
363
}
336
364
337
- private function createResponseBuilder (): ResponseBuilder
365
+ /**
366
+ * Sends a PSR-7 request in an asynchronous way.
367
+ *
368
+ * Exceptions related to processing the request are available from the returned Promise.
369
+ *
370
+ * @param RequestInterface $request
371
+ *
372
+ * @return Promise Resolves a PSR-7 Response or fails with an Http\Client\Exception.
373
+ *
374
+ * @throws \InvalidArgumentException For invalid header names or values.
375
+ * @throws \RuntimeException If creating the body stream fails.
376
+ * @throws Exception\RequestException On invalid request.
377
+ *
378
+ * @since 1.6 \UnexpectedValueException replaced with RequestException
379
+ * @since 1.0
380
+ */
381
+ public function sendAsyncRequest (RequestInterface $ request )
338
382
{
339
- $ body = $ this ->streamFactory ->createStreamFromFile ('php://temp ' , 'w+b ' );
383
+ if (!$ this ->multiRunner instanceof MultiRunner) {
384
+ $ this ->multiRunner = new MultiRunner ();
385
+ }
340
386
341
- $ response = $ this ->responseFactory
342
- ->createResponse (200 )
343
- ->withBody ($ body );
387
+ $ handle = curl_init ();
388
+ $ responseBuilder = $ this ->createResponseBuilder ();
389
+ $ requestOptions = $ this ->prepareRequestOptions ($ request , $ responseBuilder );
390
+ curl_setopt_array ($ handle , $ requestOptions );
344
391
345
- return new ResponseBuilder ($ response );
392
+ $ core = new PromiseCore ($ request , $ handle , $ responseBuilder );
393
+ $ promise = new CurlPromise ($ core , $ this ->multiRunner );
394
+ $ this ->multiRunner ->add ($ core );
395
+
396
+ return $ promise ;
346
397
}
347
398
}
0 commit comments