Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / net / http / http_util_unittest.cc
blob6ea1ca479e7edbad150bcb1cbd6255508bc286aa
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include <algorithm>
7 #include "base/basictypes.h"
8 #include "base/strings/string_util.h"
9 #include "net/http/http_util.h"
10 #include "testing/gtest/include/gtest/gtest.h"
12 namespace net {
14 namespace {
15 class HttpUtilTest : public testing::Test {};
18 TEST(HttpUtilTest, IsSafeHeader) {
19 static const char* const unsafe_headers[] = {
20 "sec-",
21 "sEc-",
22 "sec-foo",
23 "sEc-FoO",
24 "proxy-",
25 "pRoXy-",
26 "proxy-foo",
27 "pRoXy-FoO",
28 "accept-charset",
29 "accept-encoding",
30 "access-control-request-headers",
31 "access-control-request-method",
32 "connection",
33 "content-length",
34 "cookie",
35 "cookie2",
36 "content-transfer-encoding",
37 "date",
38 "expect",
39 "host",
40 "keep-alive",
41 "origin",
42 "referer",
43 "te",
44 "trailer",
45 "transfer-encoding",
46 "upgrade",
47 "user-agent",
48 "via",
50 for (size_t i = 0; i < arraysize(unsafe_headers); ++i) {
51 EXPECT_FALSE(HttpUtil::IsSafeHeader(unsafe_headers[i]))
52 << unsafe_headers[i];
53 EXPECT_FALSE(HttpUtil::IsSafeHeader(
54 base::StringToUpperASCII(std::string(unsafe_headers[i]))))
55 << unsafe_headers[i];
57 static const char* const safe_headers[] = {
58 "foo",
59 "x-",
60 "x-foo",
61 "content-disposition",
62 "update",
63 "accept-charseta",
64 "accept_charset",
65 "accept-encodinga",
66 "accept_encoding",
67 "access-control-request-headersa",
68 "access-control-request-header",
69 "access_control_request_header",
70 "access-control-request-methoda",
71 "access_control_request_method",
72 "connectiona",
73 "content-lengtha",
74 "content_length",
75 "cookiea",
76 "cookie2a",
77 "cookie3",
78 "content-transfer-encodinga",
79 "content_transfer_encoding",
80 "datea",
81 "expecta",
82 "hosta",
83 "keep-alivea",
84 "keep_alive",
85 "origina",
86 "referera",
87 "referrer",
88 "tea",
89 "trailera",
90 "transfer-encodinga",
91 "transfer_encoding",
92 "upgradea",
93 "user-agenta",
94 "user_agent",
95 "viaa",
97 for (size_t i = 0; i < arraysize(safe_headers); ++i) {
98 EXPECT_TRUE(HttpUtil::IsSafeHeader(safe_headers[i])) << safe_headers[i];
99 EXPECT_TRUE(HttpUtil::IsSafeHeader(
100 base::StringToUpperASCII(std::string(safe_headers[i]))))
101 << safe_headers[i];
105 TEST(HttpUtilTest, HasHeader) {
106 static const struct {
107 const char* const headers;
108 const char* const name;
109 bool expected_result;
110 } tests[] = {
111 { "", "foo", false },
112 { "foo\r\nbar", "foo", false },
113 { "ffoo: 1", "foo", false },
114 { "foo: 1", "foo", true },
115 { "foo: 1\r\nbar: 2", "foo", true },
116 { "fOO: 1\r\nbar: 2", "foo", true },
117 { "g: 0\r\nfoo: 1\r\nbar: 2", "foo", true },
119 for (size_t i = 0; i < arraysize(tests); ++i) {
120 bool result = HttpUtil::HasHeader(tests[i].headers, tests[i].name);
121 EXPECT_EQ(tests[i].expected_result, result);
125 TEST(HttpUtilTest, StripHeaders) {
126 static const char* const headers =
127 "Origin: origin\r\n"
128 "Content-Type: text/plain\r\n"
129 "Cookies: foo1\r\n"
130 "Custom: baz\r\n"
131 "COOKIES: foo2\r\n"
132 "Server: Apache\r\n"
133 "OrIGin: origin2\r\n";
135 static const char* const header_names[] = {
136 "origin", "content-type", "cookies"
139 static const char* const expected_stripped_headers =
140 "Custom: baz\r\n"
141 "Server: Apache\r\n";
143 EXPECT_EQ(expected_stripped_headers,
144 HttpUtil::StripHeaders(headers, header_names,
145 arraysize(header_names)));
148 TEST(HttpUtilTest, HeadersIterator) {
149 std::string headers = "foo: 1\t\r\nbar: hello world\r\nbaz: 3 \r\n";
151 HttpUtil::HeadersIterator it(headers.begin(), headers.end(), "\r\n");
153 ASSERT_TRUE(it.GetNext());
154 EXPECT_EQ(std::string("foo"), it.name());
155 EXPECT_EQ(std::string("1"), it.values());
157 ASSERT_TRUE(it.GetNext());
158 EXPECT_EQ(std::string("bar"), it.name());
159 EXPECT_EQ(std::string("hello world"), it.values());
161 ASSERT_TRUE(it.GetNext());
162 EXPECT_EQ(std::string("baz"), it.name());
163 EXPECT_EQ(std::string("3"), it.values());
165 EXPECT_FALSE(it.GetNext());
168 TEST(HttpUtilTest, HeadersIterator_MalformedLine) {
169 std::string headers = "foo: 1\n: 2\n3\nbar: 4";
171 HttpUtil::HeadersIterator it(headers.begin(), headers.end(), "\n");
173 ASSERT_TRUE(it.GetNext());
174 EXPECT_EQ(std::string("foo"), it.name());
175 EXPECT_EQ(std::string("1"), it.values());
177 ASSERT_TRUE(it.GetNext());
178 EXPECT_EQ(std::string("bar"), it.name());
179 EXPECT_EQ(std::string("4"), it.values());
181 EXPECT_FALSE(it.GetNext());
184 TEST(HttpUtilTest, HeadersIterator_AdvanceTo) {
185 std::string headers = "foo: 1\r\n: 2\r\n3\r\nbar: 4";
187 HttpUtil::HeadersIterator it(headers.begin(), headers.end(), "\r\n");
188 EXPECT_TRUE(it.AdvanceTo("foo"));
189 EXPECT_EQ("foo", it.name());
190 EXPECT_TRUE(it.AdvanceTo("bar"));
191 EXPECT_EQ("bar", it.name());
192 EXPECT_FALSE(it.AdvanceTo("blat"));
193 EXPECT_FALSE(it.GetNext()); // should be at end of headers
196 TEST(HttpUtilTest, HeadersIterator_Reset) {
197 std::string headers = "foo: 1\r\n: 2\r\n3\r\nbar: 4";
198 HttpUtil::HeadersIterator it(headers.begin(), headers.end(), "\r\n");
199 // Search past "foo".
200 EXPECT_TRUE(it.AdvanceTo("bar"));
201 // Now try advancing to "foo". This time it should fail since the iterator
202 // position is past it.
203 EXPECT_FALSE(it.AdvanceTo("foo"));
204 it.Reset();
205 // Now that we reset the iterator position, we should find 'foo'
206 EXPECT_TRUE(it.AdvanceTo("foo"));
209 TEST(HttpUtilTest, ValuesIterator) {
210 std::string values = " must-revalidate, no-cache=\"foo, bar\"\t, private ";
212 HttpUtil::ValuesIterator it(values.begin(), values.end(), ',');
214 ASSERT_TRUE(it.GetNext());
215 EXPECT_EQ(std::string("must-revalidate"), it.value());
217 ASSERT_TRUE(it.GetNext());
218 EXPECT_EQ(std::string("no-cache=\"foo, bar\""), it.value());
220 ASSERT_TRUE(it.GetNext());
221 EXPECT_EQ(std::string("private"), it.value());
223 EXPECT_FALSE(it.GetNext());
226 TEST(HttpUtilTest, ValuesIterator_Blanks) {
227 std::string values = " \t ";
229 HttpUtil::ValuesIterator it(values.begin(), values.end(), ',');
231 EXPECT_FALSE(it.GetNext());
234 TEST(HttpUtilTest, Unquote) {
235 // Replace <backslash> " with ".
236 EXPECT_STREQ("xyz\"abc", HttpUtil::Unquote("\"xyz\\\"abc\"").c_str());
238 // Replace <backslash> <backslash> with <backslash>
239 EXPECT_STREQ("xyz\\abc", HttpUtil::Unquote("\"xyz\\\\abc\"").c_str());
240 EXPECT_STREQ("xyz\\\\\\abc",
241 HttpUtil::Unquote("\"xyz\\\\\\\\\\\\abc\"").c_str());
243 // Replace <backslash> X with X
244 EXPECT_STREQ("xyzXabc", HttpUtil::Unquote("\"xyz\\Xabc\"").c_str());
246 // Act as identity function on unquoted inputs.
247 EXPECT_STREQ("X", HttpUtil::Unquote("X").c_str());
248 EXPECT_STREQ("\"", HttpUtil::Unquote("\"").c_str());
250 // Allow single quotes to act as quote marks.
251 // Not part of RFC 2616.
252 EXPECT_STREQ("x\"", HttpUtil::Unquote("'x\"'").c_str());
255 TEST(HttpUtilTest, Quote) {
256 EXPECT_STREQ("\"xyz\\\"abc\"", HttpUtil::Quote("xyz\"abc").c_str());
258 // Replace <backslash> <backslash> with <backslash>
259 EXPECT_STREQ("\"xyz\\\\abc\"", HttpUtil::Quote("xyz\\abc").c_str());
261 // Replace <backslash> X with X
262 EXPECT_STREQ("\"xyzXabc\"", HttpUtil::Quote("xyzXabc").c_str());
265 TEST(HttpUtilTest, LocateEndOfHeaders) {
266 struct {
267 const char* const input;
268 int expected_result;
269 } tests[] = {
270 {"\r\n", -1},
271 {"\n", -1},
272 {"\r", -1},
273 {"foo", -1},
274 {"\r\n\r\n", 4},
275 {"foo\r\nbar\r\n\r\n", 12},
276 {"foo\nbar\n\n", 9},
277 {"foo\r\nbar\r\n\r\njunk", 12},
278 {"foo\nbar\n\njunk", 9},
279 {"foo\nbar\n\r\njunk", 10},
280 {"foo\nbar\r\n\njunk", 10},
282 for (size_t i = 0; i < arraysize(tests); ++i) {
283 int input_len = static_cast<int>(strlen(tests[i].input));
284 int eoh = HttpUtil::LocateEndOfHeaders(tests[i].input, input_len);
285 EXPECT_EQ(tests[i].expected_result, eoh);
289 TEST(HttpUtilTest, LocateEndOfAdditionalHeaders) {
290 struct {
291 const char* const input;
292 int expected_result;
293 } tests[] = {
294 {"\r\n", 2},
295 {"\n", 1},
296 {"\r", -1},
297 {"foo", -1},
298 {"\r\n\r\n", 2},
299 {"foo\r\nbar\r\n\r\n", 12},
300 {"foo\nbar\n\n", 9},
301 {"foo\r\nbar\r\n\r\njunk", 12},
302 {"foo\nbar\n\njunk", 9},
303 {"foo\nbar\n\r\njunk", 10},
304 {"foo\nbar\r\n\njunk", 10},
306 for (size_t i = 0; i < arraysize(tests); ++i) {
307 int input_len = static_cast<int>(strlen(tests[i].input));
308 int eoh = HttpUtil::LocateEndOfAdditionalHeaders(tests[i].input, input_len);
309 EXPECT_EQ(tests[i].expected_result, eoh);
312 TEST(HttpUtilTest, AssembleRawHeaders) {
313 struct {
314 const char* const input; // with '|' representing '\0'
315 const char* const expected_result; // with '\0' changed to '|'
316 } tests[] = {
317 { "HTTP/1.0 200 OK\r\nFoo: 1\r\nBar: 2\r\n\r\n",
318 "HTTP/1.0 200 OK|Foo: 1|Bar: 2||" },
320 { "HTTP/1.0 200 OK\nFoo: 1\nBar: 2\n\n",
321 "HTTP/1.0 200 OK|Foo: 1|Bar: 2||" },
323 // Valid line continuation (single SP).
325 "HTTP/1.0 200 OK\n"
326 "Foo: 1\n"
327 " continuation\n"
328 "Bar: 2\n\n",
330 "HTTP/1.0 200 OK|"
331 "Foo: 1 continuation|"
332 "Bar: 2||"
335 // Valid line continuation (single HT).
337 "HTTP/1.0 200 OK\n"
338 "Foo: 1\n"
339 "\tcontinuation\n"
340 "Bar: 2\n\n",
342 "HTTP/1.0 200 OK|"
343 "Foo: 1 continuation|"
344 "Bar: 2||"
347 // Valid line continuation (multiple SP).
349 "HTTP/1.0 200 OK\n"
350 "Foo: 1\n"
351 " continuation\n"
352 "Bar: 2\n\n",
354 "HTTP/1.0 200 OK|"
355 "Foo: 1 continuation|"
356 "Bar: 2||"
359 // Valid line continuation (multiple HT).
361 "HTTP/1.0 200 OK\n"
362 "Foo: 1\n"
363 "\t\t\tcontinuation\n"
364 "Bar: 2\n\n",
366 "HTTP/1.0 200 OK|"
367 "Foo: 1 continuation|"
368 "Bar: 2||"
371 // Valid line continuation (mixed HT, SP).
373 "HTTP/1.0 200 OK\n"
374 "Foo: 1\n"
375 " \t \t continuation\n"
376 "Bar: 2\n\n",
378 "HTTP/1.0 200 OK|"
379 "Foo: 1 continuation|"
380 "Bar: 2||"
383 // Valid multi-line continuation
385 "HTTP/1.0 200 OK\n"
386 "Foo: 1\n"
387 " continuation1\n"
388 "\tcontinuation2\n"
389 " continuation3\n"
390 "Bar: 2\n\n",
392 "HTTP/1.0 200 OK|"
393 "Foo: 1 continuation1 continuation2 continuation3|"
394 "Bar: 2||"
397 // Continuation of quoted value.
398 // This is different from what Firefox does, since it
399 // will preserve the LWS.
401 "HTTP/1.0 200 OK\n"
402 "Etag: \"34534-d3\n"
403 " 134q\"\n"
404 "Bar: 2\n\n",
406 "HTTP/1.0 200 OK|"
407 "Etag: \"34534-d3 134q\"|"
408 "Bar: 2||"
411 // Valid multi-line continuation, full LWS lines
413 "HTTP/1.0 200 OK\n"
414 "Foo: 1\n"
415 " \n"
416 "\t\t\t\t\n"
417 "\t continuation\n"
418 "Bar: 2\n\n",
420 // One SP per continued line = 3.
421 "HTTP/1.0 200 OK|"
422 "Foo: 1 continuation|"
423 "Bar: 2||"
426 // Valid multi-line continuation, all LWS
428 "HTTP/1.0 200 OK\n"
429 "Foo: 1\n"
430 " \n"
431 "\t\t\t\t\n"
432 "\t \n"
433 "Bar: 2\n\n",
435 // One SP per continued line = 3.
436 "HTTP/1.0 200 OK|"
437 "Foo: 1 |"
438 "Bar: 2||"
441 // Valid line continuation (No value bytes in first line).
443 "HTTP/1.0 200 OK\n"
444 "Foo:\n"
445 " value\n"
446 "Bar: 2\n\n",
448 "HTTP/1.0 200 OK|"
449 "Foo: value|"
450 "Bar: 2||"
453 // Not a line continuation (can't continue status line).
455 "HTTP/1.0 200 OK\n"
456 " Foo: 1\n"
457 "Bar: 2\n\n",
459 "HTTP/1.0 200 OK|"
460 " Foo: 1|"
461 "Bar: 2||"
464 // Not a line continuation (can't continue status line).
466 "HTTP/1.0\n"
467 " 200 OK\n"
468 "Foo: 1\n"
469 "Bar: 2\n\n",
471 "HTTP/1.0|"
472 " 200 OK|"
473 "Foo: 1|"
474 "Bar: 2||"
477 // Not a line continuation (can't continue status line).
479 "HTTP/1.0 404\n"
480 " Not Found\n"
481 "Foo: 1\n"
482 "Bar: 2\n\n",
484 "HTTP/1.0 404|"
485 " Not Found|"
486 "Foo: 1|"
487 "Bar: 2||"
490 // Unterminated status line.
492 "HTTP/1.0 200 OK",
494 "HTTP/1.0 200 OK||"
497 // Single terminated, with headers
499 "HTTP/1.0 200 OK\n"
500 "Foo: 1\n"
501 "Bar: 2\n",
503 "HTTP/1.0 200 OK|"
504 "Foo: 1|"
505 "Bar: 2||"
508 // Not terminated, with headers
510 "HTTP/1.0 200 OK\n"
511 "Foo: 1\n"
512 "Bar: 2",
514 "HTTP/1.0 200 OK|"
515 "Foo: 1|"
516 "Bar: 2||"
519 // Not a line continuation (VT)
521 "HTTP/1.0 200 OK\n"
522 "Foo: 1\n"
523 "\vInvalidContinuation\n"
524 "Bar: 2\n\n",
526 "HTTP/1.0 200 OK|"
527 "Foo: 1|"
528 "\vInvalidContinuation|"
529 "Bar: 2||"
532 // Not a line continuation (formfeed)
534 "HTTP/1.0 200 OK\n"
535 "Foo: 1\n"
536 "\fInvalidContinuation\n"
537 "Bar: 2\n\n",
539 "HTTP/1.0 200 OK|"
540 "Foo: 1|"
541 "\fInvalidContinuation|"
542 "Bar: 2||"
545 // Not a line continuation -- can't continue header names.
547 "HTTP/1.0 200 OK\n"
548 "Serv\n"
549 " er: Apache\n"
550 "\tInvalidContinuation\n"
551 "Bar: 2\n\n",
553 "HTTP/1.0 200 OK|"
554 "Serv|"
555 " er: Apache|"
556 "\tInvalidContinuation|"
557 "Bar: 2||"
560 // Not a line continuation -- no value to continue.
562 "HTTP/1.0 200 OK\n"
563 "Foo: 1\n"
564 "garbage\n"
565 " not-a-continuation\n"
566 "Bar: 2\n\n",
568 "HTTP/1.0 200 OK|"
569 "Foo: 1|"
570 "garbage|"
571 " not-a-continuation|"
572 "Bar: 2||",
575 // Not a line continuation -- no valid name.
577 "HTTP/1.0 200 OK\n"
578 ": 1\n"
579 " garbage\n"
580 "Bar: 2\n\n",
582 "HTTP/1.0 200 OK|"
583 ": 1|"
584 " garbage|"
585 "Bar: 2||",
588 // Not a line continuation -- no valid name (whitespace)
590 "HTTP/1.0 200 OK\n"
591 " : 1\n"
592 " garbage\n"
593 "Bar: 2\n\n",
595 "HTTP/1.0 200 OK|"
596 " : 1|"
597 " garbage|"
598 "Bar: 2||",
601 // Embed NULLs in the status line. They should not be understood
602 // as line separators.
604 "HTTP/1.0 200 OK|Bar2:0|Baz2:1\r\nFoo: 1\r\nBar: 2\r\n\r\n",
605 "HTTP/1.0 200 OKBar2:0Baz2:1|Foo: 1|Bar: 2||"
608 // Embed NULLs in a header line. They should not be understood as
609 // line separators.
611 "HTTP/1.0 200 OK\nFoo: 1|Foo2: 3\nBar: 2\n\n",
612 "HTTP/1.0 200 OK|Foo: 1Foo2: 3|Bar: 2||"
615 for (size_t i = 0; i < arraysize(tests); ++i) {
616 std::string input = tests[i].input;
617 std::replace(input.begin(), input.end(), '|', '\0');
618 std::string raw = HttpUtil::AssembleRawHeaders(input.data(), input.size());
619 std::replace(raw.begin(), raw.end(), '\0', '|');
620 EXPECT_EQ(tests[i].expected_result, raw);
624 // Test SpecForRequest().
625 TEST(HttpUtilTest, RequestUrlSanitize) {
626 struct {
627 const char* const url;
628 const char* const expected_spec;
629 } tests[] = {
630 { // Check that #hash is removed.
631 "http://www.google.com:78/foobar?query=1#hash",
632 "http://www.google.com:78/foobar?query=1",
634 { // The reference may itself contain # -- strip all of it.
635 "http://192.168.0.1?query=1#hash#10#11#13#14",
636 "http://192.168.0.1/?query=1",
638 { // Strip username/password.
639 "http://user:pass@google.com",
640 "http://google.com/",
642 { // https scheme
643 "https://www.google.com:78/foobar?query=1#hash",
644 "https://www.google.com:78/foobar?query=1",
646 { // WebSocket's ws scheme
647 "ws://www.google.com:78/foobar?query=1#hash",
648 "ws://www.google.com:78/foobar?query=1",
650 { // WebSocket's wss scheme
651 "wss://www.google.com:78/foobar?query=1#hash",
652 "wss://www.google.com:78/foobar?query=1",
655 for (size_t i = 0; i < arraysize(tests); ++i) {
656 SCOPED_TRACE(i);
658 GURL url(GURL(tests[i].url));
659 std::string expected_spec(tests[i].expected_spec);
661 EXPECT_EQ(expected_spec, HttpUtil::SpecForRequest(url));
665 // Test SpecForRequest() for "ftp" scheme.
666 TEST(HttpUtilTest, SpecForRequestForUrlWithFtpScheme) {
667 GURL ftp_url("ftp://user:pass@google.com/pub/chromium/");
668 EXPECT_EQ("ftp://google.com/pub/chromium/",
669 HttpUtil::SpecForRequest(ftp_url));
672 TEST(HttpUtilTest, GenerateAcceptLanguageHeader) {
673 EXPECT_EQ(std::string("en-US,fr;q=0.8,de;q=0.6"),
674 HttpUtil::GenerateAcceptLanguageHeader("en-US,fr,de"));
675 EXPECT_EQ(std::string("en-US,fr;q=0.8,de;q=0.6,ko;q=0.4,zh-CN;q=0.2,"
676 "ja;q=0.2"),
677 HttpUtil::GenerateAcceptLanguageHeader("en-US,fr,de,ko,zh-CN,ja"));
680 // HttpResponseHeadersTest.GetMimeType also tests ParseContentType.
681 TEST(HttpUtilTest, ParseContentType) {
682 const struct {
683 const char* const content_type;
684 const char* const expected_mime_type;
685 const char* const expected_charset;
686 const bool expected_had_charset;
687 const char* const expected_boundary;
688 } tests[] = {
689 { "text/html; charset=utf-8",
690 "text/html",
691 "utf-8",
692 true,
695 { "text/html; charset =utf-8",
696 "text/html",
697 "utf-8",
698 true,
701 { "text/html; charset= utf-8",
702 "text/html",
703 "utf-8",
704 true,
707 { "text/html; charset=utf-8 ",
708 "text/html",
709 "utf-8",
710 true,
713 { "text/html; boundary=\"WebKit-ada-df-dsf-adsfadsfs\"",
714 "text/html",
716 false,
717 "\"WebKit-ada-df-dsf-adsfadsfs\""
719 { "text/html; boundary =\"WebKit-ada-df-dsf-adsfadsfs\"",
720 "text/html",
722 false,
723 "\"WebKit-ada-df-dsf-adsfadsfs\""
725 { "text/html; boundary= \"WebKit-ada-df-dsf-adsfadsfs\"",
726 "text/html",
728 false,
729 "\"WebKit-ada-df-dsf-adsfadsfs\""
731 { "text/html; boundary= \"WebKit-ada-df-dsf-adsfadsfs\" ",
732 "text/html",
734 false,
735 "\"WebKit-ada-df-dsf-adsfadsfs\""
737 { "text/html; boundary=\"WebKit-ada-df-dsf-adsfadsfs \"",
738 "text/html",
740 false,
741 "\"WebKit-ada-df-dsf-adsfadsfs \""
743 { "text/html; boundary=WebKit-ada-df-dsf-adsfadsfs",
744 "text/html",
746 false,
747 "WebKit-ada-df-dsf-adsfadsfs"
749 // TODO(abarth): Add more interesting test cases.
751 for (size_t i = 0; i < arraysize(tests); ++i) {
752 std::string mime_type;
753 std::string charset;
754 bool had_charset = false;
755 std::string boundary;
756 HttpUtil::ParseContentType(tests[i].content_type, &mime_type, &charset,
757 &had_charset, &boundary);
758 EXPECT_EQ(tests[i].expected_mime_type, mime_type) << "i=" << i;
759 EXPECT_EQ(tests[i].expected_charset, charset) << "i=" << i;
760 EXPECT_EQ(tests[i].expected_had_charset, had_charset) << "i=" << i;
761 EXPECT_EQ(tests[i].expected_boundary, boundary) << "i=" << i;
765 TEST(HttpUtilTest, ParseRanges) {
766 const struct {
767 const char* const headers;
768 bool expected_return_value;
769 size_t expected_ranges_size;
770 const struct {
771 int64 expected_first_byte_position;
772 int64 expected_last_byte_position;
773 int64 expected_suffix_length;
774 } expected_ranges[10];
775 } tests[] = {
776 { "Range: bytes=0-10",
777 true,
779 { {0, 10, -1}, }
781 { "Range: bytes=10-0",
782 false,
786 { "Range: BytES=0-10",
787 true,
789 { {0, 10, -1}, }
791 { "Range: megabytes=0-10",
792 false,
796 { "Range: bytes0-10",
797 false,
801 { "Range: bytes=0-0,0-10,10-20,100-200,100-,-200",
802 true,
804 { {0, 0, -1},
805 {0, 10, -1},
806 {10, 20, -1},
807 {100, 200, -1},
808 {100, -1, -1},
809 {-1, -1, 200},
812 { "Range: bytes=0-10\r\n"
813 "Range: bytes=0-10,10-20,100-200,100-,-200",
814 true,
816 { {0, 10, -1}
819 { "Range: bytes=",
820 false,
824 { "Range: bytes=-",
825 false,
829 { "Range: bytes=0-10-",
830 false,
834 { "Range: bytes=-0-10",
835 false,
839 { "Range: bytes =0-10\r\n",
840 true,
842 { {0, 10, -1}
845 { "Range: bytes= 0-10 \r\n",
846 true,
848 { {0, 10, -1}
851 { "Range: bytes = 0 - 10 \r\n",
852 true,
854 { {0, 10, -1}
857 { "Range: bytes= 0-1 0\r\n",
858 false,
862 { "Range: bytes= 0- -10\r\n",
863 false,
867 { "Range: bytes= 0 - 1 , 10 -20, 100- 200 , 100-, -200 \r\n",
868 true,
870 { {0, 1, -1},
871 {10, 20, -1},
872 {100, 200, -1},
873 {100, -1, -1},
874 {-1, -1, 200},
879 for (size_t i = 0; i < arraysize(tests); ++i) {
880 std::vector<HttpByteRange> ranges;
881 bool return_value = HttpUtil::ParseRanges(std::string(tests[i].headers),
882 &ranges);
883 EXPECT_EQ(tests[i].expected_return_value, return_value);
884 if (return_value) {
885 EXPECT_EQ(tests[i].expected_ranges_size, ranges.size());
886 for (size_t j = 0; j < ranges.size(); ++j) {
887 EXPECT_EQ(tests[i].expected_ranges[j].expected_first_byte_position,
888 ranges[j].first_byte_position());
889 EXPECT_EQ(tests[i].expected_ranges[j].expected_last_byte_position,
890 ranges[j].last_byte_position());
891 EXPECT_EQ(tests[i].expected_ranges[j].expected_suffix_length,
892 ranges[j].suffix_length());
898 TEST(HttpUtilTest, ParseRetryAfterHeader) {
899 base::Time::Exploded now_exploded = { 2014, 11, -1, 5, 22, 39, 30, 0 };
900 base::Time now = base::Time::FromUTCExploded(now_exploded);
902 base::Time::Exploded later_exploded = { 2015, 1, -1, 1, 12, 34, 56, 0 };
903 base::Time later = base::Time::FromUTCExploded(later_exploded);
905 const struct {
906 const char* retry_after_string;
907 bool expected_return_value;
908 base::TimeDelta expected_retry_after;
909 } tests[] = {
910 { "", false, base::TimeDelta() },
911 { "-3", false, base::TimeDelta() },
912 { "-2", false, base::TimeDelta() },
913 { "-1", false, base::TimeDelta() },
914 { "0", true, base::TimeDelta::FromSeconds(0) },
915 { "1", true, base::TimeDelta::FromSeconds(1) },
916 { "2", true, base::TimeDelta::FromSeconds(2) },
917 { "3", true, base::TimeDelta::FromSeconds(3) },
918 { "60", true, base::TimeDelta::FromSeconds(60) },
919 { "3600", true, base::TimeDelta::FromSeconds(3600) },
920 { "86400", true, base::TimeDelta::FromSeconds(86400) },
921 { "Thu, 1 Jan 2015 12:34:56 GMT", true, later - now },
922 { "Mon, 1 Jan 1900 12:34:56 GMT", false, base::TimeDelta() }
925 for (size_t i = 0; i < arraysize(tests); ++i) {
926 base::TimeDelta retry_after;
927 bool return_value = HttpUtil::ParseRetryAfterHeader(
928 tests[i].retry_after_string, now, &retry_after);
929 EXPECT_EQ(tests[i].expected_return_value, return_value)
930 << "Test case " << i << ": expected " << tests[i].expected_return_value
931 << " but got " << return_value << ".";
932 if (tests[i].expected_return_value && return_value) {
933 EXPECT_EQ(tests[i].expected_retry_after, retry_after)
934 << "Test case " << i << ": expected "
935 << tests[i].expected_retry_after.InSeconds() << "s but got "
936 << retry_after.InSeconds() << "s.";
941 namespace {
942 void CheckCurrentNameValuePair(HttpUtil::NameValuePairsIterator* parser,
943 bool expect_valid,
944 std::string expected_name,
945 std::string expected_value) {
946 ASSERT_EQ(expect_valid, parser->valid());
947 if (!expect_valid) {
948 return;
951 // Let's make sure that these never change (i.e., when a quoted value is
952 // unquoted, it should be cached on the first calls and not regenerated
953 // later).
954 std::string::const_iterator first_value_begin = parser->value_begin();
955 std::string::const_iterator first_value_end = parser->value_end();
957 ASSERT_EQ(expected_name, std::string(parser->name_begin(),
958 parser->name_end()));
959 ASSERT_EQ(expected_name, parser->name());
960 ASSERT_EQ(expected_value, std::string(parser->value_begin(),
961 parser->value_end()));
962 ASSERT_EQ(expected_value, parser->value());
964 // Make sure they didn't/don't change.
965 ASSERT_TRUE(first_value_begin == parser->value_begin());
966 ASSERT_TRUE(first_value_end == parser->value_end());
969 void CheckNextNameValuePair(HttpUtil::NameValuePairsIterator* parser,
970 bool expect_next,
971 bool expect_valid,
972 std::string expected_name,
973 std::string expected_value) {
974 ASSERT_EQ(expect_next, parser->GetNext());
975 ASSERT_EQ(expect_valid, parser->valid());
976 if (!expect_next || !expect_valid) {
977 return;
980 CheckCurrentNameValuePair(parser,
981 expect_valid,
982 expected_name,
983 expected_value);
986 void CheckInvalidNameValuePair(std::string valid_part,
987 std::string invalid_part) {
988 std::string whole_string = valid_part + invalid_part;
990 HttpUtil::NameValuePairsIterator valid_parser(valid_part.begin(),
991 valid_part.end(),
992 ';');
993 HttpUtil::NameValuePairsIterator invalid_parser(whole_string.begin(),
994 whole_string.end(),
995 ';');
997 ASSERT_TRUE(valid_parser.valid());
998 ASSERT_TRUE(invalid_parser.valid());
1000 // Both parsers should return all the same values until "valid_parser" is
1001 // exhausted.
1002 while (valid_parser.GetNext()) {
1003 ASSERT_TRUE(invalid_parser.GetNext());
1004 ASSERT_TRUE(valid_parser.valid());
1005 ASSERT_TRUE(invalid_parser.valid());
1006 ASSERT_EQ(valid_parser.name(), invalid_parser.name());
1007 ASSERT_EQ(valid_parser.value(), invalid_parser.value());
1010 // valid_parser is exhausted and remains 'valid'
1011 ASSERT_TRUE(valid_parser.valid());
1013 // invalid_parser's corresponding call to GetNext also returns false...
1014 ASSERT_FALSE(invalid_parser.GetNext());
1015 // ...but the parser is in an invalid state.
1016 ASSERT_FALSE(invalid_parser.valid());
1019 } // namespace
1021 TEST(HttpUtilTest, NameValuePairsIteratorCopyAndAssign) {
1022 std::string data = "alpha='\\'a\\''; beta=\" b \"; cappa='c;'; delta=\"d\"";
1023 HttpUtil::NameValuePairsIterator parser_a(data.begin(), data.end(), ';');
1025 EXPECT_TRUE(parser_a.valid());
1026 ASSERT_NO_FATAL_FAILURE(
1027 CheckNextNameValuePair(&parser_a, true, true, "alpha", "'a'"));
1029 HttpUtil::NameValuePairsIterator parser_b(parser_a);
1030 // a and b now point to same location
1031 ASSERT_NO_FATAL_FAILURE(
1032 CheckCurrentNameValuePair(&parser_b, true, "alpha", "'a'"));
1033 ASSERT_NO_FATAL_FAILURE(
1034 CheckCurrentNameValuePair(&parser_a, true, "alpha", "'a'"));
1036 // advance a, no effect on b
1037 ASSERT_NO_FATAL_FAILURE(
1038 CheckNextNameValuePair(&parser_a, true, true, "beta", " b "));
1039 ASSERT_NO_FATAL_FAILURE(
1040 CheckCurrentNameValuePair(&parser_b, true, "alpha", "'a'"));
1042 // assign b the current state of a, no effect on a
1043 parser_b = parser_a;
1044 ASSERT_NO_FATAL_FAILURE(
1045 CheckCurrentNameValuePair(&parser_b, true, "beta", " b "));
1046 ASSERT_NO_FATAL_FAILURE(
1047 CheckCurrentNameValuePair(&parser_a, true, "beta", " b "));
1049 // advance b, no effect on a
1050 ASSERT_NO_FATAL_FAILURE(
1051 CheckNextNameValuePair(&parser_b, true, true, "cappa", "c;"));
1052 ASSERT_NO_FATAL_FAILURE(
1053 CheckCurrentNameValuePair(&parser_a, true, "beta", " b "));
1056 TEST(HttpUtilTest, NameValuePairsIteratorEmptyInput) {
1057 std::string data;
1058 HttpUtil::NameValuePairsIterator parser(data.begin(), data.end(), ';');
1060 EXPECT_TRUE(parser.valid());
1061 ASSERT_NO_FATAL_FAILURE(CheckNextNameValuePair(
1062 &parser, false, true, std::string(), std::string()));
1065 TEST(HttpUtilTest, NameValuePairsIterator) {
1066 std::string data = "alpha=1; beta= 2 ;cappa =' 3; ';"
1067 "delta= \" \\\"4\\\" \"; e= \" '5'\"; e=6;"
1068 "f='\\'\\h\\e\\l\\l\\o\\ \\w\\o\\r\\l\\d\\'';"
1069 "g=''; h='hello'";
1070 HttpUtil::NameValuePairsIterator parser(data.begin(), data.end(), ';');
1071 EXPECT_TRUE(parser.valid());
1073 ASSERT_NO_FATAL_FAILURE(
1074 CheckNextNameValuePair(&parser, true, true, "alpha", "1"));
1075 ASSERT_NO_FATAL_FAILURE(
1076 CheckNextNameValuePair(&parser, true, true, "beta", "2"));
1077 ASSERT_NO_FATAL_FAILURE(
1078 CheckNextNameValuePair(&parser, true, true, "cappa", " 3; "));
1079 ASSERT_NO_FATAL_FAILURE(
1080 CheckNextNameValuePair(&parser, true, true, "delta", " \"4\" "));
1081 ASSERT_NO_FATAL_FAILURE(
1082 CheckNextNameValuePair(&parser, true, true, "e", " '5'"));
1083 ASSERT_NO_FATAL_FAILURE(
1084 CheckNextNameValuePair(&parser, true, true, "e", "6"));
1085 ASSERT_NO_FATAL_FAILURE(
1086 CheckNextNameValuePair(&parser, true, true, "f", "'hello world'"));
1087 ASSERT_NO_FATAL_FAILURE(
1088 CheckNextNameValuePair(&parser, true, true, "g", std::string()));
1089 ASSERT_NO_FATAL_FAILURE(
1090 CheckNextNameValuePair(&parser, true, true, "h", "hello"));
1091 ASSERT_NO_FATAL_FAILURE(CheckNextNameValuePair(
1092 &parser, false, true, std::string(), std::string()));
1095 TEST(HttpUtilTest, NameValuePairsIteratorOptionalValues) {
1096 std::string data = "alpha=1; beta;cappa ; delta; e ; f=1";
1097 // Test that the default parser requires values.
1098 HttpUtil::NameValuePairsIterator default_parser(data.begin(), data.end(),
1099 ';');
1100 EXPECT_TRUE(default_parser.valid());
1101 ASSERT_NO_FATAL_FAILURE(
1102 CheckNextNameValuePair(&default_parser, true, true, "alpha", "1"));
1103 ASSERT_NO_FATAL_FAILURE(CheckNextNameValuePair(&default_parser, false, false,
1104 std::string(), std::string()));
1106 HttpUtil::NameValuePairsIterator values_required_parser(
1107 data.begin(), data.end(), ';',
1108 HttpUtil::NameValuePairsIterator::VALUES_NOT_OPTIONAL);
1109 EXPECT_TRUE(values_required_parser.valid());
1110 ASSERT_NO_FATAL_FAILURE(CheckNextNameValuePair(&values_required_parser, true,
1111 true, "alpha", "1"));
1112 ASSERT_NO_FATAL_FAILURE(CheckNextNameValuePair(
1113 &values_required_parser, false, false, std::string(), std::string()));
1115 HttpUtil::NameValuePairsIterator parser(
1116 data.begin(), data.end(), ';',
1117 HttpUtil::NameValuePairsIterator::VALUES_OPTIONAL);
1118 EXPECT_TRUE(parser.valid());
1120 ASSERT_NO_FATAL_FAILURE(
1121 CheckNextNameValuePair(&parser, true, true, "alpha", "1"));
1122 ASSERT_NO_FATAL_FAILURE(
1123 CheckNextNameValuePair(&parser, true, true, "beta", std::string()));
1124 ASSERT_NO_FATAL_FAILURE(
1125 CheckNextNameValuePair(&parser, true, true, "cappa", std::string()));
1126 ASSERT_NO_FATAL_FAILURE(
1127 CheckNextNameValuePair(&parser, true, true, "delta", std::string()));
1128 ASSERT_NO_FATAL_FAILURE(
1129 CheckNextNameValuePair(&parser, true, true, "e", std::string()));
1130 ASSERT_NO_FATAL_FAILURE(
1131 CheckNextNameValuePair(&parser, true, true, "f", "1"));
1132 ASSERT_NO_FATAL_FAILURE(CheckNextNameValuePair(&parser, false, true,
1133 std::string(), std::string()));
1134 EXPECT_TRUE(parser.valid());
1137 TEST(HttpUtilTest, NameValuePairsIteratorIllegalInputs) {
1138 ASSERT_NO_FATAL_FAILURE(CheckInvalidNameValuePair("alpha=1", "; beta"));
1139 ASSERT_NO_FATAL_FAILURE(CheckInvalidNameValuePair(std::string(), "beta"));
1141 ASSERT_NO_FATAL_FAILURE(CheckInvalidNameValuePair("alpha=1", "; 'beta'=2"));
1142 ASSERT_NO_FATAL_FAILURE(CheckInvalidNameValuePair(std::string(), "'beta'=2"));
1143 ASSERT_NO_FATAL_FAILURE(CheckInvalidNameValuePair("alpha=1", ";beta="));
1144 ASSERT_NO_FATAL_FAILURE(CheckInvalidNameValuePair("alpha=1",
1145 ";beta=;cappa=2"));
1147 // According to the spec this is an error, but it doesn't seem appropriate to
1148 // change our behaviour to be less permissive at this time.
1149 // See NameValuePairsIteratorExtraSeparators test
1150 // ASSERT_NO_FATAL_FAILURE(CheckInvalidNameValuePair("alpha=1", ";; beta=2"));
1153 // If we are going to support extra separators against the spec, let's just make
1154 // sure they work rationally.
1155 TEST(HttpUtilTest, NameValuePairsIteratorExtraSeparators) {
1156 std::string data = " ; ;;alpha=1; ;; ; beta= 2;cappa=3;;; ; ";
1157 HttpUtil::NameValuePairsIterator parser(data.begin(), data.end(), ';');
1158 EXPECT_TRUE(parser.valid());
1160 ASSERT_NO_FATAL_FAILURE(
1161 CheckNextNameValuePair(&parser, true, true, "alpha", "1"));
1162 ASSERT_NO_FATAL_FAILURE(
1163 CheckNextNameValuePair(&parser, true, true, "beta", "2"));
1164 ASSERT_NO_FATAL_FAILURE(
1165 CheckNextNameValuePair(&parser, true, true, "cappa", "3"));
1166 ASSERT_NO_FATAL_FAILURE(CheckNextNameValuePair(
1167 &parser, false, true, std::string(), std::string()));
1170 // See comments on the implementation of NameValuePairsIterator::GetNext
1171 // regarding this derogation from the spec.
1172 TEST(HttpUtilTest, NameValuePairsIteratorMissingEndQuote) {
1173 std::string data = "name='value";
1174 HttpUtil::NameValuePairsIterator parser(data.begin(), data.end(), ';');
1175 EXPECT_TRUE(parser.valid());
1177 ASSERT_NO_FATAL_FAILURE(
1178 CheckNextNameValuePair(&parser, true, true, "name", "value"));
1179 ASSERT_NO_FATAL_FAILURE(CheckNextNameValuePair(
1180 &parser, false, true, std::string(), std::string()));
1183 } // namespace net