[go: nahoru, domu]

Use HttpRequestHeaders for extra_headers.
BUG=22588

Review URL: http://codereview.chromium.org/1604011

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@45096 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/base/string_util.cc b/base/string_util.cc
index fafc1060..0269ba10 100644
--- a/base/string_util.cc
+++ b/base/string_util.cc
@@ -1352,20 +1352,6 @@
   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 dc87d341..40ebe8d 100644
--- a/net/http/http_auth_handler.h
+++ b/net/http/http_auth_handler.h
@@ -15,8 +15,8 @@
 
 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..12808bf7 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 @@
 }  // 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 @@
 
 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 @@
 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 b5b35156..c0eefeac 100644
--- a/net/http/http_cache_transaction.cc
+++ b/net/http/http_cache_transaction.cc
@@ -69,16 +69,17 @@
   { 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 @@
     { 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;
-      }
-    }
+  }
 
-    // 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;
-      }
+  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];
+    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 @@
       // 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 @@
     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 @@
 
   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::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 @@
   }
 
   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 @@
 
   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 @@
   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 @@
     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 @@
 
   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 @@
     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 @@
     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 @@
   };
 
   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 @@
   };
 
   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 @@
   };
 
   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 @@
   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 @@
   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 @@
   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 @@
   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 @@
   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 @@
   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 @@
   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 @@
   // 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 @@
   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 @@
   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 @@
   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 @@
   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 @@
   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 @@
   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 @@
   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 @@
   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 @@
   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 @@
   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 @@
   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 @@
   // 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 @@
   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 @@
                                  &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 @@
   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 @@
   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 @@
   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 @@
   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 @@
   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 @@
   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 @@
   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 @@
   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 @@
   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 @@
                          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 @@
     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 @@
     "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 @@
 // 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 @@
         (HaveAuth(HttpAuth::AUTH_SERVER) ||
          SelectPreemptiveAuth(HttpAuth::AUTH_SERVER));
 
+    std::string request_line;
     HttpRequestHeaders request_headers;
     HttpRequestHeaders authorization_headers;
 
@@ -974,13 +960,15 @@
       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..8c0d8bd8 100644
--- a/net/http/http_network_transaction_unittest.cc
+++ b/net/http/http_network_transaction_unittest.cc
@@ -2924,7 +2924,8 @@
     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 @@
   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 @@
   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 @@
   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::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 @@
 
 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 @@
   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..c107a3c2 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 @@
 
 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 @@
   // 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 29431d91..f3abfbe2 100644
--- a/net/http/http_request_headers_unittest.cc
+++ b/net/http/http_request_headers_unittest.cc
@@ -10,11 +10,17 @@
 
 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 @@
   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 @@
   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 @@
   // 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..724127f4 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 a18d4222..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..8a998120 100644
--- a/net/http/http_transaction_unittest.h
+++ b/net/http/http_transaction_unittest.h
@@ -97,7 +97,7 @@
   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 @@
   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 @@
   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 @@
     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 @@
 
 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 @@
     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 @@
 
   // 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, 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, 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 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 std::string& headers) {
+bool PartialData::Init(const HttpRequestHeaders& headers) {
+  std::string range_header;
+  if (!headers.GetHeader(HttpRequestHeaders::kRange, &range_header))
+    return false;
+
   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 @@
   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 @@
     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 @@
     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..51e6d7db 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 @@
         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 @@
   // 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 @@
   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 @@
     {
       &syn_reply_info,
       true,
-      { 2, 4 },
-      { { "cookie",   "val1",
-          "cookie",   "val2",
+      { 1, 4 },
+      { { "cookie",   "val1,val2",
           NULL
         },
         { "vary",     "cookie",
@@ -1254,8 +1253,6 @@
   };
 
   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 @@
     request.load_flags = 0;
 
     // Attach the headers to the request.
-    int hdrCount = test_cases[i].num_headers[0];
-    int len = 0;
+    int header_count = test_cases[i].num_headers[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);
-
-      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..90b040cc 100644
--- a/net/spdy/spdy_session.cc
+++ b/net/spdy/spdy_session.cc
@@ -133,19 +133,21 @@
 // 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 @@
   (*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 @@
 
 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..52eda7d4 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::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 @@
   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 @@
   // 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 @@
           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 @@
   // 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 @@
   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());
+    }
   }
 }