1
0
Fork 0

Handle http 401/403 differently to allow reading warning message

pull/7096/merge
Jordi Boggiano 2018-04-12 15:57:14 +02:00
parent 7afd1a9385
commit 174c71de04
1 changed files with 36 additions and 24 deletions

View File

@ -175,6 +175,24 @@ class RemoteFilesystem
return $value; return $value;
} }
/**
* @param array $headers array of returned headers like from getLastHeaders()
* @return string|null
*/
public function findStatusMessage(array $headers)
{
$value = null;
foreach ($headers as $header) {
if (preg_match('{^HTTP/\S+ \d+}i', $header)) {
// In case of redirects, http_response_headers contains the headers of all responses
// so we can not return directly and need to keep iterating
$value = $header;
}
}
return $value;
}
/** /**
* Get file content or copy action. * Get file content or copy action.
* *
@ -299,6 +317,20 @@ class RemoteFilesystem
try { try {
$result = file_get_contents($fileUrl, false, $ctx); $result = file_get_contents($fileUrl, false, $ctx);
if (!empty($http_response_header[0])) {
$statusCode = $this->findStatusCode($http_response_header);
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);
}
}
$contentLength = !empty($http_response_header[0]) ? $this->findHeaderValue($http_response_header, 'content-length') : null; $contentLength = !empty($http_response_header[0]) ? $this->findHeaderValue($http_response_header, 'content-length') : null;
if ($contentLength && Platform::strlen($result) < $contentLength) { if ($contentLength && Platform::strlen($result) < $contentLength) {
// alas, this is not possible via the stream callback because STREAM_NOTIFY_COMPLETED is documented, but not implemented anywhere in PHP // alas, this is not possible via the stream callback because STREAM_NOTIFY_COMPLETED is documented, but not implemented anywhere in PHP
@ -558,29 +590,6 @@ class RemoteFilesystem
// but you do not send an appropriate certificate // but you do not send an appropriate certificate
throw new TransportException("The '" . $this->fileUrl . "' URL could not be accessed: " . $message, $messageCode); throw new TransportException("The '" . $this->fileUrl . "' URL could not be accessed: " . $message, $messageCode);
} }
// intentional fallthrough to the next case as the notificationCode
// isn't always consistent and we should inspect the messageCode for 401s
case STREAM_NOTIFY_AUTH_REQUIRED:
if (401 === $messageCode) {
// Bail if the caller is going to handle authentication failures itself.
if (!$this->retryAuthFailure) {
break;
}
$this->promptAuthAndRetry($messageCode);
}
break;
case STREAM_NOTIFY_AUTH_RESULT:
if (403 === $messageCode) {
// Bail if the caller is going to handle authentication failures itself.
if (!$this->retryAuthFailure) {
break;
}
$this->promptAuthAndRetry($messageCode, $message);
}
break; break;
case STREAM_NOTIFY_FILE_SIZE_IS: case STREAM_NOTIFY_FILE_SIZE_IS:
@ -603,7 +612,7 @@ class RemoteFilesystem
} }
} }
protected function promptAuthAndRetry($httpStatus, $reason = null) protected function promptAuthAndRetry($httpStatus, $reason = null, $warning = null)
{ {
if ($this->config && in_array($this->originUrl, $this->config->get('github-domains'), true)) { if ($this->config && in_array($this->originUrl, $this->config->get('github-domains'), true)) {
$message = "\n".'Could not fetch '.$this->fileUrl.', please create a GitHub OAuth token '.($httpStatus === 404 ? 'to access private repos' : 'to go over the API rate limit'); $message = "\n".'Could not fetch '.$this->fileUrl.', please create a GitHub OAuth token '.($httpStatus === 404 ? 'to access private repos' : 'to go over the API rate limit');
@ -674,6 +683,9 @@ class RemoteFilesystem
} }
$this->io->overwriteError(''); $this->io->overwriteError('');
if ($warning) {
$this->io->writeError(' <warning>'.$warning.'</warning>');
}
$this->io->writeError(' Authentication required (<info>'.parse_url($this->fileUrl, PHP_URL_HOST).'</info>):'); $this->io->writeError(' Authentication required (<info>'.parse_url($this->fileUrl, PHP_URL_HOST).'</info>):');
$username = $this->io->ask(' Username: '); $username = $this->io->ask(' Username: ');
$password = $this->io->askAndHideAnswer(' Password: '); $password = $this->io->askAndHideAnswer(' Password: ');