@@ -7,7 +7,6 @@ import 'dart:convert';
7
7
8
8
import 'body.dart' ;
9
9
import 'multipart_file.dart' ;
10
- import 'utils.dart' ;
11
10
12
11
class MultipartBody implements Body {
13
12
/// The contents of the message body.
@@ -26,21 +25,25 @@ class MultipartBody implements Body {
26
25
/// Creates a [MultipartBody] from the given [fields] and [files] .
27
26
///
28
27
/// The [boundary] is used to
29
- factory MultipartBody (Map <String , String > fields,
30
- List <MultipartFile > files,
31
- String boundary,) {
28
+ factory MultipartBody (
29
+ Map <String , String > fields,
30
+ List <MultipartFile > files,
31
+ String boundary,
32
+ ) {
32
33
var controller = new StreamController <List <int >>(sync : true );
33
34
var contentLength = 0 ;
34
35
35
36
void writeAscii (String string) {
36
37
controller.add (string.codeUnits);
37
38
contentLength += string.length;
38
39
}
40
+
39
41
void writeUtf8 (String string) {
40
42
var encoded = UTF8 .encode (string);
41
43
controller.add (encoded);
42
44
contentLength += encoded.length;
43
45
}
46
+
44
47
void writeLine () {
45
48
controller.add ([13 , 10 ]); // \r\n
46
49
contentLength += 2 ;
@@ -81,8 +84,8 @@ class MultipartBody implements Body {
81
84
Future .forEach (files, (file) {
82
85
assert (files[i] == file);
83
86
controller.add (fileHeaders[i++ ]);
84
- return writeStreamToSink (file.read (), controller). then ((_) =>
85
- controller.add ([13 , 10 ]));
87
+ return _writeStreamToSink (file.read (), controller)
88
+ . then ((_) => controller.add ([13 , 10 ]));
86
89
}).then ((_) {
87
90
// TODO(nweiz): pass any errors propagated through this future on to
88
91
// the stream. See issue 3657.
@@ -112,7 +115,7 @@ class MultipartBody implements Body {
112
115
static String _headerForField (String name, String value) {
113
116
var header =
114
117
'content-disposition: form-data; name="${_browserEncode (name )}"' ;
115
- if (! isPlainAscii (value)) {
118
+ if (! _asciiOnly. hasMatch (value)) {
116
119
header = '$header \r\n '
117
120
'content-type: text/plain; charset=utf-8\r\n '
118
121
'content-transfer-encoding: binary' ;
@@ -133,7 +136,8 @@ class MultipartBody implements Body {
133
136
return '$header \r\n\r\n ' ;
134
137
}
135
138
136
- static final _newlineRegExp = new RegExp (r"\r\n|\r|\n" );
139
+ static final _newlineRegExp = new RegExp (r'\r\n|\r|\n' );
140
+ static final _asciiOnly = new RegExp (r'^[\x00-\x7F]+$' );
137
141
138
142
/// Encode [value] in the same way browsers do.
139
143
static String _browserEncode (String value) {
@@ -144,4 +148,14 @@ class MultipartBody implements Body {
144
148
// characters). We follow their behavior.
145
149
return value.replaceAll (_newlineRegExp, "%0D%0A" ).replaceAll ('"' , "%22" );
146
150
}
151
+
152
+ /// Pipes all data and errors from [stream] into [sink] . Completes [Future] once
153
+ /// [stream] is done. Unlike [store] , [sink] remains open after [stream] is
154
+ /// done.
155
+ static Future _writeStreamToSink (Stream stream, EventSink sink) {
156
+ var completer = new Completer ();
157
+ stream.listen (sink.add,
158
+ onError: sink.addError, onDone: () => completer.complete ());
159
+ return completer.future;
160
+ }
147
161
}
0 commit comments