@@ -35,27 +35,27 @@ class CurlHttpClient implements HttpClient
35
35
36
36
/**
37
37
* cURL handle opened resource
38
- * @var resource
38
+ *
39
+ * @var resource|null
39
40
*/
40
- private $ handle ;
41
+ private $ handle = null ;
41
42
42
43
/**
43
- * cURL handle configuration TODO change description
44
+ * Client settings
44
45
*
45
46
* @var array
46
- *
47
- * @since 1.00
48
47
*/
49
- protected $ options ;
48
+ private $ settings ;
50
49
51
50
/**
52
- * Constructor
51
+ * Create new client
53
52
*
54
- * Available options (see also {@link getDefaultOptions}) :
53
+ * Available options:
55
54
*
56
- * - connection_timeout : int — connection timeout in seconds
57
- * - ssl_verify_peer : bool — verify peer when using SSL
58
- * - timeout : int — overall timeout in seconds
55
+ * - connection_timeout : int — connection timeout in seconds;
56
+ * - curl_options: array — custom cURL options;
57
+ * - ssl_verify_peer : bool — verify peer when using SSL;
58
+ * - timeout : int — overall timeout in seconds.
59
59
*
60
60
* @param MessageFactory $messageFactory HTTP Message factory
61
61
* @param StreamFactory $streamFactory HTTP Stream factory
@@ -70,12 +70,14 @@ public function __construct(
70
70
) {
71
71
$ this ->setMessageFactory ($ messageFactory );
72
72
$ this ->setStreamFactory ($ streamFactory );
73
- $ this ->options = array_merge (
74
- $ this ->getDefaultOptions (),
75
- array_intersect_key (
76
- $ options ,
77
- $ this ->getDefaultOptions ()
78
- )
73
+ $ this ->settings = array_merge (
74
+ [
75
+ 'curl_options ' => [],
76
+ 'connection_timeout ' => 3 ,
77
+ 'ssl_verify_peer ' => true ,
78
+ 'timeout ' => 10
79
+ ],
80
+ $ options
79
81
);
80
82
}
81
83
@@ -89,23 +91,6 @@ public function __destruct()
89
91
}
90
92
}
91
93
92
- /**
93
- * Return available options and there default values
94
- *
95
- * @return array
96
- *
97
- * @since 1.00
98
- */
99
- public function getDefaultOptions ()
100
- {
101
- return [
102
- 'curl_options ' => [],
103
- 'connection_timeout ' => 3 ,
104
- 'ssl_verify_peer ' => true ,
105
- 'timeout ' => 10
106
- ];
107
- }
108
-
109
94
/**
110
95
* Sends a PSR-7 request.
111
96
*
@@ -158,12 +143,19 @@ public function sendRequest(RequestInterface $request)
158
143
$ parts = explode (': ' , $ header , 2 );
159
144
$ headerName = trim (urldecode ($ parts [0 ]));
160
145
$ headerValue = trim (urldecode ($ parts [1 ]));
161
- $ response = $ this ->addHeaderToResponse ($ response , $ headerName , $ headerValue );
146
+ if ($ response ->hasHeader ($ headerName )) {
147
+ $ response = $ response ->withAddedHeader ($ headerName , $ headerValue );
148
+ } else {
149
+ $ response = $ response ->withHeader ($ headerName , $ headerValue );
150
+ }
162
151
}
163
152
153
+ /*
154
+ * substr can return boolean value for empty string. But createStream does not support
155
+ * booleans. Converting to string.
156
+ */
164
157
$ content = (string ) substr ($ raw , $ headerSize );
165
158
$ stream = $ this ->getStreamFactory ()->createStream ($ content );
166
- /** @var ResponseInterface $response */
167
159
$ response = $ response ->withBody ($ stream );
168
160
169
161
return $ response ;
@@ -188,43 +180,19 @@ protected function request($options, &$raw, &$info)
188
180
$ this ->handle = curl_init ();
189
181
}
190
182
191
- try {
192
- curl_setopt_array ($ this ->handle , $ options );
193
- $ raw = curl_exec ($ this ->handle );
183
+ curl_setopt_array ($ this ->handle , $ options );
184
+ $ raw = curl_exec ($ this ->handle );
194
185
195
- if (curl_errno ($ this ->handle ) > 0 ) {
196
- throw new RuntimeException (
197
- sprintf (
198
- 'Curl error: (%d) %s ' ,
199
- curl_errno ($ this ->handle ),
200
- curl_error ($ this ->handle )
201
- )
202
- );
203
- }
204
- $ info = curl_getinfo ($ this ->handle );
205
- } finally {
186
+ if (curl_errno ($ this ->handle ) > 0 ) {
187
+ throw new RuntimeException (
188
+ sprintf (
189
+ 'Curl error: (%d) %s ' ,
190
+ curl_errno ($ this ->handle ),
191
+ curl_error ($ this ->handle )
192
+ )
193
+ );
206
194
}
207
- }
208
-
209
- /**
210
- * Adds a header to the response object
211
- *
212
- * @param ResponseInterface $response
213
- * @param string $name
214
- * @param string $value
215
- *
216
- * @return ResponseInterface
217
- *
218
- * @since 1.00
219
- */
220
- protected function addHeaderToResponse ($ response , $ name , $ value )
221
- {
222
- if ($ response ->hasHeader ($ name )) {
223
- $ response = $ response ->withAddedHeader ($ name , $ value );
224
- } else {
225
- $ response = $ response ->withHeader ($ name , $ value );
226
- }
227
- return $ response ;
195
+ $ info = curl_getinfo ($ this ->handle );
228
196
}
229
197
230
198
/**
@@ -238,57 +206,36 @@ protected function addHeaderToResponse($response, $name, $value)
238
206
*/
239
207
private function createCurlOptions (RequestInterface $ request )
240
208
{
241
- $ options = array_key_exists ('curl_options ' , $ this ->options )
242
- ? $ this ->options ['curl_options ' ]
243
- : [];
209
+ $ options = $ this ->settings ['curl_options ' ];
244
210
245
211
$ options [CURLOPT_HEADER ] = true ;
246
212
$ options [CURLOPT_RETURNTRANSFER ] = true ;
247
213
248
214
$ options [CURLOPT_HTTP_VERSION ] = $ this ->getProtocolVersion ($ request ->getProtocolVersion ());
249
215
$ options [CURLOPT_URL ] = (string ) $ request ->getUri ();
250
216
251
- $ options [CURLOPT_CONNECTTIMEOUT ] = $ this ->options ['connection_timeout ' ];
217
+ $ options [CURLOPT_CONNECTTIMEOUT ] = $ this ->settings ['connection_timeout ' ];
252
218
$ options [CURLOPT_FOLLOWLOCATION ] = false ;
253
- $ options [CURLOPT_SSL_VERIFYPEER ] = $ this ->options ['ssl_verify_peer ' ];
254
- $ options [CURLOPT_TIMEOUT ] = $ this ->options ['timeout ' ];
219
+ $ options [CURLOPT_SSL_VERIFYPEER ] = $ this ->settings ['ssl_verify_peer ' ];
220
+ $ options [CURLOPT_TIMEOUT ] = $ this ->settings ['timeout ' ];
255
221
256
- switch ($ request ->getMethod ()) {
257
- case 'HEAD ' :
258
- $ options [CURLOPT_NOBODY ] = true ;
259
- break ;
260
- case 'OPTIONS ' :
261
- case 'POST ' :
262
- case 'PUT ' :
263
- $ options [CURLOPT_CUSTOMREQUEST ] = $ request ->getMethod ();
264
- $ body = (string ) $ request ->getBody ();
265
- if ('' !== $ body ) {
266
- $ options [CURLOPT_POSTFIELDS ] = $ body ;
267
- }
268
- break ;
269
- case 'CONNECT ' :
270
- case 'DELETE ' :
271
- case 'PATCH ' :
272
- case 'TRACE ' :
273
- $ options [CURLOPT_CUSTOMREQUEST ] = $ request ->getMethod ();
274
- break ;
222
+ if (in_array ($ request ->getMethod (), ['OPTIONS ' , 'POST ' , 'PUT ' ], true )) {
223
+ /* cURL allows request body only for these methods. */
224
+ $ body = (string ) $ request ->getBody ();
225
+ if ('' !== $ body ) {
226
+ $ options [CURLOPT_POSTFIELDS ] = $ body ;
227
+ }
275
228
}
276
229
277
- $ headers = array_keys ($ request ->getHeaders ());
278
- foreach ($ headers as $ name ) {
279
- if (strtolower ($ name ) === 'content-length ' ) {
280
- $ values = [0 ];
281
- if (array_key_exists (CURLOPT_POSTFIELDS , $ options )) {
282
- $ values = [strlen ($ options [CURLOPT_POSTFIELDS ])];
283
- }
284
- } else {
285
- $ values = $ request ->getHeader ($ name );
286
- }
287
- foreach ($ values as $ value ) {
288
- $ options [CURLOPT_HTTPHEADER ][] = $ name . ': ' . $ value ;
289
- }
230
+ if ($ request ->getMethod () === 'HEAD ' ) {
231
+ $ options [CURLOPT_NOBODY ] = true ;
232
+ } elseif ($ request ->getMethod () !== 'GET ' ) {
233
+ /* GET is a default method. Other methods should be specified explicitly. */
234
+ $ options [CURLOPT_CUSTOMREQUEST ] = $ request ->getMethod ();
290
235
}
291
236
237
+ $ options [CURLOPT_HTTPHEADER ] = $ this ->createHeaders ($ request , $ options );
238
+
292
239
if ($ request ->getUri ()->getUserInfo ()) {
293
240
$ options [CURLOPT_USERPWD ] = $ request ->getUri ()->getUserInfo ();
294
241
}
@@ -320,4 +267,32 @@ private function getProtocolVersion($requestVersion)
320
267
}
321
268
return CURL_HTTP_VERSION_NONE ;
322
269
}
270
+
271
+ /**
272
+ * Create headers array for CURLOPT_HTTPHEADER
273
+ *
274
+ * @param RequestInterface $request
275
+ * @param array $options cURL options
276
+ *
277
+ * @return string[]
278
+ */
279
+ private function createHeaders (RequestInterface $ request , array $ options )
280
+ {
281
+ $ curlHeaders = [];
282
+ $ headers = array_keys ($ request ->getHeaders ());
283
+ foreach ($ headers as $ name ) {
284
+ if (strtolower ($ name ) === 'content-length ' ) {
285
+ $ values = [0 ];
286
+ if (array_key_exists (CURLOPT_POSTFIELDS , $ options )) {
287
+ $ values = [strlen ($ options [CURLOPT_POSTFIELDS ])];
288
+ }
289
+ } else {
290
+ $ values = $ request ->getHeader ($ name );
291
+ }
292
+ foreach ($ values as $ value ) {
293
+ $ curlHeaders [] = $ name . ': ' . $ value ;
294
+ }
295
+ }
296
+ return $ curlHeaders ;
297
+ }
323
298
}
0 commit comments