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_byte_range.h"
13 #include "net/http/http_response_headers.h"
14 #include "testing/gtest/include/gtest/gtest.h"
19 const char* raw_headers
;
20 const char* expected_headers
;
21 int expected_response_code
;
22 net::HttpVersion expected_parsed_version
;
23 net::HttpVersion expected_version
;
26 struct ContentTypeTestData
{
27 const std::string raw_headers
;
28 const std::string mime_type
;
29 const bool has_mimetype
;
30 const std::string charset
;
31 const bool has_charset
;
32 const std::string all_content_type
;
35 class HttpResponseHeadersTest
: public testing::Test
{
38 // Transform "normal"-looking headers (\n-separated) to the appropriate
39 // input format for ParseRawHeaders (\0-separated).
40 void HeadersToRaw(std::string
* headers
) {
41 std::replace(headers
->begin(), headers
->end(), '\n', '\0');
42 if (!headers
->empty())
46 void TestCommon(const TestData
& test
) {
47 std::string
raw_headers(test
.raw_headers
);
48 HeadersToRaw(&raw_headers
);
49 std::string
expected_headers(test
.expected_headers
);
52 scoped_refptr
<net::HttpResponseHeaders
> parsed(
53 new net::HttpResponseHeaders(raw_headers
));
54 parsed
->GetNormalizedHeaders(&headers
);
56 // Transform to readable output format (so it's easier to see diffs).
57 std::replace(headers
.begin(), headers
.end(), ' ', '_');
58 std::replace(headers
.begin(), headers
.end(), '\n', '\\');
59 std::replace(expected_headers
.begin(), expected_headers
.end(), ' ', '_');
60 std::replace(expected_headers
.begin(), expected_headers
.end(), '\n', '\\');
62 EXPECT_EQ(expected_headers
, headers
);
64 EXPECT_EQ(test
.expected_response_code
, parsed
->response_code());
66 EXPECT_TRUE(test
.expected_parsed_version
== parsed
->GetParsedHttpVersion());
67 EXPECT_TRUE(test
.expected_version
== parsed
->GetHttpVersion());
72 // Check that we normalize headers properly.
73 TEST(HttpResponseHeadersTest
, NormalizeHeadersWhitespace
) {
75 "HTTP/1.1 202 Accepted \n"
76 "Content-TYPE : text/html; charset=utf-8 \n"
80 "HTTP/1.1 202 Accepted\n"
81 "Content-TYPE: text/html; charset=utf-8\n"
85 net::HttpVersion(1,1),
91 // Check that we normalize headers properly (header name is invalid if starts
93 TEST(HttpResponseHeadersTest
, NormalizeHeadersLeadingWhitespace
) {
95 "HTTP/1.1 202 Accepted \n"
96 // Starts with space -- will be skipped as invalid.
97 " Content-TYPE : text/html; charset=utf-8 \n"
101 "HTTP/1.1 202 Accepted\n"
102 "Set-Cookie: a, b\n",
105 net::HttpVersion(1,1),
106 net::HttpVersion(1,1)
111 TEST(HttpResponseHeadersTest
, BlankHeaders
) {
127 net::HttpVersion(1,1),
128 net::HttpVersion(1,1)
133 TEST(HttpResponseHeadersTest
, NormalizeHeadersVersion
) {
134 // Don't believe the http/0.9 version if there are headers!
137 "Content-TYPE: text/html; charset=utf-8\n",
140 "Content-TYPE: text/html; charset=utf-8\n",
143 net::HttpVersion(0,9),
144 net::HttpVersion(1,0)
149 TEST(HttpResponseHeadersTest
, PreserveHttp09
) {
150 // Accept the HTTP/0.9 version number if there are no headers.
151 // This is how HTTP/0.9 responses get constructed from HttpNetworkTransaction.
158 net::HttpVersion(0,9),
159 net::HttpVersion(0,9)
164 TEST(HttpResponseHeadersTest
, NormalizeHeadersMissingOK
) {
167 "Content-TYPE: text/html; charset=utf-8\n",
170 "Content-TYPE: text/html; charset=utf-8\n",
173 net::HttpVersion(1,1),
174 net::HttpVersion(1,1)
179 TEST(HttpResponseHeadersTest
, NormalizeHeadersBadStatus
) {
181 "SCREWED_UP_STATUS_LINE\n"
182 "Content-TYPE: text/html; charset=utf-8\n",
185 "Content-TYPE: text/html; charset=utf-8\n",
188 net::HttpVersion(0,0), // Parse error
189 net::HttpVersion(1,0)
194 TEST(HttpResponseHeadersTest
, NormalizeHeadersInvalidStatusCode
) {
196 "HTTP/1.1 -1 Unknown\n",
201 net::HttpVersion(1,1),
202 net::HttpVersion(1,1)
207 TEST(HttpResponseHeadersTest
, NormalizeHeadersEmpty
) {
214 net::HttpVersion(0,0), // Parse Error
215 net::HttpVersion(1,0)
220 TEST(HttpResponseHeadersTest
, NormalizeHeadersStartWithColon
) {
222 "HTTP/1.1 202 Accepted \n"
228 "HTTP/1.1 202 Accepted\n"
233 net::HttpVersion(1,1),
234 net::HttpVersion(1,1)
239 TEST(HttpResponseHeadersTest
, NormalizeHeadersStartWithColonAtEOL
) {
241 "HTTP/1.1 202 Accepted \n"
247 "HTTP/1.1 202 Accepted\n"
254 net::HttpVersion(1,1),
255 net::HttpVersion(1,1)
260 TEST(HttpResponseHeadersTest
, NormalizeHeadersOfWhitepace
) {
267 net::HttpVersion(0,0), // Parse error
268 net::HttpVersion(1,0)
273 TEST(HttpResponseHeadersTest
, RepeatedSetCookie
) {
280 "Set-Cookie: x=1, y=2\n",
283 net::HttpVersion(1,1),
284 net::HttpVersion(1,1)
289 TEST(HttpResponseHeadersTest
, GetNormalizedHeader
) {
290 std::string headers
=
292 "Cache-control: private\n"
293 "cache-Control: no-store\n";
294 HeadersToRaw(&headers
);
295 scoped_refptr
<net::HttpResponseHeaders
> parsed(
296 new net::HttpResponseHeaders(headers
));
299 EXPECT_TRUE(parsed
->GetNormalizedHeader("cache-control", &value
));
300 EXPECT_EQ("private, no-store", value
);
303 TEST(HttpResponseHeadersTest
, Persist
) {
305 net::HttpResponseHeaders::PersistOptions options
;
306 const char* raw_headers
;
307 const char* expected_headers
;
309 { net::HttpResponseHeaders::PERSIST_ALL
,
311 "Cache-control:private\n"
312 "cache-Control:no-store\n",
315 "Cache-control: private, no-store\n"
317 { net::HttpResponseHeaders::PERSIST_SANS_HOP_BY_HOP
,
319 "connection: keep-alive\n"
325 { net::HttpResponseHeaders::PERSIST_SANS_NON_CACHEABLE
|
326 net::HttpResponseHeaders::PERSIST_SANS_HOP_BY_HOP
,
330 "Transfer-Encoding: chunked\n"
331 "CoNnection: keep-alive\n"
332 "cache-control: private, no-cache=\"foo\"\n",
335 "cache-control: private, no-cache=\"foo\"\n"
337 { net::HttpResponseHeaders::PERSIST_SANS_NON_CACHEABLE
,
340 "Cache-Control: private,no-cache=\"foo, bar\"\n"
344 "Cache-Control: private,no-cache=\"foo, bar\"\n"
346 // ignore bogus no-cache value
347 { net::HttpResponseHeaders::PERSIST_SANS_NON_CACHEABLE
,
350 "Cache-Control: private,no-cache=foo\n",
354 "Cache-Control: private,no-cache=foo\n"
356 // ignore bogus no-cache value
357 { net::HttpResponseHeaders::PERSIST_SANS_NON_CACHEABLE
,
360 "Cache-Control: private, no-cache=\n",
364 "Cache-Control: private, no-cache=\n"
366 // ignore empty no-cache value
367 { net::HttpResponseHeaders::PERSIST_SANS_NON_CACHEABLE
,
370 "Cache-Control: private, no-cache=\"\"\n",
374 "Cache-Control: private, no-cache=\"\"\n"
376 // ignore wrong quotes no-cache value
377 { net::HttpResponseHeaders::PERSIST_SANS_NON_CACHEABLE
,
380 "Cache-Control: private, no-cache=\'foo\'\n",
384 "Cache-Control: private, no-cache=\'foo\'\n"
386 // ignore unterminated quotes no-cache value
387 { net::HttpResponseHeaders::PERSIST_SANS_NON_CACHEABLE
,
390 "Cache-Control: private, no-cache=\"foo\n",
394 "Cache-Control: private, no-cache=\"foo\n"
397 { net::HttpResponseHeaders::PERSIST_SANS_NON_CACHEABLE
,
400 "Cache-Control: private, no-cache=\" foo\t, bar\"\n",
403 "Cache-Control: private, no-cache=\" foo\t, bar\"\n"
405 // header name appears twice, separated by another header
406 { net::HttpResponseHeaders::PERSIST_ALL
,
416 // header name appears twice, separated by another header (type 2)
417 { net::HttpResponseHeaders::PERSIST_ALL
,
427 // Test filtering of cookie headers.
428 { net::HttpResponseHeaders::PERSIST_SANS_COOKIES
,
430 "Set-Cookie: foo=bar; httponly\n"
431 "Set-Cookie: bar=foo\n"
433 "Set-Cookie2: bar2=foo2\n",
438 // Test LWS at the end of a header.
439 { net::HttpResponseHeaders::PERSIST_ALL
,
441 "Content-Length: 450 \n"
442 "Content-Encoding: gzip\n",
445 "Content-Length: 450\n"
446 "Content-Encoding: gzip\n"
448 // Test LWS at the end of a header.
449 { net::HttpResponseHeaders::PERSIST_RAW
,
451 "Content-Length: 450 \n"
452 "Content-Encoding: gzip\n",
455 "Content-Length: 450\n"
456 "Content-Encoding: gzip\n"
458 // Test filtering of transport security state headers.
459 { net::HttpResponseHeaders::PERSIST_SANS_SECURITY_STATE
,
461 "Strict-Transport-Security: max-age=1576800\n"
463 "Public-Key-Pins: max-age=100000; "
464 "pin-sha1=\"ObT42aoSpAqWdY9WfRfL7i0HsVk=\";"
465 "pin-sha1=\"7kW49EVwZG0hSNx41ZO/fUPN0ek=\"",
472 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(tests
); ++i
) {
473 std::string headers
= tests
[i
].raw_headers
;
474 HeadersToRaw(&headers
);
475 scoped_refptr
<net::HttpResponseHeaders
> parsed1(
476 new net::HttpResponseHeaders(headers
));
479 parsed1
->Persist(&pickle
, tests
[i
].options
);
481 PickleIterator
iter(pickle
);
482 scoped_refptr
<net::HttpResponseHeaders
> parsed2(
483 new net::HttpResponseHeaders(pickle
, &iter
));
486 parsed2
->GetNormalizedHeaders(&h2
);
487 EXPECT_EQ(std::string(tests
[i
].expected_headers
), h2
);
491 TEST(HttpResponseHeadersTest
, EnumerateHeader_Coalesced
) {
492 // Ensure that commas in quoted strings are not regarded as value separators.
493 // Ensure that whitespace following a value is trimmed properly
494 std::string headers
=
496 "Cache-control:private , no-cache=\"set-cookie,server\" \n"
497 "cache-Control: no-store\n";
498 HeadersToRaw(&headers
);
499 scoped_refptr
<net::HttpResponseHeaders
> parsed(
500 new net::HttpResponseHeaders(headers
));
504 EXPECT_TRUE(parsed
->EnumerateHeader(&iter
, "cache-control", &value
));
505 EXPECT_EQ("private", value
);
506 EXPECT_TRUE(parsed
->EnumerateHeader(&iter
, "cache-control", &value
));
507 EXPECT_EQ("no-cache=\"set-cookie,server\"", value
);
508 EXPECT_TRUE(parsed
->EnumerateHeader(&iter
, "cache-control", &value
));
509 EXPECT_EQ("no-store", value
);
510 EXPECT_FALSE(parsed
->EnumerateHeader(&iter
, "cache-control", &value
));
513 TEST(HttpResponseHeadersTest
, EnumerateHeader_Challenge
) {
514 // Even though WWW-Authenticate has commas, it should not be treated as
516 std::string headers
=
518 "WWW-Authenticate:Digest realm=foobar, nonce=x, domain=y\n"
519 "WWW-Authenticate:Basic realm=quatar\n";
520 HeadersToRaw(&headers
);
521 scoped_refptr
<net::HttpResponseHeaders
> parsed(
522 new net::HttpResponseHeaders(headers
));
526 EXPECT_TRUE(parsed
->EnumerateHeader(&iter
, "WWW-Authenticate", &value
));
527 EXPECT_EQ("Digest realm=foobar, nonce=x, domain=y", value
);
528 EXPECT_TRUE(parsed
->EnumerateHeader(&iter
, "WWW-Authenticate", &value
));
529 EXPECT_EQ("Basic realm=quatar", value
);
530 EXPECT_FALSE(parsed
->EnumerateHeader(&iter
, "WWW-Authenticate", &value
));
533 TEST(HttpResponseHeadersTest
, EnumerateHeader_DateValued
) {
534 // The comma in a date valued header should not be treated as a
535 // field-value separator
536 std::string headers
=
538 "Date: Tue, 07 Aug 2007 23:10:55 GMT\n"
539 "Last-Modified: Wed, 01 Aug 2007 23:23:45 GMT\n";
540 HeadersToRaw(&headers
);
541 scoped_refptr
<net::HttpResponseHeaders
> parsed(
542 new net::HttpResponseHeaders(headers
));
545 EXPECT_TRUE(parsed
->EnumerateHeader(NULL
, "date", &value
));
546 EXPECT_EQ("Tue, 07 Aug 2007 23:10:55 GMT", value
);
547 EXPECT_TRUE(parsed
->EnumerateHeader(NULL
, "last-modified", &value
));
548 EXPECT_EQ("Wed, 01 Aug 2007 23:23:45 GMT", value
);
551 TEST(HttpResponseHeadersTest
, DefaultDateToGMT
) {
552 // Verify we make the best interpretation when parsing dates that incorrectly
553 // do not end in "GMT" as RFC2616 requires.
554 std::string headers
=
556 "Date: Tue, 07 Aug 2007 23:10:55\n"
557 "Last-Modified: Tue, 07 Aug 2007 19:10:55 EDT\n"
558 "Expires: Tue, 07 Aug 2007 23:10:55 UTC\n";
559 HeadersToRaw(&headers
);
560 scoped_refptr
<net::HttpResponseHeaders
> parsed(
561 new net::HttpResponseHeaders(headers
));
562 base::Time expected_value
;
563 ASSERT_TRUE(base::Time::FromString("Tue, 07 Aug 2007 23:10:55 GMT",
567 // When the timezone is missing, GMT is a good guess as its what RFC2616
569 EXPECT_TRUE(parsed
->GetDateValue(&value
));
570 EXPECT_EQ(expected_value
, value
);
571 // If GMT is missing but an RFC822-conforming one is present, use that.
572 EXPECT_TRUE(parsed
->GetLastModifiedValue(&value
));
573 EXPECT_EQ(expected_value
, value
);
574 // If an unknown timezone is present, treat like a missing timezone and
575 // default to GMT. The only example of a web server not specifying "GMT"
576 // used "UTC" which is equivalent to GMT.
577 if (parsed
->GetExpiresValue(&value
))
578 EXPECT_EQ(expected_value
, value
);
581 TEST(HttpResponseHeadersTest
, GetMimeType
) {
582 const ContentTypeTestData tests
[] = {
583 { "HTTP/1.1 200 OK\n"
584 "Content-type: text/html\n",
588 // Multiple content-type headers should give us the last one.
589 { "HTTP/1.1 200 OK\n"
590 "Content-type: text/html\n"
591 "Content-type: text/html\n",
594 "text/html, text/html" },
595 { "HTTP/1.1 200 OK\n"
596 "Content-type: text/plain\n"
597 "Content-type: text/html\n"
598 "Content-type: text/plain\n"
599 "Content-type: text/html\n",
602 "text/plain, text/html, text/plain, text/html" },
603 // Test charset parsing.
604 { "HTTP/1.1 200 OK\n"
605 "Content-type: text/html\n"
606 "Content-type: text/html; charset=ISO-8859-1\n",
609 "text/html, text/html; charset=ISO-8859-1" },
610 // Test charset in double quotes.
611 { "HTTP/1.1 200 OK\n"
612 "Content-type: text/html\n"
613 "Content-type: text/html; charset=\"ISO-8859-1\"\n",
616 "text/html, text/html; charset=\"ISO-8859-1\"" },
617 // If there are multiple matching content-type headers, we carry
618 // over the charset value.
619 { "HTTP/1.1 200 OK\n"
620 "Content-type: text/html;charset=utf-8\n"
621 "Content-type: text/html\n",
624 "text/html;charset=utf-8, text/html" },
625 // Test single quotes.
626 { "HTTP/1.1 200 OK\n"
627 "Content-type: text/html;charset='utf-8'\n"
628 "Content-type: text/html\n",
631 "text/html;charset='utf-8', text/html" },
632 // Last charset wins if matching content-type.
633 { "HTTP/1.1 200 OK\n"
634 "Content-type: text/html;charset=utf-8\n"
635 "Content-type: text/html;charset=iso-8859-1\n",
638 "text/html;charset=utf-8, text/html;charset=iso-8859-1" },
639 // Charset is ignored if the content types change.
640 { "HTTP/1.1 200 OK\n"
641 "Content-type: text/plain;charset=utf-8\n"
642 "Content-type: text/html\n",
645 "text/plain;charset=utf-8, text/html" },
646 // Empty content-type
647 { "HTTP/1.1 200 OK\n"
653 { "HTTP/1.1 200 OK\n"
654 "Content-type: text/html;charset=\n",
657 "text/html;charset=" },
658 // Multiple charsets, last one wins.
659 { "HTTP/1.1 200 OK\n"
660 "Content-type: text/html;charset=utf-8; charset=iso-8859-1\n",
663 "text/html;charset=utf-8; charset=iso-8859-1" },
665 { "HTTP/1.1 200 OK\n"
666 "Content-type: text/html; foo=utf-8; charset=iso-8859-1\n",
669 "text/html; foo=utf-8; charset=iso-8859-1" },
670 { "HTTP/1.1 200 OK\n"
671 "Content-type: text/html ; charset=utf-8 ; bar=iso-8859-1\n",
674 "text/html ; charset=utf-8 ; bar=iso-8859-1" },
675 // Comma embeded in quotes.
676 { "HTTP/1.1 200 OK\n"
677 "Content-type: text/html ; charset='utf-8,text/plain' ;\n",
679 "utf-8,text/plain", true,
680 "text/html ; charset='utf-8,text/plain' ;" },
681 // Charset with leading spaces.
682 { "HTTP/1.1 200 OK\n"
683 "Content-type: text/html ; charset= 'utf-8' ;\n",
686 "text/html ; charset= 'utf-8' ;" },
687 // Media type comments in mime-type.
688 { "HTTP/1.1 200 OK\n"
689 "Content-type: text/html (html)\n",
692 "text/html (html)" },
693 // Incomplete charset= param
694 { "HTTP/1.1 200 OK\n"
695 "Content-type: text/html; char=\n",
698 "text/html; char=" },
699 // Invalid media type: no slash
700 { "HTTP/1.1 200 OK\n"
701 "Content-type: texthtml\n",
705 // Invalid media type: */*
706 { "HTTP/1.1 200 OK\n"
707 "Content-type: */*\n",
713 for (size_t i
= 0; i
< arraysize(tests
); ++i
) {
714 std::string
headers(tests
[i
].raw_headers
);
715 HeadersToRaw(&headers
);
716 scoped_refptr
<net::HttpResponseHeaders
> parsed(
717 new net::HttpResponseHeaders(headers
));
720 EXPECT_EQ(tests
[i
].has_mimetype
, parsed
->GetMimeType(&value
));
721 EXPECT_EQ(tests
[i
].mime_type
, value
);
723 EXPECT_EQ(tests
[i
].has_charset
, parsed
->GetCharset(&value
));
724 EXPECT_EQ(tests
[i
].charset
, value
);
725 EXPECT_TRUE(parsed
->GetNormalizedHeader("content-type", &value
));
726 EXPECT_EQ(tests
[i
].all_content_type
, value
);
730 TEST(HttpResponseHeadersTest
, RequiresValidation
) {
733 bool requires_validation
;
735 // no expiry info: expires immediately
736 { "HTTP/1.1 200 OK\n"
740 // valid for a little while
741 { "HTTP/1.1 200 OK\n"
742 "cache-control: max-age=10000\n"
746 // expires in the future
747 { "HTTP/1.1 200 OK\n"
748 "date: Wed, 28 Nov 2007 00:40:11 GMT\n"
749 "expires: Wed, 28 Nov 2007 01:00:00 GMT\n"
754 { "HTTP/1.1 200 OK\n"
755 "date: Wed, 28 Nov 2007 00:40:11 GMT\n"
756 "expires: Wed, 28 Nov 2007 00:00:00 GMT\n"
760 // max-age trumps expires
761 { "HTTP/1.1 200 OK\n"
762 "date: Wed, 28 Nov 2007 00:40:11 GMT\n"
763 "expires: Wed, 28 Nov 2007 00:00:00 GMT\n"
764 "cache-control: max-age=10000\n"
768 // last-modified heuristic: modified a while ago
769 { "HTTP/1.1 200 OK\n"
770 "date: Wed, 28 Nov 2007 00:40:11 GMT\n"
771 "last-modified: Wed, 27 Nov 2007 08:00:00 GMT\n"
775 { "HTTP/1.1 203 Non-Authoritative Information\n"
776 "date: Wed, 28 Nov 2007 00:40:11 GMT\n"
777 "last-modified: Wed, 27 Nov 2007 08:00:00 GMT\n"
781 { "HTTP/1.1 206 Partial Content\n"
782 "date: Wed, 28 Nov 2007 00:40:11 GMT\n"
783 "last-modified: Wed, 27 Nov 2007 08:00:00 GMT\n"
787 // last-modified heuristic: modified recently
788 { "HTTP/1.1 200 OK\n"
789 "date: Wed, 28 Nov 2007 00:40:11 GMT\n"
790 "last-modified: Wed, 28 Nov 2007 00:40:10 GMT\n"
794 { "HTTP/1.1 203 Non-Authoritative Information\n"
795 "date: Wed, 28 Nov 2007 00:40:11 GMT\n"
796 "last-modified: Wed, 28 Nov 2007 00:40:10 GMT\n"
800 { "HTTP/1.1 206 Partial Content\n"
801 "date: Wed, 28 Nov 2007 00:40:11 GMT\n"
802 "last-modified: Wed, 28 Nov 2007 00:40:10 GMT\n"
806 // cached permanent redirect
807 { "HTTP/1.1 301 Moved Permanently\n"
811 // another cached permanent redirect
812 { "HTTP/1.1 308 Permanent Redirect\n"
816 // cached redirect: not reusable even though by default it would be
817 { "HTTP/1.1 300 Multiple Choices\n"
818 "Cache-Control: no-cache\n"
822 // cached forever by default
823 { "HTTP/1.1 410 Gone\n"
827 // cached temporary redirect: not reusable
828 { "HTTP/1.1 302 Found\n"
832 // cached temporary redirect: reusable
833 { "HTTP/1.1 302 Found\n"
834 "cache-control: max-age=10000\n"
838 // cache-control: max-age=N overrides expires: date in the past
839 { "HTTP/1.1 200 OK\n"
840 "date: Wed, 28 Nov 2007 00:40:11 GMT\n"
841 "expires: Wed, 28 Nov 2007 00:20:11 GMT\n"
842 "cache-control: max-age=10000\n"
846 // cache-control: no-store overrides expires: in the future
847 { "HTTP/1.1 200 OK\n"
848 "date: Wed, 28 Nov 2007 00:40:11 GMT\n"
849 "expires: Wed, 29 Nov 2007 00:40:11 GMT\n"
850 "cache-control: no-store,private,no-cache=\"foo\"\n"
854 // pragma: no-cache overrides last-modified heuristic
855 { "HTTP/1.1 200 OK\n"
856 "date: Wed, 28 Nov 2007 00:40:11 GMT\n"
857 "last-modified: Wed, 27 Nov 2007 08:00:00 GMT\n"
862 // TODO(darin): add many many more tests here
864 base::Time request_time
, response_time
, current_time
;
865 base::Time::FromString("Wed, 28 Nov 2007 00:40:09 GMT", &request_time
);
866 base::Time::FromString("Wed, 28 Nov 2007 00:40:12 GMT", &response_time
);
867 base::Time::FromString("Wed, 28 Nov 2007 00:45:20 GMT", ¤t_time
);
869 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(tests
); ++i
) {
870 std::string
headers(tests
[i
].headers
);
871 HeadersToRaw(&headers
);
872 scoped_refptr
<net::HttpResponseHeaders
> parsed(
873 new net::HttpResponseHeaders(headers
));
875 bool requires_validation
=
876 parsed
->RequiresValidation(request_time
, response_time
, current_time
);
877 EXPECT_EQ(tests
[i
].requires_validation
, requires_validation
);
881 TEST(HttpResponseHeadersTest
, Update
) {
883 const char* orig_headers
;
884 const char* new_headers
;
885 const char* expected_headers
;
887 { "HTTP/1.1 200 OK\n",
889 "HTTP/1/1 304 Not Modified\n"
890 "connection: keep-alive\n"
891 "Cache-control: max-age=10000\n",
894 "Cache-control: max-age=10000\n"
896 { "HTTP/1.1 200 OK\n"
898 "Cache-control: private\n",
900 "HTTP/1/1 304 Not Modified\n"
901 "connection: keep-alive\n"
902 "Cache-control: max-age=10000\n",
905 "Cache-control: max-age=10000\n"
908 { "HTTP/1.1 200 OK\n"
910 "Cache-control: private\n",
912 "HTTP/1/1 304 Not Modified\n"
913 "connection: keep-alive\n"
914 "Cache-CONTROL: max-age=10000\n",
917 "Cache-CONTROL: max-age=10000\n"
920 { "HTTP/1.1 200 OK\n"
921 "Content-Length: 450\n",
923 "HTTP/1/1 304 Not Modified\n"
924 "connection: keep-alive\n"
925 "Cache-control: max-age=10001 \n",
928 "Cache-control: max-age=10001\n"
929 "Content-Length: 450\n"
931 { "HTTP/1.1 200 OK\n"
932 "X-Frame-Options: DENY\n",
934 "HTTP/1/1 304 Not Modified\n"
935 "X-Frame-Options: ALLOW\n",
938 "X-Frame-Options: DENY\n",
940 { "HTTP/1.1 200 OK\n"
941 "X-WebKit-CSP: default-src 'none'\n",
943 "HTTP/1/1 304 Not Modified\n"
944 "X-WebKit-CSP: default-src *\n",
947 "X-WebKit-CSP: default-src 'none'\n",
949 { "HTTP/1.1 200 OK\n"
950 "X-XSS-Protection: 1\n",
952 "HTTP/1/1 304 Not Modified\n"
953 "X-XSS-Protection: 0\n",
956 "X-XSS-Protection: 1\n",
958 { "HTTP/1.1 200 OK\n",
960 "HTTP/1/1 304 Not Modified\n"
961 "X-Content-Type-Options: nosniff\n",
967 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(tests
); ++i
) {
968 std::string
orig_headers(tests
[i
].orig_headers
);
969 HeadersToRaw(&orig_headers
);
970 scoped_refptr
<net::HttpResponseHeaders
> parsed(
971 new net::HttpResponseHeaders(orig_headers
));
973 std::string
new_headers(tests
[i
].new_headers
);
974 HeadersToRaw(&new_headers
);
975 scoped_refptr
<net::HttpResponseHeaders
> new_parsed(
976 new net::HttpResponseHeaders(new_headers
));
978 parsed
->Update(*new_parsed
.get());
980 std::string resulting_headers
;
981 parsed
->GetNormalizedHeaders(&resulting_headers
);
982 EXPECT_EQ(std::string(tests
[i
].expected_headers
), resulting_headers
);
986 TEST(HttpResponseHeadersTest
, EnumerateHeaderLines
) {
989 const char* expected_lines
;
991 { "HTTP/1.1 200 OK\n",
995 { "HTTP/1.1 200 OK\n"
1000 { "HTTP/1.1 200 OK\n"
1005 "Foo: 1\nBar: 2\nFoo: 3\n"
1007 { "HTTP/1.1 200 OK\n"
1013 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(tests
); ++i
) {
1014 std::string
headers(tests
[i
].headers
);
1015 HeadersToRaw(&headers
);
1016 scoped_refptr
<net::HttpResponseHeaders
> parsed(
1017 new net::HttpResponseHeaders(headers
));
1019 std::string name
, value
, lines
;
1022 while (parsed
->EnumerateHeaderLines(&iter
, &name
, &value
)) {
1025 lines
.append(value
);
1029 EXPECT_EQ(std::string(tests
[i
].expected_lines
), lines
);
1033 TEST(HttpResponseHeadersTest
, IsRedirect
) {
1035 const char* headers
;
1036 const char* location
;
1039 { "HTTP/1.1 200 OK\n",
1043 { "HTTP/1.1 301 Moved\n"
1044 "Location: http://foopy/\n",
1048 { "HTTP/1.1 301 Moved\n"
1053 // we use the first location header as the target of the redirect
1054 { "HTTP/1.1 301 Moved\n"
1055 "Location: http://foo/\n"
1056 "Location: http://bar/\n",
1060 // we use the first _valid_ location header as the target of the redirect
1061 { "HTTP/1.1 301 Moved\n"
1063 "Location: http://bar/\n",
1067 // bug 1050541 (location header w/ an unescaped comma)
1068 { "HTTP/1.1 301 Moved\n"
1069 "Location: http://foo/bar,baz.html\n",
1070 "http://foo/bar,baz.html",
1073 // bug 1224617 (location header w/ non-ASCII bytes)
1074 { "HTTP/1.1 301 Moved\n"
1075 "Location: http://foo/bar?key=\xE4\xF6\xFC\n",
1076 "http://foo/bar?key=%E4%F6%FC",
1079 // Shift_JIS, Big5, and GBK contain multibyte characters with the trailing
1080 // byte falling in the ASCII range.
1081 { "HTTP/1.1 301 Moved\n"
1082 "Location: http://foo/bar?key=\x81\x5E\xD8\xBF\n",
1083 "http://foo/bar?key=%81^%D8%BF",
1086 { "HTTP/1.1 301 Moved\n"
1087 "Location: http://foo/bar?key=\x82\x40\xBD\xC4\n",
1088 "http://foo/bar?key=%82@%BD%C4",
1091 { "HTTP/1.1 301 Moved\n"
1092 "Location: http://foo/bar?key=\x83\x5C\x82\x5D\xCB\xD7\n",
1093 "http://foo/bar?key=%83\\%82]%CB%D7",
1097 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(tests
); ++i
) {
1098 std::string
headers(tests
[i
].headers
);
1099 HeadersToRaw(&headers
);
1100 scoped_refptr
<net::HttpResponseHeaders
> parsed(
1101 new net::HttpResponseHeaders(headers
));
1103 std::string location
;
1104 EXPECT_EQ(parsed
->IsRedirect(&location
), tests
[i
].is_redirect
);
1105 EXPECT_EQ(location
, tests
[i
].location
);
1109 TEST(HttpResponseHeadersTest
, GetContentLength
) {
1111 const char* headers
;
1114 { "HTTP/1.1 200 OK\n",
1117 { "HTTP/1.1 200 OK\n"
1118 "Content-Length: 10\n",
1121 { "HTTP/1.1 200 OK\n"
1122 "Content-Length: \n",
1125 { "HTTP/1.1 200 OK\n"
1126 "Content-Length: abc\n",
1129 { "HTTP/1.1 200 OK\n"
1130 "Content-Length: -10\n",
1133 { "HTTP/1.1 200 OK\n"
1134 "Content-Length: +10\n",
1137 { "HTTP/1.1 200 OK\n"
1138 "Content-Length: 23xb5\n",
1141 { "HTTP/1.1 200 OK\n"
1142 "Content-Length: 0xA\n",
1145 { "HTTP/1.1 200 OK\n"
1146 "Content-Length: 010\n",
1149 // Content-Length too big, will overflow an int64
1150 { "HTTP/1.1 200 OK\n"
1151 "Content-Length: 40000000000000000000\n",
1154 { "HTTP/1.1 200 OK\n"
1155 "Content-Length: 10\n",
1158 { "HTTP/1.1 200 OK\n"
1159 "Content-Length: 10 \n",
1162 { "HTTP/1.1 200 OK\n"
1163 "Content-Length: \t10\n",
1166 { "HTTP/1.1 200 OK\n"
1167 "Content-Length: \v10\n",
1170 { "HTTP/1.1 200 OK\n"
1171 "Content-Length: \f10\n",
1174 { "HTTP/1.1 200 OK\n"
1175 "cOnTeNt-LENgth: 33\n",
1178 { "HTTP/1.1 200 OK\n"
1179 "Content-Length: 34\r\n",
1183 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(tests
); ++i
) {
1184 std::string
headers(tests
[i
].headers
);
1185 HeadersToRaw(&headers
);
1186 scoped_refptr
<net::HttpResponseHeaders
> parsed(
1187 new net::HttpResponseHeaders(headers
));
1189 EXPECT_EQ(tests
[i
].expected_len
, parsed
->GetContentLength());
1193 TEST(HttpResponseHeaders
, GetContentRange
) {
1195 const char* headers
;
1196 bool expected_return_value
;
1197 int64 expected_first_byte_position
;
1198 int64 expected_last_byte_position
;
1199 int64 expected_instance_size
;
1201 { "HTTP/1.1 206 Partial Content",
1207 { "HTTP/1.1 206 Partial Content\n"
1214 { "HTTP/1.1 206 Partial Content\n"
1215 "Content-Range: megabytes 0-10/50",
1221 { "HTTP/1.1 206 Partial Content\n"
1222 "Content-Range: 0-10/50",
1228 { "HTTP/1.1 206 Partial Content\n"
1229 "Content-Range: Bytes 0-50/51",
1235 { "HTTP/1.1 206 Partial Content\n"
1236 "Content-Range: bytes 0-50/51",
1242 { "HTTP/1.1 206 Partial Content\n"
1243 "Content-Range: bytes\t0-50/51",
1249 { "HTTP/1.1 206 Partial Content\n"
1250 "Content-Range: bytes 0-50/51",
1256 { "HTTP/1.1 206 Partial Content\n"
1257 "Content-Range: bytes 0 - 50 \t / \t51",
1263 { "HTTP/1.1 206 Partial Content\n"
1264 "Content-Range: bytes 0\t-\t50\t/\t51\t",
1270 { "HTTP/1.1 206 Partial Content\n"
1271 "Content-Range: \tbytes\t\t\t 0\t-\t50\t/\t51\t",
1277 { "HTTP/1.1 206 Partial Content\n"
1278 "Content-Range: \t bytes \t 0 - 50 / 5 1",
1284 { "HTTP/1.1 206 Partial Content\n"
1285 "Content-Range: \t bytes \t 0 - 5 0 / 51",
1291 { "HTTP/1.1 206 Partial Content\n"
1292 "Content-Range: bytes 50-0/51",
1298 { "HTTP/1.1 416 Requested range not satisfiable\n"
1299 "Content-Range: bytes * /*",
1305 { "HTTP/1.1 416 Requested range not satisfiable\n"
1306 "Content-Range: bytes * / * ",
1312 { "HTTP/1.1 206 Partial Content\n"
1313 "Content-Range: bytes 0-50/*",
1319 { "HTTP/1.1 206 Partial Content\n"
1320 "Content-Range: bytes 0-50 / * ",
1326 { "HTTP/1.1 206 Partial Content\n"
1327 "Content-Range: bytes 0-10000000000/10000000001",
1333 { "HTTP/1.1 206 Partial Content\n"
1334 "Content-Range: bytes 0-10000000000/10000000000",
1340 // 64 bits wraparound.
1341 { "HTTP/1.1 206 Partial Content\n"
1342 "Content-Range: bytes 0 - 9223372036854775807 / 100",
1348 // 64 bits wraparound.
1349 { "HTTP/1.1 206 Partial Content\n"
1350 "Content-Range: bytes 0 - 100 / -9223372036854775808",
1356 { "HTTP/1.1 206 Partial Content\n"
1357 "Content-Range: bytes */50",
1363 { "HTTP/1.1 206 Partial Content\n"
1364 "Content-Range: bytes 0-50/10",
1370 { "HTTP/1.1 206 Partial Content\n"
1371 "Content-Range: bytes 40-50/45",
1377 { "HTTP/1.1 206 Partial Content\n"
1378 "Content-Range: bytes 0-50/-10",
1384 { "HTTP/1.1 206 Partial Content\n"
1385 "Content-Range: bytes 0-0/1",
1391 { "HTTP/1.1 206 Partial Content\n"
1392 "Content-Range: bytes 0-40000000000000000000/40000000000000000001",
1398 { "HTTP/1.1 206 Partial Content\n"
1399 "Content-Range: bytes 1-/100",
1405 { "HTTP/1.1 206 Partial Content\n"
1406 "Content-Range: bytes -/100",
1412 { "HTTP/1.1 206 Partial Content\n"
1413 "Content-Range: bytes -1/100",
1419 { "HTTP/1.1 206 Partial Content\n"
1420 "Content-Range: bytes 0-1233/*",
1426 { "HTTP/1.1 206 Partial Content\n"
1427 "Content-Range: bytes -123 - -1/100",
1434 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(tests
); ++i
) {
1435 std::string
headers(tests
[i
].headers
);
1436 HeadersToRaw(&headers
);
1437 scoped_refptr
<net::HttpResponseHeaders
> parsed(
1438 new net::HttpResponseHeaders(headers
));
1440 int64 first_byte_position
;
1441 int64 last_byte_position
;
1442 int64 instance_size
;
1443 bool return_value
= parsed
->GetContentRange(&first_byte_position
,
1444 &last_byte_position
,
1446 EXPECT_EQ(tests
[i
].expected_return_value
, return_value
);
1447 EXPECT_EQ(tests
[i
].expected_first_byte_position
, first_byte_position
);
1448 EXPECT_EQ(tests
[i
].expected_last_byte_position
, last_byte_position
);
1449 EXPECT_EQ(tests
[i
].expected_instance_size
, instance_size
);
1453 TEST(HttpResponseHeadersTest
, IsKeepAlive
) {
1455 const char* headers
;
1456 bool expected_keep_alive
;
1458 // The status line fabricated by HttpNetworkTransaction for a 0.9 response.
1460 { "HTTP/0.9 200 OK",
1463 // This could come from a broken server. Treated as 1.0 because it has a
1465 { "HTTP/0.9 200 OK\n"
1466 "connection: keep-alive\n",
1469 { "HTTP/1.1 200 OK\n",
1472 { "HTTP/1.0 200 OK\n",
1475 { "HTTP/1.0 200 OK\n"
1476 "connection: close\n",
1479 { "HTTP/1.0 200 OK\n"
1480 "connection: keep-alive\n",
1483 { "HTTP/1.0 200 OK\n"
1484 "connection: kEeP-AliVe\n",
1487 { "HTTP/1.0 200 OK\n"
1488 "connection: keep-aliveX\n",
1491 { "HTTP/1.1 200 OK\n"
1492 "connection: close\n",
1495 { "HTTP/1.1 200 OK\n"
1496 "connection: keep-alive\n",
1499 { "HTTP/1.0 200 OK\n"
1500 "proxy-connection: close\n",
1503 { "HTTP/1.0 200 OK\n"
1504 "proxy-connection: keep-alive\n",
1507 { "HTTP/1.1 200 OK\n"
1508 "proxy-connection: close\n",
1511 { "HTTP/1.1 200 OK\n"
1512 "proxy-connection: keep-alive\n",
1516 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(tests
); ++i
) {
1517 std::string
headers(tests
[i
].headers
);
1518 HeadersToRaw(&headers
);
1519 scoped_refptr
<net::HttpResponseHeaders
> parsed(
1520 new net::HttpResponseHeaders(headers
));
1522 EXPECT_EQ(tests
[i
].expected_keep_alive
, parsed
->IsKeepAlive());
1526 TEST(HttpResponseHeadersTest
, HasStrongValidators
) {
1528 const char* headers
;
1529 bool expected_result
;
1531 { "HTTP/0.9 200 OK",
1534 { "HTTP/1.0 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 01:40:10 GMT\n"
1542 "Last-Modified: Wed, 28 Nov 2007 00:40:10 GMT\n"
1546 { "HTTP/1.1 200 OK\n"
1547 "Date: Wed, 28 Nov 2007 00:41:10 GMT\n"
1548 "Last-Modified: Wed, 28 Nov 2007 00:40:10 GMT\n",
1551 { "HTTP/1.1 200 OK\n"
1552 "Date: Wed, 28 Nov 2007 00:41:09 GMT\n"
1553 "Last-Modified: Wed, 28 Nov 2007 00:40:10 GMT\n",
1556 { "HTTP/1.1 200 OK\n"
1560 // This is not really a weak etag:
1561 { "HTTP/1.1 200 OK\n"
1562 "etag: \"w/foo\"\n",
1565 // This is a weak etag:
1566 { "HTTP/1.1 200 OK\n"
1567 "etag: w/\"foo\"\n",
1570 { "HTTP/1.1 200 OK\n"
1571 "etag: W / \"foo\"\n",
1575 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(tests
); ++i
) {
1576 std::string
headers(tests
[i
].headers
);
1577 HeadersToRaw(&headers
);
1578 scoped_refptr
<net::HttpResponseHeaders
> parsed(
1579 new net::HttpResponseHeaders(headers
));
1581 EXPECT_EQ(tests
[i
].expected_result
, parsed
->HasStrongValidators()) <<
1582 "Failed test case " << i
;
1586 TEST(HttpResponseHeadersTest
, GetStatusText
) {
1587 std::string
headers("HTTP/1.1 404 Not Found");
1588 HeadersToRaw(&headers
);
1589 scoped_refptr
<net::HttpResponseHeaders
> parsed(
1590 new net::HttpResponseHeaders(headers
));
1591 EXPECT_EQ(std::string("Not Found"), parsed
->GetStatusText());
1594 TEST(HttpResponseHeadersTest
, GetStatusTextMissing
) {
1595 std::string
headers("HTTP/1.1 404");
1596 HeadersToRaw(&headers
);
1597 scoped_refptr
<net::HttpResponseHeaders
> parsed(
1598 new net::HttpResponseHeaders(headers
));
1599 // Since the status line gets normalized, we have OK
1600 EXPECT_EQ(std::string("OK"), parsed
->GetStatusText());
1603 TEST(HttpResponseHeadersTest
, GetStatusTextMultiSpace
) {
1604 std::string
headers("HTTP/1.0 404 Not Found");
1605 HeadersToRaw(&headers
);
1606 scoped_refptr
<net::HttpResponseHeaders
> parsed(
1607 new net::HttpResponseHeaders(headers
));
1608 EXPECT_EQ(std::string("Not Found"), parsed
->GetStatusText());
1611 TEST(HttpResponseHeadersTest
, GetStatusBadStatusLine
) {
1612 std::string
headers("Foo bar.");
1613 HeadersToRaw(&headers
);
1614 scoped_refptr
<net::HttpResponseHeaders
> parsed(
1615 new net::HttpResponseHeaders(headers
));
1616 // The bad status line would have gotten rewritten as
1618 EXPECT_EQ(std::string("OK"), parsed
->GetStatusText());
1621 TEST(HttpResponseHeadersTest
, AddHeader
) {
1623 const char* orig_headers
;
1624 const char* new_header
;
1625 const char* expected_headers
;
1627 { "HTTP/1.1 200 OK\n"
1628 "connection: keep-alive\n"
1629 "Cache-control: max-age=10000\n",
1631 "Content-Length: 450",
1634 "connection: keep-alive\n"
1635 "Cache-control: max-age=10000\n"
1636 "Content-Length: 450\n"
1638 { "HTTP/1.1 200 OK\n"
1639 "connection: keep-alive\n"
1640 "Cache-control: max-age=10000 \n",
1642 "Content-Length: 450 ",
1645 "connection: keep-alive\n"
1646 "Cache-control: max-age=10000\n"
1647 "Content-Length: 450\n"
1651 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(tests
); ++i
) {
1652 std::string
orig_headers(tests
[i
].orig_headers
);
1653 HeadersToRaw(&orig_headers
);
1654 scoped_refptr
<net::HttpResponseHeaders
> parsed(
1655 new net::HttpResponseHeaders(orig_headers
));
1657 std::string
new_header(tests
[i
].new_header
);
1658 parsed
->AddHeader(new_header
);
1660 std::string resulting_headers
;
1661 parsed
->GetNormalizedHeaders(&resulting_headers
);
1662 EXPECT_EQ(std::string(tests
[i
].expected_headers
), resulting_headers
);
1666 TEST(HttpResponseHeadersTest
, RemoveHeader
) {
1668 const char* orig_headers
;
1669 const char* to_remove
;
1670 const char* expected_headers
;
1672 { "HTTP/1.1 200 OK\n"
1673 "connection: keep-alive\n"
1674 "Cache-control: max-age=10000\n"
1675 "Content-Length: 450\n",
1680 "connection: keep-alive\n"
1681 "Cache-control: max-age=10000\n"
1683 { "HTTP/1.1 200 OK\n"
1684 "connection: keep-alive \n"
1685 "Content-Length : 450 \n"
1686 "Cache-control: max-age=10000\n",
1691 "connection: keep-alive\n"
1692 "Cache-control: max-age=10000\n"
1696 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(tests
); ++i
) {
1697 std::string
orig_headers(tests
[i
].orig_headers
);
1698 HeadersToRaw(&orig_headers
);
1699 scoped_refptr
<net::HttpResponseHeaders
> parsed(
1700 new net::HttpResponseHeaders(orig_headers
));
1702 std::string
name(tests
[i
].to_remove
);
1703 parsed
->RemoveHeader(name
);
1705 std::string resulting_headers
;
1706 parsed
->GetNormalizedHeaders(&resulting_headers
);
1707 EXPECT_EQ(std::string(tests
[i
].expected_headers
), resulting_headers
);
1711 TEST(HttpResponseHeadersTest
, RemoveIndividualHeader
) {
1713 const char* orig_headers
;
1714 const char* to_remove_name
;
1715 const char* to_remove_value
;
1716 const char* expected_headers
;
1718 { "HTTP/1.1 200 OK\n"
1719 "connection: keep-alive\n"
1720 "Cache-control: max-age=10000\n"
1721 "Content-Length: 450\n",
1728 "connection: keep-alive\n"
1729 "Cache-control: max-age=10000\n"
1731 { "HTTP/1.1 200 OK\n"
1732 "connection: keep-alive \n"
1733 "Content-Length : 450 \n"
1734 "Cache-control: max-age=10000\n",
1741 "connection: keep-alive\n"
1742 "Cache-control: max-age=10000\n"
1744 { "HTTP/1.1 200 OK\n"
1745 "connection: keep-alive \n"
1746 "Content-Length: 450\n"
1747 "Cache-control: max-age=10000\n",
1749 "Content-Length", // Matching name.
1751 "999", // Mismatching value.
1754 "connection: keep-alive\n"
1755 "Content-Length: 450\n"
1756 "Cache-control: max-age=10000\n"
1758 { "HTTP/1.1 200 OK\n"
1759 "connection: keep-alive \n"
1762 "Cache-control: max-age=10000\n",
1766 "bar, baz", // Space in value.
1769 "connection: keep-alive\n"
1771 "Cache-control: max-age=10000\n"
1773 { "HTTP/1.1 200 OK\n"
1774 "connection: keep-alive \n"
1776 "Cache-control: max-age=10000\n",
1780 "baz", // Only partial match -> ignored.
1783 "connection: keep-alive\n"
1785 "Cache-control: max-age=10000\n"
1789 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(tests
); ++i
) {
1790 std::string
orig_headers(tests
[i
].orig_headers
);
1791 HeadersToRaw(&orig_headers
);
1792 scoped_refptr
<net::HttpResponseHeaders
> parsed(
1793 new net::HttpResponseHeaders(orig_headers
));
1795 std::string
name(tests
[i
].to_remove_name
);
1796 std::string
value(tests
[i
].to_remove_value
);
1797 parsed
->RemoveHeaderLine(name
, value
);
1799 std::string resulting_headers
;
1800 parsed
->GetNormalizedHeaders(&resulting_headers
);
1801 EXPECT_EQ(std::string(tests
[i
].expected_headers
), resulting_headers
);
1805 TEST(HttpResponseHeadersTest
, ReplaceStatus
) {
1807 const char* orig_headers
;
1808 const char* new_status
;
1809 const char* expected_headers
;
1811 { "HTTP/1.1 206 Partial Content\n"
1812 "connection: keep-alive\n"
1813 "Cache-control: max-age=10000\n"
1814 "Content-Length: 450\n",
1819 "connection: keep-alive\n"
1820 "Cache-control: max-age=10000\n"
1821 "Content-Length: 450\n"
1823 { "HTTP/1.1 200 OK\n"
1824 "connection: keep-alive\n",
1826 "HTTP/1.1 304 Not Modified",
1828 "HTTP/1.1 304 Not Modified\n"
1829 "connection: keep-alive\n"
1831 { "HTTP/1.1 200 OK\n"
1832 "connection: keep-alive \n"
1833 "Content-Length : 450 \n"
1834 "Cache-control: max-age=10000\n",
1836 "HTTP/1//1 304 Not Modified",
1838 "HTTP/1.0 304 Not Modified\n"
1839 "connection: keep-alive\n"
1840 "Content-Length: 450\n"
1841 "Cache-control: max-age=10000\n"
1845 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(tests
); ++i
) {
1846 std::string
orig_headers(tests
[i
].orig_headers
);
1847 HeadersToRaw(&orig_headers
);
1848 scoped_refptr
<net::HttpResponseHeaders
> parsed(
1849 new net::HttpResponseHeaders(orig_headers
));
1851 std::string
name(tests
[i
].new_status
);
1852 parsed
->ReplaceStatusLine(name
);
1854 std::string resulting_headers
;
1855 parsed
->GetNormalizedHeaders(&resulting_headers
);
1856 EXPECT_EQ(std::string(tests
[i
].expected_headers
), resulting_headers
);
1860 TEST(HttpResponseHeadersTest
, UpdateWithNewRange
) {
1862 const char* orig_headers
;
1863 const char* expected_headers
;
1864 const char* expected_headers_with_replaced_status
;
1866 { "HTTP/1.1 200 OK\n"
1867 "Content-Length: 450\n",
1870 "Content-Range: bytes 3-5/450\n"
1871 "Content-Length: 3\n",
1873 "HTTP/1.1 206 Partial Content\n"
1874 "Content-Range: bytes 3-5/450\n"
1875 "Content-Length: 3\n",
1877 { "HTTP/1.1 200 OK\n"
1878 "Content-Length: 5\n",
1881 "Content-Range: bytes 3-5/5\n"
1882 "Content-Length: 3\n",
1884 "HTTP/1.1 206 Partial Content\n"
1885 "Content-Range: bytes 3-5/5\n"
1886 "Content-Length: 3\n",
1889 const net::HttpByteRange range
= net::HttpByteRange::Bounded(3, 5);
1891 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(tests
); ++i
) {
1892 std::string
orig_headers(tests
[i
].orig_headers
);
1893 std::replace(orig_headers
.begin(), orig_headers
.end(), '\n', '\0');
1894 scoped_refptr
<net::HttpResponseHeaders
> parsed(
1895 new net::HttpResponseHeaders(orig_headers
+ '\0'));
1896 int64 content_size
= parsed
->GetContentLength();
1897 std::string resulting_headers
;
1899 // Update headers without replacing status line.
1900 parsed
->UpdateWithNewRange(range
, content_size
, false);
1901 parsed
->GetNormalizedHeaders(&resulting_headers
);
1902 EXPECT_EQ(std::string(tests
[i
].expected_headers
), resulting_headers
);
1904 // Replace status line too.
1905 parsed
->UpdateWithNewRange(range
, content_size
, true);
1906 parsed
->GetNormalizedHeaders(&resulting_headers
);
1907 EXPECT_EQ(std::string(tests
[i
].expected_headers_with_replaced_status
),
1912 TEST(HttpResponseHeadersTest
, ToNetLogParamAndBackAgain
) {
1913 std::string
headers("HTTP/1.1 404\n"
1914 "Content-Length: 450\n"
1915 "Connection: keep-alive\n");
1916 HeadersToRaw(&headers
);
1917 scoped_refptr
<net::HttpResponseHeaders
> parsed(
1918 new net::HttpResponseHeaders(headers
));
1920 scoped_ptr
<base::Value
> event_param(
1921 parsed
->NetLogCallback(net::NetLog::LOG_ALL_BUT_BYTES
));
1922 scoped_refptr
<net::HttpResponseHeaders
> recreated
;
1924 ASSERT_TRUE(net::HttpResponseHeaders::FromNetLogParam(event_param
.get(),
1926 ASSERT_TRUE(recreated
.get());
1927 EXPECT_EQ(parsed
->GetHttpVersion(), recreated
->GetHttpVersion());
1928 EXPECT_EQ(parsed
->response_code(), recreated
->response_code());
1929 EXPECT_EQ(parsed
->GetContentLength(), recreated
->GetContentLength());
1930 EXPECT_EQ(parsed
->IsKeepAlive(), recreated
->IsKeepAlive());
1932 std::string normalized_parsed
;
1933 parsed
->GetNormalizedHeaders(&normalized_parsed
);
1934 std::string normalized_recreated
;
1935 parsed
->GetNormalizedHeaders(&normalized_recreated
);
1936 EXPECT_EQ(normalized_parsed
, normalized_recreated
);