diff --git a/src/Composer/Util/Http/CurlDownloader.php b/src/Composer/Util/Http/CurlDownloader.php index 577c81b47..1cdae6df9 100644 --- a/src/Composer/Util/Http/CurlDownloader.php +++ b/src/Composer/Util/Http/CurlDownloader.php @@ -34,6 +34,14 @@ use Symfony\Component\HttpFoundation\IpUtils; */ class CurlDownloader { + /** + * Known libcurl's broken versions when proxy is in use with HTTP/2 + * multiplexing. + * + * @var list + */ + private const BAD_MULTIPLEXING_CURL_VERSIONS = ['7.87.0', '7.88.0', '7.88.1']; + /** @var \CurlMultiHandle */ private $multiHandle; /** @var \CurlShareHandle */ @@ -99,7 +107,18 @@ class CurlDownloader $this->multiHandle = $mh = curl_multi_init(); if (function_exists('curl_multi_setopt')) { - curl_multi_setopt($mh, CURLMOPT_PIPELINING, \PHP_VERSION_ID >= 70400 ? /* CURLPIPE_MULTIPLEX */ 2 : /*CURLPIPE_HTTP1 | CURLPIPE_MULTIPLEX*/ 3); + if (ProxyManager::getInstance()->hasProxy() && ($version = curl_version()) !== false && in_array($version['version'], self::BAD_MULTIPLEXING_CURL_VERSIONS, true)) { + /** + * Disable HTTP/2 multiplexing for some broken versions of libcurl. + * + * In certain versions of libcurl when proxy is in use with HTTP/2 + * multiplexing, connections will continue stacking up. This was + * fixed in libcurl 8.0.0 in curl/curl@821f6e2a89de8aec1c7da3c0f381b92b2b801efc + */ + curl_multi_setopt($mh, CURLMOPT_PIPELINING, /* CURLPIPE_NOTHING */ 0); + } else { + curl_multi_setopt($mh, CURLMOPT_PIPELINING, \PHP_VERSION_ID >= 70400 ? /* CURLPIPE_MULTIPLEX */ 2 : /*CURLPIPE_HTTP1 | CURLPIPE_MULTIPLEX*/ 3); + } if (defined('CURLMOPT_MAX_HOST_CONNECTIONS') && !defined('HHVM_VERSION')) { curl_multi_setopt($mh, CURLMOPT_MAX_HOST_CONNECTIONS, 8); } diff --git a/src/Composer/Util/Http/ProxyManager.php b/src/Composer/Util/Http/ProxyManager.php index 247105fa5..09d061bb4 100644 --- a/src/Composer/Util/Http/ProxyManager.php +++ b/src/Composer/Util/Http/ProxyManager.php @@ -59,6 +59,11 @@ class ProxyManager self::$instance = null; } + public function hasProxy(): bool + { + return $this->httpProxy !== null && $this->httpsProxy !== null; + } + /** * Returns a RequestProxy instance for the request url *