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.
7 #include "base/basictypes.h"
8 #include "base/memory/scoped_ptr.h"
9 #include "base/pickle.h"
10 #include "base/time/time.h"
11 #include "base/values.h"
12 #include "net/http/http_response_headers.h"
13 #include "testing/gtest/include/gtest/gtest.h"
18 const char* raw_headers;
19 const char* expected_headers;
20 int expected_response_code;
21 net::HttpVersion expected_parsed_version;
22 net::HttpVersion expected_version;
25 struct ContentTypeTestData {
26 const std::string raw_headers;
27 const std::string mime_type;
28 const bool has_mimetype;
29 const std::string charset;
30 const bool has_charset;
31 const std::string all_content_type;
34 class HttpResponseHeadersTest : public testing::Test {
37 // Transform "normal"-looking headers (\n-separated) to the appropriate
38 // input format for ParseRawHeaders (\0-separated).
39 void HeadersToRaw(std::string* headers) {
40 std::replace(headers->begin(), headers->end(), '\n', '\0');
41 if (!headers->empty())
45 void TestCommon(const TestData& test) {
46 std::string raw_headers(test.raw_headers);
47 HeadersToRaw(&raw_headers);
48 std::string expected_headers(test.expected_headers);
51 scoped_refptr<net::HttpResponseHeaders> parsed(
52 new net::HttpResponseHeaders(raw_headers));
53 parsed->GetNormalizedHeaders(&headers);
55 // Transform to readable output format (so it's easier to see diffs).
56 std::replace(headers.begin(), headers.end(), ' ', '_');
57 std::replace(headers.begin(), headers.end(), '\n', '\\');
58 std::replace(expected_headers.begin(), expected_headers.end(), ' ', '_');
59 std::replace(expected_headers.begin(), expected_headers.end(), '\n', '\\');
61 EXPECT_EQ(expected_headers, headers);
63 EXPECT_EQ(test.expected_response_code, parsed->response_code());
65 EXPECT_TRUE(test.expected_parsed_version == parsed->GetParsedHttpVersion());
66 EXPECT_TRUE(test.expected_version == parsed->GetHttpVersion());
71 // Check that we normalize headers properly.
72 TEST(HttpResponseHeadersTest, NormalizeHeadersWhitespace) {
74 "HTTP/1.1 202 Accepted \n"
75 "Content-TYPE : text/html; charset=utf-8 \n"
79 "HTTP/1.1 202 Accepted\n"
80 "Content-TYPE: text/html; charset=utf-8\n"
84 net::HttpVersion(1,1),
90 // Check that we normalize headers properly (header name is invalid if starts
92 TEST(HttpResponseHeadersTest, NormalizeHeadersLeadingWhitespace) {
94 "HTTP/1.1 202 Accepted \n"
95 // Starts with space -- will be skipped as invalid.
96 " Content-TYPE : text/html; charset=utf-8 \n"
100 "HTTP/1.1 202 Accepted\n"
101 "Set-Cookie: a, b\n",
104 net::HttpVersion(1,1),
105 net::HttpVersion(1,1)
110 TEST(HttpResponseHeadersTest, BlankHeaders) {
126 net::HttpVersion(1,1),
127 net::HttpVersion(1,1)
132 TEST(HttpResponseHeadersTest, NormalizeHeadersVersion) {
133 // Don't believe the http/0.9 version if there are headers!
136 "Content-TYPE: text/html; charset=utf-8\n",
139 "Content-TYPE: text/html; charset=utf-8\n",
142 net::HttpVersion(0,9),
143 net::HttpVersion(1,0)
148 TEST(HttpResponseHeadersTest, PreserveHttp09) {
149 // Accept the HTTP/0.9 version number if there are no headers.
150 // This is how HTTP/0.9 responses get constructed from HttpNetworkTransaction.
157 net::HttpVersion(0,9),
158 net::HttpVersion(0,9)
163 TEST(HttpResponseHeadersTest, NormalizeHeadersMissingOK) {
166 "Content-TYPE: text/html; charset=utf-8\n",
169 "Content-TYPE: text/html; charset=utf-8\n",
172 net::HttpVersion(1,1),
173 net::HttpVersion(1,1)
178 TEST(HttpResponseHeadersTest, NormalizeHeadersBadStatus) {
180 "SCREWED_UP_STATUS_LINE\n"
181 "Content-TYPE: text/html; charset=utf-8\n",
184 "Content-TYPE: text/html; charset=utf-8\n",
187 net::HttpVersion(0,0), // Parse error
188 net::HttpVersion(1,0)
193 TEST(HttpResponseHeadersTest, NormalizeHeadersInvalidStatusCode) {
195 "HTTP/1.1 -1 Unknown\n",
200 net::HttpVersion(1,1),
201 net::HttpVersion(1,1)
206 TEST(HttpResponseHeadersTest, NormalizeHeadersEmpty) {
213 net::HttpVersion(0,0), // Parse Error
214 net::HttpVersion(1,0)
219 TEST(HttpResponseHeadersTest, NormalizeHeadersStartWithColon) {
221 "HTTP/1.1 202 Accepted \n"
227 "HTTP/1.1 202 Accepted\n"
232 net::HttpVersion(1,1),
233 net::HttpVersion(1,1)
238 TEST(HttpResponseHeadersTest, NormalizeHeadersStartWithColonAtEOL) {
240 "HTTP/1.1 202 Accepted \n"
246 "HTTP/1.1 202 Accepted\n"
253 net::HttpVersion(1,1),
254 net::HttpVersion(1,1)
259 TEST(HttpResponseHeadersTest, NormalizeHeadersOfWhitepace) {
266 net::HttpVersion(0,0), // Parse error
267 net::HttpVersion(1,0)
272 TEST(HttpResponseHeadersTest, RepeatedSetCookie) {
279 "Set-Cookie: x=1, y=2\n",
282 net::HttpVersion(1,1),
283 net::HttpVersion(1,1)
288 TEST(HttpResponseHeadersTest, GetNormalizedHeader) {
289 std::string headers =
291 "Cache-control: private\n"
292 "cache-Control: no-store\n";
293 HeadersToRaw(&headers);
294 scoped_refptr<net::HttpResponseHeaders> parsed(
295 new net::HttpResponseHeaders(headers));
298 EXPECT_TRUE(parsed->GetNormalizedHeader("cache-control", &value));
299 EXPECT_EQ("private, no-store", value);
302 TEST(HttpResponseHeadersTest, Persist) {
304 net::HttpResponseHeaders::PersistOptions options;
305 const char* raw_headers;
306 const char* expected_headers;
308 { net::HttpResponseHeaders::PERSIST_ALL,
310 "Cache-control:private\n"
311 "cache-Control:no-store\n",
314 "Cache-control: private, no-store\n"
316 { net::HttpResponseHeaders::PERSIST_SANS_HOP_BY_HOP,
318 "connection: keep-alive\n"
324 { net::HttpResponseHeaders::PERSIST_SANS_NON_CACHEABLE |
325 net::HttpResponseHeaders::PERSIST_SANS_HOP_BY_HOP,
329 "Transfer-Encoding: chunked\n"
330 "CoNnection: keep-alive\n"
331 "cache-control: private, no-cache=\"foo\"\n",
334 "cache-control: private, no-cache=\"foo\"\n"
336 { net::HttpResponseHeaders::PERSIST_SANS_NON_CACHEABLE,
339 "Cache-Control: private,no-cache=\"foo, bar\"\n"
343 "Cache-Control: private,no-cache=\"foo, bar\"\n"
345 // ignore bogus no-cache value
346 { net::HttpResponseHeaders::PERSIST_SANS_NON_CACHEABLE,
349 "Cache-Control: private,no-cache=foo\n",
353 "Cache-Control: private,no-cache=foo\n"
355 // ignore bogus no-cache value
356 { net::HttpResponseHeaders::PERSIST_SANS_NON_CACHEABLE,
359 "Cache-Control: private, no-cache=\n",
363 "Cache-Control: private, no-cache=\n"
365 // ignore empty no-cache value
366 { net::HttpResponseHeaders::PERSIST_SANS_NON_CACHEABLE,
369 "Cache-Control: private, no-cache=\"\"\n",
373 "Cache-Control: private, no-cache=\"\"\n"
375 // ignore wrong quotes no-cache value
376 { net::HttpResponseHeaders::PERSIST_SANS_NON_CACHEABLE,
379 "Cache-Control: private, no-cache=\'foo\'\n",
383 "Cache-Control: private, no-cache=\'foo\'\n"
385 // ignore unterminated quotes no-cache value
386 { net::HttpResponseHeaders::PERSIST_SANS_NON_CACHEABLE,
389 "Cache-Control: private, no-cache=\"foo\n",
393 "Cache-Control: private, no-cache=\"foo\n"
396 { net::HttpResponseHeaders::PERSIST_SANS_NON_CACHEABLE,
399 "Cache-Control: private, no-cache=\" foo\t, bar\"\n",
402 "Cache-Control: private, no-cache=\" foo\t, bar\"\n"
404 // header name appears twice, separated by another header
405 { net::HttpResponseHeaders::PERSIST_ALL,
415 // header name appears twice, separated by another header (type 2)
416 { net::HttpResponseHeaders::PERSIST_ALL,
426 // Test filtering of cookie headers.
427 { net::HttpResponseHeaders::PERSIST_SANS_COOKIES,
429 "Set-Cookie: foo=bar; httponly\n"
430 "Set-Cookie: bar=foo\n"
432 "Set-Cookie2: bar2=foo2\n",
437 // Test LWS at the end of a header.
438 { net::HttpResponseHeaders::PERSIST_ALL,
440 "Content-Length: 450 \n"
441 "Content-Encoding: gzip\n",
444 "Content-Length: 450\n"
445 "Content-Encoding: gzip\n"
447 // Test LWS at the end of a header.
448 { net::HttpResponseHeaders::PERSIST_RAW,
450 "Content-Length: 450 \n"
451 "Content-Encoding: gzip\n",
454 "Content-Length: 450\n"
455 "Content-Encoding: gzip\n"
457 // Test filtering of transport security state headers.
458 { net::HttpResponseHeaders::PERSIST_SANS_SECURITY_STATE,
460 "Strict-Transport-Security: max-age=1576800\n"
462 "Public-Key-Pins: max-age=100000; "
463 "pin-sha1=\"ObT42aoSpAqWdY9WfRfL7i0HsVk=\";"
464 "pin-sha1=\"7kW49EVwZG0hSNx41ZO/fUPN0ek=\"",
471 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
472 std::string headers = tests[i].raw_headers;
473 HeadersToRaw(&headers);
474 scoped_refptr<net::HttpResponseHeaders> parsed1(
475 new net::HttpResponseHeaders(headers));
478 parsed1->Persist(&pickle, tests[i].options);
480 PickleIterator iter(pickle);
481 scoped_refptr<net::HttpResponseHeaders> parsed2(
482 new net::HttpResponseHeaders(pickle, &iter));
485 parsed2->GetNormalizedHeaders(&h2);
486 EXPECT_EQ(std::string(tests[i].expected_headers), h2);
490 TEST(HttpResponseHeadersTest, EnumerateHeader_Coalesced) {
491 // Ensure that commas in quoted strings are not regarded as value separators.
492 // Ensure that whitespace following a value is trimmed properly
493 std::string headers =
495 "Cache-control:private , no-cache=\"set-cookie,server\" \n"
496 "cache-Control: no-store\n";
497 HeadersToRaw(&headers);
498 scoped_refptr<net::HttpResponseHeaders> parsed(
499 new net::HttpResponseHeaders(headers));
503 EXPECT_TRUE(parsed->EnumerateHeader(&iter, "cache-control", &value));
504 EXPECT_EQ("private", value);
505 EXPECT_TRUE(parsed->EnumerateHeader(&iter, "cache-control", &value));
506 EXPECT_EQ("no-cache=\"set-cookie,server\"", value);
507 EXPECT_TRUE(parsed->EnumerateHeader(&iter, "cache-control", &value));
508 EXPECT_EQ("no-store", value);
509 EXPECT_FALSE(parsed->EnumerateHeader(&iter, "cache-control", &value));
512 TEST(HttpResponseHeadersTest, EnumerateHeader_Challenge) {
513 // Even though WWW-Authenticate has commas, it should not be treated as
515 std::string headers =
517 "WWW-Authenticate:Digest realm=foobar, nonce=x, domain=y\n"
518 "WWW-Authenticate:Basic realm=quatar\n";
519 HeadersToRaw(&headers);
520 scoped_refptr<net::HttpResponseHeaders> parsed(
521 new net::HttpResponseHeaders(headers));
525 EXPECT_TRUE(parsed->EnumerateHeader(&iter, "WWW-Authenticate", &value));
526 EXPECT_EQ("Digest realm=foobar, nonce=x, domain=y", value);
527 EXPECT_TRUE(parsed->EnumerateHeader(&iter, "WWW-Authenticate", &value));
528 EXPECT_EQ("Basic realm=quatar", value);
529 EXPECT_FALSE(parsed->EnumerateHeader(&iter, "WWW-Authenticate", &value));
532 TEST(HttpResponseHeadersTest, EnumerateHeader_DateValued) {
533 // The comma in a date valued header should not be treated as a
534 // field-value separator
535 std::string headers =
537 "Date: Tue, 07 Aug 2007 23:10:55 GMT\n"
538 "Last-Modified: Wed, 01 Aug 2007 23:23:45 GMT\n";
539 HeadersToRaw(&headers);
540 scoped_refptr<net::HttpResponseHeaders> parsed(
541 new net::HttpResponseHeaders(headers));
544 EXPECT_TRUE(parsed->EnumerateHeader(NULL, "date", &value));
545 EXPECT_EQ("Tue, 07 Aug 2007 23:10:55 GMT", value);
546 EXPECT_TRUE(parsed->EnumerateHeader(NULL, "last-modified", &value));
547 EXPECT_EQ("Wed, 01 Aug 2007 23:23:45 GMT", value);
550 TEST(HttpResponseHeadersTest, DefaultDateToGMT) {
551 // Verify we make the best interpretation when parsing dates that incorrectly
552 // do not end in "GMT" as RFC2616 requires.
553 std::string headers =
555 "Date: Tue, 07 Aug 2007 23:10:55\n"
556 "Last-Modified: Tue, 07 Aug 2007 19:10:55 EDT\n"
557 "Expires: Tue, 07 Aug 2007 23:10:55 UTC\n";
558 HeadersToRaw(&headers);
559 scoped_refptr<net::HttpResponseHeaders> parsed(
560 new net::HttpResponseHeaders(headers));
561 base::Time expected_value;
562 ASSERT_TRUE(base::Time::FromString("Tue, 07 Aug 2007 23:10:55 GMT",
566 // When the timezone is missing, GMT is a good guess as its what RFC2616
568 EXPECT_TRUE(parsed->GetDateValue(&value));
569 EXPECT_EQ(expected_value, value);
570 // If GMT is missing but an RFC822-conforming one is present, use that.
571 EXPECT_TRUE(parsed->GetLastModifiedValue(&value));
572 EXPECT_EQ(expected_value, value);
573 // If an unknown timezone is present, treat like a missing timezone and
574 // default to GMT. The only example of a web server not specifying "GMT"
575 // used "UTC" which is equivalent to GMT.
576 if (parsed->GetExpiresValue(&value))
577 EXPECT_EQ(expected_value, value);
580 TEST(HttpResponseHeadersTest, GetMimeType) {
581 const ContentTypeTestData tests[] = {
582 { "HTTP/1.1 200 OK\n"
583 "Content-type: text/html\n",
587 // Multiple content-type headers should give us the last one.
588 { "HTTP/1.1 200 OK\n"
589 "Content-type: text/html\n"
590 "Content-type: text/html\n",
593 "text/html, text/html" },
594 { "HTTP/1.1 200 OK\n"
595 "Content-type: text/plain\n"
596 "Content-type: text/html\n"
597 "Content-type: text/plain\n"
598 "Content-type: text/html\n",
601 "text/plain, text/html, text/plain, text/html" },
602 // Test charset parsing.
603 { "HTTP/1.1 200 OK\n"
604 "Content-type: text/html\n"
605 "Content-type: text/html; charset=ISO-8859-1\n",
608 "text/html, text/html; charset=ISO-8859-1" },
609 // Test charset in double quotes.
610 { "HTTP/1.1 200 OK\n"
611 "Content-type: text/html\n"
612 "Content-type: text/html; charset=\"ISO-8859-1\"\n",
615 "text/html, text/html; charset=\"ISO-8859-1\"" },
616 // If there are multiple matching content-type headers, we carry
617 // over the charset value.
618 { "HTTP/1.1 200 OK\n"
619 "Content-type: text/html;charset=utf-8\n"
620 "Content-type: text/html\n",
623 "text/html;charset=utf-8, text/html" },
624 // Test single quotes.
625 { "HTTP/1.1 200 OK\n"
626 "Content-type: text/html;charset='utf-8'\n"
627 "Content-type: text/html\n",
630 "text/html;charset='utf-8', text/html" },
631 // Last charset wins if matching content-type.
632 { "HTTP/1.1 200 OK\n"
633 "Content-type: text/html;charset=utf-8\n"
634 "Content-type: text/html;charset=iso-8859-1\n",
637 "text/html;charset=utf-8, text/html;charset=iso-8859-1" },
638 // Charset is ignored if the content types change.
639 { "HTTP/1.1 200 OK\n"
640 "Content-type: text/plain;charset=utf-8\n"
641 "Content-type: text/html\n",
644 "text/plain;charset=utf-8, text/html" },
645 // Empty content-type
646 { "HTTP/1.1 200 OK\n"
652 { "HTTP/1.1 200 OK\n"
653 "Content-type: text/html;charset=\n",
656 "text/html;charset=" },
657 // Multiple charsets, last one wins.
658 { "HTTP/1.1 200 OK\n"
659 "Content-type: text/html;charset=utf-8; charset=iso-8859-1\n",
662 "text/html;charset=utf-8; charset=iso-8859-1" },
664 { "HTTP/1.1 200 OK\n"
665 "Content-type: text/html; foo=utf-8; charset=iso-8859-1\n",
668 "text/html; foo=utf-8; charset=iso-8859-1" },
669 { "HTTP/1.1 200 OK\n"
670 "Content-type: text/html ; charset=utf-8 ; bar=iso-8859-1\n",
673 "text/html ; charset=utf-8 ; bar=iso-8859-1" },
674 // Comma embeded in quotes.
675 { "HTTP/1.1 200 OK\n"
676 "Content-type: text/html ; charset='utf-8,text/plain' ;\n",
678 "utf-8,text/plain", true,
679 "text/html ; charset='utf-8,text/plain' ;" },
680 // Charset with leading spaces.
681 { "HTTP/1.1 200 OK\n"
682 "Content-type: text/html ; charset= 'utf-8' ;\n",
685 "text/html ; charset= 'utf-8' ;" },
686 // Media type comments in mime-type.
687 { "HTTP/1.1 200 OK\n"
688 "Content-type: text/html (html)\n",
691 "text/html (html)" },
692 // Incomplete charset= param
693 { "HTTP/1.1 200 OK\n"
694 "Content-type: text/html; char=\n",
697 "text/html; char=" },
698 // Invalid media type: no slash
699 { "HTTP/1.1 200 OK\n"
700 "Content-type: texthtml\n",
704 // Invalid media type: */*
705 { "HTTP/1.1 200 OK\n"
706 "Content-type: */*\n",
712 for (size_t i = 0; i < arraysize(tests); ++i) {
713 std::string headers(tests[i].raw_headers);
714 HeadersToRaw(&headers);
715 scoped_refptr<net::HttpResponseHeaders> parsed(
716 new net::HttpResponseHeaders(headers));
719 EXPECT_EQ(tests[i].has_mimetype, parsed->GetMimeType(&value));
720 EXPECT_EQ(tests[i].mime_type, value);
722 EXPECT_EQ(tests[i].has_charset, parsed->GetCharset(&value));
723 EXPECT_EQ(tests[i].charset, value);
724 EXPECT_TRUE(parsed->GetNormalizedHeader("content-type", &value));
725 EXPECT_EQ(tests[i].all_content_type, value);
729 TEST(HttpResponseHeadersTest, RequiresValidation) {
732 bool requires_validation;
734 // no expiry info: expires immediately
735 { "HTTP/1.1 200 OK\n"
739 // valid for a little while
740 { "HTTP/1.1 200 OK\n"
741 "cache-control: max-age=10000\n"
745 // expires in the future
746 { "HTTP/1.1 200 OK\n"
747 "date: Wed, 28 Nov 2007 00:40:11 GMT\n"
748 "expires: Wed, 28 Nov 2007 01:00:00 GMT\n"
753 { "HTTP/1.1 200 OK\n"
754 "date: Wed, 28 Nov 2007 00:40:11 GMT\n"
755 "expires: Wed, 28 Nov 2007 00:00:00 GMT\n"
759 // max-age trumps expires
760 { "HTTP/1.1 200 OK\n"
761 "date: Wed, 28 Nov 2007 00:40:11 GMT\n"
762 "expires: Wed, 28 Nov 2007 00:00:00 GMT\n"
763 "cache-control: max-age=10000\n"
767 // last-modified heuristic: modified a while ago
768 { "HTTP/1.1 200 OK\n"
769 "date: Wed, 28 Nov 2007 00:40:11 GMT\n"
770 "last-modified: Wed, 27 Nov 2007 08:00:00 GMT\n"
774 { "HTTP/1.1 203 Non-Authoritative Information\n"
775 "date: Wed, 28 Nov 2007 00:40:11 GMT\n"
776 "last-modified: Wed, 27 Nov 2007 08:00:00 GMT\n"
780 { "HTTP/1.1 206 Partial Content\n"
781 "date: Wed, 28 Nov 2007 00:40:11 GMT\n"
782 "last-modified: Wed, 27 Nov 2007 08:00:00 GMT\n"
786 // last-modified heuristic: modified recently
787 { "HTTP/1.1 200 OK\n"
788 "date: Wed, 28 Nov 2007 00:40:11 GMT\n"
789 "last-modified: Wed, 28 Nov 2007 00:40:10 GMT\n"
793 { "HTTP/1.1 203 Non-Authoritative Information\n"
794 "date: Wed, 28 Nov 2007 00:40:11 GMT\n"
795 "last-modified: Wed, 28 Nov 2007 00:40:10 GMT\n"
799 { "HTTP/1.1 206 Partial Content\n"
800 "date: Wed, 28 Nov 2007 00:40:11 GMT\n"
801 "last-modified: Wed, 28 Nov 2007 00:40:10 GMT\n"
805 // cached permanent redirect
806 { "HTTP/1.1 301 Moved Permanently\n"
810 // cached redirect: not reusable even though by default it would be
811 { "HTTP/1.1 300 Multiple Choices\n"
812 "Cache-Control: no-cache\n"
816 // cached forever by default
817 { "HTTP/1.1 410 Gone\n"
821 // cached temporary redirect: not reusable
822 { "HTTP/1.1 302 Found\n"
826 // cached temporary redirect: reusable
827 { "HTTP/1.1 302 Found\n"
828 "cache-control: max-age=10000\n"
832 // cache-control: max-age=N overrides expires: date in the past
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:20:11 GMT\n"
836 "cache-control: max-age=10000\n"
840 // cache-control: no-store overrides expires: in the future
841 { "HTTP/1.1 200 OK\n"
842 "date: Wed, 28 Nov 2007 00:40:11 GMT\n"
843 "expires: Wed, 29 Nov 2007 00:40:11 GMT\n"
844 "cache-control: no-store,private,no-cache=\"foo\"\n"
848 // pragma: no-cache overrides last-modified heuristic
849 { "HTTP/1.1 200 OK\n"
850 "date: Wed, 28 Nov 2007 00:40:11 GMT\n"
851 "last-modified: Wed, 27 Nov 2007 08:00:00 GMT\n"
856 // TODO(darin): add many many more tests here
858 base::Time request_time, response_time, current_time;
859 base::Time::FromString("Wed, 28 Nov 2007 00:40:09 GMT", &request_time);
860 base::Time::FromString("Wed, 28 Nov 2007 00:40:12 GMT", &response_time);
861 base::Time::FromString("Wed, 28 Nov 2007 00:45:20 GMT", ¤t_time);
863 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
864 std::string headers(tests[i].headers);
865 HeadersToRaw(&headers);
866 scoped_refptr<net::HttpResponseHeaders> parsed(
867 new net::HttpResponseHeaders(headers));
869 bool requires_validation =
870 parsed->RequiresValidation(request_time, response_time, current_time);
871 EXPECT_EQ(tests[i].requires_validation, requires_validation);
875 TEST(HttpResponseHeadersTest, Update) {
877 const char* orig_headers;
878 const char* new_headers;
879 const char* expected_headers;
881 { "HTTP/1.1 200 OK\n",
883 "HTTP/1/1 304 Not Modified\n"
884 "connection: keep-alive\n"
885 "Cache-control: max-age=10000\n",
888 "Cache-control: max-age=10000\n"
890 { "HTTP/1.1 200 OK\n"
892 "Cache-control: private\n",
894 "HTTP/1/1 304 Not Modified\n"
895 "connection: keep-alive\n"
896 "Cache-control: max-age=10000\n",
899 "Cache-control: max-age=10000\n"
902 { "HTTP/1.1 200 OK\n"
904 "Cache-control: private\n",
906 "HTTP/1/1 304 Not Modified\n"
907 "connection: keep-alive\n"
908 "Cache-CONTROL: max-age=10000\n",
911 "Cache-CONTROL: max-age=10000\n"
914 { "HTTP/1.1 200 OK\n"
915 "Content-Length: 450\n",
917 "HTTP/1/1 304 Not Modified\n"
918 "connection: keep-alive\n"
919 "Cache-control: max-age=10001 \n",
922 "Cache-control: max-age=10001\n"
923 "Content-Length: 450\n"
925 { "HTTP/1.1 200 OK\n"
926 "X-Frame-Options: DENY\n",
928 "HTTP/1/1 304 Not Modified\n"
929 "X-Frame-Options: ALLOW\n",
932 "X-Frame-Options: DENY\n",
934 { "HTTP/1.1 200 OK\n"
935 "X-WebKit-CSP: default-src 'none'\n",
937 "HTTP/1/1 304 Not Modified\n"
938 "X-WebKit-CSP: default-src *\n",
941 "X-WebKit-CSP: default-src 'none'\n",
943 { "HTTP/1.1 200 OK\n"
944 "X-XSS-Protection: 1\n",
946 "HTTP/1/1 304 Not Modified\n"
947 "X-XSS-Protection: 0\n",
950 "X-XSS-Protection: 1\n",
952 { "HTTP/1.1 200 OK\n",
954 "HTTP/1/1 304 Not Modified\n"
955 "X-Content-Type-Options: nosniff\n",
961 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
962 std::string orig_headers(tests[i].orig_headers);
963 HeadersToRaw(&orig_headers);
964 scoped_refptr<net::HttpResponseHeaders> parsed(
965 new net::HttpResponseHeaders(orig_headers));
967 std::string new_headers(tests[i].new_headers);
968 HeadersToRaw(&new_headers);
969 scoped_refptr<net::HttpResponseHeaders> new_parsed(
970 new net::HttpResponseHeaders(new_headers));
972 parsed->Update(*new_parsed.get());
974 std::string resulting_headers;
975 parsed->GetNormalizedHeaders(&resulting_headers);
976 EXPECT_EQ(std::string(tests[i].expected_headers), resulting_headers);
980 TEST(HttpResponseHeadersTest, EnumerateHeaderLines) {
983 const char* expected_lines;
985 { "HTTP/1.1 200 OK\n",
989 { "HTTP/1.1 200 OK\n"
994 { "HTTP/1.1 200 OK\n"
999 "Foo: 1\nBar: 2\nFoo: 3\n"
1001 { "HTTP/1.1 200 OK\n"
1007 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
1008 std::string headers(tests[i].headers);
1009 HeadersToRaw(&headers);
1010 scoped_refptr<net::HttpResponseHeaders> parsed(
1011 new net::HttpResponseHeaders(headers));
1013 std::string name, value, lines;
1016 while (parsed->EnumerateHeaderLines(&iter, &name, &value)) {
1019 lines.append(value);
1023 EXPECT_EQ(std::string(tests[i].expected_lines), lines);
1027 TEST(HttpResponseHeadersTest, IsRedirect) {
1029 const char* headers;
1030 const char* location;
1033 { "HTTP/1.1 200 OK\n",
1037 { "HTTP/1.1 301 Moved\n"
1038 "Location: http://foopy/\n",
1042 { "HTTP/1.1 301 Moved\n"
1047 // we use the first location header as the target of the redirect
1048 { "HTTP/1.1 301 Moved\n"
1049 "Location: http://foo/\n"
1050 "Location: http://bar/\n",
1054 // we use the first _valid_ location header as the target of the redirect
1055 { "HTTP/1.1 301 Moved\n"
1057 "Location: http://bar/\n",
1061 // bug 1050541 (location header w/ an unescaped comma)
1062 { "HTTP/1.1 301 Moved\n"
1063 "Location: http://foo/bar,baz.html\n",
1064 "http://foo/bar,baz.html",
1067 // bug 1224617 (location header w/ non-ASCII bytes)
1068 { "HTTP/1.1 301 Moved\n"
1069 "Location: http://foo/bar?key=\xE4\xF6\xFC\n",
1070 "http://foo/bar?key=%E4%F6%FC",
1073 // Shift_JIS, Big5, and GBK contain multibyte characters with the trailing
1074 // byte falling in the ASCII range.
1075 { "HTTP/1.1 301 Moved\n"
1076 "Location: http://foo/bar?key=\x81\x5E\xD8\xBF\n",
1077 "http://foo/bar?key=%81^%D8%BF",
1080 { "HTTP/1.1 301 Moved\n"
1081 "Location: http://foo/bar?key=\x82\x40\xBD\xC4\n",
1082 "http://foo/bar?key=%82@%BD%C4",
1085 { "HTTP/1.1 301 Moved\n"
1086 "Location: http://foo/bar?key=\x83\x5C\x82\x5D\xCB\xD7\n",
1087 "http://foo/bar?key=%83\\%82]%CB%D7",
1091 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
1092 std::string headers(tests[i].headers);
1093 HeadersToRaw(&headers);
1094 scoped_refptr<net::HttpResponseHeaders> parsed(
1095 new net::HttpResponseHeaders(headers));
1097 std::string location;
1098 EXPECT_EQ(parsed->IsRedirect(&location), tests[i].is_redirect);
1099 EXPECT_EQ(location, tests[i].location);
1103 TEST(HttpResponseHeadersTest, GetContentLength) {
1105 const char* headers;
1108 { "HTTP/1.1 200 OK\n",
1111 { "HTTP/1.1 200 OK\n"
1112 "Content-Length: 10\n",
1115 { "HTTP/1.1 200 OK\n"
1116 "Content-Length: \n",
1119 { "HTTP/1.1 200 OK\n"
1120 "Content-Length: abc\n",
1123 { "HTTP/1.1 200 OK\n"
1124 "Content-Length: -10\n",
1127 { "HTTP/1.1 200 OK\n"
1128 "Content-Length: +10\n",
1131 { "HTTP/1.1 200 OK\n"
1132 "Content-Length: 23xb5\n",
1135 { "HTTP/1.1 200 OK\n"
1136 "Content-Length: 0xA\n",
1139 { "HTTP/1.1 200 OK\n"
1140 "Content-Length: 010\n",
1143 // Content-Length too big, will overflow an int64
1144 { "HTTP/1.1 200 OK\n"
1145 "Content-Length: 40000000000000000000\n",
1148 { "HTTP/1.1 200 OK\n"
1149 "Content-Length: 10\n",
1152 { "HTTP/1.1 200 OK\n"
1153 "Content-Length: 10 \n",
1156 { "HTTP/1.1 200 OK\n"
1157 "Content-Length: \t10\n",
1160 { "HTTP/1.1 200 OK\n"
1161 "Content-Length: \v10\n",
1164 { "HTTP/1.1 200 OK\n"
1165 "Content-Length: \f10\n",
1168 { "HTTP/1.1 200 OK\n"
1169 "cOnTeNt-LENgth: 33\n",
1172 { "HTTP/1.1 200 OK\n"
1173 "Content-Length: 34\r\n",
1177 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
1178 std::string headers(tests[i].headers);
1179 HeadersToRaw(&headers);
1180 scoped_refptr<net::HttpResponseHeaders> parsed(
1181 new net::HttpResponseHeaders(headers));
1183 EXPECT_EQ(tests[i].expected_len, parsed->GetContentLength());
1187 TEST(HttpResponseHeaders, GetContentRange) {
1189 const char* headers;
1190 bool expected_return_value;
1191 int64 expected_first_byte_position;
1192 int64 expected_last_byte_position;
1193 int64 expected_instance_size;
1195 { "HTTP/1.1 206 Partial Content",
1201 { "HTTP/1.1 206 Partial Content\n"
1208 { "HTTP/1.1 206 Partial Content\n"
1209 "Content-Range: megabytes 0-10/50",
1215 { "HTTP/1.1 206 Partial Content\n"
1216 "Content-Range: 0-10/50",
1222 { "HTTP/1.1 206 Partial Content\n"
1223 "Content-Range: Bytes 0-50/51",
1229 { "HTTP/1.1 206 Partial Content\n"
1230 "Content-Range: bytes 0-50/51",
1236 { "HTTP/1.1 206 Partial Content\n"
1237 "Content-Range: bytes\t0-50/51",
1243 { "HTTP/1.1 206 Partial Content\n"
1244 "Content-Range: bytes 0-50/51",
1250 { "HTTP/1.1 206 Partial Content\n"
1251 "Content-Range: bytes 0 - 50 \t / \t51",
1257 { "HTTP/1.1 206 Partial Content\n"
1258 "Content-Range: bytes 0\t-\t50\t/\t51\t",
1264 { "HTTP/1.1 206 Partial Content\n"
1265 "Content-Range: \tbytes\t\t\t 0\t-\t50\t/\t51\t",
1271 { "HTTP/1.1 206 Partial Content\n"
1272 "Content-Range: \t bytes \t 0 - 50 / 5 1",
1278 { "HTTP/1.1 206 Partial Content\n"
1279 "Content-Range: \t bytes \t 0 - 5 0 / 51",
1285 { "HTTP/1.1 206 Partial Content\n"
1286 "Content-Range: bytes 50-0/51",
1292 { "HTTP/1.1 416 Requested range not satisfiable\n"
1293 "Content-Range: bytes * /*",
1299 { "HTTP/1.1 416 Requested range not satisfiable\n"
1300 "Content-Range: bytes * / * ",
1306 { "HTTP/1.1 206 Partial Content\n"
1307 "Content-Range: bytes 0-50/*",
1313 { "HTTP/1.1 206 Partial Content\n"
1314 "Content-Range: bytes 0-50 / * ",
1320 { "HTTP/1.1 206 Partial Content\n"
1321 "Content-Range: bytes 0-10000000000/10000000001",
1327 { "HTTP/1.1 206 Partial Content\n"
1328 "Content-Range: bytes 0-10000000000/10000000000",
1334 // 64 bits wraparound.
1335 { "HTTP/1.1 206 Partial Content\n"
1336 "Content-Range: bytes 0 - 9223372036854775807 / 100",
1342 // 64 bits wraparound.
1343 { "HTTP/1.1 206 Partial Content\n"
1344 "Content-Range: bytes 0 - 100 / -9223372036854775808",
1350 { "HTTP/1.1 206 Partial Content\n"
1351 "Content-Range: bytes */50",
1357 { "HTTP/1.1 206 Partial Content\n"
1358 "Content-Range: bytes 0-50/10",
1364 { "HTTP/1.1 206 Partial Content\n"
1365 "Content-Range: bytes 40-50/45",
1371 { "HTTP/1.1 206 Partial Content\n"
1372 "Content-Range: bytes 0-50/-10",
1378 { "HTTP/1.1 206 Partial Content\n"
1379 "Content-Range: bytes 0-0/1",
1385 { "HTTP/1.1 206 Partial Content\n"
1386 "Content-Range: bytes 0-40000000000000000000/40000000000000000001",
1392 { "HTTP/1.1 206 Partial Content\n"
1393 "Content-Range: bytes 1-/100",
1399 { "HTTP/1.1 206 Partial Content\n"
1400 "Content-Range: bytes -/100",
1406 { "HTTP/1.1 206 Partial Content\n"
1407 "Content-Range: bytes -1/100",
1413 { "HTTP/1.1 206 Partial Content\n"
1414 "Content-Range: bytes 0-1233/*",
1420 { "HTTP/1.1 206 Partial Content\n"
1421 "Content-Range: bytes -123 - -1/100",
1428 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
1429 std::string headers(tests[i].headers);
1430 HeadersToRaw(&headers);
1431 scoped_refptr<net::HttpResponseHeaders> parsed(
1432 new net::HttpResponseHeaders(headers));
1434 int64 first_byte_position;
1435 int64 last_byte_position;
1436 int64 instance_size;
1437 bool return_value = parsed->GetContentRange(&first_byte_position,
1438 &last_byte_position,
1440 EXPECT_EQ(tests[i].expected_return_value, return_value);
1441 EXPECT_EQ(tests[i].expected_first_byte_position, first_byte_position);
1442 EXPECT_EQ(tests[i].expected_last_byte_position, last_byte_position);
1443 EXPECT_EQ(tests[i].expected_instance_size, instance_size);
1447 TEST(HttpResponseHeadersTest, IsKeepAlive) {
1449 const char* headers;
1450 bool expected_keep_alive;
1452 // The status line fabricated by HttpNetworkTransaction for a 0.9 response.
1454 { "HTTP/0.9 200 OK",
1457 // This could come from a broken server. Treated as 1.0 because it has a
1459 { "HTTP/0.9 200 OK\n"
1460 "connection: keep-alive\n",
1463 { "HTTP/1.1 200 OK\n",
1466 { "HTTP/1.0 200 OK\n",
1469 { "HTTP/1.0 200 OK\n"
1470 "connection: close\n",
1473 { "HTTP/1.0 200 OK\n"
1474 "connection: keep-alive\n",
1477 { "HTTP/1.0 200 OK\n"
1478 "connection: kEeP-AliVe\n",
1481 { "HTTP/1.0 200 OK\n"
1482 "connection: keep-aliveX\n",
1485 { "HTTP/1.1 200 OK\n"
1486 "connection: close\n",
1489 { "HTTP/1.1 200 OK\n"
1490 "connection: keep-alive\n",
1493 { "HTTP/1.0 200 OK\n"
1494 "proxy-connection: close\n",
1497 { "HTTP/1.0 200 OK\n"
1498 "proxy-connection: keep-alive\n",
1501 { "HTTP/1.1 200 OK\n"
1502 "proxy-connection: close\n",
1505 { "HTTP/1.1 200 OK\n"
1506 "proxy-connection: keep-alive\n",
1510 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
1511 std::string headers(tests[i].headers);
1512 HeadersToRaw(&headers);
1513 scoped_refptr<net::HttpResponseHeaders> parsed(
1514 new net::HttpResponseHeaders(headers));
1516 EXPECT_EQ(tests[i].expected_keep_alive, parsed->IsKeepAlive());
1520 TEST(HttpResponseHeadersTest, HasStrongValidators) {
1522 const char* headers;
1523 bool expected_result;
1525 { "HTTP/0.9 200 OK",
1528 { "HTTP/1.0 200 OK\n"
1529 "Date: Wed, 28 Nov 2007 01:40:10 GMT\n"
1530 "Last-Modified: Wed, 28 Nov 2007 00:40:10 GMT\n"
1534 { "HTTP/1.1 200 OK\n"
1535 "Date: Wed, 28 Nov 2007 01:40:10 GMT\n"
1536 "Last-Modified: Wed, 28 Nov 2007 00:40:10 GMT\n"
1540 { "HTTP/1.1 200 OK\n"
1541 "Date: Wed, 28 Nov 2007 00:41:10 GMT\n"
1542 "Last-Modified: Wed, 28 Nov 2007 00:40:10 GMT\n",
1545 { "HTTP/1.1 200 OK\n"
1546 "Date: Wed, 28 Nov 2007 00:41:09 GMT\n"
1547 "Last-Modified: Wed, 28 Nov 2007 00:40:10 GMT\n",
1550 { "HTTP/1.1 200 OK\n"
1554 // This is not really a weak etag:
1555 { "HTTP/1.1 200 OK\n"
1556 "etag: \"w/foo\"\n",
1559 // This is a weak etag:
1560 { "HTTP/1.1 200 OK\n"
1561 "etag: w/\"foo\"\n",
1564 { "HTTP/1.1 200 OK\n"
1565 "etag: W / \"foo\"\n",
1569 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
1570 std::string headers(tests[i].headers);
1571 HeadersToRaw(&headers);
1572 scoped_refptr<net::HttpResponseHeaders> parsed(
1573 new net::HttpResponseHeaders(headers));
1575 EXPECT_EQ(tests[i].expected_result, parsed->HasStrongValidators()) <<
1576 "Failed test case " << i;
1580 TEST(HttpResponseHeadersTest, GetStatusText) {
1581 std::string headers("HTTP/1.1 404 Not Found");
1582 HeadersToRaw(&headers);
1583 scoped_refptr<net::HttpResponseHeaders> parsed(
1584 new net::HttpResponseHeaders(headers));
1585 EXPECT_EQ(std::string("Not Found"), parsed->GetStatusText());
1588 TEST(HttpResponseHeadersTest, GetStatusTextMissing) {
1589 std::string headers("HTTP/1.1 404");
1590 HeadersToRaw(&headers);
1591 scoped_refptr<net::HttpResponseHeaders> parsed(
1592 new net::HttpResponseHeaders(headers));
1593 // Since the status line gets normalized, we have OK
1594 EXPECT_EQ(std::string("OK"), parsed->GetStatusText());
1597 TEST(HttpResponseHeadersTest, GetStatusTextMultiSpace) {
1598 std::string headers("HTTP/1.0 404 Not Found");
1599 HeadersToRaw(&headers);
1600 scoped_refptr<net::HttpResponseHeaders> parsed(
1601 new net::HttpResponseHeaders(headers));
1602 EXPECT_EQ(std::string("Not Found"), parsed->GetStatusText());
1605 TEST(HttpResponseHeadersTest, GetStatusBadStatusLine) {
1606 std::string headers("Foo bar.");
1607 HeadersToRaw(&headers);
1608 scoped_refptr<net::HttpResponseHeaders> parsed(
1609 new net::HttpResponseHeaders(headers));
1610 // The bad status line would have gotten rewritten as
1612 EXPECT_EQ(std::string("OK"), parsed->GetStatusText());
1615 TEST(HttpResponseHeadersTest, AddHeader) {
1617 const char* orig_headers;
1618 const char* new_header;
1619 const char* expected_headers;
1621 { "HTTP/1.1 200 OK\n"
1622 "connection: keep-alive\n"
1623 "Cache-control: max-age=10000\n",
1625 "Content-Length: 450",
1628 "connection: keep-alive\n"
1629 "Cache-control: max-age=10000\n"
1630 "Content-Length: 450\n"
1632 { "HTTP/1.1 200 OK\n"
1633 "connection: keep-alive\n"
1634 "Cache-control: max-age=10000 \n",
1636 "Content-Length: 450 ",
1639 "connection: keep-alive\n"
1640 "Cache-control: max-age=10000\n"
1641 "Content-Length: 450\n"
1645 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
1646 std::string orig_headers(tests[i].orig_headers);
1647 HeadersToRaw(&orig_headers);
1648 scoped_refptr<net::HttpResponseHeaders> parsed(
1649 new net::HttpResponseHeaders(orig_headers));
1651 std::string new_header(tests[i].new_header);
1652 parsed->AddHeader(new_header);
1654 std::string resulting_headers;
1655 parsed->GetNormalizedHeaders(&resulting_headers);
1656 EXPECT_EQ(std::string(tests[i].expected_headers), resulting_headers);
1660 TEST(HttpResponseHeadersTest, RemoveHeader) {
1662 const char* orig_headers;
1663 const char* to_remove;
1664 const char* expected_headers;
1666 { "HTTP/1.1 200 OK\n"
1667 "connection: keep-alive\n"
1668 "Cache-control: max-age=10000\n"
1669 "Content-Length: 450\n",
1674 "connection: keep-alive\n"
1675 "Cache-control: max-age=10000\n"
1677 { "HTTP/1.1 200 OK\n"
1678 "connection: keep-alive \n"
1679 "Content-Length : 450 \n"
1680 "Cache-control: max-age=10000\n",
1685 "connection: keep-alive\n"
1686 "Cache-control: max-age=10000\n"
1690 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
1691 std::string orig_headers(tests[i].orig_headers);
1692 HeadersToRaw(&orig_headers);
1693 scoped_refptr<net::HttpResponseHeaders> parsed(
1694 new net::HttpResponseHeaders(orig_headers));
1696 std::string name(tests[i].to_remove);
1697 parsed->RemoveHeader(name);
1699 std::string resulting_headers;
1700 parsed->GetNormalizedHeaders(&resulting_headers);
1701 EXPECT_EQ(std::string(tests[i].expected_headers), resulting_headers);
1705 TEST(HttpResponseHeadersTest, RemoveIndividualHeader) {
1707 const char* orig_headers;
1708 const char* to_remove_name;
1709 const char* to_remove_value;
1710 const char* expected_headers;
1712 { "HTTP/1.1 200 OK\n"
1713 "connection: keep-alive\n"
1714 "Cache-control: max-age=10000\n"
1715 "Content-Length: 450\n",
1722 "connection: keep-alive\n"
1723 "Cache-control: max-age=10000\n"
1725 { "HTTP/1.1 200 OK\n"
1726 "connection: keep-alive \n"
1727 "Content-Length : 450 \n"
1728 "Cache-control: max-age=10000\n",
1735 "connection: keep-alive\n"
1736 "Cache-control: max-age=10000\n"
1738 { "HTTP/1.1 200 OK\n"
1739 "connection: keep-alive \n"
1740 "Content-Length: 450\n"
1741 "Cache-control: max-age=10000\n",
1743 "Content-Length", // Matching name.
1745 "999", // Mismatching value.
1748 "connection: keep-alive\n"
1749 "Content-Length: 450\n"
1750 "Cache-control: max-age=10000\n"
1752 { "HTTP/1.1 200 OK\n"
1753 "connection: keep-alive \n"
1756 "Cache-control: max-age=10000\n",
1760 "bar, baz", // Space in value.
1763 "connection: keep-alive\n"
1765 "Cache-control: max-age=10000\n"
1767 { "HTTP/1.1 200 OK\n"
1768 "connection: keep-alive \n"
1770 "Cache-control: max-age=10000\n",
1774 "baz", // Only partial match -> ignored.
1777 "connection: keep-alive\n"
1779 "Cache-control: max-age=10000\n"
1783 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
1784 std::string orig_headers(tests[i].orig_headers);
1785 HeadersToRaw(&orig_headers);
1786 scoped_refptr<net::HttpResponseHeaders> parsed(
1787 new net::HttpResponseHeaders(orig_headers));
1789 std::string name(tests[i].to_remove_name);
1790 std::string value(tests[i].to_remove_value);
1791 parsed->RemoveHeaderLine(name, value);
1793 std::string resulting_headers;
1794 parsed->GetNormalizedHeaders(&resulting_headers);
1795 EXPECT_EQ(std::string(tests[i].expected_headers), resulting_headers);
1799 TEST(HttpResponseHeadersTest, ReplaceStatus) {
1801 const char* orig_headers;
1802 const char* new_status;
1803 const char* expected_headers;
1805 { "HTTP/1.1 206 Partial Content\n"
1806 "connection: keep-alive\n"
1807 "Cache-control: max-age=10000\n"
1808 "Content-Length: 450\n",
1813 "connection: keep-alive\n"
1814 "Cache-control: max-age=10000\n"
1815 "Content-Length: 450\n"
1817 { "HTTP/1.1 200 OK\n"
1818 "connection: keep-alive\n",
1820 "HTTP/1.1 304 Not Modified",
1822 "HTTP/1.1 304 Not Modified\n"
1823 "connection: keep-alive\n"
1825 { "HTTP/1.1 200 OK\n"
1826 "connection: keep-alive \n"
1827 "Content-Length : 450 \n"
1828 "Cache-control: max-age=10000\n",
1830 "HTTP/1//1 304 Not Modified",
1832 "HTTP/1.0 304 Not Modified\n"
1833 "connection: keep-alive\n"
1834 "Content-Length: 450\n"
1835 "Cache-control: max-age=10000\n"
1839 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
1840 std::string orig_headers(tests[i].orig_headers);
1841 HeadersToRaw(&orig_headers);
1842 scoped_refptr<net::HttpResponseHeaders> parsed(
1843 new net::HttpResponseHeaders(orig_headers));
1845 std::string name(tests[i].new_status);
1846 parsed->ReplaceStatusLine(name);
1848 std::string resulting_headers;
1849 parsed->GetNormalizedHeaders(&resulting_headers);
1850 EXPECT_EQ(std::string(tests[i].expected_headers), resulting_headers);
1854 TEST(HttpResponseHeadersTest, ToNetLogParamAndBackAgain) {
1855 std::string headers("HTTP/1.1 404\n"
1856 "Content-Length: 450\n"
1857 "Connection: keep-alive\n");
1858 HeadersToRaw(&headers);
1859 scoped_refptr<net::HttpResponseHeaders> parsed(
1860 new net::HttpResponseHeaders(headers));
1862 scoped_ptr<base::Value> event_param(
1863 parsed->NetLogCallback(net::NetLog::LOG_ALL_BUT_BYTES));
1864 scoped_refptr<net::HttpResponseHeaders> recreated;
1866 ASSERT_TRUE(net::HttpResponseHeaders::FromNetLogParam(event_param.get(),
1868 ASSERT_TRUE(recreated.get());
1869 EXPECT_EQ(parsed->GetHttpVersion(), recreated->GetHttpVersion());
1870 EXPECT_EQ(parsed->response_code(), recreated->response_code());
1871 EXPECT_EQ(parsed->GetContentLength(), recreated->GetContentLength());
1872 EXPECT_EQ(parsed->IsKeepAlive(), recreated->IsKeepAlive());
1874 std::string normalized_parsed;
1875 parsed->GetNormalizedHeaders(&normalized_parsed);
1876 std::string normalized_recreated;
1877 parsed->GetNormalizedHeaders(&normalized_recreated);
1878 EXPECT_EQ(normalized_parsed, normalized_recreated);
1881 #if defined(SPDY_PROXY_AUTH_ORIGIN)
1882 TEST(HttpResponseHeadersTest, GetProxyBypassInfo) {
1884 const char* headers;
1885 bool expected_result;
1886 int64 expected_retry_delay;
1887 bool expected_bypass_all;
1889 { "HTTP/1.1 200 OK\n"
1890 "Content-Length: 999\n",
1895 { "HTTP/1.1 200 OK\n"
1896 "connection: keep-alive\n"
1897 "Content-Length: 999\n",
1902 { "HTTP/1.1 200 OK\n"
1903 "connection: keep-alive\n"
1904 "Chrome-Proxy: bypass=86400\n"
1905 "Content-Length: 999\n",
1910 { "HTTP/1.1 200 OK\n"
1911 "connection: keep-alive\n"
1912 "Chrome-Proxy: bypass=0\n"
1913 "Content-Length: 999\n",
1918 { "HTTP/1.1 200 OK\n"
1919 "connection: keep-alive\n"
1920 "Chrome-Proxy: bypass=-1\n"
1921 "Content-Length: 999\n",
1926 { "HTTP/1.1 200 OK\n"
1927 "connection: keep-alive\n"
1928 "Chrome-Proxy: bypass=xyz\n"
1929 "Content-Length: 999\n",
1934 { "HTTP/1.1 200 OK\n"
1935 "connection: keep-alive\n"
1936 "Chrome-Proxy: bypass\n"
1937 "Content-Length: 999\n",
1942 { "HTTP/1.1 200 OK\n"
1943 "connection: keep-alive\n"
1944 "Chrome-Proxy: foo=abc, bypass=86400\n"
1945 "Content-Length: 999\n",
1950 { "HTTP/1.1 200 OK\n"
1951 "connection: keep-alive\n"
1952 "Chrome-Proxy: bypass=86400, bar=abc\n"
1953 "Content-Length: 999\n",
1958 { "HTTP/1.1 200 OK\n"
1959 "connection: keep-alive\n"
1960 "Chrome-Proxy: bypass=3600\n"
1961 "Chrome-Proxy: bypass=86400\n"
1962 "Content-Length: 999\n",
1967 { "HTTP/1.1 200 OK\n"
1968 "connection: keep-alive\n"
1969 "Chrome-Proxy: bypass=3600, bypass=86400\n"
1970 "Content-Length: 999\n",
1975 { "HTTP/1.1 200 OK\n"
1976 "connection: keep-alive\n"
1977 "Chrome-Proxy: bypass=, bypass=86400\n"
1978 "Content-Length: 999\n",
1983 { "HTTP/1.1 200 OK\n"
1984 "connection: keep-alive\n"
1985 "Chrome-Proxy: bypass\n"
1986 "Chrome-Proxy: bypass=86400\n"
1987 "Content-Length: 999\n",
1992 { "HTTP/1.1 200 OK\n"
1993 "connection: keep-alive\n"
1994 "Chrome-Proxy: block=, block=3600\n"
1995 "Content-Length: 999\n",
2000 { "HTTP/1.1 200 OK\n"
2001 "connection: keep-alive\n"
2002 "Chrome-Proxy: bypass=86400, block=3600\n"
2003 "Content-Length: 999\n",
2008 { "HTTP/1.1 200 OK\n"
2009 "connection: proxy-bypass\n"
2010 "Chrome-Proxy: block=, bypass=86400\n"
2011 "Content-Length: 999\n",
2016 { "HTTP/1.1 200 OK\n"
2017 "connection: proxy-bypass\n"
2018 "Chrome-Proxy: block=-1\n"
2019 "Content-Length: 999\n",
2024 { "HTTP/1.1 200 OK\n"
2025 "connection: proxy-bypass\n"
2026 "Chrome-Proxy: block=99999999999999999999\n"
2027 "Content-Length: 999\n",
2033 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
2034 std::string headers(tests[i].headers);
2035 HeadersToRaw(&headers);
2036 scoped_refptr<net::HttpResponseHeaders> parsed(
2037 new net::HttpResponseHeaders(headers));
2039 net::HttpResponseHeaders::ChromeProxyInfo chrome_proxy_info;
2040 EXPECT_EQ(tests[i].expected_result,
2041 parsed->GetChromeProxyInfo(&chrome_proxy_info));
2042 EXPECT_EQ(tests[i].expected_retry_delay,
2043 chrome_proxy_info.bypass_duration.InSeconds());
2044 EXPECT_EQ(tests[i].expected_bypass_all,
2045 chrome_proxy_info.bypass_all);
2049 TEST(HttpResponseHeadersTest, IsChromeProxyResponse) {
2051 const char* headers;
2052 bool expected_result;
2054 { "HTTP/1.1 200 OK\n"
2055 "Via: 1.1 Chrome-Proxy\n",
2058 { "HTTP/1.1 200 OK\n"
2059 "Via: 1.1 Chrome-Compression-Proxy\n",
2062 { "HTTP/1.1 200 OK\n"
2063 "Via: 1.0 Chrome-Compression-Proxy\n",
2066 { "HTTP/1.1 200 OK\n"
2067 "Via: 1.1 Foo-Bar, 1.1 Chrome-Compression-Proxy\n",
2070 { "HTTP/1.1 200 OK\n"
2071 "Via: 1.1 Chrome-Compression-Proxy, 1.1 Bar-Foo\n",
2074 { "HTTP/1.1 200 OK\n"
2075 "Via: 1.1 chrome-compression-proxy\n",
2078 { "HTTP/1.1 200 OK\n"
2079 "Via: 1.1 Foo-Bar\n"
2080 "Via: 1.1 Chrome-Compression-Proxy\n",
2083 { "HTTP/1.1 200 OK\n"
2084 "Via: 1.1 Chrome-Proxy\n",
2087 { "HTTP/1.1 200 OK\n"
2088 "Via: 1.1 Chrome Compression Proxy\n",
2091 { "HTTP/1.1 200 OK\n"
2092 "Via: 1.1 Foo-Bar, 1.1 Chrome Compression Proxy\n",
2095 { "HTTP/1.1 200 OK\n"
2096 "Via: 1.1 Chrome Compression Proxy, 1.1 Bar-Foo\n",
2099 { "HTTP/1.1 200 OK\n"
2100 "Via: 1.1 chrome compression proxy\n",
2103 { "HTTP/1.1 200 OK\n"
2104 "Via: 1.1 Foo-Bar\n"
2105 "Via: 1.1 Chrome Compression Proxy\n",
2109 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
2110 std::string headers(tests[i].headers);
2111 HeadersToRaw(&headers);
2112 scoped_refptr<net::HttpResponseHeaders> parsed(
2113 new net::HttpResponseHeaders(headers));
2115 EXPECT_EQ(tests[i].expected_result, parsed->IsChromeProxyResponse());
2118 #endif // defined(SPDY_PROXY_AUTH_ORIGIN)