diff --git a/lib/Github/HttpClient/Plugin/GithubExceptionThrower.php b/lib/Github/HttpClient/Plugin/GithubExceptionThrower.php index 4603f629881..78628c6740f 100644 --- a/lib/Github/HttpClient/Plugin/GithubExceptionThrower.php +++ b/lib/Github/HttpClient/Plugin/GithubExceptionThrower.php @@ -120,6 +120,21 @@ public function handleRequest(RequestInterface $request, callable $next, callabl throw new SsoRequiredException($url); } + $remaining = ResponseMediator::getHeader($response, 'X-RateLimit-Remaining'); + if ((403 === $response->getStatusCode()) && null !== $remaining && 1 > $remaining && isset($content['message']) && (0 === strpos($content['message'], 'API rate limit exceeded'))) { + $limit = (int) ResponseMediator::getHeader($response, 'X-RateLimit-Limit'); + $reset = (int) ResponseMediator::getHeader($response, 'X-RateLimit-Reset'); + + throw new ApiLimitExceedException($limit, $reset); + } + + $reset = (int) ResponseMediator::getHeader($response, 'X-RateLimit-Reset'); + if ((403 === $response->getStatusCode()) && 0 < $reset && isset($content['message']) && (0 === strpos($content['message'], 'You have exceeded a secondary rate limit.'))) { + $limit = (int) ResponseMediator::getHeader($response, 'X-RateLimit-Limit'); + + throw new ApiLimitExceedException($limit, $reset); + } + throw new RuntimeException(isset($content['message']) ? $content['message'] : $content, $response->getStatusCode()); }); } diff --git a/test/Github/Tests/HttpClient/Plugin/GithubExceptionThrowerTest.php b/test/Github/Tests/HttpClient/Plugin/GithubExceptionThrowerTest.php index 99973521980..f8090ef622c 100644 --- a/test/Github/Tests/HttpClient/Plugin/GithubExceptionThrowerTest.php +++ b/test/Github/Tests/HttpClient/Plugin/GithubExceptionThrowerTest.php @@ -75,6 +75,40 @@ public static function responseProvider() ), 'exception' => new \Github\Exception\ApiLimitExceedException(5000), ], + 'Rate Limit Exceeded via 403 status' => [ + 'response' => new Response( + 403, + [ + 'Content-Type' => 'application/json', + 'X-RateLimit-Remaining' => 0, + 'X-RateLimit-Limit' => 5000, + 'X-RateLimit-Reset' => 1609245810, + ], + json_encode( + [ + 'message' => 'API rate limit exceeded for installation ID xxxxxxx.', + ] + ) + ), + 'exception' => new \Github\Exception\ApiLimitExceedException(5000), + ], + 'Secondary Rate Limit Exceeded via 403 status' => [ + 'response' => new Response( + 403, + [ + 'Content-Type' => 'application/json', + 'X-RateLimit-Remaining' => 100, + 'X-RateLimit-Limit' => 5000, + 'X-RateLimit-Reset' => 1609245810, + ], + json_encode( + [ + 'message' => 'You have exceeded a secondary rate limit. Please wait a few minutes before you try again.', + ] + ) + ), + 'exception' => new \Github\Exception\ApiLimitExceedException(5000), + ], 'Two Factor Authentication Required' => [ 'response' => new Response( 401,