Show warning in all 400/500 responses if available, fixes #7814
parent
5f988a34a6
commit
3f5a986170
|
@ -962,7 +962,7 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito
|
||||||
}
|
}
|
||||||
|
|
||||||
$data = $response->decodeJson();
|
$data = $response->decodeJson();
|
||||||
$this->outputWarnings($data);
|
HttpDownloader::outputWarnings($this->io, $this->url, $data);
|
||||||
|
|
||||||
if ($cacheKey) {
|
if ($cacheKey) {
|
||||||
if ($storeLastModifiedTime) {
|
if ($storeLastModifiedTime) {
|
||||||
|
@ -1036,7 +1036,7 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito
|
||||||
}
|
}
|
||||||
|
|
||||||
$data = $response->decodeJson();
|
$data = $response->decodeJson();
|
||||||
$this->outputWarnings($data);
|
HttpDownloader::outputWarnings($this->io, $this->url, $data);
|
||||||
|
|
||||||
$lastModifiedDate = $response->getHeader('last-modified');
|
$lastModifiedDate = $response->getHeader('last-modified');
|
||||||
$response->collect();
|
$response->collect();
|
||||||
|
@ -1101,7 +1101,7 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito
|
||||||
}
|
}
|
||||||
|
|
||||||
$data = $response->decodeJson();
|
$data = $response->decodeJson();
|
||||||
$this->outputWarnings($data);
|
HttpDownloader::outputWarnings($io, $url, $data);
|
||||||
|
|
||||||
$lastModifiedDate = $response->getHeader('last-modified');
|
$lastModifiedDate = $response->getHeader('last-modified');
|
||||||
$response->collect();
|
$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
|
// wipe rootData as it is fully consumed at this point and this saves some memory
|
||||||
$this->rootData = true;
|
$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].'</'.$type.'>');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,12 +71,11 @@ class AuthHelper
|
||||||
* @param string $origin
|
* @param string $origin
|
||||||
* @param int $statusCode HTTP status code that triggered this call
|
* @param int $statusCode HTTP status code that triggered this call
|
||||||
* @param string|null $reason a message/description explaining why this was called
|
* @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
|
* @param string[] $headers
|
||||||
* @return array|null containing retry (bool) and storeAuth (string|bool) keys, if retry is true the request should be
|
* @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
|
* 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;
|
$storeAuth = false;
|
||||||
$retry = false;
|
$retry = false;
|
||||||
|
@ -173,10 +172,6 @@ class AuthHelper
|
||||||
throw new TransportException("Invalid credentials for '" . $url . "', aborting.", $statusCode);
|
throw new TransportException("Invalid credentials for '" . $url . "', aborting.", $statusCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->io->overwriteError('');
|
|
||||||
if ($warning) {
|
|
||||||
$this->io->writeError(' <warning>'.$warning.'</warning>');
|
|
||||||
}
|
|
||||||
$this->io->writeError(' Authentication required (<info>'.parse_url($url, PHP_URL_HOST).'</info>):');
|
$this->io->writeError(' Authentication required (<info>'.parse_url($url, PHP_URL_HOST).'</info>):');
|
||||||
$username = $this->io->ask(' Username: ');
|
$username = $this->io->ask(' Username: ');
|
||||||
$password = $this->io->askAndHideAnswer(' Password: ');
|
$password = $this->io->askAndHideAnswer(' Password: ');
|
||||||
|
|
|
@ -20,6 +20,7 @@ use Composer\Util\RemoteFilesystem;
|
||||||
use Composer\Util\StreamContextFactory;
|
use Composer\Util\StreamContextFactory;
|
||||||
use Composer\Util\AuthHelper;
|
use Composer\Util\AuthHelper;
|
||||||
use Composer\Util\Url;
|
use Composer\Util\Url;
|
||||||
|
use Composer\Util\HttpDownloader;
|
||||||
use React\Promise\Promise;
|
use React\Promise\Promise;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -261,6 +262,10 @@ class CurlDownloader
|
||||||
$this->io->writeError('['.$statusCode.'] '.$progress['url'], true, IOInterface::DEBUG);
|
$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);
|
$result = $this->isAuthenticatedRetryNeeded($job, $response);
|
||||||
if ($result['retry']) {
|
if ($result['retry']) {
|
||||||
if ($job['filename']) {
|
if ($job['filename']) {
|
||||||
|
@ -371,15 +376,7 @@ class CurlDownloader
|
||||||
private function isAuthenticatedRetryNeeded(array $job, Response $response)
|
private function isAuthenticatedRetryNeeded(array $job, Response $response)
|
||||||
{
|
{
|
||||||
if (in_array($response->getStatusCode(), array(401, 403)) && $job['attributes']['retryAuthFailure']) {
|
if (in_array($response->getStatusCode(), array(401, 403)) && $job['attributes']['retryAuthFailure']) {
|
||||||
$warning = null;
|
$result = $this->authHelper->promptAuthIfNeeded($job['url'], $job['origin'], $response->getStatusCode(), $response->getStatusMessage(), $response->getHeaders());
|
||||||
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());
|
|
||||||
|
|
||||||
if ($result['retry']) {
|
if ($result['retry']) {
|
||||||
return $result;
|
return $result;
|
||||||
|
|
|
@ -17,6 +17,8 @@ use Composer\IO\IOInterface;
|
||||||
use Composer\Downloader\TransportException;
|
use Composer\Downloader\TransportException;
|
||||||
use Composer\CaBundle\CaBundle;
|
use Composer\CaBundle\CaBundle;
|
||||||
use Composer\Util\Http\Response;
|
use Composer\Util\Http\Response;
|
||||||
|
use Composer\Package\Version\VersionParser;
|
||||||
|
use Composer\Semver\Constraint\Constraint;
|
||||||
use React\Promise\Promise;
|
use React\Promise\Promise;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -313,4 +315,24 @@ class HttpDownloader
|
||||||
|
|
||||||
return $resp;
|
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].'</'.$type.'>');
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@ use Composer\Config;
|
||||||
use Composer\IO\IOInterface;
|
use Composer\IO\IOInterface;
|
||||||
use Composer\Downloader\TransportException;
|
use Composer\Downloader\TransportException;
|
||||||
use Composer\CaBundle\CaBundle;
|
use Composer\CaBundle\CaBundle;
|
||||||
|
use Composer\Util\HttpDownloader;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author François Pluchino <francois.pluchino@opendisplay.com>
|
* @author François Pluchino <francois.pluchino@opendisplay.com>
|
||||||
|
@ -291,15 +292,12 @@ class RemoteFilesystem
|
||||||
|
|
||||||
if (!empty($http_response_header[0])) {
|
if (!empty($http_response_header[0])) {
|
||||||
$statusCode = $this->findStatusCode($http_response_header);
|
$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) {
|
if (in_array($statusCode, array(401, 403)) && $this->retryAuthFailure) {
|
||||||
$warning = null;
|
$this->promptAuthAndRetry($statusCode, $this->findStatusMessage($http_response_header), $http_response_header);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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->storeAuth = $result['storeAuth'];
|
||||||
$this->retry = $result['retry'];
|
$this->retry = $result['retry'];
|
||||||
|
|
Loading…
Reference in New Issue