Home | History | Annotate | Download | only in http
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include <algorithm>
      6 #include <limits>
      7 
      8 #include "base/basictypes.h"
      9 #include "base/memory/scoped_ptr.h"
     10 #include "base/pickle.h"
     11 #include "base/time/time.h"
     12 #include "base/values.h"
     13 #include "net/http/http_byte_range.h"
     14 #include "net/http/http_response_headers.h"
     15 #include "testing/gtest/include/gtest/gtest.h"
     16 
     17 namespace {
     18 
     19 struct TestData {
     20   const char* raw_headers;
     21   const char* expected_headers;
     22   int expected_response_code;
     23   net::HttpVersion expected_parsed_version;
     24   net::HttpVersion expected_version;
     25 };
     26 
     27 class HttpResponseHeadersTest : public testing::Test {
     28 };
     29 
     30 // Transform "normal"-looking headers (\n-separated) to the appropriate
     31 // input format for ParseRawHeaders (\0-separated).
     32 void HeadersToRaw(std::string* headers) {
     33   std::replace(headers->begin(), headers->end(), '\n', '\0');
     34   if (!headers->empty())
     35     *headers += '\0';
     36 }
     37 
     38 class HttpResponseHeadersCacheControlTest : public HttpResponseHeadersTest {
     39  protected:
     40   // Make tests less verbose.
     41   typedef base::TimeDelta TimeDelta;
     42 
     43   // Initilise the headers() value with a Cache-Control header set to
     44   // |cache_control|. |cache_control| is copied and so can safely be a
     45   // temporary.
     46   void InitializeHeadersWithCacheControl(const char* cache_control) {
     47     std::string raw_headers("HTTP/1.1 200 OK\n");
     48     raw_headers += "Cache-Control: ";
     49     raw_headers += cache_control;
     50     raw_headers += "\n";
     51     HeadersToRaw(&raw_headers);
     52     headers_ = new net::HttpResponseHeaders(raw_headers);
     53   }
     54 
     55   const scoped_refptr<net::HttpResponseHeaders>& headers() { return headers_; }
     56 
     57   // Return a pointer to a TimeDelta object. For use when the value doesn't
     58   // matter.
     59   TimeDelta* TimeDeltaPointer() { return &delta_; }
     60 
     61   // Get the max-age value. This should only be used in tests where a valid
     62   // max-age parameter is expected to be present.
     63   TimeDelta GetMaxAgeValue() {
     64     DCHECK(headers_.get()) << "Call InitializeHeadersWithCacheControl() first";
     65     TimeDelta max_age_value;
     66     EXPECT_TRUE(headers()->GetMaxAgeValue(&max_age_value));
     67     return max_age_value;
     68   }
     69 
     70   // Get the stale-while-revalidate value. This should only be used in tests
     71   // where a valid max-age parameter is expected to be present.
     72   TimeDelta GetStaleWhileRevalidateValue() {
     73     DCHECK(headers_.get()) << "Call InitializeHeadersWithCacheControl() first";
     74     TimeDelta stale_while_revalidate_value;
     75     EXPECT_TRUE(
     76         headers()->GetStaleWhileRevalidateValue(&stale_while_revalidate_value));
     77     return stale_while_revalidate_value;
     78   }
     79 
     80  private:
     81   scoped_refptr<net::HttpResponseHeaders> headers_;
     82   TimeDelta delta_;
     83 };
     84 
     85 class CommonHttpResponseHeadersTest
     86     : public HttpResponseHeadersTest,
     87       public ::testing::WithParamInterface<TestData> {
     88 };
     89 
     90 TEST_P(CommonHttpResponseHeadersTest, TestCommon) {
     91   const TestData test = GetParam();
     92 
     93   std::string raw_headers(test.raw_headers);
     94   HeadersToRaw(&raw_headers);
     95   std::string expected_headers(test.expected_headers);
     96 
     97   std::string headers;
     98   scoped_refptr<net::HttpResponseHeaders> parsed(
     99       new net::HttpResponseHeaders(raw_headers));
    100   parsed->GetNormalizedHeaders(&headers);
    101 
    102   // Transform to readable output format (so it's easier to see diffs).
    103   std::replace(headers.begin(), headers.end(), ' ', '_');
    104   std::replace(headers.begin(), headers.end(), '\n', '\\');
    105   std::replace(expected_headers.begin(), expected_headers.end(), ' ', '_');
    106   std::replace(expected_headers.begin(), expected_headers.end(), '\n', '\\');
    107 
    108   EXPECT_EQ(expected_headers, headers);
    109 
    110   EXPECT_EQ(test.expected_response_code, parsed->response_code());
    111 
    112   EXPECT_TRUE(test.expected_parsed_version == parsed->GetParsedHttpVersion());
    113   EXPECT_TRUE(test.expected_version == parsed->GetHttpVersion());
    114 }
    115 
    116 TestData response_headers_tests[] = {
    117   {
    118     // Normalise whitespace.
    119 
    120     "HTTP/1.1    202   Accepted  \n"
    121     "Content-TYPE  : text/html; charset=utf-8  \n"
    122     "Set-Cookie: a \n"
    123     "Set-Cookie:   b \n",
    124 
    125     "HTTP/1.1 202 Accepted\n"
    126     "Content-TYPE: text/html; charset=utf-8\n"
    127     "Set-Cookie: a, b\n",
    128 
    129     202,
    130     net::HttpVersion(1,1),
    131     net::HttpVersion(1,1)
    132   },
    133   {
    134     // Normalize leading whitespace.
    135 
    136     "HTTP/1.1    202   Accepted  \n"
    137     // Starts with space -- will be skipped as invalid.
    138     "  Content-TYPE  : text/html; charset=utf-8  \n"
    139     "Set-Cookie: a \n"
    140     "Set-Cookie:   b \n",
    141 
    142     "HTTP/1.1 202 Accepted\n"
    143     "Set-Cookie: a, b\n",
    144 
    145     202,
    146     net::HttpVersion(1,1),
    147     net::HttpVersion(1,1)
    148   },
    149   {
    150     // Normalize blank headers.
    151 
    152     "HTTP/1.1 200 OK\n"
    153     "Header1 :          \n"
    154     "Header2: \n"
    155     "Header3:\n"
    156     "Header4\n"
    157     "Header5    :\n",
    158 
    159     "HTTP/1.1 200 OK\n"
    160     "Header1: \n"
    161     "Header2: \n"
    162     "Header3: \n"
    163     "Header5: \n",
    164 
    165     200,
    166     net::HttpVersion(1,1),
    167     net::HttpVersion(1,1)
    168   },
    169   {
    170     // Don't believe the http/0.9 version if there are headers!
    171 
    172     "hTtP/0.9 201\n"
    173     "Content-TYPE: text/html; charset=utf-8\n",
    174 
    175     "HTTP/1.0 201 OK\n"
    176     "Content-TYPE: text/html; charset=utf-8\n",
    177 
    178     201,
    179     net::HttpVersion(0,9),
    180     net::HttpVersion(1,0)
    181   },
    182   {
    183     // Accept the HTTP/0.9 version number if there are no headers.
    184     // This is how HTTP/0.9 responses get constructed from
    185     // HttpNetworkTransaction.
    186 
    187     "hTtP/0.9 200 OK\n",
    188 
    189     "HTTP/0.9 200 OK\n",
    190 
    191     200,
    192     net::HttpVersion(0,9),
    193     net::HttpVersion(0,9)
    194   },
    195   {
    196     // Add missing OK.
    197 
    198     "HTTP/1.1 201\n"
    199     "Content-TYPE: text/html; charset=utf-8\n",
    200 
    201     "HTTP/1.1 201 OK\n"
    202     "Content-TYPE: text/html; charset=utf-8\n",
    203 
    204     201,
    205     net::HttpVersion(1,1),
    206     net::HttpVersion(1,1)
    207   },
    208   {
    209     // Normalize bad status line.
    210 
    211     "SCREWED_UP_STATUS_LINE\n"
    212     "Content-TYPE: text/html; charset=utf-8\n",
    213 
    214     "HTTP/1.0 200 OK\n"
    215     "Content-TYPE: text/html; charset=utf-8\n",
    216 
    217     200,
    218     net::HttpVersion(0,0), // Parse error.
    219     net::HttpVersion(1,0)
    220   },
    221   {
    222     // Normalize invalid status code.
    223 
    224     "HTTP/1.1 -1  Unknown\n",
    225 
    226     "HTTP/1.1 200 OK\n",
    227 
    228     200,
    229     net::HttpVersion(1,1),
    230     net::HttpVersion(1,1)
    231   },
    232   {
    233     // Normalize empty header.
    234 
    235     "",
    236 
    237     "HTTP/1.0 200 OK\n",
    238 
    239     200,
    240     net::HttpVersion(0,0), // Parse Error.
    241     net::HttpVersion(1,0)
    242   },
    243   {
    244     // Normalize headers that start with a colon.
    245 
    246     "HTTP/1.1    202   Accepted  \n"
    247     "foo: bar\n"
    248     ": a \n"
    249     " : b\n"
    250     "baz: blat \n",
    251 
    252     "HTTP/1.1 202 Accepted\n"
    253     "foo: bar\n"
    254     "baz: blat\n",
    255 
    256     202,
    257     net::HttpVersion(1,1),
    258     net::HttpVersion(1,1)
    259   },
    260   {
    261     // Normalize headers that end with a colon.
    262 
    263     "HTTP/1.1    202   Accepted  \n"
    264     "foo:   \n"
    265     "bar:\n"
    266     "baz: blat \n"
    267     "zip:\n",
    268 
    269     "HTTP/1.1 202 Accepted\n"
    270     "foo: \n"
    271     "bar: \n"
    272     "baz: blat\n"
    273     "zip: \n",
    274 
    275     202,
    276     net::HttpVersion(1,1),
    277     net::HttpVersion(1,1)
    278   },
    279   {
    280     // Normalize whitespace headers.
    281 
    282     "\n   \n",
    283 
    284     "HTTP/1.0 200 OK\n",
    285 
    286     200,
    287     net::HttpVersion(0,0),  // Parse error.
    288     net::HttpVersion(1,0)
    289   },
    290   {
    291     // Consolidate Set-Cookie headers.
    292 
    293     "HTTP/1.1 200 OK\n"
    294     "Set-Cookie: x=1\n"
    295     "Set-Cookie: y=2\n",
    296 
    297     "HTTP/1.1 200 OK\n"
    298     "Set-Cookie: x=1, y=2\n",
    299 
    300     200,
    301     net::HttpVersion(1,1),
    302     net::HttpVersion(1,1)
    303   },
    304 };
    305 
    306 INSTANTIATE_TEST_CASE_P(HttpResponseHeaders,
    307                         CommonHttpResponseHeadersTest,
    308                         testing::ValuesIn(response_headers_tests));
    309 
    310 TEST(HttpResponseHeadersTest, GetNormalizedHeader) {
    311   std::string headers =
    312       "HTTP/1.1 200 OK\n"
    313       "Cache-control: private\n"
    314       "cache-Control: no-store\n";
    315   HeadersToRaw(&headers);
    316   scoped_refptr<net::HttpResponseHeaders> parsed(
    317       new net::HttpResponseHeaders(headers));
    318 
    319   std::string value;
    320   EXPECT_TRUE(parsed->GetNormalizedHeader("cache-control", &value));
    321   EXPECT_EQ("private, no-store", value);
    322 }
    323 
    324 struct PersistData {
    325   net::HttpResponseHeaders::PersistOptions options;
    326   const char* raw_headers;
    327   const char* expected_headers;
    328 };
    329 
    330 class PersistenceTest
    331     : public HttpResponseHeadersTest,
    332       public ::testing::WithParamInterface<PersistData> {
    333 };
    334 
    335 TEST_P(PersistenceTest, Persist) {
    336   const PersistData test = GetParam();
    337 
    338   std::string headers = test.raw_headers;
    339   HeadersToRaw(&headers);
    340   scoped_refptr<net::HttpResponseHeaders> parsed1(
    341       new net::HttpResponseHeaders(headers));
    342 
    343   Pickle pickle;
    344   parsed1->Persist(&pickle, test.options);
    345 
    346   PickleIterator iter(pickle);
    347   scoped_refptr<net::HttpResponseHeaders> parsed2(
    348       new net::HttpResponseHeaders(pickle, &iter));
    349 
    350   std::string h2;
    351   parsed2->GetNormalizedHeaders(&h2);
    352   EXPECT_EQ(std::string(test.expected_headers), h2);
    353 }
    354 
    355 const struct PersistData persistence_tests[] = {
    356   { net::HttpResponseHeaders::PERSIST_ALL,
    357     "HTTP/1.1 200 OK\n"
    358     "Cache-control:private\n"
    359     "cache-Control:no-store\n",
    360 
    361     "HTTP/1.1 200 OK\n"
    362     "Cache-control: private, no-store\n"
    363   },
    364   { net::HttpResponseHeaders::PERSIST_SANS_HOP_BY_HOP,
    365     "HTTP/1.1 200 OK\n"
    366     "connection: keep-alive\n"
    367     "server: blah\n",
    368 
    369     "HTTP/1.1 200 OK\n"
    370     "server: blah\n"
    371   },
    372   { net::HttpResponseHeaders::PERSIST_SANS_NON_CACHEABLE |
    373     net::HttpResponseHeaders::PERSIST_SANS_HOP_BY_HOP,
    374     "HTTP/1.1 200 OK\n"
    375     "fOo: 1\n"
    376     "Foo: 2\n"
    377     "Transfer-Encoding: chunked\n"
    378     "CoNnection: keep-alive\n"
    379     "cache-control: private, no-cache=\"foo\"\n",
    380 
    381     "HTTP/1.1 200 OK\n"
    382     "cache-control: private, no-cache=\"foo\"\n"
    383   },
    384   { net::HttpResponseHeaders::PERSIST_SANS_NON_CACHEABLE,
    385     "HTTP/1.1 200 OK\n"
    386     "Foo: 2\n"
    387     "Cache-Control: private,no-cache=\"foo, bar\"\n"
    388     "bar",
    389 
    390     "HTTP/1.1 200 OK\n"
    391     "Cache-Control: private,no-cache=\"foo, bar\"\n"
    392   },
    393   // Ignore bogus no-cache value.
    394   { net::HttpResponseHeaders::PERSIST_SANS_NON_CACHEABLE,
    395     "HTTP/1.1 200 OK\n"
    396     "Foo: 2\n"
    397     "Cache-Control: private,no-cache=foo\n",
    398 
    399     "HTTP/1.1 200 OK\n"
    400     "Foo: 2\n"
    401     "Cache-Control: private,no-cache=foo\n"
    402   },
    403   // Ignore bogus no-cache value.
    404   { net::HttpResponseHeaders::PERSIST_SANS_NON_CACHEABLE,
    405     "HTTP/1.1 200 OK\n"
    406     "Foo: 2\n"
    407     "Cache-Control: private, no-cache=\n",
    408 
    409     "HTTP/1.1 200 OK\n"
    410     "Foo: 2\n"
    411     "Cache-Control: private, no-cache=\n"
    412   },
    413   // Ignore empty no-cache value.
    414   { net::HttpResponseHeaders::PERSIST_SANS_NON_CACHEABLE,
    415     "HTTP/1.1 200 OK\n"
    416     "Foo: 2\n"
    417     "Cache-Control: private, no-cache=\"\"\n",
    418 
    419     "HTTP/1.1 200 OK\n"
    420     "Foo: 2\n"
    421     "Cache-Control: private, no-cache=\"\"\n"
    422   },
    423   // Ignore wrong quotes no-cache value.
    424   { net::HttpResponseHeaders::PERSIST_SANS_NON_CACHEABLE,
    425     "HTTP/1.1 200 OK\n"
    426     "Foo: 2\n"
    427     "Cache-Control: private, no-cache=\'foo\'\n",
    428 
    429     "HTTP/1.1 200 OK\n"
    430     "Foo: 2\n"
    431     "Cache-Control: private, no-cache=\'foo\'\n"
    432   },
    433   // Ignore unterminated quotes no-cache value.
    434   { net::HttpResponseHeaders::PERSIST_SANS_NON_CACHEABLE,
    435     "HTTP/1.1 200 OK\n"
    436     "Foo: 2\n"
    437     "Cache-Control: private, no-cache=\"foo\n",
    438 
    439     "HTTP/1.1 200 OK\n"
    440     "Foo: 2\n"
    441     "Cache-Control: private, no-cache=\"foo\n"
    442   },
    443   // Accept sloppy LWS.
    444   { net::HttpResponseHeaders::PERSIST_SANS_NON_CACHEABLE,
    445     "HTTP/1.1 200 OK\n"
    446     "Foo: 2\n"
    447     "Cache-Control: private, no-cache=\" foo\t, bar\"\n",
    448 
    449     "HTTP/1.1 200 OK\n"
    450     "Cache-Control: private, no-cache=\" foo\t, bar\"\n"
    451   },
    452   // Header name appears twice, separated by another header.
    453   { net::HttpResponseHeaders::PERSIST_ALL,
    454     "HTTP/1.1 200 OK\n"
    455     "Foo: 1\n"
    456     "Bar: 2\n"
    457     "Foo: 3\n",
    458 
    459     "HTTP/1.1 200 OK\n"
    460     "Foo: 1, 3\n"
    461     "Bar: 2\n"
    462   },
    463   // Header name appears twice, separated by another header (type 2).
    464   { net::HttpResponseHeaders::PERSIST_ALL,
    465     "HTTP/1.1 200 OK\n"
    466     "Foo: 1, 3\n"
    467     "Bar: 2\n"
    468     "Foo: 4\n",
    469 
    470     "HTTP/1.1 200 OK\n"
    471     "Foo: 1, 3, 4\n"
    472     "Bar: 2\n"
    473   },
    474   // Test filtering of cookie headers.
    475   { net::HttpResponseHeaders::PERSIST_SANS_COOKIES,
    476     "HTTP/1.1 200 OK\n"
    477     "Set-Cookie: foo=bar; httponly\n"
    478     "Set-Cookie: bar=foo\n"
    479     "Bar: 1\n"
    480     "Set-Cookie2: bar2=foo2\n",
    481 
    482     "HTTP/1.1 200 OK\n"
    483     "Bar: 1\n"
    484   },
    485   // Test LWS at the end of a header.
    486   { net::HttpResponseHeaders::PERSIST_ALL,
    487     "HTTP/1.1 200 OK\n"
    488     "Content-Length: 450   \n"
    489     "Content-Encoding: gzip\n",
    490 
    491     "HTTP/1.1 200 OK\n"
    492     "Content-Length: 450\n"
    493     "Content-Encoding: gzip\n"
    494   },
    495   // Test LWS at the end of a header.
    496   { net::HttpResponseHeaders::PERSIST_RAW,
    497     "HTTP/1.1 200 OK\n"
    498     "Content-Length: 450   \n"
    499     "Content-Encoding: gzip\n",
    500 
    501     "HTTP/1.1 200 OK\n"
    502     "Content-Length: 450\n"
    503     "Content-Encoding: gzip\n"
    504   },
    505   // Test filtering of transport security state headers.
    506   { net::HttpResponseHeaders::PERSIST_SANS_SECURITY_STATE,
    507     "HTTP/1.1 200 OK\n"
    508     "Strict-Transport-Security: max-age=1576800\n"
    509     "Bar: 1\n"
    510     "Public-Key-Pins: max-age=100000; "
    511         "pin-sha1=\"ObT42aoSpAqWdY9WfRfL7i0HsVk=\";"
    512         "pin-sha1=\"7kW49EVwZG0hSNx41ZO/fUPN0ek=\"",
    513 
    514     "HTTP/1.1 200 OK\n"
    515     "Bar: 1\n"
    516   },
    517 };
    518 
    519 INSTANTIATE_TEST_CASE_P(HttpResponseHeaders,
    520                         PersistenceTest,
    521                         testing::ValuesIn(persistence_tests));
    522 
    523 TEST(HttpResponseHeadersTest, EnumerateHeader_Coalesced) {
    524   // Ensure that commas in quoted strings are not regarded as value separators.
    525   // Ensure that whitespace following a value is trimmed properly.
    526   std::string headers =
    527       "HTTP/1.1 200 OK\n"
    528       "Cache-control:private , no-cache=\"set-cookie,server\" \n"
    529       "cache-Control: no-store\n";
    530   HeadersToRaw(&headers);
    531   scoped_refptr<net::HttpResponseHeaders> parsed(
    532       new net::HttpResponseHeaders(headers));
    533 
    534   void* iter = NULL;
    535   std::string value;
    536   EXPECT_TRUE(parsed->EnumerateHeader(&iter, "cache-control", &value));
    537   EXPECT_EQ("private", value);
    538   EXPECT_TRUE(parsed->EnumerateHeader(&iter, "cache-control", &value));
    539   EXPECT_EQ("no-cache=\"set-cookie,server\"", value);
    540   EXPECT_TRUE(parsed->EnumerateHeader(&iter, "cache-control", &value));
    541   EXPECT_EQ("no-store", value);
    542   EXPECT_FALSE(parsed->EnumerateHeader(&iter, "cache-control", &value));
    543 }
    544 
    545 TEST(HttpResponseHeadersTest, EnumerateHeader_Challenge) {
    546   // Even though WWW-Authenticate has commas, it should not be treated as
    547   // coalesced values.
    548   std::string headers =
    549       "HTTP/1.1 401 OK\n"
    550       "WWW-Authenticate:Digest realm=foobar, nonce=x, domain=y\n"
    551       "WWW-Authenticate:Basic realm=quatar\n";
    552   HeadersToRaw(&headers);
    553   scoped_refptr<net::HttpResponseHeaders> parsed(
    554       new net::HttpResponseHeaders(headers));
    555 
    556   void* iter = NULL;
    557   std::string value;
    558   EXPECT_TRUE(parsed->EnumerateHeader(&iter, "WWW-Authenticate", &value));
    559   EXPECT_EQ("Digest realm=foobar, nonce=x, domain=y", value);
    560   EXPECT_TRUE(parsed->EnumerateHeader(&iter, "WWW-Authenticate", &value));
    561   EXPECT_EQ("Basic realm=quatar", value);
    562   EXPECT_FALSE(parsed->EnumerateHeader(&iter, "WWW-Authenticate", &value));
    563 }
    564 
    565 TEST(HttpResponseHeadersTest, EnumerateHeader_DateValued) {
    566   // The comma in a date valued header should not be treated as a
    567   // field-value separator.
    568   std::string headers =
    569       "HTTP/1.1 200 OK\n"
    570       "Date: Tue, 07 Aug 2007 23:10:55 GMT\n"
    571       "Last-Modified: Wed, 01 Aug 2007 23:23:45 GMT\n";
    572   HeadersToRaw(&headers);
    573   scoped_refptr<net::HttpResponseHeaders> parsed(
    574       new net::HttpResponseHeaders(headers));
    575 
    576   std::string value;
    577   EXPECT_TRUE(parsed->EnumerateHeader(NULL, "date", &value));
    578   EXPECT_EQ("Tue, 07 Aug 2007 23:10:55 GMT", value);
    579   EXPECT_TRUE(parsed->EnumerateHeader(NULL, "last-modified", &value));
    580   EXPECT_EQ("Wed, 01 Aug 2007 23:23:45 GMT", value);
    581 }
    582 
    583 TEST(HttpResponseHeadersTest, DefaultDateToGMT) {
    584   // Verify we make the best interpretation when parsing dates that incorrectly
    585   // do not end in "GMT" as RFC2616 requires.
    586   std::string headers =
    587       "HTTP/1.1 200 OK\n"
    588       "Date: Tue, 07 Aug 2007 23:10:55\n"
    589       "Last-Modified: Tue, 07 Aug 2007 19:10:55 EDT\n"
    590       "Expires: Tue, 07 Aug 2007 23:10:55 UTC\n";
    591   HeadersToRaw(&headers);
    592   scoped_refptr<net::HttpResponseHeaders> parsed(
    593       new net::HttpResponseHeaders(headers));
    594   base::Time expected_value;
    595   ASSERT_TRUE(base::Time::FromString("Tue, 07 Aug 2007 23:10:55 GMT",
    596                                      &expected_value));
    597 
    598   base::Time value;
    599   // When the timezone is missing, GMT is a good guess as its what RFC2616
    600   // requires.
    601   EXPECT_TRUE(parsed->GetDateValue(&value));
    602   EXPECT_EQ(expected_value, value);
    603   // If GMT is missing but an RFC822-conforming one is present, use that.
    604   EXPECT_TRUE(parsed->GetLastModifiedValue(&value));
    605   EXPECT_EQ(expected_value, value);
    606   // If an unknown timezone is present, treat like a missing timezone and
    607   // default to GMT.  The only example of a web server not specifying "GMT"
    608   // used "UTC" which is equivalent to GMT.
    609   if (parsed->GetExpiresValue(&value))
    610     EXPECT_EQ(expected_value, value);
    611 }
    612 
    613 struct ContentTypeTestData {
    614   const std::string raw_headers;
    615   const std::string mime_type;
    616   const bool has_mimetype;
    617   const std::string charset;
    618   const bool has_charset;
    619   const std::string all_content_type;
    620 };
    621 
    622 class ContentTypeTest
    623     : public HttpResponseHeadersTest,
    624       public ::testing::WithParamInterface<ContentTypeTestData> {
    625 };
    626 
    627 TEST_P(ContentTypeTest, GetMimeType) {
    628   const ContentTypeTestData test = GetParam();
    629 
    630   std::string headers(test.raw_headers);
    631   HeadersToRaw(&headers);
    632   scoped_refptr<net::HttpResponseHeaders> parsed(
    633       new net::HttpResponseHeaders(headers));
    634 
    635   std::string value;
    636   EXPECT_EQ(test.has_mimetype, parsed->GetMimeType(&value));
    637   EXPECT_EQ(test.mime_type, value);
    638   value.clear();
    639   EXPECT_EQ(test.has_charset, parsed->GetCharset(&value));
    640   EXPECT_EQ(test.charset, value);
    641   EXPECT_TRUE(parsed->GetNormalizedHeader("content-type", &value));
    642   EXPECT_EQ(test.all_content_type, value);
    643 }
    644 
    645 const ContentTypeTestData mimetype_tests[] = {
    646   { "HTTP/1.1 200 OK\n"
    647     "Content-type: text/html\n",
    648     "text/html", true,
    649     "", false,
    650     "text/html" },
    651   // Multiple content-type headers should give us the last one.
    652   { "HTTP/1.1 200 OK\n"
    653     "Content-type: text/html\n"
    654     "Content-type: text/html\n",
    655     "text/html", true,
    656     "", false,
    657     "text/html, text/html" },
    658   { "HTTP/1.1 200 OK\n"
    659     "Content-type: text/plain\n"
    660     "Content-type: text/html\n"
    661     "Content-type: text/plain\n"
    662     "Content-type: text/html\n",
    663     "text/html", true,
    664     "", false,
    665     "text/plain, text/html, text/plain, text/html" },
    666   // Test charset parsing.
    667   { "HTTP/1.1 200 OK\n"
    668     "Content-type: text/html\n"
    669     "Content-type: text/html; charset=ISO-8859-1\n",
    670     "text/html", true,
    671     "iso-8859-1", true,
    672     "text/html, text/html; charset=ISO-8859-1" },
    673   // Test charset in double quotes.
    674   { "HTTP/1.1 200 OK\n"
    675     "Content-type: text/html\n"
    676     "Content-type: text/html; charset=\"ISO-8859-1\"\n",
    677     "text/html", true,
    678     "iso-8859-1", true,
    679     "text/html, text/html; charset=\"ISO-8859-1\"" },
    680   // If there are multiple matching content-type headers, we carry
    681   // over the charset value.
    682   { "HTTP/1.1 200 OK\n"
    683     "Content-type: text/html;charset=utf-8\n"
    684     "Content-type: text/html\n",
    685     "text/html", true,
    686     "utf-8", true,
    687     "text/html;charset=utf-8, text/html" },
    688   // Test single quotes.
    689   { "HTTP/1.1 200 OK\n"
    690     "Content-type: text/html;charset='utf-8'\n"
    691     "Content-type: text/html\n",
    692     "text/html", true,
    693     "utf-8", true,
    694     "text/html;charset='utf-8', text/html" },
    695   // Last charset wins if matching content-type.
    696   { "HTTP/1.1 200 OK\n"
    697     "Content-type: text/html;charset=utf-8\n"
    698     "Content-type: text/html;charset=iso-8859-1\n",
    699     "text/html", true,
    700     "iso-8859-1", true,
    701     "text/html;charset=utf-8, text/html;charset=iso-8859-1" },
    702   // Charset is ignored if the content types change.
    703   { "HTTP/1.1 200 OK\n"
    704     "Content-type: text/plain;charset=utf-8\n"
    705     "Content-type: text/html\n",
    706     "text/html", true,
    707     "", false,
    708     "text/plain;charset=utf-8, text/html" },
    709   // Empty content-type.
    710   { "HTTP/1.1 200 OK\n"
    711     "Content-type: \n",
    712     "", false,
    713     "", false,
    714     "" },
    715   // Emtpy charset.
    716   { "HTTP/1.1 200 OK\n"
    717     "Content-type: text/html;charset=\n",
    718     "text/html", true,
    719     "", false,
    720     "text/html;charset=" },
    721   // Multiple charsets, last one wins.
    722   { "HTTP/1.1 200 OK\n"
    723     "Content-type: text/html;charset=utf-8; charset=iso-8859-1\n",
    724     "text/html", true,
    725     "iso-8859-1", true,
    726     "text/html;charset=utf-8; charset=iso-8859-1" },
    727   // Multiple params.
    728   { "HTTP/1.1 200 OK\n"
    729     "Content-type: text/html; foo=utf-8; charset=iso-8859-1\n",
    730     "text/html", true,
    731     "iso-8859-1", true,
    732     "text/html; foo=utf-8; charset=iso-8859-1" },
    733   { "HTTP/1.1 200 OK\n"
    734     "Content-type: text/html ; charset=utf-8 ; bar=iso-8859-1\n",
    735     "text/html", true,
    736     "utf-8", true,
    737     "text/html ; charset=utf-8 ; bar=iso-8859-1" },
    738   // Comma embeded in quotes.
    739   { "HTTP/1.1 200 OK\n"
    740     "Content-type: text/html ; charset='utf-8,text/plain' ;\n",
    741     "text/html", true,
    742     "utf-8,text/plain", true,
    743     "text/html ; charset='utf-8,text/plain' ;" },
    744   // Charset with leading spaces.
    745   { "HTTP/1.1 200 OK\n"
    746     "Content-type: text/html ; charset= 'utf-8' ;\n",
    747     "text/html", true,
    748     "utf-8", true,
    749     "text/html ; charset= 'utf-8' ;" },
    750   // Media type comments in mime-type.
    751   { "HTTP/1.1 200 OK\n"
    752     "Content-type: text/html (html)\n",
    753     "text/html", true,
    754     "", false,
    755    "text/html (html)" },
    756   // Incomplete charset= param.
    757   { "HTTP/1.1 200 OK\n"
    758     "Content-type: text/html; char=\n",
    759     "text/html", true,
    760     "", false,
    761     "text/html; char=" },
    762   // Invalid media type: no slash.
    763   { "HTTP/1.1 200 OK\n"
    764     "Content-type: texthtml\n",
    765     "", false,
    766     "", false,
    767     "texthtml" },
    768   // Invalid media type: "*/*".
    769   { "HTTP/1.1 200 OK\n"
    770     "Content-type: */*\n",
    771     "", false,
    772     "", false,
    773     "*/*" },
    774 };
    775 
    776 INSTANTIATE_TEST_CASE_P(HttpResponseHeaders,
    777                         ContentTypeTest,
    778                         testing::ValuesIn(mimetype_tests));
    779 
    780 struct RequiresValidationTestData {
    781   const char* headers;
    782   bool requires_validation;
    783 };
    784 
    785 class RequiresValidationTest
    786     : public HttpResponseHeadersTest,
    787       public ::testing::WithParamInterface<RequiresValidationTestData> {
    788 };
    789 
    790 TEST_P(RequiresValidationTest, RequiresValidation) {
    791   const RequiresValidationTestData test = GetParam();
    792 
    793   base::Time request_time, response_time, current_time;
    794   base::Time::FromString("Wed, 28 Nov 2007 00:40:09 GMT", &request_time);
    795   base::Time::FromString("Wed, 28 Nov 2007 00:40:12 GMT", &response_time);
    796   base::Time::FromString("Wed, 28 Nov 2007 00:45:20 GMT", &current_time);
    797 
    798   std::string headers(test.headers);
    799   HeadersToRaw(&headers);
    800   scoped_refptr<net::HttpResponseHeaders> parsed(
    801       new net::HttpResponseHeaders(headers));
    802 
    803   bool requires_validation =
    804       parsed->RequiresValidation(request_time, response_time, current_time);
    805   EXPECT_EQ(test.requires_validation, requires_validation);
    806 }
    807 
    808 const struct RequiresValidationTestData requires_validation_tests[] = {
    809   // No expiry info: expires immediately.
    810   { "HTTP/1.1 200 OK\n"
    811     "\n",
    812     true
    813   },
    814   // No expiry info: expires immediately.
    815   { "HTTP/1.1 200 OK\n"
    816     "\n",
    817     true
    818   },
    819   // Valid for a little while.
    820   { "HTTP/1.1 200 OK\n"
    821     "cache-control: max-age=10000\n"
    822     "\n",
    823     false
    824   },
    825   // Expires in the future.
    826   { "HTTP/1.1 200 OK\n"
    827     "date: Wed, 28 Nov 2007 00:40:11 GMT\n"
    828     "expires: Wed, 28 Nov 2007 01:00:00 GMT\n"
    829     "\n",
    830     false
    831   },
    832   // Already expired.
    833   { "HTTP/1.1 200 OK\n"
    834     "date: Wed, 28 Nov 2007 00:40:11 GMT\n"
    835     "expires: Wed, 28 Nov 2007 00:00:00 GMT\n"
    836     "\n",
    837     true
    838   },
    839   // Max-age trumps expires.
    840   { "HTTP/1.1 200 OK\n"
    841     "date: Wed, 28 Nov 2007 00:40:11 GMT\n"
    842     "expires: Wed, 28 Nov 2007 00:00:00 GMT\n"
    843     "cache-control: max-age=10000\n"
    844     "\n",
    845     false
    846   },
    847   // Last-modified heuristic: modified a while ago.
    848   { "HTTP/1.1 200 OK\n"
    849     "date: Wed, 28 Nov 2007 00:40:11 GMT\n"
    850     "last-modified: Wed, 27 Nov 2007 08:00:00 GMT\n"
    851     "\n",
    852     false
    853   },
    854   { "HTTP/1.1 203 Non-Authoritative Information\n"
    855     "date: Wed, 28 Nov 2007 00:40:11 GMT\n"
    856     "last-modified: Wed, 27 Nov 2007 08:00:00 GMT\n"
    857     "\n",
    858     false
    859   },
    860   { "HTTP/1.1 206 Partial Content\n"
    861     "date: Wed, 28 Nov 2007 00:40:11 GMT\n"
    862     "last-modified: Wed, 27 Nov 2007 08:00:00 GMT\n"
    863     "\n",
    864     false
    865   },
    866   // Last-modified heuristic: modified recently.
    867   { "HTTP/1.1 200 OK\n"
    868     "date: Wed, 28 Nov 2007 00:40:11 GMT\n"
    869     "last-modified: Wed, 28 Nov 2007 00:40:10 GMT\n"
    870     "\n",
    871     true
    872   },
    873   { "HTTP/1.1 203 Non-Authoritative Information\n"
    874     "date: Wed, 28 Nov 2007 00:40:11 GMT\n"
    875     "last-modified: Wed, 28 Nov 2007 00:40:10 GMT\n"
    876     "\n",
    877     true
    878   },
    879   { "HTTP/1.1 206 Partial Content\n"
    880   "date: Wed, 28 Nov 2007 00:40:11 GMT\n"
    881     "last-modified: Wed, 28 Nov 2007 00:40:10 GMT\n"
    882     "\n",
    883     true
    884   },
    885   // Cached permanent redirect.
    886   { "HTTP/1.1 301 Moved Permanently\n"
    887     "\n",
    888     false
    889   },
    890   // Another cached permanent redirect.
    891   { "HTTP/1.1 308 Permanent Redirect\n"
    892     "\n",
    893     false
    894   },
    895   // Cached redirect: not reusable even though by default it would be.
    896   { "HTTP/1.1 300 Multiple Choices\n"
    897     "Cache-Control: no-cache\n"
    898     "\n",
    899     true
    900   },
    901   // Cached forever by default.
    902   { "HTTP/1.1 410 Gone\n"
    903     "\n",
    904     false
    905   },
    906   // Cached temporary redirect: not reusable.
    907   { "HTTP/1.1 302 Found\n"
    908     "\n",
    909     true
    910   },
    911   // Cached temporary redirect: reusable.
    912   { "HTTP/1.1 302 Found\n"
    913     "cache-control: max-age=10000\n"
    914     "\n",
    915     false
    916   },
    917   // Cache-control: max-age=N overrides expires: date in the past.
    918   { "HTTP/1.1 200 OK\n"
    919     "date: Wed, 28 Nov 2007 00:40:11 GMT\n"
    920     "expires: Wed, 28 Nov 2007 00:20:11 GMT\n"
    921     "cache-control: max-age=10000\n"
    922     "\n",
    923     false
    924   },
    925   // Cache-control: no-store overrides expires: in the future.
    926   { "HTTP/1.1 200 OK\n"
    927     "date: Wed, 28 Nov 2007 00:40:11 GMT\n"
    928     "expires: Wed, 29 Nov 2007 00:40:11 GMT\n"
    929     "cache-control: no-store,private,no-cache=\"foo\"\n"
    930     "\n",
    931     true
    932   },
    933   // Pragma: no-cache overrides last-modified heuristic.
    934   { "HTTP/1.1 200 OK\n"
    935     "date: Wed, 28 Nov 2007 00:40:11 GMT\n"
    936     "last-modified: Wed, 27 Nov 2007 08:00:00 GMT\n"
    937     "pragma: no-cache\n"
    938     "\n",
    939     true
    940   },
    941 
    942   // TODO(darin): Add many many more tests here.
    943 };
    944 
    945 INSTANTIATE_TEST_CASE_P(HttpResponseHeaders,
    946                         RequiresValidationTest,
    947                         testing::ValuesIn(requires_validation_tests));
    948 
    949 struct UpdateTestData {
    950   const char* orig_headers;
    951   const char* new_headers;
    952   const char* expected_headers;
    953 };
    954 
    955 class UpdateTest
    956     : public HttpResponseHeadersTest,
    957       public ::testing::WithParamInterface<UpdateTestData> {
    958 };
    959 
    960 TEST_P(UpdateTest, Update) {
    961   const UpdateTestData test = GetParam();
    962 
    963   std::string orig_headers(test.orig_headers);
    964   HeadersToRaw(&orig_headers);
    965   scoped_refptr<net::HttpResponseHeaders> parsed(
    966       new net::HttpResponseHeaders(orig_headers));
    967 
    968   std::string new_headers(test.new_headers);
    969   HeadersToRaw(&new_headers);
    970   scoped_refptr<net::HttpResponseHeaders> new_parsed(
    971       new net::HttpResponseHeaders(new_headers));
    972 
    973   parsed->Update(*new_parsed.get());
    974 
    975   std::string resulting_headers;
    976   parsed->GetNormalizedHeaders(&resulting_headers);
    977   EXPECT_EQ(std::string(test.expected_headers), resulting_headers);
    978 }
    979 
    980 const UpdateTestData update_tests[] = {
    981   { "HTTP/1.1 200 OK\n",
    982 
    983     "HTTP/1/1 304 Not Modified\n"
    984     "connection: keep-alive\n"
    985     "Cache-control: max-age=10000\n",
    986 
    987     "HTTP/1.1 200 OK\n"
    988     "Cache-control: max-age=10000\n"
    989   },
    990   { "HTTP/1.1 200 OK\n"
    991     "Foo: 1\n"
    992     "Cache-control: private\n",
    993 
    994     "HTTP/1/1 304 Not Modified\n"
    995     "connection: keep-alive\n"
    996     "Cache-control: max-age=10000\n",
    997 
    998     "HTTP/1.1 200 OK\n"
    999     "Cache-control: max-age=10000\n"
   1000     "Foo: 1\n"
   1001   },
   1002   { "HTTP/1.1 200 OK\n"
   1003     "Foo: 1\n"
   1004     "Cache-control: private\n",
   1005 
   1006     "HTTP/1/1 304 Not Modified\n"
   1007     "connection: keep-alive\n"
   1008     "Cache-CONTROL: max-age=10000\n",
   1009 
   1010     "HTTP/1.1 200 OK\n"
   1011     "Cache-CONTROL: max-age=10000\n"
   1012     "Foo: 1\n"
   1013   },
   1014   { "HTTP/1.1 200 OK\n"
   1015     "Content-Length: 450\n",
   1016 
   1017     "HTTP/1/1 304 Not Modified\n"
   1018     "connection: keep-alive\n"
   1019     "Cache-control:      max-age=10001   \n",
   1020 
   1021     "HTTP/1.1 200 OK\n"
   1022     "Cache-control: max-age=10001\n"
   1023     "Content-Length: 450\n"
   1024   },
   1025   { "HTTP/1.1 200 OK\n"
   1026     "X-Frame-Options: DENY\n",
   1027 
   1028     "HTTP/1/1 304 Not Modified\n"
   1029     "X-Frame-Options: ALLOW\n",
   1030 
   1031     "HTTP/1.1 200 OK\n"
   1032     "X-Frame-Options: DENY\n",
   1033   },
   1034   { "HTTP/1.1 200 OK\n"
   1035     "X-WebKit-CSP: default-src 'none'\n",
   1036 
   1037     "HTTP/1/1 304 Not Modified\n"
   1038     "X-WebKit-CSP: default-src *\n",
   1039 
   1040     "HTTP/1.1 200 OK\n"
   1041     "X-WebKit-CSP: default-src 'none'\n",
   1042   },
   1043   { "HTTP/1.1 200 OK\n"
   1044     "X-XSS-Protection: 1\n",
   1045 
   1046     "HTTP/1/1 304 Not Modified\n"
   1047     "X-XSS-Protection: 0\n",
   1048 
   1049     "HTTP/1.1 200 OK\n"
   1050     "X-XSS-Protection: 1\n",
   1051   },
   1052   { "HTTP/1.1 200 OK\n",
   1053 
   1054     "HTTP/1/1 304 Not Modified\n"
   1055     "X-Content-Type-Options: nosniff\n",
   1056 
   1057     "HTTP/1.1 200 OK\n"
   1058   },
   1059 };
   1060 
   1061 INSTANTIATE_TEST_CASE_P(HttpResponseHeaders,
   1062                         UpdateTest,
   1063                         testing::ValuesIn(update_tests));
   1064 
   1065 struct EnumerateHeaderTestData {
   1066   const char* headers;
   1067   const char* expected_lines;
   1068 };
   1069 
   1070 class EnumerateHeaderLinesTest
   1071     : public HttpResponseHeadersTest,
   1072       public ::testing::WithParamInterface<EnumerateHeaderTestData> {
   1073 };
   1074 
   1075 TEST_P(EnumerateHeaderLinesTest, EnumerateHeaderLines) {
   1076   const EnumerateHeaderTestData test = GetParam();
   1077 
   1078   std::string headers(test.headers);
   1079   HeadersToRaw(&headers);
   1080   scoped_refptr<net::HttpResponseHeaders> parsed(
   1081       new net::HttpResponseHeaders(headers));
   1082 
   1083   std::string name, value, lines;
   1084 
   1085   void* iter = NULL;
   1086   while (parsed->EnumerateHeaderLines(&iter, &name, &value)) {
   1087     lines.append(name);
   1088     lines.append(": ");
   1089     lines.append(value);
   1090     lines.append("\n");
   1091   }
   1092 
   1093   EXPECT_EQ(std::string(test.expected_lines), lines);
   1094 }
   1095 
   1096 const EnumerateHeaderTestData enumerate_header_tests[] = {
   1097   { "HTTP/1.1 200 OK\n",
   1098 
   1099     ""
   1100   },
   1101   { "HTTP/1.1 200 OK\n"
   1102     "Foo: 1\n",
   1103 
   1104     "Foo: 1\n"
   1105   },
   1106   { "HTTP/1.1 200 OK\n"
   1107     "Foo: 1\n"
   1108     "Bar: 2\n"
   1109     "Foo: 3\n",
   1110 
   1111     "Foo: 1\nBar: 2\nFoo: 3\n"
   1112   },
   1113   { "HTTP/1.1 200 OK\n"
   1114     "Foo: 1, 2, 3\n",
   1115 
   1116     "Foo: 1, 2, 3\n"
   1117   },
   1118 };
   1119 
   1120 INSTANTIATE_TEST_CASE_P(HttpResponseHeaders,
   1121                         EnumerateHeaderLinesTest,
   1122                         testing::ValuesIn(enumerate_header_tests));
   1123 
   1124 struct IsRedirectTestData {
   1125   const char* headers;
   1126   const char* location;
   1127   bool is_redirect;
   1128 };
   1129 
   1130 class IsRedirectTest
   1131     : public HttpResponseHeadersTest,
   1132       public ::testing::WithParamInterface<IsRedirectTestData> {
   1133 };
   1134 
   1135 TEST_P(IsRedirectTest, IsRedirect) {
   1136   const IsRedirectTestData test = GetParam();
   1137 
   1138   std::string headers(test.headers);
   1139   HeadersToRaw(&headers);
   1140   scoped_refptr<net::HttpResponseHeaders> parsed(
   1141       new net::HttpResponseHeaders(headers));
   1142 
   1143   std::string location;
   1144   EXPECT_EQ(parsed->IsRedirect(&location), test.is_redirect);
   1145   EXPECT_EQ(location, test.location);
   1146 }
   1147 
   1148 const IsRedirectTestData is_redirect_tests[] = {
   1149   { "HTTP/1.1 200 OK\n",
   1150     "",
   1151     false
   1152   },
   1153   { "HTTP/1.1 301 Moved\n"
   1154     "Location: http://foopy/\n",
   1155     "http://foopy/",
   1156     true
   1157   },
   1158   { "HTTP/1.1 301 Moved\n"
   1159     "Location: \t \n",
   1160     "",
   1161     false
   1162   },
   1163   // We use the first location header as the target of the redirect.
   1164   { "HTTP/1.1 301 Moved\n"
   1165     "Location: http://foo/\n"
   1166     "Location: http://bar/\n",
   1167     "http://foo/",
   1168     true
   1169   },
   1170   // We use the first _valid_ location header as the target of the redirect.
   1171   { "HTTP/1.1 301 Moved\n"
   1172     "Location: \n"
   1173     "Location: http://bar/\n",
   1174     "http://bar/",
   1175     true
   1176   },
   1177   // Bug 1050541 (location header with an unescaped comma).
   1178   { "HTTP/1.1 301 Moved\n"
   1179     "Location: http://foo/bar,baz.html\n",
   1180     "http://foo/bar,baz.html",
   1181     true
   1182   },
   1183   // Bug 1224617 (location header with non-ASCII bytes).
   1184   { "HTTP/1.1 301 Moved\n"
   1185     "Location: http://foo/bar?key=\xE4\xF6\xFC\n",
   1186     "http://foo/bar?key=%E4%F6%FC",
   1187     true
   1188   },
   1189   // Shift_JIS, Big5, and GBK contain multibyte characters with the trailing
   1190   // byte falling in the ASCII range.
   1191   { "HTTP/1.1 301 Moved\n"
   1192     "Location: http://foo/bar?key=\x81\x5E\xD8\xBF\n",
   1193     "http://foo/bar?key=%81^%D8%BF",
   1194     true
   1195   },
   1196   { "HTTP/1.1 301 Moved\n"
   1197     "Location: http://foo/bar?key=\x82\x40\xBD\xC4\n",
   1198     "http://foo/bar?key=%82@%BD%C4",
   1199     true
   1200   },
   1201   { "HTTP/1.1 301 Moved\n"
   1202     "Location: http://foo/bar?key=\x83\x5C\x82\x5D\xCB\xD7\n",
   1203     "http://foo/bar?key=%83\\%82]%CB%D7",
   1204     true
   1205   },
   1206 };
   1207 
   1208 INSTANTIATE_TEST_CASE_P(HttpResponseHeaders,
   1209                         IsRedirectTest,
   1210                         testing::ValuesIn(is_redirect_tests));
   1211 
   1212 struct ContentLengthTestData {
   1213   const char* headers;
   1214   int64 expected_len;
   1215 };
   1216 
   1217 class GetContentLengthTest
   1218     : public HttpResponseHeadersTest,
   1219       public ::testing::WithParamInterface<ContentLengthTestData> {
   1220 };
   1221 
   1222 TEST_P(GetContentLengthTest, GetContentLength) {
   1223   const ContentLengthTestData test = GetParam();
   1224 
   1225   std::string headers(test.headers);
   1226   HeadersToRaw(&headers);
   1227   scoped_refptr<net::HttpResponseHeaders> parsed(
   1228       new net::HttpResponseHeaders(headers));
   1229 
   1230   EXPECT_EQ(test.expected_len, parsed->GetContentLength());
   1231 }
   1232 
   1233 const ContentLengthTestData content_length_tests[] = {
   1234   { "HTTP/1.1 200 OK\n",
   1235     -1
   1236   },
   1237   { "HTTP/1.1 200 OK\n"
   1238     "Content-Length: 10\n",
   1239     10
   1240   },
   1241   { "HTTP/1.1 200 OK\n"
   1242     "Content-Length: \n",
   1243     -1
   1244   },
   1245   { "HTTP/1.1 200 OK\n"
   1246     "Content-Length: abc\n",
   1247     -1
   1248   },
   1249   { "HTTP/1.1 200 OK\n"
   1250     "Content-Length: -10\n",
   1251     -1
   1252   },
   1253   { "HTTP/1.1 200 OK\n"
   1254     "Content-Length:  +10\n",
   1255     -1
   1256   },
   1257   { "HTTP/1.1 200 OK\n"
   1258     "Content-Length: 23xb5\n",
   1259     -1
   1260   },
   1261   { "HTTP/1.1 200 OK\n"
   1262     "Content-Length: 0xA\n",
   1263     -1
   1264   },
   1265   { "HTTP/1.1 200 OK\n"
   1266     "Content-Length: 010\n",
   1267     10
   1268   },
   1269   // Content-Length too big, will overflow an int64.
   1270   { "HTTP/1.1 200 OK\n"
   1271     "Content-Length: 40000000000000000000\n",
   1272     -1
   1273   },
   1274   { "HTTP/1.1 200 OK\n"
   1275     "Content-Length:       10\n",
   1276     10
   1277   },
   1278   { "HTTP/1.1 200 OK\n"
   1279     "Content-Length: 10  \n",
   1280     10
   1281   },
   1282   { "HTTP/1.1 200 OK\n"
   1283     "Content-Length: \t10\n",
   1284     10
   1285   },
   1286   { "HTTP/1.1 200 OK\n"
   1287     "Content-Length: \v10\n",
   1288     -1
   1289   },
   1290   { "HTTP/1.1 200 OK\n"
   1291     "Content-Length: \f10\n",
   1292     -1
   1293   },
   1294   { "HTTP/1.1 200 OK\n"
   1295     "cOnTeNt-LENgth: 33\n",
   1296     33
   1297   },
   1298   { "HTTP/1.1 200 OK\n"
   1299     "Content-Length: 34\r\n",
   1300     -1
   1301   },
   1302 };
   1303 
   1304 INSTANTIATE_TEST_CASE_P(HttpResponseHeaders,
   1305                         GetContentLengthTest,
   1306                         testing::ValuesIn(content_length_tests));
   1307 
   1308 struct ContentRangeTestData {
   1309   const char* headers;
   1310   bool expected_return_value;
   1311   int64 expected_first_byte_position;
   1312   int64 expected_last_byte_position;
   1313   int64 expected_instance_size;
   1314 };
   1315 
   1316 class ContentRangeTest
   1317     : public HttpResponseHeadersTest,
   1318       public ::testing::WithParamInterface<ContentRangeTestData> {
   1319 };
   1320 
   1321 TEST_P(ContentRangeTest, GetContentRange) {
   1322   const ContentRangeTestData test = GetParam();
   1323 
   1324   std::string headers(test.headers);
   1325   HeadersToRaw(&headers);
   1326   scoped_refptr<net::HttpResponseHeaders> parsed(
   1327       new net::HttpResponseHeaders(headers));
   1328 
   1329   int64 first_byte_position;
   1330   int64 last_byte_position;
   1331   int64 instance_size;
   1332   bool return_value = parsed->GetContentRange(&first_byte_position,
   1333                                               &last_byte_position,
   1334                                               &instance_size);
   1335   EXPECT_EQ(test.expected_return_value, return_value);
   1336   EXPECT_EQ(test.expected_first_byte_position, first_byte_position);
   1337   EXPECT_EQ(test.expected_last_byte_position, last_byte_position);
   1338   EXPECT_EQ(test.expected_instance_size, instance_size);
   1339 }
   1340 
   1341 const ContentRangeTestData content_range_tests[] = {
   1342   { "HTTP/1.1 206 Partial Content",
   1343     false,
   1344     -1,
   1345     -1,
   1346     -1
   1347   },
   1348   { "HTTP/1.1 206 Partial Content\n"
   1349     "Content-Range:",
   1350     false,
   1351     -1,
   1352     -1,
   1353     -1
   1354   },
   1355   { "HTTP/1.1 206 Partial Content\n"
   1356     "Content-Range: megabytes 0-10/50",
   1357     false,
   1358     -1,
   1359     -1,
   1360     -1
   1361   },
   1362   { "HTTP/1.1 206 Partial Content\n"
   1363     "Content-Range: 0-10/50",
   1364     false,
   1365     -1,
   1366     -1,
   1367     -1
   1368   },
   1369   { "HTTP/1.1 206 Partial Content\n"
   1370     "Content-Range: Bytes 0-50/51",
   1371     true,
   1372     0,
   1373     50,
   1374     51
   1375   },
   1376   { "HTTP/1.1 206 Partial Content\n"
   1377     "Content-Range: bytes 0-50/51",
   1378     true,
   1379     0,
   1380     50,
   1381     51
   1382   },
   1383   { "HTTP/1.1 206 Partial Content\n"
   1384     "Content-Range: bytes\t0-50/51",
   1385     false,
   1386     -1,
   1387     -1,
   1388     -1
   1389   },
   1390   { "HTTP/1.1 206 Partial Content\n"
   1391     "Content-Range:     bytes 0-50/51",
   1392     true,
   1393     0,
   1394     50,
   1395     51
   1396   },
   1397   { "HTTP/1.1 206 Partial Content\n"
   1398     "Content-Range:     bytes    0    -   50  \t / \t51",
   1399     true,
   1400     0,
   1401     50,
   1402     51
   1403   },
   1404   { "HTTP/1.1 206 Partial Content\n"
   1405     "Content-Range: bytes 0\t-\t50\t/\t51\t",
   1406     true,
   1407     0,
   1408     50,
   1409     51
   1410   },
   1411   { "HTTP/1.1 206 Partial Content\n"
   1412     "Content-Range:   \tbytes\t\t\t 0\t-\t50\t/\t51\t",
   1413     true,
   1414     0,
   1415     50,
   1416     51
   1417   },
   1418   { "HTTP/1.1 206 Partial Content\n"
   1419     "Content-Range: \t   bytes \t  0    -   50   /   5   1",
   1420     false,
   1421     0,
   1422     50,
   1423     -1
   1424   },
   1425   { "HTTP/1.1 206 Partial Content\n"
   1426     "Content-Range: \t   bytes \t  0    -   5 0   /   51",
   1427     false,
   1428     -1,
   1429     -1,
   1430     -1
   1431   },
   1432   { "HTTP/1.1 206 Partial Content\n"
   1433     "Content-Range: bytes 50-0/51",
   1434     false,
   1435     50,
   1436     0,
   1437     -1
   1438   },
   1439   { "HTTP/1.1 416 Requested range not satisfiable\n"
   1440     "Content-Range: bytes * /*",
   1441     false,
   1442     -1,
   1443     -1,
   1444     -1
   1445   },
   1446   { "HTTP/1.1 416 Requested range not satisfiable\n"
   1447     "Content-Range: bytes *   /    *   ",
   1448     false,
   1449     -1,
   1450     -1,
   1451     -1
   1452   },
   1453   { "HTTP/1.1 206 Partial Content\n"
   1454     "Content-Range: bytes 0-50/*",
   1455     false,
   1456     0,
   1457     50,
   1458     -1
   1459   },
   1460   { "HTTP/1.1 206 Partial Content\n"
   1461     "Content-Range: bytes 0-50  /    * ",
   1462     false,
   1463     0,
   1464     50,
   1465     -1
   1466   },
   1467   { "HTTP/1.1 206 Partial Content\n"
   1468     "Content-Range: bytes 0-10000000000/10000000001",
   1469     true,
   1470     0,
   1471     10000000000ll,
   1472     10000000001ll
   1473   },
   1474   { "HTTP/1.1 206 Partial Content\n"
   1475     "Content-Range: bytes 0-10000000000/10000000000",
   1476     false,
   1477     0,
   1478     10000000000ll,
   1479     10000000000ll
   1480   },
   1481   // 64 bit wraparound.
   1482   { "HTTP/1.1 206 Partial Content\n"
   1483     "Content-Range: bytes 0 - 9223372036854775807 / 100",
   1484     false,
   1485     0,
   1486     kint64max,
   1487     100
   1488   },
   1489   // 64 bit wraparound.
   1490   { "HTTP/1.1 206 Partial Content\n"
   1491     "Content-Range: bytes 0 - 100 / -9223372036854775808",
   1492     false,
   1493     0,
   1494     100,
   1495     kint64min
   1496   },
   1497   { "HTTP/1.1 206 Partial Content\n"
   1498     "Content-Range: bytes */50",
   1499     false,
   1500     -1,
   1501     -1,
   1502     50
   1503   },
   1504   { "HTTP/1.1 206 Partial Content\n"
   1505     "Content-Range: bytes 0-50/10",
   1506     false,
   1507     0,
   1508     50,
   1509     10
   1510   },
   1511   { "HTTP/1.1 206 Partial Content\n"
   1512     "Content-Range: bytes 40-50/45",
   1513     false,
   1514     40,
   1515     50,
   1516     45
   1517   },
   1518   { "HTTP/1.1 206 Partial Content\n"
   1519     "Content-Range: bytes 0-50/-10",
   1520     false,
   1521     0,
   1522     50,
   1523     -10
   1524   },
   1525   { "HTTP/1.1 206 Partial Content\n"
   1526     "Content-Range: bytes 0-0/1",
   1527     true,
   1528     0,
   1529     0,
   1530     1
   1531   },
   1532   { "HTTP/1.1 206 Partial Content\n"
   1533     "Content-Range: bytes 0-40000000000000000000/40000000000000000001",
   1534     false,
   1535     -1,
   1536     -1,
   1537     -1
   1538   },
   1539   { "HTTP/1.1 206 Partial Content\n"
   1540     "Content-Range: bytes 1-/100",
   1541     false,
   1542     -1,
   1543     -1,
   1544     -1
   1545   },
   1546   { "HTTP/1.1 206 Partial Content\n"
   1547     "Content-Range: bytes -/100",
   1548     false,
   1549     -1,
   1550     -1,
   1551     -1
   1552   },
   1553   { "HTTP/1.1 206 Partial Content\n"
   1554     "Content-Range: bytes -1/100",
   1555     false,
   1556     -1,
   1557     -1,
   1558     -1
   1559   },
   1560   { "HTTP/1.1 206 Partial Content\n"
   1561     "Content-Range: bytes 0-1233/*",
   1562     false,
   1563     0,
   1564     1233,
   1565     -1
   1566   },
   1567   { "HTTP/1.1 206 Partial Content\n"
   1568     "Content-Range: bytes -123 - -1/100",
   1569     false,
   1570     -1,
   1571     -1,
   1572     -1
   1573   },
   1574 };
   1575 
   1576 INSTANTIATE_TEST_CASE_P(HttpResponseHeaders,
   1577                         ContentRangeTest,
   1578                         testing::ValuesIn(content_range_tests));
   1579 
   1580 struct KeepAliveTestData {
   1581   const char* headers;
   1582   bool expected_keep_alive;
   1583 };
   1584 
   1585 class IsKeepAliveTest
   1586     : public HttpResponseHeadersTest,
   1587       public ::testing::WithParamInterface<KeepAliveTestData> {
   1588 };
   1589 
   1590 TEST_P(IsKeepAliveTest, IsKeepAlive) {
   1591   const KeepAliveTestData test = GetParam();
   1592 
   1593   std::string headers(test.headers);
   1594   HeadersToRaw(&headers);
   1595   scoped_refptr<net::HttpResponseHeaders> parsed(
   1596       new net::HttpResponseHeaders(headers));
   1597 
   1598   EXPECT_EQ(test.expected_keep_alive, parsed->IsKeepAlive());
   1599 }
   1600 
   1601 const KeepAliveTestData keepalive_tests[] = {
   1602   // The status line fabricated by HttpNetworkTransaction for a 0.9 response.
   1603   // Treated as 0.9.
   1604   { "HTTP/0.9 200 OK",
   1605     false
   1606   },
   1607   // This could come from a broken server.  Treated as 1.0 because it has a
   1608   // header.
   1609   { "HTTP/0.9 200 OK\n"
   1610     "connection: keep-alive\n",
   1611     true
   1612   },
   1613   { "HTTP/1.1 200 OK\n",
   1614     true
   1615   },
   1616   { "HTTP/1.0 200 OK\n",
   1617     false
   1618   },
   1619   { "HTTP/1.0 200 OK\n"
   1620     "connection: close\n",
   1621     false
   1622   },
   1623   { "HTTP/1.0 200 OK\n"
   1624     "connection: keep-alive\n",
   1625     true
   1626   },
   1627   { "HTTP/1.0 200 OK\n"
   1628     "connection: kEeP-AliVe\n",
   1629     true
   1630   },
   1631   { "HTTP/1.0 200 OK\n"
   1632     "connection: keep-aliveX\n",
   1633     false
   1634   },
   1635   { "HTTP/1.1 200 OK\n"
   1636     "connection: close\n",
   1637     false
   1638   },
   1639   { "HTTP/1.1 200 OK\n"
   1640     "connection: keep-alive\n",
   1641     true
   1642   },
   1643   { "HTTP/1.0 200 OK\n"
   1644     "proxy-connection: close\n",
   1645     false
   1646   },
   1647   { "HTTP/1.0 200 OK\n"
   1648     "proxy-connection: keep-alive\n",
   1649     true
   1650   },
   1651   { "HTTP/1.1 200 OK\n"
   1652     "proxy-connection: close\n",
   1653     false
   1654   },
   1655   { "HTTP/1.1 200 OK\n"
   1656     "proxy-connection: keep-alive\n",
   1657     true
   1658   },
   1659 };
   1660 
   1661 INSTANTIATE_TEST_CASE_P(HttpResponseHeaders,
   1662                         IsKeepAliveTest,
   1663                         testing::ValuesIn(keepalive_tests));
   1664 
   1665 struct HasStrongValidatorsTestData {
   1666   const char* headers;
   1667   bool expected_result;
   1668 };
   1669 
   1670 class HasStrongValidatorsTest
   1671     : public HttpResponseHeadersTest,
   1672       public ::testing::WithParamInterface<HasStrongValidatorsTestData> {
   1673 };
   1674 
   1675 TEST_P(HasStrongValidatorsTest, HasStrongValidators) {
   1676   const HasStrongValidatorsTestData test = GetParam();
   1677 
   1678   std::string headers(test.headers);
   1679   HeadersToRaw(&headers);
   1680   scoped_refptr<net::HttpResponseHeaders> parsed(
   1681       new net::HttpResponseHeaders(headers));
   1682 
   1683   EXPECT_EQ(test.expected_result, parsed->HasStrongValidators());
   1684 }
   1685 
   1686 const HasStrongValidatorsTestData strong_validators_tests[] = {
   1687   { "HTTP/0.9 200 OK",
   1688     false
   1689   },
   1690   { "HTTP/1.0 200 OK\n"
   1691     "Date: Wed, 28 Nov 2007 01:40:10 GMT\n"
   1692     "Last-Modified: Wed, 28 Nov 2007 00:40:10 GMT\n"
   1693     "ETag: \"foo\"\n",
   1694     false
   1695   },
   1696   { "HTTP/1.1 200 OK\n"
   1697     "Date: Wed, 28 Nov 2007 01:40:10 GMT\n"
   1698     "Last-Modified: Wed, 28 Nov 2007 00:40:10 GMT\n"
   1699     "ETag: \"foo\"\n",
   1700     true
   1701   },
   1702   { "HTTP/1.1 200 OK\n"
   1703     "Date: Wed, 28 Nov 2007 00:41:10 GMT\n"
   1704     "Last-Modified: Wed, 28 Nov 2007 00:40:10 GMT\n",
   1705     true
   1706   },
   1707   { "HTTP/1.1 200 OK\n"
   1708     "Date: Wed, 28 Nov 2007 00:41:09 GMT\n"
   1709     "Last-Modified: Wed, 28 Nov 2007 00:40:10 GMT\n",
   1710     false
   1711   },
   1712   { "HTTP/1.1 200 OK\n"
   1713     "ETag: \"foo\"\n",
   1714     true
   1715   },
   1716   // This is not really a weak etag:
   1717   { "HTTP/1.1 200 OK\n"
   1718     "etag: \"w/foo\"\n",
   1719     true
   1720   },
   1721   // This is a weak etag:
   1722   { "HTTP/1.1 200 OK\n"
   1723     "etag: w/\"foo\"\n",
   1724     false
   1725   },
   1726   { "HTTP/1.1 200 OK\n"
   1727     "etag:    W  /   \"foo\"\n",
   1728     false
   1729   }
   1730 };
   1731 
   1732 INSTANTIATE_TEST_CASE_P(HttpResponseHeaders,
   1733                         HasStrongValidatorsTest,
   1734                         testing::ValuesIn(strong_validators_tests));
   1735 
   1736 TEST(HttpResponseHeadersTest, GetStatusText) {
   1737   std::string headers("HTTP/1.1 404 Not Found");
   1738   HeadersToRaw(&headers);
   1739     scoped_refptr<net::HttpResponseHeaders> parsed(
   1740         new net::HttpResponseHeaders(headers));
   1741   EXPECT_EQ(std::string("Not Found"), parsed->GetStatusText());
   1742 }
   1743 
   1744 TEST(HttpResponseHeadersTest, GetStatusTextMissing) {
   1745   std::string headers("HTTP/1.1 404");
   1746   HeadersToRaw(&headers);
   1747     scoped_refptr<net::HttpResponseHeaders> parsed(
   1748         new net::HttpResponseHeaders(headers));
   1749   // Since the status line gets normalized, we have OK.
   1750   EXPECT_EQ(std::string("OK"), parsed->GetStatusText());
   1751 }
   1752 
   1753 TEST(HttpResponseHeadersTest, GetStatusTextMultiSpace) {
   1754   std::string headers("HTTP/1.0     404     Not   Found");
   1755   HeadersToRaw(&headers);
   1756     scoped_refptr<net::HttpResponseHeaders> parsed(
   1757         new net::HttpResponseHeaders(headers));
   1758   EXPECT_EQ(std::string("Not   Found"), parsed->GetStatusText());
   1759 }
   1760 
   1761 TEST(HttpResponseHeadersTest, GetStatusBadStatusLine) {
   1762   std::string headers("Foo bar.");
   1763   HeadersToRaw(&headers);
   1764     scoped_refptr<net::HttpResponseHeaders> parsed(
   1765         new net::HttpResponseHeaders(headers));
   1766   // The bad status line would have gotten rewritten as
   1767   // HTTP/1.0 200 OK.
   1768   EXPECT_EQ(std::string("OK"), parsed->GetStatusText());
   1769 }
   1770 
   1771 struct AddHeaderTestData {
   1772   const char* orig_headers;
   1773   const char* new_header;
   1774   const char* expected_headers;
   1775 };
   1776 
   1777 class AddHeaderTest
   1778     : public HttpResponseHeadersTest,
   1779       public ::testing::WithParamInterface<AddHeaderTestData> {
   1780 };
   1781 
   1782 TEST_P(AddHeaderTest, AddHeader) {
   1783   const AddHeaderTestData test = GetParam();
   1784 
   1785   std::string orig_headers(test.orig_headers);
   1786   HeadersToRaw(&orig_headers);
   1787   scoped_refptr<net::HttpResponseHeaders> parsed(
   1788       new net::HttpResponseHeaders(orig_headers));
   1789 
   1790   std::string new_header(test.new_header);
   1791   parsed->AddHeader(new_header);
   1792 
   1793   std::string resulting_headers;
   1794   parsed->GetNormalizedHeaders(&resulting_headers);
   1795   EXPECT_EQ(std::string(test.expected_headers), resulting_headers);
   1796 }
   1797 
   1798 const AddHeaderTestData add_header_tests[] = {
   1799   { "HTTP/1.1 200 OK\n"
   1800     "connection: keep-alive\n"
   1801     "Cache-control: max-age=10000\n",
   1802 
   1803     "Content-Length: 450",
   1804 
   1805     "HTTP/1.1 200 OK\n"
   1806     "connection: keep-alive\n"
   1807     "Cache-control: max-age=10000\n"
   1808     "Content-Length: 450\n"
   1809   },
   1810   { "HTTP/1.1 200 OK\n"
   1811     "connection: keep-alive\n"
   1812     "Cache-control: max-age=10000    \n",
   1813 
   1814     "Content-Length: 450  ",
   1815 
   1816     "HTTP/1.1 200 OK\n"
   1817     "connection: keep-alive\n"
   1818     "Cache-control: max-age=10000\n"
   1819     "Content-Length: 450\n"
   1820   },
   1821 };
   1822 
   1823 INSTANTIATE_TEST_CASE_P(HttpResponseHeaders,
   1824                         AddHeaderTest,
   1825                         testing::ValuesIn(add_header_tests));
   1826 
   1827 struct RemoveHeaderTestData {
   1828   const char* orig_headers;
   1829   const char* to_remove;
   1830   const char* expected_headers;
   1831 };
   1832 
   1833 class RemoveHeaderTest
   1834     : public HttpResponseHeadersTest,
   1835       public ::testing::WithParamInterface<RemoveHeaderTestData> {
   1836 };
   1837 
   1838 TEST_P(RemoveHeaderTest, RemoveHeader) {
   1839   const RemoveHeaderTestData test = GetParam();
   1840 
   1841   std::string orig_headers(test.orig_headers);
   1842   HeadersToRaw(&orig_headers);
   1843   scoped_refptr<net::HttpResponseHeaders> parsed(
   1844       new net::HttpResponseHeaders(orig_headers));
   1845 
   1846   std::string name(test.to_remove);
   1847   parsed->RemoveHeader(name);
   1848 
   1849   std::string resulting_headers;
   1850   parsed->GetNormalizedHeaders(&resulting_headers);
   1851   EXPECT_EQ(std::string(test.expected_headers), resulting_headers);
   1852 }
   1853 
   1854 const RemoveHeaderTestData remove_header_tests[] = {
   1855   { "HTTP/1.1 200 OK\n"
   1856     "connection: keep-alive\n"
   1857     "Cache-control: max-age=10000\n"
   1858     "Content-Length: 450\n",
   1859 
   1860     "Content-Length",
   1861 
   1862     "HTTP/1.1 200 OK\n"
   1863     "connection: keep-alive\n"
   1864     "Cache-control: max-age=10000\n"
   1865   },
   1866   { "HTTP/1.1 200 OK\n"
   1867     "connection: keep-alive  \n"
   1868     "Content-Length  : 450  \n"
   1869     "Cache-control: max-age=10000\n",
   1870 
   1871     "Content-Length",
   1872 
   1873     "HTTP/1.1 200 OK\n"
   1874     "connection: keep-alive\n"
   1875     "Cache-control: max-age=10000\n"
   1876   },
   1877 };
   1878 
   1879 INSTANTIATE_TEST_CASE_P(HttpResponseHeaders,
   1880                         RemoveHeaderTest,
   1881                         testing::ValuesIn(remove_header_tests));
   1882 
   1883 struct RemoveIndividualHeaderTestData {
   1884   const char* orig_headers;
   1885   const char* to_remove_name;
   1886   const char* to_remove_value;
   1887   const char* expected_headers;
   1888 };
   1889 
   1890 class RemoveIndividualHeaderTest
   1891     : public HttpResponseHeadersTest,
   1892       public ::testing::WithParamInterface<RemoveIndividualHeaderTestData> {
   1893 };
   1894 
   1895 TEST_P(RemoveIndividualHeaderTest, RemoveIndividualHeader) {
   1896   const RemoveIndividualHeaderTestData test = GetParam();
   1897 
   1898   std::string orig_headers(test.orig_headers);
   1899   HeadersToRaw(&orig_headers);
   1900   scoped_refptr<net::HttpResponseHeaders> parsed(
   1901       new net::HttpResponseHeaders(orig_headers));
   1902 
   1903   std::string name(test.to_remove_name);
   1904   std::string value(test.to_remove_value);
   1905   parsed->RemoveHeaderLine(name, value);
   1906 
   1907   std::string resulting_headers;
   1908   parsed->GetNormalizedHeaders(&resulting_headers);
   1909   EXPECT_EQ(std::string(test.expected_headers), resulting_headers);
   1910 }
   1911 
   1912 const RemoveIndividualHeaderTestData remove_individual_header_tests[] = {
   1913   { "HTTP/1.1 200 OK\n"
   1914     "connection: keep-alive\n"
   1915     "Cache-control: max-age=10000\n"
   1916     "Content-Length: 450\n",
   1917 
   1918     "Content-Length",
   1919 
   1920     "450",
   1921 
   1922     "HTTP/1.1 200 OK\n"
   1923     "connection: keep-alive\n"
   1924     "Cache-control: max-age=10000\n"
   1925   },
   1926   { "HTTP/1.1 200 OK\n"
   1927     "connection: keep-alive  \n"
   1928     "Content-Length  : 450  \n"
   1929     "Cache-control: max-age=10000\n",
   1930 
   1931     "Content-Length",
   1932 
   1933     "450",
   1934 
   1935     "HTTP/1.1 200 OK\n"
   1936     "connection: keep-alive\n"
   1937     "Cache-control: max-age=10000\n"
   1938   },
   1939   { "HTTP/1.1 200 OK\n"
   1940     "connection: keep-alive  \n"
   1941     "Content-Length: 450\n"
   1942     "Cache-control: max-age=10000\n",
   1943 
   1944     "Content-Length",  // Matching name.
   1945 
   1946     "999",  // Mismatching value.
   1947 
   1948     "HTTP/1.1 200 OK\n"
   1949     "connection: keep-alive\n"
   1950     "Content-Length: 450\n"
   1951     "Cache-control: max-age=10000\n"
   1952   },
   1953   { "HTTP/1.1 200 OK\n"
   1954     "connection: keep-alive  \n"
   1955     "Foo: bar, baz\n"
   1956     "Foo: bar\n"
   1957     "Cache-control: max-age=10000\n",
   1958 
   1959     "Foo",
   1960 
   1961     "bar, baz",  // Space in value.
   1962 
   1963     "HTTP/1.1 200 OK\n"
   1964     "connection: keep-alive\n"
   1965     "Foo: bar\n"
   1966     "Cache-control: max-age=10000\n"
   1967   },
   1968   { "HTTP/1.1 200 OK\n"
   1969     "connection: keep-alive  \n"
   1970     "Foo: bar, baz\n"
   1971     "Cache-control: max-age=10000\n",
   1972 
   1973     "Foo",
   1974 
   1975     "baz",  // Only partial match -> ignored.
   1976 
   1977     "HTTP/1.1 200 OK\n"
   1978     "connection: keep-alive\n"
   1979     "Foo: bar, baz\n"
   1980     "Cache-control: max-age=10000\n"
   1981   },
   1982 };
   1983 
   1984 INSTANTIATE_TEST_CASE_P(HttpResponseHeaders,
   1985                         RemoveIndividualHeaderTest,
   1986                         testing::ValuesIn(remove_individual_header_tests));
   1987 
   1988 struct ReplaceStatusTestData {
   1989   const char* orig_headers;
   1990   const char* new_status;
   1991   const char* expected_headers;
   1992 };
   1993 
   1994 class ReplaceStatusTest
   1995     : public HttpResponseHeadersTest,
   1996       public ::testing::WithParamInterface<ReplaceStatusTestData> {
   1997 };
   1998 
   1999 TEST_P(ReplaceStatusTest, ReplaceStatus) {
   2000   const ReplaceStatusTestData test = GetParam();
   2001 
   2002   std::string orig_headers(test.orig_headers);
   2003   HeadersToRaw(&orig_headers);
   2004   scoped_refptr<net::HttpResponseHeaders> parsed(
   2005       new net::HttpResponseHeaders(orig_headers));
   2006 
   2007   std::string name(test.new_status);
   2008   parsed->ReplaceStatusLine(name);
   2009 
   2010   std::string resulting_headers;
   2011   parsed->GetNormalizedHeaders(&resulting_headers);
   2012   EXPECT_EQ(std::string(test.expected_headers), resulting_headers);
   2013 }
   2014 
   2015 const ReplaceStatusTestData replace_status_tests[] = {
   2016   { "HTTP/1.1 206 Partial Content\n"
   2017     "connection: keep-alive\n"
   2018     "Cache-control: max-age=10000\n"
   2019     "Content-Length: 450\n",
   2020 
   2021     "HTTP/1.1 200 OK",
   2022 
   2023     "HTTP/1.1 200 OK\n"
   2024     "connection: keep-alive\n"
   2025     "Cache-control: max-age=10000\n"
   2026     "Content-Length: 450\n"
   2027   },
   2028   { "HTTP/1.1 200 OK\n"
   2029     "connection: keep-alive\n",
   2030 
   2031     "HTTP/1.1 304 Not Modified",
   2032 
   2033     "HTTP/1.1 304 Not Modified\n"
   2034     "connection: keep-alive\n"
   2035   },
   2036   { "HTTP/1.1 200 OK\n"
   2037     "connection: keep-alive  \n"
   2038     "Content-Length  : 450   \n"
   2039     "Cache-control: max-age=10000\n",
   2040 
   2041     "HTTP/1//1 304 Not Modified",
   2042 
   2043     "HTTP/1.0 304 Not Modified\n"
   2044     "connection: keep-alive\n"
   2045     "Content-Length: 450\n"
   2046     "Cache-control: max-age=10000\n"
   2047   },
   2048 };
   2049 
   2050 INSTANTIATE_TEST_CASE_P(HttpResponseHeaders,
   2051                         ReplaceStatusTest,
   2052                         testing::ValuesIn(replace_status_tests));
   2053 
   2054 struct UpdateWithNewRangeTestData {
   2055   const char* orig_headers;
   2056   const char* expected_headers;
   2057   const char* expected_headers_with_replaced_status;
   2058 };
   2059 
   2060 class UpdateWithNewRangeTest
   2061     : public HttpResponseHeadersTest,
   2062       public ::testing::WithParamInterface<UpdateWithNewRangeTestData> {
   2063 };
   2064 
   2065 TEST_P(UpdateWithNewRangeTest, UpdateWithNewRange) {
   2066   const UpdateWithNewRangeTestData test = GetParam();
   2067 
   2068   const net::HttpByteRange range = net::HttpByteRange::Bounded(3, 5);
   2069 
   2070   std::string orig_headers(test.orig_headers);
   2071   std::replace(orig_headers.begin(), orig_headers.end(), '\n', '\0');
   2072   scoped_refptr<net::HttpResponseHeaders> parsed(
   2073       new net::HttpResponseHeaders(orig_headers + '\0'));
   2074   int64 content_size = parsed->GetContentLength();
   2075   std::string resulting_headers;
   2076 
   2077   // Update headers without replacing status line.
   2078   parsed->UpdateWithNewRange(range, content_size, false);
   2079   parsed->GetNormalizedHeaders(&resulting_headers);
   2080   EXPECT_EQ(std::string(test.expected_headers), resulting_headers);
   2081 
   2082   // Replace status line too.
   2083   parsed->UpdateWithNewRange(range, content_size, true);
   2084   parsed->GetNormalizedHeaders(&resulting_headers);
   2085   EXPECT_EQ(std::string(test.expected_headers_with_replaced_status),
   2086             resulting_headers);
   2087 }
   2088 
   2089 const UpdateWithNewRangeTestData update_range_tests[] = {
   2090   { "HTTP/1.1 200 OK\n"
   2091     "Content-Length: 450\n",
   2092 
   2093     "HTTP/1.1 200 OK\n"
   2094     "Content-Range: bytes 3-5/450\n"
   2095     "Content-Length: 3\n",
   2096 
   2097     "HTTP/1.1 206 Partial Content\n"
   2098     "Content-Range: bytes 3-5/450\n"
   2099     "Content-Length: 3\n",
   2100   },
   2101   { "HTTP/1.1 200 OK\n"
   2102     "Content-Length: 5\n",
   2103 
   2104     "HTTP/1.1 200 OK\n"
   2105     "Content-Range: bytes 3-5/5\n"
   2106     "Content-Length: 3\n",
   2107 
   2108     "HTTP/1.1 206 Partial Content\n"
   2109     "Content-Range: bytes 3-5/5\n"
   2110     "Content-Length: 3\n",
   2111   },
   2112 };
   2113 
   2114 INSTANTIATE_TEST_CASE_P(HttpResponseHeaders,
   2115                         UpdateWithNewRangeTest,
   2116                         testing::ValuesIn(update_range_tests));
   2117 
   2118 TEST(HttpResponseHeadersTest, ToNetLogParamAndBackAgain) {
   2119   std::string headers("HTTP/1.1 404\n"
   2120                       "Content-Length: 450\n"
   2121                       "Connection: keep-alive\n");
   2122   HeadersToRaw(&headers);
   2123   scoped_refptr<net::HttpResponseHeaders> parsed(
   2124       new net::HttpResponseHeaders(headers));
   2125 
   2126   scoped_ptr<base::Value> event_param(
   2127       parsed->NetLogCallback(net::NetLog::LOG_ALL_BUT_BYTES));
   2128   scoped_refptr<net::HttpResponseHeaders> recreated;
   2129 
   2130   ASSERT_TRUE(net::HttpResponseHeaders::FromNetLogParam(event_param.get(),
   2131                                                         &recreated));
   2132   ASSERT_TRUE(recreated.get());
   2133   EXPECT_EQ(parsed->GetHttpVersion(), recreated->GetHttpVersion());
   2134   EXPECT_EQ(parsed->response_code(), recreated->response_code());
   2135   EXPECT_EQ(parsed->GetContentLength(), recreated->GetContentLength());
   2136   EXPECT_EQ(parsed->IsKeepAlive(), recreated->IsKeepAlive());
   2137 
   2138   std::string normalized_parsed;
   2139   parsed->GetNormalizedHeaders(&normalized_parsed);
   2140   std::string normalized_recreated;
   2141   parsed->GetNormalizedHeaders(&normalized_recreated);
   2142   EXPECT_EQ(normalized_parsed, normalized_recreated);
   2143 }
   2144 
   2145 TEST_F(HttpResponseHeadersCacheControlTest, AbsentMaxAgeReturnsFalse) {
   2146   InitializeHeadersWithCacheControl("nocache");
   2147   EXPECT_FALSE(headers()->GetMaxAgeValue(TimeDeltaPointer()));
   2148 }
   2149 
   2150 TEST_F(HttpResponseHeadersCacheControlTest, MaxAgeWithNoParameterRejected) {
   2151   InitializeHeadersWithCacheControl("max-age=,private");
   2152   EXPECT_FALSE(headers()->GetMaxAgeValue(TimeDeltaPointer()));
   2153 }
   2154 
   2155 TEST_F(HttpResponseHeadersCacheControlTest, MaxAgeWithSpaceParameterRejected) {
   2156   InitializeHeadersWithCacheControl("max-age= ,private");
   2157   EXPECT_FALSE(headers()->GetMaxAgeValue(TimeDeltaPointer()));
   2158 }
   2159 
   2160 TEST_F(HttpResponseHeadersCacheControlTest,
   2161        MaxAgeWithSpaceBeforeEqualsIsRejected) {
   2162   InitializeHeadersWithCacheControl("max-age = 7");
   2163   EXPECT_FALSE(headers()->GetMaxAgeValue(TimeDeltaPointer()));
   2164 }
   2165 
   2166 TEST_F(HttpResponseHeadersCacheControlTest, MaxAgeFirstMatchUsed) {
   2167   InitializeHeadersWithCacheControl("max-age=10, max-age=20");
   2168   EXPECT_EQ(TimeDelta::FromSeconds(10), GetMaxAgeValue());
   2169 }
   2170 
   2171 TEST_F(HttpResponseHeadersCacheControlTest, MaxAgeBogusFirstMatchUsed) {
   2172   // "max-age10" isn't parsed as "max-age"; "max-age=now" is parsed as
   2173   // "max-age=0" and so "max-age=20" is not used.
   2174   InitializeHeadersWithCacheControl("max-age10, max-age=now, max-age=20");
   2175   EXPECT_EQ(TimeDelta::FromSeconds(0), GetMaxAgeValue());
   2176 }
   2177 
   2178 TEST_F(HttpResponseHeadersCacheControlTest, MaxAgeCaseInsensitive) {
   2179   InitializeHeadersWithCacheControl("Max-aGe=15");
   2180   EXPECT_EQ(TimeDelta::FromSeconds(15), GetMaxAgeValue());
   2181 }
   2182 
   2183 struct MaxAgeTestData {
   2184   const char* max_age_string;
   2185   const int64 expected_seconds;
   2186 };
   2187 
   2188 class MaxAgeEdgeCasesTest
   2189     : public HttpResponseHeadersCacheControlTest,
   2190       public ::testing::WithParamInterface<MaxAgeTestData> {
   2191 };
   2192 
   2193 TEST_P(MaxAgeEdgeCasesTest, MaxAgeEdgeCases) {
   2194   const MaxAgeTestData test = GetParam();
   2195 
   2196   std::string max_age = "max-age=";
   2197   InitializeHeadersWithCacheControl(
   2198       (max_age + test.max_age_string).c_str());
   2199   EXPECT_EQ(test.expected_seconds, GetMaxAgeValue().InSeconds())
   2200       << " for max-age=" << test.max_age_string;
   2201 }
   2202 
   2203 const MaxAgeTestData max_age_tests[] = {
   2204   {" 1 ", 1},    // Spaces are ignored.
   2205   {"-1", -1},    // Negative numbers are passed through.
   2206   {"--1", 0},    // Leading junk gives 0.
   2207   {"2s", 2},     // Trailing junk is ignored.
   2208   {"3 days", 3},
   2209   {"'4'", 0},    // Single quotes don't work.
   2210   {"\"5\"", 0},  // Double quotes don't work.
   2211   {"0x6", 0},    // Hex not parsed as hex.
   2212   {"7F", 7},     // Hex without 0x still not parsed as hex.
   2213   {"010", 10},   // Octal not parsed as octal.
   2214   {"9223372036854", 9223372036854},
   2215   //  {"9223372036855", -9223372036854},  // Undefined behaviour.
   2216   //  {"9223372036854775806", -2},        // Undefined behaviour.
   2217   {"9223372036854775807", 9223372036854775807},
   2218   {"20000000000000000000",
   2219   std::numeric_limits<int64>::max()},  // Overflow int64.
   2220 };
   2221 
   2222 INSTANTIATE_TEST_CASE_P(HttpResponseHeadersCacheControl,
   2223                         MaxAgeEdgeCasesTest,
   2224                         testing::ValuesIn(max_age_tests));
   2225 
   2226 TEST_F(HttpResponseHeadersCacheControlTest,
   2227        AbsentStaleWhileRevalidateReturnsFalse) {
   2228   InitializeHeadersWithCacheControl("max-age=3600");
   2229   EXPECT_FALSE(headers()->GetStaleWhileRevalidateValue(TimeDeltaPointer()));
   2230 }
   2231 
   2232 TEST_F(HttpResponseHeadersCacheControlTest,
   2233        StaleWhileRevalidateWithoutValueRejected) {
   2234   InitializeHeadersWithCacheControl("max-age=3600,stale-while-revalidate=");
   2235   EXPECT_FALSE(headers()->GetStaleWhileRevalidateValue(TimeDeltaPointer()));
   2236 }
   2237 
   2238 TEST_F(HttpResponseHeadersCacheControlTest,
   2239        StaleWhileRevalidateWithInvalidValueTreatedAsZero) {
   2240   InitializeHeadersWithCacheControl("max-age=3600,stale-while-revalidate=true");
   2241   EXPECT_EQ(TimeDelta(), GetStaleWhileRevalidateValue());
   2242 }
   2243 
   2244 TEST_F(HttpResponseHeadersCacheControlTest, StaleWhileRevalidateValueReturned) {
   2245   InitializeHeadersWithCacheControl("max-age=3600,stale-while-revalidate=7200");
   2246   EXPECT_EQ(TimeDelta::FromSeconds(7200), GetStaleWhileRevalidateValue());
   2247 }
   2248 
   2249 TEST_F(HttpResponseHeadersCacheControlTest,
   2250        FirstStaleWhileRevalidateValueUsed) {
   2251   InitializeHeadersWithCacheControl(
   2252       "stale-while-revalidate=1,stale-while-revalidate=7200");
   2253   EXPECT_EQ(TimeDelta::FromSeconds(1), GetStaleWhileRevalidateValue());
   2254 }
   2255 
   2256 } // end namespace
   2257