From f1e258d5bb13b67c0914d765b43e7d7fd5e4ad5c Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 22 Nov 2021 22:43:45 +0100 Subject: [PATCH] [HttpClient] fix closing curl multi handle when destructing client --- .../Component/HttpClient/CurlHttpClient.php | 31 ++---------- .../HttpClient/Internal/CurlClientState.php | 50 +++++++++++++++++++ 2 files changed, 53 insertions(+), 28 deletions(-) diff --git a/src/Symfony/Component/HttpClient/CurlHttpClient.php b/src/Symfony/Component/HttpClient/CurlHttpClient.php index af480d45bf518..119c45924e4cd 100644 --- a/src/Symfony/Component/HttpClient/CurlHttpClient.php +++ b/src/Symfony/Component/HttpClient/CurlHttpClient.php @@ -336,33 +336,8 @@ public function stream($responses, float $timeout = null): ResponseStreamInterfa public function reset() { - if ($this->logger) { - foreach ($this->multi->pushedResponses as $url => $response) { - $this->logger->debug(sprintf('Unused pushed response: "%s"', $url)); - } - } - - $this->multi->pushedResponses = []; - $this->multi->dnsCache->evictions = $this->multi->dnsCache->evictions ?: $this->multi->dnsCache->removals; - $this->multi->dnsCache->removals = $this->multi->dnsCache->hostnames = []; - - if (\is_resource($this->multi->handle) || $this->multi->handle instanceof \CurlMultiHandle) { - if (\defined('CURLMOPT_PUSHFUNCTION')) { - curl_multi_setopt($this->multi->handle, \CURLMOPT_PUSHFUNCTION, null); - } - - $active = 0; - while (\CURLM_CALL_MULTI_PERFORM === curl_multi_exec($this->multi->handle, $active)); - } - - foreach ($this->multi->openHandles as [$ch]) { - if (\is_resource($ch) || $ch instanceof \CurlHandle) { - curl_setopt($ch, \CURLOPT_VERBOSE, false); - } - } - - curl_multi_close($this->multi->handle); - $this->multi->handle = curl_multi_init(); + $this->multi->logger = $this->logger; + $this->multi->reset(); } /** @@ -380,7 +355,7 @@ public function __wakeup() public function __destruct() { - $this->reset(); + $this->multi->logger = $this->logger; } private function handlePush($parent, $pushed, array $requestHeaders, int $maxPendingPushes): int diff --git a/src/Symfony/Component/HttpClient/Internal/CurlClientState.php b/src/Symfony/Component/HttpClient/Internal/CurlClientState.php index af2e6869b37b3..a4c596eb45d3f 100644 --- a/src/Symfony/Component/HttpClient/Internal/CurlClientState.php +++ b/src/Symfony/Component/HttpClient/Internal/CurlClientState.php @@ -11,6 +11,8 @@ namespace Symfony\Component\HttpClient\Internal; +use Psr\Log\LoggerInterface; + /** * Internal representation of the cURL client's state. * @@ -26,10 +28,58 @@ final class CurlClientState extends ClientState public $pushedResponses = []; /** @var DnsCache */ public $dnsCache; + /** @var LoggerInterface|null */ + public $logger; public function __construct() { $this->handle = curl_multi_init(); $this->dnsCache = new DnsCache(); } + + public function reset() + { + if ($this->logger) { + foreach ($this->pushedResponses as $url => $response) { + $this->logger->debug(sprintf('Unused pushed response: "%s"', $url)); + } + } + + $this->pushedResponses = []; + $this->dnsCache->evictions = $this->dnsCache->evictions ?: $this->dnsCache->removals; + $this->dnsCache->removals = $this->dnsCache->hostnames = []; + + if (\is_resource($this->handle) || $this->handle instanceof \CurlMultiHandle) { + if (\defined('CURLMOPT_PUSHFUNCTION')) { + curl_multi_setopt($this->handle, \CURLMOPT_PUSHFUNCTION, null); + } + + $active = 0; + while (\CURLM_CALL_MULTI_PERFORM === curl_multi_exec($this->handle, $active)); + } + + foreach ($this->openHandles as [$ch]) { + if (\is_resource($ch) || $ch instanceof \CurlHandle) { + curl_setopt($ch, \CURLOPT_VERBOSE, false); + } + } + + curl_multi_close($this->handle); + $this->handle = curl_multi_init(); + } + + public function __sleep(): array + { + throw new \BadMethodCallException('Cannot serialize '.__CLASS__); + } + + public function __wakeup() + { + throw new \BadMethodCallException('Cannot unserialize '.__CLASS__); + } + + public function __destruct() + { + $this->reset(); + } }