| 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 base_request; | 5 library base_request; |
| 6 | 6 |
| 7 import 'dart:async'; | 7 import 'dart:async'; |
| 8 import 'dart:io'; | 8 import 'dart:io'; |
| 9 import 'dart:isolate'; | 9 import 'dart:isolate'; |
| 10 import 'dart:uri'; | 10 import 'dart:uri'; |
| 11 | 11 |
| 12 import 'byte_stream.dart'; |
| 12 import 'client.dart'; | 13 import 'client.dart'; |
| 13 import 'streamed_response.dart'; | 14 import 'streamed_response.dart'; |
| 15 import 'utils.dart'; |
| 14 | 16 |
| 15 /// The base class for HTTP requests. | 17 /// The base class for HTTP requests. |
| 16 /// | 18 /// |
| 17 /// Subclasses of [BaseRequest] can be constructed manually and passed to | 19 /// Subclasses of [BaseRequest] can be constructed manually and passed to |
| 18 /// [BaseClient.send], which allows the user to provide fine-grained control | 20 /// [BaseClient.send], which allows the user to provide fine-grained control |
| 19 /// over the request properties. However, usually it's easier to use convenience | 21 /// over the request properties. However, usually it's easier to use convenience |
| 20 /// methods like [get] or [BaseClient.get]. | 22 /// methods like [get] or [BaseClient.get]. |
| 21 abstract class BaseRequest { | 23 abstract class BaseRequest { |
| 22 /// The HTTP method of the request. Most commonly "GET" or "POST", less | 24 /// The HTTP method of the request. Most commonly "GET" or "POST", less |
| 23 /// commonly "HEAD", "PUT", or "DELETE". Non-standard method names are also | 25 /// commonly "HEAD", "PUT", or "DELETE". Non-standard method names are also |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 76 | 78 |
| 77 /// Whether the request has been finalized. | 79 /// Whether the request has been finalized. |
| 78 bool get finalized => _finalized; | 80 bool get finalized => _finalized; |
| 79 bool _finalized = false; | 81 bool _finalized = false; |
| 80 | 82 |
| 81 /// Creates a new HTTP request. | 83 /// Creates a new HTTP request. |
| 82 BaseRequest(this.method, this.url) | 84 BaseRequest(this.method, this.url) |
| 83 : headers = <String>{}; | 85 : headers = <String>{}; |
| 84 | 86 |
| 85 /// Finalizes the HTTP request in preparation for it being sent. This freezes | 87 /// Finalizes the HTTP request in preparation for it being sent. This freezes |
| 86 /// all mutable fields and returns an [InputStream] that should emit the body | 88 /// all mutable fields and returns a single-subscription [ByteStream] that |
| 87 /// of the request. The stream may be closed to indicate a request with no | 89 /// emits the body of the request. |
| 88 /// body. | |
| 89 /// | 90 /// |
| 90 /// The base implementation of this returns null rather than an [InputStream]; | 91 /// The base implementation of this returns null rather than a [ByteStream]; |
| 91 /// subclasses are responsible for creating the return value. They should also | 92 /// subclasses are responsible for creating the return value, which should be |
| 93 /// single-subscription to ensure that no data is dropped. They should also |
| 92 /// freeze any additional mutable fields they add that don't make sense to | 94 /// freeze any additional mutable fields they add that don't make sense to |
| 93 /// change after the request headers are sent. | 95 /// change after the request headers are sent. |
| 94 InputStream finalize() { | 96 ByteStream finalize() { |
| 95 // TODO(nweiz): freeze headers | 97 // TODO(nweiz): freeze headers |
| 96 if (finalized) throw new StateError("Can't finalize a finalized Request."); | 98 if (finalized) throw new StateError("Can't finalize a finalized Request."); |
| 97 _finalized = true; | 99 _finalized = true; |
| 98 return null; | 100 return null; |
| 99 } | 101 } |
| 100 | 102 |
| 101 /// Sends this request. | 103 /// Sends this request. |
| 102 /// | 104 /// |
| 103 /// This automatically initializes a new [Client] and closes that client once | 105 /// This automatically initializes a new [Client] and closes that client once |
| 104 /// the request is complete. If you're planning on making multiple requests to | 106 /// the request is complete. If you're planning on making multiple requests to |
| 105 /// the same server, you should use a single [Client] for all of those | 107 /// the same server, you should use a single [Client] for all of those |
| 106 /// requests. | 108 /// requests. |
| 107 Future<StreamedResponse> send() { | 109 Future<StreamedResponse> send() { |
| 108 var client = new Client(); | 110 var client = new Client(); |
| 109 return client.send(this).then((response) { | 111 return client.send(this).then((response) { |
| 110 // TODO(nweiz): This makes me sick to my stomach, but it's currently the | 112 var stream = onDone(response.stream, client.close); |
| 111 // best way to listen for the response stream being closed. Kill it with | 113 return new StreamedResponse( |
| 112 // fire once issue 4202 is fixed. | 114 new ByteStream(stream), |
| 113 new Timer.repeating(100, (timer) { | 115 response.statusCode, |
| 114 if (response.stream.closed) { | 116 response.contentLength, |
| 115 client.close(); | 117 request: response.request, |
| 116 timer.cancel(); | 118 headers: response.headers, |
| 117 } | 119 isRedirect: response.isRedirect, |
| 118 }); | 120 persistentConnection: response.persistentConnection, |
| 119 | 121 reasonPhrase: response.reasonPhrase); |
| 120 return response; | 122 }).catchError((e) { |
| 121 }).catchError((_) { client.close(); }); | 123 client.close(); |
| 124 throw e; |
| 125 }); |
| 122 } | 126 } |
| 123 | 127 |
| 124 /// Throws an error if this request has been finalized. | 128 /// Throws an error if this request has been finalized. |
| 125 void _checkFinalized() { | 129 void _checkFinalized() { |
| 126 if (!finalized) return; | 130 if (!finalized) return; |
| 127 throw new StateError("Can't modify a finalized Request."); | 131 throw new StateError("Can't modify a finalized Request."); |
| 128 } | 132 } |
| 129 | 133 |
| 130 String toString() => "$method $url"; | 134 String toString() => "$method $url"; |
| 131 } | 135 } |
| OLD | NEW |