OLD | NEW |
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 import 'dart:async'; | 5 import 'dart:async'; |
6 import 'dart:convert'; | 6 import 'dart:convert'; |
7 import 'dart:math'; | 7 import 'dart:math'; |
8 | 8 |
9 import 'base_request.dart'; | 9 import 'base_request.dart'; |
10 import 'byte_stream.dart'; | 10 import 'byte_stream.dart'; |
11 import 'multipart_file.dart'; | 11 import 'multipart_file.dart'; |
12 import 'utils.dart'; | 12 import 'utils.dart'; |
13 | 13 |
14 final _newlineRegExp = new RegExp(r"\r\n|\r|\n"); | 14 final _newlineRegExp = new RegExp(r"\r\n|\r|\n"); |
15 | 15 |
16 /// A `multipart/form-data` request. Such a request has both string [fields], | 16 /// A `multipart/form-data` request. Such a request has both string [fields], |
17 /// which function as normal form fields, and (potentially streamed) binary | 17 /// which function as normal form fields, and (potentially streamed) binary |
18 /// [files]. | 18 /// [files]. |
19 /// | 19 /// |
20 /// This request automatically sets the Content-Type header to | 20 /// This request automatically sets the Content-Type header to |
21 /// `multipart/form-data` and the Content-Transfer-Encoding header to `binary`. | 21 /// `multipart/form-data`. This value will override any value set by the user. |
22 /// These values will override any values set by the user. | |
23 /// | 22 /// |
24 /// var uri = Uri.parse("http://pub.dartlang.org/packages/create"); | 23 /// var uri = Uri.parse("http://pub.dartlang.org/packages/create"); |
25 /// var request = new http.MultipartRequest("POST", url); | 24 /// var request = new http.MultipartRequest("POST", url); |
26 /// request.fields['user'] = 'nweiz@google.com'; | 25 /// request.fields['user'] = 'nweiz@google.com'; |
27 /// request.files.add(new http.MultipartFile.fromFile( | 26 /// request.files.add(new http.MultipartFile.fromFile( |
28 /// 'package', | 27 /// 'package', |
29 /// new File('build/package.tar.gz'), | 28 /// new File('build/package.tar.gz'), |
30 /// contentType: new MediaType('application', 'x-tar')); | 29 /// contentType: new MediaType('application', 'x-tar')); |
31 /// request.send().then((response) { | 30 /// request.send().then((response) { |
32 /// if (response.statusCode == 200) print("Uploaded!"); | 31 /// if (response.statusCode == 200) print("Uploaded!"); |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
78 throw new UnsupportedError("Cannot set the contentLength property of " | 77 throw new UnsupportedError("Cannot set the contentLength property of " |
79 "multipart requests."); | 78 "multipart requests."); |
80 } | 79 } |
81 | 80 |
82 /// Freezes all mutable fields and returns a single-subscription [ByteStream] | 81 /// Freezes all mutable fields and returns a single-subscription [ByteStream] |
83 /// that will emit the request body. | 82 /// that will emit the request body. |
84 ByteStream finalize() { | 83 ByteStream finalize() { |
85 // TODO(nweiz): freeze fields and files | 84 // TODO(nweiz): freeze fields and files |
86 var boundary = _boundaryString(); | 85 var boundary = _boundaryString(); |
87 headers['content-type'] = 'multipart/form-data; boundary="$boundary"'; | 86 headers['content-type'] = 'multipart/form-data; boundary="$boundary"'; |
88 headers['content-transfer-encoding'] = 'binary'; | |
89 super.finalize(); | 87 super.finalize(); |
90 | 88 |
91 var controller = new StreamController<List<int>>(sync: true); | 89 var controller = new StreamController<List<int>>(sync: true); |
92 | 90 |
93 void writeAscii(String string) { | 91 void writeAscii(String string) { |
94 controller.add(UTF8.encode(string)); | 92 controller.add(UTF8.encode(string)); |
95 } | 93 } |
96 | 94 |
97 writeUtf8(String string) => controller.add(UTF8.encode(string)); | 95 writeUtf8(String string) => controller.add(UTF8.encode(string)); |
98 writeLine() => controller.add([13, 10]); // \r\n | 96 writeLine() => controller.add([13, 10]); // \r\n |
(...skipping 29 matching lines...) Expand all Loading... |
128 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, | 126 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, |
129 119, 120, 121, 122 | 127 119, 120, 121, 122 |
130 ]; | 128 ]; |
131 | 129 |
132 /// Returns the header string for a field. The return value is guaranteed to | 130 /// Returns the header string for a field. The return value is guaranteed to |
133 /// contain only ASCII characters. | 131 /// contain only ASCII characters. |
134 String _headerForField(String name, String value) { | 132 String _headerForField(String name, String value) { |
135 var header = | 133 var header = |
136 'content-disposition: form-data; name="${_browserEncode(name)}"'; | 134 'content-disposition: form-data; name="${_browserEncode(name)}"'; |
137 if (!isPlainAscii(value)) { | 135 if (!isPlainAscii(value)) { |
138 header = '$header\r\ncontent-type: text/plain; charset=utf-8'; | 136 header = '$header\r\n' |
| 137 'content-type: text/plain; charset=utf-8\r\n' |
| 138 'content-transfer-encoding: binary\r\n'; |
139 } | 139 } |
140 return '$header\r\n\r\n'; | 140 return '$header\r\n\r\n'; |
141 } | 141 } |
142 | 142 |
143 /// Returns the header string for a file. The return value is guaranteed to | 143 /// Returns the header string for a file. The return value is guaranteed to |
144 /// contain only ASCII characters. | 144 /// contain only ASCII characters. |
145 String _headerForFile(MultipartFile file) { | 145 String _headerForFile(MultipartFile file) { |
146 var header = 'content-type: ${file.contentType}\r\n' | 146 var header = 'content-type: ${file.contentType}\r\n' |
147 'content-disposition: form-data; name="${_browserEncode(file.field)}"'; | 147 'content-disposition: form-data; name="${_browserEncode(file.field)}"'; |
148 | 148 |
(...skipping 16 matching lines...) Expand all Loading... |
165 /// Returns a randomly-generated multipart boundary string | 165 /// Returns a randomly-generated multipart boundary string |
166 String _boundaryString() { | 166 String _boundaryString() { |
167 var prefix = "dart-http-boundary-"; | 167 var prefix = "dart-http-boundary-"; |
168 var list = new List<int>.generate(_BOUNDARY_LENGTH - prefix.length, | 168 var list = new List<int>.generate(_BOUNDARY_LENGTH - prefix.length, |
169 (index) => | 169 (index) => |
170 _BOUNDARY_CHARACTERS[_random.nextInt(_BOUNDARY_CHARACTERS.length)], | 170 _BOUNDARY_CHARACTERS[_random.nextInt(_BOUNDARY_CHARACTERS.length)], |
171 growable: false); | 171 growable: false); |
172 return "$prefix${new String.fromCharCodes(list)}"; | 172 return "$prefix${new String.fromCharCodes(list)}"; |
173 } | 173 } |
174 } | 174 } |
OLD | NEW |