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

Side by Side Diff: utils/pub/curl_client.dart

Issue 12095050: Roll back Pub stream changes. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Actually roll back changes Created 7 years, 10 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 | Annotate | Revision Log
« no previous file with comments | « utils/pub/command_lish.dart ('k') | utils/pub/error_group.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 library curl_client; 5 library curl_client;
6 6
7 import 'dart:async'; 7 import 'dart:async';
8 import 'dart:io'; 8 import 'dart:io';
9 9
10 import '../../pkg/http/lib/http.dart' as http; 10 import '../../pkg/http/lib/http.dart' as http;
(...skipping 23 matching lines...) Expand all
34 Future<http.StreamedResponse> send(http.BaseRequest request) { 34 Future<http.StreamedResponse> send(http.BaseRequest request) {
35 log.fine("Sending Curl request $request"); 35 log.fine("Sending Curl request $request");
36 36
37 var requestStream = request.finalize(); 37 var requestStream = request.finalize();
38 return withTempDir((tempDir) { 38 return withTempDir((tempDir) {
39 var headerFile = join(tempDir, "curl-headers"); 39 var headerFile = join(tempDir, "curl-headers");
40 var arguments = _argumentsForRequest(request, headerFile); 40 var arguments = _argumentsForRequest(request, headerFile);
41 var process; 41 var process;
42 return startProcess(executable, arguments).then((process_) { 42 return startProcess(executable, arguments).then((process_) {
43 process = process_; 43 process = process_;
44 return Future.wait([ 44 return requestStream.pipe(wrapOutputStream(process.stdin));
45 store(requestStream, process.stdin), 45 }).then((_) {
46 _waitForHeaders(process, expectBody: request.method != "HEAD") 46 return _waitForHeaders(process, expectBody: request.method != "HEAD");
47 ]);
48 }).then((_) => new File(headerFile).readAsLines()) 47 }).then((_) => new File(headerFile).readAsLines())
49 .then((lines) => _buildResponse(request, process, lines)); 48 .then((lines) => _buildResponse(request, process, lines));
50 }); 49 });
51 } 50 }
52 51
53 /// Returns the list of arguments to `curl` necessary for performing 52 /// Returns the list of arguments to `curl` necessary for performing
54 /// [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
55 /// should be stored. 54 /// should be stored.
56 List<String> _argumentsForRequest( 55 List<String> _argumentsForRequest(
57 http.BaseRequest request, String headerFile) { 56 http.BaseRequest request, String headerFile) {
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
105 /// Returns a [Future] that completes once the `curl` [process] has finished 104 /// Returns a [Future] that completes once the `curl` [process] has finished
106 /// receiving the response headers. [expectBody] indicates that the server is 105 /// receiving the response headers. [expectBody] indicates that the server is
107 /// expected to send a response body (which is not the case for HEAD 106 /// expected to send a response body (which is not the case for HEAD
108 /// requests). 107 /// requests).
109 /// 108 ///
110 /// Curl prints the headers to a file and then prints the body to stdout. So, 109 /// Curl prints the headers to a file and then prints the body to stdout. So,
111 /// in theory, we could read the headers as soon as we see anything appear 110 /// in theory, we could read the headers as soon as we see anything appear
112 /// in stdout. However, that seems to be too early to successfully read the 111 /// in stdout. However, that seems to be too early to successfully read the
113 /// file (at least on Mac). Instead, this just waits until the entire process 112 /// file (at least on Mac). Instead, this just waits until the entire process
114 /// has completed. 113 /// has completed.
115 Future _waitForHeaders(PubProcess process, {bool expectBody}) { 114 Future _waitForHeaders(Process process, {bool expectBody}) {
116 var future = process.exitCode.then((exitCode) { 115 var completer = new Completer();
116 process.onExit = (exitCode) {
117 log.io("Curl process exited with code $exitCode."); 117 log.io("Curl process exited with code $exitCode.");
118 if (exitCode == 0) return;
119 118
120 process.stderr.bytesToString().then((message) { 119 if (exitCode == 0) {
120 completer.complete(null);
121 return;
122 }
123
124 chainToCompleter(consumeInputStream(process.stderr).then((stderrBytes) {
125 var message = new String.fromCharCodes(stderrBytes);
121 log.fine('Got error reading headers from curl: $message'); 126 log.fine('Got error reading headers from curl: $message');
122 if (exitCode == 47) { 127 if (exitCode == 47) {
123 throw new RedirectLimitExceededException([]); 128 throw new RedirectLimitExceededException([]);
124 } else { 129 } else {
125 throw new HttpException(message); 130 throw new HttpException(message);
126 } 131 }
127 }); 132 }), completer);
128 }); 133 };
129
130 if (expectBody) return future;
131 134
132 // If there's not going to be a response body (e.g. for HEAD requests), curl 135 // If there's not going to be a response body (e.g. for HEAD requests), curl
133 // prints the headers to stdout instead of the body. We want to wait until 136 // prints the headers to stdout instead of the body. We want to wait until
134 // all the headers are received to read them from the header file. 137 // all the headers are received to read them from the header file.
135 return Future.wait([process.stdout.toBytes(), future]); 138 if (!expectBody) {
139 return Future.wait([
140 consumeInputStream(process.stdout),
141 completer.future
142 ]);
143 }
144
145 return completer.future;
136 } 146 }
137 147
138 /// Returns a [http.StreamedResponse] from the response data printed by the 148 /// Returns a [http.StreamedResponse] from the response data printed by the
139 /// `curl` [process]. [lines] are the headers that `curl` wrote to a file. 149 /// `curl` [process]. [lines] are the headers that `curl` wrote to a file.
140 http.StreamedResponse _buildResponse( 150 http.StreamedResponse _buildResponse(
141 http.BaseRequest request, PubProcess process, List<String> lines) { 151 http.BaseRequest request, Process process, List<String> lines) {
142 // When curl follows redirects, it prints the redirect headers as well as 152 // When curl follows redirects, it prints the redirect headers as well as
143 // the headers of the final request. Each block is separated by a blank 153 // the headers of the final request. Each block is separated by a blank
144 // line. We just care about the last block. There is one trailing empty 154 // line. We just care about the last block. There is one trailing empty
145 // line, though, which we don't want to consider a separator. 155 // line, though, which we don't want to consider a separator.
146 var lastBlank = lines.lastIndexOf("", lines.length - 2); 156 var lastBlank = lines.lastIndexOf("", lines.length - 2);
147 if (lastBlank != -1) lines.removeRange(0, lastBlank + 1); 157 if (lastBlank != -1) lines.removeRange(0, lastBlank + 1);
148 158
149 var statusParts = lines.removeAt(0).split(" "); 159 var statusParts = lines.removeAt(0).split(" ");
150 var status = int.parse(statusParts[1]); 160 var status = int.parse(statusParts[1]);
151 var isRedirect = status >= 300 && status < 400; 161 var isRedirect = status >= 300 && status < 400;
152 var reasonPhrase = 162 var reasonPhrase =
153 Strings.join(statusParts.getRange(2, statusParts.length - 2), " "); 163 Strings.join(statusParts.getRange(2, statusParts.length - 2), " ");
154 var headers = {}; 164 var headers = {};
155 for (var line in lines) { 165 for (var line in lines) {
156 if (line.isEmpty) continue; 166 if (line.isEmpty) continue;
157 var split = split1(line, ":"); 167 var split = split1(line, ":");
158 headers[split[0].toLowerCase()] = split[1].trim(); 168 headers[split[0].toLowerCase()] = split[1].trim();
159 } 169 }
170 var responseStream = process.stdout;
171 if (responseStream.closed) {
172 responseStream = new ListInputStream();
173 responseStream.markEndOfStream();
174 }
160 var contentLength = -1; 175 var contentLength = -1;
161 if (headers.containsKey('content-length')) { 176 if (headers.containsKey('content-length')) {
162 contentLength = int.parse(headers['content-length']); 177 contentLength = int.parse(headers['content-length']);
163 } 178 }
164 179
165 return new http.StreamedResponse( 180 return new http.StreamedResponse(
166 process.stdout, status, contentLength, 181 wrapInputStream(responseStream), status, contentLength,
167 request: request, 182 request: request,
168 headers: headers, 183 headers: headers,
169 isRedirect: isRedirect, 184 isRedirect: isRedirect,
170 reasonPhrase: reasonPhrase); 185 reasonPhrase: reasonPhrase);
171 } 186 }
172 187
173 /// The default executable to use for running curl. On Windows, this is the 188 /// The default executable to use for running curl. On Windows, this is the
174 /// path to the bundled `curl.exe`; elsewhere, this is just "curl", and we 189 /// path to the bundled `curl.exe`; elsewhere, this is just "curl", and we
175 /// assume it to be installed and on the user's PATH. 190 /// assume it to be installed and on the user's PATH.
176 static String get _defaultExecutable { 191 static String get _defaultExecutable {
177 if (Platform.operatingSystem != 'windows') return 'curl'; 192 if (Platform.operatingSystem != 'windows') return 'curl';
178 // Note: This line of code gets munged by create_sdk.py to be the correct 193 // Note: This line of code gets munged by create_sdk.py to be the correct
179 // relative path to curl in the SDK. 194 // relative path to curl in the SDK.
180 var pathToCurl = "../../third_party/curl/curl.exe"; 195 var pathToCurl = "../../third_party/curl/curl.exe";
181 return relativeToPub(pathToCurl); 196 return relativeToPub(pathToCurl);
182 } 197 }
183 } 198 }
OLDNEW
« no previous file with comments | « utils/pub/command_lish.dart ('k') | utils/pub/error_group.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698