Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(107)

Side by Side Diff: pkg/http/lib/src/multipart_request.dart

Issue 11825010: Update pkg/http to use the new async APIs. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Code review changes Created 7 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « pkg/http/lib/src/multipart_file.dart ('k') | pkg/http/lib/src/request.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, 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'; 8 import 'dart:io';
9 import 'dart:math'; 9 import 'dart:math';
10 import 'dart:uri'; 10 import 'dart:uri';
11 import 'dart:utf'; 11 import 'dart:utf';
12 12
13 import 'base_request.dart'; 13 import 'base_request.dart';
14 import 'byte_stream.dart';
14 import 'multipart_file.dart'; 15 import 'multipart_file.dart';
15 import 'utils.dart'; 16 import 'utils.dart';
16 17
17 /// A `multipart/form-data` request. Such a request has both string [fields], 18 /// A `multipart/form-data` request. Such a request has both string [fields],
18 /// which function as normal form fields, and (potentially streamed) binary 19 /// which function as normal form fields, and (potentially streamed) binary
19 /// [files]. 20 /// [files].
20 /// 21 ///
21 /// This request automatically sets the Content-Type header to 22 /// This request automatically sets the Content-Type header to
22 /// `multipart/form-data` and the Content-Transfer-Encoding header to `binary`. 23 /// `multipart/form-data` and the Content-Transfer-Encoding header to `binary`.
23 /// These values will override any values set by the user. 24 /// These values will override any values set by the user.
(...skipping 20 matching lines...) Expand all
44 /// [fields] and [files] and cannot be set manually. 45 /// [fields] and [files] and cannot be set manually.
45 int get contentLength { 46 int get contentLength {
46 var length = 0; 47 var length = 0;
47 48
48 fields.forEach((name, value) { 49 fields.forEach((name, value) {
49 length += "--".length + _BOUNDARY_LENGTH + "\r\n".length + 50 length += "--".length + _BOUNDARY_LENGTH + "\r\n".length +
50 _headerForField(name, value).length + 51 _headerForField(name, value).length +
51 encodeUtf8(value).length + "\r\n".length; 52 encodeUtf8(value).length + "\r\n".length;
52 }); 53 });
53 54
54 for (var file in files) { 55 for (var file in _files.collection) {
55 length += "--".length + _BOUNDARY_LENGTH + "\r\n".length + 56 length += "--".length + _BOUNDARY_LENGTH + "\r\n".length +
56 _headerForFile(file).length + 57 _headerForFile(file).length +
57 file.length + "\r\n".length; 58 file.length + "\r\n".length;
58 } 59 }
59 60
60 return length + "--".length + _BOUNDARY_LENGTH + "--\r\n".length; 61 return length + "--".length + _BOUNDARY_LENGTH + "--\r\n".length;
61 } 62 }
62 63
63 set contentLength(int value) { 64 set contentLength(int value) {
64 throw new UnsupportedError("Cannot set the contentLength property of " 65 throw new UnsupportedError("Cannot set the contentLength property of "
65 "multipart requests."); 66 "multipart requests.");
66 } 67 }
67 68
68 /// The form fields to send for this request. 69 /// The form fields to send for this request.
69 final Map<String, String> fields; 70 final Map<String, String> fields;
70 71
71 /// The files to upload for this request. 72 /// The sink for files to upload for this request.
72 final List<MultipartFile> files; 73 ///
74 /// This doesn't need to be closed. When the request is sent, whichever files
75 /// are written to this sink at that point will be used.
76 Sink<MultipartFile> get files => _files;
77
78 /// The private version of [files], typed so that the underlying collection is
79 /// accessible.
80 final CollectionSink<MultipartFile> _files;
73 81
74 /// Creates a new [MultipartRequest]. 82 /// Creates a new [MultipartRequest].
75 MultipartRequest(String method, Uri url) 83 MultipartRequest(String method, Uri url)
76 : super(method, url), 84 : super(method, url),
77 fields = <String>{}, 85 fields = <String>{},
78 files = <MultipartFile>[]; 86 _files = new CollectionSink<MultipartFile>(<MultipartFile>[]);
79 87
80 /// Freezes all mutable fields and returns an [InputStream] that will emit the 88 /// Freezes all mutable fields and returns a single-subscription [ByteStream]
81 /// request body. 89 /// that will emit the request body.
82 InputStream finalize() { 90 ByteStream finalize() {
83 // TODO(nweiz): freeze fields and files 91 // TODO(nweiz): freeze fields and files
84 var boundary = _boundaryString(_BOUNDARY_LENGTH); 92 var boundary = _boundaryString(_BOUNDARY_LENGTH);
85 headers['content-type'] = 'multipart/form-data; boundary="$boundary"'; 93 headers['content-type'] = 'multipart/form-data; boundary="$boundary"';
86 headers['content-transfer-encoding'] = 'binary'; 94 headers['content-transfer-encoding'] = 'binary';
87 super.finalize(); 95 super.finalize();
88 96
89 var stream = new ListInputStream(); 97 var controller = new StreamController<List<int>>.singleSubscription();
90 98
91 void writeAscii(String string) { 99 void writeAscii(String string) {
92 assert(isPlainAscii(string)); 100 assert(isPlainAscii(string));
93 stream.write(string.charCodes); 101 controller.add(string.charCodes);
94 } 102 }
95 103
96 void writeUtf8(String string) => stream.write(encodeUtf8(string)); 104 writeUtf8(String string) => controller.add(encodeUtf8(string));
97 void writeLine() => stream.write([13, 10]); // \r\n 105 writeLine() => controller.add([13, 10]); // \r\n
98 106
99 fields.forEach((name, value) { 107 fields.forEach((name, value) {
100 writeAscii('--$boundary\r\n'); 108 writeAscii('--$boundary\r\n');
101 writeAscii(_headerForField(name, value)); 109 writeAscii(_headerForField(name, value));
102 writeUtf8(value); 110 writeUtf8(value);
103 writeLine(); 111 writeLine();
104 }); 112 });
105 113
106 Futures.forEach(files, (file) { 114 Futures.forEach(_files.collection, (file) {
107 writeAscii('--$boundary\r\n'); 115 writeAscii('--$boundary\r\n');
108 writeAscii(_headerForFile(file)); 116 writeAscii(_headerForFile(file));
109 return writeInputToInput(file.finalize(), stream) 117 return writeStreamToSink(file.finalize(), controller)
110 .then((_) => writeLine()); 118 .then((_) => writeLine());
111 }).then((_) { 119 }).then((_) {
112 // TODO(nweiz): pass any errors propagated through this future on to 120 // TODO(nweiz): pass any errors propagated through this future on to
113 // the stream. See issue 3657. 121 // the stream. See issue 3657.
114 writeAscii('--$boundary--\r\n'); 122 writeAscii('--$boundary--\r\n');
115 stream.markEndOfStream(); 123 controller.close();
116 }); 124 });
117 125
118 return stream; 126 return new ByteStream(controller);
119 } 127 }
120 128
121 /// All character codes that are valid in multipart boundaries. From 129 /// All character codes that are valid in multipart boundaries. From
122 /// http://tools.ietf.org/html/rfc2046#section-5.1.1. 130 /// http://tools.ietf.org/html/rfc2046#section-5.1.1.
123 static final List<int> _BOUNDARY_CHARACTERS = const <int>[ 131 static final List<int> _BOUNDARY_CHARACTERS = const <int>[
124 39, 40, 41, 43, 95, 44, 45, 46, 47, 58, 61, 63, 48, 49, 50, 51, 52, 53, 54, 132 39, 40, 41, 43, 95, 44, 45, 46, 47, 58, 61, 63, 48, 49, 50, 51, 52, 53, 54,
125 55, 56, 57, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 133 55, 56, 57, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80,
126 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 97, 98, 99, 100, 101, 102, 103, 134 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 97, 98, 99, 100, 101, 102, 103,
127 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 135 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118,
128 119, 120, 121, 122 136 119, 120, 121, 122
(...skipping 29 matching lines...) Expand all
158 String _boundaryString(int length) { 166 String _boundaryString(int length) {
159 var prefix = "dart-http-boundary-"; 167 var prefix = "dart-http-boundary-";
160 var list = new List<int>.fixedLength(length - prefix.length); 168 var list = new List<int>.fixedLength(length - prefix.length);
161 for (var i = 0; i < list.length; i++) { 169 for (var i = 0; i < list.length; i++) {
162 list[i] = _BOUNDARY_CHARACTERS[ 170 list[i] = _BOUNDARY_CHARACTERS[
163 _random.nextInt(_BOUNDARY_CHARACTERS.length)]; 171 _random.nextInt(_BOUNDARY_CHARACTERS.length)];
164 } 172 }
165 return "$prefix${new String.fromCharCodes(list)}"; 173 return "$prefix${new String.fromCharCodes(list)}";
166 } 174 }
167 } 175 }
OLDNEW
« no previous file with comments | « pkg/http/lib/src/multipart_file.dart ('k') | pkg/http/lib/src/request.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698