From a7963b7fed77c76d395900d3ee97fe9a39796ce3 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Sat, 2 Oct 2021 21:22:10 +0200 Subject: [PATCH] Fix ComposerRepository handling of offline state to allow resolution as long as everything is present in the cache, fixes #10116 --- .../Repository/ComposerRepository.php | 23 ++++++++++++++++++- src/Composer/Util/Http/CurlDownloader.php | 1 + 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/Composer/Repository/ComposerRepository.php b/src/Composer/Repository/ComposerRepository.php index 930c4553d..75b3aabec 100644 --- a/src/Composer/Repository/ComposerRepository.php +++ b/src/Composer/Repository/ComposerRepository.php @@ -1178,6 +1178,14 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito throw $e; } + // try to detect offline state (if dns resolution fails it is pretty likely to keep failing) and avoid retrying in that case + if ($e instanceof TransportException && $e->getStatusCode() === null) { + $responseInfo = $e->getResponseInfo(); + if (isset($responseInfo['namelookup_time']) && $responseInfo['namelookup_time'] == 0) { + $retries = 0; + } + } + if ($retries) { usleep(100000); continue; @@ -1349,7 +1357,7 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito return $data; }; - $reject = function ($e) use (&$retries, $httpDownloader, $filename, $options, &$reject, $accept, $io, $url, &$degradedMode, $repo) { + $reject = function ($e) use (&$retries, $httpDownloader, $filename, $options, &$reject, $accept, $io, $url, &$degradedMode, $repo, $lastModifiedTime) { if ($e instanceof TransportException && $e->getStatusCode() === 404) { $repo->packagesNotFoundCache[$filename] = true; @@ -1361,6 +1369,14 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito $retries = 0; } + // try to detect offline state (if dns resolution fails it is pretty likely to keep failing) and avoid retrying in that case + if ($e instanceof TransportException && $e->getStatusCode() === null) { + $responseInfo = $e->getResponseInfo(); + if (isset($responseInfo['namelookup_time']) && $responseInfo['namelookup_time'] == 0) { + $retries = 0; + } + } + if (--$retries > 0) { usleep(100000); @@ -1372,6 +1388,11 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito } $degradedMode = true; + // if the file is in the cache, we fake a 304 Not Modified to allow the process to continue + if ($lastModifiedTime) { + return $accept(new Response(array('url' => $url), 304, array(), '')); + } + // special error code returned when network is being artificially disabled if ($e instanceof TransportException && $e->getStatusCode() === 499) { return $accept(new Response(array('url' => $url), 404, array(), '')); diff --git a/src/Composer/Util/Http/CurlDownloader.php b/src/Composer/Util/Http/CurlDownloader.php index 227449e7a..cb1f6daea 100644 --- a/src/Composer/Util/Http/CurlDownloader.php +++ b/src/Composer/Util/Http/CurlDownloader.php @@ -341,6 +341,7 @@ class CurlDownloader if (!$error && function_exists('curl_strerror')) { $error = curl_strerror($errno); } + $progress['error_code'] = $errno; throw new TransportException('curl error '.$errno.' while downloading '.Url::sanitize($progress['url']).': '.$error); } $statusCode = $progress['http_code'];