@@ -51,6 +51,9 @@ final class CurlHttpClient implements HttpClientInterface, LoggerAwareInterface,
51
51
52
52
private ?LoggerInterface $ logger = null ;
53
53
54
+ private int $ maxHostConnections ;
55
+ private int $ maxPendingPushes ;
56
+
54
57
/**
55
58
* An internal object to share state between the client and its responses.
56
59
*/
@@ -69,25 +72,31 @@ public function __construct(array $defaultOptions = [], int $maxHostConnections
69
72
throw new \LogicException ('You cannot use the "Symfony\Component\HttpClient\CurlHttpClient" as the "curl" extension is not installed. ' );
70
73
}
71
74
75
+ $ this ->maxHostConnections = $ maxHostConnections ;
76
+ $ this ->maxPendingPushes = $ maxPendingPushes ;
77
+
72
78
$ this ->defaultOptions ['buffer ' ] ??= self ::shouldBuffer (...);
73
79
74
80
if ($ defaultOptions ) {
75
81
[, $ this ->defaultOptions ] = self ::prepareRequest (null , null , $ defaultOptions , $ this ->defaultOptions );
76
82
}
77
-
78
- $ this ->multi = new CurlClientState ($ maxHostConnections , $ maxPendingPushes );
79
83
}
80
84
81
85
public function setLogger (LoggerInterface $ logger ): void
82
86
{
83
- $ this ->logger = $ this ->multi ->logger = $ logger ;
87
+ $ this ->logger = $ logger ;
88
+ if (isset ($ this ->multi )) {
89
+ $ this ->multi ->logger = $ logger ;
90
+ }
84
91
}
85
92
86
93
/**
87
94
* @see HttpClientInterface::OPTIONS_DEFAULTS for available options
88
95
*/
89
96
public function request (string $ method , string $ url , array $ options = []): ResponseInterface
90
97
{
98
+ $ multi = $ this ->ensureState ();
99
+
91
100
[$ url , $ options ] = self ::prepareRequest ($ method , $ url , $ options , $ this ->defaultOptions );
92
101
$ scheme = $ url ['scheme ' ];
93
102
$ authority = $ url ['authority ' ];
@@ -165,24 +174,24 @@ public function request(string $method, string $url, array $options = []): Respo
165
174
}
166
175
167
176
// curl's resolve feature varies by host:port but ours varies by host only, let's handle this with our own DNS map
168
- if (isset ($ this -> multi ->dnsCache ->hostnames [$ host ])) {
169
- $ options ['resolve ' ] += [$ host => $ this -> multi ->dnsCache ->hostnames [$ host ]];
177
+ if (isset ($ multi ->dnsCache ->hostnames [$ host ])) {
178
+ $ options ['resolve ' ] += [$ host => $ multi ->dnsCache ->hostnames [$ host ]];
170
179
}
171
180
172
- if ($ options ['resolve ' ] || $ this -> multi ->dnsCache ->evictions ) {
181
+ if ($ options ['resolve ' ] || $ multi ->dnsCache ->evictions ) {
173
182
// First reset any old DNS cache entries then add the new ones
174
- $ resolve = $ this -> multi ->dnsCache ->evictions ;
175
- $ this -> multi ->dnsCache ->evictions = [];
183
+ $ resolve = $ multi ->dnsCache ->evictions ;
184
+ $ multi ->dnsCache ->evictions = [];
176
185
177
186
if ($ resolve && 0x072A00 > CurlClientState::$ curlVersion ['version_number ' ]) {
178
187
// DNS cache removals require curl 7.42 or higher
179
- $ this -> multi ->reset ();
188
+ $ multi ->reset ();
180
189
}
181
190
182
191
foreach ($ options ['resolve ' ] as $ host => $ ip ) {
183
192
$ resolve [] = null === $ ip ? "- $ host: $ port " : "$ host: $ port: $ ip " ;
184
- $ this -> multi ->dnsCache ->hostnames [$ host ] = $ ip ;
185
- $ this -> multi ->dnsCache ->removals ["- $ host: $ port " ] = "- $ host: $ port " ;
193
+ $ multi ->dnsCache ->hostnames [$ host ] = $ ip ;
194
+ $ multi ->dnsCache ->removals ["- $ host: $ port " ] = "- $ host: $ port " ;
186
195
}
187
196
188
197
$ curlopts [\CURLOPT_RESOLVE ] = $ resolve ;
@@ -285,16 +294,16 @@ public function request(string $method, string $url, array $options = []): Respo
285
294
$ curlopts += $ options ['extra ' ]['curl ' ];
286
295
}
287
296
288
- if ($ pushedResponse = $ this -> multi ->pushedResponses [$ url ] ?? null ) {
289
- unset($ this -> multi ->pushedResponses [$ url ]);
297
+ if ($ pushedResponse = $ multi ->pushedResponses [$ url ] ?? null ) {
298
+ unset($ multi ->pushedResponses [$ url ]);
290
299
291
300
if (self ::acceptPushForRequest ($ method , $ options , $ pushedResponse )) {
292
301
$ this ->logger ?->debug(sprintf ('Accepting pushed response: "%s %s" ' , $ method , $ url ));
293
302
294
303
// Reinitialize the pushed response with request's options
295
304
$ ch = $ pushedResponse ->handle ;
296
305
$ pushedResponse = $ pushedResponse ->response ;
297
- $ pushedResponse ->__construct ($ this -> multi , $ url , $ options , $ this ->logger );
306
+ $ pushedResponse ->__construct ($ multi , $ url , $ options , $ this ->logger );
298
307
} else {
299
308
$ this ->logger ?->debug(sprintf ('Rejecting pushed response: "%s" ' , $ url ));
300
309
$ pushedResponse = null ;
@@ -304,7 +313,7 @@ public function request(string $method, string $url, array $options = []): Respo
304
313
if (!$ pushedResponse ) {
305
314
$ ch = curl_init ();
306
315
$ this ->logger ?->info(sprintf ('Request: "%s %s" ' , $ method , $ url ));
307
- $ curlopts += [\CURLOPT_SHARE => $ this -> multi ->share ];
316
+ $ curlopts += [\CURLOPT_SHARE => $ multi ->share ];
308
317
}
309
318
310
319
foreach ($ curlopts as $ opt => $ value ) {
@@ -314,7 +323,7 @@ public function request(string $method, string $url, array $options = []): Respo
314
323
}
315
324
}
316
325
317
- return $ pushedResponse ?? new CurlResponse ($ this -> multi , $ ch , $ options , $ this ->logger , $ method , self ::createRedirectResolver ($ options , $ host , $ port ), CurlClientState::$ curlVersion ['version_number ' ], $ url );
326
+ return $ pushedResponse ?? new CurlResponse ($ multi , $ ch , $ options , $ this ->logger , $ method , self ::createRedirectResolver ($ options , $ host , $ port ), CurlClientState::$ curlVersion ['version_number ' ], $ url );
318
327
}
319
328
320
329
public function stream (ResponseInterface |iterable $ responses , ?float $ timeout = null ): ResponseStreamInterface
@@ -323,9 +332,11 @@ public function stream(ResponseInterface|iterable $responses, ?float $timeout =
323
332
$ responses = [$ responses ];
324
333
}
325
334
326
- if ($ this ->multi ->handle instanceof \CurlMultiHandle) {
335
+ $ multi = $ this ->ensureState ();
336
+
337
+ if ($ multi ->handle instanceof \CurlMultiHandle) {
327
338
$ active = 0 ;
328
- while (\CURLM_CALL_MULTI_PERFORM === curl_multi_exec ($ this -> multi ->handle , $ active )) {
339
+ while (\CURLM_CALL_MULTI_PERFORM === curl_multi_exec ($ multi ->handle , $ active )) {
329
340
}
330
341
}
331
342
@@ -334,7 +345,9 @@ public function stream(ResponseInterface|iterable $responses, ?float $timeout =
334
345
335
346
public function reset (): void
336
347
{
337
- $ this ->multi ->reset ();
348
+ if (isset ($ this ->multi )) {
349
+ $ this ->multi ->reset ();
350
+ }
338
351
}
339
352
340
353
/**
@@ -434,6 +447,16 @@ private static function createRedirectResolver(array $options, string $host, int
434
447
};
435
448
}
436
449
450
+ private function ensureState (): CurlClientState
451
+ {
452
+ if (!isset ($ this ->multi )) {
453
+ $ this ->multi = new CurlClientState ($ this ->maxHostConnections , $ this ->maxPendingPushes );
454
+ $ this ->multi ->logger = $ this ->logger ;
455
+ }
456
+
457
+ return $ this ->multi ;
458
+ }
459
+
437
460
private function findConstantName (int $ opt ): ?string
438
461
{
439
462
$ constants = array_filter (get_defined_constants (), static fn ($ v , $ k ) => $ v === $ opt && 'C ' === $ k [0 ] && (str_starts_with ($ k , 'CURLOPT_ ' ) || str_starts_with ($ k , 'CURLINFO_ ' )), \ARRAY_FILTER_USE_BOTH );
0 commit comments