• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
TEST(HttpUtilTest,IsSafeHeader)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 
TEST(HttpUtilTest,HasHeader)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_UNSAFE(tests); ++i) {
118     bool result = HttpUtil::HasHeader(tests[i].headers, tests[i].name);
119     EXPECT_EQ(tests[i].expected_result, result);
120   }
121 }
122 
TEST(HttpUtilTest,StripHeaders)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 
TEST(HttpUtilTest,HeadersIterator)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 
TEST(HttpUtilTest,HeadersIterator_MalformedLine)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 
TEST(HttpUtilTest,HeadersIterator_AdvanceTo)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 
TEST(HttpUtilTest,HeadersIterator_Reset)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 
TEST(HttpUtilTest,ValuesIterator)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 
TEST(HttpUtilTest,ValuesIterator_Blanks)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 
TEST(HttpUtilTest,Unquote)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 
TEST(HttpUtilTest,Quote)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 
TEST(HttpUtilTest,LocateEndOfHeaders)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_UNSAFE(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 
TEST(HttpUtilTest,AssembleRawHeaders)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_UNSAFE(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().
TEST(HttpUtilTest,RequestUrlSanitize)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_UNSAFE(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.
TEST(HttpUtilTest,SpecForRequestForUrlWithFtpScheme)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 
TEST(HttpUtilTest,GenerateAcceptLanguageHeader)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.
TEST(HttpUtilTest,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_UNSAFE(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 
TEST(HttpUtilTest,ParseRanges)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_UNSAFE(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 namespace {
CheckCurrentNameValuePair(HttpUtil::NameValuePairsIterator * parser,bool expect_valid,std::string expected_name,std::string expected_value)876 void CheckCurrentNameValuePair(HttpUtil::NameValuePairsIterator* parser,
877                                bool expect_valid,
878                                std::string expected_name,
879                                std::string expected_value) {
880   ASSERT_EQ(expect_valid, parser->valid());
881   if (!expect_valid) {
882     return;
883   }
884 
885   // Let's make sure that these never change (i.e., when a quoted value is
886   // unquoted, it should be cached on the first calls and not regenerated
887   // later).
888   std::string::const_iterator first_value_begin = parser->value_begin();
889   std::string::const_iterator first_value_end = parser->value_end();
890 
891   ASSERT_EQ(expected_name, std::string(parser->name_begin(),
892                                        parser->name_end()));
893   ASSERT_EQ(expected_name, parser->name());
894   ASSERT_EQ(expected_value, std::string(parser->value_begin(),
895                                         parser->value_end()));
896   ASSERT_EQ(expected_value, parser->value());
897 
898   // Make sure they didn't/don't change.
899   ASSERT_TRUE(first_value_begin == parser->value_begin());
900   ASSERT_TRUE(first_value_end == parser->value_end());
901 }
902 
CheckNextNameValuePair(HttpUtil::NameValuePairsIterator * parser,bool expect_next,bool expect_valid,std::string expected_name,std::string expected_value)903 void CheckNextNameValuePair(HttpUtil::NameValuePairsIterator* parser,
904                             bool expect_next,
905                             bool expect_valid,
906                             std::string expected_name,
907                             std::string expected_value) {
908   ASSERT_EQ(expect_next, parser->GetNext());
909   ASSERT_EQ(expect_valid, parser->valid());
910   if (!expect_next || !expect_valid) {
911     return;
912   }
913 
914   CheckCurrentNameValuePair(parser,
915                             expect_valid,
916                             expected_name,
917                             expected_value);
918 }
919 
CheckInvalidNameValuePair(std::string valid_part,std::string invalid_part)920 void CheckInvalidNameValuePair(std::string valid_part,
921                                std::string invalid_part) {
922   std::string whole_string = valid_part + invalid_part;
923 
924   HttpUtil::NameValuePairsIterator valid_parser(valid_part.begin(),
925                                                 valid_part.end(),
926                                                 ';');
927   HttpUtil::NameValuePairsIterator invalid_parser(whole_string.begin(),
928                                                   whole_string.end(),
929                                                   ';');
930 
931   ASSERT_TRUE(valid_parser.valid());
932   ASSERT_TRUE(invalid_parser.valid());
933 
934   // Both parsers should return all the same values until "valid_parser" is
935   // exhausted.
936   while (valid_parser.GetNext()) {
937     ASSERT_TRUE(invalid_parser.GetNext());
938     ASSERT_TRUE(valid_parser.valid());
939     ASSERT_TRUE(invalid_parser.valid());
940     ASSERT_EQ(valid_parser.name(), invalid_parser.name());
941     ASSERT_EQ(valid_parser.value(), invalid_parser.value());
942   }
943 
944   // valid_parser is exhausted and remains 'valid'
945   ASSERT_TRUE(valid_parser.valid());
946 
947   // invalid_parser's corresponding call to GetNext also returns false...
948   ASSERT_FALSE(invalid_parser.GetNext());
949   // ...but the parser is in an invalid state.
950   ASSERT_FALSE(invalid_parser.valid());
951 }
952 
953 }  // anonymous namespace
954 
TEST(HttpUtilTest,NameValuePairsIteratorCopyAndAssign)955 TEST(HttpUtilTest, NameValuePairsIteratorCopyAndAssign) {
956   std::string data = "alpha='\\'a\\''; beta=\" b \"; cappa='c;'; delta=\"d\"";
957   HttpUtil::NameValuePairsIterator parser_a(data.begin(), data.end(), ';');
958 
959   EXPECT_TRUE(parser_a.valid());
960   ASSERT_NO_FATAL_FAILURE(
961       CheckNextNameValuePair(&parser_a, true, true, "alpha", "'a'"));
962 
963   HttpUtil::NameValuePairsIterator parser_b(parser_a);
964   // a and b now point to same location
965   ASSERT_NO_FATAL_FAILURE(
966       CheckCurrentNameValuePair(&parser_b, true, "alpha", "'a'"));
967   ASSERT_NO_FATAL_FAILURE(
968       CheckCurrentNameValuePair(&parser_a, true, "alpha", "'a'"));
969 
970   // advance a, no effect on b
971   ASSERT_NO_FATAL_FAILURE(
972       CheckNextNameValuePair(&parser_a, true, true, "beta", " b "));
973   ASSERT_NO_FATAL_FAILURE(
974       CheckCurrentNameValuePair(&parser_b, true, "alpha", "'a'"));
975 
976   // assign b the current state of a, no effect on a
977   parser_b = parser_a;
978   ASSERT_NO_FATAL_FAILURE(
979       CheckCurrentNameValuePair(&parser_b, true, "beta", " b "));
980   ASSERT_NO_FATAL_FAILURE(
981       CheckCurrentNameValuePair(&parser_a, true, "beta", " b "));
982 
983   // advance b, no effect on a
984   ASSERT_NO_FATAL_FAILURE(
985       CheckNextNameValuePair(&parser_b, true, true, "cappa", "c;"));
986   ASSERT_NO_FATAL_FAILURE(
987       CheckCurrentNameValuePair(&parser_a, true, "beta", " b "));
988 }
989 
TEST(HttpUtilTest,NameValuePairsIteratorEmptyInput)990 TEST(HttpUtilTest, NameValuePairsIteratorEmptyInput) {
991   std::string data;
992   HttpUtil::NameValuePairsIterator parser(data.begin(), data.end(), ';');
993 
994   EXPECT_TRUE(parser.valid());
995   ASSERT_NO_FATAL_FAILURE(CheckNextNameValuePair(
996       &parser, false, true, std::string(), std::string()));
997 }
998 
TEST(HttpUtilTest,NameValuePairsIterator)999 TEST(HttpUtilTest, NameValuePairsIterator) {
1000   std::string data = "alpha=1; beta= 2 ;cappa =' 3; ';"
1001                      "delta= \" \\\"4\\\" \"; e= \" '5'\"; e=6;"
1002                      "f='\\'\\h\\e\\l\\l\\o\\ \\w\\o\\r\\l\\d\\'';"
1003                      "g=''; h='hello'";
1004   HttpUtil::NameValuePairsIterator parser(data.begin(), data.end(), ';');
1005   EXPECT_TRUE(parser.valid());
1006 
1007   ASSERT_NO_FATAL_FAILURE(
1008       CheckNextNameValuePair(&parser, true, true, "alpha", "1"));
1009   ASSERT_NO_FATAL_FAILURE(
1010       CheckNextNameValuePair(&parser, true, true, "beta", "2"));
1011   ASSERT_NO_FATAL_FAILURE(
1012       CheckNextNameValuePair(&parser, true, true, "cappa", " 3; "));
1013   ASSERT_NO_FATAL_FAILURE(
1014       CheckNextNameValuePair(&parser, true, true, "delta", " \"4\" "));
1015   ASSERT_NO_FATAL_FAILURE(
1016       CheckNextNameValuePair(&parser, true, true, "e", " '5'"));
1017   ASSERT_NO_FATAL_FAILURE(
1018       CheckNextNameValuePair(&parser, true, true, "e", "6"));
1019   ASSERT_NO_FATAL_FAILURE(
1020       CheckNextNameValuePair(&parser, true, true, "f", "'hello world'"));
1021   ASSERT_NO_FATAL_FAILURE(
1022       CheckNextNameValuePair(&parser, true, true, "g", std::string()));
1023   ASSERT_NO_FATAL_FAILURE(
1024       CheckNextNameValuePair(&parser, true, true, "h", "hello"));
1025   ASSERT_NO_FATAL_FAILURE(CheckNextNameValuePair(
1026       &parser, false, true, std::string(), std::string()));
1027 }
1028 
TEST(HttpUtilTest,NameValuePairsIteratorIllegalInputs)1029 TEST(HttpUtilTest, NameValuePairsIteratorIllegalInputs) {
1030   ASSERT_NO_FATAL_FAILURE(CheckInvalidNameValuePair("alpha=1", "; beta"));
1031   ASSERT_NO_FATAL_FAILURE(CheckInvalidNameValuePair(std::string(), "beta"));
1032 
1033   ASSERT_NO_FATAL_FAILURE(CheckInvalidNameValuePair("alpha=1", "; 'beta'=2"));
1034   ASSERT_NO_FATAL_FAILURE(CheckInvalidNameValuePair(std::string(), "'beta'=2"));
1035   ASSERT_NO_FATAL_FAILURE(CheckInvalidNameValuePair("alpha=1", ";beta="));
1036   ASSERT_NO_FATAL_FAILURE(CheckInvalidNameValuePair("alpha=1",
1037                                                     ";beta=;cappa=2"));
1038 
1039   // According to the spec this is an error, but it doesn't seem appropriate to
1040   // change our behaviour to be less permissive at this time.
1041   // See NameValuePairsIteratorExtraSeparators test
1042   // ASSERT_NO_FATAL_FAILURE(CheckInvalidNameValuePair("alpha=1", ";; beta=2"));
1043 }
1044 
1045 // If we are going to support extra separators against the spec, let's just make
1046 // sure they work rationally.
TEST(HttpUtilTest,NameValuePairsIteratorExtraSeparators)1047 TEST(HttpUtilTest, NameValuePairsIteratorExtraSeparators) {
1048   std::string data = " ; ;;alpha=1; ;; ; beta= 2;cappa=3;;; ; ";
1049   HttpUtil::NameValuePairsIterator parser(data.begin(), data.end(), ';');
1050   EXPECT_TRUE(parser.valid());
1051 
1052   ASSERT_NO_FATAL_FAILURE(
1053       CheckNextNameValuePair(&parser, true, true, "alpha", "1"));
1054   ASSERT_NO_FATAL_FAILURE(
1055       CheckNextNameValuePair(&parser, true, true, "beta", "2"));
1056   ASSERT_NO_FATAL_FAILURE(
1057       CheckNextNameValuePair(&parser, true, true, "cappa", "3"));
1058   ASSERT_NO_FATAL_FAILURE(CheckNextNameValuePair(
1059       &parser, false, true, std::string(), std::string()));
1060 }
1061 
1062 // See comments on the implementation of NameValuePairsIterator::GetNext
1063 // regarding this derogation from the spec.
TEST(HttpUtilTest,NameValuePairsIteratorMissingEndQuote)1064 TEST(HttpUtilTest, NameValuePairsIteratorMissingEndQuote) {
1065   std::string data = "name='value";
1066   HttpUtil::NameValuePairsIterator parser(data.begin(), data.end(), ';');
1067   EXPECT_TRUE(parser.valid());
1068 
1069   ASSERT_NO_FATAL_FAILURE(
1070       CheckNextNameValuePair(&parser, true, true, "name", "value"));
1071   ASSERT_NO_FATAL_FAILURE(CheckNextNameValuePair(
1072       &parser, false, true, std::string(), std::string()));
1073 }
1074