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

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
« no previous file with comments | « 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 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
72 72
73 namespace net { 73 namespace net {
74 74
75 // Similar to DrainableIOBuffer(), but this version comes with its own 75 // Similar to DrainableIOBuffer(), but this version comes with its own
76 // storage. The motivation is to avoid repeated allocations of 76 // storage. The motivation is to avoid repeated allocations of
77 // DrainableIOBuffer. 77 // DrainableIOBuffer.
78 // 78 //
79 // Example: 79 // Example:
80 // 80 //
81 // scoped_refptr<SeekableIOBuffer> buf = new SeekableIOBuffer(1024); 81 // scoped_refptr<SeekableIOBuffer> buf = new SeekableIOBuffer(1024);
82 // // capacity() == 1024. size() == BytesRemaining == BytesConsumed() == 0. 82 // // capacity() == 1024. size() == BytesRemaining() == BytesConsumed() == 0.
83 // // data() points to the beginning of the buffer. 83 // // data() points to the beginning of the buffer.
84 // 84 //
85 // // Read() takes an IOBuffer. 85 // // Read() takes an IOBuffer.
86 // int bytes_read = some_reader->Read(buf, buf->capacity()); 86 // int bytes_read = some_reader->Read(buf, buf->capacity());
87 // buf->DidAppend(bytes_read); 87 // buf->DidAppend(bytes_read);
88 // // size() == BytesRemaining() == bytes_read. data() is unaffected. 88 // // size() == BytesRemaining() == bytes_read. data() is unaffected.
89 // 89 //
90 // while (buf->BytesRemaining() > 0) { 90 // while (buf->BytesRemaining() > 0) {
91 // // Write() takes an IOBuffer. If it takes const char*, we could 91 // // Write() takes an IOBuffer. If it takes const char*, we could
92 /// // simply use the regular IOBuffer like buf->data() + offset. 92 /// // simply use the regular IOBuffer like buf->data() + offset.
93 // int bytes_written = Write(buf, buf->BytesRemaining()); 93 // int bytes_written = Write(buf, buf->BytesRemaining());
94 // buf->DidConsume(bytes_written); 94 // buf->DidConsume(bytes_written);
95 // } 95 // }
96 // // BytesRemaining() == 0. BytesConsumed() == size(). 96 // // BytesRemaining() == 0. BytesConsumed() == size().
97 // // data() points to the end of the comsumed bytes (exclusive). 97 // // data() points to the end of the consumed bytes (exclusive).
98 // 98 //
99 // // If you want to reuse the buffer, be sure to clear the buffer. 99 // // If you want to reuse the buffer, be sure to clear the buffer.
100 // buf->Clear(); 100 // buf->Clear();
101 // // size() == BytesRemaining() == BytesConsumed() == 0. 101 // // size() == BytesRemaining() == BytesConsumed() == 0.
102 // // data() points to the beginning of the buffer. 102 // // data() points to the beginning of the buffer.
103 // 103 //
104 class HttpStreamParser::SeekableIOBuffer : public net::IOBuffer { 104 class HttpStreamParser::SeekableIOBuffer : public net::IOBuffer {
105 public: 105 public:
106 explicit SeekableIOBuffer(int capacity) 106 explicit SeekableIOBuffer(int capacity)
107 : IOBuffer(capacity), 107 : IOBuffer(capacity),
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
154 // the object is created. 154 // the object is created.
155 int capacity() const { return capacity_; }; 155 int capacity() const { return capacity_; };
156 156
157 private: 157 private:
158 virtual ~SeekableIOBuffer() { 158 virtual ~SeekableIOBuffer() {
159 // data_ will be deleted in IOBuffer::~IOBuffer(). 159 // data_ will be deleted in IOBuffer::~IOBuffer().
160 data_ = real_data_; 160 data_ = real_data_;
161 } 161 }
162 162
163 char* real_data_; 163 char* real_data_;
164 int capacity_; 164 const int capacity_;
165 int size_; 165 int size_;
166 int used_; 166 int used_;
167 }; 167 };
168 168
169 // 2 CRLFs + max of 8 hex chars. 169 // 2 CRLFs + max of 8 hex chars.
170 const size_t HttpStreamParser::kChunkHeaderFooterSize = 12; 170 const size_t HttpStreamParser::kChunkHeaderFooterSize = 12;
171 171
172 HttpStreamParser::HttpStreamParser(ClientSocketHandle* connection, 172 HttpStreamParser::HttpStreamParser(ClientSocketHandle* connection,
173 const HttpRequestInfo* request, 173 const HttpRequestInfo* request,
174 GrowableIOBuffer* read_buffer, 174 GrowableIOBuffer* read_buffer,
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after
286 if (result == ERR_IO_PENDING) 286 if (result == ERR_IO_PENDING)
287 callback_ = callback; 287 callback_ = callback;
288 288
289 return result > 0 ? OK : result; 289 return result > 0 ? OK : result;
290 } 290 }
291 291
292 int HttpStreamParser::ReadResponseHeaders(const CompletionCallback& callback) { 292 int HttpStreamParser::ReadResponseHeaders(const CompletionCallback& callback) {
293 DCHECK(io_state_ == STATE_REQUEST_SENT || io_state_ == STATE_DONE); 293 DCHECK(io_state_ == STATE_REQUEST_SENT || io_state_ == STATE_DONE);
294 DCHECK(callback_.is_null()); 294 DCHECK(callback_.is_null());
295 DCHECK(!callback.is_null()); 295 DCHECK(!callback.is_null());
296 DCHECK_EQ(0, read_buf_unused_offset_);
296 297
297 // This function can be called with io_state_ == STATE_DONE if the 298 // This function can be called with io_state_ == STATE_DONE if the
298 // connection is closed after seeing just a 1xx response code. 299 // connection is closed after seeing just a 1xx response code.
299 if (io_state_ == STATE_DONE) 300 if (io_state_ == STATE_DONE)
300 return ERR_CONNECTION_CLOSED; 301 return ERR_CONNECTION_CLOSED;
301 302
302 int result = OK; 303 int result = OK;
303 io_state_ = STATE_READ_HEADERS; 304 io_state_ = STATE_READ_HEADERS;
304 305
305 if (read_buf_->offset() > 0) { 306 if (read_buf_->offset() > 0) {
306 // Simulate the state where the data was just read from the socket. 307 // Simulate the state where the data was just read from the socket.
307 result = read_buf_->offset() - read_buf_unused_offset_; 308 result = read_buf_->offset();
308 read_buf_->set_offset(read_buf_unused_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 191 matching lines...) Expand 10 before | Expand all | Expand 10 after
510 511
511 // http://crbug.com/16371: We're seeing |user_buf_->data()| return NULL. 512 // http://crbug.com/16371: We're seeing |user_buf_->data()| return NULL.
512 // See if the user is passing in an IOBuffer with a NULL |data_|. 513 // See if the user is passing in an IOBuffer with a NULL |data_|.
513 CHECK(read_buf_->data()); 514 CHECK(read_buf_->data());
514 515
515 return connection_->socket() 516 return connection_->socket()
516 ->Read(read_buf_.get(), read_buf_->RemainingCapacity(), io_callback_); 517 ->Read(read_buf_.get(), read_buf_->RemainingCapacity(), io_callback_);
517 } 518 }
518 519
519 int HttpStreamParser::DoReadHeadersComplete(int result) { 520 int HttpStreamParser::DoReadHeadersComplete(int result) {
521 DCHECK_EQ(0, read_buf_unused_offset_);
522
520 if (result == 0) 523 if (result == 0)
521 result = ERR_CONNECTION_CLOSED; 524 result = ERR_CONNECTION_CLOSED;
522 525
523 if (result < 0 && result != ERR_CONNECTION_CLOSED) { 526 if (result < 0 && result != ERR_CONNECTION_CLOSED) {
524 io_state_ = STATE_DONE; 527 io_state_ = STATE_DONE;
525 return result; 528 return result;
526 } 529 }
527 // If we've used the connection before, then we know it is not a HTTP/0.9 530 // If we've used the connection before, then we know it is not a HTTP/0.9
528 // response and return ERR_CONNECTION_CLOSED. 531 // response and return ERR_CONNECTION_CLOSED.
529 if (result == ERR_CONNECTION_CLOSED && read_buf_->offset() == 0 && 532 if (result == ERR_CONNECTION_CLOSED && read_buf_->offset() == 0 &&
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
573 int end_of_header_offset = ParseResponseHeaders(); 576 int end_of_header_offset = ParseResponseHeaders();
574 577
575 // Note: -1 is special, it indicates we haven't found the end of headers. 578 // 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. 579 // Anything less than -1 is a net::Error, so we bail out.
577 if (end_of_header_offset < -1) 580 if (end_of_header_offset < -1)
578 return end_of_header_offset; 581 return end_of_header_offset;
579 582
580 if (end_of_header_offset == -1) { 583 if (end_of_header_offset == -1) {
581 io_state_ = STATE_READ_HEADERS; 584 io_state_ = STATE_READ_HEADERS;
582 // Prevent growing the headers buffer indefinitely. 585 // Prevent growing the headers buffer indefinitely.
583 if (read_buf_->offset() - read_buf_unused_offset_ >= kMaxHeaderBufSize) { 586 if (read_buf_->offset() >= kMaxHeaderBufSize) {
584 io_state_ = STATE_DONE; 587 io_state_ = STATE_DONE;
585 return ERR_RESPONSE_HEADERS_TOO_BIG; 588 return ERR_RESPONSE_HEADERS_TOO_BIG;
586 } 589 }
587 } else { 590 } else {
588 // Note where the headers stop. 591 CalculateResponseBodySize();
589 read_buf_unused_offset_ = end_of_header_offset; 592 // If the body is 0, the caller may not call ReadResponseBody, which
590 593 // is where any extra data is copied to read_buf_, so we move the
591 if (response_->headers->response_code() / 100 == 1) { 594 // data here.
592 // After processing a 1xx response, the caller will ask for the next 595 if (response_body_length_ == 0) {
593 // header, so reset state to support that. We don't just skip these 596 int extra_bytes = read_buf_->offset() - end_of_header_offset;
594 // completely because 1xx codes aren't acceptable when establishing a 597 if (extra_bytes) {
595 // tunnel. 598 CHECK_GT(extra_bytes, 0);
596 io_state_ = STATE_REQUEST_SENT; 599 memmove(read_buf_->StartOfBuffer(),
597 response_header_start_offset_ = -1; 600 read_buf_->StartOfBuffer() + end_of_header_offset,
601 extra_bytes);
602 }
603 read_buf_->SetCapacity(extra_bytes);
604 read_buf_unused_offset_ = 0;
605 if (response_->headers->response_code() / 100 == 1) {
606 // After processing a 1xx response, the caller will ask for the next
607 // header, so reset state to support that. We don't completely ignore a
608 // 1xx responses because they cannot be returned in reply to a CONNECT
609 // request so we return OK here, which lets the caller inspect the
610 // response and reject it in the event that we're setting up a CONNECT
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 {
SkyLined 2013/09/30 22:02:55 Nit: coding style says don't use else after return
agl 2013/10/01 14:07:45 Done.
620 // Note where the headers stop.
621 read_buf_unused_offset_ = end_of_header_offset;
599 io_state_ = STATE_BODY_PENDING; 622 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 } 623 }
618 } 624 }
619 return result; 625 return result;
620 } 626 }
621 627
622 int HttpStreamParser::DoReadBody() { 628 int HttpStreamParser::DoReadBody() {
623 io_state_ = STATE_READ_BODY_COMPLETE; 629 io_state_ = STATE_READ_BODY_COMPLETE;
624 630
625 // There may be some data left over from reading the response headers. 631 // There may be some data left over from reading the response headers.
626 if (read_buf_->offset()) { 632 if (read_buf_->offset()) {
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after
744 io_state_ = STATE_BODY_PENDING; 750 io_state_ = STATE_BODY_PENDING;
745 user_read_buf_ = NULL; 751 user_read_buf_ = NULL;
746 user_read_buf_len_ = 0; 752 user_read_buf_len_ = 0;
747 } 753 }
748 754
749 return result; 755 return result;
750 } 756 }
751 757
752 int HttpStreamParser::ParseResponseHeaders() { 758 int HttpStreamParser::ParseResponseHeaders() {
753 int end_offset = -1; 759 int end_offset = -1;
760 DCHECK_EQ(0, read_buf_unused_offset_);
754 761
755 // Look for the start of the status line, if it hasn't been found yet. 762 // Look for the start of the status line, if it hasn't been found yet.
756 if (response_header_start_offset_ < 0) { 763 if (response_header_start_offset_ < 0) {
757 response_header_start_offset_ = HttpUtil::LocateStartOfStatusLine( 764 response_header_start_offset_ = HttpUtil::LocateStartOfStatusLine(
758 read_buf_->StartOfBuffer() + read_buf_unused_offset_, 765 read_buf_->StartOfBuffer(), read_buf_->offset());
759 read_buf_->offset() - read_buf_unused_offset_);
760 } 766 }
761 767
762 if (response_header_start_offset_ >= 0) { 768 if (response_header_start_offset_ >= 0) {
763 end_offset = HttpUtil::LocateEndOfHeaders( 769 end_offset = HttpUtil::LocateEndOfHeaders(read_buf_->StartOfBuffer(),
764 read_buf_->StartOfBuffer() + read_buf_unused_offset_, 770 read_buf_->offset(),
765 read_buf_->offset() - read_buf_unused_offset_, 771 response_header_start_offset_);
766 response_header_start_offset_); 772 } else if (read_buf_->offset() >= 8) {
767 } else if (read_buf_->offset() - read_buf_unused_offset_ >= 8) {
768 // Enough data to decide that this is an HTTP/0.9 response. 773 // Enough data to decide that this is an HTTP/0.9 response.
769 // 8 bytes = (4 bytes of junk) + "http".length() 774 // 8 bytes = (4 bytes of junk) + "http".length()
770 end_offset = 0; 775 end_offset = 0;
771 } 776 }
772 777
773 if (end_offset == -1) 778 if (end_offset == -1)
774 return -1; 779 return -1;
775 780
776 int rv = DoParseResponseHeaders(end_offset); 781 int rv = DoParseResponseHeaders(end_offset);
777 if (rv < 0) 782 if (rv < 0)
778 return rv; 783 return rv;
779 return end_offset + read_buf_unused_offset_; 784 DCHECK_EQ(0, read_buf_unused_offset_);
SkyLined 2013/09/30 22:02:55 Since this check is already done at the start of t
agl 2013/10/01 14:07:45 Done.
785 return end_offset;
780 } 786 }
781 787
782 int HttpStreamParser::DoParseResponseHeaders(int end_offset) { 788 int HttpStreamParser::DoParseResponseHeaders(int end_offset) {
783 scoped_refptr<HttpResponseHeaders> headers; 789 scoped_refptr<HttpResponseHeaders> headers;
790 DCHECK_EQ(0, read_buf_unused_offset_);
791
784 if (response_header_start_offset_ >= 0) { 792 if (response_header_start_offset_ >= 0) {
785 headers = new HttpResponseHeaders(HttpUtil::AssembleRawHeaders( 793 headers = new HttpResponseHeaders(HttpUtil::AssembleRawHeaders(
786 read_buf_->StartOfBuffer() + read_buf_unused_offset_, end_offset)); 794 read_buf_->StartOfBuffer(), end_offset));
787 } else { 795 } else {
788 // Enough data was read -- there is no status line. 796 // Enough data was read -- there is no status line.
789 headers = new HttpResponseHeaders(std::string("HTTP/0.9 200 OK")); 797 headers = new HttpResponseHeaders(std::string("HTTP/0.9 200 OK"));
790 } 798 }
791 799
792 // Check for multiple Content-Length headers with no Transfer-Encoding header. 800 // Check for multiple Content-Length headers with no Transfer-Encoding header.
793 // If they exist, and have distinct values, it's a potential response 801 // If they exist, and have distinct values, it's a potential response
794 // smuggling attack. 802 // smuggling attack.
795 if (!headers->HasHeader("Transfer-Encoding")) { 803 if (!headers->HasHeader("Transfer-Encoding")) {
796 if (HeadersContainMultipleCopiesOfField(*headers.get(), "Content-Length")) 804 if (HeadersContainMultipleCopiesOfField(*headers.get(), "Content-Length"))
(...skipping 26 matching lines...) Expand all
823 // RFC 2616 Section 4.3 Message Body: 831 // RFC 2616 Section 4.3 Message Body:
824 // 832 //
825 // For response messages, whether or not a message-body is included with 833 // 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 834 // 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 835 // 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- 836 // MUST NOT include a message-body, even though the presence of entity-
829 // header fields might lead one to believe they do. All 1xx 837 // header fields might lead one to believe they do. All 1xx
830 // (informational), 204 (no content), and 304 (not modified) responses 838 // (informational), 204 (no content), and 304 (not modified) responses
831 // MUST NOT include a message-body. All other responses do include a 839 // MUST NOT include a message-body. All other responses do include a
832 // message-body, although it MAY be of zero length. 840 // message-body, although it MAY be of zero length.
833 switch (response_->headers->response_code()) { 841 if (response_->headers->response_code() / 100 == 1) {
834 // Note that 1xx was already handled earlier. 842 response_body_length_ = 0;
835 case 204: // No Content 843 } else {
836 case 205: // Reset Content 844 switch (response_->headers->response_code()) {
837 case 304: // Not Modified 845 case 204: // No Content
838 response_body_length_ = 0; 846 case 205: // Reset Content
839 break; 847 case 304: // Not Modified
848 response_body_length_ = 0;
849 break;
850 }
840 } 851 }
841 if (request_->method == "HEAD") 852 if (request_->method == "HEAD")
842 response_body_length_ = 0; 853 response_body_length_ = 0;
843 854
844 if (response_body_length_ == -1) { 855 if (response_body_length_ == -1) {
845 // "Transfer-Encoding: chunked" trumps "Content-Length: N" 856 // "Transfer-Encoding: chunked" trumps "Content-Length: N"
846 if (response_->headers->IsChunkEncoded()) { 857 if (response_->headers->IsChunkEncoded()) {
847 chunked_decoder_.reset(new HttpChunkedDecoder()); 858 chunked_decoder_.reset(new HttpChunkedDecoder());
848 } else { 859 } else {
849 response_body_length_ = response_->headers->GetContentLength(); 860 response_body_length_ = response_->headers->GetContentLength();
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after
946 request_body->IsInMemory() && 957 request_body->IsInMemory() &&
947 request_body->size() > 0) { 958 request_body->size() > 0) {
948 size_t merged_size = request_headers.size() + request_body->size(); 959 size_t merged_size = request_headers.size() + request_body->size();
949 if (merged_size <= kMaxMergedHeaderAndBodySize) 960 if (merged_size <= kMaxMergedHeaderAndBodySize)
950 return true; 961 return true;
951 } 962 }
952 return false; 963 return false;
953 } 964 }
954 965
955 } // namespace net 966 } // namespace net
OLDNEW
« no previous file with comments | « net/http/http_stream_parser.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698