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

Side by Side Diff: sdk/lib/io/http_parser.dart

Issue 1078683002: Be more lean when parsing HTTP headers (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Addressed review comments Created 5 years, 8 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 | « no previous file | tests/standalone/io/http_parser_test.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) 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];
(...skipping 316 matching lines...) Expand 10 before | Expand all | Expand 10 after
327 327
328 void _parse() { 328 void _parse() {
329 try { 329 try {
330 _doParse(); 330 _doParse();
331 } catch (e, s) { 331 } catch (e, s) {
332 _state = _State.FAILURE; 332 _state = _State.FAILURE;
333 _reportError(e, s); 333 _reportError(e, s);
334 } 334 }
335 } 335 }
336 336
337 // Process end of headers. Returns true if the parser should stop
338 // parsing and return. This will be in case of either an upgrade
339 // request or a request or response with an empty body.
340 bool _headersEnd() {
341 _headers._mutable = false;
342
343 _transferLength = _headers.contentLength;
344 // Ignore the Content-Length header if Transfer-Encoding
345 // is chunked (RFC 2616 section 4.4)
346 if (_chunked) _transferLength = -1;
347
348 // If a request message has neither Content-Length nor
349 // Transfer-Encoding the message must not have a body (RFC
350 // 2616 section 4.3).
351 if (_messageType == _MessageType.REQUEST &&
352 _transferLength < 0 &&
353 _chunked == false) {
354 _transferLength = 0;
355 }
356 if (_connectionUpgrade) {
357 _state = _State.UPGRADED;
358 _transferLength = 0;
359 }
360 _createIncoming(_transferLength);
361 if (_requestParser) {
362 _incoming.method =
363 new String.fromCharCodes(_method);
364 _incoming.uri =
365 Uri.parse(
366 new String.fromCharCodes(_uri_or_reason_phrase));
367 } else {
368 _incoming.statusCode = _statusCode;
369 _incoming.reasonPhrase =
370 new String.fromCharCodes(_uri_or_reason_phrase);
371 }
372 _method.clear();
373 _uri_or_reason_phrase.clear();
374 if (_connectionUpgrade) {
375 _incoming.upgraded = true;
376 _parserCalled = false;
377 var tmp = _incoming;
378 _closeIncoming();
379 _controller.add(tmp);
380 return true;
381 }
382 if (_transferLength == 0 ||
383 (_messageType == _MessageType.RESPONSE && _noMessageBody)) {
384 _reset();
385 var tmp = _incoming;
386 _closeIncoming();
387 _controller.add(tmp);
388 return false;
389 } else if (_chunked) {
390 _state = _State.CHUNK_SIZE;
391 _remainingContent = 0;
392 } else if (_transferLength > 0) {
393 _remainingContent = _transferLength;
394 _state = _State.BODY;
395 } else {
396 // Neither chunked nor content length. End of body
397 // indicated by close.
398 _state = _State.BODY;
399 }
400 _parserCalled = false;
401 _controller.add(_incoming);
402 return true;
403 }
404
337 // From RFC 2616. 405 // From RFC 2616.
338 // generic-message = start-line 406 // generic-message = start-line
339 // *(message-header CRLF) 407 // *(message-header CRLF)
340 // CRLF 408 // CRLF
341 // [ message-body ] 409 // [ message-body ]
342 // start-line = Request-Line | Status-Line 410 // start-line = Request-Line | Status-Line
343 // Request-Line = Method SP Request-URI SP HTTP-Version CRLF 411 // Request-Line = Method SP Request-URI SP HTTP-Version CRLF
344 // Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF 412 // Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF
345 // message-header = field-name ":" [ field-value ] 413 // message-header = field-name ":" [ field-value ]
346 void _doParse() { 414 void _doParse() {
(...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after
480 _httpVersionIndex++; 548 _httpVersionIndex++;
481 } else if (byte == _CharCode.ZERO) { 549 } else if (byte == _CharCode.ZERO) {
482 // HTTP/1.0 parsed. 550 // HTTP/1.0 parsed.
483 _httpVersion = _HttpVersion.HTTP10; 551 _httpVersion = _HttpVersion.HTTP10;
484 _persistentConnection = false; 552 _persistentConnection = false;
485 _httpVersionIndex++; 553 _httpVersionIndex++;
486 } else { 554 } else {
487 throw new HttpException("Invalid response line"); 555 throw new HttpException("Invalid response line");
488 } 556 }
489 } else { 557 } else {
490 _expect(byte, _CharCode.CR); 558 if (byte == _CharCode.CR) {
491 _state = _State.REQUEST_LINE_ENDING; 559 _state = _State.REQUEST_LINE_ENDING;
560 } else {
561 _expect(byte, _CharCode.LF);
562 _messageType = _MessageType.REQUEST;
563 _state = _State.HEADER_START;
564 }
492 } 565 }
493 break; 566 break;
494 567
495 case _State.REQUEST_LINE_ENDING: 568 case _State.REQUEST_LINE_ENDING:
496 _expect(byte, _CharCode.LF); 569 _expect(byte, _CharCode.LF);
497 _messageType = _MessageType.REQUEST; 570 _messageType = _MessageType.REQUEST;
498 _state = _State.HEADER_START; 571 _state = _State.HEADER_START;
499 break; 572 break;
500 573
501 case _State.RESPONSE_LINE_STATUS_CODE: 574 case _State.RESPONSE_LINE_STATUS_CODE:
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
538 _noMessageBody = true; 611 _noMessageBody = true;
539 } 612 }
540 } 613 }
541 _state = _State.HEADER_START; 614 _state = _State.HEADER_START;
542 break; 615 break;
543 616
544 case _State.HEADER_START: 617 case _State.HEADER_START:
545 _headers = new _HttpHeaders(version); 618 _headers = new _HttpHeaders(version);
546 if (byte == _CharCode.CR) { 619 if (byte == _CharCode.CR) {
547 _state = _State.HEADER_ENDING; 620 _state = _State.HEADER_ENDING;
621 } else if (byte == _CharCode.LF) {
622 if (_headersEnd()) {
623 return;
624 } else {
625 break;
626 }
548 } else { 627 } else {
549 // Start of new header field. 628 // Start of new header field.
550 _headerField.add(_toLowerCaseByte(byte)); 629 _headerField.add(_toLowerCaseByte(byte));
551 _state = _State.HEADER_FIELD; 630 _state = _State.HEADER_FIELD;
552 } 631 }
553 break; 632 break;
554 633
555 case _State.HEADER_FIELD: 634 case _State.HEADER_FIELD:
556 if (byte == _CharCode.COLON) { 635 if (byte == _CharCode.COLON) {
557 _state = _State.HEADER_VALUE_START; 636 _state = _State.HEADER_VALUE_START;
558 } else { 637 } else {
559 if (!_isTokenChar(byte)) { 638 if (!_isTokenChar(byte)) {
560 throw new HttpException("Invalid header field name"); 639 throw new HttpException("Invalid header field name");
561 } 640 }
562 _headerField.add(_toLowerCaseByte(byte)); 641 _headerField.add(_toLowerCaseByte(byte));
563 } 642 }
564 break; 643 break;
565 644
566 case _State.HEADER_VALUE_START: 645 case _State.HEADER_VALUE_START:
567 if (byte == _CharCode.CR) { 646 if (byte == _CharCode.CR) {
568 _state = _State.HEADER_VALUE_FOLDING_OR_ENDING; 647 _state = _State.HEADER_VALUE_FOLDING_OR_ENDING;
648 } else if (byte == _CharCode.LF) {
649 _state = _State.HEADER_VALUE_FOLD_OR_END;
569 } else if (byte != _CharCode.SP && byte != _CharCode.HT) { 650 } else if (byte != _CharCode.SP && byte != _CharCode.HT) {
570 // Start of new header value. 651 // Start of new header value.
571 _headerValue.add(byte); 652 _headerValue.add(byte);
572 _state = _State.HEADER_VALUE; 653 _state = _State.HEADER_VALUE;
573 } 654 }
574 break; 655 break;
575 656
576 case _State.HEADER_VALUE: 657 case _State.HEADER_VALUE:
577 if (byte == _CharCode.CR) { 658 if (byte == _CharCode.CR) {
578 _state = _State.HEADER_VALUE_FOLDING_OR_ENDING; 659 _state = _State.HEADER_VALUE_FOLDING_OR_ENDING;
660 } else if (byte == _CharCode.LF) {
661 _state = _State.HEADER_VALUE_FOLD_OR_END;
579 } else { 662 } else {
580 _headerValue.add(byte); 663 _headerValue.add(byte);
581 } 664 }
582 break; 665 break;
583 666
584 case _State.HEADER_VALUE_FOLDING_OR_ENDING: 667 case _State.HEADER_VALUE_FOLDING_OR_ENDING:
585 _expect(byte, _CharCode.LF); 668 _expect(byte, _CharCode.LF);
586 _state = _State.HEADER_VALUE_FOLD_OR_END; 669 _state = _State.HEADER_VALUE_FOLD_OR_END;
587 break; 670 break;
588 671
(...skipping 17 matching lines...) Expand all
606 _headers._add(headerField, tokens[i]); 689 _headers._add(headerField, tokens[i]);
607 } 690 }
608 } else { 691 } else {
609 _headers._add(headerField, headerValue); 692 _headers._add(headerField, headerValue);
610 } 693 }
611 _headerField.clear(); 694 _headerField.clear();
612 _headerValue.clear(); 695 _headerValue.clear();
613 696
614 if (byte == _CharCode.CR) { 697 if (byte == _CharCode.CR) {
615 _state = _State.HEADER_ENDING; 698 _state = _State.HEADER_ENDING;
699 } else if (byte == _CharCode.LF) {
700 if (_headersEnd()) {
701 return;
702 } else {
703 break;
704 }
616 } else { 705 } else {
617 // Start of new header field. 706 // Start of new header field.
618 _headerField.add(_toLowerCaseByte(byte)); 707 _headerField.add(_toLowerCaseByte(byte));
619 _state = _State.HEADER_FIELD; 708 _state = _State.HEADER_FIELD;
620 } 709 }
621 } 710 }
622 break; 711 break;
623 712
624 case _State.HEADER_ENDING: 713 case _State.HEADER_ENDING:
625 _expect(byte, _CharCode.LF); 714 _expect(byte, _CharCode.LF);
626 _headers._mutable = false; 715 if (_headersEnd()) {
627 716 return;
628 _transferLength = _headers.contentLength; 717 } else {
629 // Ignore the Content-Length header if Transfer-Encoding 718 break;
630 // is chunked (RFC 2616 section 4.4)
631 if (_chunked) _transferLength = -1;
632
633 // If a request message has neither Content-Length nor
634 // Transfer-Encoding the message must not have a body (RFC
635 // 2616 section 4.3).
636 if (_messageType == _MessageType.REQUEST &&
637 _transferLength < 0 &&
638 _chunked == false) {
639 _transferLength = 0;
640 } 719 }
641 if (_connectionUpgrade) {
642 _state = _State.UPGRADED;
643 _transferLength = 0;
644 }
645 _createIncoming(_transferLength);
646 if (_requestParser) {
647 _incoming.method =
648 new String.fromCharCodes(_method);
649 _incoming.uri =
650 Uri.parse(
651 new String.fromCharCodes(_uri_or_reason_phrase));
652 } else {
653 _incoming.statusCode = _statusCode;
654 _incoming.reasonPhrase =
655 new String.fromCharCodes(_uri_or_reason_phrase);
656 }
657 _method.clear();
658 _uri_or_reason_phrase.clear();
659 if (_connectionUpgrade) {
660 _incoming.upgraded = true;
661 _parserCalled = false;
662 var tmp = _incoming;
663 _closeIncoming();
664 _controller.add(tmp);
665 return;
666 }
667 if (_transferLength == 0 ||
668 (_messageType == _MessageType.RESPONSE && _noMessageBody)) {
669 _reset();
670 var tmp = _incoming;
671 _closeIncoming();
672 _controller.add(tmp);
673 break;
674 } else if (_chunked) {
675 _state = _State.CHUNK_SIZE;
676 _remainingContent = 0;
677 } else if (_transferLength > 0) {
678 _remainingContent = _transferLength;
679 _state = _State.BODY;
680 } else {
681 // Neither chunked nor content length. End of body
682 // indicated by close.
683 _state = _State.BODY;
684 }
685 _parserCalled = false;
686 _controller.add(_incoming);
687 return; 720 return;
688 721
689 case _State.CHUNK_SIZE_STARTING_CR: 722 case _State.CHUNK_SIZE_STARTING_CR:
690 _expect(byte, _CharCode.CR); 723 _expect(byte, _CharCode.CR);
691 _state = _State.CHUNK_SIZE_STARTING_LF; 724 _state = _State.CHUNK_SIZE_STARTING_LF;
692 break; 725 break;
693 726
694 case _State.CHUNK_SIZE_STARTING_LF: 727 case _State.CHUNK_SIZE_STARTING_LF:
695 _expect(byte, _CharCode.LF); 728 _expect(byte, _CharCode.LF);
696 _state = _State.CHUNK_SIZE; 729 _state = _State.CHUNK_SIZE;
(...skipping 338 matching lines...) Expand 10 before | Expand all | Expand 10 after
1035 } 1068 }
1036 } 1069 }
1037 1070
1038 void _reportError(error, [stackTrace]) { 1071 void _reportError(error, [stackTrace]) {
1039 if (_socketSubscription != null) _socketSubscription.cancel(); 1072 if (_socketSubscription != null) _socketSubscription.cancel();
1040 _state = _State.FAILURE; 1073 _state = _State.FAILURE;
1041 _controller.addError(error, stackTrace); 1074 _controller.addError(error, stackTrace);
1042 _controller.close(); 1075 _controller.close();
1043 } 1076 }
1044 } 1077 }
OLDNEW
« no previous file with comments | « no previous file | tests/standalone/io/http_parser_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698