| 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 |