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 |