OLD | NEW |
---|---|
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 // Global constants. | 7 // Global constants. |
8 class _Const { | 8 class _Const { |
9 // Bytes for "HTTP". | 9 // Bytes for "HTTP". |
10 static const HTTP = const [72, 84, 84, 80]; | 10 static const HTTP = const [72, 84, 84, 80]; |
11 // Bytes for "HTTP/1.". | 11 // Bytes for "HTTP/1.". |
12 static const HTTP1DOT = const [72, 84, 84, 80, 47, 49, 46]; | 12 static const HTTP1DOT = const [72, 84, 84, 80, 47, 49, 46]; |
13 // Bytes for "HTTP/1.0". | 13 // Bytes for "HTTP/1.0". |
14 static const HTTP10 = const [72, 84, 84, 80, 47, 49, 46, 48]; | 14 static const HTTP10 = const [72, 84, 84, 80, 47, 49, 46, 48]; |
15 // Bytes for "HTTP/1.1". | 15 // Bytes for "HTTP/1.1". |
16 static const HTTP11 = const [72, 84, 84, 80, 47, 49, 46, 49]; | 16 static const HTTP11 = const [72, 84, 84, 80, 47, 49, 46, 49]; |
17 | 17 |
18 static const bool T = true; | 18 static const bool T = true; |
19 static const bool F = false; | 19 static const bool F = false; |
20 // Loopup-map for the following characters: '()<>@,;:\\"/[]?={} \t'. | 20 // Loopup-map for the following characters: '()<>@,;:\\"/[]?={} \t'. |
21 static const SEPARATOR_MAP = const [ | 21 static const SEPARATOR_MAP = const [ |
22 F,F,F,F,F,F,F,F,F,T,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,T,F,T,F,F, | 22 F, |
floitsch
2017/03/16 10:37:54
This really makes reading this file harder.
| |
23 F,F,F,T,T,F,F,T,F,F,T,F,F,F,F,F,F,F,F,F,F,T,T,T,T,T,T,T,F,F,F,F,F,F,F,F,F, | 23 F, |
24 F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,T,T,T,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F, | 24 F, |
25 F,F,F,F,F,F,F,F,F,F,F,F,T,F,T,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F, | 25 F, |
26 F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F, | 26 F, |
27 F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F, | 27 F, |
28 F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F]; | 28 F, |
29 F, | |
30 F, | |
31 T, | |
32 F, | |
33 F, | |
34 F, | |
35 F, | |
36 F, | |
37 F, | |
38 F, | |
39 F, | |
40 F, | |
41 F, | |
42 F, | |
43 F, | |
44 F, | |
45 F, | |
46 F, | |
47 F, | |
48 F, | |
49 F, | |
50 F, | |
51 F, | |
52 F, | |
53 F, | |
54 T, | |
55 F, | |
56 T, | |
57 F, | |
58 F, | |
59 F, | |
60 F, | |
61 F, | |
62 T, | |
63 T, | |
64 F, | |
65 F, | |
66 T, | |
67 F, | |
68 F, | |
69 T, | |
70 F, | |
71 F, | |
72 F, | |
73 F, | |
74 F, | |
75 F, | |
76 F, | |
77 F, | |
78 F, | |
79 F, | |
80 T, | |
81 T, | |
82 T, | |
83 T, | |
84 T, | |
85 T, | |
86 T, | |
87 F, | |
88 F, | |
89 F, | |
90 F, | |
91 F, | |
92 F, | |
93 F, | |
94 F, | |
95 F, | |
96 F, | |
97 F, | |
98 F, | |
99 F, | |
100 F, | |
101 F, | |
102 F, | |
103 F, | |
104 F, | |
105 F, | |
106 F, | |
107 F, | |
108 F, | |
109 F, | |
110 F, | |
111 F, | |
112 F, | |
113 T, | |
114 T, | |
115 T, | |
116 F, | |
117 F, | |
118 F, | |
119 F, | |
120 F, | |
121 F, | |
122 F, | |
123 F, | |
124 F, | |
125 F, | |
126 F, | |
127 F, | |
128 F, | |
129 F, | |
130 F, | |
131 F, | |
132 F, | |
133 F, | |
134 F, | |
135 F, | |
136 F, | |
137 F, | |
138 F, | |
139 F, | |
140 F, | |
141 F, | |
142 F, | |
143 F, | |
144 F, | |
145 T, | |
146 F, | |
147 T, | |
148 F, | |
149 F, | |
150 F, | |
151 F, | |
152 F, | |
153 F, | |
154 F, | |
155 F, | |
156 F, | |
157 F, | |
158 F, | |
159 F, | |
160 F, | |
161 F, | |
162 F, | |
163 F, | |
164 F, | |
165 F, | |
166 F, | |
167 F, | |
168 F, | |
169 F, | |
170 F, | |
171 F, | |
172 F, | |
173 F, | |
174 F, | |
175 F, | |
176 F, | |
177 F, | |
178 F, | |
179 F, | |
180 F, | |
181 F, | |
182 F, | |
183 F, | |
184 F, | |
185 F, | |
186 F, | |
187 F, | |
188 F, | |
189 F, | |
190 F, | |
191 F, | |
192 F, | |
193 F, | |
194 F, | |
195 F, | |
196 F, | |
197 F, | |
198 F, | |
199 F, | |
200 F, | |
201 F, | |
202 F, | |
203 F, | |
204 F, | |
205 F, | |
206 F, | |
207 F, | |
208 F, | |
209 F, | |
210 F, | |
211 F, | |
212 F, | |
213 F, | |
214 F, | |
215 F, | |
216 F, | |
217 F, | |
218 F, | |
219 F, | |
220 F, | |
221 F, | |
222 F, | |
223 F, | |
224 F, | |
225 F, | |
226 F, | |
227 F, | |
228 F, | |
229 F, | |
230 F, | |
231 F, | |
232 F, | |
233 F, | |
234 F, | |
235 F, | |
236 F, | |
237 F, | |
238 F, | |
239 F, | |
240 F, | |
241 F, | |
242 F, | |
243 F, | |
244 F, | |
245 F, | |
246 F, | |
247 F, | |
248 F, | |
249 F, | |
250 F, | |
251 F, | |
252 F, | |
253 F, | |
254 F, | |
255 F, | |
256 F, | |
257 F, | |
258 F, | |
259 F, | |
260 F, | |
261 F, | |
262 F, | |
263 F, | |
264 F, | |
265 F, | |
266 F, | |
267 F, | |
268 F, | |
269 F, | |
270 F, | |
271 F, | |
272 F, | |
273 F, | |
274 F, | |
275 F, | |
276 F, | |
277 F | |
278 ]; | |
29 } | 279 } |
30 | 280 |
31 | |
32 // Frequently used character codes. | 281 // Frequently used character codes. |
33 class _CharCode { | 282 class _CharCode { |
34 static const int HT = 9; | 283 static const int HT = 9; |
35 static const int LF = 10; | 284 static const int LF = 10; |
36 static const int CR = 13; | 285 static const int CR = 13; |
37 static const int SP = 32; | 286 static const int SP = 32; |
38 static const int AMPERSAND = 38; | 287 static const int AMPERSAND = 38; |
39 static const int COMMA = 44; | 288 static const int COMMA = 44; |
40 static const int DASH = 45; | 289 static const int DASH = 45; |
41 static const int SLASH = 47; | 290 static const int SLASH = 47; |
42 static const int ZERO = 48; | 291 static const int ZERO = 48; |
43 static const int ONE = 49; | 292 static const int ONE = 49; |
44 static const int COLON = 58; | 293 static const int COLON = 58; |
45 static const int SEMI_COLON = 59; | 294 static const int SEMI_COLON = 59; |
46 static const int EQUAL = 61; | 295 static const int EQUAL = 61; |
47 } | 296 } |
48 | 297 |
49 | |
50 // States of the HTTP parser state machine. | 298 // States of the HTTP parser state machine. |
51 class _State { | 299 class _State { |
52 static const int START = 0; | 300 static const int START = 0; |
53 static const int METHOD_OR_RESPONSE_HTTP_VERSION = 1; | 301 static const int METHOD_OR_RESPONSE_HTTP_VERSION = 1; |
54 static const int RESPONSE_HTTP_VERSION = 2; | 302 static const int RESPONSE_HTTP_VERSION = 2; |
55 static const int REQUEST_LINE_METHOD = 3; | 303 static const int REQUEST_LINE_METHOD = 3; |
56 static const int REQUEST_LINE_URI = 4; | 304 static const int REQUEST_LINE_URI = 4; |
57 static const int REQUEST_LINE_HTTP_VERSION = 5; | 305 static const int REQUEST_LINE_HTTP_VERSION = 5; |
58 static const int REQUEST_LINE_ENDING = 6; | 306 static const int REQUEST_LINE_ENDING = 6; |
59 static const int RESPONSE_LINE_STATUS_CODE = 7; | 307 static const int RESPONSE_LINE_STATUS_CODE = 7; |
(...skipping 29 matching lines...) Expand all Loading... | |
89 static const int HTTP11 = 2; | 337 static const int HTTP11 = 2; |
90 } | 338 } |
91 | 339 |
92 // States of the HTTP parser state machine. | 340 // States of the HTTP parser state machine. |
93 class _MessageType { | 341 class _MessageType { |
94 static const int UNDETERMINED = 0; | 342 static const int UNDETERMINED = 0; |
95 static const int REQUEST = 1; | 343 static const int REQUEST = 1; |
96 static const int RESPONSE = 0; | 344 static const int RESPONSE = 0; |
97 } | 345 } |
98 | 346 |
99 | |
100 /** | 347 /** |
101 * The _HttpDetachedStreamSubscription takes a subscription and some extra data, | 348 * The _HttpDetachedStreamSubscription takes a subscription and some extra data, |
102 * and makes it possible to "inject" the data in from of other data events | 349 * and makes it possible to "inject" the data in from of other data events |
103 * from the subscription. | 350 * from the subscription. |
104 * | 351 * |
105 * It does so by overriding pause/resume, so that once the | 352 * It does so by overriding pause/resume, so that once the |
106 * _HttpDetachedStreamSubscription is resumed, it'll deliver the data before | 353 * _HttpDetachedStreamSubscription is resumed, it'll deliver the data before |
107 * resuming the underlaying subscription. | 354 * resuming the underlaying subscription. |
108 */ | 355 */ |
109 class _HttpDetachedStreamSubscription implements StreamSubscription<List<int>> { | 356 class _HttpDetachedStreamSubscription implements StreamSubscription<List<int>> { |
110 StreamSubscription<List<int>> _subscription; | 357 StreamSubscription<List<int>> _subscription; |
111 List<int> _injectData; | 358 List<int> _injectData; |
112 bool _isCanceled = false; | 359 bool _isCanceled = false; |
113 int _pauseCount = 1; | 360 int _pauseCount = 1; |
114 Function _userOnData; | 361 Function _userOnData; |
115 bool _scheduled = false; | 362 bool _scheduled = false; |
116 | 363 |
117 _HttpDetachedStreamSubscription(this._subscription, | 364 _HttpDetachedStreamSubscription( |
118 this._injectData, | 365 this._subscription, this._injectData, this._userOnData); |
119 this._userOnData); | |
120 | 366 |
121 bool get isPaused => _subscription.isPaused; | 367 bool get isPaused => _subscription.isPaused; |
122 | 368 |
123 Future<T> asFuture<T>([T futureValue]) => | 369 Future<T> |
124 _subscription.asFuture<T>(futureValue); | 370 asFuture<T>([T futureValue]) => _subscription.asFuture<T>(futureValue); |
125 | 371 |
126 Future cancel() { | 372 Future cancel() { |
127 _isCanceled = true; | 373 _isCanceled = true; |
128 _injectData = null; | 374 _injectData = null; |
129 return _subscription.cancel(); | 375 return _subscription.cancel(); |
130 } | 376 } |
131 | 377 |
132 void onData(void handleData(List<int> data)) { | 378 void onData(void handleData(List<int> data)) { |
133 _userOnData = handleData; | 379 _userOnData = handleData; |
134 _subscription.onData(handleData); | 380 _subscription.onData(handleData); |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
174 // To ensure that 'subscription.isPaused' is false, we resume the | 420 // To ensure that 'subscription.isPaused' is false, we resume the |
175 // subscription here. This is fine as potential events are delayed. | 421 // subscription here. This is fine as potential events are delayed. |
176 _subscription.resume(); | 422 _subscription.resume(); |
177 if (_userOnData != null) { | 423 if (_userOnData != null) { |
178 _userOnData(data); | 424 _userOnData(data); |
179 } | 425 } |
180 }); | 426 }); |
181 } | 427 } |
182 } | 428 } |
183 | 429 |
184 | |
185 class _HttpDetachedIncoming extends Stream<List<int>> { | 430 class _HttpDetachedIncoming extends Stream<List<int>> { |
186 final StreamSubscription<List<int>> subscription; | 431 final StreamSubscription<List<int>> subscription; |
187 final List<int> bufferedData; | 432 final List<int> bufferedData; |
188 | 433 |
189 _HttpDetachedIncoming(this.subscription, this.bufferedData); | 434 _HttpDetachedIncoming(this.subscription, this.bufferedData); |
190 | 435 |
191 StreamSubscription<List<int>> listen(void onData(List<int> event), | 436 StreamSubscription<List<int>> listen(void onData(List<int> event), |
192 {Function onError, | 437 {Function onError, void onDone(), bool cancelOnError}) { |
193 void onDone(), | |
194 bool cancelOnError}) { | |
195 if (subscription != null) { | 438 if (subscription != null) { |
196 subscription | 439 subscription |
197 ..onData(onData) | 440 ..onData(onData) |
198 ..onError(onError) | 441 ..onError(onError) |
199 ..onDone(onDone); | 442 ..onDone(onDone); |
200 if (bufferedData == null) { | 443 if (bufferedData == null) { |
201 return subscription..resume(); | 444 return subscription..resume(); |
202 } | 445 } |
203 return new _HttpDetachedStreamSubscription(subscription, | 446 return new _HttpDetachedStreamSubscription( |
204 bufferedData, | 447 subscription, bufferedData, onData)..resume(); |
205 onData) | |
206 ..resume(); | |
207 } else { | 448 } else { |
208 // TODO(26379): add test for this branch. | 449 // TODO(26379): add test for this branch. |
209 return new Stream<List<int>>.fromIterable([bufferedData]) | 450 return new Stream<List<int>>.fromIterable([bufferedData]).listen(onData, |
210 .listen(onData, | 451 onError: onError, onDone: onDone, cancelOnError: cancelOnError); |
211 onError: onError, | |
212 onDone: onDone, | |
213 cancelOnError: cancelOnError); | |
214 } | 452 } |
215 } | 453 } |
216 } | 454 } |
217 | 455 |
218 | |
219 /** | 456 /** |
220 * HTTP parser which parses the data stream given to [consume]. | 457 * HTTP parser which parses the data stream given to [consume]. |
221 * | 458 * |
222 * If an HTTP parser error occours, the parser will signal an error to either | 459 * If an HTTP parser error occours, the parser will signal an error to either |
223 * the current _HttpIncoming or the _parser itself. | 460 * the current _HttpIncoming or the _parser itself. |
224 * | 461 * |
225 * The connection upgrades (e.g. switching from HTTP/1.1 to the | 462 * The connection upgrades (e.g. switching from HTTP/1.1 to the |
226 * WebSocket protocol) is handled in a special way. If connection | 463 * WebSocket protocol) is handled in a special way. If connection |
227 * upgrade is specified in the headers, then on the callback to | 464 * upgrade is specified in the headers, then on the callback to |
228 * [:responseStart:] the [:upgrade:] property on the [:HttpParser:] | 465 * [:responseStart:] the [:upgrade:] property on the [:HttpParser:] |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
297 _pauseStateChanged(); | 534 _pauseStateChanged(); |
298 }, | 535 }, |
299 onCancel: () { | 536 onCancel: () { |
300 if (_socketSubscription != null) { | 537 if (_socketSubscription != null) { |
301 _socketSubscription.cancel(); | 538 _socketSubscription.cancel(); |
302 } | 539 } |
303 }); | 540 }); |
304 _reset(); | 541 _reset(); |
305 } | 542 } |
306 | 543 |
307 | |
308 StreamSubscription<_HttpIncoming> listen(void onData(_HttpIncoming event), | 544 StreamSubscription<_HttpIncoming> listen(void onData(_HttpIncoming event), |
309 {Function onError, | 545 {Function onError, void onDone(), bool cancelOnError}) { |
310 void onDone(), | |
311 bool cancelOnError}) { | |
312 return _controller.stream.listen(onData, | 546 return _controller.stream.listen(onData, |
313 onError: onError, | 547 onError: onError, onDone: onDone, cancelOnError: cancelOnError); |
314 onDone: onDone, | |
315 cancelOnError: cancelOnError); | |
316 } | 548 } |
317 | 549 |
318 void listenToStream(Stream<List<int>> stream) { | 550 void listenToStream(Stream<List<int>> stream) { |
319 // Listen to the stream and handle data accordingly. When a | 551 // Listen to the stream and handle data accordingly. When a |
320 // _HttpIncoming is created, _dataPause, _dataResume, _dataDone is | 552 // _HttpIncoming is created, _dataPause, _dataResume, _dataDone is |
321 // given to provide a way of controlling the parser. | 553 // given to provide a way of controlling the parser. |
322 // TODO(ajohnsen): Remove _dataPause, _dataResume and _dataDone and clean up | 554 // TODO(ajohnsen): Remove _dataPause, _dataResume and _dataDone and clean up |
323 // how the _HttpIncoming signals the parser. | 555 // how the _HttpIncoming signals the parser. |
324 _socketSubscription = stream.listen( | 556 _socketSubscription = |
325 _onData, | 557 stream.listen(_onData, onError: _controller.addError, onDone: _onDone); |
326 onError: _controller.addError, | |
327 onDone: _onDone); | |
328 } | 558 } |
329 | 559 |
330 void _parse() { | 560 void _parse() { |
331 try { | 561 try { |
332 _doParse(); | 562 _doParse(); |
333 } catch (e, s) { | 563 } catch (e, s) { |
334 _state = _State.FAILURE; | 564 _state = _State.FAILURE; |
335 _reportError(e, s); | 565 _reportError(e, s); |
336 } | 566 } |
337 } | 567 } |
338 | 568 |
339 // Process end of headers. Returns true if the parser should stop | 569 // Process end of headers. Returns true if the parser should stop |
340 // parsing and return. This will be in case of either an upgrade | 570 // parsing and return. This will be in case of either an upgrade |
341 // request or a request or response with an empty body. | 571 // request or a request or response with an empty body. |
342 bool _headersEnd() { | 572 bool _headersEnd() { |
343 _headers._mutable = false; | 573 _headers._mutable = false; |
344 | 574 |
345 _transferLength = _headers.contentLength; | 575 _transferLength = _headers.contentLength; |
346 // Ignore the Content-Length header if Transfer-Encoding | 576 // Ignore the Content-Length header if Transfer-Encoding |
347 // is chunked (RFC 2616 section 4.4) | 577 // is chunked (RFC 2616 section 4.4) |
348 if (_chunked) _transferLength = -1; | 578 if (_chunked) _transferLength = -1; |
349 | 579 |
350 // If a request message has neither Content-Length nor | 580 // If a request message has neither Content-Length nor |
351 // Transfer-Encoding the message must not have a body (RFC | 581 // Transfer-Encoding the message must not have a body (RFC |
352 // 2616 section 4.3). | 582 // 2616 section 4.3). |
353 if (_messageType == _MessageType.REQUEST && | 583 if (_messageType == _MessageType.REQUEST && |
354 _transferLength < 0 && | 584 _transferLength < 0 && |
355 _chunked == false) { | 585 _chunked == false) { |
356 _transferLength = 0; | 586 _transferLength = 0; |
357 } | 587 } |
358 if (_connectionUpgrade) { | 588 if (_connectionUpgrade) { |
359 _state = _State.UPGRADED; | 589 _state = _State.UPGRADED; |
360 _transferLength = 0; | 590 _transferLength = 0; |
361 } | 591 } |
362 _createIncoming(_transferLength); | 592 _createIncoming(_transferLength); |
363 if (_requestParser) { | 593 if (_requestParser) { |
364 _incoming.method = | 594 _incoming.method = new String.fromCharCodes(_method); |
365 new String.fromCharCodes(_method); | |
366 _incoming.uri = | 595 _incoming.uri = |
367 Uri.parse( | 596 Uri.parse(new String.fromCharCodes(_uri_or_reason_phrase)); |
368 new String.fromCharCodes(_uri_or_reason_phrase)); | |
369 } else { | 597 } else { |
370 _incoming.statusCode = _statusCode; | 598 _incoming.statusCode = _statusCode; |
371 _incoming.reasonPhrase = | 599 _incoming.reasonPhrase = new String.fromCharCodes(_uri_or_reason_phrase); |
372 new String.fromCharCodes(_uri_or_reason_phrase); | |
373 } | 600 } |
374 _method.clear(); | 601 _method.clear(); |
375 _uri_or_reason_phrase.clear(); | 602 _uri_or_reason_phrase.clear(); |
376 if (_connectionUpgrade) { | 603 if (_connectionUpgrade) { |
377 _incoming.upgraded = true; | 604 _incoming.upgraded = true; |
378 _parserCalled = false; | 605 _parserCalled = false; |
379 var tmp = _incoming; | 606 var tmp = _incoming; |
380 _closeIncoming(); | 607 _closeIncoming(); |
381 _controller.add(tmp); | 608 _controller.add(tmp); |
382 return true; | 609 return true; |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
416 void _doParse() { | 643 void _doParse() { |
417 assert(!_parserCalled); | 644 assert(!_parserCalled); |
418 _parserCalled = true; | 645 _parserCalled = true; |
419 if (_state == _State.CLOSED) { | 646 if (_state == _State.CLOSED) { |
420 throw new HttpException("Data on closed connection"); | 647 throw new HttpException("Data on closed connection"); |
421 } | 648 } |
422 if (_state == _State.FAILURE) { | 649 if (_state == _State.FAILURE) { |
423 throw new HttpException("Data on failed connection"); | 650 throw new HttpException("Data on failed connection"); |
424 } | 651 } |
425 while (_buffer != null && | 652 while (_buffer != null && |
426 _index < _buffer.length && | 653 _index < _buffer.length && |
427 _state != _State.FAILURE && | 654 _state != _State.FAILURE && |
428 _state != _State.UPGRADED) { | 655 _state != _State.UPGRADED) { |
429 // Depending on _incoming, we either break on _bodyPaused or _paused. | 656 // Depending on _incoming, we either break on _bodyPaused or _paused. |
430 if ((_incoming != null && _bodyPaused) || | 657 if ((_incoming != null && _bodyPaused) || |
431 (_incoming == null && _paused)) { | 658 (_incoming == null && _paused)) { |
432 _parserCalled = false; | 659 _parserCalled = false; |
433 return; | 660 return; |
434 } | 661 } |
435 int byte = _buffer[_index++]; | 662 int byte = _buffer[_index++]; |
436 switch (_state) { | 663 switch (_state) { |
437 case _State.START: | 664 case _State.START: |
438 if (byte == _Const.HTTP[0]) { | 665 if (byte == _Const.HTTP[0]) { |
(...skipping 12 matching lines...) Expand all Loading... | |
451 _state = _State.REQUEST_LINE_METHOD; | 678 _state = _State.REQUEST_LINE_METHOD; |
452 } | 679 } |
453 break; | 680 break; |
454 | 681 |
455 case _State.METHOD_OR_RESPONSE_HTTP_VERSION: | 682 case _State.METHOD_OR_RESPONSE_HTTP_VERSION: |
456 if (_httpVersionIndex < _Const.HTTP.length && | 683 if (_httpVersionIndex < _Const.HTTP.length && |
457 byte == _Const.HTTP[_httpVersionIndex]) { | 684 byte == _Const.HTTP[_httpVersionIndex]) { |
458 // Continue parsing HTTP version. | 685 // Continue parsing HTTP version. |
459 _httpVersionIndex++; | 686 _httpVersionIndex++; |
460 } else if (_httpVersionIndex == _Const.HTTP.length && | 687 } else if (_httpVersionIndex == _Const.HTTP.length && |
461 byte == _CharCode.SLASH) { | 688 byte == _CharCode.SLASH) { |
462 // HTTP/ parsed. As method is a token this cannot be a | 689 // HTTP/ parsed. As method is a token this cannot be a |
463 // method anymore. | 690 // method anymore. |
464 _httpVersionIndex++; | 691 _httpVersionIndex++; |
465 if (_requestParser) { | 692 if (_requestParser) { |
466 throw new HttpException("Invalid request line"); | 693 throw new HttpException("Invalid request line"); |
467 } | 694 } |
468 _state = _State.RESPONSE_HTTP_VERSION; | 695 _state = _State.RESPONSE_HTTP_VERSION; |
469 } else { | 696 } else { |
470 // Did not parse HTTP version. Expect method instead. | 697 // Did not parse HTTP version. Expect method instead. |
471 for (int i = 0; i < _httpVersionIndex; i++) { | 698 for (int i = 0; i < _httpVersionIndex; i++) { |
(...skipping 11 matching lines...) Expand all Loading... | |
483 } | 710 } |
484 } | 711 } |
485 break; | 712 break; |
486 | 713 |
487 case _State.RESPONSE_HTTP_VERSION: | 714 case _State.RESPONSE_HTTP_VERSION: |
488 if (_httpVersionIndex < _Const.HTTP1DOT.length) { | 715 if (_httpVersionIndex < _Const.HTTP1DOT.length) { |
489 // Continue parsing HTTP version. | 716 // Continue parsing HTTP version. |
490 _expect(byte, _Const.HTTP1DOT[_httpVersionIndex]); | 717 _expect(byte, _Const.HTTP1DOT[_httpVersionIndex]); |
491 _httpVersionIndex++; | 718 _httpVersionIndex++; |
492 } else if (_httpVersionIndex == _Const.HTTP1DOT.length && | 719 } else if (_httpVersionIndex == _Const.HTTP1DOT.length && |
493 byte == _CharCode.ONE) { | 720 byte == _CharCode.ONE) { |
494 // HTTP/1.1 parsed. | 721 // HTTP/1.1 parsed. |
495 _httpVersion = _HttpVersion.HTTP11; | 722 _httpVersion = _HttpVersion.HTTP11; |
496 _persistentConnection = true; | 723 _persistentConnection = true; |
497 _httpVersionIndex++; | 724 _httpVersionIndex++; |
498 } else if (_httpVersionIndex == _Const.HTTP1DOT.length && | 725 } else if (_httpVersionIndex == _Const.HTTP1DOT.length && |
499 byte == _CharCode.ZERO) { | 726 byte == _CharCode.ZERO) { |
500 // HTTP/1.0 parsed. | 727 // HTTP/1.0 parsed. |
501 _httpVersion = _HttpVersion.HTTP10; | 728 _httpVersion = _HttpVersion.HTTP10; |
502 _persistentConnection = false; | 729 _persistentConnection = false; |
503 _httpVersionIndex++; | 730 _httpVersionIndex++; |
504 } else if (_httpVersionIndex == _Const.HTTP1DOT.length + 1) { | 731 } else if (_httpVersionIndex == _Const.HTTP1DOT.length + 1) { |
505 _expect(byte, _CharCode.SP); | 732 _expect(byte, _CharCode.SP); |
506 // HTTP version parsed. | 733 // HTTP version parsed. |
507 _state = _State.RESPONSE_LINE_STATUS_CODE; | 734 _state = _State.RESPONSE_LINE_STATUS_CODE; |
508 } else { | 735 } else { |
509 throw new HttpException("Invalid response line"); | 736 throw new HttpException("Invalid response line"); |
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
601 } | 828 } |
602 break; | 829 break; |
603 | 830 |
604 case _State.RESPONSE_LINE_ENDING: | 831 case _State.RESPONSE_LINE_ENDING: |
605 _expect(byte, _CharCode.LF); | 832 _expect(byte, _CharCode.LF); |
606 _messageType == _MessageType.RESPONSE; | 833 _messageType == _MessageType.RESPONSE; |
607 if (_statusCode < 100 || _statusCode > 599) { | 834 if (_statusCode < 100 || _statusCode > 599) { |
608 throw new HttpException("Invalid response status code"); | 835 throw new HttpException("Invalid response status code"); |
609 } else { | 836 } else { |
610 // Check whether this response will never have a body. | 837 // Check whether this response will never have a body. |
611 if (_statusCode <= 199 || _statusCode == 204 || | 838 if (_statusCode <= 199 || |
839 _statusCode == 204 || | |
612 _statusCode == 304) { | 840 _statusCode == 304) { |
613 _noMessageBody = true; | 841 _noMessageBody = true; |
614 } | 842 } |
615 } | 843 } |
616 _state = _State.HEADER_START; | 844 _state = _State.HEADER_START; |
617 break; | 845 break; |
618 | 846 |
619 case _State.HEADER_START: | 847 case _State.HEADER_START: |
620 _headers = new _HttpHeaders(version); | 848 _headers = new _HttpHeaders(version); |
621 if (byte == _CharCode.CR) { | 849 if (byte == _CharCode.CR) { |
622 _state = _State.HEADER_ENDING; | 850 _state = _State.HEADER_ENDING; |
623 } else if (byte == _CharCode.LF) { | 851 } else if (byte == _CharCode.LF) { |
624 _state = _State.HEADER_ENDING; | 852 _state = _State.HEADER_ENDING; |
625 _index--; // Make the new state see the LF again. | 853 _index--; // Make the new state see the LF again. |
626 } else { | 854 } else { |
627 // Start of new header field. | 855 // Start of new header field. |
628 _headerField.add(_toLowerCaseByte(byte)); | 856 _headerField.add(_toLowerCaseByte(byte)); |
629 _state = _State.HEADER_FIELD; | 857 _state = _State.HEADER_FIELD; |
630 } | 858 } |
631 break; | 859 break; |
632 | 860 |
633 case _State.HEADER_FIELD: | 861 case _State.HEADER_FIELD: |
634 if (byte == _CharCode.COLON) { | 862 if (byte == _CharCode.COLON) { |
635 _state = _State.HEADER_VALUE_START; | 863 _state = _State.HEADER_VALUE_START; |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
674 } else { | 902 } else { |
675 String headerField = new String.fromCharCodes(_headerField); | 903 String headerField = new String.fromCharCodes(_headerField); |
676 String headerValue = new String.fromCharCodes(_headerValue); | 904 String headerValue = new String.fromCharCodes(_headerValue); |
677 if (headerField == "transfer-encoding" && | 905 if (headerField == "transfer-encoding" && |
678 _caseInsensitiveCompare("chunked".codeUnits, _headerValue)) { | 906 _caseInsensitiveCompare("chunked".codeUnits, _headerValue)) { |
679 _chunked = true; | 907 _chunked = true; |
680 } | 908 } |
681 if (headerField == "connection") { | 909 if (headerField == "connection") { |
682 List<String> tokens = _tokenizeFieldValue(headerValue); | 910 List<String> tokens = _tokenizeFieldValue(headerValue); |
683 for (int i = 0; i < tokens.length; i++) { | 911 for (int i = 0; i < tokens.length; i++) { |
684 if (_caseInsensitiveCompare("upgrade".codeUnits, | 912 if (_caseInsensitiveCompare( |
685 tokens[i].codeUnits)) { | 913 "upgrade".codeUnits, tokens[i].codeUnits)) { |
686 _connectionUpgrade = true; | 914 _connectionUpgrade = true; |
687 } | 915 } |
688 _headers._add(headerField, tokens[i]); | 916 _headers._add(headerField, tokens[i]); |
689 } | 917 } |
690 } else { | 918 } else { |
691 _headers._add(headerField, headerValue); | 919 _headers._add(headerField, headerValue); |
692 } | 920 } |
693 _headerField.clear(); | 921 _headerField.clear(); |
694 _headerValue.clear(); | 922 _headerValue.clear(); |
695 | 923 |
696 if (byte == _CharCode.CR) { | 924 if (byte == _CharCode.CR) { |
697 _state = _State.HEADER_ENDING; | 925 _state = _State.HEADER_ENDING; |
698 } else if (byte == _CharCode.LF) { | 926 } else if (byte == _CharCode.LF) { |
699 _state = _State.HEADER_ENDING; | 927 _state = _State.HEADER_ENDING; |
700 _index--; // Make the new state see the LF again. | 928 _index--; // Make the new state see the LF again. |
701 } else { | 929 } else { |
702 // Start of new header field. | 930 // Start of new header field. |
703 _headerField.add(_toLowerCaseByte(byte)); | 931 _headerField.add(_toLowerCaseByte(byte)); |
704 _state = _State.HEADER_FIELD; | 932 _state = _State.HEADER_FIELD; |
705 } | 933 } |
706 } | 934 } |
707 break; | 935 break; |
708 | 936 |
709 case _State.HEADER_ENDING: | 937 case _State.HEADER_ENDING: |
710 _expect(byte, _CharCode.LF); | 938 _expect(byte, _CharCode.LF); |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
765 case _State.BODY: | 993 case _State.BODY: |
766 // The body is not handled one byte at a time but in blocks. | 994 // The body is not handled one byte at a time but in blocks. |
767 _index--; | 995 _index--; |
768 int dataAvailable = _buffer.length - _index; | 996 int dataAvailable = _buffer.length - _index; |
769 if (_remainingContent >= 0 && dataAvailable > _remainingContent) { | 997 if (_remainingContent >= 0 && dataAvailable > _remainingContent) { |
770 dataAvailable = _remainingContent; | 998 dataAvailable = _remainingContent; |
771 } | 999 } |
772 // Always present the data as a view. This way we can handle all | 1000 // Always present the data as a view. This way we can handle all |
773 // cases like this, and the user will not experince different data | 1001 // cases like this, and the user will not experince different data |
774 // typed (which could lead to polymorphic user code). | 1002 // typed (which could lead to polymorphic user code). |
775 List<int> data = new Uint8List.view(_buffer.buffer, | 1003 List<int> data = new Uint8List.view( |
776 _buffer.offsetInBytes + _index, | 1004 _buffer.buffer, _buffer.offsetInBytes + _index, dataAvailable); |
777 dataAvailable); | |
778 _bodyController.add(data); | 1005 _bodyController.add(data); |
779 if (_remainingContent != -1) { | 1006 if (_remainingContent != -1) { |
780 _remainingContent -= data.length; | 1007 _remainingContent -= data.length; |
781 } | 1008 } |
782 _index += data.length; | 1009 _index += data.length; |
783 if (_remainingContent == 0) { | 1010 if (_remainingContent == 0) { |
784 if (!_chunked) { | 1011 if (!_chunked) { |
785 _reset(); | 1012 _reset(); |
786 _closeIncoming(); | 1013 _closeIncoming(); |
787 } else { | 1014 } else { |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
824 void _onDone() { | 1051 void _onDone() { |
825 // onDone cancles the subscription. | 1052 // onDone cancles the subscription. |
826 _socketSubscription = null; | 1053 _socketSubscription = null; |
827 if (_state == _State.CLOSED || _state == _State.FAILURE) return; | 1054 if (_state == _State.CLOSED || _state == _State.FAILURE) return; |
828 | 1055 |
829 if (_incoming != null) { | 1056 if (_incoming != null) { |
830 if (_state != _State.UPGRADED && | 1057 if (_state != _State.UPGRADED && |
831 !(_state == _State.START && !_requestParser) && | 1058 !(_state == _State.START && !_requestParser) && |
832 !(_state == _State.BODY && !_chunked && _transferLength == -1)) { | 1059 !(_state == _State.BODY && !_chunked && _transferLength == -1)) { |
833 _bodyController.addError( | 1060 _bodyController.addError( |
834 new HttpException("Connection closed while receiving data")); | 1061 new HttpException("Connection closed while receiving data")); |
835 } | 1062 } |
836 _closeIncoming(true); | 1063 _closeIncoming(true); |
837 _controller.close(); | 1064 _controller.close(); |
838 return; | 1065 return; |
839 } | 1066 } |
840 // If the connection is idle the HTTP stream is closed. | 1067 // If the connection is idle the HTTP stream is closed. |
841 if (_state == _State.START) { | 1068 if (_state == _State.START) { |
842 if (!_requestParser) { | 1069 if (!_requestParser) { |
843 _reportError(new HttpException( | 1070 _reportError(new HttpException( |
844 "Connection closed before full header was received")); | 1071 "Connection closed before full header was received")); |
845 } | 1072 } |
846 _controller.close(); | 1073 _controller.close(); |
847 return; | 1074 return; |
848 } | 1075 } |
849 | 1076 |
850 if (_state == _State.UPGRADED) { | 1077 if (_state == _State.UPGRADED) { |
851 _controller.close(); | 1078 _controller.close(); |
852 return; | 1079 return; |
853 } | 1080 } |
854 | 1081 |
855 if (_state < _State.FIRST_BODY_STATE) { | 1082 if (_state < _State.FIRST_BODY_STATE) { |
856 _state = _State.FAILURE; | 1083 _state = _State.FAILURE; |
857 // Report the error through the error callback if any. Otherwise | 1084 // Report the error through the error callback if any. Otherwise |
858 // throw the error. | 1085 // throw the error. |
859 _reportError(new HttpException( | 1086 _reportError(new HttpException( |
860 "Connection closed before full header was received")); | 1087 "Connection closed before full header was received")); |
861 _controller.close(); | 1088 _controller.close(); |
862 return; | 1089 return; |
863 } | 1090 } |
864 | 1091 |
865 if (!_chunked && _transferLength == -1) { | 1092 if (!_chunked && _transferLength == -1) { |
866 _state = _State.CLOSED; | 1093 _state = _State.CLOSED; |
867 } else { | 1094 } else { |
868 _state = _State.FAILURE; | 1095 _state = _State.FAILURE; |
869 // Report the error through the error callback if any. Otherwise | 1096 // Report the error through the error callback if any. Otherwise |
870 // throw the error. | 1097 // throw the error. |
871 _reportError(new HttpException( | 1098 _reportError( |
872 "Connection closed before full body was received")); | 1099 new HttpException("Connection closed before full body was received")); |
873 } | 1100 } |
874 _controller.close(); | 1101 _controller.close(); |
875 } | 1102 } |
876 | 1103 |
877 String get version { | 1104 String get version { |
878 switch (_httpVersion) { | 1105 switch (_httpVersion) { |
879 case _HttpVersion.HTTP10: | 1106 case _HttpVersion.HTTP10: |
880 return "1.0"; | 1107 return "1.0"; |
881 case _HttpVersion.HTTP11: | 1108 case _HttpVersion.HTTP11: |
882 return "1.1"; | 1109 return "1.1"; |
883 } | 1110 } |
884 return null; | 1111 return null; |
885 } | 1112 } |
886 | 1113 |
887 int get messageType => _messageType; | 1114 int get messageType => _messageType; |
888 int get transferLength => _transferLength; | 1115 int get transferLength => _transferLength; |
889 bool get upgrade => _connectionUpgrade && _state == _State.UPGRADED; | 1116 bool get upgrade => _connectionUpgrade && _state == _State.UPGRADED; |
890 bool get persistentConnection => _persistentConnection; | 1117 bool get persistentConnection => _persistentConnection; |
891 | 1118 |
892 void set isHead(bool value) { | 1119 void set isHead(bool value) { |
893 if (value) _noMessageBody = true; | 1120 if (value) _noMessageBody = true; |
894 } | 1121 } |
895 | 1122 |
896 _HttpDetachedIncoming detachIncoming() { | 1123 _HttpDetachedIncoming detachIncoming() { |
897 // Simulate detached by marking as upgraded. | 1124 // Simulate detached by marking as upgraded. |
898 _state = _State.UPGRADED; | 1125 _state = _State.UPGRADED; |
899 return new _HttpDetachedIncoming(_socketSubscription, | 1126 return new _HttpDetachedIncoming(_socketSubscription, readUnparsedData()); |
900 readUnparsedData()); | |
901 } | 1127 } |
902 | 1128 |
903 List<int> readUnparsedData() { | 1129 List<int> readUnparsedData() { |
904 if (_buffer == null) return null; | 1130 if (_buffer == null) return null; |
905 if (_index == _buffer.length) return null; | 1131 if (_index == _buffer.length) return null; |
906 var result = _buffer.sublist(_index); | 1132 var result = _buffer.sublist(_index); |
907 _releaseBuffer(); | 1133 _releaseBuffer(); |
908 return result; | 1134 return result; |
909 } | 1135 } |
910 | 1136 |
(...skipping 24 matching lines...) Expand all Loading... | |
935 void _releaseBuffer() { | 1161 void _releaseBuffer() { |
936 _buffer = null; | 1162 _buffer = null; |
937 _index = null; | 1163 _index = null; |
938 } | 1164 } |
939 | 1165 |
940 static bool _isTokenChar(int byte) { | 1166 static bool _isTokenChar(int byte) { |
941 return byte > 31 && byte < 128 && !_Const.SEPARATOR_MAP[byte]; | 1167 return byte > 31 && byte < 128 && !_Const.SEPARATOR_MAP[byte]; |
942 } | 1168 } |
943 | 1169 |
944 static bool _isValueChar(int byte) { | 1170 static bool _isValueChar(int byte) { |
945 return (byte > 31 && byte < 128) || (byte == _CharCode.SP) || | 1171 return (byte > 31 && byte < 128) || |
1172 (byte == _CharCode.SP) || | |
946 (byte == _CharCode.HT); | 1173 (byte == _CharCode.HT); |
947 } | 1174 } |
948 | 1175 |
949 static List<String> _tokenizeFieldValue(String headerValue) { | 1176 static List<String> _tokenizeFieldValue(String headerValue) { |
950 List<String> tokens = new List<String>(); | 1177 List<String> tokens = new List<String>(); |
951 int start = 0; | 1178 int start = 0; |
952 int index = 0; | 1179 int index = 0; |
953 while (index < headerValue.length) { | 1180 while (index < headerValue.length) { |
954 if (headerValue[index] == ",") { | 1181 if (headerValue[index] == ",") { |
955 tokens.add(headerValue.substring(start, index)); | 1182 tokens.add(headerValue.substring(start, index)); |
(...skipping 26 matching lines...) Expand all Loading... | |
982 } | 1209 } |
983 | 1210 |
984 int _expect(int val1, int val2) { | 1211 int _expect(int val1, int val2) { |
985 if (val1 != val2) { | 1212 if (val1 != val2) { |
986 throw new HttpException("Failed to parse HTTP"); | 1213 throw new HttpException("Failed to parse HTTP"); |
987 } | 1214 } |
988 } | 1215 } |
989 | 1216 |
990 int _expectHexDigit(int byte) { | 1217 int _expectHexDigit(int byte) { |
991 if (0x30 <= byte && byte <= 0x39) { | 1218 if (0x30 <= byte && byte <= 0x39) { |
992 return byte - 0x30; // 0 - 9 | 1219 return byte - 0x30; // 0 - 9 |
993 } else if (0x41 <= byte && byte <= 0x46) { | 1220 } else if (0x41 <= byte && byte <= 0x46) { |
994 return byte - 0x41 + 10; // A - F | 1221 return byte - 0x41 + 10; // A - F |
995 } else if (0x61 <= byte && byte <= 0x66) { | 1222 } else if (0x61 <= byte && byte <= 0x66) { |
996 return byte - 0x61 + 10; // a - f | 1223 return byte - 0x61 + 10; // a - f |
997 } else { | 1224 } else { |
998 throw new HttpException("Failed to parse HTTP"); | 1225 throw new HttpException("Failed to parse HTTP"); |
999 } | 1226 } |
1000 } | 1227 } |
1001 | 1228 |
1002 void _createIncoming(int transferLength) { | 1229 void _createIncoming(int transferLength) { |
1003 assert(_incoming == null); | 1230 assert(_incoming == null); |
1004 assert(_bodyController == null); | 1231 assert(_bodyController == null); |
1005 assert(!_bodyPaused); | 1232 assert(!_bodyPaused); |
1006 var incoming; | 1233 var incoming; |
(...skipping 18 matching lines...) Expand all Loading... | |
1025 _pauseStateChanged(); | 1252 _pauseStateChanged(); |
1026 }, | 1253 }, |
1027 onCancel: () { | 1254 onCancel: () { |
1028 if (incoming != _incoming) return; | 1255 if (incoming != _incoming) return; |
1029 if (_socketSubscription != null) { | 1256 if (_socketSubscription != null) { |
1030 _socketSubscription.cancel(); | 1257 _socketSubscription.cancel(); |
1031 } | 1258 } |
1032 _closeIncoming(true); | 1259 _closeIncoming(true); |
1033 _controller.close(); | 1260 _controller.close(); |
1034 }); | 1261 }); |
1035 incoming = _incoming = new _HttpIncoming( | 1262 incoming = _incoming = |
1036 _headers, transferLength, _bodyController.stream); | 1263 new _HttpIncoming(_headers, transferLength, _bodyController.stream); |
1037 _bodyPaused = true; | 1264 _bodyPaused = true; |
1038 _pauseStateChanged(); | 1265 _pauseStateChanged(); |
1039 } | 1266 } |
1040 | 1267 |
1041 void _closeIncoming([bool closing = false]) { | 1268 void _closeIncoming([bool closing = false]) { |
1042 // Ignore multiple close (can happen in re-entrance). | 1269 // Ignore multiple close (can happen in re-entrance). |
1043 if (_incoming == null) return; | 1270 if (_incoming == null) return; |
1044 var tmp = _incoming; | 1271 var tmp = _incoming; |
1045 tmp.close(closing); | 1272 tmp.close(closing); |
1046 _incoming = null; | 1273 _incoming = null; |
(...skipping 17 matching lines...) Expand all Loading... | |
1064 } | 1291 } |
1065 } | 1292 } |
1066 | 1293 |
1067 void _reportError(error, [stackTrace]) { | 1294 void _reportError(error, [stackTrace]) { |
1068 if (_socketSubscription != null) _socketSubscription.cancel(); | 1295 if (_socketSubscription != null) _socketSubscription.cancel(); |
1069 _state = _State.FAILURE; | 1296 _state = _State.FAILURE; |
1070 _controller.addError(error, stackTrace); | 1297 _controller.addError(error, stackTrace); |
1071 _controller.close(); | 1298 _controller.close(); |
1072 } | 1299 } |
1073 } | 1300 } |
OLD | NEW |