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

Side by Side Diff: net/http/http_stream_parser.cc

Issue 25312002: net: don't preserve 1xx responses in parser buffer. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years, 2 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
« net/http/http_stream_parser.h ('K') | « net/http/http_stream_parser.h ('k') | no next file » | 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 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
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
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
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
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
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
OLDNEW
« net/http/http_stream_parser.h ('K') | « net/http/http_stream_parser.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698