| 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 |