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

Side by Side Diff: lib/src/bound_multipart_stream.dart

Issue 1315033002: pkg/mime: dartfmt most of the code (Closed) Base URL: https://github.com/dart-lang/mime.git@master
Patch Set: rebase Created 5 years, 3 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
« no previous file with comments | « no previous file | lib/src/magic_number.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) 2014, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2014, 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 library mime.bound_multipart_stream; 4 library mime.bound_multipart_stream;
5 5
6 import 'dart:async'; 6 import 'dart:async';
7 import 'dart:convert'; 7 import 'dart:convert';
8 8
9 import 'mime_shared.dart'; 9 import 'mime_shared.dart';
10 import 'char_code.dart'; 10 import 'char_code.dart';
11 11
12 // Bytes for '()<>@,;:\\"/[]?={} \t'. 12 // Bytes for '()<>@,;:\\"/[]?={} \t'.
13 const _SEPARATORS = const [40, 41, 60, 62, 64, 44, 59, 58, 92, 34, 47, 91, 93, 13 const _SEPARATORS = const [40, 41, 60, 62, 64, 44, 59, 58, 92, 34, 47, 91, 93,
14 63, 61, 123, 125, 32, 9]; 14 63, 61, 123, 125, 32, 9];
15 15
16 bool _isTokenChar(int byte) { 16 bool _isTokenChar(int byte) {
17 return byte > 31 && byte < 128 && _SEPARATORS.indexOf(byte) == -1; 17 return byte > 31 && byte < 128 && _SEPARATORS.indexOf(byte) == -1;
18 } 18 }
19 19
20 int _toLowerCase(int byte) { 20 int _toLowerCase(int byte) {
21 const delta = CharCode.LOWER_A - CharCode.UPPER_A; 21 const delta = CharCode.LOWER_A - CharCode.UPPER_A;
22 return (CharCode.UPPER_A <= byte && byte <= CharCode.UPPER_Z) ? 22 return (CharCode.UPPER_A <= byte && byte <= CharCode.UPPER_Z)
23 byte + delta : byte; 23 ? byte + delta
24 : byte;
24 } 25 }
25 26
26 void _expectByteValue(int val1, int val2) { 27 void _expectByteValue(int val1, int val2) {
27 if (val1 != val2) { 28 if (val1 != val2) {
28 throw new MimeMultipartException("Failed to parse multipart mime 1"); 29 throw new MimeMultipartException("Failed to parse multipart mime 1");
29 } 30 }
30 } 31 }
31 32
32 void _expectWhitespace(int byte) { 33 void _expectWhitespace(int byte) {
33 if (byte != CharCode.SP && byte != CharCode.HT) { 34 if (byte != CharCode.SP && byte != CharCode.HT) {
34 throw new MimeMultipartException("Failed to parse multipart mime 2"); 35 throw new MimeMultipartException("Failed to parse multipart mime 2");
35 } 36 }
36 } 37 }
37 38
38 class _MimeMultipart extends MimeMultipart { 39 class _MimeMultipart extends MimeMultipart {
39 final Map<String, String> headers; 40 final Map<String, String> headers;
40 final Stream<List<int>> _stream; 41 final Stream<List<int>> _stream;
41 42
42 _MimeMultipart(this.headers, this._stream); 43 _MimeMultipart(this.headers, this._stream);
43 44
44 StreamSubscription<List<int>> listen(void onData(List<int> data), 45 StreamSubscription<List<int>> listen(void onData(List<int> data),
45 {void onDone(), 46 {void onDone(), Function onError, bool cancelOnError}) {
46 Function onError,
47 bool cancelOnError}) {
48 return _stream.listen(onData, 47 return _stream.listen(onData,
49 onDone: onDone, 48 onDone: onDone, onError: onError, cancelOnError: cancelOnError);
50 onError: onError,
51 cancelOnError: cancelOnError);
52 } 49 }
53 } 50 }
54 51
55 class BoundMultipartStream { 52 class BoundMultipartStream {
56 static const int _START = 0; 53 static const int _START = 0;
57 static const int _BOUNDARY_ENDING = 1; 54 static const int _BOUNDARY_ENDING = 1;
58 static const int _BOUNDARY_END = 2; 55 static const int _BOUNDARY_END = 2;
59 static const int _HEADER_START = 3; 56 static const int _HEADER_START = 3;
60 static const int _HEADER_FIELD = 4; 57 static const int _HEADER_FIELD = 4;
61 static const int _HEADER_VALUE_START = 5; 58 static const int _HEADER_VALUE_START = 5;
62 static const int _HEADER_VALUE = 6; 59 static const int _HEADER_VALUE = 6;
63 static const int _HEADER_VALUE_FOLDING_OR_ENDING = 7; 60 static const int _HEADER_VALUE_FOLDING_OR_ENDING = 7;
64 static const int _HEADER_VALUE_FOLD_OR_END = 8; 61 static const int _HEADER_VALUE_FOLD_OR_END = 8;
65 static const int _HEADER_ENDING = 9; 62 static const int _HEADER_ENDING = 9;
66 static const int _CONTENT = 10; 63 static const int _CONTENT = 10;
67 static const int _LAST_BOUNDARY_DASH2 = 11; 64 static const int _LAST_BOUNDARY_DASH2 = 11;
68 static const int _LAST_BOUNDARY_ENDING = 12; 65 static const int _LAST_BOUNDARY_ENDING = 12;
69 static const int _LAST_BOUNDARY_END = 13; 66 static const int _LAST_BOUNDARY_END = 13;
70 static const int _DONE = 14; 67 static const int _DONE = 14;
71 static const int _FAIL = 15; 68 static const int _FAIL = 15;
72 69
73 final List<int> _boundary; 70 final List<int> _boundary;
74 final List<int> _headerField = []; 71 final List<int> _headerField = [];
75 final List<int> _headerValue = []; 72 final List<int> _headerValue = [];
76 73
77 // The following states belong to `_controller`, state changes will not be 74 // The following states belong to `_controller`, state changes will not be
78 // immediately acted upon but rather only after the current 75 // immediately acted upon but rather only after the current
79 // `_multipartController` is done. 76 // `_multipartController` is done.
80 static const int _CONTROLLER_STATE_IDLE = 0; 77 static const int _CONTROLLER_STATE_IDLE = 0;
81 static const int _CONTROLLER_STATE_ACTIVE = 1; 78 static const int _CONTROLLER_STATE_ACTIVE = 1;
82 static const int _CONTROLLER_STATE_PAUSED = 2; 79 static const int _CONTROLLER_STATE_PAUSED = 2;
83 static const int _CONTROLLER_STATE_CANCELED = 3; 80 static const int _CONTROLLER_STATE_CANCELED = 3;
84 81
85 int _controllerState = _CONTROLLER_STATE_IDLE; 82 int _controllerState = _CONTROLLER_STATE_IDLE;
86 83
87 StreamController _controller; 84 StreamController _controller;
88 85
89 Stream<MimeMultipart> get stream => _controller.stream; 86 Stream<MimeMultipart> get stream => _controller.stream;
90 87
91 StreamSubscription _subscription; 88 StreamSubscription _subscription;
92 89
93 StreamController _multipartController; 90 StreamController _multipartController;
94 Map<String, String> _headers; 91 Map<String, String> _headers;
95 92
96 int _state = _START; 93 int _state = _START;
97 int _boundaryIndex = 2; 94 int _boundaryIndex = 2;
98 95
99 // Current index in the data buffer. If index is negative then it 96 // Current index in the data buffer. If index is negative then it
100 // is the index into the artificial prefix of the boundary string. 97 // is the index into the artificial prefix of the boundary string.
101 int _index; 98 int _index;
102 List<int> _buffer; 99 List<int> _buffer;
103 100
104 BoundMultipartStream(this._boundary, Stream<List<int>> stream) { 101 BoundMultipartStream(this._boundary, Stream<List<int>> stream) {
105 _controller = new StreamController( 102 _controller = new StreamController(
106 sync: true, 103 sync: true,
107 onPause: _pauseStream, 104 onPause: _pauseStream,
108 onResume: _resumeStream, 105 onResume: _resumeStream, onCancel: () {
109 onCancel: () { 106 _controllerState = _CONTROLLER_STATE_CANCELED;
110 _controllerState = _CONTROLLER_STATE_CANCELED; 107 _tryPropagateControllerState();
111 _tryPropagateControllerState(); 108 }, onListen: () {
112 }, 109 _controllerState = _CONTROLLER_STATE_ACTIVE;
113 onListen: () { 110 _subscription = stream.listen((data) {
114 _controllerState = _CONTROLLER_STATE_ACTIVE; 111 assert(_buffer == null);
115 _subscription = stream.listen( 112 _subscription.pause();
116 (data) { 113 _buffer = data;
117 assert(_buffer == null); 114 _index = 0;
118 _subscription.pause(); 115 _parse();
119 _buffer = data; 116 }, onDone: () {
120 _index = 0; 117 if (_state != _DONE) {
121 _parse(); 118 _controller
122 }, 119 .addError(new MimeMultipartException("Bad multipart ending"));
123 onDone: () { 120 }
124 if (_state != _DONE) { 121 _controller.close();
125 _controller.addError( 122 }, onError: _controller.addError);
126 new MimeMultipartException("Bad multipart ending")); 123 });
127 } 124 }
128 _controller.close(); 125
129 }, 126 void _resumeStream() {
130 onError: _controller.addError); 127 assert(_controllerState == _CONTROLLER_STATE_PAUSED);
131 }); 128 _controllerState = _CONTROLLER_STATE_ACTIVE;
132 } 129 _tryPropagateControllerState();
133 130 }
134 void _resumeStream() { 131
135 assert (_controllerState == _CONTROLLER_STATE_PAUSED); 132 void _pauseStream() {
136 _controllerState = _CONTROLLER_STATE_ACTIVE; 133 _controllerState = _CONTROLLER_STATE_PAUSED;
137 _tryPropagateControllerState(); 134 _tryPropagateControllerState();
138 } 135 }
139 136
140 void _pauseStream() { 137 void _tryPropagateControllerState() {
141 _controllerState = _CONTROLLER_STATE_PAUSED; 138 if (_multipartController == null) {
142 _tryPropagateControllerState(); 139 switch (_controllerState) {
143 } 140 case _CONTROLLER_STATE_ACTIVE:
144 141 if (_subscription.isPaused) _subscription.resume();
145 void _tryPropagateControllerState() { 142 break;
146 if (_multipartController == null) { 143 case _CONTROLLER_STATE_PAUSED:
147 switch (_controllerState) { 144 if (!_subscription.isPaused) _subscription.pause();
148 case _CONTROLLER_STATE_ACTIVE: 145 break;
149 if (_subscription.isPaused) _subscription.resume(); 146 case _CONTROLLER_STATE_CANCELED:
150 break; 147 _subscription.cancel();
151 case _CONTROLLER_STATE_PAUSED: 148 break;
152 if (!_subscription.isPaused) _subscription.pause(); 149 default:
153 break; 150 throw new StateError("This code should never be reached.");
154 case _CONTROLLER_STATE_CANCELED: 151 }
155 _subscription.cancel(); 152 }
156 break; 153 }
157 default: 154
158 throw new StateError("This code should never be reached."); 155 void _parse() {
159 } 156 // Number of boundary bytes to artificially place before the supplied data.
160 } 157 int boundaryPrefix = 0;
161 } 158 // Position where content starts. Will be null if no known content
162 159 // start exists. Will be negative of the content starts in the
163 void _parse() { 160 // boundary prefix. Will be zero or position if the content starts
164 // Number of boundary bytes to artificially place before the supplied data. 161 // in the current buffer.
165 int boundaryPrefix = 0; 162 int contentStartIndex;
166 // Position where content starts. Will be null if no known content 163
167 // start exists. Will be negative of the content starts in the 164 // Function to report content data for the current part. The data
168 // boundary prefix. Will be zero or position if the content starts 165 // reported is from the current content start index up til the
169 // in the current buffer. 166 // current index. As the data can be artificially prefixed with a
170 int contentStartIndex; 167 // prefix of the boundary both the content start index and index
171 168 // can be negative.
172 // Function to report content data for the current part. The data 169 void reportData() {
173 // reported is from the current content start index up til the 170 if (contentStartIndex < 0) {
174 // current index. As the data can be artificially prefixed with a 171 var contentLength = boundaryPrefix + _index - _boundaryIndex;
175 // prefix of the boundary both the content start index and index 172 if (contentLength <= boundaryPrefix) {
176 // can be negative. 173 _multipartController.add(_boundary.sublist(0, contentLength));
177 void reportData() { 174 } else {
178 if (contentStartIndex < 0) { 175 _multipartController.add(_boundary.sublist(0, boundaryPrefix));
179 var contentLength = boundaryPrefix + _index - _boundaryIndex; 176 _multipartController
180 if (contentLength <= boundaryPrefix) { 177 .add(_buffer.sublist(0, contentLength - boundaryPrefix));
181 _multipartController.add( 178 }
182 _boundary.sublist(0, contentLength)); 179 } else {
183 } else { 180 var contentEndIndex = _index - _boundaryIndex;
184 _multipartController.add( 181 _multipartController
185 _boundary.sublist(0, boundaryPrefix)); 182 .add(_buffer.sublist(contentStartIndex, contentEndIndex));
186 _multipartController.add( 183 }
187 _buffer.sublist(0, contentLength - boundaryPrefix)); 184 }
188 } 185
189 } else { 186 if (_state == _CONTENT && _boundaryIndex == 0) {
190 var contentEndIndex = _index - _boundaryIndex; 187 contentStartIndex = 0;
191 _multipartController.add( 188 } else {
192 _buffer.sublist(contentStartIndex, contentEndIndex)); 189 contentStartIndex = null;
193 } 190 }
194 } 191 // The data to parse might be "artificially" prefixed with a
195 192 // partial match of the boundary.
196 if (_state == _CONTENT && _boundaryIndex == 0) { 193 boundaryPrefix = _boundaryIndex;
197 contentStartIndex = 0; 194
198 } else { 195 while ((_index < _buffer.length) && _state != _FAIL && _state != _DONE) {
199 contentStartIndex = null; 196 int byte;
200 } 197 if (_index < 0) {
201 // The data to parse might be "artificially" prefixed with a 198 byte = _boundary[boundaryPrefix + _index];
202 // partial match of the boundary. 199 } else {
203 boundaryPrefix = _boundaryIndex; 200 byte = _buffer[_index];
204 201 }
205 while ((_index < _buffer.length) && _state != _FAIL && _state != _DONE) { 202 switch (_state) {
206 int byte; 203 case _START:
207 if (_index < 0) { 204 if (byte == _boundary[_boundaryIndex]) {
208 byte = _boundary[boundaryPrefix + _index]; 205 _boundaryIndex++;
209 } else { 206 if (_boundaryIndex == _boundary.length) {
210 byte = _buffer[_index]; 207 _state = _BOUNDARY_ENDING;
211 } 208 _boundaryIndex = 0;
212 switch (_state) { 209 }
213 case _START: 210 } else {
214 if (byte == _boundary[_boundaryIndex]) { 211 // Restart matching of the boundary.
215 _boundaryIndex++; 212 _index = _index - _boundaryIndex;
216 if (_boundaryIndex == _boundary.length) { 213 _boundaryIndex = 0;
217 _state = _BOUNDARY_ENDING; 214 }
218 _boundaryIndex = 0; 215 break;
219 } 216
220 } else { 217 case _BOUNDARY_ENDING:
221 // Restart matching of the boundary. 218 if (byte == CharCode.CR) {
222 _index = _index - _boundaryIndex; 219 _state = _BOUNDARY_END;
223 _boundaryIndex = 0; 220 } else if (byte == CharCode.DASH) {
224 } 221 _state = _LAST_BOUNDARY_DASH2;
225 break; 222 } else {
226 223 _expectWhitespace(byte);
227 case _BOUNDARY_ENDING: 224 }
228 if (byte == CharCode.CR) { 225 break;
229 _state = _BOUNDARY_END; 226
230 } else if (byte == CharCode.DASH) { 227 case _BOUNDARY_END:
231 _state = _LAST_BOUNDARY_DASH2; 228 _expectByteValue(byte, CharCode.LF);
232 } else { 229 if (_multipartController != null) {
233 _expectWhitespace(byte); 230 _multipartController.close();
234 } 231 _multipartController = null;
235 break; 232 _tryPropagateControllerState();
236 233 }
237 case _BOUNDARY_END: 234 _state = _HEADER_START;
238 _expectByteValue(byte, CharCode.LF); 235 break;
239 if (_multipartController != null) { 236
240 _multipartController.close(); 237 case _HEADER_START:
241 _multipartController = null; 238 _headers = new Map<String, String>();
242 _tryPropagateControllerState(); 239 if (byte == CharCode.CR) {
243 } 240 _state = _HEADER_ENDING;
244 _state = _HEADER_START; 241 } else {
245 break; 242 // Start of new header field.
246 243 _headerField.add(_toLowerCase(byte));
247 case _HEADER_START: 244 _state = _HEADER_FIELD;
248 _headers = new Map<String, String>(); 245 }
249 if (byte == CharCode.CR) { 246 break;
250 _state = _HEADER_ENDING; 247
251 } else { 248 case _HEADER_FIELD:
252 // Start of new header field. 249 if (byte == CharCode.COLON) {
253 _headerField.add(_toLowerCase(byte)); 250 _state = _HEADER_VALUE_START;
254 _state = _HEADER_FIELD; 251 } else {
255 } 252 if (!_isTokenChar(byte)) {
256 break; 253 throw new MimeMultipartException("Invalid header field name");
257 254 }
258 case _HEADER_FIELD: 255 _headerField.add(_toLowerCase(byte));
259 if (byte == CharCode.COLON) { 256 }
260 _state = _HEADER_VALUE_START; 257 break;
261 } else { 258
262 if (!_isTokenChar(byte)) { 259 case _HEADER_VALUE_START:
263 throw new MimeMultipartException("Invalid header field name"); 260 if (byte == CharCode.CR) {
264 } 261 _state = _HEADER_VALUE_FOLDING_OR_ENDING;
265 _headerField.add(_toLowerCase(byte)); 262 } else if (byte != CharCode.SP && byte != CharCode.HT) {
266 } 263 // Start of new header value.
267 break; 264 _headerValue.add(byte);
268 265 _state = _HEADER_VALUE;
269 case _HEADER_VALUE_START: 266 }
270 if (byte == CharCode.CR) { 267 break;
271 _state = _HEADER_VALUE_FOLDING_OR_ENDING; 268
272 } else if (byte != CharCode.SP && byte != CharCode.HT) { 269 case _HEADER_VALUE:
273 // Start of new header value. 270 if (byte == CharCode.CR) {
274 _headerValue.add(byte); 271 _state = _HEADER_VALUE_FOLDING_OR_ENDING;
275 _state = _HEADER_VALUE; 272 } else {
276 } 273 _headerValue.add(byte);
277 break; 274 }
278 275 break;
279 case _HEADER_VALUE: 276
280 if (byte == CharCode.CR) { 277 case _HEADER_VALUE_FOLDING_OR_ENDING:
281 _state = _HEADER_VALUE_FOLDING_OR_ENDING; 278 _expectByteValue(byte, CharCode.LF);
282 } else { 279 _state = _HEADER_VALUE_FOLD_OR_END;
283 _headerValue.add(byte); 280 break;
284 } 281
285 break; 282 case _HEADER_VALUE_FOLD_OR_END:
286 283 if (byte == CharCode.SP || byte == CharCode.HT) {
287 case _HEADER_VALUE_FOLDING_OR_ENDING: 284 _state = _HEADER_VALUE_START;
288 _expectByteValue(byte, CharCode.LF); 285 } else {
289 _state = _HEADER_VALUE_FOLD_OR_END; 286 String headerField = UTF8.decode(_headerField);
290 break; 287 String headerValue = UTF8.decode(_headerValue);
291 288 _headers[headerField.toLowerCase()] = headerValue;
292 case _HEADER_VALUE_FOLD_OR_END: 289 _headerField.clear();
293 if (byte == CharCode.SP || byte == CharCode.HT) { 290 _headerValue.clear();
294 _state = _HEADER_VALUE_START; 291 if (byte == CharCode.CR) {
295 } else { 292 _state = _HEADER_ENDING;
296 String headerField = UTF8.decode(_headerField); 293 } else {
297 String headerValue = UTF8.decode(_headerValue); 294 // Start of new header field.
298 _headers[headerField.toLowerCase()] = headerValue; 295 _headerField.add(_toLowerCase(byte));
299 _headerField.clear(); 296 _state = _HEADER_FIELD;
300 _headerValue.clear(); 297 }
301 if (byte == CharCode.CR) { 298 }
302 _state = _HEADER_ENDING; 299 break;
303 } else { 300
304 // Start of new header field. 301 case _HEADER_ENDING:
305 _headerField.add(_toLowerCase(byte)); 302 _expectByteValue(byte, CharCode.LF);
306 _state = _HEADER_FIELD; 303 _multipartController = new StreamController(sync: true, onListen: () {
307 } 304 if (_subscription.isPaused) _subscription.resume();
308 } 305 }, onPause: _subscription.pause, onResume: _subscription.resume);
309 break; 306 _controller
310 307 .add(new _MimeMultipart(_headers, _multipartController.stream));
311 case _HEADER_ENDING: 308 _headers = null;
312 _expectByteValue(byte, CharCode.LF); 309 _state = _CONTENT;
313 _multipartController = new StreamController( 310 contentStartIndex = _index + 1;
314 sync: true, 311 break;
315 onListen: () { 312
316 if (_subscription.isPaused) _subscription.resume(); 313 case _CONTENT:
317 }, 314 if (byte == _boundary[_boundaryIndex]) {
318 onPause: _subscription.pause, 315 _boundaryIndex++;
319 onResume: _subscription.resume); 316 if (_boundaryIndex == _boundary.length) {
320 _controller.add( 317 if (contentStartIndex != null) {
321 new _MimeMultipart(_headers, _multipartController.stream)); 318 _index++;
322 _headers = null; 319 reportData();
323 _state = _CONTENT; 320 _index--;
324 contentStartIndex = _index + 1; 321 }
325 break; 322 _multipartController.close();
326 323 _multipartController = null;
327 case _CONTENT: 324 _tryPropagateControllerState();
328 if (byte == _boundary[_boundaryIndex]) { 325 _boundaryIndex = 0;
329 _boundaryIndex++; 326 _state = _BOUNDARY_ENDING;
330 if (_boundaryIndex == _boundary.length) { 327 }
331 if (contentStartIndex != null) { 328 } else {
332 _index++; 329 // Restart matching of the boundary.
333 reportData(); 330 _index = _index - _boundaryIndex;
334 _index--; 331 if (contentStartIndex == null) contentStartIndex = _index;
335 } 332 _boundaryIndex = 0;
336 _multipartController.close(); 333 }
337 _multipartController = null; 334 break;
338 _tryPropagateControllerState(); 335
339 _boundaryIndex = 0; 336 case _LAST_BOUNDARY_DASH2:
340 _state = _BOUNDARY_ENDING; 337 _expectByteValue(byte, CharCode.DASH);
341 } 338 _state = _LAST_BOUNDARY_ENDING;
342 } else { 339 break;
343 // Restart matching of the boundary. 340
344 _index = _index - _boundaryIndex; 341 case _LAST_BOUNDARY_ENDING:
345 if (contentStartIndex == null) contentStartIndex = _index; 342 if (byte == CharCode.CR) {
346 _boundaryIndex = 0; 343 _state = _LAST_BOUNDARY_END;
347 } 344 } else {
348 break; 345 _expectWhitespace(byte);
349 346 }
350 case _LAST_BOUNDARY_DASH2: 347 break;
351 _expectByteValue(byte, CharCode.DASH); 348
352 _state = _LAST_BOUNDARY_ENDING; 349 case _LAST_BOUNDARY_END:
353 break; 350 _expectByteValue(byte, CharCode.LF);
354 351 if (_multipartController != null) {
355 case _LAST_BOUNDARY_ENDING: 352 _multipartController.close();
356 if (byte == CharCode.CR) { 353 _multipartController = null;
357 _state = _LAST_BOUNDARY_END; 354 _tryPropagateControllerState();
358 } else { 355 }
359 _expectWhitespace(byte); 356 _state = _DONE;
360 } 357 break;
361 break; 358
362 359 default:
363 case _LAST_BOUNDARY_END: 360 // Should be unreachable.
364 _expectByteValue(byte, CharCode.LF); 361 assert(false);
365 if (_multipartController != null) { 362 break;
366 _multipartController.close(); 363 }
367 _multipartController = null; 364
368 _tryPropagateControllerState(); 365 // Move to the next byte.
369 } 366 _index++;
370 _state = _DONE; 367 }
371 break; 368
372 369 // Report any known content.
373 default: 370 if (_state == _CONTENT && contentStartIndex != null) {
374 // Should be unreachable. 371 reportData();
375 assert(false); 372 }
376 break; 373
377 } 374 // Resume if at end.
378 375 if (_index == _buffer.length) {
379 // Move to the next byte. 376 _buffer = null;
380 _index++; 377 _index = null;
381 } 378 _subscription.resume();
382 379 }
383 // Report any known content. 380 }
384 if (_state == _CONTENT && contentStartIndex != null) {
385 reportData();
386 }
387
388 // Resume if at end.
389 if (_index == _buffer.length) {
390 _buffer = null;
391 _index = null;
392 _subscription.resume();
393 }
394 }
395 } 381 }
OLDNEW
« no previous file with comments | « no previous file | lib/src/magic_number.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698