Chromium Code Reviews| 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 library multipart_request; | 5 library multipart_request; |
| 6 | 6 |
| 7 import 'dart:async'; | 7 import 'dart:async'; |
| 8 import 'dart:io'; | |
| 9 import 'dart:math'; | 8 import 'dart:math'; |
| 10 import 'dart:utf'; | 9 import 'dart:utf'; |
| 11 | 10 |
| 12 import 'base_request.dart'; | 11 import 'base_request.dart'; |
| 13 import 'byte_stream.dart'; | 12 import 'byte_stream.dart'; |
| 14 import 'multipart_file.dart'; | 13 import 'multipart_file.dart'; |
| 15 import 'utils.dart'; | 14 import 'utils.dart'; |
| 16 | 15 |
| 17 /// 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], |
| 18 /// which function as normal form fields, and (potentially streamed) binary | 17 /// which function as normal form fields, and (potentially streamed) binary |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 29 /// 'package', | 28 /// 'package', |
| 30 /// new File('build/package.tar.gz'), | 29 /// new File('build/package.tar.gz'), |
| 31 /// contentType: new ContentType('application', 'x-tar')); | 30 /// contentType: new ContentType('application', 'x-tar')); |
| 32 /// request.send().then((response) { | 31 /// request.send().then((response) { |
| 33 /// if (response.statusCode == 200) print("Uploaded!"); | 32 /// if (response.statusCode == 200) print("Uploaded!"); |
| 34 /// }); | 33 /// }); |
| 35 class MultipartRequest extends BaseRequest { | 34 class MultipartRequest extends BaseRequest { |
| 36 /// The total length of the multipart boundaries used when building the | 35 /// The total length of the multipart boundaries used when building the |
| 37 /// request body. According to http://tools.ietf.org/html/rfc1341.html, this | 36 /// request body. According to http://tools.ietf.org/html/rfc1341.html, this |
| 38 /// can't be longer than 70. | 37 /// can't be longer than 70. |
| 39 static final int _BOUNDARY_LENGTH = 70; | 38 static const int _BOUNDARY_LENGTH = 70; |
| 40 | 39 |
| 41 static final Random _random = new Random(); | 40 static final Random _random = new Random(); |
| 42 | 41 |
| 43 /// The form fields to send for this request. | 42 /// The form fields to send for this request. |
| 44 final Map<String, String> fields; | 43 final Map<String, String> fields; |
| 45 | 44 |
| 46 /// The private version of [files]. | 45 /// The private version of [files]. |
| 47 final List<MultipartFile> _files; | 46 final List<MultipartFile> _files; |
| 48 | 47 |
| 49 /// Creates a new [MultipartRequest]. | 48 /// Creates a new [MultipartRequest]. |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 68 | 67 |
| 69 for (var file in _files) { | 68 for (var file in _files) { |
| 70 length += "--".length + _BOUNDARY_LENGTH + "\r\n".length + | 69 length += "--".length + _BOUNDARY_LENGTH + "\r\n".length + |
| 71 _headerForFile(file).length + | 70 _headerForFile(file).length + |
| 72 file.length + "\r\n".length; | 71 file.length + "\r\n".length; |
| 73 } | 72 } |
| 74 | 73 |
| 75 return length + "--".length + _BOUNDARY_LENGTH + "--\r\n".length; | 74 return length + "--".length + _BOUNDARY_LENGTH + "--\r\n".length; |
| 76 } | 75 } |
| 77 | 76 |
| 78 set contentLength(int value) { | |
| 79 throw new UnsupportedError("Cannot set the contentLength property of " | |
| 80 "multipart requests."); | |
| 81 } | |
|
nweiz
2013/07/23 20:18:49
Why is this being removed? It shouldn't be possibl
kevmoo-old
2013/07/23 21:08:56
Didn't read the type hierarchy correctly. Oops.
| |
| 82 | |
| 83 /// Freezes all mutable fields and returns a single-subscription [ByteStream] | 77 /// Freezes all mutable fields and returns a single-subscription [ByteStream] |
| 84 /// that will emit the request body. | 78 /// that will emit the request body. |
| 85 ByteStream finalize() { | 79 ByteStream finalize() { |
| 86 // TODO(nweiz): freeze fields and files | 80 // TODO(nweiz): freeze fields and files |
| 87 var boundary = _boundaryString(_BOUNDARY_LENGTH); | 81 var boundary = _boundaryString(_BOUNDARY_LENGTH); |
| 88 headers['content-type'] = 'multipart/form-data; boundary="$boundary"'; | 82 headers['content-type'] = 'multipart/form-data; boundary="$boundary"'; |
| 89 headers['content-transfer-encoding'] = 'binary'; | 83 headers['content-transfer-encoding'] = 'binary'; |
| 90 super.finalize(); | 84 super.finalize(); |
| 91 | 85 |
| 92 var controller = new StreamController<List<int>>(sync: true); | 86 var controller = new StreamController<List<int>>(sync: true); |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 116 // the stream. See issue 3657. | 110 // the stream. See issue 3657. |
| 117 writeAscii('--$boundary--\r\n'); | 111 writeAscii('--$boundary--\r\n'); |
| 118 controller.close(); | 112 controller.close(); |
| 119 }); | 113 }); |
| 120 | 114 |
| 121 return new ByteStream(controller.stream); | 115 return new ByteStream(controller.stream); |
| 122 } | 116 } |
| 123 | 117 |
| 124 /// All character codes that are valid in multipart boundaries. From | 118 /// All character codes that are valid in multipart boundaries. From |
| 125 /// http://tools.ietf.org/html/rfc2046#section-5.1.1. | 119 /// http://tools.ietf.org/html/rfc2046#section-5.1.1. |
| 126 static final List<int> _BOUNDARY_CHARACTERS = const <int>[ | 120 static const List<int> _BOUNDARY_CHARACTERS = const <int>[ |
| 127 39, 40, 41, 43, 95, 44, 45, 46, 47, 58, 61, 63, 48, 49, 50, 51, 52, 53, 54, | 121 39, 40, 41, 43, 95, 44, 45, 46, 47, 58, 61, 63, 48, 49, 50, 51, 52, 53, 54, |
| 128 55, 56, 57, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, | 122 55, 56, 57, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, |
| 129 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 97, 98, 99, 100, 101, 102, 103, | 123 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 97, 98, 99, 100, 101, 102, 103, |
| 130 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, | 124 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, |
| 131 119, 120, 121, 122 | 125 119, 120, 121, 122 |
| 132 ]; | 126 ]; |
| 133 | 127 |
| 134 /// Returns the header string for a field. The return value is guaranteed to | 128 /// Returns the header string for a field. The return value is guaranteed to |
| 135 /// contain only ASCII characters. | 129 /// contain only ASCII characters. |
| 136 String _headerForField(String name, String value) { | 130 static String _headerForField(String name, String value) { |
|
nweiz
2013/07/23 20:18:49
I'm not a fan of making methods static just becaus
kevmoo-old
2013/07/23 21:08:56
I think it correctly communicates it *could* be ac
nweiz
2013/07/23 21:27:34
It's an implementation detail that it doesn't acce
kevmoo-old
2013/07/23 21:36:37
I'm cool w/ philosophical differences here. Not a
| |
| 137 // http://tools.ietf.org/html/rfc2388 mandates some complex encodings for | 131 // http://tools.ietf.org/html/rfc2388 mandates some complex encodings for |
| 138 // field names and file names, but in practice user agents seem to just | 132 // field names and file names, but in practice user agents seem to just |
| 139 // URL-encode them so we do the same. | 133 // URL-encode them so we do the same. |
| 140 var header = | 134 var header = |
| 141 'content-disposition: form-data; name="${Uri.encodeFull(name)}"'; | 135 'content-disposition: form-data; name="${Uri.encodeFull(name)}"'; |
| 142 if (!isPlainAscii(value)) { | 136 if (!isPlainAscii(value)) { |
| 143 header = '$header\r\ncontent-type: text/plain; charset=utf-8'; | 137 header = '$header\r\ncontent-type: text/plain; charset=utf-8'; |
| 144 } | 138 } |
| 145 return '$header\r\n\r\n'; | 139 return '$header\r\n\r\n'; |
| 146 } | 140 } |
| 147 | 141 |
| 148 /// Returns the header string for a file. The return value is guaranteed to | 142 /// Returns the header string for a file. The return value is guaranteed to |
| 149 /// contain only ASCII characters. | 143 /// contain only ASCII characters. |
| 150 String _headerForFile(MultipartFile file) { | 144 static String _headerForFile(MultipartFile file) { |
| 151 var header = 'content-type: ${file.contentType}\r\n' | 145 var header = 'content-type: ${file.contentType}\r\n' |
| 152 'content-disposition: form-data; name="${Uri.encodeFull(file.field)}"'; | 146 'content-disposition: form-data; name="${Uri.encodeFull(file.field)}"'; |
| 153 | 147 |
| 154 if (file.filename != null) { | 148 if (file.filename != null) { |
| 155 header = '$header; filename="${Uri.encodeFull(file.filename)}"'; | 149 header = '$header; filename="${Uri.encodeFull(file.filename)}"'; |
| 156 } | 150 } |
| 157 return '$header\r\n\r\n'; | 151 return '$header\r\n\r\n'; |
| 158 } | 152 } |
| 159 | 153 |
| 160 /// Returns a randomly-generated multipart boundary string of the given | 154 /// Returns a randomly-generated multipart boundary string of the given |
| 161 /// [length]. | 155 /// [length]. |
| 162 String _boundaryString(int length) { | 156 static String _boundaryString(int length) { |
| 163 var prefix = "dart-http-boundary-"; | 157 const prefix = "dart-http-boundary-"; |
|
nweiz
2013/07/23 20:18:49
Also not a fan of const local variables, for rough
kevmoo-old
2013/07/23 21:08:56
Fair.
| |
| 164 var list = new List<int>(length - prefix.length); | 158 var list = new List<int>(length - prefix.length); |
| 165 for (var i = 0; i < list.length; i++) { | 159 for (var i = 0; i < list.length; i++) { |
| 166 list[i] = _BOUNDARY_CHARACTERS[ | 160 list[i] = _BOUNDARY_CHARACTERS[ |
| 167 _random.nextInt(_BOUNDARY_CHARACTERS.length)]; | 161 _random.nextInt(_BOUNDARY_CHARACTERS.length)]; |
| 168 } | 162 } |
| 169 return "$prefix${new String.fromCharCodes(list)}"; | 163 return "$prefix${new String.fromCharCodes(list)}"; |
| 170 } | 164 } |
| 171 } | 165 } |
| OLD | NEW |