From d274582853040f2cc99315a2b3d13955bdeec96a Mon Sep 17 00:00:00 2001 From: Don Date: Thu, 16 Feb 2017 22:43:13 -0800 Subject: [PATCH 01/12] Remove extensions of request and response --- lib/src/base_request.dart | 140 --------------------------------- lib/src/base_response.dart | 53 ------------- lib/src/streamed_request.dart | 41 ---------- lib/src/streamed_response.dart | 39 --------- 4 files changed, 273 deletions(-) delete mode 100644 lib/src/base_request.dart delete mode 100644 lib/src/base_response.dart delete mode 100644 lib/src/streamed_request.dart delete mode 100644 lib/src/streamed_response.dart diff --git a/lib/src/base_request.dart b/lib/src/base_request.dart deleted file mode 100644 index b11ef05ae5..0000000000 --- a/lib/src/base_request.dart +++ /dev/null @@ -1,140 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'dart:async'; -import 'dart:collection'; - -import 'byte_stream.dart'; -import 'client.dart'; -import 'streamed_response.dart'; -import 'utils.dart'; - -/// The base class for HTTP requests. -/// -/// Subclasses of [BaseRequest] can be constructed manually and passed to -/// [BaseClient.send], which allows the user to provide fine-grained control -/// over the request properties. However, usually it's easier to use convenience -/// methods like [get] or [BaseClient.get]. -abstract class BaseRequest { - /// The HTTP method of the request. Most commonly "GET" or "POST", less - /// commonly "HEAD", "PUT", or "DELETE". Non-standard method names are also - /// supported. - final String method; - - /// The URL to which the request will be sent. - final Uri url; - - /// The size of the request body, in bytes. - /// - /// This defaults to `null`, which indicates that the size of the request is - /// not known in advance. - int get contentLength => _contentLength; - int _contentLength; - - set contentLength(int value) { - if (value != null && value < 0) { - throw new ArgumentError("Invalid content length $value."); - } - _checkFinalized(); - _contentLength = value; - } - - /// Whether a persistent connection should be maintained with the server. - /// Defaults to true. - bool get persistentConnection => _persistentConnection; - bool _persistentConnection = true; - - set persistentConnection(bool value) { - _checkFinalized(); - _persistentConnection = value; - } - - /// Whether the client should follow redirects while resolving this request. - /// Defaults to true. - bool get followRedirects => _followRedirects; - bool _followRedirects = true; - - set followRedirects(bool value) { - _checkFinalized(); - _followRedirects = value; - } - - /// The maximum number of redirects to follow when [followRedirects] is true. - /// If this number is exceeded the [BaseResponse] future will signal a - /// [RedirectException]. Defaults to 5. - int get maxRedirects => _maxRedirects; - int _maxRedirects = 5; - - set maxRedirects(int value) { - _checkFinalized(); - _maxRedirects = value; - } - - // TODO(nweiz): automatically parse cookies from headers - - // TODO(nweiz): make this a HttpHeaders object - /// The headers for this request. - final Map headers; - - /// Whether the request has been finalized. - bool get finalized => _finalized; - bool _finalized = false; - - /// Creates a new HTTP request. - BaseRequest(this.method, this.url) - : headers = new LinkedHashMap( - equals: (key1, key2) => key1.toLowerCase() == key2.toLowerCase(), - hashCode: (key) => key.toLowerCase().hashCode); - - /// Finalizes the HTTP request in preparation for it being sent. This freezes - /// all mutable fields and returns a single-subscription [ByteStream] that - /// emits the body of the request. - /// - /// The base implementation of this returns null rather than a [ByteStream]; - /// subclasses are responsible for creating the return value, which should be - /// single-subscription to ensure that no data is dropped. They should also - /// freeze any additional mutable fields they add that don't make sense to - /// change after the request headers are sent. - ByteStream finalize() { - // TODO(nweiz): freeze headers - if (finalized) throw new StateError("Can't finalize a finalized Request."); - _finalized = true; - return null; - } - - /// Sends this request. - /// - /// This automatically initializes a new [Client] and closes that client once - /// the request is complete. If you're planning on making multiple requests to - /// the same server, you should use a single [Client] for all of those - /// requests. - Future send() async { - var client = new Client(); - - try { - var response = await client.send(this); - var stream = onDone(response.stream, client.close); - return new StreamedResponse( - new ByteStream(stream), - response.statusCode, - contentLength: response.contentLength, - request: response.request, - headers: response.headers, - isRedirect: response.isRedirect, - persistentConnection: response.persistentConnection, - reasonPhrase: response.reasonPhrase); - } catch (_) { - client.close(); - rethrow; - } - } - - // Throws an error if this request has been finalized. - void _checkFinalized() { - if (!finalized) return; - throw new StateError("Can't modify a finalized Request."); - } - - String toString() => "$method $url"; -} diff --git a/lib/src/base_response.dart b/lib/src/base_response.dart deleted file mode 100644 index 26427f806f..0000000000 --- a/lib/src/base_response.dart +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'base_request.dart'; - -/// The base class for HTTP responses. -/// -/// Subclasses of [BaseResponse] are usually not constructed manually; instead, -/// they're returned by [BaseClient.send] or other HTTP client methods. -abstract class BaseResponse { - /// The (frozen) request that triggered this response. - final BaseRequest request; - - /// The status code of the response. - final int statusCode; - - /// The reason phrase associated with the status code. - final String reasonPhrase; - - /// The size of the response body, in bytes. - /// - /// If the size of the request is not known in advance, this is `null`. - final int contentLength; - - // TODO(nweiz): automatically parse cookies from headers - - // TODO(nweiz): make this a HttpHeaders object. - /// The headers for this response. - final Map headers; - - /// Whether this response is a redirect. - final bool isRedirect; - - /// Whether the server requested that a persistent connection be maintained. - final bool persistentConnection; - - /// Creates a new HTTP response. - BaseResponse( - this.statusCode, - {this.contentLength, - this.request, - this.headers: const {}, - this.isRedirect: false, - this.persistentConnection: true, - this.reasonPhrase}) { - if (statusCode < 100) { - throw new ArgumentError("Invalid status code $statusCode."); - } else if (contentLength != null && contentLength < 0) { - throw new ArgumentError("Invalid content length $contentLength."); - } - } -} diff --git a/lib/src/streamed_request.dart b/lib/src/streamed_request.dart deleted file mode 100644 index 6a020bd77a..0000000000 --- a/lib/src/streamed_request.dart +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'dart:async'; - -import 'byte_stream.dart'; -import 'base_request.dart'; - -/// An HTTP request where the request body is sent asynchronously after the -/// connection has been established and the headers have been sent. -/// -/// When the request is sent via [BaseClient.send], only the headers and -/// whatever data has already been written to [StreamedRequest.stream] will be -/// sent immediately. More data will be sent as soon as it's written to -/// [StreamedRequest.sink], and when the sink is closed the request will end. -class StreamedRequest extends BaseRequest { - /// The sink to which to write data that will be sent as the request body. - /// This may be safely written to before the request is sent; the data will be - /// buffered. - /// - /// Closing this signals the end of the request. - EventSink> get sink => _controller.sink; - - /// The controller for [sink], from which [BaseRequest] will read data for - /// [finalize]. - final StreamController> _controller; - - /// Creates a new streaming request. - StreamedRequest(String method, Uri url) - : _controller = new StreamController>(sync: true), - super(method, url); - - /// Freezes all mutable fields other than [stream] and returns a - /// single-subscription [ByteStream] that emits the data being written to - /// [sink]. - ByteStream finalize() { - super.finalize(); - return new ByteStream(_controller.stream); - } -} diff --git a/lib/src/streamed_response.dart b/lib/src/streamed_response.dart deleted file mode 100644 index 69d8356c1d..0000000000 --- a/lib/src/streamed_response.dart +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'dart:async'; - -import 'byte_stream.dart'; -import 'base_response.dart'; -import 'base_request.dart'; -import 'utils.dart'; - -/// An HTTP response where the response body is received asynchronously after -/// the headers have been received. -class StreamedResponse extends BaseResponse { - /// The stream from which the response body data can be read. This should - /// always be a single-subscription stream. - final ByteStream stream; - - /// Creates a new streaming response. [stream] should be a single-subscription - /// stream. - StreamedResponse( - Stream> stream, - int statusCode, - {int contentLength, - BaseRequest request, - Map headers: const {}, - bool isRedirect: false, - bool persistentConnection: true, - String reasonPhrase}) - : this.stream = toByteStream(stream), - super( - statusCode, - contentLength: contentLength, - request: request, - headers: headers, - isRedirect: isRedirect, - persistentConnection: persistentConnection, - reasonPhrase: reasonPhrase); -} From bb81377784ba47367f068f893da21a56d8326809 Mon Sep 17 00:00:00 2001 From: Don Date: Thu, 16 Feb 2017 22:43:40 -0800 Subject: [PATCH 02/12] Update client interface --- lib/src/client.dart | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/lib/src/client.dart b/lib/src/client.dart index cf1ff784a0..17fd262e22 100644 --- a/lib/src/client.dart +++ b/lib/src/client.dart @@ -7,10 +7,9 @@ import 'dart:convert'; import 'dart:typed_data'; import 'base_client.dart'; -import 'base_request.dart'; import 'io_client.dart'; +import 'request.dart'; import 'response.dart'; -import 'streamed_response.dart'; /// The interface for HTTP clients that take care of maintaining persistent /// connections across multiple requests to the same server. If you only need to @@ -33,13 +32,13 @@ abstract class Client { /// can be a [Uri] or a [String]. /// /// For more fine-grained control over the request, use [send] instead. - Future head(url, {Map headers}); + FutureOr head(url, {Map headers}); /// Sends an HTTP GET request with the given headers to the given URL, which /// can be a [Uri] or a [String]. /// /// For more fine-grained control over the request, use [send] instead. - Future get(url, {Map headers}); + FutureOr get(url, {Map headers}); /// Sends an HTTP POST request with the given headers and body to the given /// URL, which can be a [Uri] or a [String]. @@ -59,7 +58,7 @@ abstract class Client { /// [encoding] defaults to [UTF8]. /// /// For more fine-grained control over the request, use [send] instead. - Future post(url, {Map headers, body, + FutureOr post(url, body, {Map headers, Encoding encoding}); /// Sends an HTTP PUT request with the given headers and body to the given @@ -80,7 +79,7 @@ abstract class Client { /// [encoding] defaults to [UTF8]. /// /// For more fine-grained control over the request, use [send] instead. - Future put(url, {Map headers, body, + FutureOr put(url, body, {Map headers, Encoding encoding}); /// Sends an HTTP PATCH request with the given headers and body to the given @@ -101,14 +100,14 @@ abstract class Client { /// [encoding] defaults to [UTF8]. /// /// For more fine-grained control over the request, use [send] instead. - Future patch(url, {Map headers, body, + FutureOr patch(url, body, {Map headers, Encoding encoding}); /// Sends an HTTP DELETE request with the given headers to the given URL, /// which can be a [Uri] or a [String]. /// /// For more fine-grained control over the request, use [send] instead. - Future delete(url, {Map headers}); + FutureOr delete(url, {Map headers}); /// Sends an HTTP GET request with the given headers to the given URL, which /// can be a [Uri] or a [String], and returns a Future that completes to the @@ -119,7 +118,7 @@ abstract class Client { /// /// For more fine-grained control over the request and response, use [send] or /// [get] instead. - Future read(url, {Map headers}); + FutureOr read(url, {Map headers}); /// Sends an HTTP GET request with the given headers to the given URL, which /// can be a [Uri] or a [String], and returns a Future that completes to the @@ -130,10 +129,10 @@ abstract class Client { /// /// For more fine-grained control over the request and response, use [send] or /// [get] instead. - Future readBytes(url, {Map headers}); + FutureOr readBytes(url, {Map headers}); /// Sends an HTTP request and asynchronously returns the response. - Future send(BaseRequest request); + FutureOr send(Request request); /// Closes the client and cleans up any resources associated with it. It's /// important to close each client when it's done being used; failing to do so From 97641583630743c1f6a13f364d34910b4bcd23f3 Mon Sep 17 00:00:00 2001 From: Don Date: Thu, 16 Feb 2017 22:44:17 -0800 Subject: [PATCH 03/12] Update async to include collectBytes --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index 4ae55d8068..29911b8318 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -4,7 +4,7 @@ author: "Dart Team " homepage: https://github.com/dart-lang/http description: A composable, Future-based API for making HTTP requests. dependencies: - async: "^1.10.0" + async: "^1.13.0" collection: "^1.5.0" http_parser: ">=0.0.1 <4.0.0" path: ">=0.9.0 <2.0.0" From cf91544a5dfb63cc5fcb5ced8e04686542b5454b Mon Sep 17 00:00:00 2001 From: Don Date: Thu, 16 Feb 2017 22:44:40 -0800 Subject: [PATCH 04/12] Implement updated interface in BaseClient --- lib/src/base_client.dart | 87 +++++++++++++++++----------------------- 1 file changed, 37 insertions(+), 50 deletions(-) diff --git a/lib/src/base_client.dart b/lib/src/base_client.dart index 7b3fbfa41e..9d3be20a2d 100644 --- a/lib/src/base_client.dart +++ b/lib/src/base_client.dart @@ -6,14 +6,12 @@ import 'dart:async'; import 'dart:convert'; import 'dart:typed_data'; -import 'package:collection/collection.dart'; +import 'package:async/async.dart'; -import 'base_request.dart'; import 'client.dart'; import 'exception.dart'; import 'request.dart'; import 'response.dart'; -import 'streamed_response.dart'; /// The abstract base class for an HTTP client. This is a mixin-style class; /// subclasses only need to implement [send] and maybe [close], and then they @@ -23,15 +21,15 @@ abstract class BaseClient implements Client { /// can be a [Uri] or a [String]. /// /// For more fine-grained control over the request, use [send] instead. - Future head(url, {Map headers}) => - _sendUnstreamed("HEAD", url, headers); + FutureOr head(url, {Map headers}) => + send(new Request.head(_uri(url), headers: headers)); /// Sends an HTTP GET request with the given headers to the given URL, which /// can be a [Uri] or a [String]. /// /// For more fine-grained control over the request, use [send] instead. - Future get(url, {Map headers}) => - _sendUnstreamed("GET", url, headers); + FutureOr get(url, {Map headers}) => + send(new Request.get(_uri(url), headers: headers)); /// Sends an HTTP POST request with the given headers and body to the given /// URL, which can be a [Uri] or a [String]. @@ -51,9 +49,10 @@ abstract class BaseClient implements Client { /// [encoding] defaults to UTF-8. /// /// For more fine-grained control over the request, use [send] instead. - Future post(url, {Map headers, body, + FutureOr post(url, body, {Map headers, Encoding encoding}) => - _sendUnstreamed("POST", url, headers, body, encoding); + send(new Request.post(_uri(url), body, headers: headers, + encoding: encoding)); /// Sends an HTTP PUT request with the given headers and body to the given /// URL, which can be a [Uri] or a [String]. @@ -73,9 +72,10 @@ abstract class BaseClient implements Client { /// [encoding] defaults to UTF-8. /// /// For more fine-grained control over the request, use [send] instead. - Future put(url, {Map headers, body, + FutureOr put(url, body, {Map headers, Encoding encoding}) => - _sendUnstreamed("PUT", url, headers, body, encoding); + send(new Request.put(_uri(url), body, headers: headers, + encoding: encoding)); /// Sends an HTTP PATCH request with the given headers and body to the given /// URL, which can be a [Uri] or a [String]. @@ -95,16 +95,17 @@ abstract class BaseClient implements Client { /// [encoding] defaults to UTF-8. /// /// For more fine-grained control over the request, use [send] instead. - Future patch(url, {Map headers, body, + FutureOr patch(url, body, {Map headers, Encoding encoding}) => - _sendUnstreamed("PATCH", url, headers, body, encoding); + send(new Request.patch(_uri(url), body, headers: headers, + encoding: encoding)); /// Sends an HTTP DELETE request with the given headers to the given URL, /// which can be a [Uri] or a [String]. /// /// For more fine-grained control over the request, use [send] instead. - Future delete(url, {Map headers}) => - _sendUnstreamed("DELETE", url, headers); + FutureOr delete(url, {Map headers}) => + send(new Request.delete(_uri(url), headers: headers)); /// Sends an HTTP GET request with the given headers to the given URL, which /// can be a [Uri] or a [String], and returns a Future that completes to the @@ -115,11 +116,11 @@ abstract class BaseClient implements Client { /// /// For more fine-grained control over the request and response, use [send] or /// [get] instead. - Future read(url, {Map headers}) { - return get(url, headers: headers).then((response) { - _checkResponseSuccess(url, response); - return response.body; - }); + FutureOr read(url, {Map headers}) async { + var response = await get(url, headers: headers); + _checkResponseSuccess(url, response); + + return await response.readAsString(); } /// Sends an HTTP GET request with the given headers to the given URL, which @@ -131,11 +132,11 @@ abstract class BaseClient implements Client { /// /// For more fine-grained control over the request and response, use [send] or /// [get] instead. - Future readBytes(url, {Map headers}) { - return get(url, headers: headers).then((response) { - _checkResponseSuccess(url, response); - return response.bodyBytes; - }); + FutureOr readBytes(url, {Map headers}) async { + var response = await get(url, headers: headers); + _checkResponseSuccess(url, response); + + return await collectBytes(response.read()); } /// Sends an HTTP request and asynchronously returns the response. @@ -145,31 +146,7 @@ abstract class BaseClient implements Client { /// state of the stream; it could have data written to it asynchronously at a /// later point, or it could already be closed when it's returned. Any /// internal HTTP errors should be wrapped as [ClientException]s. - Future send(BaseRequest request); - - /// Sends a non-streaming [Request] and returns a non-streaming [Response]. - Future _sendUnstreamed(String method, url, - Map headers, [body, Encoding encoding]) async { - - if (url is String) url = Uri.parse(url); - var request = new Request(method, url); - - if (headers != null) request.headers.addAll(headers); - if (encoding != null) request.encoding = encoding; - if (body != null) { - if (body is String) { - request.body = body; - } else if (body is List) { - request.bodyBytes = DelegatingList.typed(body); - } else if (body is Map) { - request.bodyFields = DelegatingMap.typed(body); - } else { - throw new ArgumentError('Invalid request body "$body".'); - } - } - - return Response.fromStream(await send(request)); - } + FutureOr send(Request request); /// Throws an error if [response] is not successful. void _checkResponseSuccess(url, Response response) { @@ -187,3 +164,13 @@ abstract class BaseClient implements Client { /// can cause the Dart process to hang. void close() {} } + +Uri _uri(url) { + if (url is Uri) { + return url; + } else if (url is String) { + return Uri.parse(url); + } else { + throw new ArgumentError.value(url, 'url', 'Not a Uri or String'); + } +} From 949bb5667d81bf6f54d1b95c82bdc5d3620c0ece Mon Sep 17 00:00:00 2001 From: Don Date: Thu, 16 Feb 2017 22:46:52 -0800 Subject: [PATCH 05/12] Update helper functions --- lib/http.dart | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/lib/http.dart b/lib/http.dart index 9ccd77a6f8..aceb02adb2 100644 --- a/lib/http.dart +++ b/lib/http.dart @@ -32,7 +32,7 @@ export 'src/streamed_response.dart'; /// the same server, you should use a single [Client] for all of those requests. /// /// For more fine-grained control over the request, use [Request] instead. -Future head(url, {Map headers}) => +FutureOr head(url, {Map headers}) => _withClient((client) => client.head(url, headers: headers)); /// Sends an HTTP GET request with the given headers to the given URL, which can @@ -43,7 +43,7 @@ Future head(url, {Map headers}) => /// the same server, you should use a single [Client] for all of those requests. /// /// For more fine-grained control over the request, use [Request] instead. -Future get(url, {Map headers}) => +FutureOr get(url, {Map headers}) => _withClient((client) => client.get(url, headers: headers)); /// Sends an HTTP POST request with the given headers and body to the given URL, @@ -65,10 +65,10 @@ Future get(url, {Map headers}) => /// /// For more fine-grained control over the request, use [Request] or /// [StreamedRequest] instead. -Future post(url, {Map headers, body, +FutureOr post(url, body, {Map headers, Encoding encoding}) => - _withClient((client) => client.post(url, - headers: headers, body: body, encoding: encoding)); + _withClient((client) => client.post(url, body, + headers: headers, encoding: encoding)); /// Sends an HTTP PUT request with the given headers and body to the given URL, /// which can be a [Uri] or a [String]. @@ -89,10 +89,10 @@ Future post(url, {Map headers, body, /// /// For more fine-grained control over the request, use [Request] or /// [StreamedRequest] instead. -Future put(url, {Map headers, body, +FutureOr put(url, body, {Map headers, Encoding encoding}) => - _withClient((client) => client.put(url, - headers: headers, body: body, encoding: encoding)); + _withClient((client) => client.put(url, body, + headers: headers, encoding: encoding)); /// Sends an HTTP PATCH request with the given headers and body to the given /// URL, which can be a [Uri] or a [String]. @@ -113,10 +113,10 @@ Future put(url, {Map headers, body, /// /// For more fine-grained control over the request, use [Request] or /// [StreamedRequest] instead. -Future patch(url, {Map headers, body, +FutureOr patch(url, body, {Map headers, Encoding encoding}) => - _withClient((client) => client.patch(url, - headers: headers, body: body, encoding: encoding)); + _withClient((client) => client.patch(url, body, + headers: headers, encoding: encoding)); /// Sends an HTTP DELETE request with the given headers to the given URL, which /// can be a [Uri] or a [String]. @@ -126,7 +126,7 @@ Future patch(url, {Map headers, body, /// the same server, you should use a single [Client] for all of those requests. /// /// For more fine-grained control over the request, use [Request] instead. -Future delete(url, {Map headers}) => +FutureOr delete(url, {Map headers}) => _withClient((client) => client.delete(url, headers: headers)); /// Sends an HTTP GET request with the given headers to the given URL, which can @@ -142,7 +142,7 @@ Future delete(url, {Map headers}) => /// /// For more fine-grained control over the request and response, use [Request] /// instead. -Future read(url, {Map headers}) => +FutureOr read(url, {Map headers}) => _withClient((client) => client.read(url, headers: headers)); /// Sends an HTTP GET request with the given headers to the given URL, which can @@ -158,10 +158,10 @@ Future read(url, {Map headers}) => /// /// For more fine-grained control over the request and response, use [Request] /// instead. -Future readBytes(url, {Map headers}) => +FutureOr readBytes(url, {Map headers}) => _withClient((client) => client.readBytes(url, headers: headers)); -Future/**/ _withClient/**/(Future/**/ fn(Client client)) async { +FutureOr _withClient(FutureOr fn(Client client)) async { var client = new Client(); try { return await fn(client); From 6cf06eab6c322c7ab11a4e6689b54a8a95059dba Mon Sep 17 00:00:00 2001 From: Don Date: Fri, 17 Feb 2017 10:03:53 -0800 Subject: [PATCH 06/12] Use Future in http helpers --- lib/http.dart | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/lib/http.dart b/lib/http.dart index aceb02adb2..d9c018aa72 100644 --- a/lib/http.dart +++ b/lib/http.dart @@ -11,8 +11,6 @@ import 'src/client.dart'; import 'src/response.dart'; export 'src/base_client.dart'; -export 'src/base_request.dart'; -export 'src/base_response.dart'; export 'src/byte_stream.dart'; export 'src/client.dart'; export 'src/exception.dart'; @@ -21,8 +19,6 @@ export 'src/multipart_file.dart'; export 'src/multipart_request.dart'; export 'src/request.dart'; export 'src/response.dart'; -export 'src/streamed_request.dart'; -export 'src/streamed_response.dart'; /// Sends an HTTP HEAD request with the given headers to the given URL, which /// can be a [Uri] or a [String]. @@ -32,7 +28,7 @@ export 'src/streamed_response.dart'; /// the same server, you should use a single [Client] for all of those requests. /// /// For more fine-grained control over the request, use [Request] instead. -FutureOr head(url, {Map headers}) => +Future head(url, {Map headers}) => _withClient((client) => client.head(url, headers: headers)); /// Sends an HTTP GET request with the given headers to the given URL, which can @@ -43,7 +39,7 @@ FutureOr head(url, {Map headers}) => /// the same server, you should use a single [Client] for all of those requests. /// /// For more fine-grained control over the request, use [Request] instead. -FutureOr get(url, {Map headers}) => +Future get(url, {Map headers}) => _withClient((client) => client.get(url, headers: headers)); /// Sends an HTTP POST request with the given headers and body to the given URL, @@ -65,7 +61,7 @@ FutureOr get(url, {Map headers}) => /// /// For more fine-grained control over the request, use [Request] or /// [StreamedRequest] instead. -FutureOr post(url, body, {Map headers, +Future post(url, body, {Map headers, Encoding encoding}) => _withClient((client) => client.post(url, body, headers: headers, encoding: encoding)); @@ -89,7 +85,7 @@ FutureOr post(url, body, {Map headers, /// /// For more fine-grained control over the request, use [Request] or /// [StreamedRequest] instead. -FutureOr put(url, body, {Map headers, +Future put(url, body, {Map headers, Encoding encoding}) => _withClient((client) => client.put(url, body, headers: headers, encoding: encoding)); @@ -113,7 +109,7 @@ FutureOr put(url, body, {Map headers, /// /// For more fine-grained control over the request, use [Request] or /// [StreamedRequest] instead. -FutureOr patch(url, body, {Map headers, +Future patch(url, body, {Map headers, Encoding encoding}) => _withClient((client) => client.patch(url, body, headers: headers, encoding: encoding)); @@ -126,7 +122,7 @@ FutureOr patch(url, body, {Map headers, /// the same server, you should use a single [Client] for all of those requests. /// /// For more fine-grained control over the request, use [Request] instead. -FutureOr delete(url, {Map headers}) => +Future delete(url, {Map headers}) => _withClient((client) => client.delete(url, headers: headers)); /// Sends an HTTP GET request with the given headers to the given URL, which can @@ -142,7 +138,7 @@ FutureOr delete(url, {Map headers}) => /// /// For more fine-grained control over the request and response, use [Request] /// instead. -FutureOr read(url, {Map headers}) => +Future read(url, {Map headers}) => _withClient((client) => client.read(url, headers: headers)); /// Sends an HTTP GET request with the given headers to the given URL, which can @@ -158,10 +154,10 @@ FutureOr read(url, {Map headers}) => /// /// For more fine-grained control over the request and response, use [Request] /// instead. -FutureOr readBytes(url, {Map headers}) => +Future readBytes(url, {Map headers}) => _withClient((client) => client.readBytes(url, headers: headers)); -FutureOr _withClient(FutureOr fn(Client client)) async { +Future _withClient(FutureOr fn(Client client)) async { var client = new Client(); try { return await fn(client); From 6df8771041784ed78f2cd916acde17d34fcb4bf0 Mon Sep 17 00:00:00 2001 From: Don Date: Wed, 22 Feb 2017 21:58:01 -0800 Subject: [PATCH 07/12] Modify Request to take dynamic for urls --- lib/src/request.dart | 48 +++++++++++++++++++++++++++++--------------- 1 file changed, 32 insertions(+), 16 deletions(-) diff --git a/lib/src/request.dart b/lib/src/request.dart index 1f2be464df..dc22fa5adf 100644 --- a/lib/src/request.dart +++ b/lib/src/request.dart @@ -30,12 +30,12 @@ class Request extends Message { /// /// Extra [context] can be used to pass information between inner middleware /// and handlers. - Request(this.method, this.url, + Request(String method, url, {body, Encoding encoding, Map headers, Map context}) - : super(body, encoding: encoding, headers: headers, context: context); + : this._(method, _uri(url), body, encoding, headers, context); /// Creates a new HEAD [Request] to [url]. /// @@ -44,7 +44,7 @@ class Request extends Message { /// /// Extra [context] can be used to pass information between inner middleware /// and handlers. - Request.head(Uri url, + Request.head(url, {Map headers, Map context}) : this('HEAD', url, headers: headers, context: context); @@ -55,7 +55,7 @@ class Request extends Message { /// /// Extra [context] can be used to pass information between inner middleware /// and handlers. - Request.get(Uri url, + Request.get(url, {Map headers, Map context}) : this('GET', url, headers: headers, context: context); @@ -70,8 +70,7 @@ class Request extends Message { /// /// Extra [context] can be used to pass information between inner middleware /// and handlers. - Request.post(Uri url, - body, + Request.post(url, body, {Encoding encoding, Map headers, Map context}) @@ -90,8 +89,7 @@ class Request extends Message { /// /// Extra [context] can be used to pass information between inner middleware /// and handlers. - Request.put(Uri url, - body, + Request.put(url, body, {Encoding encoding, Map headers, Map context}) @@ -110,8 +108,7 @@ class Request extends Message { /// /// Extra [context] can be used to pass information between inner middleware /// and handlers. - Request.patch(Uri url, - body, + Request.patch(url, body, {Encoding encoding, Map headers, Map context}) @@ -125,10 +122,17 @@ class Request extends Message { /// /// Extra [context] can be used to pass information between inner middleware /// and handlers. - Request.delete(Uri url, + Request.delete(url, {Map headers, Map context}) : this('DELETE', url, headers: headers, context: context); + Request._(this.method, this.url, + body, + Encoding encoding, + Map headers, + Map context) + : super(body, encoding: encoding, headers: headers, context: context); + /// Creates a new [Request] by copying existing values and applying specified /// changes. /// @@ -147,10 +151,22 @@ class Request extends Message { var updatedHeaders = updateMap(this.headers, headers); var updatedContext = updateMap(this.context, context); - return new Request(this.method, this.url, - body: body ?? getBody(this), - encoding: this.encoding, - headers: updatedHeaders, - context: updatedContext); + return new Request._( + this.method, + this.url, + body ?? getBody(this), + this.encoding, + updatedHeaders, + updatedContext); + } +} + +Uri _uri(url) { + if (url is Uri) { + return url; + } else if (url is String) { + return Uri.parse(url); + } else { + throw new ArgumentError.value(url, 'url', 'Not a Uri or String'); } } From 07dd3994d18e4d521d3291fc342f2c3a40760355 Mon Sep 17 00:00:00 2001 From: Don Date: Wed, 22 Feb 2017 21:58:38 -0800 Subject: [PATCH 08/12] Remove uses of FutureOr --- lib/http.dart | 2 +- lib/src/base_client.dart | 40 +++++++++++++++------------------------- lib/src/client.dart | 18 +++++++++--------- 3 files changed, 25 insertions(+), 35 deletions(-) diff --git a/lib/http.dart b/lib/http.dart index d9c018aa72..f59c19e732 100644 --- a/lib/http.dart +++ b/lib/http.dart @@ -157,7 +157,7 @@ Future read(url, {Map headers}) => Future readBytes(url, {Map headers}) => _withClient((client) => client.readBytes(url, headers: headers)); -Future _withClient(FutureOr fn(Client client)) async { +Future _withClient(Future fn(Client client)) async { var client = new Client(); try { return await fn(client); diff --git a/lib/src/base_client.dart b/lib/src/base_client.dart index 9d3be20a2d..29dd1107e3 100644 --- a/lib/src/base_client.dart +++ b/lib/src/base_client.dart @@ -21,15 +21,15 @@ abstract class BaseClient implements Client { /// can be a [Uri] or a [String]. /// /// For more fine-grained control over the request, use [send] instead. - FutureOr head(url, {Map headers}) => - send(new Request.head(_uri(url), headers: headers)); + Future head(url, {Map headers}) => + send(new Request.head(url, headers: headers)); /// Sends an HTTP GET request with the given headers to the given URL, which /// can be a [Uri] or a [String]. /// /// For more fine-grained control over the request, use [send] instead. - FutureOr get(url, {Map headers}) => - send(new Request.get(_uri(url), headers: headers)); + Future get(url, {Map headers}) => + send(new Request.get(url, headers: headers)); /// Sends an HTTP POST request with the given headers and body to the given /// URL, which can be a [Uri] or a [String]. @@ -49,9 +49,9 @@ abstract class BaseClient implements Client { /// [encoding] defaults to UTF-8. /// /// For more fine-grained control over the request, use [send] instead. - FutureOr post(url, body, {Map headers, + Future post(url, body, {Map headers, Encoding encoding}) => - send(new Request.post(_uri(url), body, headers: headers, + send(new Request.post(url, body, headers: headers, encoding: encoding)); /// Sends an HTTP PUT request with the given headers and body to the given @@ -72,9 +72,9 @@ abstract class BaseClient implements Client { /// [encoding] defaults to UTF-8. /// /// For more fine-grained control over the request, use [send] instead. - FutureOr put(url, body, {Map headers, + Future put(url, body, {Map headers, Encoding encoding}) => - send(new Request.put(_uri(url), body, headers: headers, + send(new Request.put(url, body, headers: headers, encoding: encoding)); /// Sends an HTTP PATCH request with the given headers and body to the given @@ -95,17 +95,17 @@ abstract class BaseClient implements Client { /// [encoding] defaults to UTF-8. /// /// For more fine-grained control over the request, use [send] instead. - FutureOr patch(url, body, {Map headers, + Future patch(url, body, {Map headers, Encoding encoding}) => - send(new Request.patch(_uri(url), body, headers: headers, + send(new Request.patch(url, body, headers: headers, encoding: encoding)); /// Sends an HTTP DELETE request with the given headers to the given URL, /// which can be a [Uri] or a [String]. /// /// For more fine-grained control over the request, use [send] instead. - FutureOr delete(url, {Map headers}) => - send(new Request.delete(_uri(url), headers: headers)); + Future delete(url, {Map headers}) => + send(new Request.delete(url, headers: headers)); /// Sends an HTTP GET request with the given headers to the given URL, which /// can be a [Uri] or a [String], and returns a Future that completes to the @@ -116,7 +116,7 @@ abstract class BaseClient implements Client { /// /// For more fine-grained control over the request and response, use [send] or /// [get] instead. - FutureOr read(url, {Map headers}) async { + Future read(url, {Map headers}) async { var response = await get(url, headers: headers); _checkResponseSuccess(url, response); @@ -132,7 +132,7 @@ abstract class BaseClient implements Client { /// /// For more fine-grained control over the request and response, use [send] or /// [get] instead. - FutureOr readBytes(url, {Map headers}) async { + Future readBytes(url, {Map headers}) async { var response = await get(url, headers: headers); _checkResponseSuccess(url, response); @@ -146,7 +146,7 @@ abstract class BaseClient implements Client { /// state of the stream; it could have data written to it asynchronously at a /// later point, or it could already be closed when it's returned. Any /// internal HTTP errors should be wrapped as [ClientException]s. - FutureOr send(Request request); + Future send(Request request); /// Throws an error if [response] is not successful. void _checkResponseSuccess(url, Response response) { @@ -164,13 +164,3 @@ abstract class BaseClient implements Client { /// can cause the Dart process to hang. void close() {} } - -Uri _uri(url) { - if (url is Uri) { - return url; - } else if (url is String) { - return Uri.parse(url); - } else { - throw new ArgumentError.value(url, 'url', 'Not a Uri or String'); - } -} diff --git a/lib/src/client.dart b/lib/src/client.dart index 17fd262e22..fd4144326f 100644 --- a/lib/src/client.dart +++ b/lib/src/client.dart @@ -32,13 +32,13 @@ abstract class Client { /// can be a [Uri] or a [String]. /// /// For more fine-grained control over the request, use [send] instead. - FutureOr head(url, {Map headers}); + Future head(url, {Map headers}); /// Sends an HTTP GET request with the given headers to the given URL, which /// can be a [Uri] or a [String]. /// /// For more fine-grained control over the request, use [send] instead. - FutureOr get(url, {Map headers}); + Future get(url, {Map headers}); /// Sends an HTTP POST request with the given headers and body to the given /// URL, which can be a [Uri] or a [String]. @@ -58,7 +58,7 @@ abstract class Client { /// [encoding] defaults to [UTF8]. /// /// For more fine-grained control over the request, use [send] instead. - FutureOr post(url, body, {Map headers, + Future post(url, body, {Map headers, Encoding encoding}); /// Sends an HTTP PUT request with the given headers and body to the given @@ -79,7 +79,7 @@ abstract class Client { /// [encoding] defaults to [UTF8]. /// /// For more fine-grained control over the request, use [send] instead. - FutureOr put(url, body, {Map headers, + Future put(url, body, {Map headers, Encoding encoding}); /// Sends an HTTP PATCH request with the given headers and body to the given @@ -100,14 +100,14 @@ abstract class Client { /// [encoding] defaults to [UTF8]. /// /// For more fine-grained control over the request, use [send] instead. - FutureOr patch(url, body, {Map headers, + Future patch(url, body, {Map headers, Encoding encoding}); /// Sends an HTTP DELETE request with the given headers to the given URL, /// which can be a [Uri] or a [String]. /// /// For more fine-grained control over the request, use [send] instead. - FutureOr delete(url, {Map headers}); + Future delete(url, {Map headers}); /// Sends an HTTP GET request with the given headers to the given URL, which /// can be a [Uri] or a [String], and returns a Future that completes to the @@ -118,7 +118,7 @@ abstract class Client { /// /// For more fine-grained control over the request and response, use [send] or /// [get] instead. - FutureOr read(url, {Map headers}); + Future read(url, {Map headers}); /// Sends an HTTP GET request with the given headers to the given URL, which /// can be a [Uri] or a [String], and returns a Future that completes to the @@ -129,10 +129,10 @@ abstract class Client { /// /// For more fine-grained control over the request and response, use [send] or /// [get] instead. - FutureOr readBytes(url, {Map headers}); + Future readBytes(url, {Map headers}); /// Sends an HTTP request and asynchronously returns the response. - FutureOr send(Request request); + Future send(Request request); /// Closes the client and cleans up any resources associated with it. It's /// important to close each client when it's done being used; failing to do so From 69df648fc64d0ac6e30ed23bbad8ce9285ab36fd Mon Sep 17 00:00:00 2001 From: Don Date: Mon, 27 Feb 2017 10:58:22 -0800 Subject: [PATCH 09/12] Update version --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index 29911b8318..27c29aa4ac 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: http -version: 0.11.3+10 +version: 0.12.0 author: "Dart Team " homepage: https://github.com/dart-lang/http description: A composable, Future-based API for making HTTP requests. From 35a765cd049100106ee1731df09de242ca7e72b5 Mon Sep 17 00:00:00 2001 From: Don Date: Wed, 1 Mar 2017 18:24:09 -0800 Subject: [PATCH 10/12] Use dev for version --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index 27c29aa4ac..15c23aae11 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: http -version: 0.12.0 +version: 0.12.0-dev author: "Dart Team " homepage: https://github.com/dart-lang/http description: A composable, Future-based API for making HTTP requests. From 8d2e50378bc0120b8e6eea1f0bd251dda346700f Mon Sep 17 00:00:00 2001 From: Don Date: Wed, 1 Mar 2017 18:30:18 -0800 Subject: [PATCH 11/12] Move url to utils and add additional documentation --- lib/src/request.dart | 30 ++++++++++++------------------ lib/src/utils.dart | 13 +++++++++++++ 2 files changed, 25 insertions(+), 18 deletions(-) diff --git a/lib/src/request.dart b/lib/src/request.dart index dc22fa5adf..f49c5b9f16 100644 --- a/lib/src/request.dart +++ b/lib/src/request.dart @@ -18,7 +18,8 @@ class Request extends Message { /// The URL to which the request will be sent. final Uri url; - /// Creates a new [Request] for [url] using [method]. + /// Creates a new [Request] for [url], which can be a [Uri] or a [String], + /// using [method]. /// /// [body] is the request body. It may be either a [String], a [List], a /// [Stream>], or `null` to indicate no body. If it's a [String], @@ -35,9 +36,9 @@ class Request extends Message { Encoding encoding, Map headers, Map context}) - : this._(method, _uri(url), body, encoding, headers, context); + : this._(method, getUrl(url), body, encoding, headers, context); - /// Creates a new HEAD [Request] to [url]. + /// Creates a new HEAD [Request] to [url], which can be a [Uri] or a [String]. /// /// [headers] are the HTTP headers for the request. If [headers] is `null`, /// it is treated as empty. @@ -48,7 +49,7 @@ class Request extends Message { {Map headers, Map context}) : this('HEAD', url, headers: headers, context: context); - /// Creates a new GET [Request] to [url]. + /// Creates a new GET [Request] to [url], which can be a [Uri] or a [String]. /// /// [headers] are the HTTP headers for the request. If [headers] is `null`, /// it is treated as empty. @@ -59,7 +60,8 @@ class Request extends Message { {Map headers, Map context}) : this('GET', url, headers: headers, context: context); - /// Creates a new POST [Request] to [url]. + /// Creates a new POST [Request] to [url], which can be a [Uri] or a [String]. + /// /// [body] is the request body. It may be either a [String], a [List], a /// [Stream>], or `null` to indicate no body. If it's a [String], /// [encoding] is used to encode it to a [Stream>]. It defaults to @@ -77,7 +79,7 @@ class Request extends Message { : this('POST', url, body: body, encoding: encoding, headers: headers, context: context); - /// Creates a new PUT [Request] to [url]. + /// Creates a new PUT [Request] to [url], which can be a [Uri] or a [String]. /// /// [body] is the request body. It may be either a [String], a [List], a /// [Stream>], or `null` to indicate no body. If it's a [String], @@ -96,7 +98,8 @@ class Request extends Message { : this('PUT', url, body: body, encoding: encoding, headers: headers, context: context); - /// Creates a new PATCH [Request] to [url]. + /// Creates a new PATCH [Request] to [url], which can be a [Uri] or a + /// [String]. /// /// [body] is the request body. It may be either a [String], a [List], a /// [Stream>], or `null` to indicate no body. If it's a [String], @@ -115,7 +118,8 @@ class Request extends Message { : this('PATCH', url, body: body, encoding: encoding, headers: headers, context: context); - /// Creates a new DELETE [Request] to [url]. + /// Creates a new DELETE [Request] to [url], which can be a [Uri] or a + /// [String]. /// /// [headers] are the HTTP headers for the request. If [headers] is `null`, /// it is treated as empty. @@ -160,13 +164,3 @@ class Request extends Message { updatedContext); } } - -Uri _uri(url) { - if (url is Uri) { - return url; - } else if (url is String) { - return Uri.parse(url); - } else { - throw new ArgumentError.value(url, 'url', 'Not a Uri or String'); - } -} diff --git a/lib/src/utils.dart b/lib/src/utils.dart index 39f1aefac4..fbe7db4cfb 100644 --- a/lib/src/utils.dart +++ b/lib/src/utils.dart @@ -170,3 +170,16 @@ String getHeader(Map headers, String name) { } return null; } + +/// Returns a [Uri] from the [url], which can be a [Uri] or a [String]. +/// +/// If the [ur] is not a [Uri] or [String] an [ArgumentError] is thrown. +Uri getUrl(url) { + if (url is Uri) { + return url; + } else if (url is String) { + return Uri.parse(url); + } else { + throw new ArgumentError.value(url, 'url', 'Not a Uri or String'); + } +} From 362ad9ccc1ab15fd2a2fbe9b61ba111377274d0c Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Mon, 6 Mar 2017 12:59:56 -0800 Subject: [PATCH 12/12] Fix a typo. --- lib/src/utils.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/utils.dart b/lib/src/utils.dart index fbe7db4cfb..b7e7347a3d 100644 --- a/lib/src/utils.dart +++ b/lib/src/utils.dart @@ -173,7 +173,7 @@ String getHeader(Map headers, String name) { /// Returns a [Uri] from the [url], which can be a [Uri] or a [String]. /// -/// If the [ur] is not a [Uri] or [String] an [ArgumentError] is thrown. +/// If the [url] is not a [Uri] or [String] an [ArgumentError] is thrown. Uri getUrl(url) { if (url is Uri) { return url;