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/compiler_specific.h" | 7 #include "base/compiler_specific.h" |
8 #include "base/metrics/histogram.h" | 8 #include "base/metrics/histogram.h" |
9 #include "base/string_util.h" | 9 #include "base/string_util.h" |
10 #include "net/base/address_list.h" | 10 #include "net/base/address_list.h" |
(...skipping 19 matching lines...) Expand all Loading... |
30 const char* header_line = null_separated_headers; | 30 const char* header_line = null_separated_headers; |
31 std::string cr_separated_headers; | 31 std::string cr_separated_headers; |
32 while (header_line[0] != 0) { | 32 while (header_line[0] != 0) { |
33 cr_separated_headers += header_line; | 33 cr_separated_headers += header_line; |
34 cr_separated_headers += "\n"; | 34 cr_separated_headers += "\n"; |
35 header_line += strlen(header_line) + 1; | 35 header_line += strlen(header_line) + 1; |
36 } | 36 } |
37 return cr_separated_headers; | 37 return cr_separated_headers; |
38 } | 38 } |
39 | 39 |
40 // Return true if |headers| contain multiple |field_name| fields. If | 40 // Return true if |headers| contain multiple |field_name| fields. |
41 // |count_same_value| is false, returns false if all copies of the field have | |
42 // the same value. | |
43 bool HeadersContainMultipleCopiesOfField( | 41 bool HeadersContainMultipleCopiesOfField( |
44 const net::HttpResponseHeaders& headers, | 42 const net::HttpResponseHeaders& headers, |
45 const std::string& field_name, | 43 const std::string& field_name) { |
46 bool count_same_value) { | |
47 void* it = NULL; | 44 void* it = NULL; |
48 std::string field_value; | 45 std::string field_value; |
49 if (!headers.EnumerateHeader(&it, field_name, &field_value)) | 46 if (!headers.EnumerateHeader(&it, field_name, &field_value)) |
50 return false; | 47 return false; |
51 // There's at least one |field_name| header. Check if there are any more | 48 // There's at least one |field_name| header. Check if there are any more |
52 // such headers, and if so, return true if they have different values or | 49 // such headers, and if so, return true if they have different values or |
53 // |count_same_value| is true. | 50 // |count_same_value| is true. |
54 std::string field_value2; | 51 std::string field_value2; |
55 while (headers.EnumerateHeader(&it, field_name, &field_value2)) { | 52 while (headers.EnumerateHeader(&it, field_name, &field_value2)) { |
56 if (count_same_value || field_value != field_value2) | 53 if (field_value != field_value2) |
57 return true; | 54 return true; |
58 } | 55 } |
59 return false; | 56 return false; |
60 } | 57 } |
61 | 58 |
62 } // namespace | 59 } // namespace |
63 | 60 |
64 namespace net { | 61 namespace net { |
65 | 62 |
66 // Similar to DrainableIOBuffer(), but this version comes with its own | 63 // Similar to DrainableIOBuffer(), but this version comes with its own |
(...skipping 703 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
770 read_buf_->StartOfBuffer() + read_buf_unused_offset_, end_offset)); | 767 read_buf_->StartOfBuffer() + read_buf_unused_offset_, end_offset)); |
771 } else { | 768 } else { |
772 // Enough data was read -- there is no status line. | 769 // Enough data was read -- there is no status line. |
773 headers = new HttpResponseHeaders(std::string("HTTP/0.9 200 OK")); | 770 headers = new HttpResponseHeaders(std::string("HTTP/0.9 200 OK")); |
774 } | 771 } |
775 | 772 |
776 // Check for multiple Content-Length headers with no Transfer-Encoding header. | 773 // Check for multiple Content-Length headers with no Transfer-Encoding header. |
777 // If they exist, and have distinct values, it's a potential response | 774 // If they exist, and have distinct values, it's a potential response |
778 // smuggling attack. | 775 // smuggling attack. |
779 if (!headers->HasHeader("Transfer-Encoding")) { | 776 if (!headers->HasHeader("Transfer-Encoding")) { |
780 if (HeadersContainMultipleCopiesOfField(*headers, | 777 if (HeadersContainMultipleCopiesOfField(*headers, "Content-Length")) |
781 "Content-Length", | |
782 false)) { | |
783 return ERR_RESPONSE_HEADERS_MULTIPLE_CONTENT_LENGTH; | 778 return ERR_RESPONSE_HEADERS_MULTIPLE_CONTENT_LENGTH; |
784 } | |
785 } | 779 } |
786 | 780 |
787 // Check for multiple Content-Disposition or Location headers. If they exist, | 781 // Check for multiple Content-Disposition or Location headers. If they exist, |
788 // it's also a potential response smuggling attack. | 782 // it's also a potential response smuggling attack. |
789 if (HeadersContainMultipleCopiesOfField(*headers, | 783 if (HeadersContainMultipleCopiesOfField(*headers, "Content-Disposition")) |
790 "Content-Disposition", | |
791 true)) { | |
792 return ERR_RESPONSE_HEADERS_MULTIPLE_CONTENT_DISPOSITION; | 784 return ERR_RESPONSE_HEADERS_MULTIPLE_CONTENT_DISPOSITION; |
793 } | 785 if (HeadersContainMultipleCopiesOfField(*headers, "Location")) |
794 if (HeadersContainMultipleCopiesOfField(*headers, "Location", true)) | |
795 return ERR_RESPONSE_HEADERS_MULTIPLE_LOCATION; | 786 return ERR_RESPONSE_HEADERS_MULTIPLE_LOCATION; |
796 | 787 |
797 response_->headers = headers; | 788 response_->headers = headers; |
798 response_->vary_data.Init(*request_, *response_->headers); | 789 response_->vary_data.Init(*request_, *response_->headers); |
799 DVLOG(1) << __FUNCTION__ << "()" | 790 DVLOG(1) << __FUNCTION__ << "()" |
800 << " content_length = \"" | 791 << " content_length = \"" |
801 << response_->headers->GetContentLength() << "\n\"" | 792 << response_->headers->GetContentLength() << "\n\"" |
802 << " headers = \"" << GetResponseHeaderLines(*response_->headers) | 793 << " headers = \"" << GetResponseHeaderLines(*response_->headers) |
803 << "\""; | 794 << "\""; |
804 return OK; | 795 return OK; |
(...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
933 request_body->IsInMemory() && | 924 request_body->IsInMemory() && |
934 request_body->size() > 0) { | 925 request_body->size() > 0) { |
935 size_t merged_size = request_headers.size() + request_body->size(); | 926 size_t merged_size = request_headers.size() + request_body->size(); |
936 if (merged_size <= kMaxMergedHeaderAndBodySize) | 927 if (merged_size <= kMaxMergedHeaderAndBodySize) |
937 return true; | 928 return true; |
938 } | 929 } |
939 return false; | 930 return false; |
940 } | 931 } |
941 | 932 |
942 } // namespace net | 933 } // namespace net |
OLD | NEW |