@@ -13,6 +13,8 @@ import 'byte_stream.dart';
13
13
import 'multipart_file.dart' ;
14
14
import 'utils.dart' ;
15
15
16
+ final _newlineRegExp = new RegExp (r"\r\n|\r|\n" );
17
+
16
18
/// A `multipart/form-data` request. Such a request has both string [fields] ,
17
19
/// which function as normal form fields, and (potentially streamed) binary
18
20
/// [files] .
@@ -61,13 +63,13 @@ class MultipartRequest extends BaseRequest {
61
63
62
64
fields.forEach ((name, value) {
63
65
length += "--" .length + _BOUNDARY_LENGTH + "\r\n " .length +
64
- _headerForField (name, value).length +
66
+ UTF8 . encode ( _headerForField (name, value) ).length +
65
67
UTF8 .encode (value).length + "\r\n " .length;
66
68
});
67
69
68
70
for (var file in _files) {
69
71
length += "--" .length + _BOUNDARY_LENGTH + "\r\n " .length +
70
- _headerForFile (file).length +
72
+ UTF8 . encode ( _headerForFile (file) ).length +
71
73
file.length + "\r\n " .length;
72
74
}
73
75
@@ -91,8 +93,7 @@ class MultipartRequest extends BaseRequest {
91
93
var controller = new StreamController <List <int >>(sync : true );
92
94
93
95
void writeAscii (String string) {
94
- assert (isPlainAscii (string));
95
- controller.add (string.codeUnits);
96
+ controller.add (UTF8 .encode (string));
96
97
}
97
98
98
99
writeUtf8 (String string) => controller.add (UTF8 .encode (string));
@@ -133,11 +134,8 @@ class MultipartRequest extends BaseRequest {
133
134
/// Returns the header string for a field. The return value is guaranteed to
134
135
/// contain only ASCII characters.
135
136
String _headerForField (String name, String value) {
136
- // http://tools.ietf.org/html/rfc2388 mandates some complex encodings for
137
- // field names and file names, but in practice user agents seem to just
138
- // URL-encode them so we do the same.
139
137
var header =
140
- 'content-disposition: form-data; name="${Uri . encodeFull (name )}"' ;
138
+ 'content-disposition: form-data; name="${_browserEncode (name )}"' ;
141
139
if (! isPlainAscii (value)) {
142
140
header = '$header \r\n content-type: text/plain; charset=utf-8' ;
143
141
}
@@ -148,14 +146,24 @@ class MultipartRequest extends BaseRequest {
148
146
/// contain only ASCII characters.
149
147
String _headerForFile (MultipartFile file) {
150
148
var header = 'content-type: ${file .contentType }\r\n '
151
- 'content-disposition: form-data; name="${Uri . encodeFull (file .field )}"' ;
149
+ 'content-disposition: form-data; name="${_browserEncode (file .field )}"' ;
152
150
153
151
if (file.filename != null ) {
154
- header = '$header ; filename="${Uri . encodeFull (file .filename )}"' ;
152
+ header = '$header ; filename="${_browserEncode (file .filename )}"' ;
155
153
}
156
154
return '$header \r\n\r\n ' ;
157
155
}
158
156
157
+ /// Encode [value] in the same way browsers do.
158
+ String _browserEncode (String value) {
159
+ // http://tools.ietf.org/html/rfc2388 mandates some complex encodings for
160
+ // field names and file names, but in practice user agents seem not to
161
+ // follow this at all. Instead, they URL-encode `\r`, `\n`, and `\r\n` as
162
+ // `\r\n`; URL-encode `"`; and do nothing else (even for `%` or non-ASCII
163
+ // characters). We follow their behavior.
164
+ return value.replaceAll (_newlineRegExp, "%0D%0A" ).replaceAll ('"' , "%22" );
165
+ }
166
+
159
167
/// Returns a randomly-generated multipart boundary string
160
168
String _boundaryString () {
161
169
var prefix = "dart-http-boundary-" ;
0 commit comments