1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include <algorithm>
6 #include <limits>
7 
8 #include "base/stl_util.h"
9 #include "base/strings/string_util.h"
10 #include "net/http/http_util.h"
11 #include "testing/gtest/include/gtest/gtest.h"
12 
13 namespace net {
14 
TEST(HttpUtilTest,IsSafeHeader)15 TEST(HttpUtilTest, IsSafeHeader) {
16   static const char* const unsafe_headers[] = {
17       "sec-",
18       "sEc-",
19       "sec-foo",
20       "sEc-FoO",
21       "proxy-",
22       "pRoXy-",
23       "proxy-foo",
24       "pRoXy-FoO",
25       "accept-charset",
26       "accept-encoding",
27       "access-control-request-headers",
28       "access-control-request-method",
29       "connection",
30       "content-length",
31       "cookie",
32       "cookie2",
33       "date",
34       "dnt",
35       "expect",
36       "host",
37       "keep-alive",
38       "origin",
39       "referer",
40       "te",
41       "trailer",
42       "transfer-encoding",
43       "upgrade",
44       "user-agent",
45       "via",
46   };
47   for (size_t i = 0; i < base::size(unsafe_headers); ++i) {
48     EXPECT_FALSE(HttpUtil::IsSafeHeader(unsafe_headers[i]))
49       << unsafe_headers[i];
50     EXPECT_FALSE(HttpUtil::IsSafeHeader(base::ToUpperASCII(unsafe_headers[i])))
51         << unsafe_headers[i];
52   }
53   static const char* const safe_headers[] = {
54       "foo",
55       "x-",
56       "x-foo",
57       "content-disposition",
58       "update",
59       "accept-charseta",
60       "accept_charset",
61       "accept-encodinga",
62       "accept_encoding",
63       "access-control-request-headersa",
64       "access-control-request-header",
65       "access_control_request_header",
66       "access-control-request-methoda",
67       "access_control_request_method",
68       "connectiona",
69       "content-lengtha",
70       "content_length",
71       "content-transfer-encoding",
72       "cookiea",
73       "cookie2a",
74       "cookie3",
75       "content-transfer-encodinga",
76       "content_transfer_encoding",
77       "datea",
78       "expecta",
79       "hosta",
80       "keep-alivea",
81       "keep_alive",
82       "origina",
83       "referera",
84       "referrer",
85       "tea",
86       "trailera",
87       "transfer-encodinga",
88       "transfer_encoding",
89       "upgradea",
90       "user-agenta",
91       "user_agent",
92       "viaa",
93   };
94   for (size_t i = 0; i < base::size(safe_headers); ++i) {
95     EXPECT_TRUE(HttpUtil::IsSafeHeader(safe_headers[i])) << safe_headers[i];
96     EXPECT_TRUE(HttpUtil::IsSafeHeader(base::ToUpperASCII(safe_headers[i])))
97         << safe_headers[i];
98   }
99 }
100 
TEST(HttpUtilTest,HeadersIterator)101 TEST(HttpUtilTest, HeadersIterator) {
102   std::string headers = "foo: 1\t\r\nbar: hello world\r\nbaz: 3 \r\n";
103 
104   HttpUtil::HeadersIterator it(headers.begin(), headers.end(), "\r\n");
105 
106   ASSERT_TRUE(it.GetNext());
107   EXPECT_EQ(std::string("foo"), it.name());
108   EXPECT_EQ(std::string("1"), it.values());
109 
110   ASSERT_TRUE(it.GetNext());
111   EXPECT_EQ(std::string("bar"), it.name());
112   EXPECT_EQ(std::string("hello world"), it.values());
113 
114   ASSERT_TRUE(it.GetNext());
115   EXPECT_EQ(std::string("baz"), it.name());
116   EXPECT_EQ(std::string("3"), it.values());
117 
118   EXPECT_FALSE(it.GetNext());
119 }
120 
TEST(HttpUtilTest,HeadersIterator_MalformedLine)121 TEST(HttpUtilTest, HeadersIterator_MalformedLine) {
122   std::string headers = "foo: 1\n: 2\n3\nbar: 4";
123 
124   HttpUtil::HeadersIterator it(headers.begin(), headers.end(), "\n");
125 
126   ASSERT_TRUE(it.GetNext());
127   EXPECT_EQ(std::string("foo"), it.name());
128   EXPECT_EQ(std::string("1"), it.values());
129 
130   ASSERT_TRUE(it.GetNext());
131   EXPECT_EQ(std::string("bar"), it.name());
132   EXPECT_EQ(std::string("4"), it.values());
133 
134   EXPECT_FALSE(it.GetNext());
135 }
136 
TEST(HttpUtilTest,HeadersIterator_MalformedName)137 TEST(HttpUtilTest, HeadersIterator_MalformedName) {
138   std::string headers = "[ignore me] /: 3\r\n";
139 
140   HttpUtil::HeadersIterator it(headers.begin(), headers.end(), "\r\n");
141 
142   EXPECT_FALSE(it.GetNext());
143 }
144 
TEST(HttpUtilTest,HeadersIterator_MalformedNameFollowedByValidLine)145 TEST(HttpUtilTest, HeadersIterator_MalformedNameFollowedByValidLine) {
146   std::string headers = "[ignore me] /: 3\r\nbar: 4\n";
147 
148   HttpUtil::HeadersIterator it(headers.begin(), headers.end(), "\r\n");
149 
150   ASSERT_TRUE(it.GetNext());
151   EXPECT_EQ(std::string("bar"), it.name());
152   EXPECT_EQ(std::string("4"), it.values());
153 
154   EXPECT_FALSE(it.GetNext());
155 }
156 
TEST(HttpUtilTest,HeadersIterator_AdvanceTo)157 TEST(HttpUtilTest, HeadersIterator_AdvanceTo) {
158   std::string headers = "foo: 1\r\n: 2\r\n3\r\nbar: 4";
159 
160   HttpUtil::HeadersIterator it(headers.begin(), headers.end(), "\r\n");
161   EXPECT_TRUE(it.AdvanceTo("foo"));
162   EXPECT_EQ("foo", it.name());
163   EXPECT_TRUE(it.AdvanceTo("bar"));
164   EXPECT_EQ("bar", it.name());
165   EXPECT_FALSE(it.AdvanceTo("blat"));
166   EXPECT_FALSE(it.GetNext());  // should be at end of headers
167 }
168 
TEST(HttpUtilTest,HeadersIterator_Reset)169 TEST(HttpUtilTest, HeadersIterator_Reset) {
170   std::string headers = "foo: 1\r\n: 2\r\n3\r\nbar: 4";
171   HttpUtil::HeadersIterator it(headers.begin(), headers.end(), "\r\n");
172   // Search past "foo".
173   EXPECT_TRUE(it.AdvanceTo("bar"));
174   // Now try advancing to "foo".  This time it should fail since the iterator
175   // position is past it.
176   EXPECT_FALSE(it.AdvanceTo("foo"));
177   it.Reset();
178   // Now that we reset the iterator position, we should find 'foo'
179   EXPECT_TRUE(it.AdvanceTo("foo"));
180 }
181 
TEST(HttpUtilTest,ValuesIterator)182 TEST(HttpUtilTest, ValuesIterator) {
183   std::string values = " must-revalidate,   no-cache=\"foo, bar\"\t, private ";
184 
185   HttpUtil::ValuesIterator it(values.begin(), values.end(), ',',
186                               true /* ignore_empty_values */);
187 
188   ASSERT_TRUE(it.GetNext());
189   EXPECT_EQ(std::string("must-revalidate"), it.value());
190 
191   ASSERT_TRUE(it.GetNext());
192   EXPECT_EQ(std::string("no-cache=\"foo, bar\""), it.value());
193 
194   ASSERT_TRUE(it.GetNext());
195   EXPECT_EQ(std::string("private"), it.value());
196 
197   EXPECT_FALSE(it.GetNext());
198 }
199 
TEST(HttpUtilTest,ValuesIterator_EmptyValues)200 TEST(HttpUtilTest, ValuesIterator_EmptyValues) {
201   std::string values = ", foopy , \t ,,,";
202 
203   HttpUtil::ValuesIterator it(values.begin(), values.end(), ',',
204                               true /* ignore_empty_values */);
205   ASSERT_TRUE(it.GetNext());
206   EXPECT_EQ(std::string("foopy"), it.value());
207   EXPECT_FALSE(it.GetNext());
208 
209   HttpUtil::ValuesIterator it_with_empty_values(
210       values.begin(), values.end(), ',', false /* ignore_empty_values */);
211   ASSERT_TRUE(it_with_empty_values.GetNext());
212   EXPECT_EQ(std::string(""), it_with_empty_values.value());
213 
214   ASSERT_TRUE(it_with_empty_values.GetNext());
215   EXPECT_EQ(std::string("foopy"), it_with_empty_values.value());
216 
217   ASSERT_TRUE(it_with_empty_values.GetNext());
218   EXPECT_EQ(std::string(""), it_with_empty_values.value());
219 
220   ASSERT_TRUE(it_with_empty_values.GetNext());
221   EXPECT_EQ(std::string(""), it_with_empty_values.value());
222 
223   ASSERT_TRUE(it_with_empty_values.GetNext());
224   EXPECT_EQ(std::string(""), it_with_empty_values.value());
225 
226   ASSERT_TRUE(it_with_empty_values.GetNext());
227   EXPECT_EQ(std::string(""), it_with_empty_values.value());
228 
229   EXPECT_FALSE(it_with_empty_values.GetNext());
230 }
231 
TEST(HttpUtilTest,ValuesIterator_Blanks)232 TEST(HttpUtilTest, ValuesIterator_Blanks) {
233   std::string values = " \t ";
234 
235   HttpUtil::ValuesIterator it(values.begin(), values.end(), ',',
236                               true /* ignore_empty_values */);
237   EXPECT_FALSE(it.GetNext());
238 
239   HttpUtil::ValuesIterator it_with_empty_values(
240       values.begin(), values.end(), ',', false /* ignore_empty_values */);
241   ASSERT_TRUE(it_with_empty_values.GetNext());
242   EXPECT_EQ(std::string(""), it_with_empty_values.value());
243   EXPECT_FALSE(it_with_empty_values.GetNext());
244 }
245 
TEST(HttpUtilTest,Unquote)246 TEST(HttpUtilTest, Unquote) {
247   // Replace <backslash> " with ".
248   EXPECT_STREQ("xyz\"abc", HttpUtil::Unquote("\"xyz\\\"abc\"").c_str());
249 
250   // Replace <backslash> <backslash> with <backslash>
251   EXPECT_STREQ("xyz\\abc", HttpUtil::Unquote("\"xyz\\\\abc\"").c_str());
252   EXPECT_STREQ("xyz\\\\\\abc",
253                HttpUtil::Unquote("\"xyz\\\\\\\\\\\\abc\"").c_str());
254 
255   // Replace <backslash> X with X
256   EXPECT_STREQ("xyzXabc", HttpUtil::Unquote("\"xyz\\Xabc\"").c_str());
257 
258   // Act as identity function on unquoted inputs.
259   EXPECT_STREQ("X", HttpUtil::Unquote("X").c_str());
260   EXPECT_STREQ("\"", HttpUtil::Unquote("\"").c_str());
261 
262   // Allow quotes in the middle of the input.
263   EXPECT_STREQ("foo\"bar", HttpUtil::Unquote("\"foo\"bar\"").c_str());
264 
265   // Allow the final quote to be escaped.
266   EXPECT_STREQ("foo", HttpUtil::Unquote("\"foo\\\"").c_str());
267 }
268 
TEST(HttpUtilTest,StrictUnquote)269 TEST(HttpUtilTest, StrictUnquote) {
270   std::string out;
271 
272   // Replace <backslash> " with ".
273   EXPECT_TRUE(HttpUtil::StrictUnquote("\"xyz\\\"abc\"", &out));
274   EXPECT_STREQ("xyz\"abc", out.c_str());
275 
276   // Replace <backslash> <backslash> with <backslash>.
277   EXPECT_TRUE(HttpUtil::StrictUnquote("\"xyz\\\\abc\"", &out));
278   EXPECT_STREQ("xyz\\abc", out.c_str());
279   EXPECT_TRUE(HttpUtil::StrictUnquote("\"xyz\\\\\\\\\\\\abc\"", &out));
280   EXPECT_STREQ("xyz\\\\\\abc", out.c_str());
281 
282   // Replace <backslash> X with X.
283   EXPECT_TRUE(HttpUtil::StrictUnquote("\"xyz\\Xabc\"", &out));
284   EXPECT_STREQ("xyzXabc", out.c_str());
285 
286   // Empty quoted string.
287   EXPECT_TRUE(HttpUtil::StrictUnquote("\"\"", &out));
288   EXPECT_STREQ("", out.c_str());
289 
290   // Return false on unquoted inputs.
291   EXPECT_FALSE(HttpUtil::StrictUnquote("X", &out));
292   EXPECT_FALSE(HttpUtil::StrictUnquote("", &out));
293 
294   // Return false on mismatched quotes.
295   EXPECT_FALSE(HttpUtil::StrictUnquote("\"", &out));
296   EXPECT_FALSE(HttpUtil::StrictUnquote("\"xyz", &out));
297   EXPECT_FALSE(HttpUtil::StrictUnquote("\"abc'", &out));
298 
299   // Return false on escaped terminal quote.
300   EXPECT_FALSE(HttpUtil::StrictUnquote("\"abc\\\"", &out));
301   EXPECT_FALSE(HttpUtil::StrictUnquote("\"\\\"", &out));
302 
303   // Allow escaped backslash before terminal quote.
304   EXPECT_TRUE(HttpUtil::StrictUnquote("\"\\\\\"", &out));
305   EXPECT_STREQ("\\", out.c_str());
306 
307   // Don't allow single quotes to act as quote marks.
308   EXPECT_FALSE(HttpUtil::StrictUnquote("'x\"'", &out));
309   EXPECT_TRUE(HttpUtil::StrictUnquote("\"x'\"", &out));
310   EXPECT_STREQ("x'", out.c_str());
311   EXPECT_FALSE(HttpUtil::StrictUnquote("''", &out));
312 }
313 
TEST(HttpUtilTest,Quote)314 TEST(HttpUtilTest, Quote) {
315   EXPECT_STREQ("\"xyz\\\"abc\"", HttpUtil::Quote("xyz\"abc").c_str());
316 
317   // Replace <backslash> <backslash> with <backslash>
318   EXPECT_STREQ("\"xyz\\\\abc\"", HttpUtil::Quote("xyz\\abc").c_str());
319 
320   // Replace <backslash> X with X
321   EXPECT_STREQ("\"xyzXabc\"", HttpUtil::Quote("xyzXabc").c_str());
322 }
323 
TEST(HttpUtilTest,LocateEndOfHeaders)324 TEST(HttpUtilTest, LocateEndOfHeaders) {
325   struct {
326     const char* const input;
327     size_t expected_result;
328   } tests[] = {
329       {"\r\n", std::string::npos},
330       {"\n", std::string::npos},
331       {"\r", std::string::npos},
332       {"foo", std::string::npos},
333       {"\r\n\r\n", 4},
334       {"foo\r\nbar\r\n\r\n", 12},
335       {"foo\nbar\n\n", 9},
336       {"foo\r\nbar\r\n\r\njunk", 12},
337       {"foo\nbar\n\njunk", 9},
338       {"foo\nbar\n\r\njunk", 10},
339       {"foo\nbar\r\n\njunk", 10},
340   };
341   for (size_t i = 0; i < base::size(tests); ++i) {
342     size_t input_len = strlen(tests[i].input);
343     size_t eoh = HttpUtil::LocateEndOfHeaders(tests[i].input, input_len);
344     EXPECT_EQ(tests[i].expected_result, eoh);
345   }
346 }
347 
TEST(HttpUtilTest,LocateEndOfAdditionalHeaders)348 TEST(HttpUtilTest, LocateEndOfAdditionalHeaders) {
349   struct {
350     const char* const input;
351     size_t expected_result;
352   } tests[] = {
353       {"\r\n", 2},
354       {"\n", 1},
355       {"\r", std::string::npos},
356       {"foo", std::string::npos},
357       {"\r\n\r\n", 2},
358       {"foo\r\nbar\r\n\r\n", 12},
359       {"foo\nbar\n\n", 9},
360       {"foo\r\nbar\r\n\r\njunk", 12},
361       {"foo\nbar\n\njunk", 9},
362       {"foo\nbar\n\r\njunk", 10},
363       {"foo\nbar\r\n\njunk", 10},
364   };
365   for (size_t i = 0; i < base::size(tests); ++i) {
366     size_t input_len = strlen(tests[i].input);
367     size_t eoh =
368         HttpUtil::LocateEndOfAdditionalHeaders(tests[i].input, input_len);
369     EXPECT_EQ(tests[i].expected_result, eoh);
370   }
371 }
TEST(HttpUtilTest,AssembleRawHeaders)372 TEST(HttpUtilTest, AssembleRawHeaders) {
373   // clang-format off
374   struct {
375     const char* const input;  // with '|' representing '\0'
376     const char* const expected_result;  // with '\0' changed to '|'
377   } tests[] = {
378     { "HTTP/1.0 200 OK\r\nFoo: 1\r\nBar: 2\r\n\r\n",
379       "HTTP/1.0 200 OK|Foo: 1|Bar: 2||" },
380 
381     { "HTTP/1.0 200 OK\nFoo: 1\nBar: 2\n\n",
382       "HTTP/1.0 200 OK|Foo: 1|Bar: 2||" },
383 
384     // Valid line continuation (single SP).
385     {
386       "HTTP/1.0 200 OK\n"
387       "Foo: 1\n"
388       " continuation\n"
389       "Bar: 2\n\n",
390 
391       "HTTP/1.0 200 OK|"
392       "Foo: 1 continuation|"
393       "Bar: 2||"
394     },
395 
396     // Valid line continuation (single HT).
397     {
398       "HTTP/1.0 200 OK\n"
399       "Foo: 1\n"
400       "\tcontinuation\n"
401       "Bar: 2\n\n",
402 
403       "HTTP/1.0 200 OK|"
404       "Foo: 1 continuation|"
405       "Bar: 2||"
406     },
407 
408     // Valid line continuation (multiple SP).
409     {
410       "HTTP/1.0 200 OK\n"
411       "Foo: 1\n"
412       "   continuation\n"
413       "Bar: 2\n\n",
414 
415       "HTTP/1.0 200 OK|"
416       "Foo: 1 continuation|"
417       "Bar: 2||"
418     },
419 
420     // Valid line continuation (multiple HT).
421     {
422       "HTTP/1.0 200 OK\n"
423       "Foo: 1\n"
424       "\t\t\tcontinuation\n"
425       "Bar: 2\n\n",
426 
427       "HTTP/1.0 200 OK|"
428       "Foo: 1 continuation|"
429       "Bar: 2||"
430     },
431 
432     // Valid line continuation (mixed HT, SP).
433     {
434       "HTTP/1.0 200 OK\n"
435       "Foo: 1\n"
436       " \t \t continuation\n"
437       "Bar: 2\n\n",
438 
439       "HTTP/1.0 200 OK|"
440       "Foo: 1 continuation|"
441       "Bar: 2||"
442     },
443 
444     // Valid multi-line continuation
445     {
446       "HTTP/1.0 200 OK\n"
447       "Foo: 1\n"
448       " continuation1\n"
449       "\tcontinuation2\n"
450       "  continuation3\n"
451       "Bar: 2\n\n",
452 
453       "HTTP/1.0 200 OK|"
454       "Foo: 1 continuation1 continuation2 continuation3|"
455       "Bar: 2||"
456     },
457 
458     // Continuation of quoted value.
459     // This is different from what Firefox does, since it
460     // will preserve the LWS.
461     {
462       "HTTP/1.0 200 OK\n"
463       "Etag: \"34534-d3\n"
464       "    134q\"\n"
465       "Bar: 2\n\n",
466 
467       "HTTP/1.0 200 OK|"
468       "Etag: \"34534-d3 134q\"|"
469       "Bar: 2||"
470     },
471 
472     // Valid multi-line continuation, full LWS lines
473     {
474       "HTTP/1.0 200 OK\n"
475       "Foo: 1\n"
476       "         \n"
477       "\t\t\t\t\n"
478       "\t  continuation\n"
479       "Bar: 2\n\n",
480 
481       // One SP per continued line = 3.
482       "HTTP/1.0 200 OK|"
483       "Foo: 1   continuation|"
484       "Bar: 2||"
485     },
486 
487     // Valid multi-line continuation, all LWS
488     {
489       "HTTP/1.0 200 OK\n"
490       "Foo: 1\n"
491       "         \n"
492       "\t\t\t\t\n"
493       "\t  \n"
494       "Bar: 2\n\n",
495 
496       // One SP per continued line = 3.
497       "HTTP/1.0 200 OK|"
498       "Foo: 1   |"
499       "Bar: 2||"
500     },
501 
502     // Valid line continuation (No value bytes in first line).
503     {
504       "HTTP/1.0 200 OK\n"
505       "Foo:\n"
506       " value\n"
507       "Bar: 2\n\n",
508 
509       "HTTP/1.0 200 OK|"
510       "Foo: value|"
511       "Bar: 2||"
512     },
513 
514     // Not a line continuation (can't continue status line).
515     {
516       "HTTP/1.0 200 OK\n"
517       " Foo: 1\n"
518       "Bar: 2\n\n",
519 
520       "HTTP/1.0 200 OK|"
521       " Foo: 1|"
522       "Bar: 2||"
523     },
524 
525     // Not a line continuation (can't continue status line).
526     {
527       "HTTP/1.0\n"
528       " 200 OK\n"
529       "Foo: 1\n"
530       "Bar: 2\n\n",
531 
532       "HTTP/1.0|"
533       " 200 OK|"
534       "Foo: 1|"
535       "Bar: 2||"
536     },
537 
538     // Not a line continuation (can't continue status line).
539     {
540       "HTTP/1.0 404\n"
541       " Not Found\n"
542       "Foo: 1\n"
543       "Bar: 2\n\n",
544 
545       "HTTP/1.0 404|"
546       " Not Found|"
547       "Foo: 1|"
548       "Bar: 2||"
549     },
550 
551     // Unterminated status line.
552     {
553       "HTTP/1.0 200 OK",
554 
555       "HTTP/1.0 200 OK||"
556     },
557 
558     // Single terminated, with headers
559     {
560       "HTTP/1.0 200 OK\n"
561       "Foo: 1\n"
562       "Bar: 2\n",
563 
564       "HTTP/1.0 200 OK|"
565       "Foo: 1|"
566       "Bar: 2||"
567     },
568 
569     // Not terminated, with headers
570     {
571       "HTTP/1.0 200 OK\n"
572       "Foo: 1\n"
573       "Bar: 2",
574 
575       "HTTP/1.0 200 OK|"
576       "Foo: 1|"
577       "Bar: 2||"
578     },
579 
580     // Not a line continuation (VT)
581     {
582       "HTTP/1.0 200 OK\n"
583       "Foo: 1\n"
584       "\vInvalidContinuation\n"
585       "Bar: 2\n\n",
586 
587       "HTTP/1.0 200 OK|"
588       "Foo: 1|"
589       "\vInvalidContinuation|"
590       "Bar: 2||"
591     },
592 
593     // Not a line continuation (formfeed)
594     {
595       "HTTP/1.0 200 OK\n"
596       "Foo: 1\n"
597       "\fInvalidContinuation\n"
598       "Bar: 2\n\n",
599 
600       "HTTP/1.0 200 OK|"
601       "Foo: 1|"
602       "\fInvalidContinuation|"
603       "Bar: 2||"
604     },
605 
606     // Not a line continuation -- can't continue header names.
607     {
608       "HTTP/1.0 200 OK\n"
609       "Serv\n"
610       " er: Apache\n"
611       "\tInvalidContinuation\n"
612       "Bar: 2\n\n",
613 
614       "HTTP/1.0 200 OK|"
615       "Serv|"
616       " er: Apache|"
617       "\tInvalidContinuation|"
618       "Bar: 2||"
619     },
620 
621     // Not a line continuation -- no value to continue.
622     {
623       "HTTP/1.0 200 OK\n"
624       "Foo: 1\n"
625       "garbage\n"
626       "  not-a-continuation\n"
627       "Bar: 2\n\n",
628 
629       "HTTP/1.0 200 OK|"
630       "Foo: 1|"
631       "garbage|"
632       "  not-a-continuation|"
633       "Bar: 2||",
634     },
635 
636     // Not a line continuation -- no valid name.
637     {
638       "HTTP/1.0 200 OK\n"
639       ": 1\n"
640       "  garbage\n"
641       "Bar: 2\n\n",
642 
643       "HTTP/1.0 200 OK|"
644       ": 1|"
645       "  garbage|"
646       "Bar: 2||",
647     },
648 
649     // Not a line continuation -- no valid name (whitespace)
650     {
651       "HTTP/1.0 200 OK\n"
652       "   : 1\n"
653       "  garbage\n"
654       "Bar: 2\n\n",
655 
656       "HTTP/1.0 200 OK|"
657       "   : 1|"
658       "  garbage|"
659       "Bar: 2||",
660     },
661 
662     // Embed NULLs in the status line. They should not be understood
663     // as line separators.
664     {
665       "HTTP/1.0 200 OK|Bar2:0|Baz2:1\r\nFoo: 1\r\nBar: 2\r\n\r\n",
666       "HTTP/1.0 200 OKBar2:0Baz2:1|Foo: 1|Bar: 2||"
667     },
668 
669     // Embed NULLs in a header line. They should not be understood as
670     // line separators.
671     {
672       "HTTP/1.0 200 OK\nFoo: 1|Foo2: 3\nBar: 2\n\n",
673       "HTTP/1.0 200 OK|Foo: 1Foo2: 3|Bar: 2||"
674     },
675 
676     // The embedded NUL at the start of the line (before "Blah:") should not be
677     // interpreted as LWS (as that would mistake it for a header line
678     // continuation).
679     {
680       "HTTP/1.0 200 OK\n"
681       "Foo: 1\n"
682       "|Blah: 3\n"
683       "Bar: 2\n\n",
684       "HTTP/1.0 200 OK|Foo: 1|Blah: 3|Bar: 2||"
685     },
686   };
687   // clang-format on
688   for (size_t i = 0; i < base::size(tests); ++i) {
689     std::string input = tests[i].input;
690     std::replace(input.begin(), input.end(), '|', '\0');
691     std::string raw = HttpUtil::AssembleRawHeaders(input);
692     std::replace(raw.begin(), raw.end(), '\0', '|');
693     EXPECT_EQ(tests[i].expected_result, raw);
694   }
695 }
696 
697 // Test SpecForRequest().
TEST(HttpUtilTest,RequestUrlSanitize)698 TEST(HttpUtilTest, RequestUrlSanitize) {
699   struct {
700     const char* const url;
701     const char* const expected_spec;
702   } tests[] = {
703     { // Check that #hash is removed.
704       "http://www.google.com:78/foobar?query=1#hash",
705       "http://www.google.com:78/foobar?query=1",
706     },
707     { // The reference may itself contain # -- strip all of it.
708       "http://192.168.0.1?query=1#hash#10#11#13#14",
709       "http://192.168.0.1/?query=1",
710     },
711     { // Strip username/password.
712       "http://user:pass@google.com",
713       "http://google.com/",
714     },
715     { // https scheme
716       "https://www.google.com:78/foobar?query=1#hash",
717       "https://www.google.com:78/foobar?query=1",
718     },
719     { // WebSocket's ws scheme
720       "ws://www.google.com:78/foobar?query=1#hash",
721       "ws://www.google.com:78/foobar?query=1",
722     },
723     { // WebSocket's wss scheme
724       "wss://www.google.com:78/foobar?query=1#hash",
725       "wss://www.google.com:78/foobar?query=1",
726     }
727   };
728   for (size_t i = 0; i < base::size(tests); ++i) {
729     SCOPED_TRACE(i);
730 
731     GURL url(GURL(tests[i].url));
732     std::string expected_spec(tests[i].expected_spec);
733 
734     EXPECT_EQ(expected_spec, HttpUtil::SpecForRequest(url));
735   }
736 }
737 
TEST(HttpUtilTest,GenerateAcceptLanguageHeader)738 TEST(HttpUtilTest, GenerateAcceptLanguageHeader) {
739   std::string header = HttpUtil::GenerateAcceptLanguageHeader("");
740   EXPECT_TRUE(header.empty());
741 
742   header = HttpUtil::GenerateAcceptLanguageHeader("es");
743   EXPECT_EQ(std::string("es"), header);
744 
745   header = HttpUtil::GenerateAcceptLanguageHeader("en-US,fr,de");
746   EXPECT_EQ(std::string("en-US,fr;q=0.9,de;q=0.8"), header);
747 
748   header = HttpUtil::GenerateAcceptLanguageHeader("en-US,fr,de,ko,zh-CN,ja");
749   EXPECT_EQ(
750       std::string("en-US,fr;q=0.9,de;q=0.8,ko;q=0.7,zh-CN;q=0.6,ja;q=0.5"),
751       header);
752 }
753 
754 // HttpResponseHeadersTest.GetMimeType also tests ParseContentType.
TEST(HttpUtilTest,ParseContentType)755 TEST(HttpUtilTest, ParseContentType) {
756   // clang-format off
757   const struct {
758     const char* const content_type;
759     const char* const expected_mime_type;
760     const char* const expected_charset;
761     const bool expected_had_charset;
762     const char* const expected_boundary;
763   } tests[] = {
764     { "text/html",
765       "text/html",
766       "",
767       false,
768       ""
769     },
770     { "text/html;",
771       "text/html",
772       "",
773       false,
774       ""
775     },
776     { "text/html; charset=utf-8",
777       "text/html",
778       "utf-8",
779       true,
780       ""
781     },
782     // Parameter name is "charset ", not "charset".  See https://crbug.com/772834.
783     { "text/html; charset =utf-8",
784       "text/html",
785       "",
786       false,
787       ""
788     },
789     { "text/html; charset= utf-8",
790       "text/html",
791       "utf-8",
792       true,
793       ""
794     },
795     { "text/html; charset=utf-8 ",
796       "text/html",
797       "utf-8",
798       true,
799       ""
800     },
801 
802     { "text/html; boundary=\"WebKit-ada-df-dsf-adsfadsfs\"",
803       "text/html",
804       "",
805       false,
806       "WebKit-ada-df-dsf-adsfadsfs"
807     },
808     // Parameter name is "boundary ", not "boundary".
809     // See https://crbug.com/772834.
810     { "text/html; boundary =\"WebKit-ada-df-dsf-adsfadsfs\"",
811       "text/html",
812       "",
813       false,
814       ""
815     },
816     // Parameter value includes leading space.  See https://crbug.com/772834.
817     { "text/html; boundary= \"WebKit-ada-df-dsf-adsfadsfs\"",
818       "text/html",
819       "",
820       false,
821       "WebKit-ada-df-dsf-adsfadsfs"
822     },
823     // Parameter value includes leading space.  See https://crbug.com/772834.
824     { "text/html; boundary= \"WebKit-ada-df-dsf-adsfadsfs\"   ",
825       "text/html",
826       "",
827       false,
828       "WebKit-ada-df-dsf-adsfadsfs"
829     },
830     { "text/html; boundary=\"WebKit-ada-df-dsf-adsfadsfs  \"",
831       "text/html",
832       "",
833       false,
834       "WebKit-ada-df-dsf-adsfadsfs"
835     },
836     { "text/html; boundary=WebKit-ada-df-dsf-adsfadsfs",
837       "text/html",
838       "",
839       false,
840       "WebKit-ada-df-dsf-adsfadsfs"
841     },
842     { "text/html; charset",
843       "text/html",
844       "",
845       false,
846       ""
847     },
848     { "text/html; charset=",
849       "text/html",
850       "",
851       false,
852       ""
853     },
854     { "text/html; charset= ",
855       "text/html",
856       "",
857       false,
858       ""
859     },
860     { "text/html; charset= ;",
861       "text/html",
862       "",
863       false,
864       ""
865     },
866     // Empty quoted strings are allowed.
867     { "text/html; charset=\"\"",
868       "text/html",
869       "",
870       true,
871       ""
872     },
873 
874     // Leading and trailing whitespace in quotes is trimmed.
875     { "text/html; charset=\" \"",
876       "text/html",
877       "",
878       true,
879       ""
880     },
881     { "text/html; charset=\" foo \"",
882       "text/html",
883       "foo",
884       true,
885       ""
886     },
887 
888     // With multiple values, should use the first one.
889     { "text/html; charset=foo; charset=utf-8",
890       "text/html",
891       "foo",
892       true,
893       ""
894     },
895     { "text/html; charset; charset=; charset=utf-8",
896       "text/html",
897       "utf-8",
898       true,
899       ""
900     },
901     { "text/html; charset=utf-8; charset=; charset",
902       "text/html",
903       "utf-8",
904       true,
905       ""
906     },
907     { "text/html; boundary=foo; boundary=bar",
908       "text/html",
909       "",
910       false,
911       "foo"
912     },
913 
914     // Stray quotes ignored.
915     { "text/html; \"; \"\"; charset=utf-8",
916       "text/html",
917       "utf-8",
918       true,
919       ""
920     },
921     // Non-leading quotes kept as-is.
922     { "text/html; charset=u\"tf-8\"",
923       "text/html",
924       "u\"tf-8\"",
925       true,
926       ""
927     },
928     { "text/html; charset=\"utf-8\"",
929       "text/html",
930       "utf-8",
931       true,
932       ""
933     },
934     // No closing quote.
935     { "text/html; charset=\"utf-8",
936       "text/html",
937       "utf-8",
938       true,
939       ""
940     },
941     // Check that \ is treated as an escape character.
942     { "text/html; charset=\"\\utf\\-\\8\"",
943       "text/html",
944       "utf-8",
945       true,
946       ""
947     },
948     // More interseting escape character test - test escaped backslash, escaped
949     // quote, and backslash at end of input in unterminated quoted string.
950     { "text/html; charset=\"\\\\\\\"\\",
951       "text/html",
952       "\\\"\\",
953       true,
954       ""
955     },
956     // Check quoted semicolon.
957     { "text/html; charset=\";charset=utf-8;\"",
958       "text/html",
959       ";charset=utf-8;",
960       true,
961       ""
962     },
963     // Unclear if this one should just return utf-8 or not.
964     { "text/html; charset= \"utf-8\"",
965       "text/html",
966       "utf-8",
967       true,
968       ""
969     },
970     // Regression test for https://crbug.com/772350:
971     // Single quotes are not delimiters but must be treated as part of charset.
972     { "text/html; charset='utf-8'",
973       "text/html",
974       "'utf-8'",
975       true,
976       ""
977     },
978     // TODO(abarth): Add more interesting test cases.
979   };
980   // clang-format on
981   for (size_t i = 0; i < base::size(tests); ++i) {
982     std::string mime_type;
983     std::string charset;
984     bool had_charset = false;
985     std::string boundary;
986     HttpUtil::ParseContentType(tests[i].content_type, &mime_type, &charset,
987                                &had_charset, &boundary);
988     EXPECT_EQ(tests[i].expected_mime_type, mime_type)
989         << "content_type=" << tests[i].content_type;
990     EXPECT_EQ(tests[i].expected_charset, charset)
991         << "content_type=" << tests[i].content_type;
992     EXPECT_EQ(tests[i].expected_had_charset, had_charset)
993         << "content_type=" << tests[i].content_type;
994     EXPECT_EQ(tests[i].expected_boundary, boundary)
995         << "content_type=" << tests[i].content_type;
996   }
997 }
998 
TEST(HttpUtilTest,ParseContentRangeHeader)999 TEST(HttpUtilTest, ParseContentRangeHeader) {
1000   const struct {
1001     const char* const content_range_header_spec;
1002     bool expected_return_value;
1003     int64_t expected_first_byte_position;
1004     int64_t expected_last_byte_position;
1005     int64_t expected_instance_length;
1006   } tests[] = {
1007       {"", false, -1, -1, -1},
1008       {"megabytes 0-10/50", false, -1, -1, -1},
1009       {"0-10/50", false, -1, -1, -1},
1010       {"Bytes 0-50/51", true, 0, 50, 51},
1011       {"bytes 0-50/51", true, 0, 50, 51},
1012       {"bytes\t0-50/51", false, -1, -1, -1},
1013       {"    bytes 0-50/51", true, 0, 50, 51},
1014       {"    bytes    0    -   50  \t / \t51", true, 0, 50, 51},
1015       {"bytes 0\t-\t50\t/\t51\t", true, 0, 50, 51},
1016       {"  \tbytes\t\t\t 0\t-\t50\t/\t51\t", true, 0, 50, 51},
1017       {"\t   bytes \t  0    -   50   /   5   1", false, -1, -1, -1},
1018       {"\t   bytes \t  0    -   5 0   /   51", false, -1, -1, -1},
1019       {"bytes 50-0/51", false, -1, -1, -1},
1020       {"bytes * /*", false, -1, -1, -1},
1021       {"bytes *   /    *   ", false, -1, -1, -1},
1022       {"bytes 0-50/*", false, -1, -1, -1},
1023       {"bytes 0-50  /    * ", false, -1, -1, -1},
1024       {"bytes 0-10000000000/10000000001", true, 0, 10000000000ll,
1025        10000000001ll},
1026       {"bytes 0-10000000000/10000000000", false, -1, -1, -1},
1027       // 64 bit wraparound.
1028       {"bytes 0 - 9223372036854775807 / 100", false, -1, -1, -1},
1029       // 64 bit wraparound.
1030       {"bytes 0 - 100 / -9223372036854775808", false, -1, -1, -1},
1031       {"bytes */50", false, -1, -1, -1},
1032       {"bytes 0-50/10", false, -1, -1, -1},
1033       {"bytes 40-50/45", false, -1, -1, -1},
1034       {"bytes 0-50/-10", false, -1, -1, -1},
1035       {"bytes 0-0/1", true, 0, 0, 1},
1036       {"bytes 0-40000000000000000000/40000000000000000001", false, -1, -1, -1},
1037       {"bytes 1-/100", false, -1, -1, -1},
1038       {"bytes -/100", false, -1, -1, -1},
1039       {"bytes -1/100", false, -1, -1, -1},
1040       {"bytes 0-1233/*", false, -1, -1, -1},
1041       {"bytes -123 - -1/100", false, -1, -1, -1},
1042   };
1043 
1044   for (const auto& test : tests) {
1045     int64_t first_byte_position, last_byte_position, instance_length;
1046     EXPECT_EQ(test.expected_return_value,
1047               HttpUtil::ParseContentRangeHeaderFor206(
1048                   test.content_range_header_spec, &first_byte_position,
1049                   &last_byte_position, &instance_length))
1050         << test.content_range_header_spec;
1051     EXPECT_EQ(test.expected_first_byte_position, first_byte_position)
1052         << test.content_range_header_spec;
1053     EXPECT_EQ(test.expected_last_byte_position, last_byte_position)
1054         << test.content_range_header_spec;
1055     EXPECT_EQ(test.expected_instance_length, instance_length)
1056         << test.content_range_header_spec;
1057   }
1058 }
1059 
TEST(HttpUtilTest,ParseRetryAfterHeader)1060 TEST(HttpUtilTest, ParseRetryAfterHeader) {
1061   base::Time::Exploded now_exploded = {2014, 11, 4, 5, 22, 39, 30, 0};
1062   base::Time now;
1063   EXPECT_TRUE(base::Time::FromUTCExploded(now_exploded, &now));
1064 
1065   base::Time::Exploded later_exploded = {2015, 1, 5, 1, 12, 34, 56, 0};
1066   base::Time later;
1067   EXPECT_TRUE(base::Time::FromUTCExploded(later_exploded, &later));
1068 
1069   const struct {
1070     const char* retry_after_string;
1071     bool expected_return_value;
1072     base::TimeDelta expected_retry_after;
1073   } tests[] = {{"", false, base::TimeDelta()},
1074                {"-3", false, base::TimeDelta()},
1075                {"-2", false, base::TimeDelta()},
1076                {"-1", false, base::TimeDelta()},
1077                {"+0", false, base::TimeDelta()},
1078                {"+1", false, base::TimeDelta()},
1079                {"0", true, base::TimeDelta::FromSeconds(0)},
1080                {"1", true, base::TimeDelta::FromSeconds(1)},
1081                {"2", true, base::TimeDelta::FromSeconds(2)},
1082                {"3", true, base::TimeDelta::FromSeconds(3)},
1083                {"60", true, base::TimeDelta::FromSeconds(60)},
1084                {"3600", true, base::TimeDelta::FromSeconds(3600)},
1085                {"86400", true, base::TimeDelta::FromSeconds(86400)},
1086                {"Thu, 1 Jan 2015 12:34:56 GMT", true, later - now},
1087                {"Mon, 1 Jan 1900 12:34:56 GMT", false, base::TimeDelta()}};
1088 
1089   for (size_t i = 0; i < base::size(tests); ++i) {
1090     base::TimeDelta retry_after;
1091     bool return_value = HttpUtil::ParseRetryAfterHeader(
1092         tests[i].retry_after_string, now, &retry_after);
1093     EXPECT_EQ(tests[i].expected_return_value, return_value)
1094         << "Test case " << i << ": expected " << tests[i].expected_return_value
1095         << " but got " << return_value << ".";
1096     if (tests[i].expected_return_value && return_value) {
1097       EXPECT_EQ(tests[i].expected_retry_after, retry_after)
1098           << "Test case " << i << ": expected "
1099           << tests[i].expected_retry_after.InSeconds() << "s but got "
1100           << retry_after.InSeconds() << "s.";
1101     }
1102   }
1103 }
1104 
1105 namespace {
CheckCurrentNameValuePair(HttpUtil::NameValuePairsIterator * parser,bool expect_valid,std::string expected_name,std::string expected_value)1106 void CheckCurrentNameValuePair(HttpUtil::NameValuePairsIterator* parser,
1107                                bool expect_valid,
1108                                std::string expected_name,
1109                                std::string expected_value) {
1110   ASSERT_EQ(expect_valid, parser->valid());
1111   if (!expect_valid) {
1112     return;
1113   }
1114 
1115   // Let's make sure that these never change (i.e., when a quoted value is
1116   // unquoted, it should be cached on the first calls and not regenerated
1117   // later).
1118   std::string::const_iterator first_value_begin = parser->value_begin();
1119   std::string::const_iterator first_value_end = parser->value_end();
1120 
1121   ASSERT_EQ(expected_name, std::string(parser->name_begin(),
1122                                        parser->name_end()));
1123   ASSERT_EQ(expected_name, parser->name());
1124   ASSERT_EQ(expected_value, std::string(parser->value_begin(),
1125                                         parser->value_end()));
1126   ASSERT_EQ(expected_value, parser->value());
1127 
1128   // Make sure they didn't/don't change.
1129   ASSERT_TRUE(first_value_begin == parser->value_begin());
1130   ASSERT_TRUE(first_value_end == parser->value_end());
1131 }
1132 
CheckNextNameValuePair(HttpUtil::NameValuePairsIterator * parser,bool expect_next,bool expect_valid,std::string expected_name,std::string expected_value)1133 void CheckNextNameValuePair(HttpUtil::NameValuePairsIterator* parser,
1134                             bool expect_next,
1135                             bool expect_valid,
1136                             std::string expected_name,
1137                             std::string expected_value) {
1138   ASSERT_EQ(expect_next, parser->GetNext());
1139   ASSERT_EQ(expect_valid, parser->valid());
1140   if (!expect_next || !expect_valid) {
1141     return;
1142   }
1143 
1144   CheckCurrentNameValuePair(parser,
1145                             expect_valid,
1146                             expected_name,
1147                             expected_value);
1148 }
1149 
CheckInvalidNameValuePair(std::string valid_part,std::string invalid_part)1150 void CheckInvalidNameValuePair(std::string valid_part,
1151                                std::string invalid_part) {
1152   std::string whole_string = valid_part + invalid_part;
1153 
1154   HttpUtil::NameValuePairsIterator valid_parser(valid_part.begin(),
1155                                                 valid_part.end(),
1156                                                 ';');
1157   HttpUtil::NameValuePairsIterator invalid_parser(whole_string.begin(),
1158                                                   whole_string.end(),
1159                                                   ';');
1160 
1161   ASSERT_TRUE(valid_parser.valid());
1162   ASSERT_TRUE(invalid_parser.valid());
1163 
1164   // Both parsers should return all the same values until "valid_parser" is
1165   // exhausted.
1166   while (valid_parser.GetNext()) {
1167     ASSERT_TRUE(invalid_parser.GetNext());
1168     ASSERT_TRUE(valid_parser.valid());
1169     ASSERT_TRUE(invalid_parser.valid());
1170     ASSERT_EQ(valid_parser.name(), invalid_parser.name());
1171     ASSERT_EQ(valid_parser.value(), invalid_parser.value());
1172   }
1173 
1174   // valid_parser is exhausted and remains 'valid'
1175   ASSERT_TRUE(valid_parser.valid());
1176 
1177   // invalid_parser's corresponding call to GetNext also returns false...
1178   ASSERT_FALSE(invalid_parser.GetNext());
1179   // ...but the parser is in an invalid state.
1180   ASSERT_FALSE(invalid_parser.valid());
1181 }
1182 
1183 }  // namespace
1184 
TEST(HttpUtilTest,NameValuePairsIteratorCopyAndAssign)1185 TEST(HttpUtilTest, NameValuePairsIteratorCopyAndAssign) {
1186   std::string data =
1187       "alpha=\"\\\"a\\\"\"; beta=\" b \"; cappa=\"c;\"; delta=\"d\"";
1188   HttpUtil::NameValuePairsIterator parser_a(data.begin(), data.end(), ';');
1189 
1190   EXPECT_TRUE(parser_a.valid());
1191   ASSERT_NO_FATAL_FAILURE(
1192       CheckNextNameValuePair(&parser_a, true, true, "alpha", "\"a\""));
1193 
1194   HttpUtil::NameValuePairsIterator parser_b(parser_a);
1195   // a and b now point to same location
1196   ASSERT_NO_FATAL_FAILURE(
1197       CheckCurrentNameValuePair(&parser_b, true, "alpha", "\"a\""));
1198   ASSERT_NO_FATAL_FAILURE(
1199       CheckCurrentNameValuePair(&parser_a, true, "alpha", "\"a\""));
1200 
1201   // advance a, no effect on b
1202   ASSERT_NO_FATAL_FAILURE(
1203       CheckNextNameValuePair(&parser_a, true, true, "beta", " b "));
1204   ASSERT_NO_FATAL_FAILURE(
1205       CheckCurrentNameValuePair(&parser_b, true, "alpha", "\"a\""));
1206 
1207   // assign b the current state of a, no effect on a
1208   parser_b = parser_a;
1209   ASSERT_NO_FATAL_FAILURE(
1210       CheckCurrentNameValuePair(&parser_b, true, "beta", " b "));
1211   ASSERT_NO_FATAL_FAILURE(
1212       CheckCurrentNameValuePair(&parser_a, true, "beta", " b "));
1213 
1214   // advance b, no effect on a
1215   ASSERT_NO_FATAL_FAILURE(
1216       CheckNextNameValuePair(&parser_b, true, true, "cappa", "c;"));
1217   ASSERT_NO_FATAL_FAILURE(
1218       CheckCurrentNameValuePair(&parser_a, true, "beta", " b "));
1219 }
1220 
TEST(HttpUtilTest,NameValuePairsIteratorEmptyInput)1221 TEST(HttpUtilTest, NameValuePairsIteratorEmptyInput) {
1222   std::string data;
1223   HttpUtil::NameValuePairsIterator parser(data.begin(), data.end(), ';');
1224 
1225   EXPECT_TRUE(parser.valid());
1226   ASSERT_NO_FATAL_FAILURE(CheckNextNameValuePair(
1227       &parser, false, true, std::string(), std::string()));
1228 }
1229 
TEST(HttpUtilTest,NameValuePairsIterator)1230 TEST(HttpUtilTest, NameValuePairsIterator) {
1231   std::string data =
1232       "alpha=1; beta= 2 ;"
1233       "cappa =' 3; foo=';"
1234       "cappa =\" 3; foo=\";"
1235       "delta= \" \\\"4\\\" \"; e= \" '5'\"; e=6;"
1236       "f=\"\\\"\\h\\e\\l\\l\\o\\ \\w\\o\\r\\l\\d\\\"\";"
1237       "g=\"\"; h=\"hello\"";
1238   HttpUtil::NameValuePairsIterator parser(data.begin(), data.end(), ';');
1239   EXPECT_TRUE(parser.valid());
1240 
1241   ASSERT_NO_FATAL_FAILURE(
1242       CheckNextNameValuePair(&parser, true, true, "alpha", "1"));
1243   ASSERT_NO_FATAL_FAILURE(
1244       CheckNextNameValuePair(&parser, true, true, "beta", "2"));
1245 
1246   // Single quotes shouldn't be treated as quotes.
1247   ASSERT_NO_FATAL_FAILURE(
1248       CheckNextNameValuePair(&parser, true, true, "cappa", "' 3"));
1249   ASSERT_NO_FATAL_FAILURE(
1250       CheckNextNameValuePair(&parser, true, true, "foo", "'"));
1251 
1252   // But double quotes should be, and can contain semi-colons and equal signs.
1253   ASSERT_NO_FATAL_FAILURE(
1254       CheckNextNameValuePair(&parser, true, true, "cappa", " 3; foo="));
1255 
1256   ASSERT_NO_FATAL_FAILURE(
1257       CheckNextNameValuePair(&parser, true, true, "delta", " \"4\" "));
1258   ASSERT_NO_FATAL_FAILURE(
1259       CheckNextNameValuePair(&parser, true, true, "e", " '5'"));
1260   ASSERT_NO_FATAL_FAILURE(
1261       CheckNextNameValuePair(&parser, true, true, "e", "6"));
1262   ASSERT_NO_FATAL_FAILURE(
1263       CheckNextNameValuePair(&parser, true, true, "f", "\"hello world\""));
1264   ASSERT_NO_FATAL_FAILURE(
1265       CheckNextNameValuePair(&parser, true, true, "g", std::string()));
1266   ASSERT_NO_FATAL_FAILURE(
1267       CheckNextNameValuePair(&parser, true, true, "h", "hello"));
1268   ASSERT_NO_FATAL_FAILURE(CheckNextNameValuePair(
1269       &parser, false, true, std::string(), std::string()));
1270 }
1271 
TEST(HttpUtilTest,NameValuePairsIteratorOptionalValues)1272 TEST(HttpUtilTest, NameValuePairsIteratorOptionalValues) {
1273   std::string data = "alpha=1; beta;cappa ;  delta; e    ; f=1";
1274   // Test that the default parser requires values.
1275   HttpUtil::NameValuePairsIterator default_parser(data.begin(), data.end(),
1276                                                   ';');
1277   EXPECT_TRUE(default_parser.valid());
1278   ASSERT_NO_FATAL_FAILURE(
1279       CheckNextNameValuePair(&default_parser, true, true, "alpha", "1"));
1280   ASSERT_NO_FATAL_FAILURE(CheckNextNameValuePair(&default_parser, false, false,
1281                                                  std::string(), std::string()));
1282 
1283   HttpUtil::NameValuePairsIterator values_required_parser(
1284       data.begin(), data.end(), ';',
1285       HttpUtil::NameValuePairsIterator::Values::REQUIRED,
1286       HttpUtil::NameValuePairsIterator::Quotes::NOT_STRICT);
1287   EXPECT_TRUE(values_required_parser.valid());
1288   ASSERT_NO_FATAL_FAILURE(CheckNextNameValuePair(&values_required_parser, true,
1289                                                  true, "alpha", "1"));
1290   ASSERT_NO_FATAL_FAILURE(CheckNextNameValuePair(
1291       &values_required_parser, false, false, std::string(), std::string()));
1292 
1293   HttpUtil::NameValuePairsIterator parser(
1294       data.begin(), data.end(), ';',
1295       HttpUtil::NameValuePairsIterator::Values::NOT_REQUIRED,
1296       HttpUtil::NameValuePairsIterator::Quotes::NOT_STRICT);
1297   EXPECT_TRUE(parser.valid());
1298 
1299   ASSERT_NO_FATAL_FAILURE(
1300       CheckNextNameValuePair(&parser, true, true, "alpha", "1"));
1301   ASSERT_NO_FATAL_FAILURE(
1302       CheckNextNameValuePair(&parser, true, true, "beta", std::string()));
1303   ASSERT_NO_FATAL_FAILURE(
1304       CheckNextNameValuePair(&parser, true, true, "cappa", std::string()));
1305   ASSERT_NO_FATAL_FAILURE(
1306       CheckNextNameValuePair(&parser, true, true, "delta", std::string()));
1307   ASSERT_NO_FATAL_FAILURE(
1308       CheckNextNameValuePair(&parser, true, true, "e", std::string()));
1309   ASSERT_NO_FATAL_FAILURE(
1310       CheckNextNameValuePair(&parser, true, true, "f", "1"));
1311   ASSERT_NO_FATAL_FAILURE(CheckNextNameValuePair(&parser, false, true,
1312                                                  std::string(), std::string()));
1313   EXPECT_TRUE(parser.valid());
1314 }
1315 
TEST(HttpUtilTest,NameValuePairsIteratorIllegalInputs)1316 TEST(HttpUtilTest, NameValuePairsIteratorIllegalInputs) {
1317   ASSERT_NO_FATAL_FAILURE(CheckInvalidNameValuePair("alpha=1", "; beta"));
1318   ASSERT_NO_FATAL_FAILURE(CheckInvalidNameValuePair(std::string(), "beta"));
1319 
1320   ASSERT_NO_FATAL_FAILURE(CheckInvalidNameValuePair("alpha=1", "; \"beta\"=2"));
1321   ASSERT_NO_FATAL_FAILURE(
1322       CheckInvalidNameValuePair(std::string(), "\"beta\"=2"));
1323   ASSERT_NO_FATAL_FAILURE(CheckInvalidNameValuePair("alpha=1", ";beta="));
1324   ASSERT_NO_FATAL_FAILURE(CheckInvalidNameValuePair("alpha=1",
1325                                                     ";beta=;cappa=2"));
1326 
1327   // According to the spec this is an error, but it doesn't seem appropriate to
1328   // change our behaviour to be less permissive at this time.
1329   // See NameValuePairsIteratorExtraSeparators test
1330   // ASSERT_NO_FATAL_FAILURE(CheckInvalidNameValuePair("alpha=1", ";; beta=2"));
1331 }
1332 
1333 // If we are going to support extra separators against the spec, let's just make
1334 // sure they work rationally.
TEST(HttpUtilTest,NameValuePairsIteratorExtraSeparators)1335 TEST(HttpUtilTest, NameValuePairsIteratorExtraSeparators) {
1336   std::string data = " ; ;;alpha=1; ;; ; beta= 2;cappa=3;;; ; ";
1337   HttpUtil::NameValuePairsIterator parser(data.begin(), data.end(), ';');
1338   EXPECT_TRUE(parser.valid());
1339 
1340   ASSERT_NO_FATAL_FAILURE(
1341       CheckNextNameValuePair(&parser, true, true, "alpha", "1"));
1342   ASSERT_NO_FATAL_FAILURE(
1343       CheckNextNameValuePair(&parser, true, true, "beta", "2"));
1344   ASSERT_NO_FATAL_FAILURE(
1345       CheckNextNameValuePair(&parser, true, true, "cappa", "3"));
1346   ASSERT_NO_FATAL_FAILURE(CheckNextNameValuePair(
1347       &parser, false, true, std::string(), std::string()));
1348 }
1349 
1350 // See comments on the implementation of NameValuePairsIterator::GetNext
1351 // regarding this derogation from the spec.
TEST(HttpUtilTest,NameValuePairsIteratorMissingEndQuote)1352 TEST(HttpUtilTest, NameValuePairsIteratorMissingEndQuote) {
1353   std::string data = "name=\"value";
1354   HttpUtil::NameValuePairsIterator parser(data.begin(), data.end(), ';');
1355   EXPECT_TRUE(parser.valid());
1356 
1357   ASSERT_NO_FATAL_FAILURE(
1358       CheckNextNameValuePair(&parser, true, true, "name", "value"));
1359   ASSERT_NO_FATAL_FAILURE(CheckNextNameValuePair(
1360       &parser, false, true, std::string(), std::string()));
1361 }
1362 
TEST(HttpUtilTest,NameValuePairsIteratorStrictQuotesEscapedEndQuote)1363 TEST(HttpUtilTest, NameValuePairsIteratorStrictQuotesEscapedEndQuote) {
1364   std::string data = "foo=bar; name=\"value\\\"";
1365   HttpUtil::NameValuePairsIterator parser(
1366       data.begin(), data.end(), ';',
1367       HttpUtil::NameValuePairsIterator::Values::REQUIRED,
1368       HttpUtil::NameValuePairsIterator::Quotes::STRICT_QUOTES);
1369   EXPECT_TRUE(parser.valid());
1370 
1371   ASSERT_NO_FATAL_FAILURE(
1372       CheckNextNameValuePair(&parser, true, true, "foo", "bar"));
1373   ASSERT_NO_FATAL_FAILURE(CheckNextNameValuePair(&parser, false, false,
1374                                                  std::string(), std::string()));
1375 }
1376 
TEST(HttpUtilTest,NameValuePairsIteratorStrictQuotesQuoteInValue)1377 TEST(HttpUtilTest, NameValuePairsIteratorStrictQuotesQuoteInValue) {
1378   std::string data = "foo=\"bar\"; name=\"va\"lue\"";
1379   HttpUtil::NameValuePairsIterator parser(
1380       data.begin(), data.end(), ';',
1381       HttpUtil::NameValuePairsIterator::Values::REQUIRED,
1382       HttpUtil::NameValuePairsIterator::Quotes::STRICT_QUOTES);
1383   EXPECT_TRUE(parser.valid());
1384 
1385   ASSERT_NO_FATAL_FAILURE(
1386       CheckNextNameValuePair(&parser, true, true, "foo", "bar"));
1387   ASSERT_NO_FATAL_FAILURE(CheckNextNameValuePair(&parser, false, false,
1388                                                  std::string(), std::string()));
1389 }
1390 
TEST(HttpUtilTest,NameValuePairsIteratorStrictQuotesMissingEndQuote)1391 TEST(HttpUtilTest, NameValuePairsIteratorStrictQuotesMissingEndQuote) {
1392   std::string data = "foo=\"bar\"; name=\"value";
1393   HttpUtil::NameValuePairsIterator parser(
1394       data.begin(), data.end(), ';',
1395       HttpUtil::NameValuePairsIterator::Values::REQUIRED,
1396       HttpUtil::NameValuePairsIterator::Quotes::STRICT_QUOTES);
1397   EXPECT_TRUE(parser.valid());
1398 
1399   ASSERT_NO_FATAL_FAILURE(
1400       CheckNextNameValuePair(&parser, true, true, "foo", "bar"));
1401   ASSERT_NO_FATAL_FAILURE(CheckNextNameValuePair(&parser, false, false,
1402                                                  std::string(), std::string()));
1403 }
1404 
TEST(HttpUtilTest,NameValuePairsIteratorStrictQuotesSingleQuotes)1405 TEST(HttpUtilTest, NameValuePairsIteratorStrictQuotesSingleQuotes) {
1406   std::string data = "foo=\"bar\"; name='value; ok=it'";
1407   HttpUtil::NameValuePairsIterator parser(
1408       data.begin(), data.end(), ';',
1409       HttpUtil::NameValuePairsIterator::Values::REQUIRED,
1410       HttpUtil::NameValuePairsIterator::Quotes::STRICT_QUOTES);
1411   EXPECT_TRUE(parser.valid());
1412 
1413   ASSERT_NO_FATAL_FAILURE(
1414       CheckNextNameValuePair(&parser, true, true, "foo", "bar"));
1415   ASSERT_NO_FATAL_FAILURE(
1416       CheckNextNameValuePair(&parser, true, true, "name", "'value"));
1417   ASSERT_NO_FATAL_FAILURE(
1418       CheckNextNameValuePair(&parser, true, true, "ok", "it'"));
1419 }
1420 
TEST(HttpUtilTest,HasValidators)1421 TEST(HttpUtilTest, HasValidators) {
1422   const char* const kMissing = "";
1423   const char* const kEtagEmpty = "\"\"";
1424   const char* const kEtagStrong = "\"strong\"";
1425   const char* const kEtagWeak = "W/\"weak\"";
1426   const char* const kLastModified = "Tue, 15 Nov 1994 12:45:26 GMT";
1427   const char* const kLastModifiedInvalid = "invalid";
1428 
1429   const HttpVersion v0_9 = HttpVersion(0, 9);
1430   EXPECT_FALSE(HttpUtil::HasValidators(v0_9, kMissing, kMissing));
1431   EXPECT_FALSE(HttpUtil::HasValidators(v0_9, kEtagStrong, kMissing));
1432   EXPECT_FALSE(HttpUtil::HasValidators(v0_9, kEtagWeak, kMissing));
1433   EXPECT_FALSE(HttpUtil::HasValidators(v0_9, kEtagEmpty, kMissing));
1434 
1435   EXPECT_FALSE(HttpUtil::HasValidators(v0_9, kMissing, kLastModified));
1436   EXPECT_FALSE(HttpUtil::HasValidators(v0_9, kEtagStrong, kLastModified));
1437   EXPECT_FALSE(HttpUtil::HasValidators(v0_9, kEtagWeak, kLastModified));
1438   EXPECT_FALSE(HttpUtil::HasValidators(v0_9, kEtagEmpty, kLastModified));
1439 
1440   EXPECT_FALSE(HttpUtil::HasValidators(v0_9, kMissing, kLastModifiedInvalid));
1441   EXPECT_FALSE(
1442       HttpUtil::HasValidators(v0_9, kEtagStrong, kLastModifiedInvalid));
1443   EXPECT_FALSE(HttpUtil::HasValidators(v0_9, kEtagWeak, kLastModifiedInvalid));
1444   EXPECT_FALSE(HttpUtil::HasValidators(v0_9, kEtagEmpty, kLastModifiedInvalid));
1445 
1446   const HttpVersion v1_0 = HttpVersion(1, 0);
1447   EXPECT_FALSE(HttpUtil::HasValidators(v1_0, kMissing, kMissing));
1448   EXPECT_FALSE(HttpUtil::HasValidators(v1_0, kEtagStrong, kMissing));
1449   EXPECT_FALSE(HttpUtil::HasValidators(v1_0, kEtagWeak, kMissing));
1450   EXPECT_FALSE(HttpUtil::HasValidators(v1_0, kEtagEmpty, kMissing));
1451 
1452   EXPECT_TRUE(HttpUtil::HasValidators(v1_0, kMissing, kLastModified));
1453   EXPECT_TRUE(HttpUtil::HasValidators(v1_0, kEtagStrong, kLastModified));
1454   EXPECT_TRUE(HttpUtil::HasValidators(v1_0, kEtagWeak, kLastModified));
1455   EXPECT_TRUE(HttpUtil::HasValidators(v1_0, kEtagEmpty, kLastModified));
1456 
1457   EXPECT_FALSE(HttpUtil::HasValidators(v1_0, kMissing, kLastModifiedInvalid));
1458   EXPECT_FALSE(
1459       HttpUtil::HasValidators(v1_0, kEtagStrong, kLastModifiedInvalid));
1460   EXPECT_FALSE(HttpUtil::HasValidators(v1_0, kEtagWeak, kLastModifiedInvalid));
1461   EXPECT_FALSE(HttpUtil::HasValidators(v1_0, kEtagEmpty, kLastModifiedInvalid));
1462 
1463   const HttpVersion v1_1 = HttpVersion(1, 1);
1464   EXPECT_FALSE(HttpUtil::HasValidators(v1_1, kMissing, kMissing));
1465   EXPECT_TRUE(HttpUtil::HasValidators(v1_1, kEtagStrong, kMissing));
1466   EXPECT_TRUE(HttpUtil::HasValidators(v1_1, kEtagWeak, kMissing));
1467   EXPECT_TRUE(HttpUtil::HasValidators(v1_1, kEtagEmpty, kMissing));
1468 
1469   EXPECT_TRUE(HttpUtil::HasValidators(v1_1, kMissing, kLastModified));
1470   EXPECT_TRUE(HttpUtil::HasValidators(v1_1, kEtagStrong, kLastModified));
1471   EXPECT_TRUE(HttpUtil::HasValidators(v1_1, kEtagWeak, kLastModified));
1472   EXPECT_TRUE(HttpUtil::HasValidators(v1_1, kEtagEmpty, kLastModified));
1473 
1474   EXPECT_FALSE(HttpUtil::HasValidators(v1_1, kMissing, kLastModifiedInvalid));
1475   EXPECT_TRUE(HttpUtil::HasValidators(v1_1, kEtagStrong, kLastModifiedInvalid));
1476   EXPECT_TRUE(HttpUtil::HasValidators(v1_1, kEtagWeak, kLastModifiedInvalid));
1477   EXPECT_TRUE(HttpUtil::HasValidators(v1_1, kEtagEmpty, kLastModifiedInvalid));
1478 }
1479 
TEST(HttpUtilTest,IsValidHeaderValue)1480 TEST(HttpUtilTest, IsValidHeaderValue) {
1481   const char* const invalid_values[] = {
1482       "X-Requested-With: chrome${NUL}Sec-Unsafe: injected",
1483       "X-Requested-With: chrome\r\nSec-Unsafe: injected",
1484       "X-Requested-With: chrome\nSec-Unsafe: injected",
1485       "X-Requested-With: chrome\rSec-Unsafe: injected",
1486   };
1487   for (const std::string& value : invalid_values) {
1488     std::string replaced = value;
1489     base::ReplaceSubstringsAfterOffset(&replaced, 0, "${NUL}",
1490                                        std::string(1, '\0'));
1491     EXPECT_FALSE(HttpUtil::IsValidHeaderValue(replaced)) << replaced;
1492   }
1493 
1494   // Check that all characters permitted by RFC7230 3.2.6 are allowed.
1495   std::string allowed = "\t";
1496   for (char c = '\x20'; c < '\x7F'; ++c) {
1497     allowed.append(1, c);
1498   }
1499   for (int c = 0x80; c <= 0xFF; ++c) {
1500     allowed.append(1, static_cast<char>(c));
1501   }
1502   EXPECT_TRUE(HttpUtil::IsValidHeaderValue(allowed));
1503 }
1504 
TEST(HttpUtilTest,IsToken)1505 TEST(HttpUtilTest, IsToken) {
1506   EXPECT_TRUE(HttpUtil::IsToken("valid"));
1507   EXPECT_TRUE(HttpUtil::IsToken("!"));
1508   EXPECT_TRUE(HttpUtil::IsToken("~"));
1509 
1510   EXPECT_FALSE(HttpUtil::IsToken(""));
1511   EXPECT_FALSE(HttpUtil::IsToken(base::StringPiece()));
1512   EXPECT_FALSE(HttpUtil::IsToken("hello, world"));
1513   EXPECT_FALSE(HttpUtil::IsToken(" "));
1514   EXPECT_FALSE(HttpUtil::IsToken(base::StringPiece("\0", 1)));
1515   EXPECT_FALSE(HttpUtil::IsToken("\x01"));
1516   EXPECT_FALSE(HttpUtil::IsToken("\x7F"));
1517   EXPECT_FALSE(HttpUtil::IsToken("\x80"));
1518   EXPECT_FALSE(HttpUtil::IsToken("\xff"));
1519 }
1520 
TEST(HttpUtilTest,IsLWS)1521 TEST(HttpUtilTest, IsLWS) {
1522   EXPECT_FALSE(HttpUtil::IsLWS('\v'));
1523   EXPECT_FALSE(HttpUtil::IsLWS('\0'));
1524   EXPECT_FALSE(HttpUtil::IsLWS('1'));
1525   EXPECT_FALSE(HttpUtil::IsLWS('a'));
1526   EXPECT_FALSE(HttpUtil::IsLWS('.'));
1527   EXPECT_FALSE(HttpUtil::IsLWS('\n'));
1528   EXPECT_FALSE(HttpUtil::IsLWS('\r'));
1529 
1530   EXPECT_TRUE(HttpUtil::IsLWS('\t'));
1531   EXPECT_TRUE(HttpUtil::IsLWS(' '));
1532 }
1533 
TEST(HttpUtilTest,ParseAcceptEncoding)1534 TEST(HttpUtilTest, ParseAcceptEncoding) {
1535   const struct {
1536     const char* const value;
1537     const char* const expected;
1538   } tests[] = {
1539       {"", "*"},
1540       {"identity;q=1, *;q=0", "identity"},
1541       {"identity", "identity"},
1542       {"FOO, Bar", "bar|foo|identity"},
1543       {"foo; q=1", "foo|identity"},
1544       {"abc, foo; Q=1.0", "abc|foo|identity"},
1545       {"abc, foo;q= 1.00 , bar", "abc|bar|foo|identity"},
1546       {"abc, foo; q=1.000, bar", "abc|bar|foo|identity"},
1547       {"abc, foo ; q = 0 , bar", "abc|bar|identity"},
1548       {"abc, foo; q=0.0, bar", "abc|bar|identity"},
1549       {"abc, foo; q=0.00, bar", "abc|bar|identity"},
1550       {"abc, foo; q=0.000, bar", "abc|bar|identity"},
1551       {"abc, foo; q=0.001, bar", "abc|bar|foo|identity"},
1552       {"gzip", "gzip|identity|x-gzip"},
1553       {"x-gzip", "gzip|identity|x-gzip"},
1554       {"compress", "compress|identity|x-compress"},
1555       {"x-compress", "compress|identity|x-compress"},
1556       {"x-compress", "compress|identity|x-compress"},
1557       {"foo bar", "INVALID"},
1558       {"foo;", "INVALID"},
1559       {"foo;w=1", "INVALID"},
1560       {"foo;q+1", "INVALID"},
1561       {"foo;q=2", "INVALID"},
1562       {"foo;q=1.001", "INVALID"},
1563       {"foo;q=0.", "INVALID"},
1564       {"foo,\"bar\"", "INVALID"},
1565   };
1566 
1567   for (size_t i = 0; i < base::size(tests); ++i) {
1568     std::string value(tests[i].value);
1569     std::string reformatted;
1570     std::set<std::string> allowed_encodings;
1571     if (!HttpUtil::ParseAcceptEncoding(value, &allowed_encodings)) {
1572       reformatted = "INVALID";
1573     } else {
1574       std::vector<std::string> encodings_list;
1575       for (auto const& encoding : allowed_encodings)
1576         encodings_list.push_back(encoding);
1577       reformatted = base::JoinString(encodings_list, "|");
1578     }
1579     EXPECT_STREQ(tests[i].expected, reformatted.c_str())
1580         << "value=\"" << value << "\"";
1581   }
1582 }
1583 
TEST(HttpUtilTest,ParseContentEncoding)1584 TEST(HttpUtilTest, ParseContentEncoding) {
1585   const struct {
1586     const char* const value;
1587     const char* const expected;
1588   } tests[] = {
1589       {"", ""},
1590       {"identity;q=1, *;q=0", "INVALID"},
1591       {"identity", "identity"},
1592       {"FOO, zergli , Bar", "bar|foo|zergli"},
1593       {"foo, *", "INVALID"},
1594       {"foo,\"bar\"", "INVALID"},
1595   };
1596 
1597   for (size_t i = 0; i < base::size(tests); ++i) {
1598     std::string value(tests[i].value);
1599     std::string reformatted;
1600     std::set<std::string> used_encodings;
1601     if (!HttpUtil::ParseContentEncoding(value, &used_encodings)) {
1602       reformatted = "INVALID";
1603     } else {
1604       std::vector<std::string> encodings_list;
1605       for (auto const& encoding : used_encodings)
1606         encodings_list.push_back(encoding);
1607       reformatted = base::JoinString(encodings_list, "|");
1608     }
1609     EXPECT_STREQ(tests[i].expected, reformatted.c_str())
1610         << "value=\"" << value << "\"";
1611   }
1612 }
1613 
1614 // Test the expansion of the Language List.
TEST(HttpUtilTest,ExpandLanguageList)1615 TEST(HttpUtilTest, ExpandLanguageList) {
1616   EXPECT_EQ("", HttpUtil::ExpandLanguageList(""));
1617   EXPECT_EQ("en-US,en", HttpUtil::ExpandLanguageList("en-US"));
1618   EXPECT_EQ("fr", HttpUtil::ExpandLanguageList("fr"));
1619 
1620   // The base language is added after all regional codes...
1621   EXPECT_EQ("en-US,en-CA,en", HttpUtil::ExpandLanguageList("en-US,en-CA"));
1622 
1623   // ... but before other language families.
1624   EXPECT_EQ("en-US,en-CA,en,fr",
1625             HttpUtil::ExpandLanguageList("en-US,en-CA,fr"));
1626   EXPECT_EQ("en-US,en-CA,en,fr,en-AU",
1627             HttpUtil::ExpandLanguageList("en-US,en-CA,fr,en-AU"));
1628   EXPECT_EQ("en-US,en-CA,en,fr-CA,fr",
1629             HttpUtil::ExpandLanguageList("en-US,en-CA,fr-CA"));
1630 
1631   // Add a base language even if it's already in the list.
1632   EXPECT_EQ("en-US,en,fr-CA,fr,it,es-AR,es,it-IT",
1633             HttpUtil::ExpandLanguageList("en-US,fr-CA,it,fr,es-AR,it-IT"));
1634   // Trims a whitespace.
1635   EXPECT_EQ("en-US,en,fr", HttpUtil::ExpandLanguageList("en-US, fr"));
1636 }
1637 
1638 }  // namespace net
1639