diff --git a/src/Composer/Repository/ComposerRepository.php b/src/Composer/Repository/ComposerRepository.php index e835e221b..0cdb74bd6 100644 --- a/src/Composer/Repository/ComposerRepository.php +++ b/src/Composer/Repository/ComposerRepository.php @@ -962,7 +962,7 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito } $data = $response->decodeJson(); - $this->outputWarnings($data); + HttpDownloader::outputWarnings($this->io, $this->url, $data); if ($cacheKey) { if ($storeLastModifiedTime) { @@ -1036,7 +1036,7 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito } $data = $response->decodeJson(); - $this->outputWarnings($data); + HttpDownloader::outputWarnings($this->io, $this->url, $data); $lastModifiedDate = $response->getHeader('last-modified'); $response->collect(); @@ -1101,7 +1101,7 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito } $data = $response->decodeJson(); - $this->outputWarnings($data); + HttpDownloader::outputWarnings($io, $url, $data); $lastModifiedDate = $response->getHeader('last-modified'); $response->collect(); @@ -1161,24 +1161,4 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito // wipe rootData as it is fully consumed at this point and this saves some memory $this->rootData = true; } - - private function outputWarnings($data) - { - foreach (array('warning', 'info') as $type) { - if (empty($data[$type])) { - continue; - } - - if (!empty($data[$type . '-versions'])) { - $versionParser = new VersionParser(); - $constraint = $versionParser->parseConstraints($data[$type . '-versions']); - $composer = new Constraint('==', $versionParser->normalize(Composer::getVersion())); - if (!$constraint->matches($composer)) { - continue; - } - } - - $this->io->writeError('<'.$type.'>'.ucfirst($type).' from '.$this->url.': '.$data[$type].''); - } - } } diff --git a/src/Composer/Util/AuthHelper.php b/src/Composer/Util/AuthHelper.php index 2868d3346..7085f2561 100644 --- a/src/Composer/Util/AuthHelper.php +++ b/src/Composer/Util/AuthHelper.php @@ -71,12 +71,11 @@ class AuthHelper * @param string $origin * @param int $statusCode HTTP status code that triggered this call * @param string|null $reason a message/description explaining why this was called - * @param string $warning an authentication warning returned by the server as {"warning": ".."}, if present * @param string[] $headers * @return array|null containing retry (bool) and storeAuth (string|bool) keys, if retry is true the request should be * retried, if storeAuth is true then on a successful retry the authentication should be persisted to auth.json */ - public function promptAuthIfNeeded($url, $origin, $statusCode, $reason = null, $warning = null, $headers = array()) + public function promptAuthIfNeeded($url, $origin, $statusCode, $reason = null, $headers = array()) { $storeAuth = false; $retry = false; @@ -173,10 +172,6 @@ class AuthHelper throw new TransportException("Invalid credentials for '" . $url . "', aborting.", $statusCode); } - $this->io->overwriteError(''); - if ($warning) { - $this->io->writeError(' '.$warning.''); - } $this->io->writeError(' Authentication required ('.parse_url($url, PHP_URL_HOST).'):'); $username = $this->io->ask(' Username: '); $password = $this->io->askAndHideAnswer(' Password: '); diff --git a/src/Composer/Util/Http/CurlDownloader.php b/src/Composer/Util/Http/CurlDownloader.php index ab0dae91e..1ebc64242 100644 --- a/src/Composer/Util/Http/CurlDownloader.php +++ b/src/Composer/Util/Http/CurlDownloader.php @@ -20,6 +20,7 @@ use Composer\Util\RemoteFilesystem; use Composer\Util\StreamContextFactory; use Composer\Util\AuthHelper; use Composer\Util\Url; +use Composer\Util\HttpDownloader; use React\Promise\Promise; /** @@ -261,6 +262,10 @@ class CurlDownloader $this->io->writeError('['.$statusCode.'] '.$progress['url'], true, IOInterface::DEBUG); } + if ($response->getStatusCode() >= 400 && $response->getHeader('content-type') === 'application/json') { + HttpDownloader::outputWarnings($this->io, $job['origin'], json_decode($response->getBody(), true)); + } + $result = $this->isAuthenticatedRetryNeeded($job, $response); if ($result['retry']) { if ($job['filename']) { @@ -371,15 +376,7 @@ class CurlDownloader private function isAuthenticatedRetryNeeded(array $job, Response $response) { if (in_array($response->getStatusCode(), array(401, 403)) && $job['attributes']['retryAuthFailure']) { - $warning = null; - if ($response->getHeader('content-type') === 'application/json') { - $data = json_decode($response->getBody(), true); - if (!empty($data['warning'])) { - $warning = $data['warning']; - } - } - - $result = $this->authHelper->promptAuthIfNeeded($job['url'], $job['origin'], $response->getStatusCode(), $response->getStatusMessage(), $warning, $response->getHeaders()); + $result = $this->authHelper->promptAuthIfNeeded($job['url'], $job['origin'], $response->getStatusCode(), $response->getStatusMessage(), $response->getHeaders()); if ($result['retry']) { return $result; diff --git a/src/Composer/Util/HttpDownloader.php b/src/Composer/Util/HttpDownloader.php index 5a5ec14b2..94e7ec0db 100644 --- a/src/Composer/Util/HttpDownloader.php +++ b/src/Composer/Util/HttpDownloader.php @@ -17,6 +17,8 @@ use Composer\IO\IOInterface; use Composer\Downloader\TransportException; use Composer\CaBundle\CaBundle; use Composer\Util\Http\Response; +use Composer\Package\Version\VersionParser; +use Composer\Semver\Constraint\Constraint; use React\Promise\Promise; /** @@ -313,4 +315,24 @@ class HttpDownloader return $resp; } + + public static function outputWarnings(IOInterface $io, $url, $data) + { + foreach (array('warning', 'info') as $type) { + if (empty($data[$type])) { + continue; + } + + if (!empty($data[$type . '-versions'])) { + $versionParser = new VersionParser(); + $constraint = $versionParser->parseConstraints($data[$type . '-versions']); + $composer = new Constraint('==', $versionParser->normalize(Composer::getVersion())); + if (!$constraint->matches($composer)) { + continue; + } + } + + $io->writeError('<'.$type.'>'.ucfirst($type).' from '.$url.': '.$data[$type].''); + } + } } diff --git a/src/Composer/Util/RemoteFilesystem.php b/src/Composer/Util/RemoteFilesystem.php index 07eccc791..c6ba4085c 100644 --- a/src/Composer/Util/RemoteFilesystem.php +++ b/src/Composer/Util/RemoteFilesystem.php @@ -16,6 +16,7 @@ use Composer\Config; use Composer\IO\IOInterface; use Composer\Downloader\TransportException; use Composer\CaBundle\CaBundle; +use Composer\Util\HttpDownloader; /** * @author François Pluchino @@ -291,15 +292,12 @@ class RemoteFilesystem if (!empty($http_response_header[0])) { $statusCode = $this->findStatusCode($http_response_header); + if ($statusCode >= 400 && $this->findHeaderValue($http_response_header, 'content-type') === 'application/json') { + HttpDownloader::outputWarnings($this->io, $originUrl, json_decode($result, true)); + } + if (in_array($statusCode, array(401, 403)) && $this->retryAuthFailure) { - $warning = null; - if ($this->findHeaderValue($http_response_header, 'content-type') === 'application/json') { - $data = json_decode($result, true); - if (!empty($data['warning'])) { - $warning = $data['warning']; - } - } - $this->promptAuthAndRetry($statusCode, $this->findStatusMessage($http_response_header), $warning, $http_response_header); + $this->promptAuthAndRetry($statusCode, $this->findStatusMessage($http_response_header), $http_response_header); } } @@ -613,9 +611,9 @@ class RemoteFilesystem } } - protected function promptAuthAndRetry($httpStatus, $reason = null, $warning = null, $headers = array()) + protected function promptAuthAndRetry($httpStatus, $reason = null, $headers = array()) { - $result = $this->authHelper->promptAuthIfNeeded($this->fileUrl, $this->originUrl, $httpStatus, $reason, $warning, $headers); + $result = $this->authHelper->promptAuthIfNeeded($this->fileUrl, $this->originUrl, $httpStatus, $reason, $headers); $this->storeAuth = $result['storeAuth']; $this->retry = $result['retry'];