Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 part of mime; | 5 part of mime; |
| 6 | 6 |
| 7 | 7 |
| 8 /** | 8 /** |
| 9 * A Mime Multipart class representing each part parsed by | 9 * A Mime Multipart class representing each part parsed by |
| 10 * [MimeMultipartTransformer]. The data is streamed in as it become available. | 10 * [MimeMultipartTransformer]. The data is streamed in as it become available. |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 79 | 79 |
| 80 List<int> _boundary; | 80 List<int> _boundary; |
| 81 int _state = _START; | 81 int _state = _START; |
| 82 int _boundaryIndex = 2; | 82 int _boundaryIndex = 2; |
| 83 | 83 |
| 84 // Current index in the data buffer. If index is negative then it | 84 // Current index in the data buffer. If index is negative then it |
| 85 // is the index into the artificial prefix of the boundary string. | 85 // is the index into the artificial prefix of the boundary string. |
| 86 int _index; | 86 int _index; |
| 87 List<int> _buffer; | 87 List<int> _buffer; |
| 88 | 88 |
| 89 StringBuffer _headerField = new StringBuffer(); | 89 List<int> _headerField = []; |
| 90 StringBuffer _headerValue = new StringBuffer(); | 90 List<int> _headerValue = []; |
| 91 | 91 |
| 92 /** | 92 /** |
| 93 * Construct a new MIME multipart parser with the boundary | 93 * Construct a new MIME multipart parser with the boundary |
| 94 * [boundary]. The boundary should be as specified in the content | 94 * [boundary]. The boundary should be as specified in the content |
| 95 * type parameter, that is without the -- prefix. | 95 * type parameter, that is without the -- prefix. |
| 96 */ | 96 */ |
| 97 MimeMultipartTransformer(String boundary) { | 97 MimeMultipartTransformer(String boundary) { |
| 98 List<int> charCodes = boundary.codeUnits; | 98 List<int> charCodes = boundary.codeUnits; |
| 99 _boundary = new Uint8List(4 + charCodes.length); | 99 _boundary = new Uint8List(4 + charCodes.length); |
| 100 // Set-up the matching boundary preceding it with CRLF and two | 100 // Set-up the matching boundary preceding it with CRLF and two |
| (...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 239 _multipartController = null; | 239 _multipartController = null; |
| 240 _state = _HEADER_START; | 240 _state = _HEADER_START; |
| 241 break; | 241 break; |
| 242 | 242 |
| 243 case _HEADER_START: | 243 case _HEADER_START: |
| 244 _headers = new Map<String, String>(); | 244 _headers = new Map<String, String>(); |
| 245 if (byte == _CharCode.CR) { | 245 if (byte == _CharCode.CR) { |
| 246 _state = _HEADER_ENDING; | 246 _state = _HEADER_ENDING; |
| 247 } else { | 247 } else { |
| 248 // Start of new header field. | 248 // Start of new header field. |
| 249 _headerField.writeCharCode(_toLowerCase(byte)); | 249 _headerField.add(_toLowerCase(byte)); |
| 250 _state = _HEADER_FIELD; | 250 _state = _HEADER_FIELD; |
| 251 } | 251 } |
| 252 break; | 252 break; |
| 253 | 253 |
| 254 case _HEADER_FIELD: | 254 case _HEADER_FIELD: |
| 255 if (byte == _CharCode.COLON) { | 255 if (byte == _CharCode.COLON) { |
| 256 _state = _HEADER_VALUE_START; | 256 _state = _HEADER_VALUE_START; |
| 257 } else { | 257 } else { |
| 258 if (!_isTokenChar(byte)) { | 258 if (!_isTokenChar(byte)) { |
| 259 throw new MimeMultipartException("Invalid header field name"); | 259 throw new MimeMultipartException("Invalid header field name"); |
| 260 } | 260 } |
| 261 _headerField.writeCharCode(_toLowerCase(byte)); | 261 _headerField.add(_toLowerCase(byte)); |
| 262 } | 262 } |
| 263 break; | 263 break; |
| 264 | 264 |
| 265 case _HEADER_VALUE_START: | 265 case _HEADER_VALUE_START: |
| 266 if (byte == _CharCode.CR) { | 266 if (byte == _CharCode.CR) { |
| 267 _state = _HEADER_VALUE_FOLDING_OR_ENDING; | 267 _state = _HEADER_VALUE_FOLDING_OR_ENDING; |
| 268 } else if (byte != _CharCode.SP && byte != _CharCode.HT) { | 268 } else if (byte != _CharCode.SP && byte != _CharCode.HT) { |
| 269 // Start of new header value. | 269 // Start of new header value. |
| 270 _headerValue.writeCharCode(byte); | 270 _headerValue.add(byte); |
| 271 _state = _HEADER_VALUE; | 271 _state = _HEADER_VALUE; |
| 272 } | 272 } |
| 273 break; | 273 break; |
| 274 | 274 |
| 275 case _HEADER_VALUE: | 275 case _HEADER_VALUE: |
| 276 if (byte == _CharCode.CR) { | 276 if (byte == _CharCode.CR) { |
| 277 _state = _HEADER_VALUE_FOLDING_OR_ENDING; | 277 _state = _HEADER_VALUE_FOLDING_OR_ENDING; |
| 278 } else { | 278 } else { |
| 279 _headerValue.writeCharCode(byte); | 279 _headerValue.add(byte); |
| 280 } | 280 } |
| 281 break; | 281 break; |
| 282 | 282 |
| 283 case _HEADER_VALUE_FOLDING_OR_ENDING: | 283 case _HEADER_VALUE_FOLDING_OR_ENDING: |
| 284 _expect(byte, _CharCode.LF); | 284 _expect(byte, _CharCode.LF); |
| 285 _state = _HEADER_VALUE_FOLD_OR_END; | 285 _state = _HEADER_VALUE_FOLD_OR_END; |
| 286 break; | 286 break; |
| 287 | 287 |
| 288 case _HEADER_VALUE_FOLD_OR_END: | 288 case _HEADER_VALUE_FOLD_OR_END: |
| 289 if (byte == _CharCode.SP || byte == _CharCode.HT) { | 289 if (byte == _CharCode.SP || byte == _CharCode.HT) { |
| 290 _state = _HEADER_VALUE_START; | 290 _state = _HEADER_VALUE_START; |
| 291 } else { | 291 } else { |
| 292 String headerField = _headerField.toString(); | 292 String headerField = UTF8.decode(_headerField); |
|
Søren Gjesse
2013/10/30 10:08:09
Should there be a way of configuring this?
Anders Johnsen
2013/10/30 10:34:04
I don't think so. The only behavior I've seen has
| |
| 293 String headerValue =_headerValue.toString(); | 293 String headerValue = UTF8.decode(_headerValue); |
| 294 _headers[headerField.toLowerCase()] = headerValue; | 294 _headers[headerField.toLowerCase()] = headerValue; |
| 295 _headerField = new StringBuffer(); | 295 _headerField = []; |
| 296 _headerValue = new StringBuffer(); | 296 _headerValue = []; |
| 297 if (byte == _CharCode.CR) { | 297 if (byte == _CharCode.CR) { |
| 298 _state = _HEADER_ENDING; | 298 _state = _HEADER_ENDING; |
| 299 } else { | 299 } else { |
| 300 // Start of new header field. | 300 // Start of new header field. |
| 301 _headerField.writeCharCode(_toLowerCase(byte)); | 301 _headerField.add(_toLowerCase(byte)); |
| 302 _state = _HEADER_FIELD; | 302 _state = _HEADER_FIELD; |
| 303 } | 303 } |
| 304 } | 304 } |
| 305 break; | 305 break; |
| 306 | 306 |
| 307 case _HEADER_ENDING: | 307 case _HEADER_ENDING: |
| 308 _expect(byte, _CharCode.LF); | 308 _expect(byte, _CharCode.LF); |
| 309 _multipartController = new StreamController( | 309 _multipartController = new StreamController( |
| 310 sync: true, | 310 sync: true, |
| 311 onPause: () { | 311 onPause: () { |
| (...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 409 } | 409 } |
| 410 } | 410 } |
| 411 } | 411 } |
| 412 | 412 |
| 413 | 413 |
| 414 class MimeMultipartException implements Exception { | 414 class MimeMultipartException implements Exception { |
| 415 const MimeMultipartException([String this.message = ""]); | 415 const MimeMultipartException([String this.message = ""]); |
| 416 String toString() => "MimeMultipartException: $message"; | 416 String toString() => "MimeMultipartException: $message"; |
| 417 final String message; | 417 final String message; |
| 418 } | 418 } |
| OLD | NEW |