| 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/logging.h" | 9 #include "base/logging.h" |
| 10 #include "base/metrics/histogram_macros.h" | 10 #include "base/metrics/histogram_macros.h" |
| (...skipping 11 matching lines...) Expand all Loading... |
| 22 #include "net/socket/client_socket_handle.h" | 22 #include "net/socket/client_socket_handle.h" |
| 23 #include "net/socket/ssl_client_socket.h" | 23 #include "net/socket/ssl_client_socket.h" |
| 24 | 24 |
| 25 namespace net { | 25 namespace net { |
| 26 | 26 |
| 27 namespace { | 27 namespace { |
| 28 | 28 |
| 29 enum HttpHeaderParserEvent { | 29 enum HttpHeaderParserEvent { |
| 30 HEADER_PARSER_INVOKED = 0, | 30 HEADER_PARSER_INVOKED = 0, |
| 31 HEADER_HTTP_09_RESPONSE = 1, | 31 HEADER_HTTP_09_RESPONSE = 1, |
| 32 HEADER_ALLOWED_TRUNCATED_HEADERS = 2, | 32 // Obsolete: HEADER_ALLOWED_TRUNCATED_HEADERS = 2, |
| 33 HEADER_SKIPPED_WS_PREFIX = 3, | 33 HEADER_SKIPPED_WS_PREFIX = 3, |
| 34 HEADER_SKIPPED_NON_WS_PREFIX = 4, | 34 HEADER_SKIPPED_NON_WS_PREFIX = 4, |
| 35 NUM_HEADER_EVENTS | 35 NUM_HEADER_EVENTS |
| 36 }; | 36 }; |
| 37 | 37 |
| 38 void RecordHeaderParserEvent(HttpHeaderParserEvent header_event) { | 38 void RecordHeaderParserEvent(HttpHeaderParserEvent header_event) { |
| 39 UMA_HISTOGRAM_ENUMERATION("Net.HttpHeaderParserEvent", header_event, | 39 UMA_HISTOGRAM_ENUMERATION("Net.HttpHeaderParserEvent", header_event, |
| 40 NUM_HEADER_EVENTS); | 40 NUM_HEADER_EVENTS); |
| 41 } | 41 } |
| 42 | 42 |
| (...skipping 718 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 761 | 761 |
| 762 return result; | 762 return result; |
| 763 } | 763 } |
| 764 | 764 |
| 765 int HttpStreamParser::HandleReadHeaderResult(int result) { | 765 int HttpStreamParser::HandleReadHeaderResult(int result) { |
| 766 DCHECK_EQ(0, read_buf_unused_offset_); | 766 DCHECK_EQ(0, read_buf_unused_offset_); |
| 767 | 767 |
| 768 if (result == 0) | 768 if (result == 0) |
| 769 result = ERR_CONNECTION_CLOSED; | 769 result = ERR_CONNECTION_CLOSED; |
| 770 | 770 |
| 771 if (result < 0 && result != ERR_CONNECTION_CLOSED) { | 771 if (result == ERR_CONNECTION_CLOSED) { |
| 772 io_state_ = STATE_DONE; | 772 if (read_buf_->offset() == 0) { |
| 773 io_state_ = STATE_DONE; |
| 774 // If the connection has not been reused, it may have been a 0-length |
| 775 // HTTP/0.9 responses, but it was most likely an error, so just return |
| 776 // ERR_EMPTY_RESPONSE instead. If the connection was reused, just pass |
| 777 // on the original connection close error, as rather than being an |
| 778 // empty HTTP/0.9 response it's much more likely the server closed the |
| 779 // socket before it received the request. |
| 780 if (!connection_->is_reused()) |
| 781 return ERR_EMPTY_RESPONSE; |
| 782 return result; |
| 783 } |
| 784 |
| 785 // The connection closed before the end of the headers. For HTTPS, |
| 786 // accepting the partial headers headers is a potential security |
| 787 // vulnerability. For HTTP, it just doesn't seem like a good idea. |
| 788 if (response_header_start_offset_ >= 0) { |
| 789 io_state_ = STATE_DONE; |
| 790 return ERR_RESPONSE_HEADERS_TRUNCATED; |
| 791 } |
| 792 |
| 793 // The response is apparently using HTTP/0.9. Treat the entire response as |
| 794 // the body. |
| 795 int rv = ParseResponseHeaders(0); |
| 796 if (rv < 0) |
| 797 return rv; |
| 773 return result; | 798 return result; |
| 774 } | 799 } |
| 775 // If we've used the connection before, then we know it is not a HTTP/0.9 | 800 |
| 776 // response and return ERR_CONNECTION_CLOSED. | 801 if (result < 0) { |
| 777 if (result == ERR_CONNECTION_CLOSED && read_buf_->offset() == 0 && | |
| 778 connection_->is_reused()) { | |
| 779 io_state_ = STATE_DONE; | 802 io_state_ = STATE_DONE; |
| 780 return result; | 803 return result; |
| 781 } | 804 } |
| 782 | 805 |
| 783 // Record our best estimate of the 'response time' as the time when we read | 806 // Record our best estimate of the 'response time' as the time when we read |
| 784 // the first bytes of the response headers. | 807 // the first bytes of the response headers. |
| 785 if (read_buf_->offset() == 0 && result != ERR_CONNECTION_CLOSED) | 808 if (read_buf_->offset() == 0) |
| 786 response_->response_time = base::Time::Now(); | 809 response_->response_time = base::Time::Now(); |
| 787 | 810 |
| 788 if (result == ERR_CONNECTION_CLOSED) { | |
| 789 // The connection closed before we detected the end of the headers. | |
| 790 if (read_buf_->offset() == 0) { | |
| 791 // The connection was closed before any data was sent. Likely an error | |
| 792 // rather than empty HTTP/0.9 response. | |
| 793 io_state_ = STATE_DONE; | |
| 794 return ERR_EMPTY_RESPONSE; | |
| 795 } else if (request_->url.SchemeIsCryptographic()) { | |
| 796 // The connection was closed in the middle of the headers. For HTTPS we | |
| 797 // don't parse partial headers. Return a different error code so that we | |
| 798 // know that we shouldn't attempt to retry the request. | |
| 799 io_state_ = STATE_DONE; | |
| 800 return ERR_RESPONSE_HEADERS_TRUNCATED; | |
| 801 } | |
| 802 // Parse things as well as we can and let the caller decide what to do. | |
| 803 int end_offset; | |
| 804 if (response_header_start_offset_ >= 0) { | |
| 805 // The response looks to be a truncated set of HTTP headers. | |
| 806 io_state_ = STATE_READ_BODY_COMPLETE; | |
| 807 end_offset = read_buf_->offset(); | |
| 808 RecordHeaderParserEvent(HEADER_ALLOWED_TRUNCATED_HEADERS); | |
| 809 } else { | |
| 810 // The response is apparently using HTTP/0.9. Treat the entire response | |
| 811 // the body. | |
| 812 end_offset = 0; | |
| 813 } | |
| 814 int rv = ParseResponseHeaders(end_offset); | |
| 815 if (rv < 0) | |
| 816 return rv; | |
| 817 return result; | |
| 818 } | |
| 819 | |
| 820 read_buf_->set_offset(read_buf_->offset() + result); | 811 read_buf_->set_offset(read_buf_->offset() + result); |
| 821 DCHECK_LE(read_buf_->offset(), read_buf_->capacity()); | 812 DCHECK_LE(read_buf_->offset(), read_buf_->capacity()); |
| 822 DCHECK_GE(result, 0); | 813 DCHECK_GE(result, 0); |
| 823 | 814 |
| 824 int end_of_header_offset = FindAndParseResponseHeaders(); | 815 int end_of_header_offset = FindAndParseResponseHeaders(); |
| 825 | 816 |
| 826 // Note: -1 is special, it indicates we haven't found the end of headers. | 817 // Note: -1 is special, it indicates we haven't found the end of headers. |
| 827 // Anything less than -1 is a net::Error, so we bail out. | 818 // Anything less than -1 is a net::Error, so we bail out. |
| 828 if (end_of_header_offset < -1) | 819 if (end_of_header_offset < -1) |
| 829 return end_of_header_offset; | 820 return end_of_header_offset; |
| (...skipping 267 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1097 request_body->IsInMemory() && | 1088 request_body->IsInMemory() && |
| 1098 request_body->size() > 0) { | 1089 request_body->size() > 0) { |
| 1099 uint64 merged_size = request_headers.size() + request_body->size(); | 1090 uint64 merged_size = request_headers.size() + request_body->size(); |
| 1100 if (merged_size <= kMaxMergedHeaderAndBodySize) | 1091 if (merged_size <= kMaxMergedHeaderAndBodySize) |
| 1101 return true; | 1092 return true; |
| 1102 } | 1093 } |
| 1103 return false; | 1094 return false; |
| 1104 } | 1095 } |
| 1105 | 1096 |
| 1106 } // namespace net | 1097 } // namespace net |
| OLD | NEW |