| 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 library curl_client; | 5 library curl_client; |
| 6 | 6 |
| 7 import 'dart:io'; | 7 import 'dart:io'; |
| 8 | 8 |
| 9 import '../../pkg/http/lib/http.dart' as http; | 9 import '../../pkg/http/lib/http.dart' as http; |
| 10 import 'io.dart'; | 10 import 'io.dart'; |
| 11 import 'utils.dart'; | 11 import 'utils.dart'; |
| 12 | 12 |
| 13 /// A drop-in replacement for [http.Client] that uses the `curl` command-line | 13 /// A drop-in replacement for [http.Client] that uses the `curl` command-line |
| 14 /// utility rather than [dart:io] to make requests. This class will only exist | 14 /// utility rather than [dart:io] to make requests. This class will only exist |
| 15 /// temporarily until [dart:io] natively supports requests over HTTPS. | 15 /// temporarily until [dart:io] natively supports requests over HTTPS. |
| 16 class CurlClient extends http.BaseClient { | 16 class CurlClient extends http.BaseClient { |
| 17 /// The path to the `curl` executable to run. By default, this will look up | 17 /// The path to the `curl` executable to run. |
| 18 /// `curl` on the system path. | 18 /// |
| 19 /// By default on Unix-like operating systems, this will look up `curl` on the |
| 20 /// system path. On Windows, it will use the bundled `curl.exe`. |
| 19 final String executable; | 21 final String executable; |
| 20 | 22 |
| 21 /// Creates a new [CurlClient] with [executable] as the path to the `curl` | 23 /// Creates a new [CurlClient] with [executable] as the path to the `curl` |
| 22 /// executable. By default, this will look up `curl` on the system path. | 24 /// executable. |
| 25 /// |
| 26 /// By default on Unix-like operating systems, this will look up `curl` on the |
| 27 /// system path. On Windows, it will use the bundled `curl.exe`. |
| 23 CurlClient([String executable]) | 28 CurlClient([String executable]) |
| 24 : executable = executable == null ? "curl" : executable; | 29 : executable = executable == null ? _defaultExecutable : executable; |
| 25 | 30 |
| 26 /// Sends a request via `curl` and returns the response. | 31 /// Sends a request via `curl` and returns the response. |
| 27 Future<http.StreamedResponse> send(http.BaseRequest request) { | 32 Future<http.StreamedResponse> send(http.BaseRequest request) { |
| 28 var requestStream = request.finalize(); | 33 var requestStream = request.finalize(); |
| 29 return withTempDir((tempDir) { | 34 return withTempDir((tempDir) { |
| 30 var headerFile = new Path(tempDir).append("curl-headers").toNativePath(); | 35 var headerFile = new Path(tempDir).append("curl-headers").toNativePath(); |
| 31 var arguments = _argumentsForRequest(request, headerFile); | 36 var arguments = _argumentsForRequest(request, headerFile); |
| 32 var process; | 37 var process; |
| 33 return Process.start("curl", arguments).chain((process_) { | 38 return Process.start(executable, arguments).chain((process_) { |
| 34 process = process_; | 39 process = process_; |
| 35 if (requestStream.closed) { | 40 if (requestStream.closed) { |
| 36 process.stdin.close(); | 41 process.stdin.close(); |
| 37 } else { | 42 } else { |
| 38 requestStream.pipe(process.stdin); | 43 requestStream.pipe(process.stdin); |
| 39 } | 44 } |
| 40 | 45 |
| 41 return _waitForHeaders(process, expectBody: request.method != "HEAD"); | 46 return _waitForHeaders(process, expectBody: request.method != "HEAD"); |
| 42 }).chain((_) => new File(headerFile).readAsLines()) | 47 }).chain((_) => new File(headerFile).readAsLines()) |
| 43 .transform((lines) => _buildResponse(process, lines)); | 48 .transform((lines) => _buildResponse(process, lines)); |
| 44 }); | 49 }); |
| 45 } | 50 } |
| 46 | 51 |
| 47 /// Returns the list of arguments to `curl` necessary for performing | 52 /// Returns the list of arguments to `curl` necessary for performing |
| 48 /// [request]. [headerFile] is the path to the file where the response headers | 53 /// [request]. [headerFile] is the path to the file where the response headers |
| 49 /// should be stored. | 54 /// should be stored. |
| 50 List<String> _argumentsForRequest( | 55 List<String> _argumentsForRequest( |
| 51 http.BaseRequest request, String headerFile) { | 56 http.BaseRequest request, String headerFile) { |
| 52 var arguments = ["--dump-header", headerFile]; | 57 // Note: This line of code gets munged by create_sdk.py to be the correct |
| 58 // relative path to the certificate file in the SDK. |
| 59 var pathToCertificates = "../../third_party/curl/ca-certificates.crt"; |
| 60 |
| 61 var arguments = [ |
| 62 "--dump-header", headerFile, |
| 63 "--cacert", relativeToPub(pathToCertificates) |
| 64 ]; |
| 53 if (request.method == 'HEAD') { | 65 if (request.method == 'HEAD') { |
| 54 arguments.add("--head"); | 66 arguments.add("--head"); |
| 55 } else { | 67 } else { |
| 56 arguments.add("--request"); | 68 arguments.add("--request"); |
| 57 arguments.add(request.method); | 69 arguments.add(request.method); |
| 58 } | 70 } |
| 59 if (request.followRedirects) { | 71 if (request.followRedirects) { |
| 60 arguments.add("--location"); | 72 arguments.add("--location"); |
| 61 arguments.add("--max-redirs"); | 73 arguments.add("--max-redirs"); |
| 62 arguments.add(request.maxRedirects.toString()); | 74 arguments.add(request.maxRedirects.toString()); |
| (...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 177 var contentLength = -1; | 189 var contentLength = -1; |
| 178 if (headers.containsKey('content-length')) { | 190 if (headers.containsKey('content-length')) { |
| 179 contentLength = int.parse(headers['content-length']); | 191 contentLength = int.parse(headers['content-length']); |
| 180 } | 192 } |
| 181 | 193 |
| 182 return new http.StreamedResponse(responseStream, status, contentLength, | 194 return new http.StreamedResponse(responseStream, status, contentLength, |
| 183 headers: headers, | 195 headers: headers, |
| 184 isRedirect: isRedirect, | 196 isRedirect: isRedirect, |
| 185 reasonPhrase: reasonPhrase); | 197 reasonPhrase: reasonPhrase); |
| 186 } | 198 } |
| 199 |
| 200 /// The default executable to use for running curl. On Windows, this is the |
| 201 /// path to the bundled `curl.exe`; elsewhere, this is just "curl", and we |
| 202 /// assume it to be installed and on the user's PATH. |
| 203 static String get _defaultExecutable { |
| 204 if (Platform.operatingSystem != 'windows') return 'curl'; |
| 205 // Note: This line of code gets munged by create_sdk.py to be the correct |
| 206 // relative path to curl in the SDK. |
| 207 var pathToCurl = "../../third_party/curl/curl.exe"; |
| 208 return relativeToPub(pathToCurl); |
| 209 } |
| 187 } | 210 } |
| OLD | NEW |