1 #include "quiche/http2/adapter/header_validator.h"
2
3 #include <optional>
4 #include <utility>
5 #include <vector>
6
7 #include "absl/strings/str_cat.h"
8 #include "quiche/common/platform/api/quiche_test.h"
9
10 namespace http2 {
11 namespace adapter {
12 namespace test {
13
14 using ::testing::Optional;
15
16 using Header = std::pair<absl::string_view, absl::string_view>;
17 constexpr Header kSampleRequestPseudoheaders[] = {{":authority", "www.foo.com"},
18 {":method", "GET"},
19 {":path", "/foo"},
20 {":scheme", "https"}};
21
TEST(HeaderValidatorTest,HeaderNameEmpty)22 TEST(HeaderValidatorTest, HeaderNameEmpty) {
23 HeaderValidator v;
24 HeaderValidator::HeaderStatus status = v.ValidateSingleHeader("", "value");
25 EXPECT_EQ(HeaderValidator::HEADER_FIELD_INVALID, status);
26 }
27
TEST(HeaderValidatorTest,HeaderValueEmpty)28 TEST(HeaderValidatorTest, HeaderValueEmpty) {
29 HeaderValidator v;
30 HeaderValidator::HeaderStatus status = v.ValidateSingleHeader("name", "");
31 EXPECT_EQ(HeaderValidator::HEADER_OK, status);
32 }
33
TEST(HeaderValidatorTest,ExceedsMaxSize)34 TEST(HeaderValidatorTest, ExceedsMaxSize) {
35 HeaderValidator v;
36 v.SetMaxFieldSize(64u);
37 HeaderValidator::HeaderStatus status =
38 v.ValidateSingleHeader("name", "value");
39 EXPECT_EQ(HeaderValidator::HEADER_OK, status);
40 status = v.ValidateSingleHeader(
41 "name2",
42 "Antidisestablishmentariansism is supercalifragilisticexpialodocious.");
43 EXPECT_EQ(HeaderValidator::HEADER_FIELD_TOO_LONG, status);
44 }
45
TEST(HeaderValidatorTest,NameHasInvalidChar)46 TEST(HeaderValidatorTest, NameHasInvalidChar) {
47 HeaderValidator v;
48 for (const bool is_pseudo_header : {true, false}) {
49 // These characters should be allowed. (Not exhaustive.)
50 for (const char* c : {"!", "3", "a", "_", "|", "~"}) {
51 const std::string name = is_pseudo_header ? absl::StrCat(":met", c, "hod")
52 : absl::StrCat("na", c, "me");
53 HeaderValidator::HeaderStatus status =
54 v.ValidateSingleHeader(name, "value");
55 EXPECT_EQ(HeaderValidator::HEADER_OK, status);
56 }
57 // These should not. (Not exhaustive.)
58 for (const char* c : {"\\", "<", ";", "[", "=", " ", "\r", "\n", ",", "\"",
59 "\x1F", "\x91"}) {
60 const std::string name = is_pseudo_header ? absl::StrCat(":met", c, "hod")
61 : absl::StrCat("na", c, "me");
62 HeaderValidator::HeaderStatus status =
63 v.ValidateSingleHeader(name, "value");
64 EXPECT_EQ(HeaderValidator::HEADER_FIELD_INVALID, status)
65 << "with name [" << name << "]";
66 }
67 // Test nul separately.
68 {
69 const absl::string_view name = is_pseudo_header
70 ? absl::string_view(":met\0hod", 8)
71 : absl::string_view("na\0me", 5);
72 HeaderValidator::HeaderStatus status =
73 v.ValidateSingleHeader(name, "value");
74 EXPECT_EQ(HeaderValidator::HEADER_FIELD_INVALID, status);
75 }
76 // Uppercase characters in header names should not be allowed.
77 const std::string uc_name = is_pseudo_header ? ":Method" : "Name";
78 HeaderValidator::HeaderStatus status =
79 v.ValidateSingleHeader(uc_name, "value");
80 EXPECT_EQ(HeaderValidator::HEADER_FIELD_INVALID, status);
81 }
82 }
83
TEST(HeaderValidatorTest,ValueHasInvalidChar)84 TEST(HeaderValidatorTest, ValueHasInvalidChar) {
85 HeaderValidator v;
86 // These characters should be allowed. (Not exhaustive.)
87 for (const char* c :
88 {"!", "3", "a", "_", "|", "~", "\\", "<", ";", "[", "=", "A", "\t"}) {
89 const std::string value = absl::StrCat("val", c, "ue");
90 EXPECT_TRUE(
91 HeaderValidator::IsValidHeaderValue(value, ObsTextOption::kDisallow));
92 HeaderValidator::HeaderStatus status =
93 v.ValidateSingleHeader("name", value);
94 EXPECT_EQ(HeaderValidator::HEADER_OK, status);
95 }
96 // These should not.
97 for (const char* c : {"\r", "\n"}) {
98 const std::string value = absl::StrCat("val", c, "ue");
99 EXPECT_FALSE(
100 HeaderValidator::IsValidHeaderValue(value, ObsTextOption::kDisallow));
101 HeaderValidator::HeaderStatus status =
102 v.ValidateSingleHeader("name", value);
103 EXPECT_EQ(HeaderValidator::HEADER_FIELD_INVALID, status);
104 }
105 // Test nul separately.
106 {
107 const std::string value("val\0ue", 6);
108 EXPECT_FALSE(
109 HeaderValidator::IsValidHeaderValue(value, ObsTextOption::kDisallow));
110 HeaderValidator::HeaderStatus status =
111 v.ValidateSingleHeader("name", value);
112 EXPECT_EQ(HeaderValidator::HEADER_FIELD_INVALID, status);
113 }
114 {
115 const std::string obs_text_value = "val\xa9ue";
116 // Test that obs-text is disallowed by default.
117 EXPECT_EQ(HeaderValidator::HEADER_FIELD_INVALID,
118 v.ValidateSingleHeader("name", obs_text_value));
119 // Test that obs-text is disallowed when configured.
120 v.SetObsTextOption(ObsTextOption::kDisallow);
121 EXPECT_FALSE(HeaderValidator::IsValidHeaderValue(obs_text_value,
122 ObsTextOption::kDisallow));
123 EXPECT_EQ(HeaderValidator::HEADER_FIELD_INVALID,
124 v.ValidateSingleHeader("name", obs_text_value));
125 // Test that obs-text is allowed when configured.
126 v.SetObsTextOption(ObsTextOption::kAllow);
127 EXPECT_TRUE(HeaderValidator::IsValidHeaderValue(obs_text_value,
128 ObsTextOption::kAllow));
129 EXPECT_EQ(HeaderValidator::HEADER_OK,
130 v.ValidateSingleHeader("name", obs_text_value));
131 }
132 }
133
TEST(HeaderValidatorTest,StatusHasInvalidChar)134 TEST(HeaderValidatorTest, StatusHasInvalidChar) {
135 HeaderValidator v;
136
137 for (HeaderType type : {HeaderType::RESPONSE, HeaderType::RESPONSE_100}) {
138 // When `:status` has a non-digit value, validation will fail.
139 v.StartHeaderBlock();
140 EXPECT_EQ(HeaderValidator::HEADER_FIELD_INVALID,
141 v.ValidateSingleHeader(":status", "bar"));
142 EXPECT_FALSE(v.FinishHeaderBlock(type));
143
144 // When `:status` is too short, validation will fail.
145 v.StartHeaderBlock();
146 EXPECT_EQ(HeaderValidator::HEADER_FIELD_INVALID,
147 v.ValidateSingleHeader(":status", "10"));
148 EXPECT_FALSE(v.FinishHeaderBlock(type));
149
150 // When `:status` is too long, validation will fail.
151 v.StartHeaderBlock();
152 EXPECT_EQ(HeaderValidator::HEADER_FIELD_INVALID,
153 v.ValidateSingleHeader(":status", "9000"));
154 EXPECT_FALSE(v.FinishHeaderBlock(type));
155
156 // When `:status` is just right, validation will succeed.
157 v.StartHeaderBlock();
158 EXPECT_EQ(HeaderValidator::HEADER_OK,
159 v.ValidateSingleHeader(":status", "400"));
160 EXPECT_TRUE(v.FinishHeaderBlock(type));
161 }
162 }
163
TEST(HeaderValidatorTest,AuthorityHasInvalidChar)164 TEST(HeaderValidatorTest, AuthorityHasInvalidChar) {
165 for (absl::string_view key : {":authority", "host"}) {
166 // These characters should be allowed. (Not exhaustive.)
167 for (const absl::string_view c : {"1", "-", "!", ":", "+", "=", ","}) {
168 const std::string value = absl::StrCat("ho", c, "st.example.com");
169 EXPECT_TRUE(HeaderValidator::IsValidAuthority(value));
170
171 HeaderValidator v;
172 v.StartHeaderBlock();
173 HeaderValidator::HeaderStatus status = v.ValidateSingleHeader(key, value);
174 EXPECT_EQ(HeaderValidator::HEADER_OK, status)
175 << " with name [" << key << "] and value [" << value << "]";
176 }
177 // These should not.
178 for (const absl::string_view c : {"\r", "\n", "|", "\\", "`"}) {
179 const std::string value = absl::StrCat("ho", c, "st.example.com");
180 EXPECT_FALSE(HeaderValidator::IsValidAuthority(value));
181
182 HeaderValidator v;
183 v.StartHeaderBlock();
184 HeaderValidator::HeaderStatus status = v.ValidateSingleHeader(key, value);
185 EXPECT_EQ(HeaderValidator::HEADER_FIELD_INVALID, status);
186 }
187
188 {
189 // IPv4 example
190 const std::string value = "123.45.67.89";
191 EXPECT_TRUE(HeaderValidator::IsValidAuthority(value));
192
193 HeaderValidator v;
194 v.StartHeaderBlock();
195 HeaderValidator::HeaderStatus status = v.ValidateSingleHeader(key, value);
196 EXPECT_EQ(HeaderValidator::HEADER_OK, status);
197 }
198
199 {
200 // IPv6 examples
201 const std::string value1 = "2001:0db8:85a3:0000:0000:8a2e:0370:7334";
202 EXPECT_TRUE(HeaderValidator::IsValidAuthority(value1));
203
204 HeaderValidator v;
205 v.StartHeaderBlock();
206 HeaderValidator::HeaderStatus status =
207 v.ValidateSingleHeader(key, value1);
208 EXPECT_EQ(HeaderValidator::HEADER_OK, status);
209
210 const std::string value2 = "[::1]:80";
211 EXPECT_TRUE(HeaderValidator::IsValidAuthority(value2));
212 HeaderValidator v2;
213 v2.StartHeaderBlock();
214 status = v2.ValidateSingleHeader(key, value2);
215 EXPECT_EQ(HeaderValidator::HEADER_OK, status);
216 }
217
218 {
219 // Empty field
220 EXPECT_TRUE(HeaderValidator::IsValidAuthority(""));
221
222 HeaderValidator v;
223 v.StartHeaderBlock();
224 HeaderValidator::HeaderStatus status = v.ValidateSingleHeader(key, "");
225 EXPECT_EQ(HeaderValidator::HEADER_OK, status);
226 }
227 }
228 }
229
TEST(HeaderValidatorTest,RequestHostAndAuthority)230 TEST(HeaderValidatorTest, RequestHostAndAuthority) {
231 HeaderValidator v;
232 v.StartHeaderBlock();
233 for (Header to_add : kSampleRequestPseudoheaders) {
234 EXPECT_EQ(HeaderValidator::HEADER_OK,
235 v.ValidateSingleHeader(to_add.first, to_add.second));
236 }
237 // If both "host" and ":authority" have the same value, validation succeeds.
238 EXPECT_EQ(HeaderValidator::HEADER_OK,
239 v.ValidateSingleHeader("host", "www.foo.com"));
240 EXPECT_TRUE(v.FinishHeaderBlock(HeaderType::REQUEST));
241
242 v.StartHeaderBlock();
243 for (Header to_add : kSampleRequestPseudoheaders) {
244 EXPECT_EQ(HeaderValidator::HEADER_OK,
245 v.ValidateSingleHeader(to_add.first, to_add.second));
246 }
247 // If "host" and ":authority" have different values, validation fails.
248 EXPECT_EQ(HeaderValidator::HEADER_FIELD_INVALID,
249 v.ValidateSingleHeader("host", "www.bar.com"));
250 }
251
TEST(HeaderValidatorTest,RequestHostAndAuthorityLax)252 TEST(HeaderValidatorTest, RequestHostAndAuthorityLax) {
253 HeaderValidator v;
254 v.SetAllowDifferentHostAndAuthority();
255 v.StartHeaderBlock();
256 for (Header to_add : kSampleRequestPseudoheaders) {
257 EXPECT_EQ(HeaderValidator::HEADER_OK,
258 v.ValidateSingleHeader(to_add.first, to_add.second));
259 }
260 // Since the option is set, validation succeeds even if "host" and
261 // ":authority" have different values.
262 EXPECT_EQ(HeaderValidator::HEADER_OK,
263 v.ValidateSingleHeader("host", "www.bar.com"));
264 }
265
TEST(HeaderValidatorTest,MethodHasInvalidChar)266 TEST(HeaderValidatorTest, MethodHasInvalidChar) {
267 HeaderValidator v;
268 v.StartHeaderBlock();
269
270 std::vector<absl::string_view> bad_methods = {
271 "In[]valid{}", "co,mma", "spac e", "a@t", "equals=",
272 "question?mark", "co:lon", "semi;colon", "sla/sh", "back\\slash",
273 };
274
275 std::vector<absl::string_view> good_methods = {
276 "lowercase", "MiXeDcAsE", "NONCANONICAL", "HASH#",
277 "under_score", "PI|PE", "Tilde~", "quote'",
278 };
279
280 for (absl::string_view value : bad_methods) {
281 v.StartHeaderBlock();
282 EXPECT_EQ(HeaderValidator::HEADER_FIELD_INVALID,
283 v.ValidateSingleHeader(":method", value));
284 }
285
286 for (absl::string_view value : good_methods) {
287 v.StartHeaderBlock();
288 EXPECT_EQ(HeaderValidator::HEADER_OK,
289 v.ValidateSingleHeader(":method", value));
290 for (Header to_add : kSampleRequestPseudoheaders) {
291 if (to_add.first == ":method") {
292 continue;
293 }
294 EXPECT_EQ(HeaderValidator::HEADER_OK,
295 v.ValidateSingleHeader(to_add.first, to_add.second));
296 }
297 EXPECT_TRUE(v.FinishHeaderBlock(HeaderType::REQUEST));
298 }
299 }
300
TEST(HeaderValidatorTest,RequestPseudoHeaders)301 TEST(HeaderValidatorTest, RequestPseudoHeaders) {
302 HeaderValidator v;
303 for (Header to_skip : kSampleRequestPseudoheaders) {
304 v.StartHeaderBlock();
305 for (Header to_add : kSampleRequestPseudoheaders) {
306 if (to_add != to_skip) {
307 EXPECT_EQ(HeaderValidator::HEADER_OK,
308 v.ValidateSingleHeader(to_add.first, to_add.second));
309 }
310 }
311 // When any pseudo-header is missing, final validation will fail.
312 EXPECT_FALSE(v.FinishHeaderBlock(HeaderType::REQUEST));
313 }
314
315 // When all pseudo-headers are present, final validation will succeed.
316 v.StartHeaderBlock();
317 for (Header to_add : kSampleRequestPseudoheaders) {
318 EXPECT_EQ(HeaderValidator::HEADER_OK,
319 v.ValidateSingleHeader(to_add.first, to_add.second));
320 }
321 EXPECT_TRUE(v.FinishHeaderBlock(HeaderType::REQUEST));
322
323 // When an extra pseudo-header is present, final validation will fail.
324 v.StartHeaderBlock();
325 for (Header to_add : kSampleRequestPseudoheaders) {
326 EXPECT_EQ(HeaderValidator::HEADER_OK,
327 v.ValidateSingleHeader(to_add.first, to_add.second));
328 }
329 EXPECT_EQ(HeaderValidator::HEADER_OK,
330 v.ValidateSingleHeader(":extra", "blah"));
331 EXPECT_FALSE(v.FinishHeaderBlock(HeaderType::REQUEST));
332
333 // When a required pseudo-header is repeated, final validation will fail.
334 for (Header to_repeat : kSampleRequestPseudoheaders) {
335 v.StartHeaderBlock();
336 for (Header to_add : kSampleRequestPseudoheaders) {
337 EXPECT_EQ(HeaderValidator::HEADER_OK,
338 v.ValidateSingleHeader(to_add.first, to_add.second));
339 if (to_add == to_repeat) {
340 EXPECT_EQ(HeaderValidator::HEADER_OK,
341 v.ValidateSingleHeader(to_add.first, to_add.second));
342 }
343 }
344 EXPECT_FALSE(v.FinishHeaderBlock(HeaderType::REQUEST));
345 }
346 }
347
TEST(HeaderValidatorTest,ConnectHeaders)348 TEST(HeaderValidatorTest, ConnectHeaders) {
349 // Too few headers.
350 HeaderValidator v;
351 v.StartHeaderBlock();
352 EXPECT_EQ(HeaderValidator::HEADER_OK,
353 v.ValidateSingleHeader(":authority", "athena.dialup.mit.edu:23"));
354 EXPECT_FALSE(v.FinishHeaderBlock(HeaderType::REQUEST));
355
356 v.StartHeaderBlock();
357 EXPECT_EQ(HeaderValidator::HEADER_OK,
358 v.ValidateSingleHeader(":method", "CONNECT"));
359 EXPECT_FALSE(v.FinishHeaderBlock(HeaderType::REQUEST));
360
361 // Too many headers.
362 v.StartHeaderBlock();
363 EXPECT_EQ(HeaderValidator::HEADER_OK,
364 v.ValidateSingleHeader(":authority", "athena.dialup.mit.edu:23"));
365 EXPECT_EQ(HeaderValidator::HEADER_OK,
366 v.ValidateSingleHeader(":method", "CONNECT"));
367 EXPECT_EQ(HeaderValidator::HEADER_OK, v.ValidateSingleHeader(":path", "/"));
368 EXPECT_FALSE(v.FinishHeaderBlock(HeaderType::REQUEST));
369
370 // Empty :authority
371 v.StartHeaderBlock();
372 EXPECT_EQ(HeaderValidator::HEADER_OK,
373 v.ValidateSingleHeader(":authority", ""));
374 EXPECT_EQ(HeaderValidator::HEADER_OK,
375 v.ValidateSingleHeader(":method", "CONNECT"));
376 EXPECT_FALSE(v.FinishHeaderBlock(HeaderType::REQUEST));
377
378 // Just right.
379 v.StartHeaderBlock();
380 EXPECT_EQ(HeaderValidator::HEADER_OK,
381 v.ValidateSingleHeader(":authority", "athena.dialup.mit.edu:23"));
382 EXPECT_EQ(HeaderValidator::HEADER_OK,
383 v.ValidateSingleHeader(":method", "CONNECT"));
384 EXPECT_TRUE(v.FinishHeaderBlock(HeaderType::REQUEST));
385
386 v.SetAllowExtendedConnect();
387 // "Classic" CONNECT headers should still be accepted.
388 v.StartHeaderBlock();
389 EXPECT_EQ(HeaderValidator::HEADER_OK,
390 v.ValidateSingleHeader(":authority", "athena.dialup.mit.edu:23"));
391 EXPECT_EQ(HeaderValidator::HEADER_OK,
392 v.ValidateSingleHeader(":method", "CONNECT"));
393 EXPECT_TRUE(v.FinishHeaderBlock(HeaderType::REQUEST));
394 }
395
TEST(HeaderValidatorTest,WebsocketPseudoHeaders)396 TEST(HeaderValidatorTest, WebsocketPseudoHeaders) {
397 HeaderValidator v;
398 v.StartHeaderBlock();
399 for (Header to_add : kSampleRequestPseudoheaders) {
400 EXPECT_EQ(HeaderValidator::HEADER_OK,
401 v.ValidateSingleHeader(to_add.first, to_add.second));
402 }
403 EXPECT_EQ(HeaderValidator::HEADER_OK,
404 v.ValidateSingleHeader(":protocol", "websocket"));
405 // At this point, `:protocol` is treated as an extra pseudo-header.
406 EXPECT_FALSE(v.FinishHeaderBlock(HeaderType::REQUEST));
407
408 // Future header blocks may send the `:protocol` pseudo-header for CONNECT
409 // requests.
410 v.SetAllowExtendedConnect();
411
412 v.StartHeaderBlock();
413 for (Header to_add : kSampleRequestPseudoheaders) {
414 EXPECT_EQ(HeaderValidator::HEADER_OK,
415 v.ValidateSingleHeader(to_add.first, to_add.second));
416 }
417 EXPECT_EQ(HeaderValidator::HEADER_OK,
418 v.ValidateSingleHeader(":protocol", "websocket"));
419 // The method is not "CONNECT", so `:protocol` is still treated as an extra
420 // pseudo-header.
421 EXPECT_FALSE(v.FinishHeaderBlock(HeaderType::REQUEST));
422
423 v.StartHeaderBlock();
424 for (Header to_add : kSampleRequestPseudoheaders) {
425 if (to_add.first == ":method") {
426 EXPECT_EQ(HeaderValidator::HEADER_OK,
427 v.ValidateSingleHeader(to_add.first, "CONNECT"));
428 } else {
429 EXPECT_EQ(HeaderValidator::HEADER_OK,
430 v.ValidateSingleHeader(to_add.first, to_add.second));
431 }
432 }
433 EXPECT_EQ(HeaderValidator::HEADER_OK,
434 v.ValidateSingleHeader(":protocol", "websocket"));
435 // After allowing the method, `:protocol` is acepted for CONNECT requests.
436 EXPECT_TRUE(v.FinishHeaderBlock(HeaderType::REQUEST));
437 }
438
TEST(HeaderValidatorTest,AsteriskPathPseudoHeader)439 TEST(HeaderValidatorTest, AsteriskPathPseudoHeader) {
440 HeaderValidator v;
441
442 // An asterisk :path should not be allowed for non-OPTIONS requests.
443 v.StartHeaderBlock();
444 for (Header to_add : kSampleRequestPseudoheaders) {
445 if (to_add.first == ":path") {
446 EXPECT_EQ(HeaderValidator::HEADER_OK,
447 v.ValidateSingleHeader(to_add.first, "*"));
448 } else {
449 EXPECT_EQ(HeaderValidator::HEADER_OK,
450 v.ValidateSingleHeader(to_add.first, to_add.second));
451 }
452 }
453 EXPECT_FALSE(v.FinishHeaderBlock(HeaderType::REQUEST));
454
455 // An asterisk :path should be allowed for OPTIONS requests.
456 v.StartHeaderBlock();
457 for (Header to_add : kSampleRequestPseudoheaders) {
458 if (to_add.first == ":path") {
459 EXPECT_EQ(HeaderValidator::HEADER_OK,
460 v.ValidateSingleHeader(to_add.first, "*"));
461 } else if (to_add.first == ":method") {
462 EXPECT_EQ(HeaderValidator::HEADER_OK,
463 v.ValidateSingleHeader(to_add.first, "OPTIONS"));
464 } else {
465 EXPECT_EQ(HeaderValidator::HEADER_OK,
466 v.ValidateSingleHeader(to_add.first, to_add.second));
467 }
468 }
469 EXPECT_TRUE(v.FinishHeaderBlock(HeaderType::REQUEST));
470 }
471
TEST(HeaderValidatorTest,InvalidPathPseudoHeader)472 TEST(HeaderValidatorTest, InvalidPathPseudoHeader) {
473 HeaderValidator v;
474
475 // An empty path should fail on single header validation and finish.
476 v.StartHeaderBlock();
477 for (Header to_add : kSampleRequestPseudoheaders) {
478 if (to_add.first == ":path") {
479 EXPECT_EQ(HeaderValidator::HEADER_FIELD_INVALID,
480 v.ValidateSingleHeader(to_add.first, ""));
481 } else {
482 EXPECT_EQ(HeaderValidator::HEADER_OK,
483 v.ValidateSingleHeader(to_add.first, to_add.second));
484 }
485 }
486 EXPECT_FALSE(v.FinishHeaderBlock(HeaderType::REQUEST));
487
488 // The remainder of the checks require enabling path validation.
489 v.SetValidatePath();
490
491 // A path that does not start with a slash should fail on finish.
492 v.StartHeaderBlock();
493 for (Header to_add : kSampleRequestPseudoheaders) {
494 if (to_add.first == ":path") {
495 EXPECT_EQ(HeaderValidator::HEADER_OK,
496 v.ValidateSingleHeader(to_add.first, "shawarma"));
497 } else {
498 EXPECT_EQ(HeaderValidator::HEADER_OK,
499 v.ValidateSingleHeader(to_add.first, to_add.second));
500 }
501 }
502 EXPECT_FALSE(v.FinishHeaderBlock(HeaderType::REQUEST));
503
504 // Various valid path characters.
505 for (const absl::string_view c :
506 {"/", "?", "_", "'", "9", "&", "(", "@", ":"}) {
507 const std::string value = absl::StrCat("/shawa", c, "rma");
508
509 HeaderValidator validator;
510 validator.SetValidatePath();
511 validator.StartHeaderBlock();
512 for (Header to_add : kSampleRequestPseudoheaders) {
513 if (to_add.first == ":path") {
514 EXPECT_EQ(HeaderValidator::HEADER_OK,
515 validator.ValidateSingleHeader(to_add.first, value))
516 << "Problematic char: [" << c << "]";
517 } else {
518 EXPECT_EQ(HeaderValidator::HEADER_OK,
519 validator.ValidateSingleHeader(to_add.first, to_add.second));
520 }
521 }
522 EXPECT_TRUE(validator.FinishHeaderBlock(HeaderType::REQUEST));
523 }
524
525 // Various invalid path characters.
526 for (const absl::string_view c : {"[", "<", "}", "`", "\\", " ", "\t", "#"}) {
527 const std::string value = absl::StrCat("/shawa", c, "rma");
528
529 HeaderValidator validator;
530 validator.SetValidatePath();
531 validator.StartHeaderBlock();
532 for (Header to_add : kSampleRequestPseudoheaders) {
533 if (to_add.first == ":path") {
534 EXPECT_EQ(HeaderValidator::HEADER_FIELD_INVALID,
535 validator.ValidateSingleHeader(to_add.first, value));
536 } else {
537 EXPECT_EQ(HeaderValidator::HEADER_OK,
538 validator.ValidateSingleHeader(to_add.first, to_add.second));
539 }
540 }
541 EXPECT_FALSE(validator.FinishHeaderBlock(HeaderType::REQUEST));
542 }
543
544 // The fragment initial character can be explicitly allowed.
545 {
546 HeaderValidator validator;
547 validator.SetValidatePath();
548 validator.SetAllowFragmentInPath();
549 validator.StartHeaderBlock();
550 for (Header to_add : kSampleRequestPseudoheaders) {
551 if (to_add.first == ":path") {
552 EXPECT_EQ(HeaderValidator::HEADER_OK,
553 validator.ValidateSingleHeader(to_add.first, "/shawa#rma"));
554 } else {
555 EXPECT_EQ(HeaderValidator::HEADER_OK,
556 validator.ValidateSingleHeader(to_add.first, to_add.second));
557 }
558 }
559 EXPECT_TRUE(validator.FinishHeaderBlock(HeaderType::REQUEST));
560 }
561 }
562
TEST(HeaderValidatorTest,ResponsePseudoHeaders)563 TEST(HeaderValidatorTest, ResponsePseudoHeaders) {
564 HeaderValidator v;
565
566 for (HeaderType type : {HeaderType::RESPONSE, HeaderType::RESPONSE_100}) {
567 // When `:status` is missing, validation will fail.
568 v.StartHeaderBlock();
569 EXPECT_EQ(HeaderValidator::HEADER_OK, v.ValidateSingleHeader("foo", "bar"));
570 EXPECT_FALSE(v.FinishHeaderBlock(type));
571
572 // When all pseudo-headers are present, final validation will succeed.
573 v.StartHeaderBlock();
574 EXPECT_EQ(HeaderValidator::HEADER_OK,
575 v.ValidateSingleHeader(":status", "199"));
576 EXPECT_TRUE(v.FinishHeaderBlock(type));
577 EXPECT_EQ("199", v.status_header());
578
579 // When `:status` is repeated, validation will fail.
580 v.StartHeaderBlock();
581 EXPECT_EQ(HeaderValidator::HEADER_OK,
582 v.ValidateSingleHeader(":status", "199"));
583 EXPECT_EQ(HeaderValidator::HEADER_OK,
584 v.ValidateSingleHeader(":status", "299"));
585 EXPECT_FALSE(v.FinishHeaderBlock(type));
586
587 // When an extra pseudo-header is present, final validation will fail.
588 v.StartHeaderBlock();
589 EXPECT_EQ(HeaderValidator::HEADER_OK,
590 v.ValidateSingleHeader(":status", "199"));
591 EXPECT_EQ(HeaderValidator::HEADER_OK,
592 v.ValidateSingleHeader(":extra", "blorp"));
593 EXPECT_FALSE(v.FinishHeaderBlock(type));
594 }
595 }
596
TEST(HeaderValidatorTest,ResponseWithHost)597 TEST(HeaderValidatorTest, ResponseWithHost) {
598 HeaderValidator v;
599
600 v.StartHeaderBlock();
601 EXPECT_EQ(HeaderValidator::HEADER_OK,
602 v.ValidateSingleHeader(":status", "200"));
603 EXPECT_EQ(HeaderValidator::HEADER_OK,
604 v.ValidateSingleHeader("host", "myserver.com"));
605 EXPECT_TRUE(v.FinishHeaderBlock(HeaderType::RESPONSE));
606 }
607
TEST(HeaderValidatorTest,Response204)608 TEST(HeaderValidatorTest, Response204) {
609 HeaderValidator v;
610
611 v.StartHeaderBlock();
612 EXPECT_EQ(HeaderValidator::HEADER_OK,
613 v.ValidateSingleHeader(":status", "204"));
614 EXPECT_EQ(HeaderValidator::HEADER_OK,
615 v.ValidateSingleHeader("x-content", "is not present"));
616 EXPECT_TRUE(v.FinishHeaderBlock(HeaderType::RESPONSE));
617 }
618
TEST(HeaderValidatorTest,ResponseWithMultipleIdenticalContentLength)619 TEST(HeaderValidatorTest, ResponseWithMultipleIdenticalContentLength) {
620 HeaderValidator v;
621
622 v.StartHeaderBlock();
623 EXPECT_EQ(HeaderValidator::HEADER_OK,
624 v.ValidateSingleHeader(":status", "200"));
625 EXPECT_EQ(HeaderValidator::HEADER_OK,
626 v.ValidateSingleHeader("content-length", "13"));
627 EXPECT_EQ(HeaderValidator::HEADER_SKIP,
628 v.ValidateSingleHeader("content-length", "13"));
629 }
630
TEST(HeaderValidatorTest,ResponseWithMultipleDifferingContentLength)631 TEST(HeaderValidatorTest, ResponseWithMultipleDifferingContentLength) {
632 HeaderValidator v;
633
634 v.StartHeaderBlock();
635 EXPECT_EQ(HeaderValidator::HEADER_OK,
636 v.ValidateSingleHeader(":status", "200"));
637 EXPECT_EQ(HeaderValidator::HEADER_OK,
638 v.ValidateSingleHeader("content-length", "13"));
639 EXPECT_EQ(HeaderValidator::HEADER_FIELD_INVALID,
640 v.ValidateSingleHeader("content-length", "17"));
641 }
642
TEST(HeaderValidatorTest,Response204WithContentLengthZero)643 TEST(HeaderValidatorTest, Response204WithContentLengthZero) {
644 HeaderValidator v;
645
646 v.StartHeaderBlock();
647 EXPECT_EQ(HeaderValidator::HEADER_OK,
648 v.ValidateSingleHeader(":status", "204"));
649 EXPECT_EQ(HeaderValidator::HEADER_OK,
650 v.ValidateSingleHeader("x-content", "is not present"));
651 EXPECT_EQ(HeaderValidator::HEADER_OK,
652 v.ValidateSingleHeader("content-length", "0"));
653 EXPECT_TRUE(v.FinishHeaderBlock(HeaderType::RESPONSE));
654 }
655
TEST(HeaderValidatorTest,Response204WithContentLength)656 TEST(HeaderValidatorTest, Response204WithContentLength) {
657 HeaderValidator v;
658
659 v.StartHeaderBlock();
660 EXPECT_EQ(HeaderValidator::HEADER_OK,
661 v.ValidateSingleHeader(":status", "204"));
662 EXPECT_EQ(HeaderValidator::HEADER_OK,
663 v.ValidateSingleHeader("x-content", "is not present"));
664 EXPECT_EQ(HeaderValidator::HEADER_FIELD_INVALID,
665 v.ValidateSingleHeader("content-length", "1"));
666 }
667
TEST(HeaderValidatorTest,Response100)668 TEST(HeaderValidatorTest, Response100) {
669 HeaderValidator v;
670
671 v.StartHeaderBlock();
672 EXPECT_EQ(HeaderValidator::HEADER_OK,
673 v.ValidateSingleHeader(":status", "100"));
674 EXPECT_EQ(HeaderValidator::HEADER_OK,
675 v.ValidateSingleHeader("x-content", "is not present"));
676 EXPECT_TRUE(v.FinishHeaderBlock(HeaderType::RESPONSE));
677 }
678
TEST(HeaderValidatorTest,Response100WithContentLengthZero)679 TEST(HeaderValidatorTest, Response100WithContentLengthZero) {
680 HeaderValidator v;
681
682 v.StartHeaderBlock();
683 EXPECT_EQ(HeaderValidator::HEADER_OK,
684 v.ValidateSingleHeader(":status", "100"));
685 EXPECT_EQ(HeaderValidator::HEADER_OK,
686 v.ValidateSingleHeader("x-content", "is not present"));
687 EXPECT_EQ(HeaderValidator::HEADER_OK,
688 v.ValidateSingleHeader("content-length", "0"));
689 EXPECT_TRUE(v.FinishHeaderBlock(HeaderType::RESPONSE));
690 }
691
TEST(HeaderValidatorTest,Response100WithContentLength)692 TEST(HeaderValidatorTest, Response100WithContentLength) {
693 HeaderValidator v;
694
695 v.StartHeaderBlock();
696 EXPECT_EQ(HeaderValidator::HEADER_OK,
697 v.ValidateSingleHeader(":status", "100"));
698 EXPECT_EQ(HeaderValidator::HEADER_OK,
699 v.ValidateSingleHeader("x-content", "is not present"));
700 EXPECT_EQ(HeaderValidator::HEADER_FIELD_INVALID,
701 v.ValidateSingleHeader("content-length", "1"));
702 }
703
TEST(HeaderValidatorTest,ResponseTrailerPseudoHeaders)704 TEST(HeaderValidatorTest, ResponseTrailerPseudoHeaders) {
705 HeaderValidator v;
706
707 // When no pseudo-headers are present, validation will succeed.
708 v.StartHeaderBlock();
709 EXPECT_EQ(HeaderValidator::HEADER_OK, v.ValidateSingleHeader("foo", "bar"));
710 EXPECT_TRUE(v.FinishHeaderBlock(HeaderType::RESPONSE_TRAILER));
711
712 // When any pseudo-header is present, final validation will fail.
713 v.StartHeaderBlock();
714 EXPECT_EQ(HeaderValidator::HEADER_OK,
715 v.ValidateSingleHeader(":status", "200"));
716 EXPECT_EQ(HeaderValidator::HEADER_OK, v.ValidateSingleHeader("foo", "bar"));
717 EXPECT_FALSE(v.FinishHeaderBlock(HeaderType::RESPONSE_TRAILER));
718 }
719
TEST(HeaderValidatorTest,ValidContentLength)720 TEST(HeaderValidatorTest, ValidContentLength) {
721 HeaderValidator v;
722
723 v.StartHeaderBlock();
724 EXPECT_EQ(v.content_length(), std::nullopt);
725 EXPECT_EQ(HeaderValidator::HEADER_OK,
726 v.ValidateSingleHeader("content-length", "41"));
727 EXPECT_THAT(v.content_length(), Optional(41));
728
729 v.StartHeaderBlock();
730 EXPECT_EQ(v.content_length(), std::nullopt);
731 EXPECT_EQ(HeaderValidator::HEADER_OK,
732 v.ValidateSingleHeader("content-length", "42"));
733 EXPECT_THAT(v.content_length(), Optional(42));
734 }
735
TEST(HeaderValidatorTest,InvalidContentLength)736 TEST(HeaderValidatorTest, InvalidContentLength) {
737 HeaderValidator v;
738
739 v.StartHeaderBlock();
740 EXPECT_EQ(v.content_length(), std::nullopt);
741 EXPECT_EQ(HeaderValidator::HEADER_FIELD_INVALID,
742 v.ValidateSingleHeader("content-length", ""));
743 EXPECT_EQ(v.content_length(), std::nullopt);
744 EXPECT_EQ(HeaderValidator::HEADER_FIELD_INVALID,
745 v.ValidateSingleHeader("content-length", "nan"));
746 EXPECT_EQ(v.content_length(), std::nullopt);
747 EXPECT_EQ(HeaderValidator::HEADER_FIELD_INVALID,
748 v.ValidateSingleHeader("content-length", "-42"));
749 EXPECT_EQ(v.content_length(), std::nullopt);
750 // End on a positive note.
751 EXPECT_EQ(HeaderValidator::HEADER_OK,
752 v.ValidateSingleHeader("content-length", "42"));
753 EXPECT_THAT(v.content_length(), Optional(42));
754 }
755
TEST(HeaderValidatorTest,TeHeader)756 TEST(HeaderValidatorTest, TeHeader) {
757 HeaderValidator v;
758
759 v.StartHeaderBlock();
760 EXPECT_EQ(HeaderValidator::HEADER_OK,
761 v.ValidateSingleHeader("te", "trailers"));
762
763 v.StartHeaderBlock();
764 EXPECT_EQ(HeaderValidator::HEADER_FIELD_INVALID,
765 v.ValidateSingleHeader("te", "trailers, deflate"));
766 }
767
TEST(HeaderValidatorTest,ConnectionSpecificHeaders)768 TEST(HeaderValidatorTest, ConnectionSpecificHeaders) {
769 const std::vector<Header> connection_headers = {
770 {"connection", "keep-alive"}, {"proxy-connection", "keep-alive"},
771 {"keep-alive", "timeout=42"}, {"transfer-encoding", "chunked"},
772 {"upgrade", "h2c"},
773 };
774 for (const auto& [connection_key, connection_value] : connection_headers) {
775 HeaderValidator v;
776 v.StartHeaderBlock();
777 for (const auto& [sample_key, sample_value] : kSampleRequestPseudoheaders) {
778 EXPECT_EQ(HeaderValidator::HEADER_OK,
779 v.ValidateSingleHeader(sample_key, sample_value));
780 }
781 EXPECT_EQ(HeaderValidator::HEADER_FIELD_INVALID,
782 v.ValidateSingleHeader(connection_key, connection_value));
783 }
784 }
785
TEST(HeaderValidatorTest,MixedCaseHeaderName)786 TEST(HeaderValidatorTest, MixedCaseHeaderName) {
787 HeaderValidator v;
788 v.SetAllowUppercaseInHeaderNames();
789 EXPECT_EQ(HeaderValidator::HEADER_OK,
790 v.ValidateSingleHeader("MixedCaseName", "value"));
791 }
792
793 // SetAllowUppercaseInHeaderNames() only applies to non-pseudo-headers.
TEST(HeaderValidatorTest,MixedCasePseudoHeader)794 TEST(HeaderValidatorTest, MixedCasePseudoHeader) {
795 HeaderValidator v;
796 v.SetAllowUppercaseInHeaderNames();
797 EXPECT_EQ(HeaderValidator::HEADER_FIELD_INVALID,
798 v.ValidateSingleHeader(":PATH", "/"));
799 }
800
801 // Matching `host` is case-insensitive.
TEST(HeaderValidatorTest,MixedCaseHost)802 TEST(HeaderValidatorTest, MixedCaseHost) {
803 HeaderValidator v;
804 v.SetAllowUppercaseInHeaderNames();
805 for (Header to_add : kSampleRequestPseudoheaders) {
806 EXPECT_EQ(HeaderValidator::HEADER_OK,
807 v.ValidateSingleHeader(to_add.first, to_add.second));
808 }
809 // Validation fails, because "host" and ":authority" have different values.
810 EXPECT_EQ(HeaderValidator::HEADER_FIELD_INVALID,
811 v.ValidateSingleHeader("Host", "www.bar.com"));
812 }
813
814 // Matching `content-length` is case-insensitive.
TEST(HeaderValidatorTest,MixedCaseContentLength)815 TEST(HeaderValidatorTest, MixedCaseContentLength) {
816 HeaderValidator v;
817 v.SetAllowUppercaseInHeaderNames();
818 EXPECT_EQ(v.content_length(), std::nullopt);
819 EXPECT_EQ(HeaderValidator::HEADER_OK,
820 v.ValidateSingleHeader("Content-Length", "42"));
821 EXPECT_THAT(v.content_length(), Optional(42));
822 }
823
824 } // namespace test
825 } // namespace adapter
826 } // namespace http2
827