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 if (strspn(read_buf_->StartOfBuffer(), " \t\r\n") >= | |
davidben
2015/04/13 19:55:14
I believe read_buf_ needn't be NUL-terminated, so
mmenke
2015/04/13 21:12:21
This is certainly true...On the other hand, we *kn
davidben
2015/04/14 23:41:39
Oh, I see. StartOfBuffer is also where LocateStart
| |
953 static_cast<size_t>(response_header_start_offset_)) { | |
954 RecordHeaderParserEvent(HEADER_SKIPPED_WS_PREFIX); | |
955 } else { | |
956 RecordHeaderParserEvent(HEADER_SKIPPED_NON_WS_PREFIX); | |
957 } | |
958 } | |
959 | |
931 if (response_header_start_offset_ >= 0) { | 960 if (response_header_start_offset_ >= 0) { |
932 received_bytes_ += end_offset; | 961 received_bytes_ += end_offset; |
933 headers = new HttpResponseHeaders(HttpUtil::AssembleRawHeaders( | 962 headers = new HttpResponseHeaders(HttpUtil::AssembleRawHeaders( |
934 read_buf_->StartOfBuffer(), end_offset)); | 963 read_buf_->StartOfBuffer(), end_offset)); |
935 } else { | 964 } else { |
936 // Enough data was read -- there is no status line. | 965 // Enough data was read -- there is no status line. |
937 headers = new HttpResponseHeaders(std::string("HTTP/0.9 200 OK")); | 966 headers = new HttpResponseHeaders(std::string("HTTP/0.9 200 OK")); |
967 RecordHeaderParserEvent(HEADER_HTTP_09_RESPONSE); | |
938 } | 968 } |
939 | 969 |
940 // Check for multiple Content-Length headers with no Transfer-Encoding header. | 970 // Check for multiple Content-Length headers with no Transfer-Encoding header. |
941 // If they exist, and have distinct values, it's a potential response | 971 // If they exist, and have distinct values, it's a potential response |
942 // smuggling attack. | 972 // smuggling attack. |
943 if (!headers->HasHeader("Transfer-Encoding")) { | 973 if (!headers->HasHeader("Transfer-Encoding")) { |
944 if (HeadersContainMultipleCopiesOfField(*headers.get(), "Content-Length")) | 974 if (HeadersContainMultipleCopiesOfField(*headers.get(), "Content-Length")) |
945 return ERR_RESPONSE_HEADERS_MULTIPLE_CONTENT_LENGTH; | 975 return ERR_RESPONSE_HEADERS_MULTIPLE_CONTENT_LENGTH; |
946 } | 976 } |
947 | 977 |
(...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1093 request_body->IsInMemory() && | 1123 request_body->IsInMemory() && |
1094 request_body->size() > 0) { | 1124 request_body->size() > 0) { |
1095 uint64 merged_size = request_headers.size() + request_body->size(); | 1125 uint64 merged_size = request_headers.size() + request_body->size(); |
1096 if (merged_size <= kMaxMergedHeaderAndBodySize) | 1126 if (merged_size <= kMaxMergedHeaderAndBodySize) |
1097 return true; | 1127 return true; |
1098 } | 1128 } |
1099 return false; | 1129 return false; |
1100 } | 1130 } |
1101 | 1131 |
1102 } // namespace net | 1132 } // namespace net |
OLD | NEW |