xref: /third_party/nghttp2/src/http2_test.cc (revision 2c593315)
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
38using 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
46namespace shrpx {
47
48namespace {
49void 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
57void 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
109void 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
132namespace {
133auto 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
153namespace {
154auto 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
174void 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
221void 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
253void test_http2_lws(void) {
254  CU_ASSERT(!http2::lws("alpha"));
255  CU_ASSERT(http2::lws(" "));
256  CU_ASSERT(http2::lws(""));
257}
258
259namespace {
260void 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
274void 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
301void 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
311void 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
321void 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
330void 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
717void 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
1041void 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
1070void 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
1098void 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
1117void 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
1176void 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
1192void test_http2_check_transfer_encoding(void) {
1193  CU_ASSERT(http2::check_transfer_encoding(StringRef::from_lit("chunked")));
1194  CU_ASSERT(http2::check_transfer_encoding(StringRef::from_lit("foo,chunked")));
1195  CU_ASSERT(
1196      http2::check_transfer_encoding(StringRef::from_lit("foo,  chunked")));
1197  CU_ASSERT(
1198      http2::check_transfer_encoding(StringRef::from_lit("foo   ,  chunked")));
1199  CU_ASSERT(
1200      http2::check_transfer_encoding(StringRef::from_lit("chunked;foo=bar")));
1201  CU_ASSERT(
1202      http2::check_transfer_encoding(StringRef::from_lit("chunked ; foo=bar")));
1203  CU_ASSERT(http2::check_transfer_encoding(
1204      StringRef::from_lit(R"(chunked;foo="bar")")));
1205  CU_ASSERT(http2::check_transfer_encoding(
1206      StringRef::from_lit(R"(chunked;foo="\bar\"";FOO=BAR)")));
1207  CU_ASSERT(
1208      http2::check_transfer_encoding(StringRef::from_lit(R"(chunked;foo="")")));
1209  CU_ASSERT(http2::check_transfer_encoding(
1210      StringRef::from_lit(R"(chunked;foo="bar" , gzip)")));
1211
1212  CU_ASSERT(!http2::check_transfer_encoding(StringRef{}));
1213  CU_ASSERT(!http2::check_transfer_encoding(StringRef::from_lit(",chunked")));
1214  CU_ASSERT(!http2::check_transfer_encoding(StringRef::from_lit("chunked,")));
1215  CU_ASSERT(!http2::check_transfer_encoding(StringRef::from_lit("chunked, ")));
1216  CU_ASSERT(
1217      !http2::check_transfer_encoding(StringRef::from_lit("foo,,chunked")));
1218  CU_ASSERT(
1219      !http2::check_transfer_encoding(StringRef::from_lit("chunked;foo")));
1220  CU_ASSERT(!http2::check_transfer_encoding(StringRef::from_lit("chunked;")));
1221  CU_ASSERT(
1222      !http2::check_transfer_encoding(StringRef::from_lit("chunked;foo=bar;")));
1223  CU_ASSERT(
1224      !http2::check_transfer_encoding(StringRef::from_lit("chunked;?=bar")));
1225  CU_ASSERT(
1226      !http2::check_transfer_encoding(StringRef::from_lit("chunked;=bar")));
1227  CU_ASSERT(!http2::check_transfer_encoding(StringRef::from_lit("chunked;;")));
1228  CU_ASSERT(!http2::check_transfer_encoding(StringRef::from_lit("chunked?")));
1229  CU_ASSERT(!http2::check_transfer_encoding(StringRef::from_lit(",")));
1230  CU_ASSERT(!http2::check_transfer_encoding(StringRef::from_lit(" ")));
1231  CU_ASSERT(!http2::check_transfer_encoding(StringRef::from_lit(";")));
1232  CU_ASSERT(!http2::check_transfer_encoding(StringRef::from_lit("\"")));
1233  CU_ASSERT(!http2::check_transfer_encoding(
1234      StringRef::from_lit(R"(chunked;foo="bar)")));
1235  CU_ASSERT(!http2::check_transfer_encoding(
1236      StringRef::from_lit(R"(chunked;foo="bar\)")));
1237  CU_ASSERT(
1238      !http2::check_transfer_encoding(StringRef::from_lit(R"(chunked;foo="bar\)"
1239                                                          "\x0a"
1240                                                          R"(")")));
1241  CU_ASSERT(
1242      !http2::check_transfer_encoding(StringRef::from_lit(R"(chunked;foo=")"
1243                                                          "\x0a"
1244                                                          R"(")")));
1245  CU_ASSERT(!http2::check_transfer_encoding(
1246      StringRef::from_lit(R"(chunked;foo="bar",,gzip)")));
1247}
1248
1249} // namespace shrpx
1250