Fix consolidate HTTP response and add test  (#17082)

* Fix consolidate response and add test

* Update AUTHORS

* ignore content-length

* fix formatting/update comment

* more commas

* Fix consolidate response and add test

* Update AUTHORS

* ignore content-length

* fix formatting/update comment

* more commas

* remove extra newline
diff --git a/AUTHORS b/AUTHORS
index 26cc1e9..fd1df22 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -21,3 +21,4 @@
 Fredrik Simón <fredrik@fsimon.net>
 Ali Bitek <alibitek@protonmail.ch>
 Tetsuhiro Ueda <najeira@gmail.com>
+Dan Field <dfield@gmail.com>
diff --git a/packages/flutter/lib/src/foundation/consolidate_response.dart b/packages/flutter/lib/src/foundation/consolidate_response.dart
index 183117e..cd6f158 100644
--- a/packages/flutter/lib/src/foundation/consolidate_response.dart
+++ b/packages/flutter/lib/src/foundation/consolidate_response.dart
@@ -10,39 +10,24 @@
 /// 
 /// The future returned will forward all errors emitted by [response].
 Future<Uint8List> consolidateHttpClientResponseBytes(HttpClientResponse response) {
-  // dart:io guarantees that [contentLength] is -1 if the the header is missing or
-  // invalid.  This could still happen if a mocked response object does not fully
-  // implement the interface.
-  assert(response.contentLength != null);
+  // response.contentLength is not trustworthy when GZIP is involved
+  // or other cases where an intermediate transformer has been applied
+  // to the stream.
   final Completer<Uint8List> completer = new Completer<Uint8List>.sync();
-  if (response.contentLength == -1) {
-    final List<List<int>> chunks = <List<int>>[];
-    int contentLength = 0;
-    response.listen((List<int> chunk) {
-      chunks.add(chunk);
-      contentLength += chunk.length;
-    }, onDone: () {
-      final Uint8List bytes = new Uint8List(contentLength);
-      int offset = 0;
-      for (List<int> chunk in chunks) {
-        bytes.setRange(offset, offset + chunk.length, chunk);
-        offset += chunk.length;
-      }
-      completer.complete(bytes);
-    }, onError: completer.completeError, cancelOnError: true);
-  } else {
-    // If the response has a content length, then allocate a buffer of the correct size.
-    final Uint8List bytes = new Uint8List(response.contentLength);
+  final List<List<int>> chunks = <List<int>>[];
+  int contentLength = 0;
+  response.listen((List<int> chunk) {
+    chunks.add(chunk);
+    contentLength += chunk.length;
+  }, onDone: () {
+    final Uint8List bytes = new Uint8List(contentLength);
     int offset = 0;
-    response.listen((List<int> chunk) {
+    for (List<int> chunk in chunks) {
       bytes.setRange(offset, offset + chunk.length, chunk);
       offset += chunk.length;
-    },
-    onError: completer.completeError,
-    onDone: () {
-      completer.complete(bytes);
-    },
-    cancelOnError: true);
-  }
+    }
+    completer.complete(bytes);
+  }, onError: completer.completeError, cancelOnError: true);
+  
   return completer.future;
 }
diff --git a/packages/flutter/test/foundation/consolidate_response_test.dart b/packages/flutter/test/foundation/consolidate_response_test.dart
index 184d9a2..c967197 100644
--- a/packages/flutter/test/foundation/consolidate_response_test.dart
+++ b/packages/flutter/test/foundation/consolidate_response_test.dart
@@ -24,21 +24,40 @@
         final void Function() onDone = invocation.namedArguments[#onDone];
         final bool cancelOnError = invocation.namedArguments[#cancelOnError];
 
-        return new Stream<List<int>>.fromIterable(<List<int>>[chunkOne, chunkTwo])
-          .listen(onData, onDone: onDone, onError: onError, cancelOnError: cancelOnError);
+        return new Stream<List<int>>.fromIterable(
+            <List<int>>[chunkOne, chunkTwo]).listen(
+          onData,
+          onDone: onDone,
+          onError: onError,
+          cancelOnError: cancelOnError,
+        );
       });
     });
 
-    test('Converts an HttpClientResponse with contentLength to bytes', () async {
-      when(response.contentLength).thenReturn(chunkOne.length + chunkTwo.length);
-      final List<int> bytes = await consolidateHttpClientResponseBytes(response);
+    test('Converts an HttpClientResponse with contentLength to bytes',
+        () async {
+      when(response.contentLength)
+          .thenReturn(chunkOne.length + chunkTwo.length);
+      final List<int> bytes =
+          await consolidateHttpClientResponseBytes(response);
 
       expect(bytes, <int>[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
     });
 
-    test('Converts an HttpClientResponse without contentLength to bytes', () async {
+    test('Converts a compressed HttpClientResponse with contentLength to bytes',
+        () async {
+      when(response.contentLength).thenReturn(chunkOne.length);
+      final List<int> bytes =
+          await consolidateHttpClientResponseBytes(response);
+
+      expect(bytes, <int>[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
+    });
+
+    test('Converts an HttpClientResponse without contentLength to bytes',
+        () async {
       when(response.contentLength).thenReturn(-1);
-      final List<int> bytes = await consolidateHttpClientResponseBytes(response);
+      final List<int> bytes =
+          await consolidateHttpClientResponseBytes(response);
 
       expect(bytes, <int>[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
     });
@@ -55,12 +74,19 @@
         final void Function() onDone = invocation.namedArguments[#onDone];
         final bool cancelOnError = invocation.namedArguments[#cancelOnError];
 
-        return new Stream<List<int>>.fromFuture(new Future<List<int>>.error(new Exception('Test Error')))
-          .listen(onData, onDone: onDone, onError: onError, cancelOnError: cancelOnError);
+        return new Stream<List<int>>.fromFuture(
+                new Future<List<int>>.error(new Exception('Test Error')))
+            .listen(
+          onData,
+          onDone: onDone,
+          onError: onError,
+          cancelOnError: cancelOnError,
+        );
       });
       when(response.contentLength).thenReturn(-1);
 
-      expect(consolidateHttpClientResponseBytes(response), throwsA(const isInstanceOf<Exception>()));
+      expect(consolidateHttpClientResponseBytes(response),
+          throwsA(const isInstanceOf<Exception>()));
     });
   });
 }