Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(65)

Side by Side Diff: net/http/http_response_headers_unittest.cc

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

Powered by Google App Engine
This is Rietveld 408576698