Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(251)

Side by Side Diff: lib/src/http.dart

Issue 1235013002: Remove the timeout for downloading packages. (Closed) Base URL: git@github.com:dart-lang/pub.git@master
Patch Set: Code review changes Created 5 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « lib/src/command/lish.dart ('k') | lib/src/io.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 /// Helpers for dealing with HTTP. 5 /// Helpers for dealing with HTTP.
6 library pub.http; 6 library pub.http;
7 7
8 import 'dart:async'; 8 import 'dart:async';
9 import 'dart:convert'; 9 import 'dart:convert';
10 import 'dart:io'; 10 import 'dart:io';
11 11
12 import 'package:http/http.dart' as http; 12 import 'package:http/http.dart' as http;
13 import 'package:http_throttle/http_throttle.dart'; 13 import 'package:http_throttle/http_throttle.dart';
14 import 'package:stack_trace/stack_trace.dart'; 14 import 'package:stack_trace/stack_trace.dart';
15 15
16 import 'io.dart';
17 import 'log.dart' as log; 16 import 'log.dart' as log;
18 import 'oauth2.dart' as oauth2; 17 import 'oauth2.dart' as oauth2;
19 import 'sdk.dart' as sdk; 18 import 'sdk.dart' as sdk;
20 import 'utils.dart'; 19 import 'utils.dart';
21 20
22 // TODO(nweiz): make this configurable
23 /// The amount of time in milliseconds to allow HTTP requests before assuming
24 /// they've failed.
25 final HTTP_TIMEOUT = 30 * 1000;
26
27 /// Headers and field names that should be censored in the log output. 21 /// Headers and field names that should be censored in the log output.
28 final _CENSORED_FIELDS = const ['refresh_token', 'authorization']; 22 final _CENSORED_FIELDS = const ['refresh_token', 'authorization'];
29 23
30 /// Headers required for pub.dartlang.org API requests. 24 /// Headers required for pub.dartlang.org API requests.
31 /// 25 ///
32 /// The Accept header tells pub.dartlang.org which version of the API we're 26 /// The Accept header tells pub.dartlang.org which version of the API we're
33 /// expecting, so it can either serve that version or give us a 406 error if 27 /// expecting, so it can either serve that version or give us a 406 error if
34 /// it's not supported. 28 /// it's not supported.
35 final PUB_API_HEADERS = const {'Accept': 'application/vnd.pub.v2+json'}; 29 final PUB_API_HEADERS = const {'Accept': 'application/vnd.pub.v2+json'};
36 30
37 /// An HTTP client that transforms 40* errors and socket exceptions into more 31 /// An HTTP client that transforms 40* errors and socket exceptions into more
38 /// user-friendly error messages. 32 /// user-friendly error messages.
39 ///
40 /// This also adds a 30-second timeout to every request. This can be configured
41 /// on a per-request basis by setting the 'Pub-Request-Timeout' header to the
42 /// desired number of milliseconds, or to "None" to disable the timeout.
43 class _PubHttpClient extends http.BaseClient { 33 class _PubHttpClient extends http.BaseClient {
44 final _requestStopwatches = new Map<http.BaseRequest, Stopwatch>(); 34 final _requestStopwatches = new Map<http.BaseRequest, Stopwatch>();
45 35
46 http.Client _inner; 36 http.Client _inner;
47 37
48 _PubHttpClient([http.Client inner]) 38 _PubHttpClient([http.Client inner])
49 : this._inner = inner == null ? new http.Client() : inner; 39 : this._inner = inner == null ? new http.Client() : inner;
50 40
51 Future<http.StreamedResponse> send(http.BaseRequest request) { 41 Future<http.StreamedResponse> send(http.BaseRequest request) async {
52 _requestStopwatches[request] = new Stopwatch()..start(); 42 _requestStopwatches[request] = new Stopwatch()..start();
53 request.headers[HttpHeaders.USER_AGENT] = "Dart pub ${sdk.version}"; 43 request.headers[HttpHeaders.USER_AGENT] = "Dart pub ${sdk.version}";
54 _logRequest(request); 44 _logRequest(request);
55 45
56 var timeoutLength = HTTP_TIMEOUT; 46 var streamedResponse;
57 var timeoutString = request.headers.remove('Pub-Request-Timeout'); 47 try {
58 if (timeoutString == 'None') { 48 streamedResponse = await _inner.send(request);
59 timeoutLength = null; 49 } on SocketException catch (error, stackTrace) {
60 } else if (timeoutString != null) {
61 timeoutLength = int.parse(timeoutString);
62 }
63
64 var future = _inner.send(request).then((streamedResponse) {
65 _logResponse(streamedResponse);
66
67 var status = streamedResponse.statusCode;
68 // 401 responses should be handled by the OAuth2 client. It's very
69 // unlikely that they'll be returned by non-OAuth2 requests. We also want
70 // to pass along 400 responses from the token endpoint.
71 var tokenRequest = urisEqual(
72 streamedResponse.request.url, oauth2.tokenEndpoint);
73 if (status < 400 || status == 401 || (status == 400 && tokenRequest)) {
74 return streamedResponse;
75 }
76
77 if (status == 406 &&
78 request.headers['Accept'] == PUB_API_HEADERS['Accept']) {
79 fail("Pub ${sdk.version} is incompatible with the current version of "
80 "${request.url.host}.\n"
81 "Upgrade pub to the latest version and try again.");
82 }
83
84 if (status == 500 &&
85 (request.url.host == "pub.dartlang.org" ||
86 request.url.host == "storage.googleapis.com")) {
87 var message = "HTTP error 500: Internal Server Error at "
88 "${request.url}.";
89
90 if (request.url.host == "pub.dartlang.org" ||
91 request.url.host == "storage.googleapis.com") {
92 message += "\nThis is likely a transient error. Please try again "
93 "later.";
94 }
95
96 fail(message);
97 }
98
99 return http.Response.fromStream(streamedResponse).then((response) {
100 throw new PubHttpException(response);
101 });
102 }).catchError((error, stackTrace) {
103 // Work around issue 23008. 50 // Work around issue 23008.
104 if (stackTrace == null) stackTrace = new Chain.current(); 51 if (stackTrace == null) stackTrace = new Chain.current();
105 52
106 if (error is SocketException && 53 if (error.osError == null) rethrow;
107 error.osError != null) { 54
108 if (error.osError.errorCode == 8 || 55 if (error.osError.errorCode == 8 ||
109 error.osError.errorCode == -2 || 56 error.osError.errorCode == -2 ||
110 error.osError.errorCode == -5 || 57 error.osError.errorCode == -5 ||
111 error.osError.errorCode == 11001 || 58 error.osError.errorCode == 11001 ||
112 error.osError.errorCode == 11004) { 59 error.osError.errorCode == 11004) {
113 fail('Could not resolve URL "${request.url.origin}".', 60 fail('Could not resolve URL "${request.url.origin}".',
114 error, stackTrace); 61 error, stackTrace);
115 } else if (error.osError.errorCode == -12276) { 62 } else if (error.osError.errorCode == -12276) {
116 fail('Unable to validate SSL certificate for ' 63 fail('Unable to validate SSL certificate for '
117 '"${request.url.origin}".', 64 '"${request.url.origin}".',
118 error, stackTrace); 65 error, stackTrace);
119 } 66 } else {
67 rethrow;
120 } 68 }
121 throw error; 69 }
122 });
123 70
124 if (timeoutLength == null) return future; 71 _logResponse(streamedResponse);
125 return timeout(future, timeoutLength, request.url, 72
126 'fetching URL "${request.url}"'); 73 var status = streamedResponse.statusCode;
74 // 401 responses should be handled by the OAuth2 client. It's very
75 // unlikely that they'll be returned by non-OAuth2 requests. We also want
76 // to pass along 400 responses from the token endpoint.
77 var tokenRequest = urisEqual(
78 streamedResponse.request.url, oauth2.tokenEndpoint);
79 if (status < 400 || status == 401 || (status == 400 && tokenRequest)) {
80 return streamedResponse;
81 }
82
83 if (status == 406 &&
84 request.headers['Accept'] == PUB_API_HEADERS['Accept']) {
85 fail("Pub ${sdk.version} is incompatible with the current version of "
86 "${request.url.host}.\n"
87 "Upgrade pub to the latest version and try again.");
88 }
89
90 if (status == 500 &&
91 (request.url.host == "pub.dartlang.org" ||
92 request.url.host == "storage.googleapis.com")) {
93 var message = "HTTP error 500: Internal Server Error at "
94 "${request.url}.";
95
96 if (request.url.host == "pub.dartlang.org" ||
97 request.url.host == "storage.googleapis.com") {
98 message += "\nThis is likely a transient error. Please try again "
99 "later.";
100 }
101
102 fail(message);
103 }
104
105 throw new PubHttpException(
106 await http.Response.fromStream(streamedResponse));
127 } 107 }
128 108
129 /// Logs the fact that [request] was sent, and information about it. 109 /// Logs the fact that [request] was sent, and information about it.
130 void _logRequest(http.BaseRequest request) { 110 void _logRequest(http.BaseRequest request) {
131 var requestLog = new StringBuffer(); 111 var requestLog = new StringBuffer();
132 requestLog.writeln("HTTP ${request.method} ${request.url}"); 112 requestLog.writeln("HTTP ${request.method} ${request.url}");
133 request.headers.forEach((name, value) => 113 request.headers.forEach((name, value) =>
134 requestLog.writeln(_logField(name, value))); 114 requestLog.writeln(_logField(name, value)));
135 115
136 if (request.method == 'POST') { 116 if (request.method == 'POST') {
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after
249 229
250 /// Exception thrown when an HTTP operation fails. 230 /// Exception thrown when an HTTP operation fails.
251 class PubHttpException implements Exception { 231 class PubHttpException implements Exception {
252 final http.Response response; 232 final http.Response response;
253 233
254 const PubHttpException(this.response); 234 const PubHttpException(this.response);
255 235
256 String toString() => 'HTTP error ${response.statusCode}: ' 236 String toString() => 'HTTP error ${response.statusCode}: '
257 '${response.reasonPhrase}'; 237 '${response.reasonPhrase}';
258 } 238 }
OLDNEW
« no previous file with comments | « lib/src/command/lish.dart ('k') | lib/src/io.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698