Commit bd929c4a authored by Alexander Aprelev's avatar Alexander Aprelev Committed by Kaushik Iska

Revert "Use separate isolate for image loading. (#34188)" (#40984)

This reverts commit b12bdd0e as it
breaks existing tests that expect image loaded after certaing number of
pupms. With image loading done on separate isolate pumping is not
guaranteed to get image loaded.
parent 57c319a9
...@@ -5,7 +5,6 @@ ...@@ -5,7 +5,6 @@
import 'dart:async'; import 'dart:async';
import 'dart:convert'; import 'dart:convert';
import 'dart:io'; import 'dart:io';
import 'dart:isolate';
import 'dart:typed_data'; import 'dart:typed_data';
/// Signature for getting notified when chunks of bytes are received while /// Signature for getting notified when chunks of bytes are received while
...@@ -23,11 +22,11 @@ import 'dart:typed_data'; ...@@ -23,11 +22,11 @@ import 'dart:typed_data';
/// returned to the client and the total size of the response may not be known /// returned to the client and the total size of the response may not be known
/// until the request has been fully processed). /// until the request has been fully processed).
/// ///
/// This is used in [getHttpClientResponseBytes]. /// This is used in [consolidateHttpClientResponseBytes].
typedef BytesReceivedCallback = void Function(int cumulative, int total); typedef BytesReceivedCallback = void Function(int cumulative, int total);
/// Efficiently converts the response body of an [HttpClientResponse] into a /// Efficiently converts the response body of an [HttpClientResponse] into a
/// [TransferableTypedData]. /// [Uint8List].
/// ///
/// The future returned will forward any error emitted by `response`. /// The future returned will forward any error emitted by `response`.
/// ///
...@@ -44,13 +43,13 @@ typedef BytesReceivedCallback = void Function(int cumulative, int total); ...@@ -44,13 +43,13 @@ typedef BytesReceivedCallback = void Function(int cumulative, int total);
/// bytes from this method (assuming the response is sending compressed bytes), /// bytes from this method (assuming the response is sending compressed bytes),
/// set both [HttpClient.autoUncompress] to false and the `autoUncompress` /// set both [HttpClient.autoUncompress] to false and the `autoUncompress`
/// parameter to false. /// parameter to false.
Future<TransferableTypedData> getHttpClientResponseBytes( Future<Uint8List> consolidateHttpClientResponseBytes(
HttpClientResponse response, { HttpClientResponse response, {
bool autoUncompress = true, bool autoUncompress = true,
BytesReceivedCallback onBytesReceived, BytesReceivedCallback onBytesReceived,
}) { }) {
assert(autoUncompress != null); assert(autoUncompress != null);
final Completer<TransferableTypedData> completer = Completer<TransferableTypedData>.sync(); final Completer<Uint8List> completer = Completer<Uint8List>.sync();
final _OutputBuffer output = _OutputBuffer(); final _OutputBuffer output = _OutputBuffer();
ByteConversionSink sink = output; ByteConversionSink sink = output;
...@@ -90,54 +89,41 @@ Future<TransferableTypedData> getHttpClientResponseBytes( ...@@ -90,54 +89,41 @@ Future<TransferableTypedData> getHttpClientResponseBytes(
} }
}, onDone: () { }, onDone: () {
sink.close(); sink.close();
completer.complete(TransferableTypedData.fromList(output.chunks)); completer.complete(output.bytes);
}, onError: completer.completeError, cancelOnError: true); }, onError: completer.completeError, cancelOnError: true);
return completer.future; return completer.future;
} }
/// Efficiently converts the response body of an [HttpClientResponse] into a
/// [Uint8List].
///
/// (This method is deprecated - use [getHttpClientResponseBytes] instead.)
///
/// 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.
@Deprecated('Use getHttpClientResponseBytes instead')
Future<Uint8List> consolidateHttpClientResponseBytes(
HttpClientResponse response, {
bool autoUncompress = true,
BytesReceivedCallback onBytesReceived,
}) async {
final TransferableTypedData bytes = await getHttpClientResponseBytes(
response,
autoUncompress: autoUncompress,
onBytesReceived: onBytesReceived,
);
return bytes.materialize().asUint8List();
}
class _OutputBuffer extends ByteConversionSinkBase { class _OutputBuffer extends ByteConversionSinkBase {
final List<Uint8List> chunks = <Uint8List>[]; List<List<int>> _chunks = <List<int>>[];
int _contentLength = 0;
Uint8List _bytes;
@override @override
void add(List<int> chunk) { void add(List<int> chunk) {
chunks.add(chunk); assert(_bytes == null);
_chunks.add(chunk);
_contentLength += chunk.length;
} }
@override @override
void close() {} void close() {
if (_bytes != null) {
// We've already been closed; this is a no-op
return;
}
_bytes = Uint8List(_contentLength);
int offset = 0;
for (List<int> chunk in _chunks) {
_bytes.setRange(offset, offset + chunk.length, chunk);
offset += chunk.length;
}
_chunks = null;
}
Uint8List get bytes {
assert(_bytes != null);
return _bytes;
}
} }
...@@ -5,7 +5,6 @@ ...@@ -5,7 +5,6 @@
import 'dart:async'; import 'dart:async';
import 'dart:convert'; import 'dart:convert';
import 'dart:io'; import 'dart:io';
import 'dart:isolate';
import 'dart:typed_data'; import 'dart:typed_data';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
...@@ -121,8 +120,8 @@ class NetworkAssetBundle extends AssetBundle { ...@@ -121,8 +120,8 @@ class NetworkAssetBundle extends AssetBundle {
'Unable to load asset: $key\n' 'Unable to load asset: $key\n'
'HTTP status code: ${response.statusCode}' 'HTTP status code: ${response.statusCode}'
); );
final TransferableTypedData transferable = await getHttpClientResponseBytes(response); final Uint8List bytes = await consolidateHttpClientResponseBytes(response);
return transferable.materialize().asByteData(); return bytes.buffer.asByteData();
} }
/// Retrieve a string from the asset bundle, parse it with the given function, /// Retrieve a string from the asset bundle, parse it with the given function,
......
...@@ -6,7 +6,6 @@ ...@@ -6,7 +6,6 @@
import 'dart:async'; import 'dart:async';
import 'dart:io'; import 'dart:io';
import 'dart:isolate';
import 'dart:typed_data'; import 'dart:typed_data';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
...@@ -15,7 +14,7 @@ import 'package:mockito/mockito.dart'; ...@@ -15,7 +14,7 @@ import 'package:mockito/mockito.dart';
import '../flutter_test_alternative.dart'; import '../flutter_test_alternative.dart';
void main() { void main() {
group(getHttpClientResponseBytes, () { group(consolidateHttpClientResponseBytes, () {
final Uint8List chunkOne = Uint8List.fromList(<int>[0, 1, 2, 3, 4, 5]); final Uint8List chunkOne = Uint8List.fromList(<int>[0, 1, 2, 3, 4, 5]);
final Uint8List chunkTwo = Uint8List.fromList(<int>[6, 7, 8, 9, 10]); final Uint8List chunkTwo = Uint8List.fromList(<int>[6, 7, 8, 9, 10]);
MockHttpClientResponse response; MockHttpClientResponse response;
...@@ -47,24 +46,24 @@ void main() { ...@@ -47,24 +46,24 @@ void main() {
test('Converts an HttpClientResponse with contentLength to bytes', () async { test('Converts an HttpClientResponse with contentLength to bytes', () async {
when(response.contentLength) when(response.contentLength)
.thenReturn(chunkOne.length + chunkTwo.length); .thenReturn(chunkOne.length + chunkTwo.length);
final List<int> bytes = (await getHttpClientResponseBytes(response)) final List<int> bytes =
.materialize().asUint8List(); 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 a compressed HttpClientResponse with contentLength to bytes', () async { test('Converts a compressed HttpClientResponse with contentLength to bytes', () async {
when(response.contentLength).thenReturn(chunkOne.length); when(response.contentLength).thenReturn(chunkOne.length);
final List<int> bytes = (await getHttpClientResponseBytes(response)) final List<int> bytes =
.materialize().asUint8List(); 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 an HttpClientResponse without contentLength to bytes', () async {
when(response.contentLength).thenReturn(-1); when(response.contentLength).thenReturn(-1);
final List<int> bytes = (await getHttpClientResponseBytes(response)) final List<int> bytes =
.materialize().asUint8List(); 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]);
}); });
...@@ -73,7 +72,7 @@ void main() { ...@@ -73,7 +72,7 @@ void main() {
final int syntheticTotal = (chunkOne.length + chunkTwo.length) * 2; final int syntheticTotal = (chunkOne.length + chunkTwo.length) * 2;
when(response.contentLength).thenReturn(syntheticTotal); when(response.contentLength).thenReturn(syntheticTotal);
final List<int> records = <int>[]; final List<int> records = <int>[];
await getHttpClientResponseBytes( await consolidateHttpClientResponseBytes(
response, response,
onBytesReceived: (int cumulative, int total) { onBytesReceived: (int cumulative, int total) {
records.addAll(<int>[cumulative, total]); records.addAll(<int>[cumulative, total]);
...@@ -111,13 +110,13 @@ void main() { ...@@ -111,13 +110,13 @@ void main() {
}); });
when(response.contentLength).thenReturn(-1); when(response.contentLength).thenReturn(-1);
expect(getHttpClientResponseBytes(response), expect(consolidateHttpClientResponseBytes(response),
throwsA(isInstanceOf<Exception>())); throwsA(isInstanceOf<Exception>()));
}); });
test('Propagates error to Future return value if onBytesReceived throws', () async { test('Propagates error to Future return value if onBytesReceived throws', () async {
when(response.contentLength).thenReturn(-1); when(response.contentLength).thenReturn(-1);
final Future<TransferableTypedData> result = getHttpClientResponseBytes( final Future<List<int>> result = consolidateHttpClientResponseBytes(
response, response,
onBytesReceived: (int cumulative, int total) { onBytesReceived: (int cumulative, int total) {
throw 'misbehaving callback'; throw 'misbehaving callback';
...@@ -158,14 +157,14 @@ void main() { ...@@ -158,14 +157,14 @@ void main() {
test('Uncompresses GZIP bytes if autoUncompress is true and response.compressionState is compressed', () async { test('Uncompresses GZIP bytes if autoUncompress is true and response.compressionState is compressed', () async {
when(response.compressionState).thenReturn(HttpClientResponseCompressionState.compressed); when(response.compressionState).thenReturn(HttpClientResponseCompressionState.compressed);
when(response.contentLength).thenReturn(gzipped.length); when(response.contentLength).thenReturn(gzipped.length);
final List<int> bytes = (await getHttpClientResponseBytes(response)).materialize().asUint8List(); 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('returns gzipped bytes if autoUncompress is false and response.compressionState is compressed', () async { test('returns gzipped bytes if autoUncompress is false and response.compressionState is compressed', () async {
when(response.compressionState).thenReturn(HttpClientResponseCompressionState.compressed); when(response.compressionState).thenReturn(HttpClientResponseCompressionState.compressed);
when(response.contentLength).thenReturn(gzipped.length); when(response.contentLength).thenReturn(gzipped.length);
final List<int> bytes = (await getHttpClientResponseBytes(response, autoUncompress: false)).materialize().asUint8List(); final List<int> bytes = await consolidateHttpClientResponseBytes(response, autoUncompress: false);
expect(bytes, gzipped); expect(bytes, gzipped);
}); });
...@@ -173,7 +172,7 @@ void main() { ...@@ -173,7 +172,7 @@ void main() {
when(response.compressionState).thenReturn(HttpClientResponseCompressionState.compressed); when(response.compressionState).thenReturn(HttpClientResponseCompressionState.compressed);
when(response.contentLength).thenReturn(gzipped.length); when(response.contentLength).thenReturn(gzipped.length);
final List<int> records = <int>[]; final List<int> records = <int>[];
await getHttpClientResponseBytes( await consolidateHttpClientResponseBytes(
response, response,
onBytesReceived: (int cumulative, int total) { onBytesReceived: (int cumulative, int total) {
records.addAll(<int>[cumulative, total]); records.addAll(<int>[cumulative, total]);
...@@ -193,7 +192,7 @@ void main() { ...@@ -193,7 +192,7 @@ void main() {
when(response.compressionState).thenReturn(HttpClientResponseCompressionState.decompressed); when(response.compressionState).thenReturn(HttpClientResponseCompressionState.decompressed);
when(response.contentLength).thenReturn(syntheticTotal); when(response.contentLength).thenReturn(syntheticTotal);
final List<int> records = <int>[]; final List<int> records = <int>[];
await getHttpClientResponseBytes( await consolidateHttpClientResponseBytes(
response, response,
onBytesReceived: (int cumulative, int total) { onBytesReceived: (int cumulative, int total) {
records.addAll(<int>[cumulative, total]); records.addAll(<int>[cumulative, total]);
......
// 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 'dart:async';
import 'dart:io';
import 'package:flutter/widgets.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/mockito.dart';
import '../painting/image_data.dart';
void main() {
final MockHttpClient client = MockHttpClient();
final MockHttpClientRequest request = MockHttpClientRequest();
final MockHttpClientResponse response = MockHttpClientResponse();
final MockHttpHeaders headers = MockHttpHeaders();
testWidgets('Headers', (WidgetTester tester) async {
HttpOverrides.runZoned<Future<void>>(() async {
await tester.pumpWidget(Image.network(
'https://www.example.com/images/frame.png',
headers: const <String, String>{'flutter': 'flutter'},
));
verify(headers.add('flutter', 'flutter')).called(1);
}, createHttpClient: (SecurityContext _) {
when(client.getUrl(any)).thenAnswer((_) => Future<HttpClientRequest>.value(request));
when(request.headers).thenReturn(headers);
when(request.close()).thenAnswer((_) => Future<HttpClientResponse>.value(response));
when(response.contentLength).thenReturn(kTransparentImage.length);
when(response.statusCode).thenReturn(HttpStatus.ok);
when(response.listen(any)).thenAnswer((Invocation invocation) {
final void Function(List<int>) onData = invocation.positionalArguments[0];
final void Function() onDone = invocation.namedArguments[#onDone];
final void Function(Object, [ StackTrace ]) onError = invocation.namedArguments[#onError];
final bool cancelOnError = invocation.namedArguments[#cancelOnError];
return Stream<List<int>>.fromIterable(<List<int>>[kTransparentImage]).listen(onData, onDone: onDone, onError: onError, cancelOnError: cancelOnError);
});
return client;
});
}, skip: isBrowser);
}
class MockHttpClient extends Mock implements HttpClient {}
class MockHttpClientRequest extends Mock implements HttpClientRequest {}
class MockHttpClientResponse extends Mock implements HttpClientResponse {}
class MockHttpHeaders extends Mock implements HttpHeaders {}
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