Fix race condition where multiple http requests requiring auth end up failing, fixes #10763
parent
1d0fa93495
commit
aeb204bb1d
|
@ -79,11 +79,12 @@ class AuthHelper
|
||||||
* @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[] $headers
|
* @param string[] $headers
|
||||||
|
* @param int $retryCount the amount of retries already done on this URL
|
||||||
* @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
|
||||||
* @phpstan-return ?array{retry: bool, storeAuth: string|bool}
|
* @phpstan-return ?array{retry: bool, storeAuth: string|bool}
|
||||||
*/
|
*/
|
||||||
public function promptAuthIfNeeded($url, $origin, $statusCode, $reason = null, $headers = array())
|
public function promptAuthIfNeeded($url, $origin, $statusCode, $reason = null, $headers = array(), $retryCount = 0)
|
||||||
{
|
{
|
||||||
$storeAuth = false;
|
$storeAuth = false;
|
||||||
|
|
||||||
|
@ -200,8 +201,15 @@ class AuthHelper
|
||||||
|
|
||||||
throw new TransportException($message, $statusCode);
|
throw new TransportException($message, $statusCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
// fail if we already have auth
|
// fail if we already have auth
|
||||||
if ($this->io->hasAuthentication($origin)) {
|
if ($this->io->hasAuthentication($origin)) {
|
||||||
|
// if two or more requests are started together for the same host, and the first
|
||||||
|
// received authentication already, we let the others retry before failing them
|
||||||
|
if ($retryCount === 0) {
|
||||||
|
return array('retry' => true, 'storeAuth' => false);
|
||||||
|
}
|
||||||
|
|
||||||
throw new TransportException("Invalid credentials for '" . $url . "', aborting.", $statusCode);
|
throw new TransportException("Invalid credentials for '" . $url . "', aborting.", $statusCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -528,7 +528,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']) {
|
||||||
$result = $this->authHelper->promptAuthIfNeeded($job['url'], $job['origin'], $response->getStatusCode(), $response->getStatusMessage(), $response->getHeaders());
|
$result = $this->authHelper->promptAuthIfNeeded($job['url'], $job['origin'], $response->getStatusCode(), $response->getStatusMessage(), $response->getHeaders(), $job['attributes']['retries']);
|
||||||
|
|
||||||
if ($result['retry']) {
|
if ($result['retry']) {
|
||||||
return $result;
|
return $result;
|
||||||
|
@ -560,7 +560,7 @@ class CurlDownloader
|
||||||
|
|
||||||
if ($needsAuthRetry) {
|
if ($needsAuthRetry) {
|
||||||
if ($job['attributes']['retryAuthFailure']) {
|
if ($job['attributes']['retryAuthFailure']) {
|
||||||
$result = $this->authHelper->promptAuthIfNeeded($job['url'], $job['origin'], 401);
|
$result = $this->authHelper->promptAuthIfNeeded($job['url'], $job['origin'], 401, null, array(), $job['attributes']['retries']);
|
||||||
if ($result['retry']) {
|
if ($result['retry']) {
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -645,7 +645,7 @@ class RemoteFilesystem
|
||||||
*/
|
*/
|
||||||
protected function promptAuthAndRetry($httpStatus, $reason = null, $headers = array())
|
protected function promptAuthAndRetry($httpStatus, $reason = null, $headers = array())
|
||||||
{
|
{
|
||||||
$result = $this->authHelper->promptAuthIfNeeded($this->fileUrl, $this->originUrl, $httpStatus, $reason, $headers);
|
$result = $this->authHelper->promptAuthIfNeeded($this->fileUrl, $this->originUrl, $httpStatus, $reason, $headers, 1 /** always pass 1 as RemoteFilesystem is single threaded there is no race condition possible */);
|
||||||
|
|
||||||
$this->storeAuth = $result['storeAuth'];
|
$this->storeAuth = $result['storeAuth'];
|
||||||
$this->retry = $result['retry'];
|
$this->retry = $result['retry'];
|
||||||
|
|
Loading…
Reference in New Issue