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