1 /*
2 * nghttp2 - HTTP/2 C Library
3 *
4 * Copyright (c) 2013 Tatsuhiro Tsujikawa
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining
7 * a copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sublicense, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be
15 * included in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 */
25 #include "http2_test.h"
26
27 #include <cassert>
28 #include <cstring>
29 #include <iostream>
30
31 #include <CUnit/CUnit.h>
32
33 #include "url-parser/url_parser.h"
34
35 #include "http2.h"
36 #include "util.h"
37
38 using namespace nghttp2;
39
40 #define MAKE_NV(K, V) \
41 { \
42 (uint8_t *)K, (uint8_t *)V, sizeof(K) - 1, sizeof(V) - 1, \
43 NGHTTP2_NV_FLAG_NONE \
44 }
45
46 namespace shrpx {
47
48 namespace {
check_nv(const HeaderRef & a,const nghttp2_nv * b)49 void check_nv(const HeaderRef &a, const nghttp2_nv *b) {
50 CU_ASSERT(a.name.size() == b->namelen);
51 CU_ASSERT(a.value.size() == b->valuelen);
52 CU_ASSERT(memcmp(a.name.c_str(), b->name, b->namelen) == 0);
53 CU_ASSERT(memcmp(a.value.c_str(), b->value, b->valuelen) == 0);
54 }
55 } // namespace
56
test_http2_add_header(void)57 void test_http2_add_header(void) {
58 auto nva = Headers();
59
60 http2::add_header(nva, (const uint8_t *)"alpha", 5, (const uint8_t *)"123", 3,
61 false, -1);
62 CU_ASSERT(Headers::value_type("alpha", "123") == nva[0]);
63 CU_ASSERT(!nva[0].no_index);
64
65 nva.clear();
66
67 http2::add_header(nva, (const uint8_t *)"alpha", 5, (const uint8_t *)"", 0,
68 true, -1);
69 CU_ASSERT(Headers::value_type("alpha", "") == nva[0]);
70 CU_ASSERT(nva[0].no_index);
71
72 nva.clear();
73
74 http2::add_header(nva, (const uint8_t *)"a", 1, (const uint8_t *)" b", 2,
75 false, -1);
76 CU_ASSERT(Headers::value_type("a", "b") == nva[0]);
77
78 nva.clear();
79
80 http2::add_header(nva, (const uint8_t *)"a", 1, (const uint8_t *)"b ", 2,
81 false, -1);
82 CU_ASSERT(Headers::value_type("a", "b") == nva[0]);
83
84 nva.clear();
85
86 http2::add_header(nva, (const uint8_t *)"a", 1, (const uint8_t *)" b ", 5,
87 false, -1);
88 CU_ASSERT(Headers::value_type("a", "b") == nva[0]);
89
90 nva.clear();
91
92 http2::add_header(nva, (const uint8_t *)"a", 1, (const uint8_t *)" bravo ",
93 9, false, -1);
94 CU_ASSERT(Headers::value_type("a", "bravo") == nva[0]);
95
96 nva.clear();
97
98 http2::add_header(nva, (const uint8_t *)"a", 1, (const uint8_t *)" ", 4,
99 false, -1);
100 CU_ASSERT(Headers::value_type("a", "") == nva[0]);
101
102 nva.clear();
103
104 http2::add_header(nva, (const uint8_t *)"te", 2, (const uint8_t *)"trailers",
105 8, false, http2::HD_TE);
106 CU_ASSERT(http2::HD_TE == nva[0].token);
107 }
108
test_http2_get_header(void)109 void test_http2_get_header(void) {
110 auto nva = Headers{{"alpha", "1"}, {"bravo", "2"}, {"bravo", "3"},
111 {"charlie", "4"}, {"delta", "5"}, {"echo", "6"},
112 {"content-length", "7"}};
113 const Headers::value_type *rv;
114 rv = http2::get_header(nva, "delta");
115 CU_ASSERT(rv != nullptr);
116 CU_ASSERT("delta" == rv->name);
117
118 rv = http2::get_header(nva, "bravo");
119 CU_ASSERT(rv != nullptr);
120 CU_ASSERT("bravo" == rv->name);
121
122 rv = http2::get_header(nva, "foxtrot");
123 CU_ASSERT(rv == nullptr);
124
125 http2::HeaderIndex hdidx;
126 http2::init_hdidx(hdidx);
127 hdidx[http2::HD_CONTENT_LENGTH] = 6;
128 rv = http2::get_header(hdidx, http2::HD_CONTENT_LENGTH, nva);
129 CU_ASSERT("content-length" == rv->name);
130 }
131
132 namespace {
133 auto headers = HeaderRefs{
134 {StringRef::from_lit("alpha"), StringRef::from_lit("0"), true},
135 {StringRef::from_lit("bravo"), StringRef::from_lit("1")},
136 {StringRef::from_lit("connection"), StringRef::from_lit("2"), false,
137 http2::HD_CONNECTION},
138 {StringRef::from_lit("connection"), StringRef::from_lit("3"), false,
139 http2::HD_CONNECTION},
140 {StringRef::from_lit("delta"), StringRef::from_lit("4")},
141 {StringRef::from_lit("expect"), StringRef::from_lit("5")},
142 {StringRef::from_lit("foxtrot"), StringRef::from_lit("6")},
143 {StringRef::from_lit("tango"), StringRef::from_lit("7")},
144 {StringRef::from_lit("te"), StringRef::from_lit("8"), false, http2::HD_TE},
145 {StringRef::from_lit("te"), StringRef::from_lit("9"), false, http2::HD_TE},
146 {StringRef::from_lit("x-forwarded-proto"), StringRef::from_lit("10"), false,
147 http2::HD_X_FORWARDED_FOR},
148 {StringRef::from_lit("x-forwarded-proto"), StringRef::from_lit("11"), false,
149 http2::HD_X_FORWARDED_FOR},
150 {StringRef::from_lit("zulu"), StringRef::from_lit("12")}};
151 } // namespace
152
153 namespace {
154 auto headers2 = HeaderRefs{
155 {StringRef::from_lit("x-forwarded-for"), StringRef::from_lit("xff1"), false,
156 http2::HD_X_FORWARDED_FOR},
157 {StringRef::from_lit("x-forwarded-for"), StringRef::from_lit("xff2"), false,
158 http2::HD_X_FORWARDED_FOR},
159 {StringRef::from_lit("x-forwarded-proto"), StringRef::from_lit("xfp1"),
160 false, http2::HD_X_FORWARDED_PROTO},
161 {StringRef::from_lit("x-forwarded-proto"), StringRef::from_lit("xfp2"),
162 false, http2::HD_X_FORWARDED_PROTO},
163 {StringRef::from_lit("forwarded"), StringRef::from_lit("fwd1"), false,
164 http2::HD_FORWARDED},
165 {StringRef::from_lit("forwarded"), StringRef::from_lit("fwd2"), false,
166 http2::HD_FORWARDED},
167 {StringRef::from_lit("via"), StringRef::from_lit("via1"), false,
168 http2::HD_VIA},
169 {StringRef::from_lit("via"), StringRef::from_lit("via2"), false,
170 http2::HD_VIA},
171 };
172 } // namespace
173
test_http2_copy_headers_to_nva(void)174 void test_http2_copy_headers_to_nva(void) {
175 auto ans = std::vector<int>{0, 1, 4, 5, 6, 7, 12};
176 std::vector<nghttp2_nv> nva;
177
178 http2::copy_headers_to_nva_nocopy(nva, headers,
179 http2::HDOP_STRIP_X_FORWARDED_FOR);
180 CU_ASSERT(7 == nva.size());
181 for (size_t i = 0; i < ans.size(); ++i) {
182 check_nv(headers[ans[i]], &nva[i]);
183
184 if (ans[i] == 0) {
185 CU_ASSERT((NGHTTP2_NV_FLAG_NO_COPY_NAME | NGHTTP2_NV_FLAG_NO_COPY_VALUE |
186 NGHTTP2_NV_FLAG_NO_INDEX) == nva[i].flags);
187 } else {
188 CU_ASSERT((NGHTTP2_NV_FLAG_NO_COPY_NAME |
189 NGHTTP2_NV_FLAG_NO_COPY_VALUE) == nva[i].flags);
190 }
191 }
192
193 nva.clear();
194 http2::copy_headers_to_nva(nva, headers, http2::HDOP_STRIP_X_FORWARDED_FOR);
195 CU_ASSERT(7 == nva.size());
196 for (size_t i = 0; i < ans.size(); ++i) {
197 check_nv(headers[ans[i]], &nva[i]);
198
199 if (ans[i] == 0) {
200 CU_ASSERT(nva[i].flags & NGHTTP2_NV_FLAG_NO_INDEX);
201 } else {
202 CU_ASSERT(NGHTTP2_NV_FLAG_NONE == nva[i].flags);
203 }
204 }
205
206 nva.clear();
207
208 auto ans2 = std::vector<int>{0, 2, 4, 6};
209 http2::copy_headers_to_nva(nva, headers2, http2::HDOP_NONE);
210 CU_ASSERT(ans2.size() == nva.size());
211 for (size_t i = 0; i < ans2.size(); ++i) {
212 check_nv(headers2[ans2[i]], &nva[i]);
213 }
214
215 nva.clear();
216
217 http2::copy_headers_to_nva(nva, headers2, http2::HDOP_STRIP_ALL);
218 CU_ASSERT(nva.empty());
219 }
220
test_http2_build_http1_headers_from_headers(void)221 void test_http2_build_http1_headers_from_headers(void) {
222 MemchunkPool pool;
223 DefaultMemchunks buf(&pool);
224 http2::build_http1_headers_from_headers(&buf, headers,
225 http2::HDOP_STRIP_X_FORWARDED_FOR);
226 auto hdrs = std::string(buf.head->pos, buf.head->last);
227 CU_ASSERT("Alpha: 0\r\n"
228 "Bravo: 1\r\n"
229 "Delta: 4\r\n"
230 "Expect: 5\r\n"
231 "Foxtrot: 6\r\n"
232 "Tango: 7\r\n"
233 "Te: 8\r\n"
234 "Te: 9\r\n"
235 "Zulu: 12\r\n" == hdrs);
236
237 buf.reset();
238
239 http2::build_http1_headers_from_headers(&buf, headers2, http2::HDOP_NONE);
240 hdrs = std::string(buf.head->pos, buf.head->last);
241 CU_ASSERT("X-Forwarded-For: xff1\r\n"
242 "X-Forwarded-Proto: xfp1\r\n"
243 "Forwarded: fwd1\r\n"
244 "Via: via1\r\n" == hdrs);
245
246 buf.reset();
247
248 http2::build_http1_headers_from_headers(&buf, headers2,
249 http2::HDOP_STRIP_ALL);
250 CU_ASSERT(0 == buf.rleft());
251 }
252
test_http2_lws(void)253 void test_http2_lws(void) {
254 CU_ASSERT(!http2::lws("alpha"));
255 CU_ASSERT(http2::lws(" "));
256 CU_ASSERT(http2::lws(""));
257 }
258
259 namespace {
check_rewrite_location_uri(const std::string & want,const std::string & uri,const std::string & match_host,const std::string & req_authority,const std::string & upstream_scheme)260 void check_rewrite_location_uri(const std::string &want, const std::string &uri,
261 const std::string &match_host,
262 const std::string &req_authority,
263 const std::string &upstream_scheme) {
264 BlockAllocator balloc(4096, 4096);
265 http_parser_url u{};
266 CU_ASSERT(0 == http_parser_parse_url(uri.c_str(), uri.size(), 0, &u));
267 auto got = http2::rewrite_location_uri(
268 balloc, StringRef{uri}, u, StringRef{match_host},
269 StringRef{req_authority}, StringRef{upstream_scheme});
270 CU_ASSERT(want == got);
271 }
272 } // namespace
273
test_http2_rewrite_location_uri(void)274 void test_http2_rewrite_location_uri(void) {
275 check_rewrite_location_uri("https://localhost:3000/alpha?bravo#charlie",
276 "http://localhost:3001/alpha?bravo#charlie",
277 "localhost:3001", "localhost:3000", "https");
278 check_rewrite_location_uri("https://localhost/", "http://localhost:3001/",
279 "localhost", "localhost", "https");
280 check_rewrite_location_uri("http://localhost/", "http://localhost:3001/",
281 "localhost", "localhost", "http");
282 check_rewrite_location_uri("http://localhost:443/", "http://localhost:3001/",
283 "localhost", "localhost:443", "http");
284 check_rewrite_location_uri("https://localhost:80/", "http://localhost:3001/",
285 "localhost", "localhost:80", "https");
286 check_rewrite_location_uri("", "http://localhost:3001/", "127.0.0.1",
287 "127.0.0.1", "https");
288 check_rewrite_location_uri("https://localhost:3000/",
289 "http://localhost:3001/", "localhost",
290 "localhost:3000", "https");
291 check_rewrite_location_uri("https://localhost:3000/", "http://localhost/",
292 "localhost", "localhost:3000", "https");
293
294 // match_host != req_authority
295 check_rewrite_location_uri("https://example.org", "http://127.0.0.1:8080",
296 "127.0.0.1", "example.org", "https");
297 check_rewrite_location_uri("", "http://example.org", "127.0.0.1",
298 "example.org", "https");
299 }
300
test_http2_parse_http_status_code(void)301 void test_http2_parse_http_status_code(void) {
302 CU_ASSERT(200 == http2::parse_http_status_code(StringRef::from_lit("200")));
303 CU_ASSERT(102 == http2::parse_http_status_code(StringRef::from_lit("102")));
304 CU_ASSERT(-1 == http2::parse_http_status_code(StringRef::from_lit("099")));
305 CU_ASSERT(-1 == http2::parse_http_status_code(StringRef::from_lit("99")));
306 CU_ASSERT(-1 == http2::parse_http_status_code(StringRef::from_lit("-1")));
307 CU_ASSERT(-1 == http2::parse_http_status_code(StringRef::from_lit("20a")));
308 CU_ASSERT(-1 == http2::parse_http_status_code(StringRef{}));
309 }
310
test_http2_index_header(void)311 void test_http2_index_header(void) {
312 http2::HeaderIndex hdidx;
313 http2::init_hdidx(hdidx);
314
315 http2::index_header(hdidx, http2::HD__AUTHORITY, 0);
316 http2::index_header(hdidx, -1, 1);
317
318 CU_ASSERT(0 == hdidx[http2::HD__AUTHORITY]);
319 }
320
test_http2_lookup_token(void)321 void test_http2_lookup_token(void) {
322 CU_ASSERT(http2::HD__AUTHORITY ==
323 http2::lookup_token(StringRef::from_lit(":authority")));
324 CU_ASSERT(-1 == http2::lookup_token(StringRef::from_lit(":authorit")));
325 CU_ASSERT(-1 == http2::lookup_token(StringRef::from_lit(":Authority")));
326 CU_ASSERT(http2::HD_EXPECT ==
327 http2::lookup_token(StringRef::from_lit("expect")));
328 }
329
test_http2_parse_link_header(void)330 void test_http2_parse_link_header(void) {
331 {
332 // only URI appears; we don't extract URI unless it bears rel=preload
333 auto res = http2::parse_link_header(StringRef::from_lit("<url>"));
334 CU_ASSERT(0 == res.size());
335 }
336 {
337 // URI url should be extracted
338 auto res =
339 http2::parse_link_header(StringRef::from_lit("<url>; rel=preload"));
340 CU_ASSERT(1 == res.size());
341 CU_ASSERT("url" == res[0].uri);
342 }
343 {
344 // With extra link-param. URI url should be extracted
345 auto res = http2::parse_link_header(
346 StringRef::from_lit("<url>; rel=preload; as=file"));
347 CU_ASSERT(1 == res.size());
348 CU_ASSERT("url" == res[0].uri);
349 }
350 {
351 // With extra link-param. URI url should be extracted
352 auto res = http2::parse_link_header(
353 StringRef::from_lit("<url>; as=file; rel=preload"));
354 CU_ASSERT(1 == res.size());
355 CU_ASSERT("url" == res[0].uri);
356 }
357 {
358 // With extra link-param and quote-string. URI url should be
359 // extracted
360 auto res = http2::parse_link_header(
361 StringRef::from_lit(R"(<url>; rel=preload; title="foo,bar")"));
362 CU_ASSERT(1 == res.size());
363 CU_ASSERT("url" == res[0].uri);
364 }
365 {
366 // With extra link-param and quote-string. URI url should be
367 // extracted
368 auto res = http2::parse_link_header(
369 StringRef::from_lit(R"(<url>; title="foo,bar"; rel=preload)"));
370 CU_ASSERT(1 == res.size());
371 CU_ASSERT("url" == res[0].uri);
372 }
373 {
374 // ',' after quote-string
375 auto res = http2::parse_link_header(
376 StringRef::from_lit(R"(<url>; title="foo,bar", <url2>; rel=preload)"));
377 CU_ASSERT(1 == res.size());
378 CU_ASSERT("url2" == res[0].uri);
379 }
380 {
381 // Only first URI should be extracted.
382 auto res = http2::parse_link_header(
383 StringRef::from_lit("<url>; rel=preload, <url2>"));
384 CU_ASSERT(1 == res.size());
385 CU_ASSERT("url" == res[0].uri);
386 }
387 {
388 // Both have rel=preload, so both urls should be extracted
389 auto res = http2::parse_link_header(
390 StringRef::from_lit("<url>; rel=preload, <url2>; rel=preload"));
391 CU_ASSERT(2 == res.size());
392 CU_ASSERT("url" == res[0].uri);
393 CU_ASSERT("url2" == res[1].uri);
394 }
395 {
396 // Second URI uri should be extracted.
397 auto res = http2::parse_link_header(
398 StringRef::from_lit("<url>, <url2>;rel=preload"));
399 CU_ASSERT(1 == res.size());
400 CU_ASSERT("url2" == res[0].uri);
401 }
402 {
403 // Error if input ends with ';'
404 auto res =
405 http2::parse_link_header(StringRef::from_lit("<url>;rel=preload;"));
406 CU_ASSERT(0 == res.size());
407 }
408 {
409 // Error if link header ends with ';'
410 auto res = http2::parse_link_header(
411 StringRef::from_lit("<url>;rel=preload;, <url>"));
412 CU_ASSERT(0 == res.size());
413 }
414 {
415 // OK if input ends with ','
416 auto res =
417 http2::parse_link_header(StringRef::from_lit("<url>;rel=preload,"));
418 CU_ASSERT(1 == res.size());
419 CU_ASSERT("url" == res[0].uri);
420 }
421 {
422 // Multiple repeated ','s between fields is OK
423 auto res = http2::parse_link_header(
424 StringRef::from_lit("<url>,,,<url2>;rel=preload"));
425 CU_ASSERT(1 == res.size());
426 CU_ASSERT("url2" == res[0].uri);
427 }
428 {
429 // Error if url is not enclosed by <>
430 auto res =
431 http2::parse_link_header(StringRef::from_lit("url>;rel=preload"));
432 CU_ASSERT(0 == res.size());
433 }
434 {
435 // Error if url is not enclosed by <>
436 auto res =
437 http2::parse_link_header(StringRef::from_lit("<url;rel=preload"));
438 CU_ASSERT(0 == res.size());
439 }
440 {
441 // Empty parameter value is not allowed
442 auto res =
443 http2::parse_link_header(StringRef::from_lit("<url>;rel=preload; as="));
444 CU_ASSERT(0 == res.size());
445 }
446 {
447 // Empty parameter value is not allowed
448 auto res =
449 http2::parse_link_header(StringRef::from_lit("<url>;as=;rel=preload"));
450 CU_ASSERT(0 == res.size());
451 }
452 {
453 // Empty parameter value is not allowed
454 auto res = http2::parse_link_header(
455 StringRef::from_lit("<url>;as=, <url>;rel=preload"));
456 CU_ASSERT(0 == res.size());
457 }
458 {
459 // Empty parameter name is not allowed
460 auto res = http2::parse_link_header(
461 StringRef::from_lit("<url>; =file; rel=preload"));
462 CU_ASSERT(0 == res.size());
463 }
464 {
465 // Without whitespaces
466 auto res = http2::parse_link_header(
467 StringRef::from_lit("<url>;as=file;rel=preload,<url2>;rel=preload"));
468 CU_ASSERT(2 == res.size());
469 CU_ASSERT("url" == res[0].uri);
470 CU_ASSERT("url2" == res[1].uri);
471 }
472 {
473 // link-extension may have no value
474 auto res =
475 http2::parse_link_header(StringRef::from_lit("<url>; as; rel=preload"));
476 CU_ASSERT(1 == res.size());
477 CU_ASSERT("url" == res[0].uri);
478 }
479 {
480 // ext-name-star
481 auto res = http2::parse_link_header(
482 StringRef::from_lit("<url>; foo*=bar; rel=preload"));
483 CU_ASSERT(1 == res.size());
484 CU_ASSERT("url" == res[0].uri);
485 }
486 {
487 // '*' is not allowed expect for trailing one
488 auto res = http2::parse_link_header(
489 StringRef::from_lit("<url>; *=bar; rel=preload"));
490 CU_ASSERT(0 == res.size());
491 }
492 {
493 // '*' is not allowed expect for trailing one
494 auto res = http2::parse_link_header(
495 StringRef::from_lit("<url>; foo*bar=buzz; rel=preload"));
496 CU_ASSERT(0 == res.size());
497 }
498 {
499 // ext-name-star must be followed by '='
500 auto res = http2::parse_link_header(
501 StringRef::from_lit("<url>; foo*; rel=preload"));
502 CU_ASSERT(0 == res.size());
503 }
504 {
505 // '>' is not followed by ';'
506 auto res =
507 http2::parse_link_header(StringRef::from_lit("<url> rel=preload"));
508 CU_ASSERT(0 == res.size());
509 }
510 {
511 // Starting with whitespace is no problem.
512 auto res =
513 http2::parse_link_header(StringRef::from_lit(" <url>; rel=preload"));
514 CU_ASSERT(1 == res.size());
515 CU_ASSERT("url" == res[0].uri);
516 }
517 {
518 // preload is a prefix of bogus rel parameter value
519 auto res =
520 http2::parse_link_header(StringRef::from_lit("<url>; rel=preloadx"));
521 CU_ASSERT(0 == res.size());
522 }
523 {
524 // preload in relation-types list
525 auto res = http2::parse_link_header(
526 StringRef::from_lit(R"(<url>; rel="preload")"));
527 CU_ASSERT(1 == res.size());
528 CU_ASSERT("url" == res[0].uri);
529 }
530 {
531 // preload in relation-types list followed by another parameter
532 auto res = http2::parse_link_header(
533 StringRef::from_lit(R"(<url>; rel="preload foo")"));
534 CU_ASSERT(1 == res.size());
535 CU_ASSERT("url" == res[0].uri);
536 }
537 {
538 // preload in relation-types list following another parameter
539 auto res = http2::parse_link_header(
540 StringRef::from_lit(R"(<url>; rel="foo preload")"));
541 CU_ASSERT(1 == res.size());
542 CU_ASSERT("url" == res[0].uri);
543 }
544 {
545 // preload in relation-types list between other parameters
546 auto res = http2::parse_link_header(
547 StringRef::from_lit(R"(<url>; rel="foo preload bar")"));
548 CU_ASSERT(1 == res.size());
549 CU_ASSERT("url" == res[0].uri);
550 }
551 {
552 // preload in relation-types list between other parameters
553 auto res = http2::parse_link_header(
554 StringRef::from_lit(R"(<url>; rel="foo preload bar")"));
555 CU_ASSERT(1 == res.size());
556 CU_ASSERT("url" == res[0].uri);
557 }
558 {
559 // no preload in relation-types list
560 auto res =
561 http2::parse_link_header(StringRef::from_lit(R"(<url>; rel="foo")"));
562 CU_ASSERT(0 == res.size());
563 }
564 {
565 // no preload in relation-types list, multiple unrelated elements.
566 auto res = http2::parse_link_header(
567 StringRef::from_lit(R"(<url>; rel="foo bar")"));
568 CU_ASSERT(0 == res.size());
569 }
570 {
571 // preload in relation-types list, followed by another link-value.
572 auto res = http2::parse_link_header(
573 StringRef::from_lit(R"(<url>; rel="preload", <url2>)"));
574 CU_ASSERT(1 == res.size());
575 CU_ASSERT("url" == res[0].uri);
576 }
577 {
578 // preload in relation-types list, following another link-value.
579 auto res = http2::parse_link_header(
580 StringRef::from_lit(R"(<url>, <url2>; rel="preload")"));
581 CU_ASSERT(1 == res.size());
582 CU_ASSERT("url2" == res[0].uri);
583 }
584 {
585 // preload in relation-types list, followed by another link-param.
586 auto res = http2::parse_link_header(
587 StringRef::from_lit(R"(<url>; rel="preload"; as="font")"));
588 CU_ASSERT(1 == res.size());
589 CU_ASSERT("url" == res[0].uri);
590 }
591 {
592 // preload in relation-types list, followed by character other
593 // than ';' or ','
594 auto res = http2::parse_link_header(
595 StringRef::from_lit(R"(<url>; rel="preload".)"));
596 CU_ASSERT(0 == res.size());
597 }
598 {
599 // preload in relation-types list, followed by ';' but it
600 // terminates input
601 auto res = http2::parse_link_header(
602 StringRef::from_lit(R"(<url>; rel="preload";)"));
603 CU_ASSERT(0 == res.size());
604 }
605 {
606 // preload in relation-types list, followed by ',' but it
607 // terminates input
608 auto res = http2::parse_link_header(
609 StringRef::from_lit(R"(<url>; rel="preload",)"));
610 CU_ASSERT(1 == res.size());
611 CU_ASSERT("url" == res[0].uri);
612 }
613 {
614 // preload in relation-types list but there is preceding white
615 // space.
616 auto res = http2::parse_link_header(
617 StringRef::from_lit(R"(<url>; rel=" preload")"));
618 CU_ASSERT(0 == res.size());
619 }
620 {
621 // preload in relation-types list but there is trailing white
622 // space.
623 auto res = http2::parse_link_header(
624 StringRef::from_lit(R"(<url>; rel="preload ")"));
625 CU_ASSERT(0 == res.size());
626 }
627 {
628 // backslash escaped characters in quoted-string
629 auto res = http2::parse_link_header(
630 StringRef::from_lit(R"(<url>; rel=preload; title="foo\"baz\"bar")"));
631 CU_ASSERT(1 == res.size());
632 CU_ASSERT("url" == res[0].uri);
633 }
634 {
635 // anchor="" is acceptable
636 auto res = http2::parse_link_header(
637 StringRef::from_lit(R"(<url>; rel=preload; anchor="")"));
638 CU_ASSERT(1 == res.size());
639 CU_ASSERT("url" == res[0].uri);
640 }
641 {
642 // With anchor="#foo", url should be ignored
643 auto res = http2::parse_link_header(
644 StringRef::from_lit(R"(<url>; rel=preload; anchor="#foo")"));
645 CU_ASSERT(0 == res.size());
646 }
647 {
648 // With anchor=f, url should be ignored
649 auto res = http2::parse_link_header(
650 StringRef::from_lit("<url>; rel=preload; anchor=f"));
651 CU_ASSERT(0 == res.size());
652 }
653 {
654 // First url is ignored With anchor="#foo", but url should be
655 // accepted.
656 auto res = http2::parse_link_header(StringRef::from_lit(
657 R"(<url>; rel=preload; anchor="#foo", <url2>; rel=preload)"));
658 CU_ASSERT(1 == res.size());
659 CU_ASSERT("url2" == res[0].uri);
660 }
661 {
662 // With loadpolicy="next", url should be ignored
663 auto res = http2::parse_link_header(
664 StringRef::from_lit(R"(<url>; rel=preload; loadpolicy="next")"));
665 CU_ASSERT(0 == res.size());
666 }
667 {
668 // url should be picked up if empty loadpolicy is specified
669 auto res = http2::parse_link_header(
670 StringRef::from_lit(R"(<url>; rel=preload; loadpolicy="")"));
671 CU_ASSERT(1 == res.size());
672 CU_ASSERT("url" == res[0].uri);
673 }
674 {
675 // case-insensitive match
676 auto res = http2::parse_link_header(
677 StringRef::from_lit(R"(<url>; rel=preload; ANCHOR="#foo", <url2>; )"
678 R"(REL=PRELOAD, <url3>; REL="foo PRELOAD bar")"));
679 CU_ASSERT(2 == res.size());
680 CU_ASSERT("url2" == res[0].uri);
681 CU_ASSERT("url3" == res[1].uri);
682 }
683 {
684 // nopush at the end of input
685 auto res = http2::parse_link_header(
686 StringRef::from_lit("<url>; rel=preload; nopush"));
687 CU_ASSERT(0 == res.size());
688 }
689 {
690 // nopush followed by ';'
691 auto res = http2::parse_link_header(
692 StringRef::from_lit("<url>; rel=preload; nopush; foo"));
693 CU_ASSERT(0 == res.size());
694 }
695 {
696 // nopush followed by ','
697 auto res = http2::parse_link_header(
698 StringRef::from_lit("<url>; nopush; rel=preload"));
699 CU_ASSERT(0 == res.size());
700 }
701 {
702 // string whose prefix is nopush
703 auto res = http2::parse_link_header(
704 StringRef::from_lit("<url>; nopushyes; rel=preload"));
705 CU_ASSERT(1 == res.size());
706 CU_ASSERT("url" == res[0].uri);
707 }
708 {
709 // rel=preload twice
710 auto res = http2::parse_link_header(
711 StringRef::from_lit("<url>; rel=preload; rel=preload"));
712 CU_ASSERT(1 == res.size());
713 CU_ASSERT("url" == res[0].uri);
714 }
715 }
716
717 void test_http2_path_join(void) {
718 {
719 auto base = StringRef::from_lit("/");
720 auto rel = StringRef::from_lit("/");
721 CU_ASSERT("/" == http2::path_join(base, StringRef{}, rel, StringRef{}));
722 }
723 {
724 auto base = StringRef::from_lit("/");
725 auto rel = StringRef::from_lit("/alpha");
726 CU_ASSERT("/alpha" ==
727 http2::path_join(base, StringRef{}, rel, StringRef{}));
728 }
729 {
730 // rel ends with trailing '/'
731 auto base = StringRef::from_lit("/");
732 auto rel = StringRef::from_lit("/alpha/");
733 CU_ASSERT("/alpha/" ==
734 http2::path_join(base, StringRef{}, rel, StringRef{}));
735 }
736 {
737 // rel contains multiple components
738 auto base = StringRef::from_lit("/");
739 auto rel = StringRef::from_lit("/alpha/bravo");
740 CU_ASSERT("/alpha/bravo" ==
741 http2::path_join(base, StringRef{}, rel, StringRef{}));
742 }
743 {
744 // rel is relative
745 auto base = StringRef::from_lit("/");
746 auto rel = StringRef::from_lit("alpha/bravo");
747 CU_ASSERT("/alpha/bravo" ==
748 http2::path_join(base, StringRef{}, rel, StringRef{}));
749 }
750 {
751 // rel is relative and base ends without /, which means it refers
752 // to file.
753 auto base = StringRef::from_lit("/alpha");
754 auto rel = StringRef::from_lit("bravo/charlie");
755 CU_ASSERT("/bravo/charlie" ==
756 http2::path_join(base, StringRef{}, rel, StringRef{}));
757 }
758 {
759 // rel contains repeated '/'s
760 auto base = StringRef::from_lit("/");
761 auto rel = StringRef::from_lit("/alpha/////bravo/////");
762 CU_ASSERT("/alpha/bravo/" ==
763 http2::path_join(base, StringRef{}, rel, StringRef{}));
764 }
765 {
766 // base ends with '/', so '..' eats 'bravo'
767 auto base = StringRef::from_lit("/alpha/bravo/");
768 auto rel = StringRef::from_lit("../charlie/delta");
769 CU_ASSERT("/alpha/charlie/delta" ==
770 http2::path_join(base, StringRef{}, rel, StringRef{}));
771 }
772 {
773 // base does not end with '/', so '..' eats 'alpha/bravo'
774 auto base = StringRef::from_lit("/alpha/bravo");
775 auto rel = StringRef::from_lit("../charlie");
776 CU_ASSERT("/charlie" ==
777 http2::path_join(base, StringRef{}, rel, StringRef{}));
778 }
779 {
780 // 'charlie' is eaten by following '..'
781 auto base = StringRef::from_lit("/alpha/bravo/");
782 auto rel = StringRef::from_lit("../charlie/../delta");
783 CU_ASSERT("/alpha/delta" ==
784 http2::path_join(base, StringRef{}, rel, StringRef{}));
785 }
786 {
787 // excessive '..' results in '/'
788 auto base = StringRef::from_lit("/alpha/bravo/");
789 auto rel = StringRef::from_lit("../../../");
790 CU_ASSERT("/" == http2::path_join(base, StringRef{}, rel, StringRef{}));
791 }
792 {
793 // excessive '..' and path component
794 auto base = StringRef::from_lit("/alpha/bravo/");
795 auto rel = StringRef::from_lit("../../../charlie");
796 CU_ASSERT("/charlie" ==
797 http2::path_join(base, StringRef{}, rel, StringRef{}));
798 }
799 {
800 // rel ends with '..'
801 auto base = StringRef::from_lit("/alpha/bravo/");
802 auto rel = StringRef::from_lit("charlie/..");
803 CU_ASSERT("/alpha/bravo/" ==
804 http2::path_join(base, StringRef{}, rel, StringRef{}));
805 }
806 {
807 // base empty and rel contains '..'
808 auto base = StringRef{};
809 auto rel = StringRef::from_lit("charlie/..");
810 CU_ASSERT("/" == http2::path_join(base, StringRef{}, rel, StringRef{}));
811 }
812 {
813 // '.' is ignored
814 auto base = StringRef::from_lit("/");
815 auto rel = StringRef::from_lit("charlie/././././delta");
816 CU_ASSERT("/charlie/delta" ==
817 http2::path_join(base, StringRef{}, rel, StringRef{}));
818 }
819 {
820 // trailing '.' is ignored
821 auto base = StringRef::from_lit("/");
822 auto rel = StringRef::from_lit("charlie/.");
823 CU_ASSERT("/charlie/" ==
824 http2::path_join(base, StringRef{}, rel, StringRef{}));
825 }
826 {
827 // query
828 auto base = StringRef::from_lit("/");
829 auto rel = StringRef::from_lit("/");
830 auto relq = StringRef::from_lit("q");
831 CU_ASSERT("/?q" == http2::path_join(base, StringRef{}, rel, relq));
832 }
833 {
834 // empty rel and query
835 auto base = StringRef::from_lit("/alpha");
836 auto rel = StringRef{};
837 auto relq = StringRef::from_lit("q");
838 CU_ASSERT("/alpha?q" == http2::path_join(base, StringRef{}, rel, relq));
839 }
840 {
841 // both rel and query are empty
842 auto base = StringRef::from_lit("/alpha");
843 auto baseq = StringRef::from_lit("r");
844 auto rel = StringRef{};
845 auto relq = StringRef{};
846 CU_ASSERT("/alpha?r" == http2::path_join(base, baseq, rel, relq));
847 }
848 {
849 // empty base
850 auto base = StringRef{};
851 auto rel = StringRef::from_lit("/alpha");
852 CU_ASSERT("/alpha" ==
853 http2::path_join(base, StringRef{}, rel, StringRef{}));
854 }
855 {
856 // everything is empty
857 CU_ASSERT("/" == http2::path_join(StringRef{}, StringRef{}, StringRef{},
858 StringRef{}));
859 }
860 {
861 // only baseq is not empty
862 auto base = StringRef{};
863 auto baseq = StringRef::from_lit("r");
864 auto rel = StringRef{};
865 CU_ASSERT("/?r" == http2::path_join(base, baseq, rel, StringRef{}));
866 }
867 {
868 // path starts with multiple '/'s.
869 auto base = StringRef{};
870 auto baseq = StringRef{};
871 auto rel = StringRef::from_lit("//alpha//bravo");
872 auto relq = StringRef::from_lit("charlie");
873 CU_ASSERT("/alpha/bravo?charlie" ==
874 http2::path_join(base, baseq, rel, relq));
875 }
876 // Test cases from RFC 3986, section 5.4.
877 constexpr auto base = StringRef::from_lit("/b/c/d;p");
878 constexpr auto baseq = StringRef::from_lit("q");
879 {
880 auto rel = StringRef::from_lit("g");
881 auto relq = StringRef{};
882 CU_ASSERT("/b/c/g" == http2::path_join(base, baseq, rel, relq));
883 }
884 {
885 auto rel = StringRef::from_lit("./g");
886 auto relq = StringRef{};
887 CU_ASSERT("/b/c/g" == http2::path_join(base, baseq, rel, relq));
888 }
889 {
890 auto rel = StringRef::from_lit("g/");
891 auto relq = StringRef{};
892 CU_ASSERT("/b/c/g/" == http2::path_join(base, baseq, rel, relq));
893 }
894 {
895 auto rel = StringRef::from_lit("/g");
896 auto relq = StringRef{};
897 CU_ASSERT("/g" == http2::path_join(base, baseq, rel, relq));
898 }
899 {
900 auto rel = StringRef{};
901 auto relq = StringRef::from_lit("y");
902 CU_ASSERT("/b/c/d;p?y" == http2::path_join(base, baseq, rel, relq));
903 }
904 {
905 auto rel = StringRef::from_lit("g");
906 auto relq = StringRef::from_lit("y");
907 CU_ASSERT("/b/c/g?y" == http2::path_join(base, baseq, rel, relq));
908 }
909 {
910 auto rel = StringRef::from_lit(";x");
911 auto relq = StringRef{};
912 CU_ASSERT("/b/c/;x" == http2::path_join(base, baseq, rel, relq));
913 }
914 {
915 auto rel = StringRef::from_lit("g;x");
916 auto relq = StringRef{};
917 CU_ASSERT("/b/c/g;x" == http2::path_join(base, baseq, rel, relq));
918 }
919 {
920 auto rel = StringRef::from_lit("g;x");
921 auto relq = StringRef::from_lit("y");
922 CU_ASSERT("/b/c/g;x?y" == http2::path_join(base, baseq, rel, relq));
923 }
924 {
925 auto rel = StringRef{};
926 auto relq = StringRef{};
927 CU_ASSERT("/b/c/d;p?q" == http2::path_join(base, baseq, rel, relq));
928 }
929 {
930 auto rel = StringRef::from_lit(".");
931 auto relq = StringRef{};
932 CU_ASSERT("/b/c/" == http2::path_join(base, baseq, rel, relq));
933 }
934 {
935 auto rel = StringRef::from_lit("./");
936 auto relq = StringRef{};
937 CU_ASSERT("/b/c/" == http2::path_join(base, baseq, rel, relq));
938 }
939 {
940 auto rel = StringRef::from_lit("..");
941 auto relq = StringRef{};
942 CU_ASSERT("/b/" == http2::path_join(base, baseq, rel, relq));
943 }
944 {
945 auto rel = StringRef::from_lit("../");
946 auto relq = StringRef{};
947 CU_ASSERT("/b/" == http2::path_join(base, baseq, rel, relq));
948 }
949 {
950 auto rel = StringRef::from_lit("../g");
951 auto relq = StringRef{};
952 CU_ASSERT("/b/g" == http2::path_join(base, baseq, rel, relq));
953 }
954 {
955 auto rel = StringRef::from_lit("../..");
956 auto relq = StringRef{};
957 CU_ASSERT("/" == http2::path_join(base, baseq, rel, relq));
958 }
959 {
960 auto rel = StringRef::from_lit("../../");
961 auto relq = StringRef{};
962 CU_ASSERT("/" == http2::path_join(base, baseq, rel, relq));
963 }
964 {
965 auto rel = StringRef::from_lit("../../g");
966 auto relq = StringRef{};
967 CU_ASSERT("/g" == http2::path_join(base, baseq, rel, relq));
968 }
969 {
970 auto rel = StringRef::from_lit("../../../g");
971 auto relq = StringRef{};
972 CU_ASSERT("/g" == http2::path_join(base, baseq, rel, relq));
973 }
974 {
975 auto rel = StringRef::from_lit("../../../../g");
976 auto relq = StringRef{};
977 CU_ASSERT("/g" == http2::path_join(base, baseq, rel, relq));
978 }
979 {
980 auto rel = StringRef::from_lit("/./g");
981 auto relq = StringRef{};
982 CU_ASSERT("/g" == http2::path_join(base, baseq, rel, relq));
983 }
984 {
985 auto rel = StringRef::from_lit("/../g");
986 auto relq = StringRef{};
987 CU_ASSERT("/g" == http2::path_join(base, baseq, rel, relq));
988 }
989 {
990 auto rel = StringRef::from_lit("g.");
991 auto relq = StringRef{};
992 CU_ASSERT("/b/c/g." == http2::path_join(base, baseq, rel, relq));
993 }
994 {
995 auto rel = StringRef::from_lit(".g");
996 auto relq = StringRef{};
997 CU_ASSERT("/b/c/.g" == http2::path_join(base, baseq, rel, relq));
998 }
999 {
1000 auto rel = StringRef::from_lit("g..");
1001 auto relq = StringRef{};
1002 CU_ASSERT("/b/c/g.." == http2::path_join(base, baseq, rel, relq));
1003 }
1004 {
1005 auto rel = StringRef::from_lit("..g");
1006 auto relq = StringRef{};
1007 CU_ASSERT("/b/c/..g" == http2::path_join(base, baseq, rel, relq));
1008 }
1009 {
1010 auto rel = StringRef::from_lit("./../g");
1011 auto relq = StringRef{};
1012 CU_ASSERT("/b/g" == http2::path_join(base, baseq, rel, relq));
1013 }
1014 {
1015 auto rel = StringRef::from_lit("./g/.");
1016 auto relq = StringRef{};
1017 CU_ASSERT("/b/c/g/" == http2::path_join(base, baseq, rel, relq));
1018 }
1019 {
1020 auto rel = StringRef::from_lit("g/./h");
1021 auto relq = StringRef{};
1022 CU_ASSERT("/b/c/g/h" == http2::path_join(base, baseq, rel, relq));
1023 }
1024 {
1025 auto rel = StringRef::from_lit("g/../h");
1026 auto relq = StringRef{};
1027 CU_ASSERT("/b/c/h" == http2::path_join(base, baseq, rel, relq));
1028 }
1029 {
1030 auto rel = StringRef::from_lit("g;x=1/./y");
1031 auto relq = StringRef{};
1032 CU_ASSERT("/b/c/g;x=1/y" == http2::path_join(base, baseq, rel, relq));
1033 }
1034 {
1035 auto rel = StringRef::from_lit("g;x=1/../y");
1036 auto relq = StringRef{};
1037 CU_ASSERT("/b/c/y" == http2::path_join(base, baseq, rel, relq));
1038 }
1039 }
1040
test_http2_normalize_path(void)1041 void test_http2_normalize_path(void) {
1042 CU_ASSERT("/alpha/charlie" ==
1043 http2::normalize_path(
1044 StringRef::from_lit("/alpha/bravo/../charlie"), StringRef{}));
1045
1046 CU_ASSERT("/alpha" ==
1047 http2::normalize_path(StringRef::from_lit("/a%6c%70%68%61"),
1048 StringRef{}));
1049
1050 CU_ASSERT(
1051 "/alpha%2F%3A" ==
1052 http2::normalize_path(StringRef::from_lit("/alpha%2f%3a"), StringRef{}));
1053
1054 CU_ASSERT("/%2F" ==
1055 http2::normalize_path(StringRef::from_lit("%2f"), StringRef{}));
1056
1057 CU_ASSERT("/%f" ==
1058 http2::normalize_path(StringRef::from_lit("%f"), StringRef{}));
1059
1060 CU_ASSERT("/%" ==
1061 http2::normalize_path(StringRef::from_lit("%"), StringRef{}));
1062
1063 CU_ASSERT("/" == http2::normalize_path(StringRef{}, StringRef{}));
1064
1065 CU_ASSERT("/alpha?bravo" ==
1066 http2::normalize_path(StringRef::from_lit("/alpha"),
1067 StringRef::from_lit("bravo")));
1068 }
1069
test_http2_rewrite_clean_path(void)1070 void test_http2_rewrite_clean_path(void) {
1071 BlockAllocator balloc(4096, 4096);
1072
1073 // unreserved characters
1074 CU_ASSERT("/alpha/bravo/" ==
1075 http2::rewrite_clean_path(balloc,
1076 StringRef::from_lit("/alpha/%62ravo/")));
1077
1078 // percent-encoding is converted to upper case.
1079 CU_ASSERT("/delta%3A" == http2::rewrite_clean_path(
1080 balloc, StringRef::from_lit("/delta%3a")));
1081
1082 // path component is normalized before matching
1083 CU_ASSERT(
1084 "/alpha/bravo/" ==
1085 http2::rewrite_clean_path(
1086 balloc, StringRef::from_lit("/alpha/charlie/%2e././bravo/delta/..")));
1087
1088 CU_ASSERT("alpha%3a" ==
1089 http2::rewrite_clean_path(balloc, StringRef::from_lit("alpha%3a")));
1090
1091 CU_ASSERT("" == http2::rewrite_clean_path(balloc, StringRef{}));
1092
1093 CU_ASSERT(
1094 "/alpha?bravo" ==
1095 http2::rewrite_clean_path(balloc, StringRef::from_lit("//alpha?bravo")));
1096 }
1097
test_http2_get_pure_path_component(void)1098 void test_http2_get_pure_path_component(void) {
1099 CU_ASSERT("/" == http2::get_pure_path_component(StringRef::from_lit("/")));
1100
1101 CU_ASSERT("/foo" ==
1102 http2::get_pure_path_component(StringRef::from_lit("/foo")));
1103
1104 CU_ASSERT("/bar" == http2::get_pure_path_component(
1105 StringRef::from_lit("https://example.org/bar")));
1106
1107 CU_ASSERT("/alpha" == http2::get_pure_path_component(StringRef::from_lit(
1108 "https://example.org/alpha?q=a")));
1109
1110 CU_ASSERT("/bravo" == http2::get_pure_path_component(StringRef::from_lit(
1111 "https://example.org/bravo?q=a#fragment")));
1112
1113 CU_ASSERT("" ==
1114 http2::get_pure_path_component(StringRef::from_lit("\x01\x02")));
1115 }
1116
test_http2_construct_push_component(void)1117 void test_http2_construct_push_component(void) {
1118 BlockAllocator balloc(4096, 4096);
1119 StringRef base, uri;
1120 StringRef scheme, authority, path;
1121
1122 base = StringRef::from_lit("/b/");
1123 uri = StringRef::from_lit("https://example.org/foo");
1124
1125 CU_ASSERT(0 == http2::construct_push_component(balloc, scheme, authority,
1126 path, base, uri));
1127 CU_ASSERT("https" == scheme);
1128 CU_ASSERT("example.org" == authority);
1129 CU_ASSERT("/foo" == path);
1130
1131 scheme = StringRef{};
1132 authority = StringRef{};
1133 path = StringRef{};
1134
1135 uri = StringRef::from_lit("/foo/bar?q=a");
1136
1137 CU_ASSERT(0 == http2::construct_push_component(balloc, scheme, authority,
1138 path, base, uri));
1139 CU_ASSERT("" == scheme);
1140 CU_ASSERT("" == authority);
1141 CU_ASSERT("/foo/bar?q=a" == path);
1142
1143 scheme = StringRef{};
1144 authority = StringRef{};
1145 path = StringRef{};
1146
1147 uri = StringRef::from_lit("foo/../bar?q=a");
1148
1149 CU_ASSERT(0 == http2::construct_push_component(balloc, scheme, authority,
1150 path, base, uri));
1151 CU_ASSERT("" == scheme);
1152 CU_ASSERT("" == authority);
1153 CU_ASSERT("/b/bar?q=a" == path);
1154
1155 scheme = StringRef{};
1156 authority = StringRef{};
1157 path = StringRef{};
1158
1159 uri = StringRef{};
1160
1161 CU_ASSERT(-1 == http2::construct_push_component(balloc, scheme, authority,
1162 path, base, uri));
1163 scheme = StringRef{};
1164 authority = StringRef{};
1165 path = StringRef{};
1166
1167 uri = StringRef::from_lit("?q=a");
1168
1169 CU_ASSERT(0 == http2::construct_push_component(balloc, scheme, authority,
1170 path, base, uri));
1171 CU_ASSERT("" == scheme);
1172 CU_ASSERT("" == authority);
1173 CU_ASSERT("/b/?q=a" == path);
1174 }
1175
test_http2_contains_trailers(void)1176 void test_http2_contains_trailers(void) {
1177 CU_ASSERT(!http2::contains_trailers(StringRef::from_lit("")));
1178 CU_ASSERT(http2::contains_trailers(StringRef::from_lit("trailers")));
1179 // Match must be case-insensitive.
1180 CU_ASSERT(http2::contains_trailers(StringRef::from_lit("TRAILERS")));
1181 CU_ASSERT(!http2::contains_trailers(StringRef::from_lit("trailer")));
1182 CU_ASSERT(!http2::contains_trailers(StringRef::from_lit("trailers 3")));
1183 CU_ASSERT(http2::contains_trailers(StringRef::from_lit("trailers,")));
1184 CU_ASSERT(http2::contains_trailers(StringRef::from_lit("trailers,foo")));
1185 CU_ASSERT(http2::contains_trailers(StringRef::from_lit("foo,trailers")));
1186 CU_ASSERT(http2::contains_trailers(StringRef::from_lit("foo,trailers,bar")));
1187 CU_ASSERT(
1188 http2::contains_trailers(StringRef::from_lit("foo, trailers ,bar")));
1189 CU_ASSERT(http2::contains_trailers(StringRef::from_lit(",trailers")));
1190 }
1191
1192 } // namespace shrpx
1193