Skip to content

Commit cb5f957

Browse files
Merge branch '6.4' into 7.0
* 6.4: [HttpKernel] Fix creating `ReflectionMethod` with only one argument [VarDumper] Fix test suite with PHP 8.4 [DoctrineBridge] Add missing return type [Mailer] Fix sendmail transport not handling failure [HttpClient] Lazily initialize CurlClientState updating missing translations for Greek #53768 [Validator] Allow BICs’ first four characters to be digits [ErrorHandler] Fix exit code when an exception occurs and the exception handler has been unregistered [Validator] Review Arabic translations and add correct translations.
2 parents 9391528 + c6fe585 commit cb5f957

File tree

2 files changed

+44
-21
lines changed

2 files changed

+44
-21
lines changed

CurlHttpClient.php

Lines changed: 42 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,9 @@ final class CurlHttpClient implements HttpClientInterface, LoggerAwareInterface,
5151

5252
private ?LoggerInterface $logger = null;
5353

54+
private int $maxHostConnections;
55+
private int $maxPendingPushes;
56+
5457
/**
5558
* An internal object to share state between the client and its responses.
5659
*/
@@ -69,25 +72,31 @@ public function __construct(array $defaultOptions = [], int $maxHostConnections
6972
throw new \LogicException('You cannot use the "Symfony\Component\HttpClient\CurlHttpClient" as the "curl" extension is not installed.');
7073
}
7174

75+
$this->maxHostConnections = $maxHostConnections;
76+
$this->maxPendingPushes = $maxPendingPushes;
77+
7278
$this->defaultOptions['buffer'] ??= self::shouldBuffer(...);
7379

7480
if ($defaultOptions) {
7581
[, $this->defaultOptions] = self::prepareRequest(null, null, $defaultOptions, $this->defaultOptions);
7682
}
77-
78-
$this->multi = new CurlClientState($maxHostConnections, $maxPendingPushes);
7983
}
8084

8185
public function setLogger(LoggerInterface $logger): void
8286
{
83-
$this->logger = $this->multi->logger = $logger;
87+
$this->logger = $logger;
88+
if (isset($this->multi)) {
89+
$this->multi->logger = $logger;
90+
}
8491
}
8592

8693
/**
8794
* @see HttpClientInterface::OPTIONS_DEFAULTS for available options
8895
*/
8996
public function request(string $method, string $url, array $options = []): ResponseInterface
9097
{
98+
$multi = $this->ensureState();
99+
91100
[$url, $options] = self::prepareRequest($method, $url, $options, $this->defaultOptions);
92101
$scheme = $url['scheme'];
93102
$authority = $url['authority'];
@@ -165,24 +174,24 @@ public function request(string $method, string $url, array $options = []): Respo
165174
}
166175

167176
// 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]];
170179
}
171180

172-
if ($options['resolve'] || $this->multi->dnsCache->evictions) {
181+
if ($options['resolve'] || $multi->dnsCache->evictions) {
173182
// 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 = [];
176185

177186
if ($resolve && 0x072A00 > CurlClientState::$curlVersion['version_number']) {
178187
// DNS cache removals require curl 7.42 or higher
179-
$this->multi->reset();
188+
$multi->reset();
180189
}
181190

182191
foreach ($options['resolve'] as $host => $ip) {
183192
$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";
186195
}
187196

188197
$curlopts[\CURLOPT_RESOLVE] = $resolve;
@@ -285,16 +294,16 @@ public function request(string $method, string $url, array $options = []): Respo
285294
$curlopts += $options['extra']['curl'];
286295
}
287296

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]);
290299

291300
if (self::acceptPushForRequest($method, $options, $pushedResponse)) {
292301
$this->logger?->debug(sprintf('Accepting pushed response: "%s %s"', $method, $url));
293302

294303
// Reinitialize the pushed response with request's options
295304
$ch = $pushedResponse->handle;
296305
$pushedResponse = $pushedResponse->response;
297-
$pushedResponse->__construct($this->multi, $url, $options, $this->logger);
306+
$pushedResponse->__construct($multi, $url, $options, $this->logger);
298307
} else {
299308
$this->logger?->debug(sprintf('Rejecting pushed response: "%s"', $url));
300309
$pushedResponse = null;
@@ -304,7 +313,7 @@ public function request(string $method, string $url, array $options = []): Respo
304313
if (!$pushedResponse) {
305314
$ch = curl_init();
306315
$this->logger?->info(sprintf('Request: "%s %s"', $method, $url));
307-
$curlopts += [\CURLOPT_SHARE => $this->multi->share];
316+
$curlopts += [\CURLOPT_SHARE => $multi->share];
308317
}
309318

310319
foreach ($curlopts as $opt => $value) {
@@ -314,7 +323,7 @@ public function request(string $method, string $url, array $options = []): Respo
314323
}
315324
}
316325

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);
318327
}
319328

320329
public function stream(ResponseInterface|iterable $responses, ?float $timeout = null): ResponseStreamInterface
@@ -323,9 +332,11 @@ public function stream(ResponseInterface|iterable $responses, ?float $timeout =
323332
$responses = [$responses];
324333
}
325334

326-
if ($this->multi->handle instanceof \CurlMultiHandle) {
335+
$multi = $this->ensureState();
336+
337+
if ($multi->handle instanceof \CurlMultiHandle) {
327338
$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)) {
329340
}
330341
}
331342

@@ -334,7 +345,9 @@ public function stream(ResponseInterface|iterable $responses, ?float $timeout =
334345

335346
public function reset(): void
336347
{
337-
$this->multi->reset();
348+
if (isset($this->multi)) {
349+
$this->multi->reset();
350+
}
338351
}
339352

340353
/**
@@ -434,6 +447,16 @@ private static function createRedirectResolver(array $options, string $host, int
434447
};
435448
}
436449

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+
437460
private function findConstantName(int $opt): ?string
438461
{
439462
$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);

Tests/CurlHttpClientTest.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,8 @@ public function testHandleIsReinitOnReset()
5858
{
5959
$httpClient = $this->getHttpClient(__FUNCTION__);
6060

61-
$r = new \ReflectionProperty($httpClient, 'multi');
62-
$clientState = $r->getValue($httpClient);
61+
$r = new \ReflectionMethod($httpClient, 'ensureState');
62+
$clientState = $r->invoke($httpClient);
6363
$initialShareId = $clientState->share;
6464
$httpClient->reset();
6565
self::assertNotSame($initialShareId, $clientState->share);

0 commit comments

Comments
 (0)