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/profiler/scoped_tracker.h" | 11 #include "base/profiler/scoped_tracker.h" |
11 #include "base/strings/string_util.h" | 12 #include "base/strings/string_util.h" |
12 #include "base/values.h" | 13 #include "base/values.h" |
13 #include "net/base/io_buffer.h" | 14 #include "net/base/io_buffer.h" |
14 #include "net/base/ip_endpoint.h" | 15 #include "net/base/ip_endpoint.h" |
15 #include "net/base/upload_data_stream.h" | 16 #include "net/base/upload_data_stream.h" |
16 #include "net/http/http_chunked_decoder.h" | 17 #include "net/http/http_chunked_decoder.h" |
17 #include "net/http/http_request_headers.h" | 18 #include "net/http/http_request_headers.h" |
18 #include "net/http/http_request_info.h" | 19 #include "net/http/http_request_info.h" |
19 #include "net/http/http_response_headers.h" | 20 #include "net/http/http_response_headers.h" |
20 #include "net/http/http_util.h" | 21 #include "net/http/http_util.h" |
21 #include "net/socket/client_socket_handle.h" | 22 #include "net/socket/client_socket_handle.h" |
22 #include "net/socket/ssl_client_socket.h" | 23 #include "net/socket/ssl_client_socket.h" |
23 | 24 |
24 namespace net { | 25 namespace net { |
25 | 26 |
26 namespace { | 27 namespace { |
27 | 28 |
| 29 enum HttpHeaderParserEvent { |
| 30 HEADER_PARSER_INVOKED = 0, |
| 31 HEADER_HTTP_09_RESPONSE = 1, |
| 32 HEADER_ALLOWED_TRUNCATED_HEADERS = 2, |
| 33 HEADER_SKIPPED_WS_PREFIX = 3, |
| 34 HEADER_SKIPPED_NON_WS_PREFIX = 4, |
| 35 NUM_HEADER_EVENTS |
| 36 }; |
| 37 |
| 38 void RecordHeaderParserEvent(HttpHeaderParserEvent header_event) { |
| 39 UMA_HISTOGRAM_ENUMERATION("Net.HttpHeaderParserEvent", header_event, |
| 40 NUM_HEADER_EVENTS); |
| 41 } |
| 42 |
28 const uint64 kMaxMergedHeaderAndBodySize = 1400; | 43 const uint64 kMaxMergedHeaderAndBodySize = 1400; |
29 const size_t kRequestBodyBufferSize = 1 << 14; // 16KB | 44 const size_t kRequestBodyBufferSize = 1 << 14; // 16KB |
30 | 45 |
31 std::string GetResponseHeaderLines(const HttpResponseHeaders& headers) { | 46 std::string GetResponseHeaderLines(const HttpResponseHeaders& headers) { |
32 std::string raw_headers = headers.raw_headers(); | 47 std::string raw_headers = headers.raw_headers(); |
33 const char* null_separated_headers = raw_headers.c_str(); | 48 const char* null_separated_headers = raw_headers.c_str(); |
34 const char* header_line = null_separated_headers; | 49 const char* header_line = null_separated_headers; |
35 std::string cr_separated_headers; | 50 std::string cr_separated_headers; |
36 while (header_line[0] != 0) { | 51 while (header_line[0] != 0) { |
37 cr_separated_headers += header_line; | 52 cr_separated_headers += header_line; |
(...skipping 783 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
821 } else if (request_->url.SchemeIsSecure()) { | 836 } else if (request_->url.SchemeIsSecure()) { |
822 // The connection was closed in the middle of the headers. For HTTPS we | 837 // The connection was closed in the middle of the headers. For HTTPS we |
823 // don't parse partial headers. Return a different error code so that we | 838 // don't parse partial headers. Return a different error code so that we |
824 // know that we shouldn't attempt to retry the request. | 839 // know that we shouldn't attempt to retry the request. |
825 io_state_ = STATE_DONE; | 840 io_state_ = STATE_DONE; |
826 return ERR_RESPONSE_HEADERS_TRUNCATED; | 841 return ERR_RESPONSE_HEADERS_TRUNCATED; |
827 } | 842 } |
828 // Parse things as well as we can and let the caller decide what to do. | 843 // Parse things as well as we can and let the caller decide what to do. |
829 int end_offset; | 844 int end_offset; |
830 if (response_header_start_offset_ >= 0) { | 845 if (response_header_start_offset_ >= 0) { |
| 846 // The response looks to be a truncated set of HTTP headers. |
831 io_state_ = STATE_READ_BODY_COMPLETE; | 847 io_state_ = STATE_READ_BODY_COMPLETE; |
832 end_offset = read_buf_->offset(); | 848 end_offset = read_buf_->offset(); |
| 849 RecordHeaderParserEvent(HEADER_ALLOWED_TRUNCATED_HEADERS); |
833 } else { | 850 } else { |
834 // Now waiting for the body to be read. | 851 // The response is apparently using HTTP/0.9. Treat the entire response |
| 852 // the body. |
835 end_offset = 0; | 853 end_offset = 0; |
836 } | 854 } |
837 int rv = DoParseResponseHeaders(end_offset); | 855 int rv = ParseResponseHeaders(end_offset); |
838 if (rv < 0) | 856 if (rv < 0) |
839 return rv; | 857 return rv; |
840 return result; | 858 return result; |
841 } | 859 } |
842 | 860 |
843 read_buf_->set_offset(read_buf_->offset() + result); | 861 read_buf_->set_offset(read_buf_->offset() + result); |
844 DCHECK_LE(read_buf_->offset(), read_buf_->capacity()); | 862 DCHECK_LE(read_buf_->offset(), read_buf_->capacity()); |
845 DCHECK_GE(result, 0); | 863 DCHECK_GE(result, 0); |
846 | 864 |
847 int end_of_header_offset = ParseResponseHeaders(); | 865 int end_of_header_offset = FindAndParseResponseHeaders(); |
848 | 866 |
849 // Note: -1 is special, it indicates we haven't found the end of headers. | 867 // Note: -1 is special, it indicates we haven't found the end of headers. |
850 // Anything less than -1 is a net::Error, so we bail out. | 868 // Anything less than -1 is a net::Error, so we bail out. |
851 if (end_of_header_offset < -1) | 869 if (end_of_header_offset < -1) |
852 return end_of_header_offset; | 870 return end_of_header_offset; |
853 | 871 |
854 if (end_of_header_offset == -1) { | 872 if (end_of_header_offset == -1) { |
855 io_state_ = STATE_READ_HEADERS; | 873 io_state_ = STATE_READ_HEADERS; |
856 // Prevent growing the headers buffer indefinitely. | 874 // Prevent growing the headers buffer indefinitely. |
857 if (read_buf_->offset() >= kMaxHeaderBufSize) { | 875 if (read_buf_->offset() >= kMaxHeaderBufSize) { |
(...skipping 30 matching lines...) Expand all Loading... |
888 return OK; | 906 return OK; |
889 } | 907 } |
890 | 908 |
891 // Note where the headers stop. | 909 // Note where the headers stop. |
892 read_buf_unused_offset_ = end_of_header_offset; | 910 read_buf_unused_offset_ = end_of_header_offset; |
893 // Now waiting for the body to be read. | 911 // Now waiting for the body to be read. |
894 } | 912 } |
895 return result; | 913 return result; |
896 } | 914 } |
897 | 915 |
898 int HttpStreamParser::ParseResponseHeaders() { | 916 int HttpStreamParser::FindAndParseResponseHeaders() { |
899 int end_offset = -1; | 917 int end_offset = -1; |
900 DCHECK_EQ(0, read_buf_unused_offset_); | 918 DCHECK_EQ(0, read_buf_unused_offset_); |
901 | 919 |
902 // Look for the start of the status line, if it hasn't been found yet. | 920 // Look for the start of the status line, if it hasn't been found yet. |
903 if (response_header_start_offset_ < 0) { | 921 if (response_header_start_offset_ < 0) { |
904 response_header_start_offset_ = HttpUtil::LocateStartOfStatusLine( | 922 response_header_start_offset_ = HttpUtil::LocateStartOfStatusLine( |
905 read_buf_->StartOfBuffer(), read_buf_->offset()); | 923 read_buf_->StartOfBuffer(), read_buf_->offset()); |
906 } | 924 } |
907 | 925 |
908 if (response_header_start_offset_ >= 0) { | 926 if (response_header_start_offset_ >= 0) { |
909 end_offset = HttpUtil::LocateEndOfHeaders(read_buf_->StartOfBuffer(), | 927 end_offset = HttpUtil::LocateEndOfHeaders(read_buf_->StartOfBuffer(), |
910 read_buf_->offset(), | 928 read_buf_->offset(), |
911 response_header_start_offset_); | 929 response_header_start_offset_); |
912 } else if (read_buf_->offset() >= 8) { | 930 } else if (read_buf_->offset() >= 8) { |
913 // Enough data to decide that this is an HTTP/0.9 response. | 931 // Enough data to decide that this is an HTTP/0.9 response. |
914 // 8 bytes = (4 bytes of junk) + "http".length() | 932 // 8 bytes = (4 bytes of junk) + "http".length() |
915 end_offset = 0; | 933 end_offset = 0; |
916 } | 934 } |
917 | 935 |
918 if (end_offset == -1) | 936 if (end_offset == -1) |
919 return -1; | 937 return -1; |
920 | 938 |
921 int rv = DoParseResponseHeaders(end_offset); | 939 int rv = ParseResponseHeaders(end_offset); |
922 if (rv < 0) | 940 if (rv < 0) |
923 return rv; | 941 return rv; |
924 return end_offset; | 942 return end_offset; |
925 } | 943 } |
926 | 944 |
927 int HttpStreamParser::DoParseResponseHeaders(int end_offset) { | 945 int HttpStreamParser::ParseResponseHeaders(int end_offset) { |
928 scoped_refptr<HttpResponseHeaders> headers; | 946 scoped_refptr<HttpResponseHeaders> headers; |
929 DCHECK_EQ(0, read_buf_unused_offset_); | 947 DCHECK_EQ(0, read_buf_unused_offset_); |
930 | 948 |
| 949 RecordHeaderParserEvent(HEADER_PARSER_INVOKED); |
| 950 |
| 951 if (response_header_start_offset_ > 0) { |
| 952 bool has_non_whitespace_in_prefix = false; |
| 953 for (int i = 0; i < response_header_start_offset_; ++i) { |
| 954 if (!strchr(" \t\r\n", read_buf_->StartOfBuffer()[i])) { |
| 955 has_non_whitespace_in_prefix = true; |
| 956 break; |
| 957 } |
| 958 } |
| 959 if (has_non_whitespace_in_prefix) { |
| 960 RecordHeaderParserEvent(HEADER_SKIPPED_NON_WS_PREFIX); |
| 961 } else { |
| 962 RecordHeaderParserEvent(HEADER_SKIPPED_WS_PREFIX); |
| 963 } |
| 964 } |
| 965 |
931 if (response_header_start_offset_ >= 0) { | 966 if (response_header_start_offset_ >= 0) { |
932 received_bytes_ += end_offset; | 967 received_bytes_ += end_offset; |
933 headers = new HttpResponseHeaders(HttpUtil::AssembleRawHeaders( | 968 headers = new HttpResponseHeaders(HttpUtil::AssembleRawHeaders( |
934 read_buf_->StartOfBuffer(), end_offset)); | 969 read_buf_->StartOfBuffer(), end_offset)); |
935 } else { | 970 } else { |
936 // Enough data was read -- there is no status line. | 971 // Enough data was read -- there is no status line. |
937 headers = new HttpResponseHeaders(std::string("HTTP/0.9 200 OK")); | 972 headers = new HttpResponseHeaders(std::string("HTTP/0.9 200 OK")); |
| 973 RecordHeaderParserEvent(HEADER_HTTP_09_RESPONSE); |
938 } | 974 } |
939 | 975 |
940 // Check for multiple Content-Length headers with no Transfer-Encoding header. | 976 // Check for multiple Content-Length headers with no Transfer-Encoding header. |
941 // If they exist, and have distinct values, it's a potential response | 977 // If they exist, and have distinct values, it's a potential response |
942 // smuggling attack. | 978 // smuggling attack. |
943 if (!headers->HasHeader("Transfer-Encoding")) { | 979 if (!headers->HasHeader("Transfer-Encoding")) { |
944 if (HeadersContainMultipleCopiesOfField(*headers.get(), "Content-Length")) | 980 if (HeadersContainMultipleCopiesOfField(*headers.get(), "Content-Length")) |
945 return ERR_RESPONSE_HEADERS_MULTIPLE_CONTENT_LENGTH; | 981 return ERR_RESPONSE_HEADERS_MULTIPLE_CONTENT_LENGTH; |
946 } | 982 } |
947 | 983 |
(...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1093 request_body->IsInMemory() && | 1129 request_body->IsInMemory() && |
1094 request_body->size() > 0) { | 1130 request_body->size() > 0) { |
1095 uint64 merged_size = request_headers.size() + request_body->size(); | 1131 uint64 merged_size = request_headers.size() + request_body->size(); |
1096 if (merged_size <= kMaxMergedHeaderAndBodySize) | 1132 if (merged_size <= kMaxMergedHeaderAndBodySize) |
1097 return true; | 1133 return true; |
1098 } | 1134 } |
1099 return false; | 1135 return false; |
1100 } | 1136 } |
1101 | 1137 |
1102 } // namespace net | 1138 } // namespace net |
OLD | NEW |