Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / net / http / http_util_unittest.cc
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
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"
11
12 using net::HttpUtil;
13
14 namespace {
15 class HttpUtilTest : public testing::Test {};
16 }
17
18 TEST(HttpUtilTest, IsSafeHeader) {
19   static const char* 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",
49   };
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(StringToUpperASCII(std::string(
54         unsafe_headers[i])))) << unsafe_headers[i];
55   }
56   static const char* safe_headers[] = {
57     "foo",
58     "x-",
59     "x-foo",
60     "content-disposition",
61     "update",
62     "accept-charseta",
63     "accept_charset",
64     "accept-encodinga",
65     "accept_encoding",
66     "access-control-request-headersa",
67     "access-control-request-header",
68     "access_control_request_header",
69     "access-control-request-methoda",
70     "access_control_request_method",
71     "connectiona",
72     "content-lengtha",
73     "content_length",
74     "cookiea",
75     "cookie2a",
76     "cookie3",
77     "content-transfer-encodinga",
78     "content_transfer_encoding",
79     "datea",
80     "expecta",
81     "hosta",
82     "keep-alivea",
83     "keep_alive",
84     "origina",
85     "referera",
86     "referrer",
87     "tea",
88     "trailera",
89     "transfer-encodinga",
90     "transfer_encoding",
91     "upgradea",
92     "user-agenta",
93     "user_agent",
94     "viaa",
95   };
96   for (size_t i = 0; i < arraysize(safe_headers); ++i) {
97     EXPECT_TRUE(HttpUtil::IsSafeHeader(safe_headers[i])) << safe_headers[i];
98     EXPECT_TRUE(HttpUtil::IsSafeHeader(StringToUpperASCII(std::string(
99         safe_headers[i])))) << safe_headers[i];
100   }
101 }
102
103 TEST(HttpUtilTest, HasHeader) {
104   static const struct {
105     const char* headers;
106     const char* name;
107     bool expected_result;
108   } tests[] = {
109     { "", "foo", false },
110     { "foo\r\nbar", "foo", false },
111     { "ffoo: 1", "foo", false },
112     { "foo: 1", "foo", true },
113     { "foo: 1\r\nbar: 2", "foo", true },
114     { "fOO: 1\r\nbar: 2", "foo", true },
115     { "g: 0\r\nfoo: 1\r\nbar: 2", "foo", true },
116   };
117   for (size_t i = 0; i < arraysize(tests); ++i) {
118     bool result = HttpUtil::HasHeader(tests[i].headers, tests[i].name);
119     EXPECT_EQ(tests[i].expected_result, result);
120   }
121 }
122
123 TEST(HttpUtilTest, StripHeaders) {
124   static const char* headers =
125       "Origin: origin\r\n"
126       "Content-Type: text/plain\r\n"
127       "Cookies: foo1\r\n"
128       "Custom: baz\r\n"
129       "COOKIES: foo2\r\n"
130       "Server: Apache\r\n"
131       "OrIGin: origin2\r\n";
132
133   static const char* header_names[] = {
134     "origin", "content-type", "cookies"
135   };
136
137   static const char* expected_stripped_headers =
138       "Custom: baz\r\n"
139       "Server: Apache\r\n";
140
141   EXPECT_EQ(expected_stripped_headers,
142             HttpUtil::StripHeaders(headers, header_names,
143                                    arraysize(header_names)));
144 }
145
146 TEST(HttpUtilTest, HeadersIterator) {
147   std::string headers = "foo: 1\t\r\nbar: hello world\r\nbaz: 3 \r\n";
148
149   HttpUtil::HeadersIterator it(headers.begin(), headers.end(), "\r\n");
150
151   ASSERT_TRUE(it.GetNext());
152   EXPECT_EQ(std::string("foo"), it.name());
153   EXPECT_EQ(std::string("1"), it.values());
154
155   ASSERT_TRUE(it.GetNext());
156   EXPECT_EQ(std::string("bar"), it.name());
157   EXPECT_EQ(std::string("hello world"), it.values());
158
159   ASSERT_TRUE(it.GetNext());
160   EXPECT_EQ(std::string("baz"), it.name());
161   EXPECT_EQ(std::string("3"), it.values());
162
163   EXPECT_FALSE(it.GetNext());
164 }
165
166 TEST(HttpUtilTest, HeadersIterator_MalformedLine) {
167   std::string headers = "foo: 1\n: 2\n3\nbar: 4";
168
169   HttpUtil::HeadersIterator it(headers.begin(), headers.end(), "\n");
170
171   ASSERT_TRUE(it.GetNext());
172   EXPECT_EQ(std::string("foo"), it.name());
173   EXPECT_EQ(std::string("1"), it.values());
174
175   ASSERT_TRUE(it.GetNext());
176   EXPECT_EQ(std::string("bar"), it.name());
177   EXPECT_EQ(std::string("4"), it.values());
178
179   EXPECT_FALSE(it.GetNext());
180 }
181
182 TEST(HttpUtilTest, HeadersIterator_AdvanceTo) {
183   std::string headers = "foo: 1\r\n: 2\r\n3\r\nbar: 4";
184
185   HttpUtil::HeadersIterator it(headers.begin(), headers.end(), "\r\n");
186   EXPECT_TRUE(it.AdvanceTo("foo"));
187   EXPECT_EQ("foo", it.name());
188   EXPECT_TRUE(it.AdvanceTo("bar"));
189   EXPECT_EQ("bar", it.name());
190   EXPECT_FALSE(it.AdvanceTo("blat"));
191   EXPECT_FALSE(it.GetNext());  // should be at end of headers
192 }
193
194 TEST(HttpUtilTest, HeadersIterator_Reset) {
195   std::string headers = "foo: 1\r\n: 2\r\n3\r\nbar: 4";
196   HttpUtil::HeadersIterator it(headers.begin(), headers.end(), "\r\n");
197   // Search past "foo".
198   EXPECT_TRUE(it.AdvanceTo("bar"));
199   // Now try advancing to "foo".  This time it should fail since the iterator
200   // position is past it.
201   EXPECT_FALSE(it.AdvanceTo("foo"));
202   it.Reset();
203   // Now that we reset the iterator position, we should find 'foo'
204   EXPECT_TRUE(it.AdvanceTo("foo"));
205 }
206
207 TEST(HttpUtilTest, ValuesIterator) {
208   std::string values = " must-revalidate,   no-cache=\"foo, bar\"\t, private ";
209
210   HttpUtil::ValuesIterator it(values.begin(), values.end(), ',');
211
212   ASSERT_TRUE(it.GetNext());
213   EXPECT_EQ(std::string("must-revalidate"), it.value());
214
215   ASSERT_TRUE(it.GetNext());
216   EXPECT_EQ(std::string("no-cache=\"foo, bar\""), it.value());
217
218   ASSERT_TRUE(it.GetNext());
219   EXPECT_EQ(std::string("private"), it.value());
220
221   EXPECT_FALSE(it.GetNext());
222 }
223
224 TEST(HttpUtilTest, ValuesIterator_Blanks) {
225   std::string values = " \t ";
226
227   HttpUtil::ValuesIterator it(values.begin(), values.end(), ',');
228
229   EXPECT_FALSE(it.GetNext());
230 }
231
232 TEST(HttpUtilTest, Unquote) {
233   // Replace <backslash> " with ".
234   EXPECT_STREQ("xyz\"abc", HttpUtil::Unquote("\"xyz\\\"abc\"").c_str());
235
236   // Replace <backslash> <backslash> with <backslash>
237   EXPECT_STREQ("xyz\\abc", HttpUtil::Unquote("\"xyz\\\\abc\"").c_str());
238   EXPECT_STREQ("xyz\\\\\\abc",
239                HttpUtil::Unquote("\"xyz\\\\\\\\\\\\abc\"").c_str());
240
241   // Replace <backslash> X with X
242   EXPECT_STREQ("xyzXabc", HttpUtil::Unquote("\"xyz\\Xabc\"").c_str());
243
244   // Act as identity function on unquoted inputs.
245   EXPECT_STREQ("X", HttpUtil::Unquote("X").c_str());
246   EXPECT_STREQ("\"", HttpUtil::Unquote("\"").c_str());
247
248   // Allow single quotes to act as quote marks.
249   // Not part of RFC 2616.
250   EXPECT_STREQ("x\"", HttpUtil::Unquote("'x\"'").c_str());
251 }
252
253 TEST(HttpUtilTest, Quote) {
254   EXPECT_STREQ("\"xyz\\\"abc\"", HttpUtil::Quote("xyz\"abc").c_str());
255
256   // Replace <backslash> <backslash> with <backslash>
257   EXPECT_STREQ("\"xyz\\\\abc\"", HttpUtil::Quote("xyz\\abc").c_str());
258
259   // Replace <backslash> X with X
260   EXPECT_STREQ("\"xyzXabc\"", HttpUtil::Quote("xyzXabc").c_str());
261 }
262
263 TEST(HttpUtilTest, LocateEndOfHeaders) {
264   struct {
265     const char* input;
266     int expected_result;
267   } tests[] = {
268     { "foo\r\nbar\r\n\r\n", 12 },
269     { "foo\nbar\n\n", 9 },
270     { "foo\r\nbar\r\n\r\njunk", 12 },
271     { "foo\nbar\n\njunk", 9 },
272     { "foo\nbar\n\r\njunk", 10 },
273     { "foo\nbar\r\n\njunk", 10 },
274   };
275   for (size_t i = 0; i < arraysize(tests); ++i) {
276     int input_len = static_cast<int>(strlen(tests[i].input));
277     int eoh = HttpUtil::LocateEndOfHeaders(tests[i].input, input_len);
278     EXPECT_EQ(tests[i].expected_result, eoh);
279   }
280 }
281
282 TEST(HttpUtilTest, AssembleRawHeaders) {
283   struct {
284     const char* input;  // with '|' representing '\0'
285     const char* expected_result;  // with '\0' changed to '|'
286   } tests[] = {
287     { "HTTP/1.0 200 OK\r\nFoo: 1\r\nBar: 2\r\n\r\n",
288       "HTTP/1.0 200 OK|Foo: 1|Bar: 2||" },
289
290     { "HTTP/1.0 200 OK\nFoo: 1\nBar: 2\n\n",
291       "HTTP/1.0 200 OK|Foo: 1|Bar: 2||" },
292
293     // Valid line continuation (single SP).
294     {
295       "HTTP/1.0 200 OK\n"
296       "Foo: 1\n"
297       " continuation\n"
298       "Bar: 2\n\n",
299
300       "HTTP/1.0 200 OK|"
301       "Foo: 1 continuation|"
302       "Bar: 2||"
303     },
304
305     // Valid line continuation (single HT).
306     {
307       "HTTP/1.0 200 OK\n"
308       "Foo: 1\n"
309       "\tcontinuation\n"
310       "Bar: 2\n\n",
311
312       "HTTP/1.0 200 OK|"
313       "Foo: 1 continuation|"
314       "Bar: 2||"
315     },
316
317     // Valid line continuation (multiple SP).
318     {
319       "HTTP/1.0 200 OK\n"
320       "Foo: 1\n"
321       "   continuation\n"
322       "Bar: 2\n\n",
323
324       "HTTP/1.0 200 OK|"
325       "Foo: 1 continuation|"
326       "Bar: 2||"
327     },
328
329     // Valid line continuation (multiple HT).
330     {
331       "HTTP/1.0 200 OK\n"
332       "Foo: 1\n"
333       "\t\t\tcontinuation\n"
334       "Bar: 2\n\n",
335
336       "HTTP/1.0 200 OK|"
337       "Foo: 1 continuation|"
338       "Bar: 2||"
339     },
340
341     // Valid line continuation (mixed HT, SP).
342     {
343       "HTTP/1.0 200 OK\n"
344       "Foo: 1\n"
345       " \t \t continuation\n"
346       "Bar: 2\n\n",
347
348       "HTTP/1.0 200 OK|"
349       "Foo: 1 continuation|"
350       "Bar: 2||"
351     },
352
353     // Valid multi-line continuation
354     {
355       "HTTP/1.0 200 OK\n"
356       "Foo: 1\n"
357       " continuation1\n"
358       "\tcontinuation2\n"
359       "  continuation3\n"
360       "Bar: 2\n\n",
361
362       "HTTP/1.0 200 OK|"
363       "Foo: 1 continuation1 continuation2 continuation3|"
364       "Bar: 2||"
365     },
366
367     // Continuation of quoted value.
368     // This is different from what Firefox does, since it
369     // will preserve the LWS.
370     {
371       "HTTP/1.0 200 OK\n"
372       "Etag: \"34534-d3\n"
373       "    134q\"\n"
374       "Bar: 2\n\n",
375
376       "HTTP/1.0 200 OK|"
377       "Etag: \"34534-d3 134q\"|"
378       "Bar: 2||"
379     },
380
381     // Valid multi-line continuation, full LWS lines
382     {
383       "HTTP/1.0 200 OK\n"
384       "Foo: 1\n"
385       "         \n"
386       "\t\t\t\t\n"
387       "\t  continuation\n"
388       "Bar: 2\n\n",
389
390       // One SP per continued line = 3.
391       "HTTP/1.0 200 OK|"
392       "Foo: 1   continuation|"
393       "Bar: 2||"
394     },
395
396     // Valid multi-line continuation, all LWS
397     {
398       "HTTP/1.0 200 OK\n"
399       "Foo: 1\n"
400       "         \n"
401       "\t\t\t\t\n"
402       "\t  \n"
403       "Bar: 2\n\n",
404
405       // One SP per continued line = 3.
406       "HTTP/1.0 200 OK|"
407       "Foo: 1   |"
408       "Bar: 2||"
409     },
410
411     // Valid line continuation (No value bytes in first line).
412     {
413       "HTTP/1.0 200 OK\n"
414       "Foo:\n"
415       " value\n"
416       "Bar: 2\n\n",
417
418       "HTTP/1.0 200 OK|"
419       "Foo: value|"
420       "Bar: 2||"
421     },
422
423     // Not a line continuation (can't continue status line).
424     {
425       "HTTP/1.0 200 OK\n"
426       " Foo: 1\n"
427       "Bar: 2\n\n",
428
429       "HTTP/1.0 200 OK|"
430       " Foo: 1|"
431       "Bar: 2||"
432     },
433
434     // Not a line continuation (can't continue status line).
435     {
436       "HTTP/1.0\n"
437       " 200 OK\n"
438       "Foo: 1\n"
439       "Bar: 2\n\n",
440
441       "HTTP/1.0|"
442       " 200 OK|"
443       "Foo: 1|"
444       "Bar: 2||"
445     },
446
447     // Not a line continuation (can't continue status line).
448     {
449       "HTTP/1.0 404\n"
450       " Not Found\n"
451       "Foo: 1\n"
452       "Bar: 2\n\n",
453
454       "HTTP/1.0 404|"
455       " Not Found|"
456       "Foo: 1|"
457       "Bar: 2||"
458     },
459
460     // Unterminated status line.
461     {
462       "HTTP/1.0 200 OK",
463
464       "HTTP/1.0 200 OK||"
465     },
466
467     // Single terminated, with headers
468     {
469       "HTTP/1.0 200 OK\n"
470       "Foo: 1\n"
471       "Bar: 2\n",
472
473       "HTTP/1.0 200 OK|"
474       "Foo: 1|"
475       "Bar: 2||"
476     },
477
478     // Not terminated, with headers
479     {
480       "HTTP/1.0 200 OK\n"
481       "Foo: 1\n"
482       "Bar: 2",
483
484       "HTTP/1.0 200 OK|"
485       "Foo: 1|"
486       "Bar: 2||"
487     },
488
489     // Not a line continuation (VT)
490     {
491       "HTTP/1.0 200 OK\n"
492       "Foo: 1\n"
493       "\vInvalidContinuation\n"
494       "Bar: 2\n\n",
495
496       "HTTP/1.0 200 OK|"
497       "Foo: 1|"
498       "\vInvalidContinuation|"
499       "Bar: 2||"
500     },
501
502     // Not a line continuation (formfeed)
503     {
504       "HTTP/1.0 200 OK\n"
505       "Foo: 1\n"
506       "\fInvalidContinuation\n"
507       "Bar: 2\n\n",
508
509       "HTTP/1.0 200 OK|"
510       "Foo: 1|"
511       "\fInvalidContinuation|"
512       "Bar: 2||"
513     },
514
515     // Not a line continuation -- can't continue header names.
516     {
517       "HTTP/1.0 200 OK\n"
518       "Serv\n"
519       " er: Apache\n"
520       "\tInvalidContinuation\n"
521       "Bar: 2\n\n",
522
523       "HTTP/1.0 200 OK|"
524       "Serv|"
525       " er: Apache|"
526       "\tInvalidContinuation|"
527       "Bar: 2||"
528     },
529
530     // Not a line continuation -- no value to continue.
531     {
532       "HTTP/1.0 200 OK\n"
533       "Foo: 1\n"
534       "garbage\n"
535       "  not-a-continuation\n"
536       "Bar: 2\n\n",
537
538       "HTTP/1.0 200 OK|"
539       "Foo: 1|"
540       "garbage|"
541       "  not-a-continuation|"
542       "Bar: 2||",
543     },
544
545     // Not a line continuation -- no valid name.
546     {
547       "HTTP/1.0 200 OK\n"
548       ": 1\n"
549       "  garbage\n"
550       "Bar: 2\n\n",
551
552       "HTTP/1.0 200 OK|"
553       ": 1|"
554       "  garbage|"
555       "Bar: 2||",
556     },
557
558     // Not a line continuation -- no valid name (whitespace)
559     {
560       "HTTP/1.0 200 OK\n"
561       "   : 1\n"
562       "  garbage\n"
563       "Bar: 2\n\n",
564
565       "HTTP/1.0 200 OK|"
566       "   : 1|"
567       "  garbage|"
568       "Bar: 2||",
569     },
570
571     // Embed NULLs in the status line. They should not be understood
572     // as line separators.
573     {
574       "HTTP/1.0 200 OK|Bar2:0|Baz2:1\r\nFoo: 1\r\nBar: 2\r\n\r\n",
575       "HTTP/1.0 200 OKBar2:0Baz2:1|Foo: 1|Bar: 2||"
576     },
577
578     // Embed NULLs in a header line. They should not be understood as
579     // line separators.
580     {
581       "HTTP/1.0 200 OK\nFoo: 1|Foo2: 3\nBar: 2\n\n",
582       "HTTP/1.0 200 OK|Foo: 1Foo2: 3|Bar: 2||"
583     },
584   };
585   for (size_t i = 0; i < arraysize(tests); ++i) {
586     std::string input = tests[i].input;
587     std::replace(input.begin(), input.end(), '|', '\0');
588     std::string raw = HttpUtil::AssembleRawHeaders(input.data(), input.size());
589     std::replace(raw.begin(), raw.end(), '\0', '|');
590     EXPECT_EQ(tests[i].expected_result, raw);
591   }
592 }
593
594 // Test SpecForRequest() and PathForRequest().
595 TEST(HttpUtilTest, RequestUrlSanitize) {
596   struct {
597     const char* url;
598     const char* expected_spec;
599     const char* expected_path;
600   } tests[] = {
601     { // Check that #hash is removed.
602       "http://www.google.com:78/foobar?query=1#hash",
603       "http://www.google.com:78/foobar?query=1",
604       "/foobar?query=1"
605     },
606     { // The reference may itself contain # -- strip all of it.
607       "http://192.168.0.1?query=1#hash#10#11#13#14",
608       "http://192.168.0.1/?query=1",
609       "/?query=1"
610     },
611     { // Strip username/password.
612       "http://user:pass@google.com",
613       "http://google.com/",
614       "/"
615     },
616     { // https scheme
617       "https://www.google.com:78/foobar?query=1#hash",
618       "https://www.google.com:78/foobar?query=1",
619       "/foobar?query=1"
620     },
621     { // WebSocket's ws scheme
622       "ws://www.google.com:78/foobar?query=1#hash",
623       "ws://www.google.com:78/foobar?query=1",
624       "/foobar?query=1"
625     },
626     { // WebSocket's wss scheme
627       "wss://www.google.com:78/foobar?query=1#hash",
628       "wss://www.google.com:78/foobar?query=1",
629       "/foobar?query=1"
630     }
631   };
632   for (size_t i = 0; i < arraysize(tests); ++i) {
633     GURL url(GURL(tests[i].url));
634     std::string expected_spec(tests[i].expected_spec);
635     std::string expected_path(tests[i].expected_path);
636
637     EXPECT_EQ(expected_spec, HttpUtil::SpecForRequest(url));
638     EXPECT_EQ(expected_path, HttpUtil::PathForRequest(url));
639   }
640 }
641
642 // Test SpecForRequest() for "ftp" scheme.
643 TEST(HttpUtilTest, SpecForRequestForUrlWithFtpScheme) {
644   GURL ftp_url("ftp://user:pass@google.com/pub/chromium/");
645   EXPECT_EQ("ftp://google.com/pub/chromium/",
646             HttpUtil::SpecForRequest(ftp_url));
647 }
648
649 TEST(HttpUtilTest, GenerateAcceptLanguageHeader) {
650   EXPECT_EQ(std::string("en-US,fr;q=0.8,de;q=0.6"),
651             HttpUtil::GenerateAcceptLanguageHeader("en-US,fr,de"));
652   EXPECT_EQ(std::string("en-US,fr;q=0.8,de;q=0.6,ko;q=0.4,zh-CN;q=0.2,"
653                         "ja;q=0.2"),
654             HttpUtil::GenerateAcceptLanguageHeader("en-US,fr,de,ko,zh-CN,ja"));
655 }
656
657 // HttpResponseHeadersTest.GetMimeType also tests ParseContentType.
658 TEST(HttpUtilTest, ParseContentType) {
659   const struct {
660     const char* content_type;
661     const char* expected_mime_type;
662     const char* expected_charset;
663     const bool expected_had_charset;
664     const char* expected_boundary;
665   } tests[] = {
666     { "text/html; charset=utf-8",
667       "text/html",
668       "utf-8",
669       true,
670       ""
671     },
672     { "text/html; charset =utf-8",
673       "text/html",
674       "utf-8",
675       true,
676       ""
677     },
678     { "text/html; charset= utf-8",
679       "text/html",
680       "utf-8",
681       true,
682       ""
683     },
684     { "text/html; charset=utf-8 ",
685       "text/html",
686       "utf-8",
687       true,
688       ""
689     },
690     { "text/html; boundary=\"WebKit-ada-df-dsf-adsfadsfs\"",
691       "text/html",
692       "",
693       false,
694       "\"WebKit-ada-df-dsf-adsfadsfs\""
695     },
696     { "text/html; boundary =\"WebKit-ada-df-dsf-adsfadsfs\"",
697       "text/html",
698       "",
699       false,
700       "\"WebKit-ada-df-dsf-adsfadsfs\""
701     },
702     { "text/html; boundary= \"WebKit-ada-df-dsf-adsfadsfs\"",
703       "text/html",
704       "",
705       false,
706       "\"WebKit-ada-df-dsf-adsfadsfs\""
707     },
708     { "text/html; boundary= \"WebKit-ada-df-dsf-adsfadsfs\"   ",
709       "text/html",
710       "",
711       false,
712       "\"WebKit-ada-df-dsf-adsfadsfs\""
713     },
714     { "text/html; boundary=\"WebKit-ada-df-dsf-adsfadsfs  \"",
715       "text/html",
716       "",
717       false,
718       "\"WebKit-ada-df-dsf-adsfadsfs  \""
719     },
720     { "text/html; boundary=WebKit-ada-df-dsf-adsfadsfs",
721       "text/html",
722       "",
723       false,
724       "WebKit-ada-df-dsf-adsfadsfs"
725     },
726     // TODO(abarth): Add more interesting test cases.
727   };
728   for (size_t i = 0; i < arraysize(tests); ++i) {
729     std::string mime_type;
730     std::string charset;
731     bool had_charset = false;
732     std::string boundary;
733     net::HttpUtil::ParseContentType(tests[i].content_type, &mime_type,
734                                     &charset, &had_charset, &boundary);
735     EXPECT_EQ(tests[i].expected_mime_type, mime_type) << "i=" << i;
736     EXPECT_EQ(tests[i].expected_charset, charset) << "i=" << i;
737     EXPECT_EQ(tests[i].expected_had_charset, had_charset) << "i=" << i;
738     EXPECT_EQ(tests[i].expected_boundary, boundary) << "i=" << i;
739   }
740 }
741
742 TEST(HttpUtilTest, ParseRanges) {
743   const struct {
744     const char* headers;
745     bool expected_return_value;
746     size_t expected_ranges_size;
747     const struct {
748       int64 expected_first_byte_position;
749       int64 expected_last_byte_position;
750       int64 expected_suffix_length;
751     } expected_ranges[10];
752   } tests[] = {
753     { "Range: bytes=0-10",
754       true,
755       1,
756       { {0, 10, -1}, }
757     },
758     { "Range: bytes=10-0",
759       false,
760       0,
761       {}
762     },
763     { "Range: BytES=0-10",
764       true,
765       1,
766       { {0, 10, -1}, }
767     },
768     { "Range: megabytes=0-10",
769       false,
770       0,
771       {}
772     },
773     { "Range: bytes0-10",
774       false,
775       0,
776       {}
777     },
778     { "Range: bytes=0-0,0-10,10-20,100-200,100-,-200",
779       true,
780       6,
781       { {0, 0, -1},
782         {0, 10, -1},
783         {10, 20, -1},
784         {100, 200, -1},
785         {100, -1, -1},
786         {-1, -1, 200},
787       }
788     },
789     { "Range: bytes=0-10\r\n"
790       "Range: bytes=0-10,10-20,100-200,100-,-200",
791       true,
792       1,
793       { {0, 10, -1}
794       }
795     },
796     { "Range: bytes=",
797       false,
798       0,
799       {}
800     },
801     { "Range: bytes=-",
802       false,
803       0,
804       {}
805     },
806     { "Range: bytes=0-10-",
807       false,
808       0,
809       {}
810     },
811     { "Range: bytes=-0-10",
812       false,
813       0,
814       {}
815     },
816     { "Range: bytes =0-10\r\n",
817       true,
818       1,
819       { {0, 10, -1}
820       }
821     },
822     { "Range: bytes=  0-10      \r\n",
823       true,
824       1,
825       { {0, 10, -1}
826       }
827     },
828     { "Range: bytes  =   0  -   10      \r\n",
829       true,
830       1,
831       { {0, 10, -1}
832       }
833     },
834     { "Range: bytes=   0-1   0\r\n",
835       false,
836       0,
837       {}
838     },
839     { "Range: bytes=   0-     -10\r\n",
840       false,
841       0,
842       {}
843     },
844     { "Range: bytes=   0  -  1   ,   10 -20,   100- 200 ,  100-,  -200 \r\n",
845       true,
846       5,
847       { {0, 1, -1},
848         {10, 20, -1},
849         {100, 200, -1},
850         {100, -1, -1},
851         {-1, -1, 200},
852       }
853     },
854   };
855
856   for (size_t i = 0; i < arraysize(tests); ++i) {
857     std::vector<net::HttpByteRange> ranges;
858     bool return_value = HttpUtil::ParseRanges(std::string(tests[i].headers),
859                                               &ranges);
860     EXPECT_EQ(tests[i].expected_return_value, return_value);
861     if (return_value) {
862       EXPECT_EQ(tests[i].expected_ranges_size, ranges.size());
863       for (size_t j = 0; j < ranges.size(); ++j) {
864         EXPECT_EQ(tests[i].expected_ranges[j].expected_first_byte_position,
865                   ranges[j].first_byte_position());
866         EXPECT_EQ(tests[i].expected_ranges[j].expected_last_byte_position,
867                   ranges[j].last_byte_position());
868         EXPECT_EQ(tests[i].expected_ranges[j].expected_suffix_length,
869                   ranges[j].suffix_length());
870       }
871     }
872   }
873 }
874
875 TEST(HttpUtilTest, ParseRetryAfterHeader) {
876   base::Time::Exploded now_exploded = { 2014, 11, -1, 5, 22, 39, 30, 0 };
877   base::Time now = base::Time::FromUTCExploded(now_exploded);
878
879   base::Time::Exploded later_exploded = { 2015, 1, -1, 1, 12, 34, 56, 0 };
880   base::Time later = base::Time::FromUTCExploded(later_exploded);
881
882   const struct {
883     const char* retry_after_string;
884     bool expected_return_value;
885     base::TimeDelta expected_retry_after;
886   } tests[] = {
887     { "", false, base::TimeDelta() },
888     { "-3", false, base::TimeDelta() },
889     { "-2", false, base::TimeDelta() },
890     { "-1", false, base::TimeDelta() },
891     { "0", true, base::TimeDelta::FromSeconds(0) },
892     { "1", true, base::TimeDelta::FromSeconds(1) },
893     { "2", true, base::TimeDelta::FromSeconds(2) },
894     { "3", true, base::TimeDelta::FromSeconds(3) },
895     { "60", true, base::TimeDelta::FromSeconds(60) },
896     { "3600", true, base::TimeDelta::FromSeconds(3600) },
897     { "86400", true, base::TimeDelta::FromSeconds(86400) },
898     { "Thu, 1 Jan 2015 12:34:56 GMT", true, later - now },
899     { "Mon, 1 Jan 1900 12:34:56 GMT", false, base::TimeDelta() }
900   };
901
902   for (size_t i = 0; i < arraysize(tests); ++i) {
903     base::TimeDelta retry_after;
904     bool return_value = HttpUtil::ParseRetryAfterHeader(
905         tests[i].retry_after_string, now, &retry_after);
906     EXPECT_EQ(tests[i].expected_return_value, return_value)
907         << "Test case " << i << ": expected " << tests[i].expected_return_value
908         << " but got " << return_value << ".";
909     if (tests[i].expected_return_value && return_value) {
910       EXPECT_EQ(tests[i].expected_retry_after, retry_after)
911           << "Test case " << i << ": expected "
912           << tests[i].expected_retry_after.InSeconds() << "s but got "
913           << retry_after.InSeconds() << "s.";
914     }
915   }
916 }
917
918 namespace {
919 void CheckCurrentNameValuePair(HttpUtil::NameValuePairsIterator* parser,
920                                bool expect_valid,
921                                std::string expected_name,
922                                std::string expected_value) {
923   ASSERT_EQ(expect_valid, parser->valid());
924   if (!expect_valid) {
925     return;
926   }
927
928   // Let's make sure that these never change (i.e., when a quoted value is
929   // unquoted, it should be cached on the first calls and not regenerated
930   // later).
931   std::string::const_iterator first_value_begin = parser->value_begin();
932   std::string::const_iterator first_value_end = parser->value_end();
933
934   ASSERT_EQ(expected_name, std::string(parser->name_begin(),
935                                        parser->name_end()));
936   ASSERT_EQ(expected_name, parser->name());
937   ASSERT_EQ(expected_value, std::string(parser->value_begin(),
938                                         parser->value_end()));
939   ASSERT_EQ(expected_value, parser->value());
940
941   // Make sure they didn't/don't change.
942   ASSERT_TRUE(first_value_begin == parser->value_begin());
943   ASSERT_TRUE(first_value_end == parser->value_end());
944 }
945
946 void CheckNextNameValuePair(HttpUtil::NameValuePairsIterator* parser,
947                             bool expect_next,
948                             bool expect_valid,
949                             std::string expected_name,
950                             std::string expected_value) {
951   ASSERT_EQ(expect_next, parser->GetNext());
952   ASSERT_EQ(expect_valid, parser->valid());
953   if (!expect_next || !expect_valid) {
954     return;
955   }
956
957   CheckCurrentNameValuePair(parser,
958                             expect_valid,
959                             expected_name,
960                             expected_value);
961 }
962
963 void CheckInvalidNameValuePair(std::string valid_part,
964                                std::string invalid_part) {
965   std::string whole_string = valid_part + invalid_part;
966
967   HttpUtil::NameValuePairsIterator valid_parser(valid_part.begin(),
968                                                 valid_part.end(),
969                                                 ';');
970   HttpUtil::NameValuePairsIterator invalid_parser(whole_string.begin(),
971                                                   whole_string.end(),
972                                                   ';');
973
974   ASSERT_TRUE(valid_parser.valid());
975   ASSERT_TRUE(invalid_parser.valid());
976
977   // Both parsers should return all the same values until "valid_parser" is
978   // exhausted.
979   while (valid_parser.GetNext()) {
980     ASSERT_TRUE(invalid_parser.GetNext());
981     ASSERT_TRUE(valid_parser.valid());
982     ASSERT_TRUE(invalid_parser.valid());
983     ASSERT_EQ(valid_parser.name(), invalid_parser.name());
984     ASSERT_EQ(valid_parser.value(), invalid_parser.value());
985   }
986
987   // valid_parser is exhausted and remains 'valid'
988   ASSERT_TRUE(valid_parser.valid());
989
990   // invalid_parser's corresponding call to GetNext also returns false...
991   ASSERT_FALSE(invalid_parser.GetNext());
992   // ...but the parser is in an invalid state.
993   ASSERT_FALSE(invalid_parser.valid());
994 }
995
996 }  // anonymous namespace
997
998 TEST(HttpUtilTest, NameValuePairsIteratorCopyAndAssign) {
999   std::string data = "alpha='\\'a\\''; beta=\" b \"; cappa='c;'; delta=\"d\"";
1000   HttpUtil::NameValuePairsIterator parser_a(data.begin(), data.end(), ';');
1001
1002   EXPECT_TRUE(parser_a.valid());
1003   ASSERT_NO_FATAL_FAILURE(
1004       CheckNextNameValuePair(&parser_a, true, true, "alpha", "'a'"));
1005
1006   HttpUtil::NameValuePairsIterator parser_b(parser_a);
1007   // a and b now point to same location
1008   ASSERT_NO_FATAL_FAILURE(
1009       CheckCurrentNameValuePair(&parser_b, true, "alpha", "'a'"));
1010   ASSERT_NO_FATAL_FAILURE(
1011       CheckCurrentNameValuePair(&parser_a, true, "alpha", "'a'"));
1012
1013   // advance a, no effect on b
1014   ASSERT_NO_FATAL_FAILURE(
1015       CheckNextNameValuePair(&parser_a, true, true, "beta", " b "));
1016   ASSERT_NO_FATAL_FAILURE(
1017       CheckCurrentNameValuePair(&parser_b, true, "alpha", "'a'"));
1018
1019   // assign b the current state of a, no effect on a
1020   parser_b = parser_a;
1021   ASSERT_NO_FATAL_FAILURE(
1022       CheckCurrentNameValuePair(&parser_b, true, "beta", " b "));
1023   ASSERT_NO_FATAL_FAILURE(
1024       CheckCurrentNameValuePair(&parser_a, true, "beta", " b "));
1025
1026   // advance b, no effect on a
1027   ASSERT_NO_FATAL_FAILURE(
1028       CheckNextNameValuePair(&parser_b, true, true, "cappa", "c;"));
1029   ASSERT_NO_FATAL_FAILURE(
1030       CheckCurrentNameValuePair(&parser_a, true, "beta", " b "));
1031 }
1032
1033 TEST(HttpUtilTest, NameValuePairsIteratorEmptyInput) {
1034   std::string data;
1035   HttpUtil::NameValuePairsIterator parser(data.begin(), data.end(), ';');
1036
1037   EXPECT_TRUE(parser.valid());
1038   ASSERT_NO_FATAL_FAILURE(CheckNextNameValuePair(
1039       &parser, false, true, std::string(), std::string()));
1040 }
1041
1042 TEST(HttpUtilTest, NameValuePairsIterator) {
1043   std::string data = "alpha=1; beta= 2 ;cappa =' 3; ';"
1044                      "delta= \" \\\"4\\\" \"; e= \" '5'\"; e=6;"
1045                      "f='\\'\\h\\e\\l\\l\\o\\ \\w\\o\\r\\l\\d\\'';"
1046                      "g=''; h='hello'";
1047   HttpUtil::NameValuePairsIterator parser(data.begin(), data.end(), ';');
1048   EXPECT_TRUE(parser.valid());
1049
1050   ASSERT_NO_FATAL_FAILURE(
1051       CheckNextNameValuePair(&parser, true, true, "alpha", "1"));
1052   ASSERT_NO_FATAL_FAILURE(
1053       CheckNextNameValuePair(&parser, true, true, "beta", "2"));
1054   ASSERT_NO_FATAL_FAILURE(
1055       CheckNextNameValuePair(&parser, true, true, "cappa", " 3; "));
1056   ASSERT_NO_FATAL_FAILURE(
1057       CheckNextNameValuePair(&parser, true, true, "delta", " \"4\" "));
1058   ASSERT_NO_FATAL_FAILURE(
1059       CheckNextNameValuePair(&parser, true, true, "e", " '5'"));
1060   ASSERT_NO_FATAL_FAILURE(
1061       CheckNextNameValuePair(&parser, true, true, "e", "6"));
1062   ASSERT_NO_FATAL_FAILURE(
1063       CheckNextNameValuePair(&parser, true, true, "f", "'hello world'"));
1064   ASSERT_NO_FATAL_FAILURE(
1065       CheckNextNameValuePair(&parser, true, true, "g", std::string()));
1066   ASSERT_NO_FATAL_FAILURE(
1067       CheckNextNameValuePair(&parser, true, true, "h", "hello"));
1068   ASSERT_NO_FATAL_FAILURE(CheckNextNameValuePair(
1069       &parser, false, true, std::string(), std::string()));
1070 }
1071
1072 TEST(HttpUtilTest, NameValuePairsIteratorIllegalInputs) {
1073   ASSERT_NO_FATAL_FAILURE(CheckInvalidNameValuePair("alpha=1", "; beta"));
1074   ASSERT_NO_FATAL_FAILURE(CheckInvalidNameValuePair(std::string(), "beta"));
1075
1076   ASSERT_NO_FATAL_FAILURE(CheckInvalidNameValuePair("alpha=1", "; 'beta'=2"));
1077   ASSERT_NO_FATAL_FAILURE(CheckInvalidNameValuePair(std::string(), "'beta'=2"));
1078   ASSERT_NO_FATAL_FAILURE(CheckInvalidNameValuePair("alpha=1", ";beta="));
1079   ASSERT_NO_FATAL_FAILURE(CheckInvalidNameValuePair("alpha=1",
1080                                                     ";beta=;cappa=2"));
1081
1082   // According to the spec this is an error, but it doesn't seem appropriate to
1083   // change our behaviour to be less permissive at this time.
1084   // See NameValuePairsIteratorExtraSeparators test
1085   // ASSERT_NO_FATAL_FAILURE(CheckInvalidNameValuePair("alpha=1", ";; beta=2"));
1086 }
1087
1088 // If we are going to support extra separators against the spec, let's just make
1089 // sure they work rationally.
1090 TEST(HttpUtilTest, NameValuePairsIteratorExtraSeparators) {
1091   std::string data = " ; ;;alpha=1; ;; ; beta= 2;cappa=3;;; ; ";
1092   HttpUtil::NameValuePairsIterator parser(data.begin(), data.end(), ';');
1093   EXPECT_TRUE(parser.valid());
1094
1095   ASSERT_NO_FATAL_FAILURE(
1096       CheckNextNameValuePair(&parser, true, true, "alpha", "1"));
1097   ASSERT_NO_FATAL_FAILURE(
1098       CheckNextNameValuePair(&parser, true, true, "beta", "2"));
1099   ASSERT_NO_FATAL_FAILURE(
1100       CheckNextNameValuePair(&parser, true, true, "cappa", "3"));
1101   ASSERT_NO_FATAL_FAILURE(CheckNextNameValuePair(
1102       &parser, false, true, std::string(), std::string()));
1103 }
1104
1105 // See comments on the implementation of NameValuePairsIterator::GetNext
1106 // regarding this derogation from the spec.
1107 TEST(HttpUtilTest, NameValuePairsIteratorMissingEndQuote) {
1108   std::string data = "name='value";
1109   HttpUtil::NameValuePairsIterator parser(data.begin(), data.end(), ';');
1110   EXPECT_TRUE(parser.valid());
1111
1112   ASSERT_NO_FATAL_FAILURE(
1113       CheckNextNameValuePair(&parser, true, true, "name", "value"));
1114   ASSERT_NO_FATAL_FAILURE(CheckNextNameValuePair(
1115       &parser, false, true, std::string(), std::string()));
1116 }