OLD | NEW |
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 /** | 5 /** |
6 * Helper functionality to make working with IO easier. | 6 * Helper functionality to make working with IO easier. |
7 */ | 7 */ |
8 library io; | 8 library io; |
9 | 9 |
10 import 'dart:io'; | 10 import 'dart:io'; |
11 import 'dart:isolate'; | 11 import 'dart:isolate'; |
| 12 import 'dart:json'; |
12 import 'dart:uri'; | 13 import 'dart:uri'; |
13 | 14 |
14 // TODO(nweiz): Make this import better. | |
15 import '../../pkg/http/lib/http.dart' as http; | |
16 import 'curl_client.dart'; | |
17 import 'log.dart' as log; | 15 import 'log.dart' as log; |
18 import 'path.dart' as path; | 16 import 'path.dart' as path; |
19 import 'utils.dart'; | 17 import 'utils.dart'; |
20 | 18 |
21 bool _isGitInstalledCache; | 19 bool _isGitInstalledCache; |
22 | 20 |
23 /// The cached Git command. | 21 /// The cached Git command. |
24 String _gitCommandCache; | 22 String _gitCommandCache; |
25 | 23 |
26 final NEWLINE_PATTERN = new RegExp("\r\n?|\n\r?"); | 24 final NEWLINE_PATTERN = new RegExp("\r\n?|\n\r?"); |
(...skipping 468 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
495 }; | 493 }; |
496 | 494 |
497 stream.onError = (e) { | 495 stream.onError = (e) { |
498 removeCallbacks(); | 496 removeCallbacks(); |
499 completer.completeException(e, stackTrace); | 497 completer.completeException(e, stackTrace); |
500 }; | 498 }; |
501 | 499 |
502 return completer.future; | 500 return completer.future; |
503 } | 501 } |
504 | 502 |
505 // TODO(nweiz): make this configurable | |
506 /** | |
507 * The amount of time in milliseconds to allow HTTP requests before assuming | |
508 * they've failed. | |
509 */ | |
510 final HTTP_TIMEOUT = 30 * 1000; | |
511 | |
512 /// An HTTP client that transforms 40* errors and socket exceptions into more | |
513 /// user-friendly error messages. | |
514 class PubHttpClient extends http.BaseClient { | |
515 final http.Client _inner; | |
516 | |
517 PubHttpClient([http.Client inner]) | |
518 : _inner = inner == null ? new http.Client() : inner; | |
519 | |
520 Future<http.StreamedResponse> send(http.BaseRequest request) { | |
521 log.io("Sending HTTP request $request."); | |
522 // TODO(rnystrom): Log request body when it's available and plaintext, but | |
523 // not when it contains OAuth2 credentials. | |
524 | |
525 // TODO(nweiz): remove this when issue 4061 is fixed. | |
526 var stackTrace; | |
527 try { | |
528 throw null; | |
529 } catch (_, localStackTrace) { | |
530 stackTrace = localStackTrace; | |
531 } | |
532 | |
533 // TODO(nweiz): Ideally the timeout would extend to reading from the | |
534 // response input stream, but until issue 3657 is fixed that's not feasible. | |
535 return timeout(_inner.send(request).chain((streamedResponse) { | |
536 log.fine("Got response ${streamedResponse.statusCode} " | |
537 "${streamedResponse.reasonPhrase}."); | |
538 | |
539 var status = streamedResponse.statusCode; | |
540 // 401 responses should be handled by the OAuth2 client. It's very | |
541 // unlikely that they'll be returned by non-OAuth2 requests. | |
542 if (status < 400 || status == 401) { | |
543 return new Future.immediate(streamedResponse); | |
544 } | |
545 | |
546 return http.Response.fromStream(streamedResponse).transform((response) { | |
547 throw new PubHttpException(response); | |
548 }); | |
549 }).transformException((e) { | |
550 if (e is SocketIOException && | |
551 e.osError != null && | |
552 (e.osError.errorCode == 8 || | |
553 e.osError.errorCode == -2 || | |
554 e.osError.errorCode == -5 || | |
555 e.osError.errorCode == 11004)) { | |
556 throw 'Could not resolve URL "${request.url.origin}".'; | |
557 } | |
558 throw e; | |
559 }), HTTP_TIMEOUT, 'fetching URL "${request.url}"'); | |
560 } | |
561 } | |
562 | |
563 /// The HTTP client to use for all HTTP requests. | |
564 final httpClient = new PubHttpClient(); | |
565 | |
566 final curlClient = new PubHttpClient(new CurlClient()); | |
567 | |
568 /** | 503 /** |
569 * Takes all input from [source] and writes it to [sink]. | 504 * Takes all input from [source] and writes it to [sink]. |
570 * | 505 * |
571 * Returns a future that completes when [source] is closed. | 506 * Returns a future that completes when [source] is closed. |
572 */ | 507 */ |
573 Future pipeInputToInput(InputStream source, ListInputStream sink) { | 508 Future pipeInputToInput(InputStream source, ListInputStream sink) { |
574 var completer = new Completer(); | 509 var completer = new Completer(); |
575 source.onClosed = () { | 510 source.onClosed = () { |
576 sink.markEndOfStream(); | 511 sink.markEndOfStream(); |
577 completer.complete(null); | 512 completer.complete(null); |
(...skipping 429 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1007 // TODO(rnystrom): Should log this and display it if an actual error | 942 // TODO(rnystrom): Should log this and display it if an actual error |
1008 // occurs. | 943 // occurs. |
1009 consumeInputStream(process.stderr); | 944 consumeInputStream(process.stderr); |
1010 return pipeInputToInput(process.stdout, stream); | 945 return pipeInputToInput(process.stdout, stream); |
1011 }); | 946 }); |
1012 }); | 947 }); |
1013 return stream; | 948 return stream; |
1014 } | 949 } |
1015 | 950 |
1016 /** | 951 /** |
1017 * Exception thrown when an HTTP operation fails. | |
1018 */ | |
1019 class PubHttpException implements Exception { | |
1020 final http.Response response; | |
1021 | |
1022 const PubHttpException(this.response); | |
1023 | |
1024 String toString() => 'HTTP error ${response.statusCode}: ' | |
1025 '${response.reasonPhrase}'; | |
1026 } | |
1027 | |
1028 /** | |
1029 * Exception thrown when an operation times out. | 952 * Exception thrown when an operation times out. |
1030 */ | 953 */ |
1031 class TimeoutException implements Exception { | 954 class TimeoutException implements Exception { |
1032 final String message; | 955 final String message; |
1033 | 956 |
1034 const TimeoutException(this.message); | 957 const TimeoutException(this.message); |
1035 | 958 |
1036 String toString() => message; | 959 String toString() => message; |
1037 } | 960 } |
1038 | 961 |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1070 return new Directory(entry); | 993 return new Directory(entry); |
1071 } | 994 } |
1072 | 995 |
1073 /** | 996 /** |
1074 * Gets a [Uri] for [uri], which can either already be one, or be a [String]. | 997 * Gets a [Uri] for [uri], which can either already be one, or be a [String]. |
1075 */ | 998 */ |
1076 Uri _getUri(uri) { | 999 Uri _getUri(uri) { |
1077 if (uri is Uri) return uri; | 1000 if (uri is Uri) return uri; |
1078 return new Uri.fromString(uri); | 1001 return new Uri.fromString(uri); |
1079 } | 1002 } |
OLD | NEW |