Fix retry logic (#1762)
Closes https://github.com/dart-lang/pub/issues/1556
diff --git a/lib/src/http.dart b/lib/src/http.dart
index 3441892..9f11012 100644
--- a/lib/src/http.dart
+++ b/lib/src/http.dart
@@ -92,39 +92,7 @@
_logResponse(streamedResponse);
- var status = streamedResponse.statusCode;
- // 401 responses should be handled by the OAuth2 client. It's very
- // unlikely that they'll be returned by non-OAuth2 requests. We also want
- // to pass along 400 responses from the token endpoint.
- var tokenRequest = streamedResponse.request.url == oauth2.tokenEndpoint;
- if (status < 400 || status == 401 || (status == 400 && tokenRequest)) {
- return streamedResponse;
- }
-
- if (status == 406 &&
- request.headers['Accept'] == PUB_API_HEADERS['Accept']) {
- fail("Pub ${sdk.version} is incompatible with the current version of "
- "${request.url.host}.\n"
- "Upgrade pub to the latest version and try again.");
- }
-
- if (status == 500 &&
- (request.url.host == "pub.dartlang.org" ||
- request.url.host == "storage.googleapis.com")) {
- var message = "HTTP error 500: Internal Server Error at "
- "${request.url}.";
-
- if (request.url.host == "pub.dartlang.org" ||
- request.url.host == "storage.googleapis.com") {
- message += "\nThis is likely a transient error. Please try again "
- "later.";
- }
-
- fail(message);
- }
-
- throw new PubHttpException(
- await http.Response.fromStream(streamedResponse));
+ return streamedResponse;
}
/// Whether extra metadata headers should be added to [request].
@@ -216,10 +184,48 @@
/// we're waiting for them to come back up.
final _retriedHosts = new Set<String>();
+/// Intercepts all requests and throws exceptions if the response was not
+/// considered successful.
+class _ThrowingClient extends http.BaseClient {
+ final http.Client _inner;
+
+ _ThrowingClient(this._inner);
+
+ Future<http.StreamedResponse> send(http.BaseRequest request) async {
+ final streamedResponse = await _inner.send(request);
+
+ var status = streamedResponse.statusCode;
+ // 401 responses should be handled by the OAuth2 client. It's very
+ // unlikely that they'll be returned by non-OAuth2 requests. We also want
+ // to pass along 400 responses from the token endpoint.
+ var tokenRequest = streamedResponse.request.url == oauth2.tokenEndpoint;
+ if (status < 400 || status == 401 || (status == 400 && tokenRequest)) {
+ return streamedResponse;
+ }
+
+ if (status == 406 &&
+ request.headers['Accept'] == PUB_API_HEADERS['Accept']) {
+ fail("Pub ${sdk.version} is incompatible with the current version of "
+ "${request.url.host}.\n"
+ "Upgrade pub to the latest version and try again.");
+ }
+
+ if (status == 500 &&
+ (request.url.host == "pub.dartlang.org" ||
+ request.url.host == "storage.googleapis.com")) {
+ fail("HTTP error 500: Internal Server Error at ${request.url}.\n"
+ "This is likely a transient error. Please try again later.");
+ }
+
+ throw new PubHttpException(
+ await http.Response.fromStream(streamedResponse));
+ }
+}
+
/// The HTTP client to use for all HTTP requests.
final httpClient = new ThrottleClient(
16,
- new RetryClient(_pubClient,
+ new _ThrowingClient(new RetryClient(_pubClient,
retries: 5,
when: (response) => const [502, 503, 504].contains(response.statusCode),
delay: (retryCount) {
@@ -245,7 +251,7 @@
log.message(
"It looks like ${request.url.host} is having some trouble.\n"
"Pub will wait for a while before trying to connect again.");
- }));
+ })));
/// The underlying HTTP client wrapped by [httpClient].
http.Client get innerHttpClient => _pubClient._inner;