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

Side by Side Diff: sdk/lib/io/http_body_impl.dart

Issue 14865008: Extend HttpBody handler to support 'multipart/form-data'. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Fix interface. Created 7 years, 7 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 | « sdk/lib/io/http_body.dart ('k') | sdk/lib/io/http_multipart_form_data_impl.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) 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 part of dart.io; 5 part of dart.io;
6 6
7 class _HttpBodyHandlerTransformer 7 class _HttpBodyHandlerTransformer
8 extends StreamEventTransformer<HttpRequest, HttpRequestBody> { 8 extends StreamEventTransformer<HttpRequest, HttpRequestBody> {
9 void handleData(HttpRequest request, EventSink<HttpRequestBody> sink) { 9 void handleData(HttpRequest request, EventSink<HttpRequestBody> sink) {
10 HttpBodyHandler.processRequest(request) 10 HttpBodyHandler.processRequest(request)
(...skipping 15 matching lines...) Expand all
26 } 26 }
27 27
28 static Future<HttpClientResponseBody> processResponse( 28 static Future<HttpClientResponseBody> processResponse(
29 HttpClientResponse response) { 29 HttpClientResponse response) {
30 return process(response, response.headers) 30 return process(response, response.headers)
31 .then((body) => new _HttpClientResponseBody(response, body)); 31 .then((body) => new _HttpClientResponseBody(response, body));
32 } 32 }
33 33
34 static Future<HttpBody> process(Stream<List<int>> stream, 34 static Future<HttpBody> process(Stream<List<int>> stream,
35 HttpHeaders headers) { 35 HttpHeaders headers) {
36 return stream.fold( 36 ContentType contentType = headers.contentType;
37 new _BufferList(),
38 (buffer, data) {
39 // TODO(ajohnsen): Add limit for POST data.
40 buffer.add(data);
41 return buffer;
42 })
43 .then((list) {
44 dynamic content = list.readBytes();
45 String type = "binary";
46 ContentType contentType = headers.contentType;
47 if (contentType == null) {
48 return new _HttpBody(null, type, content);
49 }
50 String asText(Encoding defaultEncoding) {
51 var encoding;
52 var charset = contentType.charset;
53 if (charset != null) encoding = Encoding.fromName(charset);
54 if (encoding == null) encoding = defaultEncoding;
55 return _decodeString(content, encoding);
56 }
57 switch (contentType.primaryType) {
58 case "text":
59 type = "text";
60 content = asText(Encoding.ASCII);
61 break;
62 37
63 case "application": 38 Future<HttpBody> asBinary() {
64 switch (contentType.subType) { 39 return stream
65 case "json": 40 .fold(new _BufferList(), (buffer, data) => buffer..add(data))
66 content = JSON.parse(asText(Encoding.UTF_8)); 41 .then((buffer) => new _HttpBody(contentType,
67 type = "json"; 42 "binary",
68 break; 43 buffer.readBytes()));
44 }
69 45
70 default: 46 Future<HttpBody> asText(Encoding defaultEncoding) {
71 break; 47 var encoding;
48 var charset = contentType.charset;
49 if (charset != null) encoding = Encoding.fromName(charset);
50 if (encoding == null) encoding = defaultEncoding;
51 return stream
52 .transform(new StringDecoder(encoding))
53 .fold(new StringBuffer(), (buffer, data) => buffer..write(data))
54 .then((buffer) => new _HttpBody(contentType,
55 "text",
56 buffer.toString()));
57 }
58
59 Future<HttpBody> asFormData() {
60 return stream
61 .transform(new MimeMultipartTransformer(
62 contentType.parameters['boundary']))
63 .map((HttpMultipartFormData.parse))
64 .map((multipart) {
65 var future;
66 if (multipart.isText) {
67 future = multipart
68 .fold(new StringBuffer(), (b, s) => b..write(s))
69 .then((b) => b.toString());
70 } else {
71 future = multipart
72 .fold(new _BufferList(), (b, d) => b..add(d))
73 .then((b) => b.readBytes());
74 }
75 return future.then((data) {
76 var filename =
77 multipart.contentDisposition.parameters['filename'];
78 if (filename != null) {
79 data = new _HttpBodyFileUpload(multipart.contentType,
80 filename,
81 data);
72 } 82 }
73 break; 83 return [multipart.contentDisposition.parameters['name'], data];
84 });
85 })
86 .fold([], (l, f) => l..add(f))
87 .then(Future.wait)
88 .then((parts) {
89 Map<String, dynamic> map = new Map<String, dynamic>();
90 for (var part in parts) {
91 map[part[0]] = part[1]; // Override existing entries.
92 }
93 return new _HttpBody(contentType, 'form', map);
94 });
95 }
74 96
75 default: 97 if (contentType == null) {
76 break; 98 return asBinary();
77 } 99 }
78 return new _HttpBody(contentType.mimeType, type, content); 100
79 }); 101 switch (contentType.primaryType) {
102 case "text":
103 return asText(Encoding.ASCII);
104
105 case "application":
106 switch (contentType.subType) {
107 case "json":
108 return asText(Encoding.UTF_8)
109 .then((body) => new _HttpBody(contentType,
110 "json",
111 JSON.parse(body.body)));
112
113 default:
114 break;
115 }
116 break;
117
118 case "multipart":
119 switch (contentType.subType) {
120 case "form-data":
121 return asFormData();
122
123 default:
124 break;
125 }
126 break;
127
128 default:
129 break;
130 }
131
132 return asBinary();
80 } 133 }
81 } 134 }
82 135
136 class _HttpBodyFileUpload implements HttpBodyFileUpload {
137 final ContentType contentType;
138 final String filename;
139 final dynamic content;
140 _HttpBodyFileUpload(this.contentType, this.filename, this.content);
141 }
142
83 class _HttpBody implements HttpBody { 143 class _HttpBody implements HttpBody {
84 final String mimeType; 144 final ContentType contentType;
85 final String type; 145 final String type;
86 final dynamic body; 146 final dynamic body;
87 147
88 _HttpBody(String this.mimeType, 148 _HttpBody(ContentType this.contentType,
89 String this.type, 149 String this.type,
90 dynamic this.body); 150 dynamic this.body);
91 } 151 }
92 152
93 class _HttpRequestBody extends _HttpBody implements HttpRequestBody { 153 class _HttpRequestBody extends _HttpBody implements HttpRequestBody {
94 final String method; 154 final String method;
95 final Uri uri; 155 final Uri uri;
96 final HttpHeaders headers; 156 final HttpHeaders headers;
97 final HttpResponse response; 157 final HttpResponse response;
98 158
99 _HttpRequestBody(HttpRequest request, HttpBody body) 159 _HttpRequestBody(HttpRequest request, HttpBody body)
100 : super(body.mimeType, body.type, body.body), 160 : super(body.contentType, body.type, body.body),
101 method = request.method, 161 method = request.method,
102 uri = request.uri, 162 uri = request.uri,
103 headers = request.headers, 163 headers = request.headers,
104 response = request.response; 164 response = request.response;
105 } 165 }
106 166
107 class _HttpClientResponseBody 167 class _HttpClientResponseBody
108 extends _HttpBody implements HttpClientResponseBody { 168 extends _HttpBody implements HttpClientResponseBody {
109 final HttpClientResponse response; 169 final HttpClientResponse response;
110 170
111 _HttpClientResponseBody(HttpClientResponse response, HttpBody body) 171 _HttpClientResponseBody(HttpClientResponse response, HttpBody body)
112 : super(body.mimeType, body.type, body.body), 172 : super(body.contentType, body.type, body.body),
113 this.response = response; 173 this.response = response;
114 174
115 int get statusCode => response.statusCode; 175 int get statusCode => response.statusCode;
116 176
117 String get reasonPhrase => response.reasonPhrase; 177 String get reasonPhrase => response.reasonPhrase;
118 178
119 HttpHeaders get headers => response.headers; 179 HttpHeaders get headers => response.headers;
120 } 180 }
OLDNEW
« no previous file with comments | « sdk/lib/io/http_body.dart ('k') | sdk/lib/io/http_multipart_form_data_impl.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698