Farewell, local fork of the http package. (#8642)
diff --git a/examples/stocks/lib/stock_data.dart b/examples/stocks/lib/stock_data.dart
index 7ab4c65..cd82d8b 100644
--- a/examples/stocks/lib/stock_data.dart
+++ b/examples/stocks/lib/stock_data.dart
@@ -10,7 +10,8 @@
import 'dart:convert';
import 'dart:math' as math;
-import 'package:flutter/http.dart' as http;
+import 'package:flutter/services.dart';
+import 'package:http/http.dart' as http;
final math.Random _rng = new math.Random();
@@ -60,19 +61,22 @@
}
class StockDataFetcher {
- int _nextChunk = 0;
+ StockDataFetcher(this.callback) {
+ _httpClient = createHttpClient();
+ _fetchNextChunk();
+ }
+
final StockDataCallback callback;
+ http.Client _httpClient;
static bool actuallyFetchData = true;
- StockDataFetcher(this.callback) {
- _fetchNextChunk();
- }
+ int _nextChunk = 0;
void _fetchNextChunk() {
if (!actuallyFetchData)
return;
- http.get(_urlToFetch(_nextChunk++)).then<Null>((http.Response response) {
+ _httpClient.get(_urlToFetch(_nextChunk++)).then<Null>((http.Response response) {
final String json = response.body;
if (json == null) {
print("Failed to load stock data chunk ${_nextChunk - 1}");
diff --git a/examples/stocks/pubspec.yaml b/examples/stocks/pubspec.yaml
index 07fb30f..f15f87d 100644
--- a/examples/stocks/pubspec.yaml
+++ b/examples/stocks/pubspec.yaml
@@ -3,6 +3,7 @@
flutter:
sdk: flutter
intl: '>=0.14.0 <0.15.0'
+ http: '>=0.11.3+11'
dev_dependencies:
flutter_test:
diff --git a/packages/flutter/lib/http.dart b/packages/flutter/lib/http.dart
deleted file mode 100644
index b0240bc..0000000
--- a/packages/flutter/lib/http.dart
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-/// A [Future]-based library for making HTTP requests.
-///
-/// To use, import `package:flutter/http.dart`.
-///
-/// This library is based on Dart's `http` package, but differs in that it does
-/// not have a dependency on mirrors.
-///
-// TODO(chinmaygarde): The contents of `lib/src/http` will become redundant
-// once https://github.com/dart-lang/http/issues/1 is fixed (removes the use
-// of mirrors). Once that issue is addressed, we should get rid this directory
-// and use `dart-lang/http` directly.
-library http;
-
-export 'src/http/http.dart';
-export 'src/http/mock_client.dart';
-export 'src/http/response.dart';
diff --git a/packages/flutter/lib/services.dart b/packages/flutter/lib/services.dart
index 4c34210..cbbbefe 100644
--- a/packages/flutter/lib/services.dart
+++ b/packages/flutter/lib/services.dart
@@ -13,14 +13,15 @@
export 'src/services/asset_bundle.dart';
export 'src/services/binding.dart';
export 'src/services/clipboard.dart';
-export 'src/services/message_codec.dart';
-export 'src/services/message_codecs.dart';
export 'src/services/haptic_feedback.dart';
+export 'src/services/http_client.dart';
export 'src/services/image_cache.dart';
export 'src/services/image_decoder.dart';
export 'src/services/image_provider.dart';
export 'src/services/image_resolution.dart';
export 'src/services/image_stream.dart';
+export 'src/services/message_codec.dart';
+export 'src/services/message_codecs.dart';
export 'src/services/path_provider.dart';
export 'src/services/platform_channel.dart';
export 'src/services/platform_messages.dart';
diff --git a/packages/flutter/lib/src/http/.dartignore b/packages/flutter/lib/src/http/.dartignore
deleted file mode 100644
index e69de29..0000000
--- a/packages/flutter/lib/src/http/.dartignore
+++ /dev/null
diff --git a/packages/flutter/lib/src/http/README.md b/packages/flutter/lib/src/http/README.md
deleted file mode 100644
index 1db8904..0000000
--- a/packages/flutter/lib/src/http/README.md
+++ /dev/null
@@ -1,7 +0,0 @@
-`dart-lang/http` without Mirrors
-================================
-
-The contents of this will become redundant once
-https://github.com/dart-lang/http/issues/1 is fixed (removes the use
-of mirrors). Once that issue is addressed, we should get rid this directory
-and use `dart-lang/http` directly.
diff --git a/packages/flutter/lib/src/http/base_client.dart b/packages/flutter/lib/src/http/base_client.dart
deleted file mode 100644
index 1b16c25..0000000
--- a/packages/flutter/lib/src/http/base_client.dart
+++ /dev/null
@@ -1,199 +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:convert';
-import 'dart:typed_data';
-
-import 'package:collection/collection.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
-/// get various convenience methods for free.
-abstract class BaseClient implements Client {
- /// Sends an HTTP HEAD 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.
- @override
- Future<Response> head(dynamic url, {Map<String, String> headers}) =>
- _sendUnstreamed("HEAD", url, 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.
- @override
- Future<Response> get(dynamic url, {Map<String, String> headers}) =>
- _sendUnstreamed("GET", url, headers);
-
- /// Sends an HTTP POST request with the given headers and body to the given
- /// URL, which can be a [Uri] or a [String].
- ///
- /// [body] sets the body of the request. It can be a [String], a [List<int>]
- /// or a [Map<String, String>]. If it's a String, it's encoded using
- /// [encoding] and used as the body of the request. The content-type of the
- /// request will default to "text/plain".
- ///
- /// If [body] is a List, it's used as a list of bytes for the body of the
- /// request.
- ///
- /// If [body] is a Map, it's encoded as form fields using [encoding]. The
- /// content-type of the request will be set to
- /// `"application/x-www-form-urlencoded"`; this cannot be overridden.
- ///
- /// [encoding] defaults to UTF-8.
- ///
- /// For more fine-grained control over the request, use [send] instead.
- @override
- Future<Response> post(dynamic url, {Map<String, String> headers, dynamic body,
- Encoding encoding}) =>
- _sendUnstreamed("POST", url, headers, body, encoding);
-
- /// Sends an HTTP PUT request with the given headers and body to the given
- /// URL, which can be a [Uri] or a [String].
- ///
- /// [body] sets the body of the request. It can be a [String], a [List<int>]
- /// or a [Map<String, String>]. If it's a String, it's encoded using
- /// [encoding] and used as the body of the request. The content-type of the
- /// request will default to "text/plain".
- ///
- /// If [body] is a List, it's used as a list of bytes for the body of the
- /// request.
- ///
- /// If [body] is a Map, it's encoded as form fields using [encoding]. The
- /// content-type of the request will be set to
- /// `"application/x-www-form-urlencoded"`; this cannot be overridden.
- ///
- /// [encoding] defaults to UTF-8.
- ///
- /// For more fine-grained control over the request, use [send] instead.
- @override
- Future<Response> put(dynamic url, {Map<String, String> headers, dynamic body,
- Encoding encoding}) =>
- _sendUnstreamed("PUT", url, headers, body, encoding);
-
- /// Sends an HTTP PATCH request with the given headers and body to the given
- /// URL, which can be a [Uri] or a [String].
- ///
- /// [body] sets the body of the request. It can be a [String], a [List<int>]
- /// or a [Map<String, String>]. If it's a String, it's encoded using
- /// [encoding] and used as the body of the request. The content-type of the
- /// request will default to "text/plain".
- ///
- /// If [body] is a List, it's used as a list of bytes for the body of the
- /// request.
- ///
- /// If [body] is a Map, it's encoded as form fields using [encoding]. The
- /// content-type of the request will be set to
- /// `"application/x-www-form-urlencoded"`; this cannot be overridden.
- ///
- /// [encoding] defaults to UTF-8.
- ///
- /// For more fine-grained control over the request, use [send] instead.
- @override
- Future<Response> patch(dynamic url, {Map<String, String> headers, dynamic body,
- Encoding encoding}) =>
- _sendUnstreamed("PATCH", url, headers, body, 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.
- @override
- Future<Response> delete(dynamic url, {Map<String, String> headers}) =>
- _sendUnstreamed("DELETE", url, 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
- /// body of the response as a String.
- ///
- /// The Future will emit a [ClientException] if the response doesn't have a
- /// success status code.
- ///
- /// For more fine-grained control over the request and response, use [send] or
- /// [get] instead.
- @override
- Future<String> read(dynamic url, {Map<String, String> headers}) {
- return get(url, headers: headers).then((Response response) {
- _checkResponseSuccess(url, response);
- return response.body;
- });
- }
-
- /// 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
- /// body of the response as a list of bytes.
- ///
- /// The Future will emit an [ClientException] if the response doesn't have a
- /// success status code.
- ///
- /// For more fine-grained control over the request and response, use [send] or
- /// [get] instead.
- @override
- Future<Uint8List> readBytes(dynamic url, {Map<String, String> headers}) {
- return get(url, headers: headers).then((Response response) {
- _checkResponseSuccess(url, response);
- return response.bodyBytes;
- });
- }
-
- /// Sends an HTTP request and asynchronously returns the response.
- ///
- /// Implementers should call [BaseRequest.finalize] to get the body of the
- /// request as a [ByteStream]. They shouldn't make any assumptions about the
- /// 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.
- @override
- Future<StreamedResponse> send(BaseRequest request);
-
- /// Sends a non-streaming [Request] and returns a non-streaming [Response].
- Future<Response> _sendUnstreamed(String method, dynamic url,
- Map<String, String> headers, [dynamic body, Encoding encoding]) async {
-
- if (url is String) url = Uri.parse(url);
- Request 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));
- }
-
- /// Throws an error if [response] is not successful.
- void _checkResponseSuccess(dynamic url, Response response) {
- if (response.statusCode < 400) return;
- String message = "Request to $url failed with status ${response.statusCode}";
- if (response.reasonPhrase != null) {
- message = "$message: ${response.reasonPhrase}";
- }
- if (url is String) url = Uri.parse(url);
- throw new ClientException("$message.", url);
- }
-
- /// 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
- /// can cause the Dart process to hang.
- @override
- void close() {}
-}
diff --git a/packages/flutter/lib/src/http/base_request.dart b/packages/flutter/lib/src/http/base_request.dart
deleted file mode 100644
index 4af1673..0000000
--- a/packages/flutter/lib/src/http/base_request.dart
+++ /dev/null
@@ -1,141 +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;
-
- /// Creates a new HTTP request.
- BaseRequest(this.method, this.url)
- : headers = new LinkedHashMap<String, String>(
- equals: (String key1, String key2) => key1.toLowerCase() == key2.toLowerCase(),
- hashCode: (String key) => key.toLowerCase().hashCode);
-
- /// 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<String, String> headers;
-
- /// Whether the request has been finalized.
- bool get finalized => _finalized;
- bool _finalized = false;
-
- /// 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<StreamedResponse> send() async {
- Client client = new Client();
-
- try {
- StreamedResponse response = await client.send(this);
- Stream<dynamic> 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 (ex) {
- 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.");
- }
-
- @override
- String toString() => "$method $url";
-}
diff --git a/packages/flutter/lib/src/http/base_response.dart b/packages/flutter/lib/src/http/base_response.dart
deleted file mode 100644
index 148b751..0000000
--- a/packages/flutter/lib/src/http/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<String, String> 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 <String, String>{},
- 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/packages/flutter/lib/src/http/byte_stream.dart b/packages/flutter/lib/src/http/byte_stream.dart
deleted file mode 100644
index 825d419..0000000
--- a/packages/flutter/lib/src/http/byte_stream.dart
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright (c) 2013, 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:convert';
-import 'dart:typed_data';
-
-/// A stream of chunks of bytes representing a single piece of data.
-class ByteStream extends StreamView<List<int>> {
- ByteStream(Stream<List<int>> stream)
- : super(stream);
-
- /// Returns a single-subscription byte stream that will emit the given bytes
- /// in a single chunk.
- factory ByteStream.fromBytes(List<int> bytes) =>
- new ByteStream(new Stream<dynamic>.fromIterable(<List<int>>[bytes]));
-
- /// Collects the data of this stream in a [Uint8List].
- Future<Uint8List> toBytes() {
- Completer<Uint8List> completer = new Completer<Uint8List>();
- dynamic sink = new ByteConversionSink.withCallback((dynamic bytes) =>
- completer.complete(new Uint8List.fromList(bytes)));
- listen(sink.add, onError: completer.completeError, onDone: sink.close,
- cancelOnError: true);
- return completer.future;
- }
-
- /// Collect the data of this stream in a [String], decoded according to
- /// [encoding], which defaults to `UTF8`.
- Future<String> bytesToString([Encoding encoding=UTF8]) =>
- encoding.decodeStream(this);
-
- Stream<String> toStringStream([Encoding encoding=UTF8]) =>
- encoding.decoder.bind(this);
-}
diff --git a/packages/flutter/lib/src/http/client.dart b/packages/flutter/lib/src/http/client.dart
deleted file mode 100644
index 3280777..0000000
--- a/packages/flutter/lib/src/http/client.dart
+++ /dev/null
@@ -1,148 +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:convert';
-import 'dart:typed_data';
-
-import 'base_client.dart';
-import 'base_request.dart';
-import 'io_client.dart';
-import 'response.dart';
-import 'streamed_response.dart';
-
-typedef Client ClientOverride();
-
-/// The interface for HTTP clients that take care of maintaining persistent
-/// connections across multiple requests to the same server. If you only need to
-/// send a single request, it's usually easier to use [head], [get], [post],
-/// [put], [patch], or [delete] instead.
-///
-/// When creating an HTTP client class with additional functionality, you must
-/// extend [BaseClient] rather than [Client]. In most cases, you can wrap
-/// another instance of [Client] and add functionality on top of that. This
-/// allows all classes implementing [Client] to be mutually composable.
-abstract class Client {
- /// Creates a new client.
- ///
- /// Currently this will create an [IOClient] if `dart:io` is available and
- /// throw an [UnsupportedError] otherwise. In the future, it will create a
- /// [BrowserClient] if `dart:html` is available.
- factory Client() {
- return clientOverride == null ? new IOClient() : clientOverride();
- }
-
- static ClientOverride clientOverride;
-
- /// Sends an HTTP HEAD 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<Response> head(dynamic url, {Map<String, String> 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<Response> get(dynamic url, {Map<String, String> headers});
-
- /// Sends an HTTP POST request with the given headers and body to the given
- /// URL, which can be a [Uri] or a [String].
- ///
- /// [body] sets the body of the request. It can be a [String], a [List<int>]
- /// or a [Map<String, String>]. If it's a String, it's encoded using
- /// [encoding] and used as the body of the request. The content-type of the
- /// request will default to "text/plain".
- ///
- /// If [body] is a List, it's used as a list of bytes for the body of the
- /// request.
- ///
- /// If [body] is a Map, it's encoded as form fields using [encoding]. The
- /// content-type of the request will be set to
- /// `"application/x-www-form-urlencoded"`; this cannot be overridden.
- ///
- /// [encoding] defaults to [UTF8].
- ///
- /// For more fine-grained control over the request, use [send] instead.
- Future<Response> post(dynamic url, {Map<String, String> headers, dynamic body,
- 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].
- ///
- /// [body] sets the body of the request. It can be a [String], a [List<int>]
- /// or a [Map<String, String>]. If it's a String, it's encoded using
- /// [encoding] and used as the body of the request. The content-type of the
- /// request will default to "text/plain".
- ///
- /// If [body] is a List, it's used as a list of bytes for the body of the
- /// request.
- ///
- /// If [body] is a Map, it's encoded as form fields using [encoding]. The
- /// content-type of the request will be set to
- /// `"application/x-www-form-urlencoded"`; this cannot be overridden.
- ///
- /// [encoding] defaults to [UTF8].
- ///
- /// For more fine-grained control over the request, use [send] instead.
- Future<Response> put(dynamic url, {Map<String, String> headers, dynamic body,
- 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].
- ///
- /// [body] sets the body of the request. It can be a [String], a [List<int>]
- /// or a [Map<String, String>]. If it's a String, it's encoded using
- /// [encoding] and used as the body of the request. The content-type of the
- /// request will default to "text/plain".
- ///
- /// If [body] is a List, it's used as a list of bytes for the body of the
- /// request.
- ///
- /// If [body] is a Map, it's encoded as form fields using [encoding]. The
- /// content-type of the request will be set to
- /// `"application/x-www-form-urlencoded"`; this cannot be overridden.
- ///
- /// [encoding] defaults to [UTF8].
- ///
- /// For more fine-grained control over the request, use [send] instead.
- Future<Response> patch(dynamic url, {Map<String, String> headers, dynamic body,
- 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<Response> delete(dynamic url, {Map<String, String> 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
- /// body of the response as a String.
- ///
- /// The Future will emit a [ClientException] if the response doesn't have a
- /// success status code.
- ///
- /// For more fine-grained control over the request and response, use [send] or
- /// [get] instead.
- Future<String> read(dynamic url, {Map<String, String> 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
- /// body of the response as a list of bytes.
- ///
- /// The Future will emit a [ClientException] if the response doesn't have a
- /// success status code.
- ///
- /// For more fine-grained control over the request and response, use [send] or
- /// [get] instead.
- Future<Uint8List> readBytes(dynamic url, {Map<String, String> headers});
-
- /// Sends an HTTP request and asynchronously returns the response.
- Future<StreamedResponse> send(BaseRequest 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
- /// can cause the Dart process to hang.
- void close();
-}
diff --git a/packages/flutter/lib/src/http/exception.dart b/packages/flutter/lib/src/http/exception.dart
deleted file mode 100644
index c92a861..0000000
--- a/packages/flutter/lib/src/http/exception.dart
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright (c) 2014, 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.
-
-/// An exception caused by an error in a pkg/http client.
-class ClientException implements Exception {
- final String message;
-
- /// The URL of the HTTP request or response that failed.
- final Uri uri;
-
- ClientException(this.message, [this.uri]);
-
- @override
- String toString() => message;
-}
diff --git a/packages/flutter/lib/src/http/http.dart b/packages/flutter/lib/src/http/http.dart
deleted file mode 100644
index 6806075..0000000
--- a/packages/flutter/lib/src/http/http.dart
+++ /dev/null
@@ -1,171 +0,0 @@
-// Copyright (c) 2013, 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.
-
-/// A composable, [Future]-based library for making HTTP requests.
-import 'dart:async';
-import 'dart:convert';
-import 'dart:typed_data';
-
-import 'client.dart';
-import 'response.dart';
-
-export 'base_client.dart';
-export 'base_request.dart';
-export 'base_response.dart';
-export 'byte_stream.dart';
-export 'client.dart';
-export 'exception.dart';
-export 'io_client.dart';
-export 'multipart_file.dart';
-export 'multipart_request.dart';
-export 'request.dart';
-export 'response.dart';
-export 'streamed_request.dart';
-export 'streamed_response.dart';
-
-/// Sends an HTTP HEAD request with the given headers to the given URL, which
-/// can be a [Uri] or a [String].
-///
-/// 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.
-///
-/// For more fine-grained control over the request, use [Request] instead.
-Future<Response> head(dynamic url, {Map<String, String> headers}) =>
- _withClient((Client client) => client.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].
-///
-/// 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.
-///
-/// For more fine-grained control over the request, use [Request] instead.
-Future<Response> get(dynamic url, {Map<String, String> headers}) =>
- _withClient((Client client) => client.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].
-///
-/// [body] sets the body of the request. It can be a [String], a [List<int>] or
-/// a [Map<String, String>]. If it's a String, it's encoded using [encoding] and
-/// used as the body of the request. The content-type of the request will
-/// default to "text/plain".
-///
-/// If [body] is a List, it's used as a list of bytes for the body of the
-/// request.
-///
-/// If [body] is a Map, it's encoded as form fields using [encoding]. The
-/// content-type of the request will be set to
-/// `"application/x-www-form-urlencoded"`; this cannot be overridden.
-///
-/// [encoding] defaults to [UTF8].
-///
-/// For more fine-grained control over the request, use [Request] or
-/// [StreamedRequest] instead.
-Future<Response> post(dynamic url, {Map<String, String> headers, dynamic body,
- Encoding encoding}) =>
- _withClient((Client client) => client.post(url,
- headers: headers, body: body, 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].
-///
-/// [body] sets the body of the request. It can be a [String], a [List<int>] or
-/// a [Map<String, String>]. If it's a String, it's encoded using [encoding] and
-/// used as the body of the request. The content-type of the request will
-/// default to "text/plain".
-///
-/// If [body] is a List, it's used as a list of bytes for the body of the
-/// request.
-///
-/// If [body] is a Map, it's encoded as form fields using [encoding]. The
-/// content-type of the request will be set to
-/// `"application/x-www-form-urlencoded"`; this cannot be overridden.
-///
-/// [encoding] defaults to [UTF8].
-///
-/// For more fine-grained control over the request, use [Request] or
-/// [StreamedRequest] instead.
-Future<Response> put(dynamic url, {Map<String, String> headers, dynamic body,
- Encoding encoding}) =>
- _withClient((Client client) => client.put(url,
- headers: headers, body: body, 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].
-///
-/// [body] sets the body of the request. It can be a [String], a [List<int>] or
-/// a [Map<String, String>]. If it's a String, it's encoded using [encoding] and
-/// used as the body of the request. The content-type of the request will
-/// default to "text/plain".
-///
-/// If [body] is a List, it's used as a list of bytes for the body of the
-/// request.
-///
-/// If [body] is a Map, it's encoded as form fields using [encoding]. The
-/// content-type of the request will be set to
-/// `"application/x-www-form-urlencoded"`; this cannot be overridden.
-///
-/// [encoding] defaults to [UTF8].
-///
-/// For more fine-grained control over the request, use [Request] or
-/// [StreamedRequest] instead.
-Future<Response> patch(dynamic url, {Map<String, String> headers, dynamic body,
- Encoding encoding}) =>
- _withClient((Client client) => client.patch(url,
- headers: headers, body: body, encoding: encoding));
-
-/// Sends an HTTP DELETE request with the given headers to the given URL, which
-/// can be a [Uri] or a [String].
-///
-/// 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.
-///
-/// For more fine-grained control over the request, use [Request] instead.
-Future<Response> delete(dynamic url, {Map<String, String> headers}) =>
- _withClient((Client client) => client.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 body of
-/// the response as a [String].
-///
-/// The Future will emit a [ClientException] if the response doesn't have a
-/// success status code.
-///
-/// 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.
-///
-/// For more fine-grained control over the request and response, use [Request]
-/// instead.
-Future<String> read(dynamic url, {Map<String, String> headers}) =>
- _withClient((Client client) => client.read(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 body of
-/// the response as a list of bytes.
-///
-/// The Future will emit a [ClientException] if the response doesn't have a
-/// success status code.
-///
-/// 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.
-///
-/// For more fine-grained control over the request and response, use [Request]
-/// instead.
-Future<Uint8List> readBytes(dynamic url, {Map<String, String> headers}) =>
- _withClient((Client client) => client.readBytes(url, headers: headers));
-
-Future/*<T>*/ _withClient/*<T>*/(Future/*<T>*/ fn(Client client)) async {
- Client client = new Client();
- try {
- return await fn(client);
- } finally {
- client.close();
- }
-}
diff --git a/packages/flutter/lib/src/http/io.dart b/packages/flutter/lib/src/http/io.dart
deleted file mode 100644
index 7748a6d..0000000
--- a/packages/flutter/lib/src/http/io.dart
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright (c) 2014, 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:io' as io;
-
-/// Whether `dart:io` is supported on this platform.
-bool get supported => true;
-
-/// Asserts that the [name]d `dart:io` feature is supported on this platform.
-///
-/// If `dart:io` doesn't work on this platform, this throws an
-/// [UnsupportedError].
-void assertSupported(String name) {}
-
-/// Creates a new `dart:io` HttpClient instance.
-io.HttpClient newHttpClient() => new io.HttpClient();
-
-/// Creates a new `dart:io` File instance with the given [path].
-io.File newFile(String path) => new io.File(path);
-
-/// Returns whether [error] is a `dart:io` HttpException.
-bool isHttpException(dynamic error) => error is io.HttpException;
-
-/// Returns whether [client] is a `dart:io` HttpClient.
-bool isHttpClient(dynamic client) => client is io.HttpClient;
diff --git a/packages/flutter/lib/src/http/io_client.dart b/packages/flutter/lib/src/http/io_client.dart
deleted file mode 100644
index 5a3ae79..0000000
--- a/packages/flutter/lib/src/http/io_client.dart
+++ /dev/null
@@ -1,90 +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 'package:async/async.dart';
-
-import 'base_client.dart';
-import 'base_request.dart';
-import 'exception.dart';
-import 'io.dart' as io;
-import 'streamed_response.dart';
-
-/// A `dart:io`-based HTTP client.
-///
-/// This is the default client when running on the command line.
-class IOClient extends BaseClient {
- /// The underlying `dart:io` HTTP client.
- dynamic _inner;
-
- /// Creates a new HTTP client.
- ///
- /// [innerClient] must be a `dart:io` HTTP client. If it's not passed, a
- /// default one will be instantiated.
- IOClient([dynamic innerClient]) {
- io.assertSupported("IOClient");
- if (innerClient != null) {
- // TODO(nweiz): remove this assert when we can type [innerClient]
- // properly.
- assert(io.isHttpClient(innerClient));
- _inner = innerClient;
- } else {
- _inner = io.newHttpClient();
- }
- }
-
- /// Sends an HTTP request and asynchronously returns the response.
- @override
- Future<StreamedResponse> send(BaseRequest request) async {
- dynamic stream = request.finalize();
-
- try {
- dynamic ioRequest = await _inner.openUrl(request.method, request.url);
-
- ioRequest
- ..followRedirects = request.followRedirects
- ..maxRedirects = request.maxRedirects
- ..contentLength = request.contentLength == null
- ? -1
- : request.contentLength
- ..persistentConnection = request.persistentConnection;
- request.headers.forEach((String name, String value) {
- ioRequest.headers.set(name, value);
- });
-
- dynamic response = await stream.pipe(
- DelegatingStreamConsumer.typed(ioRequest));
- Map<String, dynamic> headers = <String, dynamic>{};
- response.headers.forEach((String key, dynamic values) {
- headers[key] = values.join(',');
- });
-
- return new StreamedResponse(
- DelegatingStream.typed/*<List<int>>*/(response).handleError((dynamic error) =>
- throw new ClientException(error.message, error.uri),
- test: (dynamic error) => io.isHttpException(error)),
- response.statusCode,
- contentLength: response.contentLength == -1
- ? null
- : response.contentLength,
- request: request,
- headers: headers,
- isRedirect: response.isRedirect,
- persistentConnection: response.persistentConnection,
- reasonPhrase: response.reasonPhrase);
- } catch (error) {
- if (!io.isHttpException(error)) rethrow;
- throw new ClientException(error.message, error.uri);
- }
- }
-
- /// Closes the client. This terminates all active connections. If a client
- /// remains unclosed, the Dart process may not terminate.
- @override
- void close() {
- if (_inner != null) _inner.close(force: true);
- _inner = null;
- }
-}
diff --git a/packages/flutter/lib/src/http/mock_client.dart b/packages/flutter/lib/src/http/mock_client.dart
deleted file mode 100644
index 9b44e84..0000000
--- a/packages/flutter/lib/src/http/mock_client.dart
+++ /dev/null
@@ -1,88 +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:typed_data';
-
-import 'base_client.dart';
-import 'base_request.dart';
-import 'byte_stream.dart';
-import 'request.dart';
-import 'response.dart';
-import 'streamed_response.dart';
-
-// TODO(nweiz): once Dart has some sort of Rack- or WSGI-like standard for
-// server APIs, MockClient should conform to it.
-
-/// A mock HTTP client designed for use when testing code that uses
-/// [BaseClient]. This client allows you to define a handler callback for all
-/// requests that are made through it so that you can mock a server without
-/// having to send real HTTP requests.
-class MockClient extends BaseClient {
- /// The handler for receiving [StreamedRequest]s and sending
- /// [StreamedResponse]s.
- final MockClientStreamHandler _handler;
-
- /// Creates a [MockClient] with a handler that receives [Request]s and sends
- /// [Response]s.
- MockClient(MockClientHandler fn)
- : this._((BaseRequest baseRequest, ByteStream bodyStream) {
- return bodyStream.toBytes().then((Uint8List bodyBytes) {
- Request request = new Request(baseRequest.method, baseRequest.url)
- ..persistentConnection = baseRequest.persistentConnection
- ..followRedirects = baseRequest.followRedirects
- ..maxRedirects = baseRequest.maxRedirects
- ..headers.addAll(baseRequest.headers)
- ..bodyBytes = bodyBytes
- ..finalize();
-
- return fn(request);
- }).then((Response response) {
- return new StreamedResponse(
- new ByteStream.fromBytes(response.bodyBytes),
- response.statusCode,
- contentLength: response.contentLength,
- request: baseRequest,
- headers: response.headers,
- isRedirect: response.isRedirect,
- persistentConnection: response.persistentConnection,
- reasonPhrase: response.reasonPhrase);
- });
- });
-
- MockClient._(this._handler);
-
- /// Creates a [MockClient] with a handler that receives [StreamedRequest]s and
- /// sends [StreamedResponse]s.
- MockClient.streaming(MockClientStreamHandler fn)
- : this._((BaseRequest request, ByteStream bodyStream) {
- return fn(request, bodyStream).then((StreamedResponse response) {
- return new StreamedResponse(
- response.stream,
- response.statusCode,
- contentLength: response.contentLength,
- request: request,
- headers: response.headers,
- isRedirect: response.isRedirect,
- persistentConnection: response.persistentConnection,
- reasonPhrase: response.reasonPhrase);
- });
- });
-
- /// Sends a request.
- @override
- Future<StreamedResponse> send(BaseRequest request) async {
- ByteStream bodyStream = request.finalize();
- return await _handler(request, bodyStream);
- }
-}
-
-/// A handler function that receives [StreamedRequest]s and sends
-/// [StreamedResponse]s. Note that [request] will be finalized.
-typedef Future<StreamedResponse> MockClientStreamHandler(
- BaseRequest request, ByteStream bodyStream);
-
-/// A handler function that receives [Request]s and sends [Response]s. Note that
-/// [request] will be finalized.
-typedef Future<Response> MockClientHandler(BaseRequest request);
diff --git a/packages/flutter/lib/src/http/multipart_file.dart b/packages/flutter/lib/src/http/multipart_file.dart
deleted file mode 100644
index a21e624..0000000
--- a/packages/flutter/lib/src/http/multipart_file.dart
+++ /dev/null
@@ -1,111 +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:convert';
-
-import 'package:async/async.dart';
-import 'package:http_parser/http_parser.dart';
-import 'package:path/path.dart' as path;
-
-import 'byte_stream.dart';
-import 'io.dart' as io;
-import 'utils.dart';
-
-/// A file to be uploaded as part of a [MultipartRequest]. This doesn't need to
-/// correspond to a physical file.
-class MultipartFile {
- /// The name of the form field for the file.
- final String field;
-
- /// The size of the file in bytes. This must be known in advance, even if this
- /// file is created from a [ByteStream].
- final int length;
-
- /// The basename of the file. May be null.
- final String filename;
-
- /// The content-type of the file. Defaults to `application/octet-stream`.
- final MediaType contentType;
-
- /// The stream that will emit the file's contents.
- final ByteStream _stream;
-
- /// Creates a new [MultipartFile] from a chunked [Stream] of bytes. The length
- /// of the file in bytes must be known in advance. If it's not, read the data
- /// from the stream and use [MultipartFile.fromBytes] instead.
- ///
- /// [contentType] currently defaults to `application/octet-stream`, but in the
- /// future may be inferred from [filename].
- MultipartFile(this.field, Stream<List<int>> stream, this.length,
- {this.filename, MediaType contentType})
- : this._stream = toByteStream(stream),
- this.contentType = contentType != null ? contentType :
- new MediaType("application", "octet-stream");
-
- /// Creates a new [MultipartFile] from a byte array.
- ///
- /// [contentType] currently defaults to `application/octet-stream`, but in the
- /// future may be inferred from [filename].
- factory MultipartFile.fromBytes(String field, List<int> value,
- {String filename, MediaType contentType}) {
- ByteStream stream = new ByteStream.fromBytes(value);
- return new MultipartFile(field, stream, value.length,
- filename: filename,
- contentType: contentType);
- }
-
- /// Creates a new [MultipartFile] from a string.
- ///
- /// The encoding to use when translating [value] into bytes is taken from
- /// [contentType] if it has a charset set. Otherwise, it defaults to UTF-8.
- /// [contentType] currently defaults to `text/plain; charset=utf-8`, but in
- /// the future may be inferred from [filename].
- factory MultipartFile.fromString(String field, String value,
- {String filename, MediaType contentType}) {
- contentType = contentType == null ? new MediaType("text", "plain")
- : contentType;
- Encoding encoding = encodingForCharset(contentType.parameters['charset'], UTF8);
- contentType = contentType.change(parameters: <String, String>{'charset': encoding.name});
-
- return new MultipartFile.fromBytes(field, encoding.encode(value),
- filename: filename,
- contentType: contentType);
- }
-
- /// Whether [finalize] has been called.
- bool get isFinalized => _isFinalized;
- bool _isFinalized = false;
-
- // TODO(nweiz): Infer the content-type from the filename.
- /// Creates a new [MultipartFile] from a path to a file on disk.
- ///
- /// [filename] defaults to the basename of [filePath]. [contentType] currently
- /// defaults to `application/octet-stream`, but in the future may be inferred
- /// from [filename].
- ///
- /// This can only be used in an environment that supports "dart:io".
- static Future<MultipartFile> fromPath(String field, String filePath,
- {String filename, MediaType contentType}) async {
- io.assertSupported("MultipartFile.fromPath");
- if (filename == null) filename = path.basename(filePath);
- dynamic file = io.newFile(filePath);
- int length = await file.length();
- ByteStream stream = new ByteStream(DelegatingStream.typed(file.openRead()));
- return new MultipartFile(field, stream, length,
- filename: filename,
- contentType: contentType);
- }
-
- // Finalizes the file in preparation for it being sent as part of a
- // [MultipartRequest]. This returns a [ByteStream] that should emit the body
- // of the file. The stream may be closed to indicate an empty file.
- ByteStream finalize() {
- if (isFinalized) {
- throw new StateError("Can't finalize a finalized MultipartFile.");
- }
- _isFinalized = true;
- return _stream;
- }
-}
diff --git a/packages/flutter/lib/src/http/multipart_request.dart b/packages/flutter/lib/src/http/multipart_request.dart
deleted file mode 100644
index c108eda..0000000
--- a/packages/flutter/lib/src/http/multipart_request.dart
+++ /dev/null
@@ -1,177 +0,0 @@
-// Copyright (c) 2013, 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:convert';
-import 'dart:math';
-
-import 'base_request.dart';
-import 'byte_stream.dart';
-import 'multipart_file.dart';
-import 'utils.dart';
-
-final RegExp _newlineRegExp = new RegExp(r"\r\n|\r|\n");
-
-/// A `multipart/form-data` request. Such a request has both string [fields],
-/// which function as normal form fields, and (potentially streamed) binary
-/// [files].
-///
-/// This request automatically sets the Content-Type header to
-/// `multipart/form-data`. This value will override any value set by the user.
-///
-/// var uri = Uri.parse("http://pub.dartlang.org/packages/create");
-/// var request = new http.MultipartRequest("POST", url);
-/// request.fields['user'] = 'nweiz@google.com';
-/// request.files.add(new http.MultipartFile.fromFile(
-/// 'package',
-/// new File('build/package.tar.gz'),
-/// contentType: new MediaType('application', 'x-tar'));
-/// request.send().then((response) {
-/// if (response.statusCode == 200) print("Uploaded!");
-/// });
-class MultipartRequest extends BaseRequest {
- /// The total length of the multipart boundaries used when building the
- /// request body. According to http://tools.ietf.org/html/rfc1341.html, this
- /// can't be longer than 70.
- static const int _BOUNDARY_LENGTH = 70;
-
- static final Random _random = new Random();
-
- /// The form fields to send for this request.
- final Map<String, String> fields;
-
- /// The private version of [files].
- final List<MultipartFile> _files;
-
- /// Creates a new [MultipartRequest].
- MultipartRequest(String method, Uri url)
- : fields = <String, String>{},
- _files = <MultipartFile>[],
- super(method, url);
-
- /// The list of files to upload for this request.
- List<MultipartFile> get files => _files;
-
- /// The total length of the request body, in bytes. This is calculated from
- /// [fields] and [files] and cannot be set manually.
- @override
- int get contentLength {
- int length = 0;
-
- fields.forEach((String name, String value) {
- length += "--".length + _BOUNDARY_LENGTH + "\r\n".length +
- UTF8.encode(_headerForField(name, value)).length +
- UTF8.encode(value).length + "\r\n".length;
- });
-
- for (MultipartFile file in _files) {
- length += "--".length + _BOUNDARY_LENGTH + "\r\n".length +
- UTF8.encode(_headerForFile(file)).length +
- file.length + "\r\n".length;
- }
-
- return length + "--".length + _BOUNDARY_LENGTH + "--\r\n".length;
- }
-
- @override
- set contentLength(int value) {
- throw new UnsupportedError("Cannot set the contentLength property of "
- "multipart requests.");
- }
-
- /// Freezes all mutable fields and returns a single-subscription [ByteStream]
- /// that will emit the request body.
- @override
- ByteStream finalize() {
- // TODO(nweiz): freeze fields and files
- String boundary = _boundaryString();
- headers['content-type'] = 'multipart/form-data; boundary="$boundary"';
- super.finalize();
-
- StreamController<List<int>> controller = new StreamController<List<int>>(sync: true);
-
- void writeAscii(String string) {
- controller.add(UTF8.encode(string));
- }
-
- dynamic writeUtf8(String string) => controller.add(UTF8.encode(string));
- dynamic writeLine() => controller.add(<int>[13, 10]); // \r\n
-
- fields.forEach((String name, String value) {
- writeAscii('--$boundary\r\n');
- writeAscii(_headerForField(name, value));
- writeUtf8(value);
- writeLine();
- });
-
- Future.forEach(_files, (MultipartFile file) {
- writeAscii('--$boundary\r\n');
- writeAscii(_headerForFile(file));
- return writeStreamToSink(file.finalize(), controller)
- .then((_) => writeLine());
- }).then((_) {
- // TODO(nweiz): pass any errors propagated through this future on to
- // the stream. See issue 3657.
- writeAscii('--$boundary--\r\n');
- controller.close();
- });
-
- return new ByteStream(controller.stream);
- }
-
- /// All character codes that are valid in multipart boundaries. From
- /// http://tools.ietf.org/html/rfc2046#section-5.1.1.
- static const List<int> _BOUNDARY_CHARACTERS = const <int>[
- 39, 40, 41, 43, 95, 44, 45, 46, 47, 58, 61, 63, 48, 49, 50, 51, 52, 53, 54,
- 55, 56, 57, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80,
- 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 97, 98, 99, 100, 101, 102, 103,
- 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118,
- 119, 120, 121, 122
- ];
-
- /// Returns the header string for a field. The return value is guaranteed to
- /// contain only ASCII characters.
- String _headerForField(String name, String value) {
- String header =
- 'content-disposition: form-data; name="${_browserEncode(name)}"';
- if (!isPlainAscii(value)) {
- header = '$header\r\n'
- 'content-type: text/plain; charset=utf-8\r\n'
- 'content-transfer-encoding: binary';
- }
- return '$header\r\n\r\n';
- }
-
- /// Returns the header string for a file. The return value is guaranteed to
- /// contain only ASCII characters.
- String _headerForFile(MultipartFile file) {
- String header = 'content-type: ${file.contentType}\r\n'
- 'content-disposition: form-data; name="${_browserEncode(file.field)}"';
-
- if (file.filename != null) {
- header = '$header; filename="${_browserEncode(file.filename)}"';
- }
- return '$header\r\n\r\n';
- }
-
- /// Encode [value] in the same way browsers do.
- String _browserEncode(String value) {
- // http://tools.ietf.org/html/rfc2388 mandates some complex encodings for
- // field names and file names, but in practice user agents seem not to
- // follow this at all. Instead, they URL-encode `\r`, `\n`, and `\r\n` as
- // `\r\n`; URL-encode `"`; and do nothing else (even for `%` or non-ASCII
- // characters). We follow their behavior.
- return value.replaceAll(_newlineRegExp, "%0D%0A").replaceAll('"', "%22");
- }
-
- /// Returns a randomly-generated multipart boundary string
- String _boundaryString() {
- String prefix = "dart-http-boundary-";
- List<int> list = new List<int>.generate(_BOUNDARY_LENGTH - prefix.length,
- (int index) =>
- _BOUNDARY_CHARACTERS[_random.nextInt(_BOUNDARY_CHARACTERS.length)],
- growable: false);
- return "$prefix${new String.fromCharCodes(list)}";
- }
-}
diff --git a/packages/flutter/lib/src/http/request.dart b/packages/flutter/lib/src/http/request.dart
deleted file mode 100644
index 495e663..0000000
--- a/packages/flutter/lib/src/http/request.dart
+++ /dev/null
@@ -1,164 +0,0 @@
-// Copyright (c) 2013, 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:convert';
-import 'dart:typed_data';
-
-import 'package:http_parser/http_parser.dart';
-
-import 'base_request.dart';
-import 'byte_stream.dart';
-import 'utils.dart';
-
-/// An HTTP request where the entire request body is known in advance.
-class Request extends BaseRequest {
- /// Creates a new HTTP request.
- Request(String method, Uri url)
- : _defaultEncoding = UTF8,
- _bodyBytes = new Uint8List(0),
- super(method, url);
-
- /// The size of the request body, in bytes. This is calculated from
- /// [bodyBytes].
- ///
- /// The content length cannot be set for [Request], since it's automatically
- /// calculated from [bodyBytes].
- @override
- int get contentLength => bodyBytes.length;
-
- @override
- set contentLength(int value) {
- throw new UnsupportedError("Cannot set the contentLength property of "
- "non-streaming Request objects.");
- }
-
- /// The default encoding to use when converting between [bodyBytes] and
- /// [body]. This is only used if [encoding] hasn't been manually set and if
- /// the content-type header has no encoding information.
- Encoding _defaultEncoding;
-
- /// The encoding used for the request. This encoding is used when converting
- /// between [bodyBytes] and [body].
- ///
- /// If the request has a `Content-Type` header and that header has a `charset`
- /// parameter, that parameter's value is used as the encoding. Otherwise, if
- /// [encoding] has been set manually, that encoding is used. If that hasn't
- /// been set either, this defaults to [UTF8].
- ///
- /// If the `charset` parameter's value is not a known [Encoding], reading this
- /// will throw a [FormatException].
- ///
- /// If the request has a `Content-Type` header, setting this will set the
- /// charset parameter on that header.
- Encoding get encoding {
- if (_contentType == null ||
- !_contentType.parameters.containsKey('charset')) {
- return _defaultEncoding;
- }
- return requiredEncodingForCharset(_contentType.parameters['charset']);
- }
-
- set encoding(Encoding value) {
- _checkFinalized();
- _defaultEncoding = value;
- MediaType contentType = _contentType;
- if (contentType == null) return;
- _contentType = contentType.change(parameters: <String, String>{'charset': value.name});
- }
-
- // TODO(nweiz): make this return a read-only view
- /// The bytes comprising the body of the request. This is converted to and
- /// from [body] using [encoding].
- ///
- /// This list should only be set, not be modified in place.
- Uint8List get bodyBytes => _bodyBytes;
- Uint8List _bodyBytes;
-
- set bodyBytes(List<int> value) {
- _checkFinalized();
- _bodyBytes = toUint8List(value);
- }
-
- /// The body of the request as a string. This is converted to and from
- /// [bodyBytes] using [encoding].
- ///
- /// When this is set, if the request does not yet have a `Content-Type`
- /// header, one will be added with the type `text/plain`. Then the `charset`
- /// parameter of the `Content-Type` header (whether new or pre-existing) will
- /// be set to [encoding] if it wasn't already set.
- String get body => encoding.decode(bodyBytes);
-
- set body(String value) {
- bodyBytes = encoding.encode(value);
- MediaType contentType = _contentType;
- if (contentType == null) {
- _contentType = new MediaType("text", "plain", <String, String>{'charset': encoding.name});
- } else if (!contentType.parameters.containsKey('charset')) {
- _contentType = contentType.change(parameters: <String, String>{'charset': encoding.name});
- }
- }
-
- /// The form-encoded fields in the body of the request as a map from field
- /// names to values. The form-encoded body is converted to and from
- /// [bodyBytes] using [encoding] (in the same way as [body]).
- ///
- /// If the request doesn't have a `Content-Type` header of
- /// `application/x-www-form-urlencoded`, reading this will throw a
- /// [StateError].
- ///
- /// If the request has a `Content-Type` header with a type other than
- /// `application/x-www-form-urlencoded`, setting this will throw a
- /// [StateError]. Otherwise, the content type will be set to
- /// `application/x-www-form-urlencoded`.
- ///
- /// This map should only be set, not modified in place.
- Map<String, String> get bodyFields {
- MediaType contentType = _contentType;
- if (contentType == null ||
- contentType.mimeType != "application/x-www-form-urlencoded") {
- throw new StateError('Cannot access the body fields of a Request without '
- 'content-type "application/x-www-form-urlencoded".');
- }
-
- return Uri.splitQueryString(body, encoding: encoding);
- }
-
- set bodyFields(Map<String, String> fields) {
- MediaType contentType = _contentType;
- if (contentType == null) {
- _contentType = new MediaType("application", "x-www-form-urlencoded");
- } else if (contentType.mimeType != "application/x-www-form-urlencoded") {
- throw new StateError('Cannot set the body fields of a Request with '
- 'content-type "${contentType.mimeType}".');
- }
-
- this.body = mapToQuery(fields, encoding: encoding);
- }
-
- /// Freezes all mutable fields and returns a single-subscription [ByteStream]
- /// containing the request body.
- @override
- ByteStream finalize() {
- super.finalize();
- return new ByteStream.fromBytes(bodyBytes);
- }
-
- /// The `Content-Type` header of the request (if it exists) as a
- /// [MediaType].
- MediaType get _contentType {
- String contentType = headers['content-type'];
- if (contentType == null) return null;
- return new MediaType.parse(contentType);
- }
-
- set _contentType(MediaType value) {
- headers['content-type'] = value.toString();
- }
-
- /// Throw an error if this request has been finalized.
- void _checkFinalized() {
- if (!finalized) return;
- throw new StateError("Can't modify a finalized Request.");
- }
-}
diff --git a/packages/flutter/lib/src/http/response.dart b/packages/flutter/lib/src/http/response.dart
deleted file mode 100644
index caba63b..0000000
--- a/packages/flutter/lib/src/http/response.dart
+++ /dev/null
@@ -1,95 +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:convert';
-import 'dart:typed_data';
-
-import 'package:http_parser/http_parser.dart';
-
-import 'base_request.dart';
-import 'base_response.dart';
-import 'streamed_response.dart';
-import 'utils.dart';
-
-/// An HTTP response where the entire response body is known in advance.
-class Response extends BaseResponse {
- /// The bytes comprising the body of this response.
- final Uint8List bodyBytes;
-
- /// Creates a new HTTP response with a string body.
- Response(
- String body,
- int statusCode,
- {BaseRequest request,
- Map<String, String> headers: const <String, String>{},
- bool isRedirect: false,
- bool persistentConnection: true,
- String reasonPhrase})
- : this.bytes(
- _encodingForHeaders(headers).encode(body),
- statusCode,
- request: request,
- headers: headers,
- isRedirect: isRedirect,
- persistentConnection: persistentConnection,
- reasonPhrase: reasonPhrase);
-
- /// Create a new HTTP response with a byte array body.
- Response.bytes(
- List<int> bodyBytes,
- int statusCode,
- {BaseRequest request,
- Map<String, String> headers: const <String, String>{},
- bool isRedirect: false,
- bool persistentConnection: true,
- String reasonPhrase})
- : bodyBytes = toUint8List(bodyBytes),
- super(
- statusCode,
- contentLength: bodyBytes.length,
- request: request,
- headers: headers,
- isRedirect: isRedirect,
- persistentConnection: persistentConnection,
- reasonPhrase: reasonPhrase);
-
- /// The body of the response as a string. This is converted from [bodyBytes]
- /// using the `charset` parameter of the `Content-Type` header field, if
- /// available. If it's unavailable or if the encoding name is unknown,
- /// [LATIN1] is used by default, as per [RFC 2616][].
- ///
- /// [RFC 2616]: http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html
- String get body => _encodingForHeaders(headers).decode(bodyBytes);
-
- /// Creates a new HTTP response by waiting for the full body to become
- /// available from a [StreamedResponse].
- static Future<Response> fromStream(StreamedResponse response) {
- return response.stream.toBytes().then((List<int> body) {
- return new Response.bytes(
- body,
- response.statusCode,
- request: response.request,
- headers: response.headers,
- isRedirect: response.isRedirect,
- persistentConnection: response.persistentConnection,
- reasonPhrase: response.reasonPhrase);
- });
- }
-}
-
-/// Returns the encoding to use for a response with the given headers. This
-/// defaults to [LATIN1] if the headers don't specify a charset or
-/// if that charset is unknown.
-Encoding _encodingForHeaders(Map<String, String> headers) =>
- encodingForCharset(_contentTypeForHeaders(headers).parameters['charset']);
-
-/// Returns the [MediaType] object for the given headers's content-type.
-///
-/// Defaults to `application/octet-stream`.
-MediaType _contentTypeForHeaders(Map<String, String> headers) {
- String contentType = headers['content-type'];
- if (contentType != null) return new MediaType.parse(contentType);
- return new MediaType("application", "octet-stream");
-}
diff --git a/packages/flutter/lib/src/http/streamed_request.dart b/packages/flutter/lib/src/http/streamed_request.dart
deleted file mode 100644
index 8d1b408..0000000
--- a/packages/flutter/lib/src/http/streamed_request.dart
+++ /dev/null
@@ -1,42 +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 {
- /// Creates a new streaming request.
- StreamedRequest(String method, Uri url)
- : _controller = new StreamController<List<int>>(sync: true),
- super(method, url);
-
- /// 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<List<int>> get sink => _controller.sink;
-
- /// The controller for [sink], from which [BaseRequest] will read data for
- /// [finalize].
- final StreamController<List<int>> _controller;
-
- /// Freezes all mutable fields other than [stream] and returns a
- /// single-subscription [ByteStream] that emits the data being written to
- /// [sink].
- @override
- ByteStream finalize() {
- super.finalize();
- return new ByteStream(_controller.stream);
- }
-}
diff --git a/packages/flutter/lib/src/http/streamed_response.dart b/packages/flutter/lib/src/http/streamed_response.dart
deleted file mode 100644
index a23a952..0000000
--- a/packages/flutter/lib/src/http/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<List<int>> stream,
- int statusCode,
- {int contentLength,
- BaseRequest request,
- Map<String, String> headers: const <String, String> {},
- 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);
-}
diff --git a/packages/flutter/lib/src/http/utils.dart b/packages/flutter/lib/src/http/utils.dart
deleted file mode 100644
index 4617269..0000000
--- a/packages/flutter/lib/src/http/utils.dart
+++ /dev/null
@@ -1,143 +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:convert';
-import 'dart:typed_data';
-
-import 'byte_stream.dart';
-
-/// Converts a [Map] from parameter names to values to a URL query string.
-///
-/// mapToQuery({"foo": "bar", "baz": "bang"});
-/// //=> "foo=bar&baz=bang"
-String mapToQuery(Map<String, String> map, {Encoding encoding}) {
- List<List<String>> pairs = <List<String>>[];
- map.forEach((String key, String value) =>
- pairs.add(<String>[Uri.encodeQueryComponent(key, encoding: encoding),
- Uri.encodeQueryComponent(value, encoding: encoding)]));
- return pairs.map((List<String> pair) => "${pair[0]}=${pair[1]}").join("&");
-}
-
-/// Like [String.split], but only splits on the first occurrence of the pattern.
-/// This will always return an array of two elements or fewer.
-///
-/// split1("foo,bar,baz", ","); //=> ["foo", "bar,baz"]
-/// split1("foo", ","); //=> ["foo"]
-/// split1("", ","); //=> []
-List<String> split1(String toSplit, String pattern) {
- if (toSplit.isEmpty) return <String>[];
-
- int index = toSplit.indexOf(pattern);
- if (index == -1) return <String>[toSplit];
- return <String>[
- toSplit.substring(0, index),
- toSplit.substring(index + pattern.length)
- ];
-}
-
-/// Returns the [Encoding] that corresponds to [charset]. Returns [fallback] if
-/// [charset] is null or if no [Encoding] was found that corresponds to
-/// [charset].
-Encoding encodingForCharset(String charset, [Encoding fallback = LATIN1]) {
- if (charset == null) return fallback;
- Encoding encoding = Encoding.getByName(charset);
- return encoding == null ? fallback : encoding;
-}
-
-
-/// Returns the [Encoding] that corresponds to [charset]. Throws a
-/// [FormatException] if no [Encoding] was found that corresponds to [charset].
-/// [charset] may not be null.
-Encoding requiredEncodingForCharset(String charset) {
- Encoding encoding = Encoding.getByName(charset);
- if (encoding != null) return encoding;
- throw new FormatException('Unsupported encoding "$charset".');
-}
-
-/// A regular expression that matches strings that are composed entirely of
-/// ASCII-compatible characters.
-final RegExp _kAsciiOnly = new RegExp(r"^[\x00-\x7F]+$");
-
-/// Returns whether [string] is composed entirely of ASCII-compatible
-/// characters.
-bool isPlainAscii(String string) => _kAsciiOnly.hasMatch(string);
-
-/// Converts [input] into a [Uint8List].
-///
-/// If [input] is a [TypedData], this just returns a view on [input].
-Uint8List toUint8List(dynamic input) {
- if (input is Uint8List)
- return input;
- if (input is TypedData)
- return new Uint8List.view(input.buffer);
- return new Uint8List.fromList(input);
-}
-
-/// If [stream] is already a [ByteStream], returns it. Otherwise, wraps it in a
-/// [ByteStream].
-ByteStream toByteStream(Stream<List<int>> stream) {
- if (stream is ByteStream) return stream;
- return new ByteStream(stream);
-}
-
-/// Calls [onDone] once [stream] (a single-subscription [Stream]) is finished.
-/// The return value, also a single-subscription [Stream] should be used in
-/// place of [stream] after calling this method.
-Stream/*<T>*/ onDone/*<T>*/(Stream/*<T>*/ stream, void onDone()) =>
- stream.transform(new StreamTransformer.fromHandlers(handleDone: (EventSink<dynamic> sink) { // ignore: always_specify_types
- sink.close();
- onDone();
- }));
-
-// TODO(nweiz): remove this when issue 7786 is fixed.
-/// Pipes all data and errors from [stream] into [sink]. When [stream] is done,
-/// [sink] is closed and the returned [Future] is completed.
-Future<dynamic> store(Stream<dynamic> stream, EventSink<dynamic> sink) {
- Completer<dynamic> completer = new Completer<dynamic>();
- stream.listen(sink.add,
- onError: sink.addError,
- onDone: () {
- sink.close();
- completer.complete();
- });
- return completer.future;
-}
-
-/// Pipes all data and errors from [stream] into [sink]. Completes [Future] once
-/// [stream] is done. Unlike [store], [sink] remains open after [stream] is
-/// done.
-Future<dynamic> writeStreamToSink(Stream<dynamic> stream, EventSink<dynamic> sink) {
- Completer<dynamic> completer = new Completer<dynamic>();
- stream.listen(sink.add,
- onError: sink.addError,
- onDone: () => completer.complete());
- return completer.future;
-}
-
-/// A pair of values.
-class Pair<E, F> {
- E first;
- F last;
-
- Pair(this.first, this.last);
-
- @override
- String toString() => '($first, $last)';
-
- @override
- bool operator==(dynamic other) {
- if (other is! Pair) return false;
- return other.first == first && other.last == last;
- }
-
- @override
- int get hashCode => first.hashCode ^ last.hashCode;
-}
-
-/// Configures [future] so that its result (success or exception) is passed on
-/// to [completer].
-void chainToCompleter(Future<dynamic> future, Completer<dynamic> completer) {
- future.then(completer.complete, onError: completer.completeError);
-}
diff --git a/packages/flutter/lib/src/services/asset_bundle.dart b/packages/flutter/lib/src/services/asset_bundle.dart
index 373aa84..d649952 100644
--- a/packages/flutter/lib/src/services/asset_bundle.dart
+++ b/packages/flutter/lib/src/services/asset_bundle.dart
@@ -7,9 +7,10 @@
import 'dart:typed_data';
import 'package:flutter/foundation.dart';
-import 'package:flutter/http.dart' as http;
+import 'package:http/http.dart' as http;
import 'platform_messages.dart';
+import 'http_client.dart';
/// A collection of resources used by the application.
///
@@ -84,15 +85,18 @@
class NetworkAssetBundle extends AssetBundle {
/// Creates an network asset bundle that resolves asset keys as URLs relative
/// to the given base URL.
- NetworkAssetBundle(Uri baseUrl) : _baseUrl = baseUrl;
+ NetworkAssetBundle(Uri baseUrl)
+ : _baseUrl = baseUrl,
+ _httpClient = createHttpClient();
final Uri _baseUrl;
+ final http.Client _httpClient;
String _urlFromKey(String key) => _baseUrl.resolve(key).toString();
@override
Future<ByteData> load(String key) async {
- final http.Response response = await http.get(_urlFromKey(key));
+ final http.Response response = await _httpClient.get(_urlFromKey(key));
if (response.statusCode == 200)
return null;
return response.bodyBytes.buffer.asByteData();
@@ -100,7 +104,7 @@
@override
Future<String> loadString(String key, { bool cache: true }) async {
- final http.Response response = await http.get(_urlFromKey(key));
+ final http.Response response = await _httpClient.get(_urlFromKey(key));
return response.statusCode == 200 ? response.body : null;
}
diff --git a/packages/flutter/lib/src/services/http_client.dart b/packages/flutter/lib/src/services/http_client.dart
new file mode 100644
index 0000000..2a058d8
--- /dev/null
+++ b/packages/flutter/lib/src/services/http_client.dart
@@ -0,0 +1,16 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:flutter/foundation.dart';
+import 'package:http/http.dart' as http;
+
+/// Create a new [http.Client] object.
+///
+/// This can be set to a new function to override the default logic for creating
+/// HTTP clients, for example so that all logic in the framework that triggers
+/// HTTP requests will use the same `UserAgent` header, or so that tests can
+/// provide an [http.MockClient].
+ValueGetter<http.Client> createHttpClient = () {
+ return new http.Client();
+};
diff --git a/packages/flutter/lib/src/services/image_provider.dart b/packages/flutter/lib/src/services/image_provider.dart
index 1d59abc..ab83712 100644
--- a/packages/flutter/lib/src/services/image_provider.dart
+++ b/packages/flutter/lib/src/services/image_provider.dart
@@ -9,9 +9,10 @@
import 'dart:ui' show Size, Locale, hashValues;
import 'package:flutter/foundation.dart';
-import 'package:flutter/http.dart' as http;
+import 'package:http/http.dart' as http;
import 'asset_bundle.dart';
+import 'http_client.dart';
import 'image_cache.dart';
import 'image_decoder.dart';
import 'image_stream.dart';
@@ -332,11 +333,13 @@
);
}
+ static final http.Client _httpClient = createHttpClient();
+
Future<ImageInfo> _loadAsync(NetworkImage key) async {
assert(key == this);
final Uri resolved = Uri.base.resolve(key.url);
- final http.Response response = await http.get(resolved);
+ final http.Response response = await _httpClient.get(resolved);
if (response == null || response.statusCode != 200)
return null;
diff --git a/packages/flutter/pubspec.yaml b/packages/flutter/pubspec.yaml
index 7a3651b..4a8eae1 100644
--- a/packages/flutter/pubspec.yaml
+++ b/packages/flutter/pubspec.yaml
@@ -6,15 +6,11 @@
dependencies:
collection: '>=1.9.1 <2.0.0'
+ http: '>=0.11.3+11'
intl: '>=0.14.0 <0.15.0'
meta: ^1.0.4
vector_math: '>=2.0.3 <3.0.0'
- # async and http_parser can be removed when we move to using dart-lang/http
- # directly.
- async: "^1.10.0"
- http_parser: ">=0.0.1 <4.0.0"
-
sky_engine:
path: ../../bin/cache/pkg/sky_engine
diff --git a/packages/flutter_test/lib/src/binding.dart b/packages/flutter_test/lib/src/binding.dart
index 38498e7..e1f8f31 100644
--- a/packages/flutter_test/lib/src/binding.dart
+++ b/packages/flutter_test/lib/src/binding.dart
@@ -8,10 +8,12 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart';
-import 'package:flutter/http.dart' as http;
import 'package:flutter/rendering.dart';
import 'package:flutter/scheduler.dart';
+import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';
+import 'package:http/http.dart' as http;
+import 'package:http/testing.dart' as http;
import 'package:meta/meta.dart';
import 'package:quiver/testing/async.dart';
import 'package:quiver/time.dart';
@@ -119,7 +121,7 @@
@override
void initInstances() {
timeDilation = 1.0; // just in case the developer has artificially changed it for development
- http.Client.clientOverride = () {
+ createHttpClient = () {
return new http.MockClient((http.BaseRequest request) {
return new Future<http.Response>.value(
new http.Response("Mocked: Unavailable.", 404, request: request)