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 dart.io; | 5 part of dart.io; |
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. |
11 */ | 11 */ |
12 abstract class MimeMultipart extends Stream<List<int>> { | 12 abstract class MimeMultipart extends Stream<List<int>> { |
13 Map<String, String> get headers; | 13 Map<String, String> get headers; |
14 } | 14 } |
15 | 15 |
16 class _MimeMultipartImpl extends MimeMultipart { | 16 class _MimeMultipart extends MimeMultipart { |
17 final Map<String, String> headers; | 17 final Map<String, String> headers; |
18 final Stream<List<int>> _stream; | 18 final Stream<List<int>> _stream; |
19 | 19 |
20 _MimeMultipartImpl(this.headers, this._stream); | 20 _MimeMultipart(this.headers, this._stream); |
21 | 21 |
22 StreamSubscription<List<int>> listen(void onData(List<int> data), | 22 StreamSubscription<List<int>> listen(void onData(List<int> data), |
23 {void onDone(), | 23 {void onDone(), |
24 void onError(error), | 24 void onError(error), |
25 bool cancelOnError}) { | 25 bool cancelOnError}) { |
26 return _stream.listen(onData, | 26 return _stream.listen(onData, |
27 onDone: onDone, | 27 onDone: onDone, |
28 onError: onError, | 28 onError: onError, |
29 cancelOnError: cancelOnError); | 29 cancelOnError: cancelOnError); |
30 } | 30 } |
(...skipping 26 matching lines...) Expand all Loading... |
57 static const int _FAILURE = 15; | 57 static const int _FAILURE = 15; |
58 | 58 |
59 StreamController _controller; | 59 StreamController _controller; |
60 StreamSubscription _subscription; | 60 StreamSubscription _subscription; |
61 | 61 |
62 StreamController _multipartController; | 62 StreamController _multipartController; |
63 Map<String, String> _headers; | 63 Map<String, String> _headers; |
64 | 64 |
65 List<int> _boundary; | 65 List<int> _boundary; |
66 int _state = _START; | 66 int _state = _START; |
67 int _boundaryIndex = 0; | 67 int _boundaryIndex = 2; |
68 | 68 |
69 // Current index in the data buffer. If index is negative then it | 69 // Current index in the data buffer. If index is negative then it |
70 // is the index into the artificial prefix of the boundary string. | 70 // is the index into the artificial prefix of the boundary string. |
71 int _index; | 71 int _index; |
72 List<int> _buffer; | 72 List<int> _buffer; |
73 | 73 |
74 StringBuffer _headerField = new StringBuffer(); | 74 StringBuffer _headerField = new StringBuffer(); |
75 StringBuffer _headerValue = new StringBuffer(); | 75 StringBuffer _headerValue = new StringBuffer(); |
76 | 76 |
77 /** | 77 /** |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
112 (data) { | 112 (data) { |
113 assert(_buffer == null); | 113 assert(_buffer == null); |
114 _pauseStream(); | 114 _pauseStream(); |
115 _buffer = data; | 115 _buffer = data; |
116 _index = 0; | 116 _index = 0; |
117 _parse(); | 117 _parse(); |
118 }, | 118 }, |
119 onDone: () { | 119 onDone: () { |
120 if (_state != _DONE) { | 120 if (_state != _DONE) { |
121 _controller.addError( | 121 _controller.addError( |
122 new MimeParserException("Bad multipart ending")); | 122 new MimeMultipartException("Bad multipart ending")); |
123 } | 123 } |
124 _controller.close(); | 124 _controller.close(); |
125 }, | 125 }, |
126 onError: (error) { | 126 onError: (error) { |
127 _controller.addError(error); | 127 _controller.addError(error); |
128 }); | 128 }); |
129 }, | 129 }, |
130 onCancel: () { | 130 onCancel: () { |
131 _subscription.cancel(); | 131 _subscription.cancel(); |
132 }); | 132 }); |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
180 return; | 180 return; |
181 } | 181 } |
182 int byte; | 182 int byte; |
183 if (_index < 0) { | 183 if (_index < 0) { |
184 byte = _boundary[boundaryPrefix + _index]; | 184 byte = _boundary[boundaryPrefix + _index]; |
185 } else { | 185 } else { |
186 byte = _buffer[_index]; | 186 byte = _buffer[_index]; |
187 } | 187 } |
188 switch (_state) { | 188 switch (_state) { |
189 case _START: | 189 case _START: |
190 if (_toLowerCase(byte) == _toLowerCase(_boundary[_boundaryIndex])) { | 190 if (byte == _boundary[_boundaryIndex]) { |
191 _boundaryIndex++; | 191 _boundaryIndex++; |
192 if (_boundaryIndex == _boundary.length) { | 192 if (_boundaryIndex == _boundary.length) { |
193 _state = _FIRST_BOUNDARY_ENDING; | 193 _state = _FIRST_BOUNDARY_ENDING; |
194 _boundaryIndex = 0; | 194 _boundaryIndex = 0; |
195 } | 195 } |
196 } else { | 196 } else { |
197 // Restart matching of the boundary. | 197 // Restart matching of the boundary. |
198 _index = _index - _boundaryIndex; | 198 _index = _index - _boundaryIndex; |
199 _boundaryIndex = 0; | 199 _boundaryIndex = 0; |
200 } | 200 } |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
239 _headerField.writeCharCode(_toLowerCase(byte)); | 239 _headerField.writeCharCode(_toLowerCase(byte)); |
240 _state = _HEADER_FIELD; | 240 _state = _HEADER_FIELD; |
241 } | 241 } |
242 break; | 242 break; |
243 | 243 |
244 case _HEADER_FIELD: | 244 case _HEADER_FIELD: |
245 if (byte == _CharCode.COLON) { | 245 if (byte == _CharCode.COLON) { |
246 _state = _HEADER_VALUE_START; | 246 _state = _HEADER_VALUE_START; |
247 } else { | 247 } else { |
248 if (!_isTokenChar(byte)) { | 248 if (!_isTokenChar(byte)) { |
249 throw new MimeParserException("Invalid header field name"); | 249 throw new MimeMultipartException("Invalid header field name"); |
250 } | 250 } |
251 _headerField.writeCharCode(_toLowerCase(byte)); | 251 _headerField.writeCharCode(_toLowerCase(byte)); |
252 } | 252 } |
253 break; | 253 break; |
254 | 254 |
255 case _HEADER_VALUE_START: | 255 case _HEADER_VALUE_START: |
256 if (byte == _CharCode.CR) { | 256 if (byte == _CharCode.CR) { |
257 _state = _HEADER_VALUE_FOLDING_OR_ENDING; | 257 _state = _HEADER_VALUE_FOLDING_OR_ENDING; |
258 } else if (byte != _CharCode.SP && byte != _CharCode.HT) { | 258 } else if (byte != _CharCode.SP && byte != _CharCode.HT) { |
259 // Start of new header value. | 259 // Start of new header value. |
(...skipping 14 matching lines...) Expand all Loading... |
274 _expect(byte, _CharCode.LF); | 274 _expect(byte, _CharCode.LF); |
275 _state = _HEADER_VALUE_FOLD_OR_END; | 275 _state = _HEADER_VALUE_FOLD_OR_END; |
276 break; | 276 break; |
277 | 277 |
278 case _HEADER_VALUE_FOLD_OR_END: | 278 case _HEADER_VALUE_FOLD_OR_END: |
279 if (byte == _CharCode.SP || byte == _CharCode.HT) { | 279 if (byte == _CharCode.SP || byte == _CharCode.HT) { |
280 _state = _HEADER_VALUE_START; | 280 _state = _HEADER_VALUE_START; |
281 } else { | 281 } else { |
282 String headerField = _headerField.toString(); | 282 String headerField = _headerField.toString(); |
283 String headerValue =_headerValue.toString(); | 283 String headerValue =_headerValue.toString(); |
284 _headers[headerField] = headerValue; | 284 _headers[headerField.toLowerCase()] = headerValue; |
285 _headerField = new StringBuffer(); | 285 _headerField = new StringBuffer(); |
286 _headerValue = new StringBuffer(); | 286 _headerValue = new StringBuffer(); |
287 if (byte == _CharCode.CR) { | 287 if (byte == _CharCode.CR) { |
288 _state = _HEADER_ENDING; | 288 _state = _HEADER_ENDING; |
289 } else { | 289 } else { |
290 // Start of new header field. | 290 // Start of new header field. |
291 _headerField.writeCharCode(_toLowerCase(byte)); | 291 _headerField.writeCharCode(_toLowerCase(byte)); |
292 _state = _HEADER_FIELD; | 292 _state = _HEADER_FIELD; |
293 } | 293 } |
294 } | 294 } |
295 break; | 295 break; |
296 | 296 |
297 case _HEADER_ENDING: | 297 case _HEADER_ENDING: |
298 _expect(byte, _CharCode.LF); | 298 _expect(byte, _CharCode.LF); |
299 _multipartController = new StreamController( | 299 _multipartController = new StreamController( |
300 onPause: () { | 300 onPause: () { |
301 _pauseStream(); | 301 _pauseStream(); |
302 }, | 302 }, |
303 onResume: () { | 303 onResume: () { |
304 _resumeStream(); | 304 _resumeStream(); |
305 _parse(); | 305 _parse(); |
306 }); | 306 }); |
307 _controller.add( | 307 _controller.add( |
308 new _MimeMultipartImpl(_headers, _multipartController.stream)); | 308 new _MimeMultipart(_headers, _multipartController.stream)); |
309 _headers = null; | 309 _headers = null; |
310 _state = _CONTENT; | 310 _state = _CONTENT; |
311 contentStartIndex = _index + 1; | 311 contentStartIndex = _index + 1; |
312 break; | 312 break; |
313 | 313 |
314 case _CONTENT: | 314 case _CONTENT: |
315 if (byte == _boundary[_boundaryIndex]) { | 315 if (byte == _boundary[_boundaryIndex]) { |
316 _boundaryIndex++; | 316 _boundaryIndex++; |
317 if (_boundaryIndex == _boundary.length) { | 317 if (_boundaryIndex == _boundary.length) { |
318 if (contentStartIndex != null) { | 318 if (contentStartIndex != null) { |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
381 | 381 |
382 int _toLowerCase(int byte) { | 382 int _toLowerCase(int byte) { |
383 final int aCode = "A".codeUnitAt(0); | 383 final int aCode = "A".codeUnitAt(0); |
384 final int zCode = "Z".codeUnitAt(0); | 384 final int zCode = "Z".codeUnitAt(0); |
385 final int delta = "a".codeUnitAt(0) - aCode; | 385 final int delta = "a".codeUnitAt(0) - aCode; |
386 return (aCode <= byte && byte <= zCode) ? byte + delta : byte; | 386 return (aCode <= byte && byte <= zCode) ? byte + delta : byte; |
387 } | 387 } |
388 | 388 |
389 void _expect(int val1, int val2) { | 389 void _expect(int val1, int val2) { |
390 if (val1 != val2) { | 390 if (val1 != val2) { |
391 throw new MimeParserException("Failed to parse multipart mime 1"); | 391 throw new MimeMultipartException("Failed to parse multipart mime 1"); |
392 } | 392 } |
393 } | 393 } |
394 | 394 |
395 void _expectWS(int byte) { | 395 void _expectWS(int byte) { |
396 if (byte != _CharCode.SP && byte != _CharCode.HT) { | 396 if (byte != _CharCode.SP && byte != _CharCode.HT) { |
397 throw new MimeParserException("Failed to parse multipart mime 2"); | 397 throw new MimeMultipartException("Failed to parse multipart mime 2"); |
398 } | 398 } |
399 } | 399 } |
400 } | 400 } |
401 | 401 |
402 | 402 |
403 class MimeParserException implements Exception { | 403 class MimeMultipartException implements Exception { |
404 const MimeParserException([String this.message = ""]); | 404 const MimeMultipartException([String this.message = ""]); |
405 String toString() => "MimeParserException: $message"; | 405 String toString() => "MimeMultipartException: $message"; |
406 final String message; | 406 final String message; |
407 } | 407 } |
OLD | NEW |