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

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: g try 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
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 {
591 CalculateResponseBodySize();
592 // If the body is 0, the caller may not call ReadResponseBody, which
wtc 2013/10/01 18:12:57 1. Nit: "If the body is 0" isn't clear. I think it
agl 2013/10/01 19:53:18 Fixed.
593 // is where any extra data is copied to read_buf_, so we move the
594 // data here.
595 if (response_body_length_ == 0) {
596 int extra_bytes = read_buf_->offset() - end_of_header_offset;
597 if (extra_bytes) {
598 CHECK_GT(extra_bytes, 0);
599 memmove(read_buf_->StartOfBuffer(),
wtc 2013/10/01 18:12:57 IMPORTANT: is it correct to move the extra data fo
agl 2013/10/01 19:53:18 (see bug.)
600 read_buf_->StartOfBuffer() + end_of_header_offset,
601 extra_bytes);
602 }
603 read_buf_->SetCapacity(extra_bytes);
604 read_buf_unused_offset_ = 0;
wtc 2013/10/01 18:12:57 This is not necessary in the new code. (It was nec
agl 2013/10/01 19:53:18 Done.
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
wtc 2013/10/01 18:12:57 Nit: delete "a" at the end of this line.
agl 2013/10/01 19:53:18 Done.
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;
wtc 2013/10/01 18:12:57 Why do we need to change response_body_length_ to
agl 2013/10/01 19:53:18 It will have been set to 0 by CalculateResponseBod
614 io_state_ = STATE_REQUEST_SENT;
615 } else {
616 io_state_ = STATE_DONE;
617 }
618 return OK;
619 }
620
588 // Note where the headers stop. 621 // Note where the headers stop.
589 read_buf_unused_offset_ = end_of_header_offset; 622 read_buf_unused_offset_ = end_of_header_offset;
590 623 io_state_ = STATE_BODY_PENDING;
591 if (response_->headers->response_code() / 100 == 1) {
592 // After processing a 1xx response, the caller will ask for the next
593 // header, so reset state to support that. We don't just skip these
594 // completely because 1xx codes aren't acceptable when establishing a
595 // tunnel.
596 io_state_ = STATE_REQUEST_SENT;
597 response_header_start_offset_ = -1;
598 } else {
599 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 }
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()) {
627 int available = read_buf_->offset() - read_buf_unused_offset_; 633 int available = read_buf_->offset() - read_buf_unused_offset_;
(...skipping 116 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 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;
789 DCHECK_EQ(0, read_buf_unused_offset_);
790
784 if (response_header_start_offset_ >= 0) { 791 if (response_header_start_offset_ >= 0) {
785 headers = new HttpResponseHeaders(HttpUtil::AssembleRawHeaders( 792 headers = new HttpResponseHeaders(HttpUtil::AssembleRawHeaders(
786 read_buf_->StartOfBuffer() + read_buf_unused_offset_, end_offset)); 793 read_buf_->StartOfBuffer(), end_offset));
787 } else { 794 } else {
788 // Enough data was read -- there is no status line. 795 // Enough data was read -- there is no status line.
789 headers = new HttpResponseHeaders(std::string("HTTP/0.9 200 OK")); 796 headers = new HttpResponseHeaders(std::string("HTTP/0.9 200 OK"));
790 } 797 }
791 798
792 // Check for multiple Content-Length headers with no Transfer-Encoding header. 799 // Check for multiple Content-Length headers with no Transfer-Encoding header.
793 // If they exist, and have distinct values, it's a potential response 800 // If they exist, and have distinct values, it's a potential response
794 // smuggling attack. 801 // smuggling attack.
795 if (!headers->HasHeader("Transfer-Encoding")) { 802 if (!headers->HasHeader("Transfer-Encoding")) {
796 if (HeadersContainMultipleCopiesOfField(*headers.get(), "Content-Length")) 803 if (HeadersContainMultipleCopiesOfField(*headers.get(), "Content-Length"))
(...skipping 26 matching lines...) Expand all
823 // RFC 2616 Section 4.3 Message Body: 830 // RFC 2616 Section 4.3 Message Body:
824 // 831 //
825 // For response messages, whether or not a message-body is included with 832 // 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 833 // 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 834 // 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- 835 // MUST NOT include a message-body, even though the presence of entity-
829 // header fields might lead one to believe they do. All 1xx 836 // header fields might lead one to believe they do. All 1xx
830 // (informational), 204 (no content), and 304 (not modified) responses 837 // (informational), 204 (no content), and 304 (not modified) responses
831 // MUST NOT include a message-body. All other responses do include a 838 // MUST NOT include a message-body. All other responses do include a
832 // message-body, although it MAY be of zero length. 839 // message-body, although it MAY be of zero length.
833 switch (response_->headers->response_code()) { 840 if (response_->headers->response_code() / 100 == 1) {
834 // Note that 1xx was already handled earlier. 841 response_body_length_ = 0;
835 case 204: // No Content 842 } else {
836 case 205: // Reset Content 843 switch (response_->headers->response_code()) {
837 case 304: // Not Modified 844 case 204: // No Content
838 response_body_length_ = 0; 845 case 205: // Reset Content
839 break; 846 case 304: // Not Modified
847 response_body_length_ = 0;
848 break;
849 }
840 } 850 }
841 if (request_->method == "HEAD") 851 if (request_->method == "HEAD")
842 response_body_length_ = 0; 852 response_body_length_ = 0;
843 853
844 if (response_body_length_ == -1) { 854 if (response_body_length_ == -1) {
845 // "Transfer-Encoding: chunked" trumps "Content-Length: N" 855 // "Transfer-Encoding: chunked" trumps "Content-Length: N"
846 if (response_->headers->IsChunkEncoded()) { 856 if (response_->headers->IsChunkEncoded()) {
847 chunked_decoder_.reset(new HttpChunkedDecoder()); 857 chunked_decoder_.reset(new HttpChunkedDecoder());
848 } else { 858 } else {
849 response_body_length_ = response_->headers->GetContentLength(); 859 response_body_length_ = response_->headers->GetContentLength();
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after
946 request_body->IsInMemory() && 956 request_body->IsInMemory() &&
947 request_body->size() > 0) { 957 request_body->size() > 0) {
948 size_t merged_size = request_headers.size() + request_body->size(); 958 size_t merged_size = request_headers.size() + request_body->size();
949 if (merged_size <= kMaxMergedHeaderAndBodySize) 959 if (merged_size <= kMaxMergedHeaderAndBodySize)
950 return true; 960 return true;
951 } 961 }
952 return false; 962 return false;
953 } 963 }
954 964
955 } // namespace net 965 } // namespace net
OLDNEW
« net/http/http_proxy_client_socket_pool_unittest.cc ('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