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 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 zero length, the caller may not call ReadResponseBody, |
| 593 // which 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(), |
| 600 read_buf_->StartOfBuffer() + end_of_header_offset, |
| 601 extra_bytes); |
| 602 } |
| 603 read_buf_->SetCapacity(extra_bytes); |
| 604 if (response_->headers->response_code() / 100 == 1) { |
| 605 // After processing a 1xx response, the caller will ask for the next |
| 606 // header, so reset state to support that. We don't completely ignore a |
| 607 // 1xx response because it cannot be returned in reply to a CONNECT |
| 608 // request so we return OK here, which lets the caller inspect the |
| 609 // response and reject it in the event that we're setting up a CONNECT |
| 610 // tunnel. |
| 611 response_header_start_offset_ = -1; |
| 612 response_body_length_ = -1; |
| 613 io_state_ = STATE_REQUEST_SENT; |
| 614 } else { |
| 615 io_state_ = STATE_DONE; |
| 616 } |
| 617 return OK; |
| 618 } |
| 619 |
588 // Note where the headers stop. | 620 // Note where the headers stop. |
589 read_buf_unused_offset_ = end_of_header_offset; | 621 read_buf_unused_offset_ = end_of_header_offset; |
590 | 622 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 } | 623 } |
619 return result; | 624 return result; |
620 } | 625 } |
621 | 626 |
622 int HttpStreamParser::DoReadBody() { | 627 int HttpStreamParser::DoReadBody() { |
623 io_state_ = STATE_READ_BODY_COMPLETE; | 628 io_state_ = STATE_READ_BODY_COMPLETE; |
624 | 629 |
625 // There may be some data left over from reading the response headers. | 630 // There may be some data left over from reading the response headers. |
626 if (read_buf_->offset()) { | 631 if (read_buf_->offset()) { |
627 int available = read_buf_->offset() - read_buf_unused_offset_; | 632 int available = read_buf_->offset() - read_buf_unused_offset_; |
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
744 io_state_ = STATE_BODY_PENDING; | 749 io_state_ = STATE_BODY_PENDING; |
745 user_read_buf_ = NULL; | 750 user_read_buf_ = NULL; |
746 user_read_buf_len_ = 0; | 751 user_read_buf_len_ = 0; |
747 } | 752 } |
748 | 753 |
749 return result; | 754 return result; |
750 } | 755 } |
751 | 756 |
752 int HttpStreamParser::ParseResponseHeaders() { | 757 int HttpStreamParser::ParseResponseHeaders() { |
753 int end_offset = -1; | 758 int end_offset = -1; |
| 759 DCHECK_EQ(0, read_buf_unused_offset_); |
754 | 760 |
755 // Look for the start of the status line, if it hasn't been found yet. | 761 // Look for the start of the status line, if it hasn't been found yet. |
756 if (response_header_start_offset_ < 0) { | 762 if (response_header_start_offset_ < 0) { |
757 response_header_start_offset_ = HttpUtil::LocateStartOfStatusLine( | 763 response_header_start_offset_ = HttpUtil::LocateStartOfStatusLine( |
758 read_buf_->StartOfBuffer() + read_buf_unused_offset_, | 764 read_buf_->StartOfBuffer(), read_buf_->offset()); |
759 read_buf_->offset() - read_buf_unused_offset_); | |
760 } | 765 } |
761 | 766 |
762 if (response_header_start_offset_ >= 0) { | 767 if (response_header_start_offset_ >= 0) { |
763 end_offset = HttpUtil::LocateEndOfHeaders( | 768 end_offset = HttpUtil::LocateEndOfHeaders(read_buf_->StartOfBuffer(), |
764 read_buf_->StartOfBuffer() + read_buf_unused_offset_, | 769 read_buf_->offset(), |
765 read_buf_->offset() - read_buf_unused_offset_, | 770 response_header_start_offset_); |
766 response_header_start_offset_); | 771 } 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. | 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 return end_offset; |
780 } | 784 } |
781 | 785 |
782 int HttpStreamParser::DoParseResponseHeaders(int end_offset) { | 786 int HttpStreamParser::DoParseResponseHeaders(int end_offset) { |
783 scoped_refptr<HttpResponseHeaders> headers; | 787 scoped_refptr<HttpResponseHeaders> headers; |
| 788 DCHECK_EQ(0, read_buf_unused_offset_); |
| 789 |
784 if (response_header_start_offset_ >= 0) { | 790 if (response_header_start_offset_ >= 0) { |
785 headers = new HttpResponseHeaders(HttpUtil::AssembleRawHeaders( | 791 headers = new HttpResponseHeaders(HttpUtil::AssembleRawHeaders( |
786 read_buf_->StartOfBuffer() + read_buf_unused_offset_, end_offset)); | 792 read_buf_->StartOfBuffer(), end_offset)); |
787 } else { | 793 } else { |
788 // Enough data was read -- there is no status line. | 794 // Enough data was read -- there is no status line. |
789 headers = new HttpResponseHeaders(std::string("HTTP/0.9 200 OK")); | 795 headers = new HttpResponseHeaders(std::string("HTTP/0.9 200 OK")); |
790 } | 796 } |
791 | 797 |
792 // Check for multiple Content-Length headers with no Transfer-Encoding header. | 798 // Check for multiple Content-Length headers with no Transfer-Encoding header. |
793 // If they exist, and have distinct values, it's a potential response | 799 // If they exist, and have distinct values, it's a potential response |
794 // smuggling attack. | 800 // smuggling attack. |
795 if (!headers->HasHeader("Transfer-Encoding")) { | 801 if (!headers->HasHeader("Transfer-Encoding")) { |
796 if (HeadersContainMultipleCopiesOfField(*headers.get(), "Content-Length")) | 802 if (HeadersContainMultipleCopiesOfField(*headers.get(), "Content-Length")) |
(...skipping 26 matching lines...) Expand all Loading... |
823 // RFC 2616 Section 4.3 Message Body: | 829 // RFC 2616 Section 4.3 Message Body: |
824 // | 830 // |
825 // For response messages, whether or not a message-body is included with | 831 // 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 | 832 // 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 | 833 // 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- | 834 // MUST NOT include a message-body, even though the presence of entity- |
829 // header fields might lead one to believe they do. All 1xx | 835 // header fields might lead one to believe they do. All 1xx |
830 // (informational), 204 (no content), and 304 (not modified) responses | 836 // (informational), 204 (no content), and 304 (not modified) responses |
831 // MUST NOT include a message-body. All other responses do include a | 837 // MUST NOT include a message-body. All other responses do include a |
832 // message-body, although it MAY be of zero length. | 838 // message-body, although it MAY be of zero length. |
833 switch (response_->headers->response_code()) { | 839 if (response_->headers->response_code() / 100 == 1) { |
834 // Note that 1xx was already handled earlier. | 840 response_body_length_ = 0; |
835 case 204: // No Content | 841 } else { |
836 case 205: // Reset Content | 842 switch (response_->headers->response_code()) { |
837 case 304: // Not Modified | 843 case 204: // No Content |
838 response_body_length_ = 0; | 844 case 205: // Reset Content |
839 break; | 845 case 304: // Not Modified |
| 846 response_body_length_ = 0; |
| 847 break; |
| 848 } |
840 } | 849 } |
841 if (request_->method == "HEAD") | 850 if (request_->method == "HEAD") |
842 response_body_length_ = 0; | 851 response_body_length_ = 0; |
843 | 852 |
844 if (response_body_length_ == -1) { | 853 if (response_body_length_ == -1) { |
845 // "Transfer-Encoding: chunked" trumps "Content-Length: N" | 854 // "Transfer-Encoding: chunked" trumps "Content-Length: N" |
846 if (response_->headers->IsChunkEncoded()) { | 855 if (response_->headers->IsChunkEncoded()) { |
847 chunked_decoder_.reset(new HttpChunkedDecoder()); | 856 chunked_decoder_.reset(new HttpChunkedDecoder()); |
848 } else { | 857 } else { |
849 response_body_length_ = response_->headers->GetContentLength(); | 858 response_body_length_ = response_->headers->GetContentLength(); |
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
946 request_body->IsInMemory() && | 955 request_body->IsInMemory() && |
947 request_body->size() > 0) { | 956 request_body->size() > 0) { |
948 size_t merged_size = request_headers.size() + request_body->size(); | 957 size_t merged_size = request_headers.size() + request_body->size(); |
949 if (merged_size <= kMaxMergedHeaderAndBodySize) | 958 if (merged_size <= kMaxMergedHeaderAndBodySize) |
950 return true; | 959 return true; |
951 } | 960 } |
952 return false; | 961 return false; |
953 } | 962 } |
954 | 963 |
955 } // namespace net | 964 } // namespace net |
OLD | NEW |