OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 // The rules for header parsing were borrowed from Firefox: | 5 // The rules for header parsing were borrowed from Firefox: |
6 // http://lxr.mozilla.org/seamonkey/source/netwerk/protocol/http/src/nsHttpRespo
nseHead.cpp | 6 // http://lxr.mozilla.org/seamonkey/source/netwerk/protocol/http/src/nsHttpRespo
nseHead.cpp |
7 // The rules for parsing content-types were also borrowed from Firefox: | 7 // The rules for parsing content-types were also borrowed from Firefox: |
8 // http://lxr.mozilla.org/mozilla/source/netwerk/base/src/nsURLHelper.cpp#834 | 8 // http://lxr.mozilla.org/mozilla/source/netwerk/base/src/nsURLHelper.cpp#834 |
9 | 9 |
10 #include "net/http/http_response_headers.h" | 10 #include "net/http/http_response_headers.h" |
(...skipping 602 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
613 bool HttpResponseHeaders::HasHeader(const base::StringPiece& name) const { | 613 bool HttpResponseHeaders::HasHeader(const base::StringPiece& name) const { |
614 return FindHeader(0, name) != std::string::npos; | 614 return FindHeader(0, name) != std::string::npos; |
615 } | 615 } |
616 | 616 |
617 HttpResponseHeaders::HttpResponseHeaders() : response_code_(-1) { | 617 HttpResponseHeaders::HttpResponseHeaders() : response_code_(-1) { |
618 } | 618 } |
619 | 619 |
620 HttpResponseHeaders::~HttpResponseHeaders() { | 620 HttpResponseHeaders::~HttpResponseHeaders() { |
621 } | 621 } |
622 | 622 |
| 623 // Function to parse HTTP Version in accordance to |
| 624 // RFC2616 sec 3.1: HTTP-Version = "HTTP" "/" 1*DIGIT "." 1*DIGIT |
| 625 // if input string is valid, returns corresponding number in value |
| 626 // else returns false |
| 627 bool HttpResponseHeaders::ParseVersionInternal( |
| 628 std::string::const_iterator begin, |
| 629 std::string::const_iterator end, |
| 630 uint32* value) { |
| 631 std::string error_msg; |
| 632 if(!base::StringToUint(StringPiece(begin, end), value)) { |
| 633 if(*value == 0) { |
| 634 if(begin == end) { |
| 635 error_msg = "Empty String!!!"; |
| 636 } else if(!(*begin >= '0' && *begin <= '9')) { |
| 637 error_msg = "Invalid char at beginning!!!"; |
| 638 } else { |
| 639 error_msg = "Underflow!!!"; |
| 640 } |
| 641 } else if(*value == 0xFFFFFFFF) { |
| 642 error_msg = "Overflow!!!"; |
| 643 } else if(!(*(end-1) >= '0' && *(end-1) <= '9')) { |
| 644 error_msg = "Invalid char at end!!!"; |
| 645 } else { |
| 646 error_msg = "Invalid value!!!"; |
| 647 } |
| 648 DVLOG(1) << error_msg; |
| 649 return false; |
| 650 } |
| 651 return true; |
| 652 } |
| 653 |
623 // Note: this implementation implicitly assumes that line_end points at a valid | 654 // Note: this implementation implicitly assumes that line_end points at a valid |
624 // sentinel character (such as '\0'). | 655 // sentinel character (such as '\0'). |
625 // static | 656 // static |
626 HttpVersion HttpResponseHeaders::ParseVersion( | 657 HttpVersion HttpResponseHeaders::ParseVersion( |
627 std::string::const_iterator line_begin, | 658 std::string::const_iterator line_begin, |
628 std::string::const_iterator line_end) { | 659 std::string::const_iterator line_end) { |
629 std::string::const_iterator p = line_begin; | 660 std::string::const_iterator p = line_begin; |
630 | 661 |
631 // RFC2616 sec 3.1: HTTP-Version = "HTTP" "/" 1*DIGIT "." 1*DIGIT | |
632 // TODO: (1*DIGIT apparently means one or more digits, but we only handle 1). | |
633 // TODO: handle leading zeros, which is allowed by the rfc1616 sec 3.1. | |
634 | |
635 if ((line_end - p < 4) || !LowerCaseEqualsASCII(p, p + 4, "http")) { | 662 if ((line_end - p < 4) || !LowerCaseEqualsASCII(p, p + 4, "http")) { |
636 DVLOG(1) << "missing status line"; | 663 DVLOG(1) << "missing status line"; |
637 return HttpVersion(); | 664 return HttpVersion(); |
638 } | 665 } |
639 | 666 |
640 p += 4; | 667 p += 4; |
641 | 668 |
642 if (p >= line_end || *p != '/') { | 669 if (p >= line_end || *p != '/') { |
643 DVLOG(1) << "missing version"; | 670 DVLOG(1) << "missing version"; |
644 return HttpVersion(); | 671 return HttpVersion(); |
645 } | 672 } |
646 | 673 |
647 std::string::const_iterator dot = std::find(p, line_end, '.'); | 674 std::string::const_iterator dot = std::find(p, line_end, '.'); |
648 if (dot == line_end) { | 675 std::string::const_iterator end_of_minor = dot+1; |
649 DVLOG(1) << "malformed version"; | 676 |
| 677 // find end of minor. |
| 678 while(*end_of_minor != ' ') |
| 679 end_of_minor++; |
| 680 |
| 681 ++p; // from / to first digit. |
| 682 uint32 major = 0; |
| 683 uint32 minor = 0; |
| 684 |
| 685 if (ParseVersionInternal(p, dot, &major) && |
| 686 ParseVersionInternal(dot + 1, end_of_minor, &minor)) { |
| 687 DVLOG(1) << "ParseVersion success!!!"; |
| 688 return HttpVersion(major, minor); |
| 689 } else { |
| 690 DVLOG(1) << "ParseVersion fail!!!"; |
650 return HttpVersion(); | 691 return HttpVersion(); |
651 } | 692 } |
652 | |
653 ++p; // from / to first digit. | |
654 ++dot; // from . to second digit. | |
655 | |
656 if (!(*p >= '0' && *p <= '9' && *dot >= '0' && *dot <= '9')) { | |
657 DVLOG(1) << "malformed version number"; | |
658 return HttpVersion(); | |
659 } | |
660 | |
661 uint16 major = *p - '0'; | |
662 uint16 minor = *dot - '0'; | |
663 | |
664 return HttpVersion(major, minor); | |
665 } | 693 } |
666 | 694 |
667 // Note: this implementation implicitly assumes that line_end points at a valid | 695 // Note: this implementation implicitly assumes that line_end points at a valid |
668 // sentinel character (such as '\0'). | 696 // sentinel character (such as '\0'). |
669 void HttpResponseHeaders::ParseStatusLine( | 697 void HttpResponseHeaders::ParseStatusLine( |
670 std::string::const_iterator line_begin, | 698 std::string::const_iterator line_begin, |
671 std::string::const_iterator line_end, | 699 std::string::const_iterator line_end, |
672 bool has_headers) { | 700 bool has_headers) { |
673 // Extract the version number | 701 // Extract the version number |
674 parsed_http_version_ = ParseVersion(line_begin, line_end); | 702 parsed_http_version_ = ParseVersion(line_begin, line_end); |
675 | 703 |
676 // Clamp the version number to one of: {0.9, 1.0, 1.1} | 704 //Allow mulitple digits in major and minor values of HTTP Version. |
677 if (parsed_http_version_ == HttpVersion(0, 9) && !has_headers) { | 705 //If parseVersion failed, keep version as 1.0 as per old logic |
678 http_version_ = HttpVersion(0, 9); | 706 //If version is 0.9 and has headers, keep version as 1.0 as per old logic |
679 raw_headers_ = "HTTP/0.9"; | 707 //If version is 0.9 and has no headers, keep version as 0.9 as per old logic |
680 } else if (parsed_http_version_ >= HttpVersion(1, 1)) { | 708 //Else in all other cases, http_version will be same as parsed_http_version |
681 http_version_ = HttpVersion(1, 1); | 709 if (parsed_http_version_ == HttpVersion()) { |
682 raw_headers_ = "HTTP/1.1"; | |
683 } else { | |
684 // Treat everything else like HTTP 1.0 | |
685 http_version_ = HttpVersion(1, 0); | 710 http_version_ = HttpVersion(1, 0); |
686 raw_headers_ = "HTTP/1.0"; | 711 raw_headers_ = "HTTP/1.0"; |
| 712 } else if (parsed_http_version_ == HttpVersion(0, 9) && has_headers) { |
| 713 http_version_ = HttpVersion(1, 0); |
| 714 raw_headers_ = "HTTP/1.0"; |
| 715 } else { |
| 716 http_version_ = parsed_http_version_; |
| 717 raw_headers_ = "HTTP/"; |
| 718 raw_headers_.append(base::UintToString(http_version_.major_value())); |
| 719 raw_headers_.append("."); |
| 720 raw_headers_.append(base::UintToString(http_version_.minor_value())); |
687 } | 721 } |
688 if (parsed_http_version_ != http_version_) { | 722 if (parsed_http_version_ != http_version_) { |
689 DVLOG(1) << "assuming HTTP/" << http_version_.major_value() << "." | 723 DVLOG(1) << "assuming HTTP/" << http_version_.major_value() << "." |
690 << http_version_.minor_value(); | 724 << http_version_.minor_value(); |
691 } | 725 } |
692 | 726 |
693 // TODO(eroman): this doesn't make sense if ParseVersion failed. | 727 // TODO(eroman): this doesn't make sense if ParseVersion failed. |
694 std::string::const_iterator p = std::find(line_begin, line_end, ' '); | 728 std::string::const_iterator p = std::find(line_begin, line_end, ' '); |
695 | 729 |
696 if (p == line_end) { | 730 if (p == line_end) { |
(...skipping 700 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1397 return true; | 1431 return true; |
1398 } | 1432 } |
1399 | 1433 |
1400 bool HttpResponseHeaders::IsChunkEncoded() const { | 1434 bool HttpResponseHeaders::IsChunkEncoded() const { |
1401 // Ignore spurious chunked responses from HTTP/1.0 servers and proxies. | 1435 // Ignore spurious chunked responses from HTTP/1.0 servers and proxies. |
1402 return GetHttpVersion() >= HttpVersion(1, 1) && | 1436 return GetHttpVersion() >= HttpVersion(1, 1) && |
1403 HasHeaderValue("Transfer-Encoding", "chunked"); | 1437 HasHeaderValue("Transfer-Encoding", "chunked"); |
1404 } | 1438 } |
1405 | 1439 |
1406 } // namespace net | 1440 } // namespace net |
OLD | NEW |