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

Side by Side Diff: pkg/http_server/lib/src/http_body_impl.dart

Issue 18438005: Move MimeMultipartTransformer and HttpBodyHandler to mime and http_server packages. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 7 years, 5 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
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 http_server;
6 6
7 class _HttpBodyHandlerTransformer 7 class _HttpBodyHandlerTransformer
8 extends StreamEventTransformer<HttpRequest, HttpRequestBody> { 8 extends StreamEventTransformer<HttpRequest, HttpRequestBody> {
9 final Encoding _defaultEncoding; 9 final Encoding _defaultEncoding;
10 _HttpBodyHandlerTransformer(this._defaultEncoding); 10 _HttpBodyHandlerTransformer(this._defaultEncoding);
11 11
12 void handleData(HttpRequest request, EventSink<HttpRequestBody> sink) { 12 void handleData(HttpRequest request, EventSink<HttpRequestBody> sink) {
13 _HttpBodyHandler.processRequest(request, _defaultEncoding) 13 _HttpBodyHandler.processRequest(request, _defaultEncoding)
14 .then(sink.add, onError: sink.addError); 14 .then(sink.add, onError: sink.addError);
15 } 15 }
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after
113 switch (contentType.subType) { 113 switch (contentType.subType) {
114 case "json": 114 case "json":
115 return asText(Encoding.UTF_8) 115 return asText(Encoding.UTF_8)
116 .then((body) => new _HttpBody(contentType, 116 .then((body) => new _HttpBody(contentType,
117 "json", 117 "json",
118 JSON.parse(body.body))); 118 JSON.parse(body.body)));
119 119
120 case "x-www-form-urlencoded": 120 case "x-www-form-urlencoded":
121 return asText(Encoding.ASCII) 121 return asText(Encoding.ASCII)
122 .then((body) { 122 .then((body) {
123 var map = _HttpUtils.splitQueryString( 123 var map = _splitQueryString(
124 body.body, encoding: defaultEncoding); 124 body.body, encoding: defaultEncoding);
125 var result = {}; 125 var result = {};
126 for (var key in map.keys) { 126 for (var key in map.keys) {
127 result[key] = map[key]; 127 result[key] = map[key];
128 } 128 }
129 return new _HttpBody(contentType, "form", result); 129 return new _HttpBody(contentType, "form", result);
130 }); 130 });
131 131
132 default: 132 default:
133 break; 133 break;
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
190 _HttpClientResponseBody(HttpClientResponse response, HttpBody body) 190 _HttpClientResponseBody(HttpClientResponse response, HttpBody body)
191 : super(body.contentType, body.type, body.body), 191 : super(body.contentType, body.type, body.body),
192 this.response = response; 192 this.response = response;
193 193
194 int get statusCode => response.statusCode; 194 int get statusCode => response.statusCode;
195 195
196 String get reasonPhrase => response.reasonPhrase; 196 String get reasonPhrase => response.reasonPhrase;
197 197
198 HttpHeaders get headers => response.headers; 198 HttpHeaders get headers => response.headers;
199 } 199 }
200
201
202 class _CharCode {
203 static const int AMPERSAND = 38;
204 static const int SEMI_COLON = 59;
205 static const int EQUAL = 61;
206 }
207
208
209 // TODO(ajohnsen): Provide in dart:io?
Bill Hesse 2013/07/03 11:30:27 Do you now mean "Provide in pkg/http_server?" Do
Anders Johnsen 2013/07/12 10:45:57 Removed.
210 Map<String, String> _splitQueryString(String queryString,
211 {Encoding encoding: Encoding.UTF_8}) {
212 Map<String, String> result = new Map<String, String>();
213 int currentPosition = 0;
214 int length = queryString.length;
215
216 while (currentPosition < length) {
217
218 // Find the first equals character between current position and
219 // the provided end.
Bill Hesse 2013/07/03 11:30:27 I don't think you need this function. You can, in
Anders Johnsen 2013/07/12 10:45:57 This is gone.
220 int indexOfEquals(int end) {
221 int index = currentPosition;
222 while (index < end) {
223 if (queryString.codeUnitAt(index) == _CharCode.EQUAL) return index;
224 index++;
225 }
226 return -1;
227 }
228
229 // Find the next separator (either & or ;), see
230 // http://www.w3.org/TR/REC-html40/appendix/notes.html#ampersands-in-uris
231 // relating the ; separator. If no separator is found returns
232 // the length of the query string.
233 int indexOfSeparator() {
234 int end = length;
235 int index = currentPosition;
236 while (index < end) {
237 int codeUnit = queryString.codeUnitAt(index);
238 if (codeUnit == _CharCode.AMPERSAND ||
239 codeUnit == _CharCode.SEMI_COLON) {
240 return index;
241 }
242 index++;
243 }
244 return end;
245 }
246
247 int seppos = indexOfSeparator();
248 int equalspos = indexOfEquals(seppos);
249 String name;
250 String value;
251 if (equalspos == -1) {
252 name = queryString.substring(currentPosition, seppos);
253 value = '';
254 } else {
255 name = queryString.substring(currentPosition, equalspos);
256 value = queryString.substring(equalspos + 1, seppos);
257 }
258 currentPosition = seppos + 1; // This also works when seppos == length.
259 if (name == '') continue;
260 result[_decodeUrlEncodedString(name, encoding: encoding)] =
261 _decodeUrlEncodedString(value, encoding: encoding);
262 }
263 return result;
264 }
265
266
267 // TODO(ajohnsen): Provide in dart:io?
268 String _decodeUrlEncodedString(String urlEncoded,
269 {Encoding encoding: Encoding.UTF_8}) {
270 // First check the string for any encoding.
271 int index = 0;
272 bool encoded = false;
273 while (!encoded && index < urlEncoded.length) {
Bill Hesse 2013/07/03 11:30:27 .indexOf(RegExp('[%+]'))?
Anders Johnsen 2013/07/12 10:45:57 This is gone.
274 encoded = urlEncoded[index] == "+" || urlEncoded[index] == "%";
275 index++;
276 }
277 if (!encoded) return urlEncoded;
278 index--;
279
280 // Start decoding from the first encoded character.
281 List<int> bytes = new List<int>();
282 for (int i = 0; i < index; i++) bytes.add(urlEncoded.codeUnitAt(i));
283 for (int i = index; i < urlEncoded.length; i++) {
284 if (urlEncoded[i] == "+") {
285 bytes.add(32);
286 } else if (urlEncoded[i] == "%") {
287 if (urlEncoded.length - i < 2) {
288 throw new HttpException("Invalid URL encoding");
289 }
290 int byte = 0;
291 for (int j = 0; j < 2; j++) {
292 var charCode = urlEncoded.codeUnitAt(i + j + 1);
293 if (0x30 <= charCode && charCode <= 0x39) {
294 byte = byte * 16 + charCode - 0x30;
295 } else {
296 // Check ranges A-F (0x41-0x46) and a-f (0x61-0x66).
297 charCode |= 0x20;
298 if (0x61 <= charCode && charCode <= 0x66) {
299 byte = byte * 16 + charCode - 0x57;
300 } else {
301 throw new ArgumentError("Invalid URL encoding");
302 }
303 }
304 }
305 bytes.add(byte);
306 i += 2;
307 } else {
308 bytes.add(urlEncoded.codeUnitAt(i));
309 }
310 }
311 return _decodeString(bytes, encoding);
312 }
313
314 // Utility function to synchronously decode a list of bytes.
315 // TODO(ajohnsen): Provide in dart:?.
316 String _decodeString(List<int> bytes, [Encoding encoding = Encoding.UTF_8]) {
317 if (bytes.length == 0) return "";
318 var string;
319 var error;
320 var controller = new StreamController(sync: true);
321 controller.stream
322 .transform(new StringDecoder(encoding))
323 .listen((data) => string = data,
324 onError: (e) => error = e);
325 controller.add(bytes);
326 controller.close();
327 if (error != null) throw error;
328 assert(string != null);
329 return string;
330 }
331
332 /**
333 * Utility class that can fast concatenate [List<int>]s of bytes. Use
334 * [readBytes] to get the final buffer.
335 */
336 // TODO(ajohnsen): Provide in dart:io?
337 class _BufferList {
338 const int _INIT_SIZE = 1 * 1024;
339
340 _BufferList() {
341 clear();
342 }
343
344 int pow2roundup(int x) {
345 --x;
346 x |= x >> 1;
347 x |= x >> 2;
348 x |= x >> 4;
349 x |= x >> 8;
350 x |= x >> 16;
351 return x + 1;
352 }
353
354 /**
355 * Adds a new buffer to the list.
356 */
357 void add(List<int> buffer) {
Bill Hesse 2013/07/03 11:30:27 buffer and _buffer in the same function is confusi
Anders Johnsen 2013/07/12 10:45:57 Also gone.
358 int bufferLength = buffer.length;
359 int required = _length + bufferLength;
360 if (_buffer == null) {
361 int size = pow2roundup(required);
362 if (size < _INIT_SIZE) size = _INIT_SIZE;
363 _buffer = new Uint8List(size);
364 } else if (_buffer.length < required) {
365 // This will give is a list in the range of 2-4 times larger than
366 // required.
367 int size = pow2roundup(required) * 2;
368 Uint8List newBuffer = new Uint8List(size);
369 newBuffer.setRange(0, _buffer.length, _buffer);
370 _buffer = newBuffer;
371 }
372 assert(_buffer.length >= required);
373 if (buffer is Uint8List) {
374 _buffer.setRange(_length, required, buffer);
375 } else {
376 for (int i = 0; i < bufferLength; i++) {
Bill Hesse 2013/07/03 11:30:27 Why aren't we using setRange for both cases?
Anders Johnsen 2013/07/12 10:45:57 We are now.
377 _buffer[_length + i] = buffer[i];
378 }
379 }
380 _length = required;
381 }
382
383 /**
384 * Same as [add].
385 */
386 void write(List<int> buffer) {
387 add(buffer);
388 }
389
390 /**
391 * Read all the bytes from the buffer list. If it's empty, an empty list
392 * is returned. A call to [readBytes] will clear the buffer.
393 */
394 List<int> readBytes() {
395 if (_buffer == null) return new Uint8List(0);
396 var buffer = new Uint8List.view(_buffer.buffer, 0, _length);
397 clear();
398 return buffer;
399 }
400
401 /**
402 * Returns the total number of bytes in the buffer.
403 */
404 int get length => _length;
405
406 /**
407 * Returns whether the buffer list is empty.
408 */
409 bool get isEmpty => _length == 0;
410
411 /**
412 * Returns whether the buffer list is not empty.
413 */
414 bool get isNotEmpty => !isEmpty;
415
416 /**
417 * Clears the content of the buffer list.
418 */
419 void clear() {
420 _length = 0;
421 _buffer = null;
422 }
423
424 int _length; // Total number of bytes in the buffer.
425 Uint8List _buffer; // Internal buffer.
426 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698