Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(116)

Side by Side Diff: net/http/http_stream_parser.cc

Issue 1074263003: Add histograms for a number of hacks in the HTTP header parsing logic. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@fetcher4
Patch Set: Merge Created 5 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698