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

Side by Side Diff: runtime/bin/http_parser.dart

Issue 9812005: Change the message body handling in the HTTP parser (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Addressed review comments Created 8 years, 9 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
« no previous file with comments | « runtime/bin/http_impl.dart ('k') | tests/standalone/src/io/HttpParserTest.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) 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 // Global constants. 5 // Global constants.
6 class _Const { 6 class _Const {
7 // Bytes for "HTTP/1.0". 7 // Bytes for "HTTP/1.0".
8 static final HTTP10 = const [72, 84, 84, 80, 47, 49, 46, 48]; 8 static final HTTP10 = const [72, 84, 84, 80, 47, 49, 46, 48];
9 // Bytes for "HTTP/1.1". 9 // Bytes for "HTTP/1.1".
10 static final HTTP11 = const [72, 84, 84, 80, 47, 49, 46, 49]; 10 static final HTTP11 = const [72, 84, 84, 80, 47, 49, 46, 49];
11 11
12 static final END_CHUNKED = const [0x30, 13, 10, 13, 10]; 12 static final END_CHUNKED = const [0x30, 13, 10, 13, 10];
13 } 13 }
14 14
15 15
16 // Frequently used character codes. 16 // Frequently used character codes.
17 class _CharCode { 17 class _CharCode {
18 static final int HT = 9; 18 static final int HT = 9;
19 static final int LF = 10; 19 static final int LF = 10;
20 static final int CR = 13; 20 static final int CR = 13;
21 static final int SP = 32; 21 static final int SP = 32;
22 static final int COLON = 58; 22 static final int COLON = 58;
23 static final int SEMI_COLON = 59;
23 } 24 }
24 25
25 26
26 // States of the HTTP parser state machine. 27 // States of the HTTP parser state machine.
27 class _State { 28 class _State {
28 static final int START = 0; 29 static final int START = 0;
29 static final int METHOD_OR_HTTP_VERSION = 1; 30 static final int METHOD_OR_HTTP_VERSION = 1;
30 static final int REQUEST_LINE_METHOD = 2; 31 static final int REQUEST_LINE_METHOD = 2;
31 static final int REQUEST_LINE_URI = 3; 32 static final int REQUEST_LINE_URI = 3;
32 static final int REQUEST_LINE_HTTP_VERSION = 4; 33 static final int REQUEST_LINE_HTTP_VERSION = 4;
33 static final int REQUEST_LINE_ENDING = 5; 34 static final int REQUEST_LINE_ENDING = 5;
34 static final int RESPONSE_LINE_STATUS_CODE = 6; 35 static final int RESPONSE_LINE_STATUS_CODE = 6;
35 static final int RESPONSE_LINE_REASON_PHRASE = 7; 36 static final int RESPONSE_LINE_REASON_PHRASE = 7;
36 static final int RESPONSE_LINE_ENDING = 8; 37 static final int RESPONSE_LINE_ENDING = 8;
37 static final int HEADER_START = 9; 38 static final int HEADER_START = 9;
38 static final int HEADER_FIELD = 10; 39 static final int HEADER_FIELD = 10;
39 static final int HEADER_VALUE_START = 11; 40 static final int HEADER_VALUE_START = 11;
40 static final int HEADER_VALUE = 12; 41 static final int HEADER_VALUE = 12;
41 static final int HEADER_VALUE_FOLDING_OR_ENDING = 13; 42 static final int HEADER_VALUE_FOLDING_OR_ENDING = 13;
42 static final int HEADER_VALUE_FOLD_OR_END = 14; 43 static final int HEADER_VALUE_FOLD_OR_END = 14;
43 static final int HEADER_ENDING = 15; 44 static final int HEADER_ENDING = 15;
44 static final int CHUNK_SIZE_STARTING_CR = 16; 45 static final int CHUNK_SIZE_STARTING_CR = 16;
45 static final int CHUNK_SIZE_STARTING_LF = 17; 46 static final int CHUNK_SIZE_STARTING_LF = 17;
46 static final int CHUNK_SIZE = 18; 47 static final int CHUNK_SIZE = 18;
47 static final int CHUNK_SIZE_ENDING = 19; 48 static final int CHUNK_SIZE_EXTENSION = 19;
48 static final int CHUNKED_BODY_DONE_CR = 20; 49 static final int CHUNK_SIZE_ENDING = 20;
49 static final int CHUNKED_BODY_DONE_LF = 21; 50 static final int CHUNKED_BODY_DONE_CR = 21;
50 static final int BODY = 22; 51 static final int CHUNKED_BODY_DONE_LF = 22;
52 static final int BODY = 23;
51 } 53 }
52 54
53 55
56 // States of the HTTP parser state machine.
57 class _MessageType {
58 static final int UNDETERMINED = 0;
59 static final int REQUEST = 1;
60 static final int RESPONSE = 0;
61 }
62
63
54 /** 64 /**
55 * HTTP parser which parses the HTTP stream as data is supplied 65 * HTTP parser which parses the HTTP stream as data is supplied
56 * through the writeList method. As the data is parsed the events 66 * through the writeList method. As the data is parsed the events
57 * RequestStart 67 * RequestStart
68 * ResponseStart
58 * UriReceived 69 * UriReceived
59 * HeaderReceived 70 * HeaderReceived
60 * HeadersComplete 71 * HeadersComplete
61 * DataReceived 72 * DataReceived
62 * DataEnd 73 * DataEnd
63 * are generated. 74 * are generated.
64 * Currently only HTTP requests with Content-Length header are supported. 75 * Currently only HTTP requests with Content-Length header are supported.
65 */ 76 */
66 class _HttpParser { 77 class _HttpParser {
67 _HttpParser() { 78 _HttpParser() {
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after
135 _expect(byte, _Const.HTTP11[_httpVersionIndex]); 146 _expect(byte, _Const.HTTP11[_httpVersionIndex]);
136 _httpVersionIndex++; 147 _httpVersionIndex++;
137 } else { 148 } else {
138 _expect(byte, _CharCode.CR); 149 _expect(byte, _CharCode.CR);
139 _state = _State.REQUEST_LINE_ENDING; 150 _state = _State.REQUEST_LINE_ENDING;
140 } 151 }
141 break; 152 break;
142 153
143 case _State.REQUEST_LINE_ENDING: 154 case _State.REQUEST_LINE_ENDING:
144 _expect(byte, _CharCode.LF); 155 _expect(byte, _CharCode.LF);
156 _messageType = _MessageType.REQUEST;
145 if (requestStart != null) { 157 if (requestStart != null) {
146 requestStart(_method_or_status_code.toString(), 158 requestStart(_method_or_status_code.toString(),
147 _uri_or_reason_phrase.toString()); 159 _uri_or_reason_phrase.toString());
148 } 160 }
149 _method_or_status_code.clear(); 161 _method_or_status_code.clear();
150 _uri_or_reason_phrase.clear(); 162 _uri_or_reason_phrase.clear();
151 _state = _State.HEADER_START; 163 _state = _State.HEADER_START;
152 break; 164 break;
153 165
154 case _State.RESPONSE_LINE_STATUS_CODE: 166 case _State.RESPONSE_LINE_STATUS_CODE:
(...skipping 12 matching lines...) Expand all
167 case _State.RESPONSE_LINE_REASON_PHRASE: 179 case _State.RESPONSE_LINE_REASON_PHRASE:
168 if (byte == _CharCode.CR) { 180 if (byte == _CharCode.CR) {
169 _state = _State.RESPONSE_LINE_ENDING; 181 _state = _State.RESPONSE_LINE_ENDING;
170 } else { 182 } else {
171 _uri_or_reason_phrase.addCharCode(byte); 183 _uri_or_reason_phrase.addCharCode(byte);
172 } 184 }
173 break; 185 break;
174 186
175 case _State.RESPONSE_LINE_ENDING: 187 case _State.RESPONSE_LINE_ENDING:
176 _expect(byte, _CharCode.LF); 188 _expect(byte, _CharCode.LF);
177 // TODO(sgjesse): Check for valid status code. 189 _messageType == _MessageType.RESPONSE;
178 if (responseStart != null) { 190 if (responseStart != null) {
179 responseStart(Math.parseInt(_method_or_status_code.toString()), 191 int statusCode = Math.parseInt(_method_or_status_code.toString());
180 _uri_or_reason_phrase.toString()); 192 if (statusCode < 100 || statusCode > 599) {
193 if (error != null) error("Invalid response status code");
194 _failure = true;
195 } else {
196 // Check whether this response will never have a body.
197 _noMessageBody =
198 statusCode <= 199 || statusCode == 204 || statusCode == 304;
199 responseStart(statusCode, _uri_or_reason_phrase.toString());
200 }
181 } 201 }
182 _method_or_status_code.clear(); 202 _method_or_status_code.clear();
183 _uri_or_reason_phrase.clear(); 203 _uri_or_reason_phrase.clear();
184 _state = _State.HEADER_START; 204 _state = _State.HEADER_START;
185 break; 205 break;
186 206
187 case _State.HEADER_START: 207 case _State.HEADER_START:
188 if (byte == _CharCode.CR) { 208 if (byte == _CharCode.CR) {
189 _state = _State.HEADER_ENDING; 209 _state = _State.HEADER_ENDING;
190 } else { 210 } else {
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
254 _headerField.addCharCode(_toLowerCase(byte)); 274 _headerField.addCharCode(_toLowerCase(byte));
255 _state = _State.HEADER_FIELD; 275 _state = _State.HEADER_FIELD;
256 } 276 }
257 } 277 }
258 break; 278 break;
259 279
260 case _State.HEADER_ENDING: 280 case _State.HEADER_ENDING:
261 _expect(byte, _CharCode.LF); 281 _expect(byte, _CharCode.LF);
262 if (headersComplete != null) headersComplete(); 282 if (headersComplete != null) headersComplete();
263 283
264 // If there is no data get ready to process the next request.
265 if (_chunked) { 284 if (_chunked) {
266 _state = _State.CHUNK_SIZE; 285 _state = _State.CHUNK_SIZE;
267 _remainingContent = 0; 286 _remainingContent = 0;
268 } else if (_contentLength == 0) { 287 } else if (_contentLength == 0 ||
288 (_messageType == _MessageType.REQUEST &&
289 _contentLength == -1) ||
290 (_messageType == _MessageType.RESPONSE &&
291 (_noMessageBody || _responseToMethod == "HEAD"))) {
292 // If there is no message body get ready to process the
293 // next request.
269 if (dataEnd != null) dataEnd(); 294 if (dataEnd != null) dataEnd();
270 _state = _State.START; 295 _state = _State.START;
271 } else if (_contentLength > 0) { 296 } else if (_contentLength > 0) {
272 _remainingContent = _contentLength; 297 _remainingContent = _contentLength;
273 _state = _State.BODY; 298 _state = _State.BODY;
274 } else { 299 } else {
275 // Neither chunked nor content length. End of body 300 // Neither chunked nor content length. End of body
276 // indicated by close. 301 // indicated by close.
277 _state = _State.BODY; 302 _state = _State.BODY;
278 } 303 }
279 break; 304 break;
280 305
281 case _State.CHUNK_SIZE_STARTING_CR: 306 case _State.CHUNK_SIZE_STARTING_CR:
282 _expect(byte, _CharCode.CR); 307 _expect(byte, _CharCode.CR);
283 _state = _State.CHUNK_SIZE_STARTING_LF; 308 _state = _State.CHUNK_SIZE_STARTING_LF;
284 break; 309 break;
285 310
286 case _State.CHUNK_SIZE_STARTING_LF: 311 case _State.CHUNK_SIZE_STARTING_LF:
287 _expect(byte, _CharCode.LF); 312 _expect(byte, _CharCode.LF);
288 _state = _State.CHUNK_SIZE; 313 _state = _State.CHUNK_SIZE;
289 break; 314 break;
290 315
291 case _State.CHUNK_SIZE: 316 case _State.CHUNK_SIZE:
292 if (byte == _CharCode.CR) { 317 if (byte == _CharCode.CR) {
293 _state = _State.CHUNK_SIZE_ENDING; 318 _state = _State.CHUNK_SIZE_ENDING;
319 } else if (byte == _CharCode.SEMI_COLON) {
320 _state = _State.CHUNK_SIZE_EXTENSION;
294 } else { 321 } else {
295 int value = _expectHexDigit(byte); 322 int value = _expectHexDigit(byte);
296 _remainingContent = _remainingContent * 16 + value; 323 _remainingContent = _remainingContent * 16 + value;
297 } 324 }
298 break; 325 break;
299 326
327 case _State.CHUNK_SIZE_EXTENSION:
328 if (byte == _CharCode.CR) {
329 _state = _State.CHUNK_SIZE_ENDING;
330 }
331 break;
332
300 case _State.CHUNK_SIZE_ENDING: 333 case _State.CHUNK_SIZE_ENDING:
301 _expect(byte, _CharCode.LF); 334 _expect(byte, _CharCode.LF);
302 if (_remainingContent > 0) { 335 if (_remainingContent > 0) {
303 _state = _State.BODY; 336 _state = _State.BODY;
304 } else { 337 } else {
305 _state = _State.CHUNKED_BODY_DONE_CR; 338 _state = _State.CHUNKED_BODY_DONE_CR;
306 } 339 }
307 break; 340 break;
308 341
309 case _State.CHUNKED_BODY_DONE_CR: 342 case _State.CHUNKED_BODY_DONE_CR:
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
363 int connectionClosed() { 396 int connectionClosed() {
364 if (!_chunked && _contentLength == -1) { 397 if (!_chunked && _contentLength == -1) {
365 if (dataEnd != null) dataEnd(); 398 if (dataEnd != null) dataEnd();
366 } else { 399 } else {
367 if (error != null) { 400 if (error != null) {
368 error("Connection closed before full body was received"); 401 error("Connection closed before full body was received");
369 } 402 }
370 } 403 }
371 } 404 }
372 405
406 int get messageType() => _messageType;
373 int get contentLength() => _contentLength; 407 int get contentLength() => _contentLength;
374 bool get keepAlive() => _keepAlive; 408 bool get keepAlive() => _keepAlive;
375 409
410 void set responseToMethod(String method) => _responseToMethod = method;
411
376 _reset() { 412 _reset() {
377 _state = _State.START; 413 _state = _State.START;
378 _failure = false; 414 _failure = false;
415 _messageType = _MessageType.UNDETERMINED;
379 _headerField = new StringBuffer(); 416 _headerField = new StringBuffer();
380 _headerValue = new StringBuffer(); 417 _headerValue = new StringBuffer();
381 _method_or_status_code = new StringBuffer(); 418 _method_or_status_code = new StringBuffer();
382 _uri_or_reason_phrase = new StringBuffer(); 419 _uri_or_reason_phrase = new StringBuffer();
383 420
384 _contentLength = -1; 421 _contentLength = -1;
385 _keepAlive = false; 422 _keepAlive = false;
386 _chunked = false; 423 _chunked = false;
424
425 _noMessageBody = false;
426 _responseToMethod = null;
387 _remainingContent = null; 427 _remainingContent = null;
388 } 428 }
389 429
390 int _toLowerCase(int byte) { 430 int _toLowerCase(int byte) {
391 final int aCode = "A".charCodeAt(0); 431 final int aCode = "A".charCodeAt(0);
392 final int zCode = "Z".charCodeAt(0); 432 final int zCode = "Z".charCodeAt(0);
393 final int delta = "a".charCodeAt(0) - aCode; 433 final int delta = "a".charCodeAt(0) - aCode;
394 return (aCode <= byte && byte <= zCode) ? byte + delta : byte; 434 return (aCode <= byte && byte <= zCode) ? byte + delta : byte;
395 } 435 }
396 436
(...skipping 13 matching lines...) Expand all
410 return byte - 0x61 + 10; // a - f 450 return byte - 0x61 + 10; // a - f
411 } else { 451 } else {
412 _failure = true; 452 _failure = true;
413 return 0; 453 return 0;
414 } 454 }
415 } 455 }
416 456
417 int _state; 457 int _state;
418 bool _failure; 458 bool _failure;
419 int _httpVersionIndex; 459 int _httpVersionIndex;
460 int _messageType;
420 StringBuffer _method_or_status_code; 461 StringBuffer _method_or_status_code;
421 StringBuffer _uri_or_reason_phrase; 462 StringBuffer _uri_or_reason_phrase;
422 StringBuffer _headerField; 463 StringBuffer _headerField;
423 StringBuffer _headerValue; 464 StringBuffer _headerValue;
424 465
425 int _contentLength; 466 int _contentLength;
426 bool _keepAlive; 467 bool _keepAlive;
427 bool _chunked; 468 bool _chunked;
428 469
470 bool _noMessageBody;
471 String _responseToMethod; // Indicates the method used for the request.
429 int _remainingContent; 472 int _remainingContent;
430 473
431 // Callbacks. 474 // Callbacks.
432 Function requestStart; 475 Function requestStart;
433 Function responseStart; 476 Function responseStart;
434 Function headerReceived; 477 Function headerReceived;
435 Function headersComplete; 478 Function headersComplete;
436 Function dataReceived; 479 Function dataReceived;
437 Function dataEnd; 480 Function dataEnd;
438 Function error; 481 Function error;
439 } 482 }
OLDNEW
« no previous file with comments | « runtime/bin/http_impl.dart ('k') | tests/standalone/src/io/HttpParserTest.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698