Skip to content

Commit 9a17157

Browse files
authored
Refactor to async/await (#328)
Use an `async*` for `MultipartRequest.finalize()`. Refactor `.then` chains to async methods. Add test for error forwarding in multipart request. This relates to a TODO that had been solved but had not been removed.
1 parent 2a22f2b commit 9a17157

File tree

5 files changed

+69
-77
lines changed

5 files changed

+69
-77
lines changed

lib/src/base_client.dart

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -121,11 +121,10 @@ abstract class BaseClient implements Client {
121121
/// For more fine-grained control over the request and response, use [send] or
122122
/// [get] instead.
123123
@override
124-
Future<String> read(url, {Map<String, String> headers}) {
125-
return get(url, headers: headers).then((response) {
126-
_checkResponseSuccess(url, response);
127-
return response.body;
128-
});
124+
Future<String> read(url, {Map<String, String> headers}) async {
125+
final response = await get(url, headers: headers);
126+
_checkResponseSuccess(url, response);
127+
return response.body;
129128
}
130129

131130
/// Sends an HTTP GET request with the given headers to the given URL, which
@@ -138,11 +137,10 @@ abstract class BaseClient implements Client {
138137
/// For more fine-grained control over the request and response, use [send] or
139138
/// [get] instead.
140139
@override
141-
Future<Uint8List> readBytes(url, {Map<String, String> headers}) {
142-
return get(url, headers: headers).then((response) {
143-
_checkResponseSuccess(url, response);
144-
return response.bodyBytes;
145-
});
140+
Future<Uint8List> readBytes(url, {Map<String, String> headers}) async {
141+
final response = await get(url, headers: headers);
142+
_checkResponseSuccess(url, response);
143+
return response.bodyBytes;
146144
}
147145

148146
/// Sends an HTTP request and asynchronously returns the response.

lib/src/mock_client.dart

Lines changed: 27 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -30,42 +30,39 @@ class MockClient extends BaseClient {
3030
/// Creates a [MockClient] with a handler that receives [Request]s and sends
3131
/// [Response]s.
3232
MockClient(MockClientHandler fn)
33-
: this._((baseRequest, bodyStream) {
34-
return bodyStream.toBytes().then((bodyBytes) {
35-
var request = Request(baseRequest.method, baseRequest.url)
36-
..persistentConnection = baseRequest.persistentConnection
37-
..followRedirects = baseRequest.followRedirects
38-
..maxRedirects = baseRequest.maxRedirects
39-
..headers.addAll(baseRequest.headers)
40-
..bodyBytes = bodyBytes
41-
..finalize();
33+
: this._((baseRequest, bodyStream) async {
34+
final bodyBytes = await bodyStream.toBytes();
35+
var request = Request(baseRequest.method, baseRequest.url)
36+
..persistentConnection = baseRequest.persistentConnection
37+
..followRedirects = baseRequest.followRedirects
38+
..maxRedirects = baseRequest.maxRedirects
39+
..headers.addAll(baseRequest.headers)
40+
..bodyBytes = bodyBytes
41+
..finalize();
4242

43-
return fn(request);
44-
}).then((response) {
45-
return StreamedResponse(
46-
ByteStream.fromBytes(response.bodyBytes), response.statusCode,
47-
contentLength: response.contentLength,
48-
request: baseRequest,
49-
headers: response.headers,
50-
isRedirect: response.isRedirect,
51-
persistentConnection: response.persistentConnection,
52-
reasonPhrase: response.reasonPhrase);
53-
});
43+
final response = await fn(request);
44+
return StreamedResponse(
45+
ByteStream.fromBytes(response.bodyBytes), response.statusCode,
46+
contentLength: response.contentLength,
47+
request: baseRequest,
48+
headers: response.headers,
49+
isRedirect: response.isRedirect,
50+
persistentConnection: response.persistentConnection,
51+
reasonPhrase: response.reasonPhrase);
5452
});
5553

5654
/// Creates a [MockClient] with a handler that receives [StreamedRequest]s and
5755
/// sends [StreamedResponse]s.
5856
MockClient.streaming(MockClientStreamHandler fn)
59-
: this._((request, bodyStream) {
60-
return fn(request, bodyStream).then((response) {
61-
return StreamedResponse(response.stream, response.statusCode,
62-
contentLength: response.contentLength,
63-
request: request,
64-
headers: response.headers,
65-
isRedirect: response.isRedirect,
66-
persistentConnection: response.persistentConnection,
67-
reasonPhrase: response.reasonPhrase);
68-
});
57+
: this._((request, bodyStream) async {
58+
final response = await fn(request, bodyStream);
59+
return StreamedResponse(response.stream, response.statusCode,
60+
contentLength: response.contentLength,
61+
request: request,
62+
headers: response.headers,
63+
isRedirect: response.isRedirect,
64+
persistentConnection: response.persistentConnection,
65+
reasonPhrase: response.reasonPhrase);
6966
});
7067

7168
@override

lib/src/multipart_request.dart

Lines changed: 19 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -87,40 +87,31 @@ class MultipartRequest extends BaseRequest {
8787
/// Freezes all mutable fields and returns a single-subscription [ByteStream]
8888
/// that will emit the request body.
8989
@override
90-
ByteStream finalize() {
90+
ByteStream finalize() => ByteStream(_finalize());
91+
92+
Stream<List<int>> _finalize() async* {
9193
// TODO(nweiz): freeze fields and files
9294
var boundary = _boundaryString();
9395
headers['content-type'] = 'multipart/form-data; boundary=$boundary';
9496
super.finalize();
95-
96-
var controller = StreamController<List<int>>(sync: true);
97-
98-
void writeAscii(String string) {
99-
controller.add(utf8.encode(string));
97+
const line = [13, 10]; // \r\n
98+
final separator = utf8.encode('--$boundary\r\n');
99+
final close = utf8.encode('--$boundary--\r\n');
100+
101+
for (var field in fields.entries) {
102+
yield separator;
103+
yield utf8.encode(_headerForField(field.key, field.value));
104+
yield utf8.encode(field.value);
105+
yield line;
100106
}
101107

102-
writeUtf8(String string) => controller.add(utf8.encode(string));
103-
writeLine() => controller.add([13, 10]); // \r\n
104-
105-
fields.forEach((name, value) {
106-
writeAscii('--$boundary\r\n');
107-
writeAscii(_headerForField(name, value));
108-
writeUtf8(value);
109-
writeLine();
110-
});
111-
112-
Future.forEach(_files, (MultipartFile file) {
113-
writeAscii('--$boundary\r\n');
114-
writeAscii(_headerForFile(file));
115-
return controller.addStream(file.finalize()).then((_) => writeLine());
116-
}).then((_) {
117-
// TODO(nweiz): pass any errors propagated through this future on to
118-
// the stream. See issue 3657.
119-
writeAscii('--$boundary--\r\n');
120-
controller.close();
121-
});
122-
123-
return ByteStream(controller.stream);
108+
for (final file in _files) {
109+
yield separator;
110+
yield utf8.encode(_headerForFile(file));
111+
yield* file.finalize();
112+
yield line;
113+
}
114+
yield close;
124115
}
125116

126117
/// Returns the header string for a field.

lib/src/response.dart

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -60,15 +60,14 @@ class Response extends BaseResponse {
6060

6161
/// Creates a new HTTP response by waiting for the full body to become
6262
/// available from a [StreamedResponse].
63-
static Future<Response> fromStream(StreamedResponse response) {
64-
return response.stream.toBytes().then((body) {
65-
return Response.bytes(body, response.statusCode,
66-
request: response.request,
67-
headers: response.headers,
68-
isRedirect: response.isRedirect,
69-
persistentConnection: response.persistentConnection,
70-
reasonPhrase: response.reasonPhrase);
71-
});
63+
static Future<Response> fromStream(StreamedResponse response) async {
64+
final body = await response.stream.toBytes();
65+
return Response.bytes(body, response.statusCode,
66+
request: response.request,
67+
headers: response.headers,
68+
isRedirect: response.isRedirect,
69+
persistentConnection: response.persistentConnection,
70+
reasonPhrase: response.reasonPhrase);
7271
}
7372
}
7473

test/multipart_test.dart

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,4 +239,11 @@ void main() {
239239
--{{boundary}}--
240240
'''));
241241
});
242+
243+
test('with a file that has an error', () async {
244+
var file = http.MultipartFile(
245+
'file', Future<List<int>>.error('error').asStream(), 1);
246+
var request = http.MultipartRequest('POST', dummyUrl)..files.add(file);
247+
expect(request.finalize().drain(), throwsA('error'));
248+
});
242249
}

0 commit comments

Comments
 (0)