consolidateHttpClientResponseBytes function

Future<Uint8List> consolidateHttpClientResponseBytes (HttpClientResponse response, { bool autoUncompress: true, BytesReceivedCallback onBytesReceived })

Efficiently converts the response body of an HttpClientResponse into a Uint8List.

The future returned will forward any error emitted by response.

The onBytesReceived callback, if specified, will be invoked for every chunk of bytes that is received while consolidating the response bytes. If the callback throws an error, processing of the response will halt, and the returned future will complete with the error that was thrown by the callback. For more information on how to interpret the parameters to the callback, see the documentation on BytesReceivedCallback.

If the response is gzipped and the autoUncompress parameter is true, this will automatically un-compress the bytes in the returned list if it hasn't already been done via HttpClient.autoUncompress. To get compressed bytes from this method (assuming the response is sending compressed bytes), set both HttpClient.autoUncompress to false and the autoUncompress parameter to false.

Implementation

Future<Uint8List> consolidateHttpClientResponseBytes(
  HttpClientResponse response, {
  bool autoUncompress = true,
  BytesReceivedCallback onBytesReceived,
}) {
  assert(autoUncompress != null);
  final Completer<Uint8List> completer = Completer<Uint8List>.sync();

  final _OutputBuffer output = _OutputBuffer();
  ByteConversionSink sink = output;
  int expectedContentLength = response.contentLength;
  if (expectedContentLength == -1)
    expectedContentLength = null;
  switch (response.compressionState) {
    case HttpClientResponseCompressionState.compressed:
      if (autoUncompress) {
        // We need to un-compress the bytes as they come in.
        sink = gzip.decoder.startChunkedConversion(output);
      }
      break;
    case HttpClientResponseCompressionState.decompressed:
      // response.contentLength will not match our bytes stream, so we declare
      // that we don't know the expected content length.
      expectedContentLength = null;
      break;
    case HttpClientResponseCompressionState.notCompressed:
      // Fall-through.
      break;
  }

  int bytesReceived = 0;
  StreamSubscription<List<int>> subscription;
  subscription = response.listen((List<int> chunk) {
    sink.add(chunk);
    if (onBytesReceived != null) {
      bytesReceived += chunk.length;
      try {
        onBytesReceived(bytesReceived, expectedContentLength);
      } catch (error, stackTrace) {
        completer.completeError(error, stackTrace);
        subscription.cancel();
        return;
      }
    }
  }, onDone: () {
    sink.close();
    completer.complete(output.bytes);
  }, onError: completer.completeError, cancelOnError: true);

  return completer.future;
}