Unverified Commit 85cb38e7 authored by Dan Field's avatar Dan Field Committed by GitHub

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
parent 62b7aee9
...@@ -21,3 +21,4 @@ Yusuke Konishi <yahpeycoy0403@gmail.com> ...@@ -21,3 +21,4 @@ Yusuke Konishi <yahpeycoy0403@gmail.com>
Fredrik Simón <fredrik@fsimon.net> Fredrik Simón <fredrik@fsimon.net>
Ali Bitek <alibitek@protonmail.ch> Ali Bitek <alibitek@protonmail.ch>
Tetsuhiro Ueda <najeira@gmail.com> Tetsuhiro Ueda <najeira@gmail.com>
Dan Field <dfield@gmail.com>
...@@ -10,39 +10,24 @@ import 'dart:typed_data'; ...@@ -10,39 +10,24 @@ import 'dart:typed_data';
/// ///
/// The future returned will forward all errors emitted by [response]. /// The future returned will forward all errors emitted by [response].
Future<Uint8List> consolidateHttpClientResponseBytes(HttpClientResponse response) { Future<Uint8List> consolidateHttpClientResponseBytes(HttpClientResponse response) {
// dart:io guarantees that [contentLength] is -1 if the the header is missing or // response.contentLength is not trustworthy when GZIP is involved
// invalid. This could still happen if a mocked response object does not fully // or other cases where an intermediate transformer has been applied
// implement the interface. // to the stream.
assert(response.contentLength != null);
final Completer<Uint8List> completer = new Completer<Uint8List>.sync(); final Completer<Uint8List> completer = new Completer<Uint8List>.sync();
if (response.contentLength == -1) { final List<List<int>> chunks = <List<int>>[];
final List<List<int>> chunks = <List<int>>[]; int contentLength = 0;
int contentLength = 0; response.listen((List<int> chunk) {
response.listen((List<int> chunk) { chunks.add(chunk);
chunks.add(chunk); contentLength += chunk.length;
contentLength += chunk.length; }, onDone: () {
}, onDone: () { final Uint8List bytes = new Uint8List(contentLength);
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);
int offset = 0; int offset = 0;
response.listen((List<int> chunk) { for (List<int> chunk in chunks) {
bytes.setRange(offset, offset + chunk.length, chunk); bytes.setRange(offset, offset + chunk.length, chunk);
offset += chunk.length; offset += chunk.length;
}, }
onError: completer.completeError, completer.complete(bytes);
onDone: () { }, onError: completer.completeError, cancelOnError: true);
completer.complete(bytes);
},
cancelOnError: true);
}
return completer.future; return completer.future;
} }
...@@ -24,21 +24,40 @@ void main() { ...@@ -24,21 +24,40 @@ void main() {
final void Function() onDone = invocation.namedArguments[#onDone]; final void Function() onDone = invocation.namedArguments[#onDone];
final bool cancelOnError = invocation.namedArguments[#cancelOnError]; final bool cancelOnError = invocation.namedArguments[#cancelOnError];
return new Stream<List<int>>.fromIterable(<List<int>>[chunkOne, chunkTwo]) return new Stream<List<int>>.fromIterable(
.listen(onData, onDone: onDone, onError: onError, cancelOnError: cancelOnError); <List<int>>[chunkOne, chunkTwo]).listen(
onData,
onDone: onDone,
onError: onError,
cancelOnError: cancelOnError,
);
}); });
}); });
test('Converts an HttpClientResponse with contentLength to bytes', () async { test('Converts an HttpClientResponse with contentLength to bytes',
when(response.contentLength).thenReturn(chunkOne.length + chunkTwo.length); () async {
final List<int> bytes = await consolidateHttpClientResponseBytes(response); 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]); 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); 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]); expect(bytes, <int>[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
}); });
...@@ -55,12 +74,19 @@ void main() { ...@@ -55,12 +74,19 @@ void main() {
final void Function() onDone = invocation.namedArguments[#onDone]; final void Function() onDone = invocation.namedArguments[#onDone];
final bool cancelOnError = invocation.namedArguments[#cancelOnError]; final bool cancelOnError = invocation.namedArguments[#cancelOnError];
return new Stream<List<int>>.fromFuture(new Future<List<int>>.error(new Exception('Test Error'))) return new Stream<List<int>>.fromFuture(
.listen(onData, onDone: onDone, onError: onError, cancelOnError: cancelOnError); new Future<List<int>>.error(new Exception('Test Error')))
.listen(
onData,
onDone: onDone,
onError: onError,
cancelOnError: cancelOnError,
);
}); });
when(response.contentLength).thenReturn(-1); when(response.contentLength).thenReturn(-1);
expect(consolidateHttpClientResponseBytes(response), throwsA(const isInstanceOf<Exception>())); expect(consolidateHttpClientResponseBytes(response),
throwsA(const isInstanceOf<Exception>()));
}); });
}); });
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment