Chromium Code Reviews| 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 #include "net/http/http_stream_parser.h" | 5 #include "net/http/http_stream_parser.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/compiler_specific.h" | 8 #include "base/compiler_specific.h" |
| 9 #include "base/strings/string_util.h" | 9 #include "base/strings/string_util.h" |
| 10 #include "base/values.h" | 10 #include "base/values.h" |
| (...skipping 286 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 297 // This function can be called with io_state_ == STATE_DONE if the | 297 // This function can be called with io_state_ == STATE_DONE if the |
| 298 // connection is closed after seeing just a 1xx response code. | 298 // connection is closed after seeing just a 1xx response code. |
| 299 if (io_state_ == STATE_DONE) | 299 if (io_state_ == STATE_DONE) |
| 300 return ERR_CONNECTION_CLOSED; | 300 return ERR_CONNECTION_CLOSED; |
| 301 | 301 |
| 302 int result = OK; | 302 int result = OK; |
| 303 io_state_ = STATE_READ_HEADERS; | 303 io_state_ = STATE_READ_HEADERS; |
| 304 | 304 |
| 305 if (read_buf_->offset() > 0) { | 305 if (read_buf_->offset() > 0) { |
| 306 // Simulate the state where the data was just read from the socket. | 306 // Simulate the state where the data was just read from the socket. |
| 307 result = read_buf_->offset() - read_buf_unused_offset_; | 307 DCHECK_EQ(0, read_buf_unused_offset_); |
|
SkyLined
2013/09/30 18:27:47
Should we move this DCHECK to the start of the fun
agl
2013/09/30 20:59:28
Done.
| |
| 308 read_buf_->set_offset(read_buf_unused_offset_); | 308 result = read_buf_->offset(); |
| 309 read_buf_->set_offset(0); | |
| 309 } | 310 } |
| 310 if (result > 0) | 311 if (result > 0) |
| 311 io_state_ = STATE_READ_HEADERS_COMPLETE; | 312 io_state_ = STATE_READ_HEADERS_COMPLETE; |
| 312 | 313 |
| 313 result = DoLoop(result); | 314 result = DoLoop(result); |
| 314 if (result == ERR_IO_PENDING) | 315 if (result == ERR_IO_PENDING) |
| 315 callback_ = callback; | 316 callback_ = callback; |
| 316 | 317 |
| 317 return result > 0 ? OK : result; | 318 return result > 0 ? OK : result; |
| 318 } | 319 } |
| (...skipping 254 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 573 int end_of_header_offset = ParseResponseHeaders(); | 574 int end_of_header_offset = ParseResponseHeaders(); |
| 574 | 575 |
| 575 // Note: -1 is special, it indicates we haven't found the end of headers. | 576 // Note: -1 is special, it indicates we haven't found the end of headers. |
| 576 // Anything less than -1 is a net::Error, so we bail out. | 577 // Anything less than -1 is a net::Error, so we bail out. |
| 577 if (end_of_header_offset < -1) | 578 if (end_of_header_offset < -1) |
| 578 return end_of_header_offset; | 579 return end_of_header_offset; |
| 579 | 580 |
| 580 if (end_of_header_offset == -1) { | 581 if (end_of_header_offset == -1) { |
| 581 io_state_ = STATE_READ_HEADERS; | 582 io_state_ = STATE_READ_HEADERS; |
| 582 // Prevent growing the headers buffer indefinitely. | 583 // Prevent growing the headers buffer indefinitely. |
| 583 if (read_buf_->offset() - read_buf_unused_offset_ >= kMaxHeaderBufSize) { | 584 DCHECK_EQ(0, read_buf_unused_offset_); |
|
SkyLined
2013/09/30 18:27:47
Should we move this DCHECK to the start of the fun
agl
2013/09/30 20:59:28
Done.
| |
| 585 if (read_buf_->offset() >= kMaxHeaderBufSize) { | |
| 584 io_state_ = STATE_DONE; | 586 io_state_ = STATE_DONE; |
| 585 return ERR_RESPONSE_HEADERS_TOO_BIG; | 587 return ERR_RESPONSE_HEADERS_TOO_BIG; |
| 586 } | 588 } |
| 587 } else { | 589 } else { |
| 588 // Note where the headers stop. | 590 // Note where the headers stop. |
| 589 read_buf_unused_offset_ = end_of_header_offset; | 591 read_buf_unused_offset_ = end_of_header_offset; |
|
SkyLined
2013/09/30 18:27:47
This is only needed if the response contains a bod
agl
2013/09/30 20:59:28
Done.
| |
| 590 | 592 |
| 591 if (response_->headers->response_code() / 100 == 1) { | 593 CalculateResponseBodySize(); |
| 592 // After processing a 1xx response, the caller will ask for the next | 594 // If the body is 0, the caller may not call ReadResponseBody, which |
| 593 // header, so reset state to support that. We don't just skip these | 595 // is where any extra data is copied to read_buf_, so we move the |
| 594 // completely because 1xx codes aren't acceptable when establishing a | 596 // data here. |
| 595 // tunnel. | 597 if (response_body_length_ == 0) { |
| 596 io_state_ = STATE_REQUEST_SENT; | 598 int extra_bytes = read_buf_->offset() - read_buf_unused_offset_; |
| 597 response_header_start_offset_ = -1; | 599 if (extra_bytes) { |
| 600 CHECK_GT(extra_bytes, 0); | |
| 601 memmove(read_buf_->StartOfBuffer(), | |
| 602 read_buf_->StartOfBuffer() + read_buf_unused_offset_, | |
| 603 extra_bytes); | |
| 604 } | |
| 605 read_buf_->SetCapacity(extra_bytes); | |
| 606 read_buf_unused_offset_ = 0; | |
| 607 if (response_->headers->response_code() / 100 == 1) { | |
| 608 // After processing a 1xx response, the caller will ask for the next | |
| 609 // header, so reset state to support that. We don't just skip these | |
| 610 // completely because 1xx codes aren't acceptable when establishing a | |
| 611 // tunnel. | |
| 612 response_header_start_offset_ = -1; | |
| 613 response_body_length_ = -1; | |
| 614 io_state_ = STATE_REQUEST_SENT; | |
| 615 } else { | |
| 616 io_state_ = STATE_DONE; | |
| 617 } | |
| 618 return OK; | |
| 598 } else { | 619 } else { |
| 599 io_state_ = STATE_BODY_PENDING; | 620 io_state_ = STATE_BODY_PENDING; |
| 600 CalculateResponseBodySize(); | |
| 601 // If the body is 0, the caller may not call ReadResponseBody, which | |
| 602 // is where any extra data is copied to read_buf_, so we move the | |
| 603 // data here and transition to DONE. | |
| 604 if (response_body_length_ == 0) { | |
| 605 io_state_ = STATE_DONE; | |
| 606 int extra_bytes = read_buf_->offset() - read_buf_unused_offset_; | |
| 607 if (extra_bytes) { | |
| 608 CHECK_GT(extra_bytes, 0); | |
| 609 memmove(read_buf_->StartOfBuffer(), | |
| 610 read_buf_->StartOfBuffer() + read_buf_unused_offset_, | |
| 611 extra_bytes); | |
| 612 } | |
| 613 read_buf_->SetCapacity(extra_bytes); | |
| 614 read_buf_unused_offset_ = 0; | |
| 615 return OK; | |
| 616 } | |
| 617 } | 621 } |
| 618 } | 622 } |
| 619 return result; | 623 return result; |
| 620 } | 624 } |
| 621 | 625 |
| 622 int HttpStreamParser::DoReadBody() { | 626 int HttpStreamParser::DoReadBody() { |
| 623 io_state_ = STATE_READ_BODY_COMPLETE; | 627 io_state_ = STATE_READ_BODY_COMPLETE; |
| 624 | 628 |
| 625 // There may be some data left over from reading the response headers. | 629 // There may be some data left over from reading the response headers. |
| 626 if (read_buf_->offset()) { | 630 if (read_buf_->offset()) { |
| (...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 747 } | 751 } |
| 748 | 752 |
| 749 return result; | 753 return result; |
| 750 } | 754 } |
| 751 | 755 |
| 752 int HttpStreamParser::ParseResponseHeaders() { | 756 int HttpStreamParser::ParseResponseHeaders() { |
| 753 int end_offset = -1; | 757 int end_offset = -1; |
| 754 | 758 |
| 755 // Look for the start of the status line, if it hasn't been found yet. | 759 // Look for the start of the status line, if it hasn't been found yet. |
| 756 if (response_header_start_offset_ < 0) { | 760 if (response_header_start_offset_ < 0) { |
| 761 DCHECK_EQ(0, read_buf_unused_offset_); | |
|
SkyLined
2013/09/30 18:27:47
Should we move this DCHECK to the start of the fun
agl
2013/09/30 20:59:28
Done.
| |
| 757 response_header_start_offset_ = HttpUtil::LocateStartOfStatusLine( | 762 response_header_start_offset_ = HttpUtil::LocateStartOfStatusLine( |
| 758 read_buf_->StartOfBuffer() + read_buf_unused_offset_, | 763 read_buf_->StartOfBuffer(), read_buf_->offset()); |
| 759 read_buf_->offset() - read_buf_unused_offset_); | |
| 760 } | 764 } |
| 761 | 765 |
| 762 if (response_header_start_offset_ >= 0) { | 766 if (response_header_start_offset_ >= 0) { |
| 763 end_offset = HttpUtil::LocateEndOfHeaders( | 767 DCHECK_EQ(0, read_buf_unused_offset_); |
|
SkyLined
2013/09/30 18:27:47
Should we move this DCHECK to the start of the fun
agl
2013/09/30 20:59:28
Done.
| |
| 764 read_buf_->StartOfBuffer() + read_buf_unused_offset_, | 768 end_offset = HttpUtil::LocateEndOfHeaders(read_buf_->StartOfBuffer(), |
| 765 read_buf_->offset() - read_buf_unused_offset_, | 769 read_buf_->offset(), |
| 766 response_header_start_offset_); | 770 response_header_start_offset_); |
| 767 } else if (read_buf_->offset() - read_buf_unused_offset_ >= 8) { | 771 } else if (read_buf_->offset() - read_buf_unused_offset_ >= 8) { |
| 768 // Enough data to decide that this is an HTTP/0.9 response. | 772 // Enough data to decide that this is an HTTP/0.9 response. |
| 769 // 8 bytes = (4 bytes of junk) + "http".length() | 773 // 8 bytes = (4 bytes of junk) + "http".length() |
| 770 end_offset = 0; | 774 end_offset = 0; |
| 771 } | 775 } |
| 772 | 776 |
| 773 if (end_offset == -1) | 777 if (end_offset == -1) |
| 774 return -1; | 778 return -1; |
| 775 | 779 |
| 776 int rv = DoParseResponseHeaders(end_offset); | 780 int rv = DoParseResponseHeaders(end_offset); |
| 777 if (rv < 0) | 781 if (rv < 0) |
| 778 return rv; | 782 return rv; |
| 779 return end_offset + read_buf_unused_offset_; | 783 DCHECK_EQ(0, read_buf_unused_offset_); |
|
SkyLined
2013/09/30 18:27:47
Should we move this DCHECK to the start of the fun
agl
2013/09/30 20:59:28
Done.
| |
| 784 return end_offset; | |
| 780 } | 785 } |
| 781 | 786 |
| 782 int HttpStreamParser::DoParseResponseHeaders(int end_offset) { | 787 int HttpStreamParser::DoParseResponseHeaders(int end_offset) { |
| 783 scoped_refptr<HttpResponseHeaders> headers; | 788 scoped_refptr<HttpResponseHeaders> headers; |
| 784 if (response_header_start_offset_ >= 0) { | 789 if (response_header_start_offset_ >= 0) { |
| 785 headers = new HttpResponseHeaders(HttpUtil::AssembleRawHeaders( | 790 headers = new HttpResponseHeaders(HttpUtil::AssembleRawHeaders( |
| 786 read_buf_->StartOfBuffer() + read_buf_unused_offset_, end_offset)); | 791 read_buf_->StartOfBuffer() + read_buf_unused_offset_, end_offset)); |
|
SkyLined
2013/09/30 18:27:47
"read_buf_unused_offset_" should be removed here t
agl
2013/09/30 20:59:28
Done.
| |
| 787 } else { | 792 } else { |
| 788 // Enough data was read -- there is no status line. | 793 // Enough data was read -- there is no status line. |
| 789 headers = new HttpResponseHeaders(std::string("HTTP/0.9 200 OK")); | 794 headers = new HttpResponseHeaders(std::string("HTTP/0.9 200 OK")); |
| 790 } | 795 } |
| 791 | 796 |
| 792 // Check for multiple Content-Length headers with no Transfer-Encoding header. | 797 // Check for multiple Content-Length headers with no Transfer-Encoding header. |
| 793 // If they exist, and have distinct values, it's a potential response | 798 // If they exist, and have distinct values, it's a potential response |
| 794 // smuggling attack. | 799 // smuggling attack. |
| 795 if (!headers->HasHeader("Transfer-Encoding")) { | 800 if (!headers->HasHeader("Transfer-Encoding")) { |
| 796 if (HeadersContainMultipleCopiesOfField(*headers.get(), "Content-Length")) | 801 if (HeadersContainMultipleCopiesOfField(*headers.get(), "Content-Length")) |
| (...skipping 26 matching lines...) Expand all Loading... | |
| 823 // RFC 2616 Section 4.3 Message Body: | 828 // RFC 2616 Section 4.3 Message Body: |
| 824 // | 829 // |
| 825 // For response messages, whether or not a message-body is included with | 830 // For response messages, whether or not a message-body is included with |
| 826 // a message is dependent on both the request method and the response | 831 // a message is dependent on both the request method and the response |
| 827 // status code (section 6.1.1). All responses to the HEAD request method | 832 // status code (section 6.1.1). All responses to the HEAD request method |
| 828 // MUST NOT include a message-body, even though the presence of entity- | 833 // MUST NOT include a message-body, even though the presence of entity- |
| 829 // header fields might lead one to believe they do. All 1xx | 834 // header fields might lead one to believe they do. All 1xx |
| 830 // (informational), 204 (no content), and 304 (not modified) responses | 835 // (informational), 204 (no content), and 304 (not modified) responses |
| 831 // MUST NOT include a message-body. All other responses do include a | 836 // MUST NOT include a message-body. All other responses do include a |
| 832 // message-body, although it MAY be of zero length. | 837 // message-body, although it MAY be of zero length. |
| 833 switch (response_->headers->response_code()) { | 838 if (response_->headers->response_code() / 100 == 1) { |
| 834 // Note that 1xx was already handled earlier. | 839 response_body_length_ = 0; |
| 835 case 204: // No Content | 840 } else { |
| 836 case 205: // Reset Content | 841 switch (response_->headers->response_code()) { |
| 837 case 304: // Not Modified | 842 case 204: // No Content |
| 838 response_body_length_ = 0; | 843 case 205: // Reset Content |
| 839 break; | 844 case 304: // Not Modified |
| 845 response_body_length_ = 0; | |
| 846 break; | |
| 847 } | |
| 840 } | 848 } |
| 841 if (request_->method == "HEAD") | 849 if (request_->method == "HEAD") |
| 842 response_body_length_ = 0; | 850 response_body_length_ = 0; |
| 843 | 851 |
| 844 if (response_body_length_ == -1) { | 852 if (response_body_length_ == -1) { |
| 845 // "Transfer-Encoding: chunked" trumps "Content-Length: N" | 853 // "Transfer-Encoding: chunked" trumps "Content-Length: N" |
| 846 if (response_->headers->IsChunkEncoded()) { | 854 if (response_->headers->IsChunkEncoded()) { |
| 847 chunked_decoder_.reset(new HttpChunkedDecoder()); | 855 chunked_decoder_.reset(new HttpChunkedDecoder()); |
| 848 } else { | 856 } else { |
| 849 response_body_length_ = response_->headers->GetContentLength(); | 857 response_body_length_ = response_->headers->GetContentLength(); |
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 946 request_body->IsInMemory() && | 954 request_body->IsInMemory() && |
| 947 request_body->size() > 0) { | 955 request_body->size() > 0) { |
| 948 size_t merged_size = request_headers.size() + request_body->size(); | 956 size_t merged_size = request_headers.size() + request_body->size(); |
| 949 if (merged_size <= kMaxMergedHeaderAndBodySize) | 957 if (merged_size <= kMaxMergedHeaderAndBodySize) |
| 950 return true; | 958 return true; |
| 951 } | 959 } |
| 952 return false; | 960 return false; |
| 953 } | 961 } |
| 954 | 962 |
| 955 } // namespace net | 963 } // namespace net |
| OLD | NEW |