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