Synchronously finalize headers (#359)

Fixes #351

An `async*` method is not started until after the stream has a listener,
if a caller reads the headers before listening to the stream, they would
see the value before they have been set. Move the header assignment and
other finalization work to the wrapping method and keep the `async*`
method handling only the stream content.
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 119227f..c87e445 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,6 @@
 ## 0.12.0+4-dev
 
-* Internal changes.
+* Fix a bug setting the `'content-type'` header in `MultipartRequest`.
 
 ## 0.12.0+3
 
diff --git a/lib/src/multipart_request.dart b/lib/src/multipart_request.dart
index 699c643..4d89c6c 100644
--- a/lib/src/multipart_request.dart
+++ b/lib/src/multipart_request.dart
@@ -85,13 +85,15 @@
   /// Freezes all mutable fields and returns a single-subscription [ByteStream]
   /// that will emit the request body.
   @override
-  ByteStream finalize() => ByteStream(_finalize());
-
-  Stream<List<int>> _finalize() async* {
-    // TODO(nweiz): freeze fields and files
-    var boundary = _boundaryString();
+  ByteStream finalize() {
+    // TODO: freeze fields and files
+    final boundary = _boundaryString();
     headers['content-type'] = 'multipart/form-data; boundary=$boundary';
     super.finalize();
+    return ByteStream(_finalize(boundary));
+  }
+
+  Stream<List<int>> _finalize(String boundary) async* {
     const line = [13, 10]; // \r\n
     final separator = utf8.encode('--$boundary\r\n');
     final close = utf8.encode('--$boundary--\r\n');
diff --git a/test/io/client_test.dart b/test/io/client_test.dart
index f8c83f7..25bbd6b 100644
--- a/test/io/client_test.dart
+++ b/test/io/client_test.dart
@@ -4,6 +4,7 @@
 
 @TestOn('vm')
 
+import 'dart:convert';
 import 'dart:io';
 
 import 'package:http/http.dart' as http;
@@ -106,4 +107,18 @@
     request.sink.add('{"hello": "world"}'.codeUnits);
     request.sink.close();
   });
+
+  test('sends a MultipartRequest with correct content-type header', () async {
+    var client = http.Client();
+    var request = http.MultipartRequest('POST', serverUrl);
+
+    var response = await client.send(request);
+
+    var bytesString = await response.stream.bytesToString();
+    client.close();
+
+    var headers = jsonDecode(bytesString)['headers'] as Map<String, dynamic>;
+    var contentType = (headers['content-type'] as List).single;
+    expect(contentType, startsWith('multipart/form-data; boundary='));
+  });
 }