Chromium Code Reviews| 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 |