[SyncFS] Use variadic template in callback_tracker_internal.h
[chromium-blink-merge.git] / net / http / http_response_headers_unittest.cc
blob098ce73e99aa48a85c42311b3876228ac37567f3
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.
5 #include <algorithm>
6 #include <limits>
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"
17 namespace {
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;
27 class HttpResponseHeadersTest : public testing::Test {
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';
38 class HttpResponseHeadersCacheControlTest : public HttpResponseHeadersTest {
39 protected:
40 // Make tests less verbose.
41 typedef base::TimeDelta TimeDelta;
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);
55 const scoped_refptr<net::HttpResponseHeaders>& headers() { return headers_; }
57 // Return a pointer to a TimeDelta object. For use when the value doesn't
58 // matter.
59 TimeDelta* TimeDeltaPointer() { return &delta_; }
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;
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;
80 private:
81 scoped_refptr<net::HttpResponseHeaders> headers_;
82 TimeDelta delta_;
85 class CommonHttpResponseHeadersTest
86 : public HttpResponseHeadersTest,
87 public ::testing::WithParamInterface<TestData> {
90 TEST_P(CommonHttpResponseHeadersTest, TestCommon) {
91 const TestData test = GetParam();
93 std::string raw_headers(test.raw_headers);
94 HeadersToRaw(&raw_headers);
95 std::string expected_headers(test.expected_headers);
97 std::string headers;
98 scoped_refptr<net::HttpResponseHeaders> parsed(
99 new net::HttpResponseHeaders(raw_headers));
100 parsed->GetNormalizedHeaders(&headers);
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', '\\');
108 EXPECT_EQ(expected_headers, headers);
110 EXPECT_EQ(test.expected_response_code, parsed->response_code());
112 EXPECT_TRUE(test.expected_parsed_version == parsed->GetParsedHttpVersion());
113 EXPECT_TRUE(test.expected_version == parsed->GetHttpVersion());
116 TestData response_headers_tests[] = {
118 // Normalise whitespace.
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",
125 "HTTP/1.1 202 Accepted\n"
126 "Content-TYPE: text/html; charset=utf-8\n"
127 "Set-Cookie: a, b\n",
129 202,
130 net::HttpVersion(1,1),
131 net::HttpVersion(1,1)
134 // Normalize leading whitespace.
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",
142 "HTTP/1.1 202 Accepted\n"
143 "Set-Cookie: a, b\n",
145 202,
146 net::HttpVersion(1,1),
147 net::HttpVersion(1,1)
150 // Normalize blank headers.
152 "HTTP/1.1 200 OK\n"
153 "Header1 : \n"
154 "Header2: \n"
155 "Header3:\n"
156 "Header4\n"
157 "Header5 :\n",
159 "HTTP/1.1 200 OK\n"
160 "Header1: \n"
161 "Header2: \n"
162 "Header3: \n"
163 "Header5: \n",
165 200,
166 net::HttpVersion(1,1),
167 net::HttpVersion(1,1)
170 // Don't believe the http/0.9 version if there are headers!
172 "hTtP/0.9 201\n"
173 "Content-TYPE: text/html; charset=utf-8\n",
175 "HTTP/1.0 201 OK\n"
176 "Content-TYPE: text/html; charset=utf-8\n",
178 201,
179 net::HttpVersion(0,9),
180 net::HttpVersion(1,0)
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.
187 "hTtP/0.9 200 OK\n",
189 "HTTP/0.9 200 OK\n",
191 200,
192 net::HttpVersion(0,9),
193 net::HttpVersion(0,9)
196 // Add missing OK.
198 "HTTP/1.1 201\n"
199 "Content-TYPE: text/html; charset=utf-8\n",
201 "HTTP/1.1 201 OK\n"
202 "Content-TYPE: text/html; charset=utf-8\n",
204 201,
205 net::HttpVersion(1,1),
206 net::HttpVersion(1,1)
209 // Normalize bad status line.
211 "SCREWED_UP_STATUS_LINE\n"
212 "Content-TYPE: text/html; charset=utf-8\n",
214 "HTTP/1.0 200 OK\n"
215 "Content-TYPE: text/html; charset=utf-8\n",
217 200,
218 net::HttpVersion(0,0), // Parse error.
219 net::HttpVersion(1,0)
222 // Normalize invalid status code.
224 "HTTP/1.1 -1 Unknown\n",
226 "HTTP/1.1 200 OK\n",
228 200,
229 net::HttpVersion(1,1),
230 net::HttpVersion(1,1)
233 // Normalize empty header.
237 "HTTP/1.0 200 OK\n",
239 200,
240 net::HttpVersion(0,0), // Parse Error.
241 net::HttpVersion(1,0)
244 // Normalize headers that start with a colon.
246 "HTTP/1.1 202 Accepted \n"
247 "foo: bar\n"
248 ": a \n"
249 " : b\n"
250 "baz: blat \n",
252 "HTTP/1.1 202 Accepted\n"
253 "foo: bar\n"
254 "baz: blat\n",
256 202,
257 net::HttpVersion(1,1),
258 net::HttpVersion(1,1)
261 // Normalize headers that end with a colon.
263 "HTTP/1.1 202 Accepted \n"
264 "foo: \n"
265 "bar:\n"
266 "baz: blat \n"
267 "zip:\n",
269 "HTTP/1.1 202 Accepted\n"
270 "foo: \n"
271 "bar: \n"
272 "baz: blat\n"
273 "zip: \n",
275 202,
276 net::HttpVersion(1,1),
277 net::HttpVersion(1,1)
280 // Normalize whitespace headers.
282 "\n \n",
284 "HTTP/1.0 200 OK\n",
286 200,
287 net::HttpVersion(0,0), // Parse error.
288 net::HttpVersion(1,0)
291 // Consolidate Set-Cookie headers.
293 "HTTP/1.1 200 OK\n"
294 "Set-Cookie: x=1\n"
295 "Set-Cookie: y=2\n",
297 "HTTP/1.1 200 OK\n"
298 "Set-Cookie: x=1, y=2\n",
300 200,
301 net::HttpVersion(1,1),
302 net::HttpVersion(1,1)
306 INSTANTIATE_TEST_CASE_P(HttpResponseHeaders,
307 CommonHttpResponseHeadersTest,
308 testing::ValuesIn(response_headers_tests));
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));
319 std::string value;
320 EXPECT_TRUE(parsed->GetNormalizedHeader("cache-control", &value));
321 EXPECT_EQ("private, no-store", value);
324 struct PersistData {
325 net::HttpResponseHeaders::PersistOptions options;
326 const char* raw_headers;
327 const char* expected_headers;
330 class PersistenceTest
331 : public HttpResponseHeadersTest,
332 public ::testing::WithParamInterface<PersistData> {
335 TEST_P(PersistenceTest, Persist) {
336 const PersistData test = GetParam();
338 std::string headers = test.raw_headers;
339 HeadersToRaw(&headers);
340 scoped_refptr<net::HttpResponseHeaders> parsed1(
341 new net::HttpResponseHeaders(headers));
343 Pickle pickle;
344 parsed1->Persist(&pickle, test.options);
346 PickleIterator iter(pickle);
347 scoped_refptr<net::HttpResponseHeaders> parsed2(
348 new net::HttpResponseHeaders(pickle, &iter));
350 std::string h2;
351 parsed2->GetNormalizedHeaders(&h2);
352 EXPECT_EQ(std::string(test.expected_headers), h2);
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",
361 "HTTP/1.1 200 OK\n"
362 "Cache-control: private, no-store\n"
364 { net::HttpResponseHeaders::PERSIST_SANS_HOP_BY_HOP,
365 "HTTP/1.1 200 OK\n"
366 "connection: keep-alive\n"
367 "server: blah\n",
369 "HTTP/1.1 200 OK\n"
370 "server: blah\n"
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",
381 "HTTP/1.1 200 OK\n"
382 "cache-control: private, no-cache=\"foo\"\n"
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",
390 "HTTP/1.1 200 OK\n"
391 "Cache-Control: private,no-cache=\"foo, bar\"\n"
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",
399 "HTTP/1.1 200 OK\n"
400 "Foo: 2\n"
401 "Cache-Control: private,no-cache=foo\n"
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",
409 "HTTP/1.1 200 OK\n"
410 "Foo: 2\n"
411 "Cache-Control: private, no-cache=\n"
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",
419 "HTTP/1.1 200 OK\n"
420 "Foo: 2\n"
421 "Cache-Control: private, no-cache=\"\"\n"
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",
429 "HTTP/1.1 200 OK\n"
430 "Foo: 2\n"
431 "Cache-Control: private, no-cache=\'foo\'\n"
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",
439 "HTTP/1.1 200 OK\n"
440 "Foo: 2\n"
441 "Cache-Control: private, no-cache=\"foo\n"
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",
449 "HTTP/1.1 200 OK\n"
450 "Cache-Control: private, no-cache=\" foo\t, bar\"\n"
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",
459 "HTTP/1.1 200 OK\n"
460 "Foo: 1, 3\n"
461 "Bar: 2\n"
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",
470 "HTTP/1.1 200 OK\n"
471 "Foo: 1, 3, 4\n"
472 "Bar: 2\n"
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",
482 "HTTP/1.1 200 OK\n"
483 "Bar: 1\n"
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",
491 "HTTP/1.1 200 OK\n"
492 "Content-Length: 450\n"
493 "Content-Encoding: gzip\n"
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",
501 "HTTP/1.1 200 OK\n"
502 "Content-Length: 450\n"
503 "Content-Encoding: gzip\n"
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=\"",
514 "HTTP/1.1 200 OK\n"
515 "Bar: 1\n"
519 INSTANTIATE_TEST_CASE_P(HttpResponseHeaders,
520 PersistenceTest,
521 testing::ValuesIn(persistence_tests));
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));
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));
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));
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));
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));
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);
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));
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);
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;
622 class ContentTypeTest
623 : public HttpResponseHeadersTest,
624 public ::testing::WithParamInterface<ContentTypeTestData> {
627 TEST_P(ContentTypeTest, GetMimeType) {
628 const ContentTypeTestData test = GetParam();
630 std::string headers(test.raw_headers);
631 HeadersToRaw(&headers);
632 scoped_refptr<net::HttpResponseHeaders> parsed(
633 new net::HttpResponseHeaders(headers));
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);
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 "*/*" },
776 INSTANTIATE_TEST_CASE_P(HttpResponseHeaders,
777 ContentTypeTest,
778 testing::ValuesIn(mimetype_tests));
780 struct RequiresValidationTestData {
781 const char* headers;
782 bool requires_validation;
785 class RequiresValidationTest
786 : public HttpResponseHeadersTest,
787 public ::testing::WithParamInterface<RequiresValidationTestData> {
790 TEST_P(RequiresValidationTest, RequiresValidation) {
791 const RequiresValidationTestData test = GetParam();
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);
798 std::string headers(test.headers);
799 HeadersToRaw(&headers);
800 scoped_refptr<net::HttpResponseHeaders> parsed(
801 new net::HttpResponseHeaders(headers));
803 bool requires_validation =
804 parsed->RequiresValidation(request_time, response_time, current_time);
805 EXPECT_EQ(test.requires_validation, requires_validation);
808 const struct RequiresValidationTestData requires_validation_tests[] = {
809 // No expiry info: expires immediately.
810 { "HTTP/1.1 200 OK\n"
811 "\n",
812 true
814 // No expiry info: expires immediately.
815 { "HTTP/1.1 200 OK\n"
816 "\n",
817 true
819 // Valid for a little while.
820 { "HTTP/1.1 200 OK\n"
821 "cache-control: max-age=10000\n"
822 "\n",
823 false
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
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
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
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
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
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
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
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
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
885 // Cached permanent redirect.
886 { "HTTP/1.1 301 Moved Permanently\n"
887 "\n",
888 false
890 // Another cached permanent redirect.
891 { "HTTP/1.1 308 Permanent Redirect\n"
892 "\n",
893 false
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
901 // Cached forever by default.
902 { "HTTP/1.1 410 Gone\n"
903 "\n",
904 false
906 // Cached temporary redirect: not reusable.
907 { "HTTP/1.1 302 Found\n"
908 "\n",
909 true
911 // Cached temporary redirect: reusable.
912 { "HTTP/1.1 302 Found\n"
913 "cache-control: max-age=10000\n"
914 "\n",
915 false
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
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
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
942 // TODO(darin): Add many many more tests here.
945 INSTANTIATE_TEST_CASE_P(HttpResponseHeaders,
946 RequiresValidationTest,
947 testing::ValuesIn(requires_validation_tests));
949 struct UpdateTestData {
950 const char* orig_headers;
951 const char* new_headers;
952 const char* expected_headers;
955 class UpdateTest
956 : public HttpResponseHeadersTest,
957 public ::testing::WithParamInterface<UpdateTestData> {
960 TEST_P(UpdateTest, Update) {
961 const UpdateTestData test = GetParam();
963 std::string orig_headers(test.orig_headers);
964 HeadersToRaw(&orig_headers);
965 scoped_refptr<net::HttpResponseHeaders> parsed(
966 new net::HttpResponseHeaders(orig_headers));
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));
973 parsed->Update(*new_parsed.get());
975 std::string resulting_headers;
976 parsed->GetNormalizedHeaders(&resulting_headers);
977 EXPECT_EQ(std::string(test.expected_headers), resulting_headers);
980 const UpdateTestData update_tests[] = {
981 { "HTTP/1.1 200 OK\n",
983 "HTTP/1/1 304 Not Modified\n"
984 "connection: keep-alive\n"
985 "Cache-control: max-age=10000\n",
987 "HTTP/1.1 200 OK\n"
988 "Cache-control: max-age=10000\n"
990 { "HTTP/1.1 200 OK\n"
991 "Foo: 1\n"
992 "Cache-control: private\n",
994 "HTTP/1/1 304 Not Modified\n"
995 "connection: keep-alive\n"
996 "Cache-control: max-age=10000\n",
998 "HTTP/1.1 200 OK\n"
999 "Cache-control: max-age=10000\n"
1000 "Foo: 1\n"
1002 { "HTTP/1.1 200 OK\n"
1003 "Foo: 1\n"
1004 "Cache-control: private\n",
1006 "HTTP/1/1 304 Not Modified\n"
1007 "connection: keep-alive\n"
1008 "Cache-CONTROL: max-age=10000\n",
1010 "HTTP/1.1 200 OK\n"
1011 "Cache-CONTROL: max-age=10000\n"
1012 "Foo: 1\n"
1014 { "HTTP/1.1 200 OK\n"
1015 "Content-Length: 450\n",
1017 "HTTP/1/1 304 Not Modified\n"
1018 "connection: keep-alive\n"
1019 "Cache-control: max-age=10001 \n",
1021 "HTTP/1.1 200 OK\n"
1022 "Cache-control: max-age=10001\n"
1023 "Content-Length: 450\n"
1025 { "HTTP/1.1 200 OK\n"
1026 "X-Frame-Options: DENY\n",
1028 "HTTP/1/1 304 Not Modified\n"
1029 "X-Frame-Options: ALLOW\n",
1031 "HTTP/1.1 200 OK\n"
1032 "X-Frame-Options: DENY\n",
1034 { "HTTP/1.1 200 OK\n"
1035 "X-WebKit-CSP: default-src 'none'\n",
1037 "HTTP/1/1 304 Not Modified\n"
1038 "X-WebKit-CSP: default-src *\n",
1040 "HTTP/1.1 200 OK\n"
1041 "X-WebKit-CSP: default-src 'none'\n",
1043 { "HTTP/1.1 200 OK\n"
1044 "X-XSS-Protection: 1\n",
1046 "HTTP/1/1 304 Not Modified\n"
1047 "X-XSS-Protection: 0\n",
1049 "HTTP/1.1 200 OK\n"
1050 "X-XSS-Protection: 1\n",
1052 { "HTTP/1.1 200 OK\n",
1054 "HTTP/1/1 304 Not Modified\n"
1055 "X-Content-Type-Options: nosniff\n",
1057 "HTTP/1.1 200 OK\n"
1061 INSTANTIATE_TEST_CASE_P(HttpResponseHeaders,
1062 UpdateTest,
1063 testing::ValuesIn(update_tests));
1065 struct EnumerateHeaderTestData {
1066 const char* headers;
1067 const char* expected_lines;
1070 class EnumerateHeaderLinesTest
1071 : public HttpResponseHeadersTest,
1072 public ::testing::WithParamInterface<EnumerateHeaderTestData> {
1075 TEST_P(EnumerateHeaderLinesTest, EnumerateHeaderLines) {
1076 const EnumerateHeaderTestData test = GetParam();
1078 std::string headers(test.headers);
1079 HeadersToRaw(&headers);
1080 scoped_refptr<net::HttpResponseHeaders> parsed(
1081 new net::HttpResponseHeaders(headers));
1083 std::string name, value, lines;
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");
1093 EXPECT_EQ(std::string(test.expected_lines), lines);
1096 const EnumerateHeaderTestData enumerate_header_tests[] = {
1097 { "HTTP/1.1 200 OK\n",
1101 { "HTTP/1.1 200 OK\n"
1102 "Foo: 1\n",
1104 "Foo: 1\n"
1106 { "HTTP/1.1 200 OK\n"
1107 "Foo: 1\n"
1108 "Bar: 2\n"
1109 "Foo: 3\n",
1111 "Foo: 1\nBar: 2\nFoo: 3\n"
1113 { "HTTP/1.1 200 OK\n"
1114 "Foo: 1, 2, 3\n",
1116 "Foo: 1, 2, 3\n"
1120 INSTANTIATE_TEST_CASE_P(HttpResponseHeaders,
1121 EnumerateHeaderLinesTest,
1122 testing::ValuesIn(enumerate_header_tests));
1124 struct IsRedirectTestData {
1125 const char* headers;
1126 const char* location;
1127 bool is_redirect;
1130 class IsRedirectTest
1131 : public HttpResponseHeadersTest,
1132 public ::testing::WithParamInterface<IsRedirectTestData> {
1135 TEST_P(IsRedirectTest, IsRedirect) {
1136 const IsRedirectTestData test = GetParam();
1138 std::string headers(test.headers);
1139 HeadersToRaw(&headers);
1140 scoped_refptr<net::HttpResponseHeaders> parsed(
1141 new net::HttpResponseHeaders(headers));
1143 std::string location;
1144 EXPECT_EQ(parsed->IsRedirect(&location), test.is_redirect);
1145 EXPECT_EQ(location, test.location);
1148 const IsRedirectTestData is_redirect_tests[] = {
1149 { "HTTP/1.1 200 OK\n",
1151 false
1153 { "HTTP/1.1 301 Moved\n"
1154 "Location: http://foopy/\n",
1155 "http://foopy/",
1156 true
1158 { "HTTP/1.1 301 Moved\n"
1159 "Location: \t \n",
1161 false
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
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
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
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
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
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
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
1208 INSTANTIATE_TEST_CASE_P(HttpResponseHeaders,
1209 IsRedirectTest,
1210 testing::ValuesIn(is_redirect_tests));
1212 struct ContentLengthTestData {
1213 const char* headers;
1214 int64 expected_len;
1217 class GetContentLengthTest
1218 : public HttpResponseHeadersTest,
1219 public ::testing::WithParamInterface<ContentLengthTestData> {
1222 TEST_P(GetContentLengthTest, GetContentLength) {
1223 const ContentLengthTestData test = GetParam();
1225 std::string headers(test.headers);
1226 HeadersToRaw(&headers);
1227 scoped_refptr<net::HttpResponseHeaders> parsed(
1228 new net::HttpResponseHeaders(headers));
1230 EXPECT_EQ(test.expected_len, parsed->GetContentLength());
1233 const ContentLengthTestData content_length_tests[] = {
1234 { "HTTP/1.1 200 OK\n",
1237 { "HTTP/1.1 200 OK\n"
1238 "Content-Length: 10\n",
1241 { "HTTP/1.1 200 OK\n"
1242 "Content-Length: \n",
1245 { "HTTP/1.1 200 OK\n"
1246 "Content-Length: abc\n",
1249 { "HTTP/1.1 200 OK\n"
1250 "Content-Length: -10\n",
1253 { "HTTP/1.1 200 OK\n"
1254 "Content-Length: +10\n",
1257 { "HTTP/1.1 200 OK\n"
1258 "Content-Length: 23xb5\n",
1261 { "HTTP/1.1 200 OK\n"
1262 "Content-Length: 0xA\n",
1265 { "HTTP/1.1 200 OK\n"
1266 "Content-Length: 010\n",
1269 // Content-Length too big, will overflow an int64.
1270 { "HTTP/1.1 200 OK\n"
1271 "Content-Length: 40000000000000000000\n",
1274 { "HTTP/1.1 200 OK\n"
1275 "Content-Length: 10\n",
1278 { "HTTP/1.1 200 OK\n"
1279 "Content-Length: 10 \n",
1282 { "HTTP/1.1 200 OK\n"
1283 "Content-Length: \t10\n",
1286 { "HTTP/1.1 200 OK\n"
1287 "Content-Length: \v10\n",
1290 { "HTTP/1.1 200 OK\n"
1291 "Content-Length: \f10\n",
1294 { "HTTP/1.1 200 OK\n"
1295 "cOnTeNt-LENgth: 33\n",
1298 { "HTTP/1.1 200 OK\n"
1299 "Content-Length: 34\r\n",
1304 INSTANTIATE_TEST_CASE_P(HttpResponseHeaders,
1305 GetContentLengthTest,
1306 testing::ValuesIn(content_length_tests));
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;
1316 class ContentRangeTest
1317 : public HttpResponseHeadersTest,
1318 public ::testing::WithParamInterface<ContentRangeTestData> {
1321 TEST_P(ContentRangeTest, GetContentRange) {
1322 const ContentRangeTestData test = GetParam();
1324 std::string headers(test.headers);
1325 HeadersToRaw(&headers);
1326 scoped_refptr<net::HttpResponseHeaders> parsed(
1327 new net::HttpResponseHeaders(headers));
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);
1341 const ContentRangeTestData content_range_tests[] = {
1342 { "HTTP/1.1 206 Partial Content",
1343 false,
1348 { "HTTP/1.1 206 Partial Content\n"
1349 "Content-Range:",
1350 false,
1355 { "HTTP/1.1 206 Partial Content\n"
1356 "Content-Range: megabytes 0-10/50",
1357 false,
1362 { "HTTP/1.1 206 Partial Content\n"
1363 "Content-Range: 0-10/50",
1364 false,
1369 { "HTTP/1.1 206 Partial Content\n"
1370 "Content-Range: Bytes 0-50/51",
1371 true,
1376 { "HTTP/1.1 206 Partial Content\n"
1377 "Content-Range: bytes 0-50/51",
1378 true,
1383 { "HTTP/1.1 206 Partial Content\n"
1384 "Content-Range: bytes\t0-50/51",
1385 false,
1390 { "HTTP/1.1 206 Partial Content\n"
1391 "Content-Range: bytes 0-50/51",
1392 true,
1397 { "HTTP/1.1 206 Partial Content\n"
1398 "Content-Range: bytes 0 - 50 \t / \t51",
1399 true,
1404 { "HTTP/1.1 206 Partial Content\n"
1405 "Content-Range: bytes 0\t-\t50\t/\t51\t",
1406 true,
1411 { "HTTP/1.1 206 Partial Content\n"
1412 "Content-Range: \tbytes\t\t\t 0\t-\t50\t/\t51\t",
1413 true,
1418 { "HTTP/1.1 206 Partial Content\n"
1419 "Content-Range: \t bytes \t 0 - 50 / 5 1",
1420 false,
1425 { "HTTP/1.1 206 Partial Content\n"
1426 "Content-Range: \t bytes \t 0 - 5 0 / 51",
1427 false,
1432 { "HTTP/1.1 206 Partial Content\n"
1433 "Content-Range: bytes 50-0/51",
1434 false,
1439 { "HTTP/1.1 416 Requested range not satisfiable\n"
1440 "Content-Range: bytes * /*",
1441 false,
1446 { "HTTP/1.1 416 Requested range not satisfiable\n"
1447 "Content-Range: bytes * / * ",
1448 false,
1453 { "HTTP/1.1 206 Partial Content\n"
1454 "Content-Range: bytes 0-50/*",
1455 false,
1460 { "HTTP/1.1 206 Partial Content\n"
1461 "Content-Range: bytes 0-50 / * ",
1462 false,
1467 { "HTTP/1.1 206 Partial Content\n"
1468 "Content-Range: bytes 0-10000000000/10000000001",
1469 true,
1471 10000000000ll,
1472 10000000001ll
1474 { "HTTP/1.1 206 Partial Content\n"
1475 "Content-Range: bytes 0-10000000000/10000000000",
1476 false,
1478 10000000000ll,
1479 10000000000ll
1481 // 64 bit wraparound.
1482 { "HTTP/1.1 206 Partial Content\n"
1483 "Content-Range: bytes 0 - 9223372036854775807 / 100",
1484 false,
1486 kint64max,
1489 // 64 bit wraparound.
1490 { "HTTP/1.1 206 Partial Content\n"
1491 "Content-Range: bytes 0 - 100 / -9223372036854775808",
1492 false,
1494 100,
1495 kint64min
1497 { "HTTP/1.1 206 Partial Content\n"
1498 "Content-Range: bytes */50",
1499 false,
1504 { "HTTP/1.1 206 Partial Content\n"
1505 "Content-Range: bytes 0-50/10",
1506 false,
1511 { "HTTP/1.1 206 Partial Content\n"
1512 "Content-Range: bytes 40-50/45",
1513 false,
1518 { "HTTP/1.1 206 Partial Content\n"
1519 "Content-Range: bytes 0-50/-10",
1520 false,
1525 { "HTTP/1.1 206 Partial Content\n"
1526 "Content-Range: bytes 0-0/1",
1527 true,
1532 { "HTTP/1.1 206 Partial Content\n"
1533 "Content-Range: bytes 0-40000000000000000000/40000000000000000001",
1534 false,
1539 { "HTTP/1.1 206 Partial Content\n"
1540 "Content-Range: bytes 1-/100",
1541 false,
1546 { "HTTP/1.1 206 Partial Content\n"
1547 "Content-Range: bytes -/100",
1548 false,
1553 { "HTTP/1.1 206 Partial Content\n"
1554 "Content-Range: bytes -1/100",
1555 false,
1560 { "HTTP/1.1 206 Partial Content\n"
1561 "Content-Range: bytes 0-1233/*",
1562 false,
1564 1233,
1567 { "HTTP/1.1 206 Partial Content\n"
1568 "Content-Range: bytes -123 - -1/100",
1569 false,
1576 INSTANTIATE_TEST_CASE_P(HttpResponseHeaders,
1577 ContentRangeTest,
1578 testing::ValuesIn(content_range_tests));
1580 struct KeepAliveTestData {
1581 const char* headers;
1582 bool expected_keep_alive;
1585 class IsKeepAliveTest
1586 : public HttpResponseHeadersTest,
1587 public ::testing::WithParamInterface<KeepAliveTestData> {
1590 TEST_P(IsKeepAliveTest, IsKeepAlive) {
1591 const KeepAliveTestData test = GetParam();
1593 std::string headers(test.headers);
1594 HeadersToRaw(&headers);
1595 scoped_refptr<net::HttpResponseHeaders> parsed(
1596 new net::HttpResponseHeaders(headers));
1598 EXPECT_EQ(test.expected_keep_alive, parsed->IsKeepAlive());
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
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
1613 { "HTTP/1.1 200 OK\n",
1614 true
1616 { "HTTP/1.0 200 OK\n",
1617 false
1619 { "HTTP/1.0 200 OK\n"
1620 "connection: close\n",
1621 false
1623 { "HTTP/1.0 200 OK\n"
1624 "connection: keep-alive\n",
1625 true
1627 { "HTTP/1.0 200 OK\n"
1628 "connection: kEeP-AliVe\n",
1629 true
1631 { "HTTP/1.0 200 OK\n"
1632 "connection: keep-aliveX\n",
1633 false
1635 { "HTTP/1.1 200 OK\n"
1636 "connection: close\n",
1637 false
1639 { "HTTP/1.1 200 OK\n"
1640 "connection: keep-alive\n",
1641 true
1643 { "HTTP/1.0 200 OK\n"
1644 "proxy-connection: close\n",
1645 false
1647 { "HTTP/1.0 200 OK\n"
1648 "proxy-connection: keep-alive\n",
1649 true
1651 { "HTTP/1.1 200 OK\n"
1652 "proxy-connection: close\n",
1653 false
1655 { "HTTP/1.1 200 OK\n"
1656 "proxy-connection: keep-alive\n",
1657 true
1661 INSTANTIATE_TEST_CASE_P(HttpResponseHeaders,
1662 IsKeepAliveTest,
1663 testing::ValuesIn(keepalive_tests));
1665 struct HasStrongValidatorsTestData {
1666 const char* headers;
1667 bool expected_result;
1670 class HasStrongValidatorsTest
1671 : public HttpResponseHeadersTest,
1672 public ::testing::WithParamInterface<HasStrongValidatorsTestData> {
1675 TEST_P(HasStrongValidatorsTest, HasStrongValidators) {
1676 const HasStrongValidatorsTestData test = GetParam();
1678 std::string headers(test.headers);
1679 HeadersToRaw(&headers);
1680 scoped_refptr<net::HttpResponseHeaders> parsed(
1681 new net::HttpResponseHeaders(headers));
1683 EXPECT_EQ(test.expected_result, parsed->HasStrongValidators());
1686 const HasStrongValidatorsTestData strong_validators_tests[] = {
1687 { "HTTP/0.9 200 OK",
1688 false
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
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
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
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
1712 { "HTTP/1.1 200 OK\n"
1713 "ETag: \"foo\"\n",
1714 true
1716 // This is not really a weak etag:
1717 { "HTTP/1.1 200 OK\n"
1718 "etag: \"w/foo\"\n",
1719 true
1721 // This is a weak etag:
1722 { "HTTP/1.1 200 OK\n"
1723 "etag: w/\"foo\"\n",
1724 false
1726 { "HTTP/1.1 200 OK\n"
1727 "etag: W / \"foo\"\n",
1728 false
1732 INSTANTIATE_TEST_CASE_P(HttpResponseHeaders,
1733 HasStrongValidatorsTest,
1734 testing::ValuesIn(strong_validators_tests));
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());
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());
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());
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());
1771 struct AddHeaderTestData {
1772 const char* orig_headers;
1773 const char* new_header;
1774 const char* expected_headers;
1777 class AddHeaderTest
1778 : public HttpResponseHeadersTest,
1779 public ::testing::WithParamInterface<AddHeaderTestData> {
1782 TEST_P(AddHeaderTest, AddHeader) {
1783 const AddHeaderTestData test = GetParam();
1785 std::string orig_headers(test.orig_headers);
1786 HeadersToRaw(&orig_headers);
1787 scoped_refptr<net::HttpResponseHeaders> parsed(
1788 new net::HttpResponseHeaders(orig_headers));
1790 std::string new_header(test.new_header);
1791 parsed->AddHeader(new_header);
1793 std::string resulting_headers;
1794 parsed->GetNormalizedHeaders(&resulting_headers);
1795 EXPECT_EQ(std::string(test.expected_headers), resulting_headers);
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",
1803 "Content-Length: 450",
1805 "HTTP/1.1 200 OK\n"
1806 "connection: keep-alive\n"
1807 "Cache-control: max-age=10000\n"
1808 "Content-Length: 450\n"
1810 { "HTTP/1.1 200 OK\n"
1811 "connection: keep-alive\n"
1812 "Cache-control: max-age=10000 \n",
1814 "Content-Length: 450 ",
1816 "HTTP/1.1 200 OK\n"
1817 "connection: keep-alive\n"
1818 "Cache-control: max-age=10000\n"
1819 "Content-Length: 450\n"
1823 INSTANTIATE_TEST_CASE_P(HttpResponseHeaders,
1824 AddHeaderTest,
1825 testing::ValuesIn(add_header_tests));
1827 struct RemoveHeaderTestData {
1828 const char* orig_headers;
1829 const char* to_remove;
1830 const char* expected_headers;
1833 class RemoveHeaderTest
1834 : public HttpResponseHeadersTest,
1835 public ::testing::WithParamInterface<RemoveHeaderTestData> {
1838 TEST_P(RemoveHeaderTest, RemoveHeader) {
1839 const RemoveHeaderTestData test = GetParam();
1841 std::string orig_headers(test.orig_headers);
1842 HeadersToRaw(&orig_headers);
1843 scoped_refptr<net::HttpResponseHeaders> parsed(
1844 new net::HttpResponseHeaders(orig_headers));
1846 std::string name(test.to_remove);
1847 parsed->RemoveHeader(name);
1849 std::string resulting_headers;
1850 parsed->GetNormalizedHeaders(&resulting_headers);
1851 EXPECT_EQ(std::string(test.expected_headers), resulting_headers);
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",
1860 "Content-Length",
1862 "HTTP/1.1 200 OK\n"
1863 "connection: keep-alive\n"
1864 "Cache-control: max-age=10000\n"
1866 { "HTTP/1.1 200 OK\n"
1867 "connection: keep-alive \n"
1868 "Content-Length : 450 \n"
1869 "Cache-control: max-age=10000\n",
1871 "Content-Length",
1873 "HTTP/1.1 200 OK\n"
1874 "connection: keep-alive\n"
1875 "Cache-control: max-age=10000\n"
1879 INSTANTIATE_TEST_CASE_P(HttpResponseHeaders,
1880 RemoveHeaderTest,
1881 testing::ValuesIn(remove_header_tests));
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;
1890 class RemoveIndividualHeaderTest
1891 : public HttpResponseHeadersTest,
1892 public ::testing::WithParamInterface<RemoveIndividualHeaderTestData> {
1895 TEST_P(RemoveIndividualHeaderTest, RemoveIndividualHeader) {
1896 const RemoveIndividualHeaderTestData test = GetParam();
1898 std::string orig_headers(test.orig_headers);
1899 HeadersToRaw(&orig_headers);
1900 scoped_refptr<net::HttpResponseHeaders> parsed(
1901 new net::HttpResponseHeaders(orig_headers));
1903 std::string name(test.to_remove_name);
1904 std::string value(test.to_remove_value);
1905 parsed->RemoveHeaderLine(name, value);
1907 std::string resulting_headers;
1908 parsed->GetNormalizedHeaders(&resulting_headers);
1909 EXPECT_EQ(std::string(test.expected_headers), resulting_headers);
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",
1918 "Content-Length",
1920 "450",
1922 "HTTP/1.1 200 OK\n"
1923 "connection: keep-alive\n"
1924 "Cache-control: max-age=10000\n"
1926 { "HTTP/1.1 200 OK\n"
1927 "connection: keep-alive \n"
1928 "Content-Length : 450 \n"
1929 "Cache-control: max-age=10000\n",
1931 "Content-Length",
1933 "450",
1935 "HTTP/1.1 200 OK\n"
1936 "connection: keep-alive\n"
1937 "Cache-control: max-age=10000\n"
1939 { "HTTP/1.1 200 OK\n"
1940 "connection: keep-alive \n"
1941 "Content-Length: 450\n"
1942 "Cache-control: max-age=10000\n",
1944 "Content-Length", // Matching name.
1946 "999", // Mismatching value.
1948 "HTTP/1.1 200 OK\n"
1949 "connection: keep-alive\n"
1950 "Content-Length: 450\n"
1951 "Cache-control: max-age=10000\n"
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",
1959 "Foo",
1961 "bar, baz", // Space in value.
1963 "HTTP/1.1 200 OK\n"
1964 "connection: keep-alive\n"
1965 "Foo: bar\n"
1966 "Cache-control: max-age=10000\n"
1968 { "HTTP/1.1 200 OK\n"
1969 "connection: keep-alive \n"
1970 "Foo: bar, baz\n"
1971 "Cache-control: max-age=10000\n",
1973 "Foo",
1975 "baz", // Only partial match -> ignored.
1977 "HTTP/1.1 200 OK\n"
1978 "connection: keep-alive\n"
1979 "Foo: bar, baz\n"
1980 "Cache-control: max-age=10000\n"
1984 INSTANTIATE_TEST_CASE_P(HttpResponseHeaders,
1985 RemoveIndividualHeaderTest,
1986 testing::ValuesIn(remove_individual_header_tests));
1988 struct ReplaceStatusTestData {
1989 const char* orig_headers;
1990 const char* new_status;
1991 const char* expected_headers;
1994 class ReplaceStatusTest
1995 : public HttpResponseHeadersTest,
1996 public ::testing::WithParamInterface<ReplaceStatusTestData> {
1999 TEST_P(ReplaceStatusTest, ReplaceStatus) {
2000 const ReplaceStatusTestData test = GetParam();
2002 std::string orig_headers(test.orig_headers);
2003 HeadersToRaw(&orig_headers);
2004 scoped_refptr<net::HttpResponseHeaders> parsed(
2005 new net::HttpResponseHeaders(orig_headers));
2007 std::string name(test.new_status);
2008 parsed->ReplaceStatusLine(name);
2010 std::string resulting_headers;
2011 parsed->GetNormalizedHeaders(&resulting_headers);
2012 EXPECT_EQ(std::string(test.expected_headers), resulting_headers);
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",
2021 "HTTP/1.1 200 OK",
2023 "HTTP/1.1 200 OK\n"
2024 "connection: keep-alive\n"
2025 "Cache-control: max-age=10000\n"
2026 "Content-Length: 450\n"
2028 { "HTTP/1.1 200 OK\n"
2029 "connection: keep-alive\n",
2031 "HTTP/1.1 304 Not Modified",
2033 "HTTP/1.1 304 Not Modified\n"
2034 "connection: keep-alive\n"
2036 { "HTTP/1.1 200 OK\n"
2037 "connection: keep-alive \n"
2038 "Content-Length : 450 \n"
2039 "Cache-control: max-age=10000\n",
2041 "HTTP/1//1 304 Not Modified",
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"
2050 INSTANTIATE_TEST_CASE_P(HttpResponseHeaders,
2051 ReplaceStatusTest,
2052 testing::ValuesIn(replace_status_tests));
2054 struct UpdateWithNewRangeTestData {
2055 const char* orig_headers;
2056 const char* expected_headers;
2057 const char* expected_headers_with_replaced_status;
2060 class UpdateWithNewRangeTest
2061 : public HttpResponseHeadersTest,
2062 public ::testing::WithParamInterface<UpdateWithNewRangeTestData> {
2065 TEST_P(UpdateWithNewRangeTest, UpdateWithNewRange) {
2066 const UpdateWithNewRangeTestData test = GetParam();
2068 const net::HttpByteRange range = net::HttpByteRange::Bounded(3, 5);
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;
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);
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);
2089 const UpdateWithNewRangeTestData update_range_tests[] = {
2090 { "HTTP/1.1 200 OK\n"
2091 "Content-Length: 450\n",
2093 "HTTP/1.1 200 OK\n"
2094 "Content-Range: bytes 3-5/450\n"
2095 "Content-Length: 3\n",
2097 "HTTP/1.1 206 Partial Content\n"
2098 "Content-Range: bytes 3-5/450\n"
2099 "Content-Length: 3\n",
2101 { "HTTP/1.1 200 OK\n"
2102 "Content-Length: 5\n",
2104 "HTTP/1.1 200 OK\n"
2105 "Content-Range: bytes 3-5/5\n"
2106 "Content-Length: 3\n",
2108 "HTTP/1.1 206 Partial Content\n"
2109 "Content-Range: bytes 3-5/5\n"
2110 "Content-Length: 3\n",
2114 INSTANTIATE_TEST_CASE_P(HttpResponseHeaders,
2115 UpdateWithNewRangeTest,
2116 testing::ValuesIn(update_range_tests));
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));
2126 scoped_ptr<base::Value> event_param(
2127 parsed->NetLogCallback(net::NetLog::LOG_ALL_BUT_BYTES));
2128 scoped_refptr<net::HttpResponseHeaders> recreated;
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());
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);
2145 TEST_F(HttpResponseHeadersCacheControlTest, AbsentMaxAgeReturnsFalse) {
2146 InitializeHeadersWithCacheControl("nocache");
2147 EXPECT_FALSE(headers()->GetMaxAgeValue(TimeDeltaPointer()));
2150 TEST_F(HttpResponseHeadersCacheControlTest, MaxAgeWithNoParameterRejected) {
2151 InitializeHeadersWithCacheControl("max-age=,private");
2152 EXPECT_FALSE(headers()->GetMaxAgeValue(TimeDeltaPointer()));
2155 TEST_F(HttpResponseHeadersCacheControlTest, MaxAgeWithSpaceParameterRejected) {
2156 InitializeHeadersWithCacheControl("max-age= ,private");
2157 EXPECT_FALSE(headers()->GetMaxAgeValue(TimeDeltaPointer()));
2160 TEST_F(HttpResponseHeadersCacheControlTest,
2161 MaxAgeWithSpaceBeforeEqualsIsRejected) {
2162 InitializeHeadersWithCacheControl("max-age = 7");
2163 EXPECT_FALSE(headers()->GetMaxAgeValue(TimeDeltaPointer()));
2166 TEST_F(HttpResponseHeadersCacheControlTest, MaxAgeFirstMatchUsed) {
2167 InitializeHeadersWithCacheControl("max-age=10, max-age=20");
2168 EXPECT_EQ(TimeDelta::FromSeconds(10), GetMaxAgeValue());
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());
2178 TEST_F(HttpResponseHeadersCacheControlTest, MaxAgeCaseInsensitive) {
2179 InitializeHeadersWithCacheControl("Max-aGe=15");
2180 EXPECT_EQ(TimeDelta::FromSeconds(15), GetMaxAgeValue());
2183 struct MaxAgeTestData {
2184 const char* max_age_string;
2185 const int64 expected_seconds;
2188 class MaxAgeEdgeCasesTest
2189 : public HttpResponseHeadersCacheControlTest,
2190 public ::testing::WithParamInterface<MaxAgeTestData> {
2193 TEST_P(MaxAgeEdgeCasesTest, MaxAgeEdgeCases) {
2194 const MaxAgeTestData test = GetParam();
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;
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.
2222 INSTANTIATE_TEST_CASE_P(HttpResponseHeadersCacheControl,
2223 MaxAgeEdgeCasesTest,
2224 testing::ValuesIn(max_age_tests));
2226 TEST_F(HttpResponseHeadersCacheControlTest,
2227 AbsentStaleWhileRevalidateReturnsFalse) {
2228 InitializeHeadersWithCacheControl("max-age=3600");
2229 EXPECT_FALSE(headers()->GetStaleWhileRevalidateValue(TimeDeltaPointer()));
2232 TEST_F(HttpResponseHeadersCacheControlTest,
2233 StaleWhileRevalidateWithoutValueRejected) {
2234 InitializeHeadersWithCacheControl("max-age=3600,stale-while-revalidate=");
2235 EXPECT_FALSE(headers()->GetStaleWhileRevalidateValue(TimeDeltaPointer()));
2238 TEST_F(HttpResponseHeadersCacheControlTest,
2239 StaleWhileRevalidateWithInvalidValueTreatedAsZero) {
2240 InitializeHeadersWithCacheControl("max-age=3600,stale-while-revalidate=true");
2241 EXPECT_EQ(TimeDelta(), GetStaleWhileRevalidateValue());
2244 TEST_F(HttpResponseHeadersCacheControlTest, StaleWhileRevalidateValueReturned) {
2245 InitializeHeadersWithCacheControl("max-age=3600,stale-while-revalidate=7200");
2246 EXPECT_EQ(TimeDelta::FromSeconds(7200), GetStaleWhileRevalidateValue());
2249 TEST_F(HttpResponseHeadersCacheControlTest,
2250 FirstStaleWhileRevalidateValueUsed) {
2251 InitializeHeadersWithCacheControl(
2252 "stale-while-revalidate=1,stale-while-revalidate=7200");
2253 EXPECT_EQ(TimeDelta::FromSeconds(1), GetStaleWhileRevalidateValue());
2256 } // end namespace