diff --git a/doc/03-cli.md b/doc/03-cli.md index 74374ec6b..f0b3dca35 100644 --- a/doc/03-cli.md +++ b/doc/03-cli.md @@ -928,4 +928,9 @@ repository options. Defaults to `1`. If set to `0`, Composer will not create `.htaccess` files in the composer home, cache, and data directories. +### COMPOSER_DISABLE_NETWORK + +If set to `1`, disables network access (best effort). This can be used for debugging or +to run Composer on a plane or a starship with poor connectivity. + ← [Libraries](02-libraries.md) | [Schema](04-schema.md) → diff --git a/src/Composer/Repository/ComposerRepository.php b/src/Composer/Repository/ComposerRepository.php index 06c984bd5..624621d79 100644 --- a/src/Composer/Repository/ComposerRepository.php +++ b/src/Composer/Repository/ComposerRepository.php @@ -1044,7 +1044,12 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito return false; } - if (--$retries) { + // special error code returned when network is being artificially disabled + if ($e instanceof TransportException && $e->getStatusCode() === 499) { + $retries = 0; + } + + if (--$retries > 0) { usleep(100000); return $httpDownloader->add($filename, $options)->then($accept, $reject); diff --git a/src/Composer/Util/HttpDownloader.php b/src/Composer/Util/HttpDownloader.php index 0e882c4a3..f2308d75a 100644 --- a/src/Composer/Util/HttpDownloader.php +++ b/src/Composer/Util/HttpDownloader.php @@ -16,6 +16,7 @@ use Composer\Config; use Composer\IO\IOInterface; use Composer\Downloader\TransportException; use Composer\CaBundle\CaBundle; +use Composer\Util\Http\Response; use Psr\Log\LoggerInterface; use React\Promise\Promise; @@ -40,6 +41,7 @@ class HttpDownloader private $curl; private $rfs; private $idGen = 0; + private $disabled; /** * @param IOInterface $io The IO instance @@ -51,6 +53,8 @@ class HttpDownloader { $this->io = $io; + $this->disabled = (bool) getenv('COMPOSER_DISABLE_NETWORK'); + // Setup TLS options // The cafile option can be set via config.json if ($disableTls === false) { @@ -216,6 +220,17 @@ class HttpDownloader $options = $job['request']['options']; $origin = $job['origin']; + if ($this->disabled) { + if (isset($job['request']['options']['http']['header']) && false !== stripos(implode('', $job['request']['options']['http']['header']), 'if-modified-since')) { + $resolve(new Response(array('url' => $url), 304, array(), '')); + } else { + $e = new TransportException('Network disabled', 499); + $e->setStatusCode(499); + $reject($e); + } + return; + } + if ($job['request']['copyTo']) { $this->curl->download($resolve, $reject, $origin, $url, $options, $job['request']['copyTo']); } else {