Fix all strong mode warnings.

R=rnystrom@google.com

Review URL: https://codereview.chromium.org//1913383002 .
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 087107d..e609b67 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.11.3+4
+
+* Fix all strong mode warnings.
+
 ## 0.11.3+3
 
 * Support `http_parser` 2.0.0.
diff --git a/lib/browser_client.dart b/lib/browser_client.dart
index d1179dc..883b2b1 100644
--- a/lib/browser_client.dart
+++ b/lib/browser_client.dart
@@ -4,6 +4,7 @@
 
 import 'dart:async';
 import 'dart:html';
+import 'dart:typed_data';
 
 import 'package:stack_trace/stack_trace.dart';
 
@@ -42,53 +43,63 @@
   bool withCredentials = false;
 
   /// Sends an HTTP request and asynchronously returns the response.
-  Future<StreamedResponse> send(BaseRequest request) {
-    return request.finalize().toBytes().then((bytes) {
-      var xhr = new HttpRequest();
-      _xhrs.add(xhr);
-      xhr.open(request.method, request.url.toString(), async: true);
-      xhr.responseType = 'blob';
-      xhr.withCredentials = withCredentials;
-      request.headers.forEach(xhr.setRequestHeader);
+  Future<StreamedResponse> send(BaseRequest request) async {
+    var bytes = await request.finalize().toBytes();
+    var xhr = new HttpRequest();
+    _xhrs.add(xhr);
+    _openHttpRequest(xhr, request.method, request.url.toString(), asynch: true);
+    xhr.responseType = 'blob';
+    xhr.withCredentials = withCredentials;
+    request.headers.forEach(xhr.setRequestHeader);
 
-      var completer = new Completer();
-      xhr.onLoad.first.then((_) {
-        // TODO(nweiz): Set the response type to "arraybuffer" when issue 18542
-        // is fixed.
-        var blob = xhr.response == null ? new Blob([]) : xhr.response;
-        var reader = new FileReader();
+    var completer = new Completer<StreamedResponse>();
+    xhr.onLoad.first.then((_) {
+      // TODO(nweiz): Set the response type to "arraybuffer" when issue 18542
+      // is fixed.
+      var blob = xhr.response == null ? new Blob([]) : xhr.response;
+      var reader = new FileReader();
 
-        reader.onLoad.first.then((_) {
-          var body = reader.result;
-          completer.complete(new StreamedResponse(
-              new ByteStream.fromBytes(body),
-              xhr.status,
-              contentLength: body.length,
-              request: request,
-              headers: xhr.responseHeaders,
-              reasonPhrase: xhr.statusText));
-        });
-
-        reader.onError.first.then((error) {
-          completer.completeError(
-              new ClientException(error.toString(), request.url),
-              new Chain.current());
-        });
-
-        reader.readAsArrayBuffer(blob);
+      reader.onLoad.first.then((_) {
+        var body = reader.result as Uint8List;
+        completer.complete(new StreamedResponse(
+            new ByteStream.fromBytes(body),
+            xhr.status,
+            contentLength: body.length,
+            request: request,
+            headers: xhr.responseHeaders,
+            reasonPhrase: xhr.statusText));
       });
 
-      xhr.onError.first.then((_) {
-        // Unfortunately, the underlying XMLHttpRequest API doesn't expose any
-        // specific information about the error itself.
+      reader.onError.first.then((error) {
         completer.completeError(
-            new ClientException("XMLHttpRequest error.", request.url),
+            new ClientException(error.toString(), request.url),
             new Chain.current());
       });
 
-      xhr.send(bytes);
-      return completer.future.whenComplete(() => _xhrs.remove(xhr));
+      reader.readAsArrayBuffer(blob);
     });
+
+    xhr.onError.first.then((_) {
+      // Unfortunately, the underlying XMLHttpRequest API doesn't expose any
+      // specific information about the error itself.
+      completer.completeError(
+          new ClientException("XMLHttpRequest error.", request.url),
+          new Chain.current());
+    });
+
+    xhr.send(bytes);
+
+    try {
+      return await completer.future;
+    } finally {
+      _xhrs.remove(xhr);
+    }
+  }
+
+  // TODO(nweiz): Remove this when sdk#24637 is fixed.
+  void _openHttpRequest(HttpRequest request, String method, String url,
+      {bool asynch, String user, String password}) {
+    request.open(method, url, async: asynch, user: user, password: password);
   }
 
   /// Closes the client.
diff --git a/lib/src/base_client.dart b/lib/src/base_client.dart
index cd5945e..7b3fbfa 100644
--- a/lib/src/base_client.dart
+++ b/lib/src/base_client.dart
@@ -6,6 +6,8 @@
 import 'dart:convert';
 import 'dart:typed_data';
 
+import 'package:collection/collection.dart';
+
 import 'base_request.dart';
 import 'client.dart';
 import 'exception.dart';
@@ -158,9 +160,9 @@
       if (body is String) {
         request.body = body;
       } else if (body is List) {
-        request.bodyBytes = body;
+        request.bodyBytes = DelegatingList.typed(body);
       } else if (body is Map) {
-        request.bodyFields = body;
+        request.bodyFields = DelegatingMap.typed(body);
       } else {
         throw new ArgumentError('Invalid request body "$body".');
       }
diff --git a/lib/src/base_request.dart b/lib/src/base_request.dart
index a9318cc..b11ef05 100644
--- a/lib/src/base_request.dart
+++ b/lib/src/base_request.dart
@@ -109,9 +109,11 @@
   /// 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() {
+  Future<StreamedResponse> send() async {
     var client = new Client();
-    return client.send(this).then((response) {
+
+    try {
+      var response = await client.send(this);
       var stream = onDone(response.stream, client.close);
       return new StreamedResponse(
           new ByteStream(stream),
@@ -122,10 +124,10 @@
           isRedirect: response.isRedirect,
           persistentConnection: response.persistentConnection,
           reasonPhrase: response.reasonPhrase);
-    }).catchError((e) {
+    } catch (_) {
       client.close();
-      throw e;
-    });
+      rethrow;
+    }
   }
 
   // Throws an error if this request has been finalized.
diff --git a/lib/src/byte_stream.dart b/lib/src/byte_stream.dart
index 2ce4deb..a9d47b0 100644
--- a/lib/src/byte_stream.dart
+++ b/lib/src/byte_stream.dart
@@ -6,8 +6,6 @@
 import 'dart:convert';
 import 'dart:typed_data';
 
-import 'utils.dart';
-
 /// A stream of chunks of bytes representing a single piece of data.
 class ByteStream extends StreamView<List<int>> {
   ByteStream(Stream<List<int>> stream)
@@ -16,11 +14,11 @@
   /// Returns a single-subscription byte stream that will emit the given bytes
   /// in a single chunk.
   factory ByteStream.fromBytes(List<int> bytes) =>
-      new ByteStream(streamFromIterable([bytes]));
+      new ByteStream(new Stream.fromIterable([bytes]));
 
   /// Collects the data of this stream in a [Uint8List].
   Future<Uint8List> toBytes() {
-    var completer = new Completer();
+    var completer = new Completer<Uint8List>();
     var sink = new ByteConversionSink.withCallback((bytes) =>
         completer.complete(new Uint8List.fromList(bytes)));
     listen(sink.add, onError: completer.completeError, onDone: sink.close,
@@ -34,5 +32,5 @@
       encoding.decodeStream(this);
 
   Stream<String> toStringStream([Encoding encoding=UTF8]) =>
-      transform(encoding.decoder);
+      encoding.decoder.bind(this);
 }
diff --git a/lib/src/io_client.dart b/lib/src/io_client.dart
index 3f7bfc9..7387a30 100644
--- a/lib/src/io_client.dart
+++ b/lib/src/io_client.dart
@@ -4,6 +4,8 @@
 
 import 'dart:async';
 
+import 'package:async/async.dart';
+
 import 'base_client.dart';
 import 'base_request.dart';
 import 'exception.dart';
@@ -34,45 +36,47 @@
   }
 
   /// Sends an HTTP request and asynchronously returns the response.
-  Future<StreamedResponse> send(BaseRequest request) {
+  Future<StreamedResponse> send(BaseRequest request) async {
     var stream = request.finalize();
 
-    return _inner.openUrl(request.method, request.url)
-        .then((ioRequest) {
-      var contentLength = request.contentLength == null ?
-          -1 : request.contentLength;
+    try {
+      var ioRequest = await _inner.openUrl(request.method, request.url);
+
       ioRequest
           ..followRedirects = request.followRedirects
           ..maxRedirects = request.maxRedirects
-          ..contentLength = contentLength
+          ..contentLength = request.contentLength == null
+              ? -1
+              : request.contentLength
           ..persistentConnection = request.persistentConnection;
       request.headers.forEach((name, value) {
         ioRequest.headers.set(name, value);
       });
-      return stream.pipe(ioRequest);
-    }).then((response) {
-      var headers = {};
+
+      var response = await stream.pipe(
+          DelegatingStreamConsumer.typed(ioRequest));
+      var headers = <String, String>{};
       response.headers.forEach((key, values) {
         headers[key] = values.join(',');
       });
 
-      var contentLength = response.contentLength == -1 ?
-          null : response.contentLength;
       return new StreamedResponse(
-          response.handleError((error) =>
+          DelegatingStream.typed/*<List<int>>*/(response).handleError((error) =>
               throw new ClientException(error.message, error.uri),
               test: (error) => io.isHttpException(error)),
           response.statusCode,
-          contentLength: contentLength,
+          contentLength: response.contentLength == -1
+              ? null
+              : response.contentLength,
           request: request,
           headers: headers,
           isRedirect: response.isRedirect,
           persistentConnection: response.persistentConnection,
           reasonPhrase: response.reasonPhrase);
-    }).catchError((error) {
-      if (!io.isHttpException(error)) throw error;
+    } 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
diff --git a/lib/src/multipart_request.dart b/lib/src/multipart_request.dart
index c799d70..f589eaa 100644
--- a/lib/src/multipart_request.dart
+++ b/lib/src/multipart_request.dart
@@ -47,9 +47,9 @@
 
   /// Creates a new [MultipartRequest].
   MultipartRequest(String method, Uri url)
-    : super(method, url),
-      fields = {},
-      _files = <MultipartFile>[];
+    : fields = {},
+      _files = <MultipartFile>[],
+      super(method, url);
 
   /// The list of files to upload for this request.
   List<MultipartFile> get files => _files;
diff --git a/lib/src/request.dart b/lib/src/request.dart
index fe05d7d..67b664c 100644
--- a/lib/src/request.dart
+++ b/lib/src/request.dart
@@ -113,7 +113,7 @@
           'content-type "application/x-www-form-urlencoded".');
     }
 
-    return queryToMap(body, encoding: encoding);
+    return Uri.splitQueryString(body, encoding: encoding);
   }
 
   set bodyFields(Map<String, String> fields) {
@@ -130,9 +130,9 @@
 
   /// Creates a new HTTP request.
   Request(String method, Uri url)
-    : super(method, url),
-      _defaultEncoding = UTF8,
-      _bodyBytes = new Uint8List(0);
+    : _defaultEncoding = UTF8,
+      _bodyBytes = new Uint8List(0),
+      super(method, url);
 
   /// Freezes all mutable fields and returns a single-subscription [ByteStream]
   /// containing the request body.
diff --git a/lib/src/streamed_request.dart b/lib/src/streamed_request.dart
index e52f240..6a020bd 100644
--- a/lib/src/streamed_request.dart
+++ b/lib/src/streamed_request.dart
@@ -28,8 +28,8 @@
 
   /// Creates a new streaming request.
   StreamedRequest(String method, Uri url)
-    : super(method, url),
-      _controller = new StreamController<List<int>>(sync: true);
+    : _controller = new StreamController<List<int>>(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
diff --git a/lib/src/streamed_response.dart b/lib/src/streamed_response.dart
index 6f20efc..69d8356 100644
--- a/lib/src/streamed_response.dart
+++ b/lib/src/streamed_response.dart
@@ -27,13 +27,13 @@
        bool isRedirect: false,
        bool persistentConnection: true,
        String reasonPhrase})
-    : super(
-        statusCode,
-        contentLength: contentLength,
-        request: request,
-        headers: headers,
-        isRedirect: isRedirect,
-        persistentConnection: persistentConnection,
-        reasonPhrase: reasonPhrase),
-      this.stream = toByteStream(stream);
+    : this.stream = toByteStream(stream),
+      super(
+          statusCode,
+          contentLength: contentLength,
+          request: request,
+          headers: headers,
+          isRedirect: isRedirect,
+          persistentConnection: persistentConnection,
+          reasonPhrase: reasonPhrase);
 }
diff --git a/lib/src/utils.dart b/lib/src/utils.dart
index 195bbc0..a0f5e36 100644
--- a/lib/src/utils.dart
+++ b/lib/src/utils.dart
@@ -8,24 +8,6 @@
 
 import 'byte_stream.dart';
 
-/// Converts a URL query string (or `application/x-www-form-urlencoded` body)
-/// into a [Map] from parameter names to values.
-///
-///     queryToMap("foo=bar&baz=bang&qux");
-///     //=> {"foo": "bar", "baz": "bang", "qux": ""}
-Map<String, String> queryToMap(String queryList, {Encoding encoding}) {
-  var map = {};
-  for (var pair in queryList.split("&")) {
-    var split = split1(pair, "=");
-    if (split.isEmpty) continue;
-    var key = Uri.decodeQueryComponent(split[0], encoding: encoding);
-    var value = Uri.decodeQueryComponent(split.length > 1 ? split[1] : "",
-        encoding: encoding);
-    map[key] = value;
-  }
-  return map;
-}
-
 /// Converts a [Map] from parameter names to values to a URL query string.
 ///
 ///     mapToQuery({"foo": "bar", "baz": "bang"});
@@ -104,11 +86,11 @@
 /// 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 onDone(Stream stream, void onDone()) {
-  var pair = tee(stream);
-  pair.first.listen((_) {}, onError: (_) {}, onDone: onDone);
-  return pair.last;
-}
+Stream/*<T>*/ onDone/*<T>*/(Stream/*<T>*/ stream, void onDone()) =>
+    stream.transform(new StreamTransformer.fromHandlers(handleDone: (sink) {
+      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,
@@ -138,38 +120,6 @@
 /// Returns a [Future] that asynchronously completes to `null`.
 Future get async => new Future.value();
 
-/// Returns a closed [Stream] with no elements.
-Stream get emptyStream => streamFromIterable([]);
-
-/// Creates a single-subscription stream that emits the items in [iter] and then
-/// ends.
-Stream streamFromIterable(Iterable iter) {
-  var controller = new StreamController(sync: true);
-  iter.forEach(controller.add);
-  controller.close();
-  return controller.stream;
-}
-
-// TODO(nweiz): remove this when issue 7787 is fixed.
-/// Creates two single-subscription [Stream]s that each emit all values and
-/// errors from [stream]. This is useful if [stream] is single-subscription but
-/// multiple subscribers are necessary.
-Pair<Stream, Stream> tee(Stream stream) {
-  var controller1 = new StreamController(sync: true);
-  var controller2 = new StreamController(sync: true);
-  stream.listen((value) {
-    controller1.add(value);
-    controller2.add(value);
-  }, onError: (error, [StackTrace stackTrace]) {
-    controller1.addError(error, stackTrace);
-    controller2.addError(error, stackTrace);
-  }, onDone: () {
-    controller1.close();
-    controller2.close();
-  });
-  return new Pair<Stream, Stream>(controller1.stream, controller2.stream);
-}
-
 /// A pair of values.
 class Pair<E, F> {
   E first;
diff --git a/pubspec.yaml b/pubspec.yaml
index f2ba38e..1c59d5e 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,9 +1,11 @@
 name: http
-version: 0.11.3+3
+version: 0.11.3+4
 author: "Dart Team <misc@dartlang.org>"
 homepage: https://github.com/dart-lang/http
 description: A composable, Future-based API for making HTTP requests.
 dependencies:
+  async: "^1.10.0"
+  collection: "^1.5.0"
   http_parser: ">=0.0.1 <3.0.0"
   path: ">=0.9.0 <2.0.0"
   stack_trace: ">=0.9.1 <2.0.0"