diff options
29 files changed, 409 insertions, 332 deletions
diff --git a/base/string_util.cc b/base/string_util.cc index fafc106..0269ba1 100644 --- a/base/string_util.cc +++ b/base/string_util.cc @@ -1352,20 +1352,6 @@ void SplitStringUsingSubstr(const std::string& str, SplitStringUsingSubstrT(str, s, r); } -std::vector<string16> SplitStringUsingSubstr(const string16& str, - const string16& s) { - std::vector<string16> result; - SplitStringUsingSubstr(str, s, &result); - return result; -} - -std::vector<std::string> SplitStringUsingSubstr(const std::string& str, - const std::string& s) { - std::vector<std::string> result; - SplitStringUsingSubstr(str, s, &result); - return result; -} - template<typename STR> static size_t TokenizeT(const STR& str, const STR& delimiters, diff --git a/net/http/http_auth_handler.h b/net/http/http_auth_handler.h index dc87d34..40ebe8d 100644 --- a/net/http/http_auth_handler.h +++ b/net/http/http_auth_handler.h @@ -15,8 +15,8 @@ namespace net { class BoundNetLog; class HostResolver; -class HttpRequestInfo; class ProxyInfo; +struct HttpRequestInfo; // HttpAuthHandler is the interface for the authentication schemes // (basic, digest, NTLM, Negotiate). diff --git a/net/http/http_auth_sspi_win.h b/net/http/http_auth_sspi_win.h index a6fb49e..12808bf 100644 --- a/net/http/http_auth_sspi_win.h +++ b/net/http/http_auth_sspi_win.h @@ -20,7 +20,7 @@ namespace net { -class HttpRequestInfo; +struct HttpRequestInfo; class ProxyInfo; // SSPILibrary is introduced so unit tests can mock the calls to Windows' SSPI @@ -152,4 +152,3 @@ int DetermineMaxTokenLength(SSPILibrary* library, } // namespace net #endif // NET_HTTP_HTTP_AUTH_SSPI_WIN_H_ - diff --git a/net/http/http_basic_stream.h b/net/http/http_basic_stream.h index cd533db..8a31d64 100644 --- a/net/http/http_basic_stream.h +++ b/net/http/http_basic_stream.h @@ -20,7 +20,7 @@ namespace net { class BoundNetLog; class ClientSocketHandle; -class HttpRequestInfo; +struct HttpRequestInfo; class HttpResponseInfo; class UploadDataStream; diff --git a/net/http/http_cache.h b/net/http/http_cache.h index f8db513..836bb52 100644 --- a/net/http/http_cache.h +++ b/net/http/http_cache.h @@ -40,7 +40,7 @@ namespace net { class HostResolver; class HttpAuthHandlerFactory; class HttpNetworkSession; -class HttpRequestInfo; +struct HttpRequestInfo; class HttpResponseInfo; class IOBuffer; class NetworkChangeNotifier; diff --git a/net/http/http_cache_transaction.cc b/net/http/http_cache_transaction.cc index b5b3515..c0eefea 100644 --- a/net/http/http_cache_transaction.cc +++ b/net/http/http_cache_transaction.cc @@ -69,16 +69,17 @@ static const HeaderNameAndValue kForceValidateHeaders[] = { { NULL, NULL } }; -static bool HeaderMatches(const HttpUtil::HeadersIterator& h, +static bool HeaderMatches(const HttpRequestHeaders& headers, const HeaderNameAndValue* search) { for (; search->name; ++search) { - if (!LowerCaseEqualsASCII(h.name_begin(), h.name_end(), search->name)) + std::string header_value; + if (!headers.GetHeader(search->name, &header_value)) continue; if (!search->value) return true; - HttpUtil::ValuesIterator v(h.values_begin(), h.values_end(), ','); + HttpUtil::ValuesIterator v(header_value.begin(), header_value.end(), ','); while (v.GetNext()) { if (LowerCaseEqualsASCII(v.value_begin(), v.value_end(), search->value)) return true; @@ -1176,45 +1177,37 @@ void HttpCache::Transaction::SetRequest(const BoundNetLog& net_log, { kForceValidateHeaders, LOAD_VALIDATE_CACHE }, }; - std::string new_extra_headers; bool range_found = false; bool external_validation_error = false; - // scan request headers to see if we have any that would impact our load flags - HttpUtil::HeadersIterator it(request_->extra_headers.begin(), - request_->extra_headers.end(), - "\r\n"); - while (it.GetNext()) { - if (!LowerCaseEqualsASCII(it.name(), "range")) { - new_extra_headers.append(it.name_begin(), it.values_end()); - new_extra_headers.append("\r\n"); + if (request_->extra_headers.HasHeader(HttpRequestHeaders::kRange)) { + if (enable_range_support_) { + range_found = true; } else { - if (enable_range_support_) { - range_found = true; - } else { - effective_load_flags_ |= LOAD_DISABLE_CACHE; - continue; - } + effective_load_flags_ |= LOAD_DISABLE_CACHE; } - for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kSpecialHeaders); ++i) { - if (HeaderMatches(it, kSpecialHeaders[i].search)) { - effective_load_flags_ |= kSpecialHeaders[i].load_flag; - break; - } + } + + for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kSpecialHeaders); ++i) { + if (HeaderMatches(request_->extra_headers, kSpecialHeaders[i].search)) { + effective_load_flags_ |= kSpecialHeaders[i].load_flag; + break; } + } - // Check for conditionalization headers which may correspond with a - // cache validation request. - for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kValidationHeaders); ++i) { - const ValidationHeaderInfo& info = kValidationHeaders[i]; - if (LowerCaseEqualsASCII(it.name_begin(), it.name_end(), - info.request_header_name)) { - if (!external_validation_.values[i].empty() || it.values().empty()) - external_validation_error = true; - external_validation_.values[i] = it.values(); - external_validation_.initialized = true; - break; - } + // Check for conditionalization headers which may correspond with a + // cache validation request. + for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kValidationHeaders); ++i) { + const ValidationHeaderInfo& info = kValidationHeaders[i]; + std::string validation_value; + if (request_->extra_headers.GetHeader( + info.request_header_name, &validation_value)) { + if (!external_validation_.values[i].empty() || + validation_value.empty()) + external_validation_error = true; + external_validation_.values[i] = validation_value; + external_validation_.initialized = true; + break; } } @@ -1238,9 +1231,9 @@ void HttpCache::Transaction::SetRequest(const BoundNetLog& net_log, // We will be modifying the actual range requested to the server, so // let's remove the header here. custom_request_.reset(new HttpRequestInfo(*request_)); + custom_request_->extra_headers.RemoveHeader(HttpRequestHeaders::kRange); request_ = custom_request_.get(); - custom_request_->extra_headers = new_extra_headers; - partial_->SetHeaders(new_extra_headers); + partial_->SetHeaders(custom_request_->extra_headers); } else { // The range is invalid or we cannot handle it properly. LOG(INFO) << "Invalid byte range found."; @@ -1502,12 +1495,12 @@ bool HttpCache::Transaction::ConditionalizeRequest() { if (partial_.get() && !partial_->IsCurrentRangeCached()) { // We don't want to switch to WRITE mode if we don't have this block of a // byte-range request because we may have other parts cached. - custom_request_->extra_headers.append("If-Range: "); + custom_request_->extra_headers.SetHeader( + HttpRequestHeaders::kIfRange, etag_value); } else { - custom_request_->extra_headers.append("If-None-Match: "); + custom_request_->extra_headers.SetHeader( + HttpRequestHeaders::kIfNoneMatch, etag_value); } - custom_request_->extra_headers.append(etag_value); - custom_request_->extra_headers.append("\r\n"); // For byte-range requests, make sure that we use only one way to validate // the request. if (partial_.get() && !partial_->IsCurrentRangeCached()) @@ -1516,12 +1509,12 @@ bool HttpCache::Transaction::ConditionalizeRequest() { if (!last_modified_value.empty()) { if (partial_.get() && !partial_->IsCurrentRangeCached()) { - custom_request_->extra_headers.append("If-Range: "); + custom_request_->extra_headers.SetHeader( + HttpRequestHeaders::kIfRange, last_modified_value); } else { - custom_request_->extra_headers.append("If-Modified-Since: "); + custom_request_->extra_headers.SetHeader( + HttpRequestHeaders::kIfModifiedSince, last_modified_value); } - custom_request_->extra_headers.append(last_modified_value); - custom_request_->extra_headers.append("\r\n"); } return true; diff --git a/net/http/http_cache_unittest.cc b/net/http/http_cache_unittest.cc index 4e8a139..48e61e7 100644 --- a/net/http/http_cache_unittest.cc +++ b/net/http/http_cache_unittest.cc @@ -15,6 +15,7 @@ #include "net/base/ssl_cert_request_info.h" #include "net/disk_cache/disk_cache.h" #include "net/http/http_byte_range.h" +#include "net/http/http_request_headers.h" #include "net/http/http_request_info.h" #include "net/http/http_response_headers.h" #include "net/http/http_response_info.h" @@ -726,20 +727,21 @@ bool RangeTransactionServer::modified_ = false; bool RangeTransactionServer::bad_200_ = false; // A dummy extra header that must be preserved on a given request. -#define EXTRA_HEADER "Extra: header\r\n" +#define EXTRA_HEADER "Extra: header" +static const char kExtraHeaderKey[] = "Extra"; // Static. void RangeTransactionServer::RangeHandler(const net::HttpRequestInfo* request, std::string* response_status, std::string* response_headers, std::string* response_data) { - if (request->extra_headers.empty()) { + if (request->extra_headers.IsEmpty()) { response_status->assign("HTTP/1.1 416 Requested Range Not Satisfiable"); return; } // We want to make sure we don't delete extra headers. - EXPECT_TRUE(request->extra_headers.find(EXTRA_HEADER) != std::string::npos); + EXPECT_TRUE(request->extra_headers.HasHeader(kExtraHeaderKey)); if (not_modified_) { response_status->assign("HTTP/1.1 304 Not Modified"); @@ -747,7 +749,10 @@ void RangeTransactionServer::RangeHandler(const net::HttpRequestInfo* request, } std::vector<net::HttpByteRange> ranges; - if (!net::HttpUtil::ParseRanges(request->extra_headers, &ranges) || + std::string range_header; + if (!request->extra_headers.GetHeader( + net::HttpRequestHeaders::kRange, &range_header) || + !net::HttpUtil::ParseRangeHeader(range_header, &ranges) || ranges.size() != 1) return; // We can handle this range request. @@ -763,19 +768,11 @@ void RangeTransactionServer::RangeHandler(const net::HttpRequestInfo* request, EXPECT_LT(end, 80); - size_t if_range_header = request->extra_headers.find("If-Range"); - if (std::string::npos != if_range_header) { - // Check that If-Range isn't specified twice. - EXPECT_EQ(std::string::npos, - request->extra_headers.find("If-Range", if_range_header + 1)); - } - std::string content_range = StringPrintf("Content-Range: bytes %d-%d/80\n", start, end); response_headers->append(content_range); - if (request->extra_headers.find("If-None-Match") == std::string::npos || - modified_) { + if (!request->extra_headers.HasHeader("If-None-Match") || modified_) { EXPECT_EQ(9, (end - start) % 10); std::string data; for (int block_start = start; block_start < end; block_start += 10) @@ -819,33 +816,25 @@ const MockTransaction kRangeGET_TransactionOK = { 0 }; -// Returns true if the response headers (|response|) match a partial content +// Verifies the response headers (|response|) match a partial content // response for the range starting at |start| and ending at |end|. -bool Verify206Response(std::string response, int start, int end) { +void Verify206Response(std::string response, int start, int end) { std::string raw_headers(net::HttpUtil::AssembleRawHeaders(response.data(), response.size())); scoped_refptr<net::HttpResponseHeaders> headers = new net::HttpResponseHeaders(raw_headers); - if (206 != headers->response_code()) - return false; + ASSERT_EQ(206, headers->response_code()); int64 range_start, range_end, object_size; - if (!headers->GetContentRange(&range_start, &range_end, &object_size)) - return false; + ASSERT_TRUE( + headers->GetContentRange(&range_start, &range_end, &object_size)); int64 content_length = headers->GetContentLength(); int length = end - start + 1; - if (content_length != length) - return false; - - if (range_start != start) - return false; - - if (range_end != end) - return false; - - return true; + ASSERT_EQ(length, content_length); + ASSERT_EQ(start, range_start); + ASSERT_EQ(end, range_end); } // Helper to represent a network HTTP response. @@ -1220,7 +1209,7 @@ static void PreserveRequestHeaders_Handler( std::string* response_status, std::string* response_headers, std::string* response_data) { - EXPECT_TRUE(request->extra_headers.find(EXTRA_HEADER) != std::string::npos); + EXPECT_TRUE(request->extra_headers.HasHeader(kExtraHeaderKey)); } // Tests that we don't remove extra headers for simple requests. @@ -1252,7 +1241,7 @@ TEST(HttpCache, ConditionalizedGET_PreserveRequestHeaders) { MockTransaction transaction(kETagGET_Transaction); transaction.handler = PreserveRequestHeaders_Handler; - transaction.request_headers = "If-None-Match: \"foopy\"\n" + transaction.request_headers = "If-None-Match: \"foopy\"\r\n" EXTRA_HEADER; AddMockTransaction(&transaction); @@ -1703,8 +1692,8 @@ static void ETagGet_ConditionalRequest_Handler( std::string* response_status, std::string* response_headers, std::string* response_data) { - EXPECT_TRUE(request->extra_headers.find("If-None-Match") != - std::string::npos); + EXPECT_TRUE( + request->extra_headers.HasHeader(net::HttpRequestHeaders::kIfNoneMatch)); response_status->assign("HTTP/1.1 304 Not Modified"); response_headers->assign(kETagGET_Transaction.response_headers); response_data->clear(); @@ -1738,8 +1727,8 @@ static void ETagGet_ConditionalRequest_NoStore_Handler( std::string* response_status, std::string* response_headers, std::string* response_data) { - EXPECT_TRUE(request->extra_headers.find("If-None-Match") != - std::string::npos); + EXPECT_TRUE( + request->extra_headers.HasHeader(net::HttpRequestHeaders::kIfNoneMatch)); response_status->assign("HTTP/1.1 304 Not Modified"); response_headers->assign("Cache-Control: no-store\n"); response_data->clear(); @@ -2004,7 +1993,7 @@ TEST(HttpCache, ConditionalizedRequestUpdatesCache4) { }; const char* kExtraRequestHeaders = - "If-Modified-Since: Wed, 06 Feb 2008 22:38:21 GMT\n"; + "If-Modified-Since: Wed, 06 Feb 2008 22:38:21 GMT"; // We will control the network layer's responses for |kUrl| using // |mock_network_response|. @@ -2048,7 +2037,7 @@ TEST(HttpCache, ConditionalizedRequestUpdatesCache5) { }; const char* kExtraRequestHeaders = - "If-Modified-Since: Wed, 06 Feb 2008 22:38:21 GMT\n"; + "If-Modified-Since: Wed, 06 Feb 2008 22:38:21 GMT"; // We will control the network layer's responses for |kUrl| using // |mock_network_response|. @@ -2156,8 +2145,8 @@ TEST(HttpCache, ConditionalizedRequestUpdatesCache8) { }; const char* kExtraRequestHeaders = - "If-Modified-Since: Wed, 06 Feb 2008 22:38:21 GMT\n" - "If-None-Match: \"Foo1\"\n"; + "If-Modified-Since: Wed, 06 Feb 2008 22:38:21 GMT\r\n" + "If-None-Match: \"Foo1\"\r\n"; ConditionalizedRequestUpdatesCacheHelper( kNetResponse1, kNetResponse2, kNetResponse2, kExtraRequestHeaders); @@ -2371,9 +2360,9 @@ TEST(HttpCache, RangeGET_SkipsCache2) { cache.http_cache()->set_enable_range_support(true); MockTransaction transaction(kRangeGET_Transaction); - transaction.request_headers = "If-None-Match: foo\n" + transaction.request_headers = "If-None-Match: foo\r\n" EXTRA_HEADER - "Range: bytes = 40-49\n"; + "\r\nRange: bytes = 40-49"; RunTransactionTest(cache.http_cache(), transaction); EXPECT_EQ(1, cache.network_layer()->transaction_count()); @@ -2381,18 +2370,18 @@ TEST(HttpCache, RangeGET_SkipsCache2) { EXPECT_EQ(0, cache.disk_cache()->create_count()); transaction.request_headers = - "If-Modified-Since: Wed, 28 Nov 2007 00:45:20 GMT\n" + "If-Modified-Since: Wed, 28 Nov 2007 00:45:20 GMT\r\n" EXTRA_HEADER - "Range: bytes = 40-49\n"; + "\r\nRange: bytes = 40-49"; RunTransactionTest(cache.http_cache(), transaction); EXPECT_EQ(2, cache.network_layer()->transaction_count()); EXPECT_EQ(0, cache.disk_cache()->open_count()); EXPECT_EQ(0, cache.disk_cache()->create_count()); - transaction.request_headers = "If-Range: bla\n" + transaction.request_headers = "If-Range: bla\r\n" EXTRA_HEADER - "Range: bytes = 40-49\n"; + "\r\nRange: bytes = 40-49\n"; RunTransactionTest(cache.http_cache(), transaction); EXPECT_EQ(3, cache.network_layer()->transaction_count()); @@ -2437,7 +2426,7 @@ TEST(HttpCache, RangeGET_OK) { RunTransactionTestWithResponse(cache.http_cache(), kRangeGET_TransactionOK, &headers); - EXPECT_TRUE(Verify206Response(headers, 40, 49)); + Verify206Response(headers, 40, 49); EXPECT_EQ(1, cache.network_layer()->transaction_count()); EXPECT_EQ(0, cache.disk_cache()->open_count()); EXPECT_EQ(1, cache.disk_cache()->create_count()); @@ -2446,7 +2435,7 @@ TEST(HttpCache, RangeGET_OK) { RunTransactionTestWithResponse(cache.http_cache(), kRangeGET_TransactionOK, &headers); - EXPECT_TRUE(Verify206Response(headers, 40, 49)); + Verify206Response(headers, 40, 49); EXPECT_EQ(2, cache.network_layer()->transaction_count()); EXPECT_EQ(1, cache.disk_cache()->open_count()); EXPECT_EQ(1, cache.disk_cache()->create_count()); @@ -2460,7 +2449,7 @@ TEST(HttpCache, RangeGET_OK) { transaction.data = "rg: 30-39 "; RunTransactionTestWithResponse(cache.http_cache(), transaction, &headers); - EXPECT_TRUE(Verify206Response(headers, 30, 39)); + Verify206Response(headers, 30, 39); EXPECT_EQ(3, cache.network_layer()->transaction_count()); EXPECT_EQ(2, cache.disk_cache()->open_count()); EXPECT_EQ(1, cache.disk_cache()->create_count()); @@ -2473,7 +2462,7 @@ TEST(HttpCache, RangeGET_OK) { transaction.data = "rg: 20-29 rg: 30-39 rg: 40-49 rg: 50-59 "; RunTransactionTestWithResponse(cache.http_cache(), transaction, &headers); - EXPECT_TRUE(Verify206Response(headers, 20, 59)); + Verify206Response(headers, 20, 59); EXPECT_EQ(5, cache.network_layer()->transaction_count()); EXPECT_EQ(3, cache.disk_cache()->open_count()); EXPECT_EQ(1, cache.disk_cache()->create_count()); @@ -2495,7 +2484,7 @@ TEST(HttpCache, RangeGET_SyncOK) { std::string headers; RunTransactionTestWithResponse(cache.http_cache(), transaction, &headers); - EXPECT_TRUE(Verify206Response(headers, 40, 49)); + Verify206Response(headers, 40, 49); EXPECT_EQ(1, cache.network_layer()->transaction_count()); EXPECT_EQ(0, cache.disk_cache()->open_count()); EXPECT_EQ(1, cache.disk_cache()->create_count()); @@ -2503,7 +2492,7 @@ TEST(HttpCache, RangeGET_SyncOK) { // Read from the cache (40-49). RunTransactionTestWithResponse(cache.http_cache(), transaction, &headers); - EXPECT_TRUE(Verify206Response(headers, 40, 49)); + Verify206Response(headers, 40, 49); EXPECT_EQ(2, cache.network_layer()->transaction_count()); EXPECT_EQ(0, cache.disk_cache()->open_count()); EXPECT_EQ(1, cache.disk_cache()->create_count()); @@ -2516,7 +2505,7 @@ TEST(HttpCache, RangeGET_SyncOK) { transaction.data = "rg: 30-39 "; RunTransactionTestWithResponse(cache.http_cache(), transaction, &headers); - EXPECT_TRUE(Verify206Response(headers, 30, 39)); + Verify206Response(headers, 30, 39); EXPECT_EQ(3, cache.network_layer()->transaction_count()); EXPECT_EQ(1, cache.disk_cache()->open_count()); EXPECT_EQ(1, cache.disk_cache()->create_count()); @@ -2529,7 +2518,7 @@ TEST(HttpCache, RangeGET_SyncOK) { transaction.data = "rg: 20-29 rg: 30-39 rg: 40-49 rg: 50-59 "; RunTransactionTestWithResponse(cache.http_cache(), transaction, &headers); - EXPECT_TRUE(Verify206Response(headers, 20, 59)); + Verify206Response(headers, 20, 59); EXPECT_EQ(5, cache.network_layer()->transaction_count()); EXPECT_EQ(2, cache.disk_cache()->open_count()); EXPECT_EQ(1, cache.disk_cache()->create_count()); @@ -2548,7 +2537,7 @@ TEST(HttpCache, RangeGET_304) { RunTransactionTestWithResponse(cache.http_cache(), kRangeGET_TransactionOK, &headers); - EXPECT_TRUE(Verify206Response(headers, 40, 49)); + Verify206Response(headers, 40, 49); EXPECT_EQ(1, cache.network_layer()->transaction_count()); EXPECT_EQ(0, cache.disk_cache()->open_count()); EXPECT_EQ(1, cache.disk_cache()->create_count()); @@ -2559,7 +2548,7 @@ TEST(HttpCache, RangeGET_304) { RunTransactionTestWithResponse(cache.http_cache(), kRangeGET_TransactionOK, &headers); - EXPECT_TRUE(Verify206Response(headers, 40, 49)); + Verify206Response(headers, 40, 49); EXPECT_EQ(2, cache.network_layer()->transaction_count()); EXPECT_EQ(1, cache.disk_cache()->open_count()); EXPECT_EQ(1, cache.disk_cache()->create_count()); @@ -2578,7 +2567,7 @@ TEST(HttpCache, RangeGET_ModifiedResult) { RunTransactionTestWithResponse(cache.http_cache(), kRangeGET_TransactionOK, &headers); - EXPECT_TRUE(Verify206Response(headers, 40, 49)); + Verify206Response(headers, 40, 49); EXPECT_EQ(1, cache.network_layer()->transaction_count()); EXPECT_EQ(0, cache.disk_cache()->open_count()); EXPECT_EQ(1, cache.disk_cache()->create_count()); @@ -2589,7 +2578,7 @@ TEST(HttpCache, RangeGET_ModifiedResult) { RunTransactionTestWithResponse(cache.http_cache(), kRangeGET_TransactionOK, &headers); - EXPECT_TRUE(Verify206Response(headers, 40, 49)); + Verify206Response(headers, 40, 49); EXPECT_EQ(2, cache.network_layer()->transaction_count()); EXPECT_EQ(1, cache.disk_cache()->open_count()); EXPECT_EQ(1, cache.disk_cache()->create_count()); @@ -2617,7 +2606,7 @@ TEST(HttpCache, UnknownRangeGET_1) { transaction.data = "rg: 70-79 "; RunTransactionTestWithResponse(cache.http_cache(), transaction, &headers); - EXPECT_TRUE(Verify206Response(headers, 70, 79)); + Verify206Response(headers, 70, 79); EXPECT_EQ(1, cache.network_layer()->transaction_count()); EXPECT_EQ(0, cache.disk_cache()->open_count()); EXPECT_EQ(1, cache.disk_cache()->create_count()); @@ -2630,7 +2619,7 @@ TEST(HttpCache, UnknownRangeGET_1) { transaction.data = "rg: 60-69 rg: 70-79 "; RunTransactionTestWithResponse(cache.http_cache(), transaction, &headers); - EXPECT_TRUE(Verify206Response(headers, 60, 79)); + Verify206Response(headers, 60, 79); EXPECT_EQ(2, cache.network_layer()->transaction_count()); EXPECT_EQ(1, cache.disk_cache()->open_count()); EXPECT_EQ(1, cache.disk_cache()->create_count()); @@ -2657,7 +2646,7 @@ TEST(HttpCache, UnknownRangeGET_2) { transaction.data = "rg: 70-79 "; RunTransactionTestWithResponse(cache.http_cache(), transaction, &headers); - EXPECT_TRUE(Verify206Response(headers, 70, 79)); + Verify206Response(headers, 70, 79); EXPECT_EQ(1, cache.network_layer()->transaction_count()); EXPECT_EQ(0, cache.disk_cache()->open_count()); EXPECT_EQ(1, cache.disk_cache()->create_count()); @@ -2670,7 +2659,7 @@ TEST(HttpCache, UnknownRangeGET_2) { transaction.data = "rg: 60-69 rg: 70-79 "; RunTransactionTestWithResponse(cache.http_cache(), transaction, &headers); - EXPECT_TRUE(Verify206Response(headers, 60, 79)); + Verify206Response(headers, 60, 79); EXPECT_EQ(2, cache.network_layer()->transaction_count()); EXPECT_EQ(1, cache.disk_cache()->open_count()); EXPECT_EQ(1, cache.disk_cache()->create_count()); @@ -2719,7 +2708,7 @@ TEST(HttpCache, GET_Previous206) { RunTransactionTestWithResponse(cache.http_cache(), kRangeGET_TransactionOK, &headers); - EXPECT_TRUE(Verify206Response(headers, 40, 49)); + Verify206Response(headers, 40, 49); EXPECT_EQ(1, cache.network_layer()->transaction_count()); EXPECT_EQ(0, cache.disk_cache()->open_count()); EXPECT_EQ(1, cache.disk_cache()->create_count()); @@ -2754,7 +2743,7 @@ TEST(HttpCache, GET_Previous206_NotModified) { // Write to the cache (0-9). RunTransactionTestWithResponse(cache.http_cache(), transaction, &headers); - EXPECT_TRUE(Verify206Response(headers, 0, 9)); + Verify206Response(headers, 0, 9); EXPECT_EQ(1, cache.network_layer()->transaction_count()); EXPECT_EQ(0, cache.disk_cache()->open_count()); EXPECT_EQ(1, cache.disk_cache()->create_count()); @@ -2788,7 +2777,7 @@ TEST(HttpCache, GET_Previous206_NewContent) { transaction.data = "rg: 00-09 "; RunTransactionTestWithResponse(cache.http_cache(), transaction, &headers); - EXPECT_TRUE(Verify206Response(headers, 0, 9)); + Verify206Response(headers, 0, 9); EXPECT_EQ(1, cache.network_layer()->transaction_count()); EXPECT_EQ(0, cache.disk_cache()->open_count()); EXPECT_EQ(1, cache.disk_cache()->create_count()); @@ -2892,7 +2881,7 @@ TEST(HttpCache, RangeGET_Previous206_NotSparse_2) { &headers); // We are expecting a 206. - EXPECT_TRUE(Verify206Response(headers, 40, 49)); + Verify206Response(headers, 40, 49); EXPECT_EQ(1, cache.network_layer()->transaction_count()); EXPECT_EQ(1, cache.disk_cache()->open_count()); EXPECT_EQ(2, cache.disk_cache()->create_count()); @@ -2927,7 +2916,7 @@ TEST(HttpCache, RangeGET_Previous200) { RunTransactionTestWithResponse(cache.http_cache(), transaction2, &headers); // We are expecting a 206. - EXPECT_TRUE(Verify206Response(headers, 40, 49)); + Verify206Response(headers, 40, 49); EXPECT_EQ(2, cache.network_layer()->transaction_count()); EXPECT_EQ(1, cache.disk_cache()->open_count()); EXPECT_EQ(1, cache.disk_cache()->create_count()); @@ -2939,7 +2928,7 @@ TEST(HttpCache, RangeGET_Previous200) { handler.set_not_modified(false); transaction2.request_headers = kRangeGET_TransactionOK.request_headers; RunTransactionTestWithResponse(cache.http_cache(), transaction2, &headers); - EXPECT_TRUE(Verify206Response(headers, 40, 49)); + Verify206Response(headers, 40, 49); EXPECT_EQ(3, cache.network_layer()->transaction_count()); EXPECT_EQ(2, cache.disk_cache()->open_count()); EXPECT_EQ(1, cache.disk_cache()->create_count()); @@ -2963,7 +2952,7 @@ TEST(HttpCache, RangeRequestResultsIn200) { transaction.data = "rg: 70-79 "; RunTransactionTestWithResponse(cache.http_cache(), transaction, &headers); - EXPECT_TRUE(Verify206Response(headers, 70, 79)); + Verify206Response(headers, 70, 79); EXPECT_EQ(1, cache.network_layer()->transaction_count()); EXPECT_EQ(0, cache.disk_cache()->open_count()); EXPECT_EQ(1, cache.disk_cache()->create_count()); @@ -3002,7 +2991,7 @@ TEST(HttpCache, RangeGET_MoreThanCurrentSize) { RunTransactionTestWithResponse(cache.http_cache(), kRangeGET_TransactionOK, &headers); - EXPECT_TRUE(Verify206Response(headers, 40, 49)); + Verify206Response(headers, 40, 49); EXPECT_EQ(1, cache.network_layer()->transaction_count()); EXPECT_EQ(0, cache.disk_cache()->open_count()); EXPECT_EQ(1, cache.disk_cache()->create_count()); @@ -3243,7 +3232,7 @@ TEST(HttpCache, RangeGET_InvalidResponse3) { AddMockTransaction(&transaction); RunTransactionTestWithResponse(cache.http_cache(), transaction, &headers); - EXPECT_TRUE(Verify206Response(headers, 50, 59)); + Verify206Response(headers, 50, 59); EXPECT_EQ(1, cache.network_layer()->transaction_count()); EXPECT_EQ(0, cache.disk_cache()->open_count()); EXPECT_EQ(1, cache.disk_cache()->create_count()); @@ -3256,7 +3245,7 @@ TEST(HttpCache, RangeGET_InvalidResponse3) { RunTransactionTestWithResponse(cache.http_cache(), kRangeGET_TransactionOK, &headers); - EXPECT_TRUE(Verify206Response(headers, 40, 49)); + Verify206Response(headers, 40, 49); EXPECT_EQ(2, cache.network_layer()->transaction_count()); EXPECT_EQ(1, cache.disk_cache()->open_count()); EXPECT_EQ(1, cache.disk_cache()->create_count()); @@ -3334,7 +3323,7 @@ TEST(HttpCache, RangeHEAD) { std::string headers; RunTransactionTestWithResponse(cache.http_cache(), transaction, &headers); - EXPECT_TRUE(Verify206Response(headers, 70, 79)); + Verify206Response(headers, 70, 79); EXPECT_EQ(1, cache.network_layer()->transaction_count()); EXPECT_EQ(0, cache.disk_cache()->open_count()); EXPECT_EQ(0, cache.disk_cache()->create_count()); @@ -3876,7 +3865,7 @@ TEST(HttpCache, RangeGET_IncompleteResource) { RunTransactionTestWithResponse(cache.http_cache(), kRangeGET_TransactionOK, &headers); - EXPECT_TRUE(Verify206Response(headers, 40, 49)); + Verify206Response(headers, 40, 49); EXPECT_EQ(1, cache.network_layer()->transaction_count()); EXPECT_EQ(1, cache.disk_cache()->open_count()); EXPECT_EQ(2, cache.disk_cache()->create_count()); diff --git a/net/http/http_network_layer_unittest.cc b/net/http/http_network_layer_unittest.cc index e8aa494..697fe98 100644 --- a/net/http/http_network_layer_unittest.cc +++ b/net/http/http_network_layer_unittest.cc @@ -82,7 +82,8 @@ TEST_F(HttpNetworkLayerTest, GET) { net::HttpRequestInfo request_info; request_info.url = GURL("http://www.google.com/"); request_info.method = "GET"; - request_info.user_agent = "Foo/1.0"; + request_info.extra_headers.SetHeader(net::HttpRequestHeaders::kUserAgent, + "Foo/1.0"); request_info.load_flags = net::LOAD_NORMAL; rv = trans->Start(&request_info, &callback, net::BoundNetLog()); diff --git a/net/http/http_network_transaction.cc b/net/http/http_network_transaction.cc index 64c4fd9..39111f4 100644 --- a/net/http/http_network_transaction.cc +++ b/net/http/http_network_transaction.cc @@ -57,13 +57,13 @@ void BuildRequestHeaders(const HttpRequestInfo* request_info, const HttpRequestHeaders& authorization_headers, const UploadDataStream* upload_data_stream, bool using_proxy, + std::string* request_line, HttpRequestHeaders* request_headers) { const std::string path = using_proxy ? HttpUtil::SpecForRequest(request_info->url) : HttpUtil::PathForRequest(request_info->url); - request_headers->SetRequestLine( - request_info->method, path, "1.1"); - + *request_line = StringPrintf( + "%s %s HTTP/1.1\r\n", request_info->method.c_str(), path.c_str()); request_headers->SetHeader(HttpRequestHeaders::kHost, GetHostAndOptionalPort(request_info->url)); @@ -75,11 +75,6 @@ void BuildRequestHeaders(const HttpRequestInfo* request_info, request_headers->SetHeader(HttpRequestHeaders::kConnection, "keep-alive"); } - if (!request_info->user_agent.empty()) { - request_headers->SetHeader(HttpRequestHeaders::kUserAgent, - request_info->user_agent); - } - // Our consumer should have made sure that this is a safe referrer. See for // instance WebCore::FrameLoader::HideReferrer. if (request_info->referrer.is_valid()) { @@ -120,22 +115,11 @@ void BuildRequestHeaders(const HttpRequestInfo* request_info, "Referer" }; - // TODO(willchan): Change HttpRequestInfo::extra_headers to be a - // HttpRequestHeaders. - - std::vector<std::string> extra_headers_vector; - Tokenize(request_info->extra_headers, "\r\n", &extra_headers_vector); - HttpRequestHeaders extra_headers; - if (!extra_headers_vector.empty()) { - for (std::vector<std::string>::const_iterator it = - extra_headers_vector.begin(); it != extra_headers_vector.end(); ++it) - extra_headers.AddHeaderFromString(*it); - + HttpRequestHeaders stripped_extra_headers; + stripped_extra_headers.CopyFrom(request_info->extra_headers); for (size_t i = 0; i < arraysize(kExtraHeadersToBeStripped); ++i) - extra_headers.RemoveHeader(kExtraHeadersToBeStripped[i]); - - request_headers->MergeFrom(extra_headers); - } + stripped_extra_headers.RemoveHeader(kExtraHeadersToBeStripped[i]); + request_headers->MergeFrom(stripped_extra_headers); } // The HTTP CONNECT method for establishing a tunnel connection is documented @@ -143,21 +127,22 @@ void BuildRequestHeaders(const HttpRequestInfo* request_info, // 5.3. void BuildTunnelRequest(const HttpRequestInfo* request_info, const HttpRequestHeaders& authorization_headers, + std::string* request_line, HttpRequestHeaders* request_headers) { // RFC 2616 Section 9 says the Host request-header field MUST accompany all // HTTP/1.1 requests. Add "Proxy-Connection: keep-alive" for compat with // HTTP/1.0 proxies such as Squid (required for NTLM authentication). - request_headers->SetRequestLine( - "CONNECT", GetHostAndPort(request_info->url), "1.1"); + *request_line = StringPrintf( + "CONNECT %s HTTP/1.1\r\n", GetHostAndPort(request_info->url).c_str()); request_headers->SetHeader(HttpRequestHeaders::kHost, GetHostAndOptionalPort(request_info->url)); request_headers->SetHeader(HttpRequestHeaders::kProxyConnection, "keep-alive"); - if (!request_info->user_agent.empty()) { - request_headers->SetHeader(HttpRequestHeaders::kUserAgent, - request_info->user_agent); - } + std::string user_agent; + if (request_info->extra_headers.GetHeader(HttpRequestHeaders::kUserAgent, + &user_agent)) + request_headers->SetHeader(HttpRequestHeaders::kUserAgent, user_agent); request_headers->MergeFrom(authorization_headers); } @@ -962,6 +947,7 @@ int HttpNetworkTransaction::DoSendRequest() { (HaveAuth(HttpAuth::AUTH_SERVER) || SelectPreemptiveAuth(HttpAuth::AUTH_SERVER)); + std::string request_line; HttpRequestHeaders request_headers; HttpRequestHeaders authorization_headers; @@ -974,13 +960,15 @@ int HttpNetworkTransaction::DoSendRequest() { AddAuthorizationHeader(HttpAuth::AUTH_SERVER, &authorization_headers); if (establishing_tunnel_) { - BuildTunnelRequest(request_, authorization_headers, &request_headers); + BuildTunnelRequest(request_, authorization_headers, &request_line, + &request_headers); } else { BuildRequestHeaders(request_, authorization_headers, request_body, - proxy_mode_ == kHTTPProxy, &request_headers); + proxy_mode_ == kHTTPProxy, &request_line, + &request_headers); } - request_headers_ = request_headers.ToString(); + request_headers_ = request_line + request_headers.ToString(); } headers_valid_ = false; diff --git a/net/http/http_network_transaction_unittest.cc b/net/http/http_network_transaction_unittest.cc index 28dfa8d..8c0d8bd 100644 --- a/net/http/http_network_transaction_unittest.cc +++ b/net/http/http_network_transaction_unittest.cc @@ -2924,7 +2924,8 @@ TEST_F(HttpNetworkTransactionTest, ResetStateForRestart) { std::string temp("HTTP/1.1 200 OK\nVary: foo, bar\n\n"); std::replace(temp.begin(), temp.end(), '\n', '\0'); scoped_refptr<HttpResponseHeaders> headers = new HttpResponseHeaders(temp); - request.extra_headers = "Foo: 1\nbar: 23"; + request.extra_headers.SetHeader("Foo", "1"); + request.extra_headers.SetHeader("bar", "23"); EXPECT_TRUE(response->vary_data.Init(request, *headers)); } @@ -3083,7 +3084,8 @@ TEST_F(HttpNetworkTransactionTest, BuildRequest_UserAgent) { HttpRequestInfo request; request.method = "GET"; request.url = GURL("http://www.google.com/"); - request.user_agent = "Chromium Ultra Awesome X Edition"; + request.extra_headers.SetHeader(HttpRequestHeaders::kUserAgent, + "Chromium Ultra Awesome X Edition"); MockWrite data_writes[] = { MockWrite("GET / HTTP/1.1\r\n" @@ -3349,7 +3351,7 @@ TEST_F(HttpNetworkTransactionTest, BuildRequest_ExtraHeaders) { HttpRequestInfo request; request.method = "GET"; request.url = GURL("http://www.google.com/"); - request.extra_headers = "FooHeader: Bar\r\n"; + request.extra_headers.SetHeader("FooHeader", "Bar"); MockWrite data_writes[] = { MockWrite("GET / HTTP/1.1\r\n" @@ -3387,7 +3389,9 @@ TEST_F(HttpNetworkTransactionTest, BuildRequest_ExtraHeadersStripped) { HttpRequestInfo request; request.method = "GET"; request.url = GURL("http://www.google.com/"); - request.extra_headers = "referer: www.foo.com\nhEllo: Kitty\rFoO: bar\r\n"; + request.extra_headers.SetHeader("referer", "www.foo.com"); + request.extra_headers.SetHeader("hEllo", "Kitty"); + request.extra_headers.SetHeader("FoO", "bar"); MockWrite data_writes[] = { MockWrite("GET / HTTP/1.1\r\n" diff --git a/net/http/http_request_headers.cc b/net/http/http_request_headers.cc index d894584..43e6205 100644 --- a/net/http/http_request_headers.cc +++ b/net/http/http_request_headers.cc @@ -11,29 +11,57 @@ namespace net { const char HttpRequestHeaders::kGetMethod[] = "GET"; - +const char HttpRequestHeaders::kAcceptCharset[] = "Accept-Charset"; +const char HttpRequestHeaders::kAcceptEncoding[] = "Accept-Encoding"; +const char HttpRequestHeaders::kAcceptLanguage[] = "Accept-Language"; const char HttpRequestHeaders::kCacheControl[] = "Cache-Control"; const char HttpRequestHeaders::kConnection[] = "Connection"; +const char HttpRequestHeaders::kCookie[] = "Cookie"; const char HttpRequestHeaders::kContentLength[] = "Content-Length"; const char HttpRequestHeaders::kHost[] = "Host"; +const char HttpRequestHeaders::kIfModifiedSince[] = "If-Modified-Since"; +const char HttpRequestHeaders::kIfNoneMatch[] = "If-None-Match"; +const char HttpRequestHeaders::kIfRange[] = "If-Range"; const char HttpRequestHeaders::kPragma[] = "Pragma"; const char HttpRequestHeaders::kProxyConnection[] = "Proxy-Connection"; +const char HttpRequestHeaders::kRange[] = "Range"; const char HttpRequestHeaders::kReferer[] = "Referer"; const char HttpRequestHeaders::kUserAgent[] = "User-Agent"; +HttpRequestHeaders::Iterator::Iterator(const HttpRequestHeaders& headers) + : started_(false), + curr_(headers.headers_.begin()), + end_(headers.headers_.end()) {} + +HttpRequestHeaders::Iterator::~Iterator() {} + +bool HttpRequestHeaders::Iterator::GetNext() { + if (!started_) { + started_ = true; + return curr_ != end_; + } + + if (curr_ == end_) + return false; + + ++curr_; + return curr_ != end_; +} + HttpRequestHeaders::HttpRequestHeaders() {} HttpRequestHeaders::~HttpRequestHeaders() {} -void HttpRequestHeaders::SetRequestLine(const base::StringPiece& method, - const base::StringPiece& path, - const base::StringPiece& version) { - DCHECK(!method.empty()); - DCHECK(!path.empty()); - DCHECK(!version.empty()); +bool HttpRequestHeaders::GetHeader(const base::StringPiece& key, + std::string* out) const { + HeaderVector::const_iterator it = FindHeader(key); + if (it == headers_.end()) + return false; + out->assign(it->value); + return true; +} - method_.assign(method.data(), method.length()); - path_.assign(path.data(), path.length()); - version_.assign(version.data(), version.length()); +void HttpRequestHeaders::Clear() { + headers_.clear(); } void HttpRequestHeaders::SetHeader(const base::StringPiece& key, @@ -95,11 +123,20 @@ void HttpRequestHeaders::AddHeaderFromString( } } -void HttpRequestHeaders::MergeFrom(const HttpRequestHeaders& other) { - DCHECK(other.method_.empty()); - DCHECK(other.path_.empty()); - DCHECK(other.version_.empty()); +void HttpRequestHeaders::AddHeadersFromString( + const base::StringPiece& headers) { + // TODO(willchan): Consider adding more StringPiece support in string_util.h + // to eliminate copies. + std::vector<std::string> header_line_vector; + SplitStringUsingSubstr(headers.as_string(), "\r\n", &header_line_vector); + for (std::vector<std::string>::const_iterator it = header_line_vector.begin(); + it != header_line_vector.end(); ++it) { + if (!it->empty()) + AddHeaderFromString(*it); + } +} +void HttpRequestHeaders::MergeFrom(const HttpRequestHeaders& other) { for (HeaderVector::const_iterator it = other.headers_.begin(); it != other.headers_.end(); ++it ) { SetHeader(it->key, it->value); @@ -108,12 +145,6 @@ void HttpRequestHeaders::MergeFrom(const HttpRequestHeaders& other) { std::string HttpRequestHeaders::ToString() const { std::string output; - if (!method_.empty()) { - DCHECK(!path_.empty()); - DCHECK(!version_.empty()); - output = StringPrintf( - "%s %s HTTP/%s\r\n", method_.c_str(), path_.c_str(), version_.c_str()); - } for (HeaderVector::const_iterator it = headers_.begin(); it != headers_.end(); ++it) { if (!it->value.empty()) @@ -137,4 +168,16 @@ HttpRequestHeaders::FindHeader(const base::StringPiece& key) { return headers_.end(); } +HttpRequestHeaders::HeaderVector::const_iterator +HttpRequestHeaders::FindHeader(const base::StringPiece& key) const { + for (HeaderVector::const_iterator it = headers_.begin(); + it != headers_.end(); ++it) { + if (key.length() == it->key.length() && + !base::strncasecmp(key.data(), it->key.data(), key.length())) + return it; + } + + return headers_.end(); +} + } // namespace net diff --git a/net/http/http_request_headers.h b/net/http/http_request_headers.h index 79522aa..c107a3c 100644 --- a/net/http/http_request_headers.h +++ b/net/http/http_request_headers.h @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // -// HttpRequestHeaders manages the request headers (including the request line). +// HttpRequestHeaders manages the request headers. // It maintains these in a vector of header key/value pairs, thereby maintaining // the order of the headers. This means that any lookups are linear time // operations. @@ -19,23 +19,74 @@ namespace net { class HttpRequestHeaders { public: + struct HeaderKeyValuePair { + HeaderKeyValuePair() {} + HeaderKeyValuePair(const base::StringPiece& key, + const base::StringPiece& value) + : key(key.data(), key.size()), value(value.data(), value.size()) {} + + std::string key; + std::string value; + }; + + typedef std::vector<HeaderKeyValuePair> HeaderVector; + + class Iterator { + public: + explicit Iterator(const HttpRequestHeaders& headers); + ~Iterator(); + + // Advances the iterator to the next header, if any. Returns true if there + // is a next header. Use name() and value() methods to access the resultant + // header name and value. + bool GetNext(); + + // These two accessors are only valid if GetNext() returned true. + const std::string& name() const { return curr_->key; } + const std::string& value() const { return curr_->value; } + + private: + bool started_; + HttpRequestHeaders::HeaderVector::const_iterator curr_; + const HttpRequestHeaders::HeaderVector::const_iterator end_; + + DISALLOW_COPY_AND_ASSIGN(Iterator); + }; + static const char kGetMethod[]; + static const char kAcceptCharset[]; + static const char kAcceptEncoding[]; + static const char kAcceptLanguage[]; static const char kCacheControl[]; static const char kConnection[]; + static const char kCookie[]; static const char kContentLength[]; static const char kHost[]; + static const char kIfModifiedSince[]; + static const char kIfNoneMatch[]; + static const char kIfRange[]; static const char kPragma[]; static const char kProxyConnection[]; + static const char kRange[]; static const char kReferer[]; static const char kUserAgent[]; HttpRequestHeaders(); ~HttpRequestHeaders(); - void SetRequestLine(const base::StringPiece& method, - const base::StringPiece& path, - const base::StringPiece& version); + bool IsEmpty() const { return headers_.empty(); } + + bool HasHeader(const base::StringPiece& key) const { + return FindHeader(key) != headers_.end(); + } + + // Gets the first header that matches |key|. If found, returns true and + // writes the value to |out|. + bool GetHeader(const base::StringPiece& key, std::string* out) const; + + // Clears all the headers. + void Clear(); // Sets the header value pair for |key| and |value|. If |key| already exists, // then the header value is modified, but the key is untouched, and the order @@ -59,37 +110,35 @@ class HttpRequestHeaders { // field-content. void AddHeaderFromString(const base::StringPiece& header_line); + // Same thing as AddHeaderFromString() except that |headers| is a "\r\n" + // delimited string of header lines. It will split up the string by "\r\n" + // and call AddHeaderFromString() on each. + void AddHeadersFromString(const base::StringPiece& headers); + // Calls SetHeader() on each header from |other|, maintaining order. void MergeFrom(const HttpRequestHeaders& other); + // Copies from |other| to |this|. + void CopyFrom(const HttpRequestHeaders& other) { + *this = other; + } + // Serializes HttpRequestHeaders to a string representation. Joins all the // header keys and values with ": ", and inserts "\r\n" between each header // line, and adds the trailing "\r\n". std::string ToString() const; private: - struct HeaderKeyValuePair { - HeaderKeyValuePair() {} - HeaderKeyValuePair(const base::StringPiece& key, - const base::StringPiece& value) - : key(key.data(), key.size()), value(value.data(), value.size()) {} - - std::string key; - std::string value; - }; - - typedef std::vector<HeaderKeyValuePair> HeaderVector; - HeaderVector::iterator FindHeader(const base::StringPiece& key); HeaderVector::const_iterator FindHeader(const base::StringPiece& key) const; - std::string method_; - std::string path_; - std::string version_; - HeaderVector headers_; - DISALLOW_COPY_AND_ASSIGN(HttpRequestHeaders); + // Allow the copy construction and operator= to facilitate copying in + // HttpRequestInfo. + // TODO(willchan): Investigate to see if we can remove the need to copy + // HttpRequestInfo. + // DISALLOW_COPY_AND_ASSIGN(HttpRequestHeaders); }; } // namespace net diff --git a/net/http/http_request_headers_unittest.cc b/net/http/http_request_headers_unittest.cc index 29431d9..f3abfbe2 100644 --- a/net/http/http_request_headers_unittest.cc +++ b/net/http/http_request_headers_unittest.cc @@ -10,11 +10,17 @@ namespace net { namespace { -TEST(HttpRequestHeaders, SetRequestLine) { +TEST(HttpRequestHeaders, HasHeader) { HttpRequestHeaders headers; - headers.SetRequestLine( - HttpRequestHeaders::kGetMethod, "/foo", "1.1"); - EXPECT_EQ("GET /foo HTTP/1.1\r\n\r\n", headers.ToString()); + headers.SetHeader("Foo", "bar"); + EXPECT_TRUE(headers.HasHeader("foo")); + EXPECT_TRUE(headers.HasHeader("Foo")); + EXPECT_FALSE(headers.HasHeader("Fo")); + + const HttpRequestHeaders& headers_ref = headers; + EXPECT_TRUE(headers_ref.HasHeader("foo")); + EXPECT_TRUE(headers_ref.HasHeader("Foo")); + EXPECT_FALSE(headers_ref.HasHeader("Fo")); } TEST(HttpRequestHeaders, SetHeader) { @@ -50,6 +56,8 @@ TEST(HttpRequestHeaders, SetHeaderTwiceSamePrefix) { headers.SetHeader("FooBar", "smokes"); headers.SetHeader("Foo", "crack"); EXPECT_EQ("FooBar: smokes\r\nFoo: crack\r\n\r\n", headers.ToString()); + const HttpRequestHeaders& headers_ref = headers; + EXPECT_EQ("FooBar: smokes\r\nFoo: crack\r\n\r\n", headers_ref.ToString()); } TEST(HttpRequestHeaders, SetEmptyHeader) { @@ -135,6 +143,18 @@ TEST(HttpRequestHeaders, MergeFrom) { EXPECT_EQ("A: A\r\nB: b\r\nC: c\r\n\r\n", headers.ToString()); } +TEST(HttpRequestHeaders, CopyFrom) { + HttpRequestHeaders headers; + headers.SetHeader("A", "A"); + headers.SetHeader("B", "B"); + + HttpRequestHeaders headers2; + headers2.SetHeader("B", "b"); + headers2.SetHeader("C", "c"); + headers.CopyFrom(headers2); + EXPECT_EQ("B: b\r\nC: c\r\n\r\n", headers.ToString()); +} + } // namespace } // namespace net diff --git a/net/http/http_request_info.h b/net/http/http_request_info.h index 7ada539..c36e21a 100644 --- a/net/http/http_request_info.h +++ b/net/http/http_request_info.h @@ -10,10 +10,11 @@ #include "googleurl/src/gurl.h" #include "net/base/request_priority.h" #include "net/base/upload_data.h" +#include "net/http/http_request_headers.h" namespace net { -class HttpRequestInfo { +struct HttpRequestInfo { public: HttpRequestInfo() : load_flags(0), priority(LOWEST) { } @@ -27,12 +28,8 @@ class HttpRequestInfo { // The method to use (GET, POST, etc.). std::string method; - // The user agent string to use. TODO(darin): we should just add this to - // extra_headers - std::string user_agent; - - // Any extra request headers (\r\n-delimited). - std::string extra_headers; + // Any extra request headers (including User-Agent). + HttpRequestHeaders extra_headers; // Any upload data. scoped_refptr<UploadData> upload_data; diff --git a/net/http/http_stream.h b/net/http/http_stream.h index 87bd8e2..de2a8d78 100644 --- a/net/http/http_stream.h +++ b/net/http/http_stream.h @@ -17,7 +17,7 @@ namespace net { -class HttpRequestInfo; +struct HttpRequestInfo; class HttpResponseInfo; class IOBuffer; class UploadDataStream; diff --git a/net/http/http_stream_parser.h b/net/http/http_stream_parser.h index e42b9b5..724127f 100644 --- a/net/http/http_stream_parser.h +++ b/net/http/http_stream_parser.h @@ -18,7 +18,7 @@ namespace net { class ClientSocketHandle; -class HttpRequestInfo; +struct HttpRequestInfo; class HttpStreamParser { public: diff --git a/net/http/http_transaction.h b/net/http/http_transaction.h index a18d422..103f8f6 100644 --- a/net/http/http_transaction.h +++ b/net/http/http_transaction.h @@ -13,7 +13,7 @@ namespace net { class BoundNetLog; -class HttpRequestInfo; +struct HttpRequestInfo; class HttpResponseInfo; class IOBuffer; class X509Certificate; diff --git a/net/http/http_transaction_unittest.h b/net/http/http_transaction_unittest.h index e578db2..8a99812 100644 --- a/net/http/http_transaction_unittest.h +++ b/net/http/http_transaction_unittest.h @@ -97,7 +97,7 @@ class MockHttpRequest : public net::HttpRequestInfo { explicit MockHttpRequest(const MockTransaction& t) { url = GURL(t.url); method = t.method; - extra_headers = t.request_headers; + extra_headers.AddHeadersFromString(t.request_headers); load_flags = t.load_flags; } }; diff --git a/net/http/http_util.cc b/net/http/http_util.cc index 5ea46d0..2ca8f02 100644 --- a/net/http/http_util.cc +++ b/net/http/http_util.cc @@ -202,6 +202,12 @@ bool HttpUtil::ParseRanges(const std::string& headers, if (ranges_specifier.empty()) return false; + return ParseRangeHeader(ranges_specifier, ranges); +} + +// static +bool HttpUtil::ParseRangeHeader(const std::string& ranges_specifier, + std::vector<HttpByteRange>* ranges) { size_t equal_char_offset = ranges_specifier.find('='); if (equal_char_offset == std::string::npos) return false; diff --git a/net/http/http_util.h b/net/http/http_util.h index c630cfe..4d4b200 100644 --- a/net/http/http_util.h +++ b/net/http/http_util.h @@ -54,6 +54,11 @@ class HttpUtil { static bool ParseRanges(const std::string& headers, std::vector<HttpByteRange>* ranges); + // Same thing as ParseRanges except the Range header is known and its value + // is directly passed in, rather than requiring searching through a string. + static bool ParseRangeHeader(const std::string& range_specifier, + std::vector<HttpByteRange>* ranges); + // Scans the '\r\n'-delimited headers for the given header name. Returns // true if a match is found. Input is assumed to be well-formed. // TODO(darin): kill this diff --git a/net/http/http_vary_data.cc b/net/http/http_vary_data.cc index fa7a325..f5c7514 100644 --- a/net/http/http_vary_data.cc +++ b/net/http/http_vary_data.cc @@ -8,6 +8,7 @@ #include "base/pickle.h" #include "base/string_util.h" +#include "net/http/http_request_headers.h" #include "net/http/http_request_info.h" #include "net/http/http_response_headers.h" #include "net/http/http_util.h" @@ -97,33 +98,18 @@ std::string HttpVaryData::GetRequestValue( const HttpRequestInfo& request_info, const std::string& request_header) { // Some special cases: - if (LowerCaseEqualsASCII(request_header, "referer")) + if (!base::strcasecmp(request_header.c_str(), HttpRequestHeaders::kReferer)) return request_info.referrer.spec(); - if (LowerCaseEqualsASCII(request_header, "user-agent")) - return request_info.user_agent; - - std::string result; - - // Check extra headers: - HttpUtil::HeadersIterator it(request_info.extra_headers.begin(), - request_info.extra_headers.end(), - "\r\n"); - while (it.GetNext()) { - size_t name_len = it.name_end() - it.name_begin(); - if (request_header.size() == name_len && - std::equal(it.name_begin(), it.name_end(), request_header.begin(), - CaseInsensitiveCompare<char>())) { - if (!result.empty()) - result.append(1, ','); - result.append(it.values()); - } - } // Unfortunately, we do not have access to all of the request headers at this // point. Most notably, we do not have access to an Authorization header if // one will be added to the request. - return result; + std::string result; + if (request_info.extra_headers.GetHeader(request_header, &result)) + return result; + + return ""; } // static diff --git a/net/http/http_vary_data.h b/net/http/http_vary_data.h index 360799d..98b94fa 100644 --- a/net/http/http_vary_data.h +++ b/net/http/http_vary_data.h @@ -11,7 +11,7 @@ class Pickle; namespace net { -class HttpRequestInfo; +struct HttpRequestInfo; class HttpResponseHeaders; // Used to implement the HTTP/1.1 Vary header. This class contains a MD5 hash diff --git a/net/http/http_vary_data_unittest.cc b/net/http/http_vary_data_unittest.cc index 7b2bd16..38e4e32 100644 --- a/net/http/http_vary_data_unittest.cc +++ b/net/http/http_vary_data_unittest.cc @@ -23,7 +23,8 @@ struct TestTransaction { std::replace(temp.begin(), temp.end(), '\n', '\0'); response = new net::HttpResponseHeaders(temp); - request.extra_headers = request_headers; + request.extra_headers.Clear(); + request.extra_headers.AddHeadersFromString(request_headers); } }; @@ -54,13 +55,13 @@ TEST(HttpVaryDataTest, MultipleInit) { // Init to something valid. TestTransaction t1; - t1.Init("Foo: 1\nbar: 23", "HTTP/1.1 200 OK\nVary: foo, bar\n\n"); + t1.Init("Foo: 1\r\nbar: 23", "HTTP/1.1 200 OK\nVary: foo, bar\n\n"); EXPECT_TRUE(v.Init(t1.request, *t1.response)); EXPECT_TRUE(v.is_valid()); // Now overwrite by initializing to something invalid. TestTransaction t2; - t2.Init("Foo: 1\nbar: 23", "HTTP/1.1 200 OK\nVary: *\n\n"); + t2.Init("Foo: 1\r\nbar: 23", "HTTP/1.1 200 OK\nVary: *\n\n"); EXPECT_FALSE(v.Init(t2.request, *t2.response)); EXPECT_FALSE(v.is_valid()); } @@ -80,10 +81,10 @@ TEST(HttpVaryDataTest, DoesVary) { TEST(HttpVaryDataTest, DoesVary2) { TestTransaction a; - a.Init("Foo: 1\nbar: 23", "HTTP/1.1 200 OK\nVary: foo, bar\n\n"); + a.Init("Foo: 1\r\nbar: 23", "HTTP/1.1 200 OK\nVary: foo, bar\n\n"); TestTransaction b; - b.Init("Foo: 12\nbar: 3", "HTTP/1.1 200 OK\nVary: foo, bar\n\n"); + b.Init("Foo: 12\r\nbar: 3", "HTTP/1.1 200 OK\nVary: foo, bar\n\n"); net::HttpVaryData v; EXPECT_TRUE(v.Init(a.request, *a.response)); @@ -106,10 +107,10 @@ TEST(HttpVaryDataTest, DoesntVary) { TEST(HttpVaryDataTest, DoesntVary2) { TestTransaction a; - a.Init("Foo: 1\nbAr: 2", "HTTP/1.1 200 OK\nVary: foo, bar\n\n"); + a.Init("Foo: 1\r\nbAr: 2", "HTTP/1.1 200 OK\nVary: foo, bar\n\n"); TestTransaction b; - b.Init("Foo: 1\nbaR: 2", "HTTP/1.1 200 OK\nVary: foo\nVary: bar\n\n"); + b.Init("Foo: 1\r\nbaR: 2", "HTTP/1.1 200 OK\nVary: foo\nVary: bar\n\n"); net::HttpVaryData v; EXPECT_TRUE(v.Init(a.request, *a.response)); diff --git a/net/http/partial_data.cc b/net/http/partial_data.cc index f727699..83bdb3b 100644 --- a/net/http/partial_data.cc +++ b/net/http/partial_data.cc @@ -12,6 +12,8 @@ #include "net/http/http_response_headers.h" #include "net/http/http_util.h" +namespace net { + namespace { // The headers that we have to process. @@ -19,13 +21,28 @@ const char kLengthHeader[] = "Content-Length"; const char kRangeHeader[] = "Content-Range"; const int kDataStream = 1; +void AddRangeHeader(int64 start, int64 end, HttpRequestHeaders* headers) { + DCHECK(start >= 0 || end >= 0); + std::string my_start, my_end; + if (start >= 0) + my_start = Int64ToString(start); + if (end >= 0) + my_end = Int64ToString(end); + + headers->SetHeader( + HttpRequestHeaders::kRange, + StringPrintf("bytes=%s-%s", my_start.c_str(), my_end.c_str())); } -namespace net { +} // namespace + +bool PartialData::Init(const HttpRequestHeaders& headers) { + std::string range_header; + if (!headers.GetHeader(HttpRequestHeaders::kRange, &range_header)) + return false; -bool PartialData::Init(const std::string& headers) { std::vector<HttpByteRange> ranges; - if (!HttpUtil::ParseRanges(headers, &ranges) || ranges.size() != 1) + if (!HttpUtil::ParseRangeHeader(range_header, &ranges) || ranges.size() != 1) return false; // We can handle this range request. @@ -38,23 +55,23 @@ bool PartialData::Init(const std::string& headers) { return true; } -void PartialData::SetHeaders(const std::string& headers) { - DCHECK(extra_headers_.empty()); - extra_headers_ = headers; +void PartialData::SetHeaders(const HttpRequestHeaders& headers) { + DCHECK(extra_headers_.IsEmpty()); + extra_headers_.CopyFrom(headers); } -void PartialData::RestoreHeaders(std::string* headers) const { +void PartialData::RestoreHeaders(HttpRequestHeaders* headers) const { DCHECK(current_range_start_ >= 0 || byte_range_.IsSuffixByteRange()); int64 end = byte_range_.IsSuffixByteRange() ? byte_range_.suffix_length() : byte_range_.last_byte_position(); - headers->assign(extra_headers_); + headers->CopyFrom(extra_headers_); if (byte_range_.IsValid()) AddRangeHeader(current_range_start_, end, headers); } int PartialData::PrepareCacheValidation(disk_cache::Entry* entry, - std::string* headers) { + HttpRequestHeaders* headers) { DCHECK(current_range_start_ >= 0); // Scan the disk cache for the first cached portion within this range. @@ -86,7 +103,7 @@ int PartialData::PrepareCacheValidation(disk_cache::Entry* entry, return cached_min_len_; } - headers->assign(extra_headers_); + headers->CopyFrom(extra_headers_); if (!cached_min_len_) { // We don't have anything else stored. @@ -322,17 +339,4 @@ void PartialData::OnNetworkReadCompleted(int result) { current_range_start_ += result; } -// Static. -void PartialData::AddRangeHeader(int64 start, int64 end, std::string* headers) { - DCHECK(start >= 0 || end >= 0); - std::string my_start, my_end; - if (start >= 0) - my_start = Int64ToString(start); - if (end >= 0) - my_end = Int64ToString(end); - - headers->append(StringPrintf("Range: bytes=%s-%s\r\n", my_start.c_str(), - my_end.c_str())); -} - } // namespace net diff --git a/net/http/partial_data.h b/net/http/partial_data.h index 3a30e0a..51e6d7d 100644 --- a/net/http/partial_data.h +++ b/net/http/partial_data.h @@ -10,6 +10,7 @@ #include "base/basictypes.h" #include "net/base/completion_callback.h" #include "net/http/http_byte_range.h" +#include "net/http/http_request_headers.h" namespace disk_cache { class Entry; @@ -36,19 +37,19 @@ class PartialData { truncated_(false) {} ~PartialData() {} - // Performs initialization of the object by parsing the request |headers| + // Performs initialization of the object by examining the request |headers| // and verifying that we can process the requested range. Returns true if // we can process the requested range, and false otherwise. - bool Init(const std::string& headers); + bool Init(const HttpRequestHeaders& headers); // Sets the headers that we should use to make byte range requests. This is a // subset of the request extra headers, with byte-range related headers // removed. - void SetHeaders(const std::string& headers); + void SetHeaders(const HttpRequestHeaders& headers); // Restores the byte-range headers, by appending the byte range to the headers // provided to SetHeaders(). - void RestoreHeaders(std::string* headers) const; + void RestoreHeaders(HttpRequestHeaders* headers) const; // Builds the required |headers| to perform the proper cache validation for // the next range to be fetched. Returns 0 when there is no need to perform @@ -56,7 +57,8 @@ class PartialData { // should be actually returned to the user), a positive number to indicate // that |headers| should be used to validate the cache, or an appropriate // error code. - int PrepareCacheValidation(disk_cache::Entry* entry, std::string* headers); + int PrepareCacheValidation(disk_cache::Entry* entry, + HttpRequestHeaders* headers); // Returns true if the current range is stored in the cache. bool IsCurrentRangeCached() const; @@ -105,14 +107,13 @@ class PartialData { void OnNetworkReadCompleted(int result); private: - static void AddRangeHeader(int64 start, int64 end, std::string* headers); - int64 current_range_start_; int64 cached_start_; int64 resource_size_; int cached_min_len_; HttpByteRange byte_range_; // The range requested by the user. - std::string extra_headers_; // The clean set of extra headers (no ranges). + // The clean set of extra headers (no ranges). + HttpRequestHeaders extra_headers_; bool range_present_; // True if next range entry is already stored. bool final_range_; bool sparse_entry_; diff --git a/net/spdy/spdy_network_transaction_unittest.cc b/net/spdy/spdy_network_transaction_unittest.cc index cc08a9e..12625b2 100644 --- a/net/spdy/spdy_network_transaction_unittest.cc +++ b/net/spdy/spdy_network_transaction_unittest.cc @@ -1193,9 +1193,8 @@ TEST_F(SpdyNetworkTransactionTest, SynReplyHeadersVary) { { &syn_reply_info, true, - { 2, 4 }, - { { "cookie", "val1", - "cookie", "val2", + { 1, 4 }, + { { "cookie", "val1,val2", NULL }, { "vary", "cookie", @@ -1254,8 +1253,6 @@ TEST_F(SpdyNetworkTransactionTest, SynReplyHeadersVary) { }; for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) { - char modified_syn_header[64]; - // Construct the request. scoped_ptr<spdy::SpdyFrame> frame_req( ConstructSpdyGet(test_cases[i].extra_headers[0], @@ -1292,17 +1289,12 @@ TEST_F(SpdyNetworkTransactionTest, SynReplyHeadersVary) { request.load_flags = 0; // Attach the headers to the request. - int hdrCount = test_cases[i].num_headers[0]; - int len = 0; - - for (int ct = 0; ct < hdrCount; ct++) { - len = ConstructSpdyHeader(test_cases[i].extra_headers[0], - test_cases[i].num_headers[0], - modified_syn_header, - 64, - ct); + int header_count = test_cases[i].num_headers[0]; - request.extra_headers.append(modified_syn_header); + for (int ct = 0; ct < header_count; ct++) { + const char* header_key = test_cases[i].extra_headers[0][ct * 2]; + const char* header_value = test_cases[i].extra_headers[0][ct * 2 + 1]; + request.extra_headers.SetHeader(header_key, header_value); } scoped_refptr<DelayedSocketData> data( diff --git a/net/spdy/spdy_session.cc b/net/spdy/spdy_session.cc index 54e80c9..90b040c 100644 --- a/net/spdy/spdy_session.cc +++ b/net/spdy/spdy_session.cc @@ -133,19 +133,21 @@ bool SpdyHeadersToHttpResponse(const spdy::SpdyHeaderBlock& headers, // a HttpRequestInfo block. void CreateSpdyHeadersFromHttpRequest( const HttpRequestInfo& info, spdy::SpdyHeaderBlock* headers) { + // TODO(willchan): It's not really necessary to convert from + // HttpRequestHeaders to spdy::SpdyHeaderBlock. + static const char kHttpProtocolVersion[] = "HTTP/1.1"; - HttpUtil::HeadersIterator it(info.extra_headers.begin(), - info.extra_headers.end(), - "\r\n"); + HttpRequestHeaders::Iterator it(info.extra_headers); + while (it.GetNext()) { std::string name = StringToLowerASCII(it.name()); if (headers->find(name) == headers->end()) { - (*headers)[name] = it.values(); + (*headers)[name] = it.value(); } else { std::string new_value = (*headers)[name]; new_value.append(1, '\0'); // +=() doesn't append 0's - new_value += it.values(); + new_value += it.value(); (*headers)[name] = new_value; } } @@ -156,8 +158,6 @@ void CreateSpdyHeadersFromHttpRequest( (*headers)["method"] = info.method; (*headers)["url"] = info.url.spec(); (*headers)["version"] = kHttpProtocolVersion; - if (info.user_agent.length()) - (*headers)["user-agent"] = info.user_agent; if (!info.referrer.is_empty()) (*headers)["referer"] = info.referrer.spec(); diff --git a/net/spdy/spdy_session.h b/net/spdy/spdy_session.h index d7f60c0..0564354 100644 --- a/net/spdy/spdy_session.h +++ b/net/spdy/spdy_session.h @@ -30,7 +30,7 @@ namespace net { class SpdyStream; class HttpNetworkSession; -class HttpRequestInfo; +struct HttpRequestInfo; class HttpResponseInfo; class BoundNetLog; class SSLInfo; diff --git a/net/url_request/url_request_http_job.cc b/net/url_request/url_request_http_job.cc index feeba7b..52eda7d 100644 --- a/net/url_request/url_request_http_job.cc +++ b/net/url_request/url_request_http_job.cc @@ -22,6 +22,7 @@ #include "net/base/net_util.h" #include "net/base/sdch_manager.h" #include "net/base/ssl_cert_request_info.h" +#include "net/http/http_request_headers.h" #include "net/http/http_response_headers.h" #include "net/http/http_response_info.h" #include "net/http/http_transaction.h" @@ -32,6 +33,8 @@ #include "net/url_request/url_request_error_job.h" #include "net/url_request/url_request_redirect_job.h" +static const char kAvailDictionaryHeader[] = "Avail-Dictionary"; + // TODO(darin): make sure the port blocking code is not lost // static URLRequestJob* URLRequestHttpJob::Factory(URLRequest* request, @@ -130,7 +133,7 @@ void URLRequestHttpJob::SetUpload(net::UploadData* upload) { void URLRequestHttpJob::SetExtraRequestHeaders( const std::string& headers) { DCHECK(!transaction_.get()) << "cannot change once started"; - request_info_.extra_headers = headers; + request_info_.extra_headers.AddHeadersFromString(headers); } void URLRequestHttpJob::Start() { @@ -146,8 +149,9 @@ void URLRequestHttpJob::Start() { request_info_.priority = request_->priority(); if (request_->context()) { - request_info_.user_agent = - request_->context()->GetUserAgent(request_->url()); + request_info_.extra_headers.SetHeader( + net::HttpRequestHeaders::kUserAgent, + request_->context()->GetUserAgent(request_->url())); } AddExtraHeaders(); @@ -334,9 +338,8 @@ void URLRequestHttpJob::RestartTransactionWithAuth( // Update the cookies, since the cookie store may have been updated from the // headers in the 401/407. Since cookies were already appended to // extra_headers, we need to strip them out before adding them again. - static const char* const cookie_name[] = { "cookie" }; - request_info_.extra_headers = net::HttpUtil::StripHeaders( - request_info_.extra_headers, cookie_name, arraysize(cookie_name)); + request_info_.extra_headers.RemoveHeader( + net::HttpRequestHeaders::kCookie); AddCookieHeaderAndStart(); } @@ -446,8 +449,10 @@ void URLRequestHttpJob::OnCanGetCookiesCompleted(int policy) { request_->context()->cookie_store()->GetCookiesWithOptions( request_->url(), options); if (request_->context()->InterceptRequestCookies(request_, cookies) && - !cookies.empty()) - request_info_.extra_headers += "Cookie: " + cookies + "\r\n"; + !cookies.empty()) { + request_info_.extra_headers.SetHeader( + net::HttpRequestHeaders::kCookie, cookies); + } } // We may have been canceled within OnGetCookiesBlocked. if (GetStatus().is_success()) { @@ -665,14 +670,16 @@ void URLRequestHttpJob::AddExtraHeaders() { // these headers. Some proxies deliberately corrupt Accept-Encoding headers. if (!advertise_sdch) { // Tell the server what compression formats we support (other than SDCH). - request_info_.extra_headers += "Accept-Encoding: gzip,deflate\r\n"; + request_info_.extra_headers.SetHeader( + net::HttpRequestHeaders::kAcceptEncoding, "gzip,deflate"); } else { // Include SDCH in acceptable list. - request_info_.extra_headers += "Accept-Encoding: " - "gzip,deflate,sdch\r\n"; + request_info_.extra_headers.SetHeader( + net::HttpRequestHeaders::kAcceptEncoding, "gzip,deflate,sdch"); if (!avail_dictionaries.empty()) { - request_info_.extra_headers += "Avail-Dictionary: " - + avail_dictionaries + "\r\n"; + request_info_.extra_headers.SetHeader( + kAvailDictionaryHeader, + avail_dictionaries); sdch_dictionary_advertised_ = true; // Since we're tagging this transaction as advertising a dictionary, we'll // definately employ an SDCH filter (or tentative sdch filter) when we get @@ -686,12 +693,18 @@ void URLRequestHttpJob::AddExtraHeaders() { if (context) { // Only add default Accept-Language and Accept-Charset if the request // didn't have them specified. - net::HttpUtil::AppendHeaderIfMissing("Accept-Language", - context->accept_language(), - &request_info_.extra_headers); - net::HttpUtil::AppendHeaderIfMissing("Accept-Charset", - context->accept_charset(), - &request_info_.extra_headers); + if (!request_info_.extra_headers.HasHeader( + net::HttpRequestHeaders::kAcceptLanguage)) { + request_info_.extra_headers.SetHeader( + net::HttpRequestHeaders::kAcceptLanguage, + context->accept_language()); + } + if (!request_info_.extra_headers.HasHeader( + net::HttpRequestHeaders::kAcceptCharset)) { + request_info_.extra_headers.SetHeader( + net::HttpRequestHeaders::kAcceptCharset, + context->accept_charset()); + } } } |