1 /*
2 * nghttp2 - HTTP/2 C Library
3 *
4 * Copyright (c) 2012 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.h"
26
27 #include "llhttp.h"
28
29 #include "util.h"
30
31 namespace nghttp2 {
32
33 namespace http2 {
34
get_reason_phrase(unsigned int status_code)35 StringRef get_reason_phrase(unsigned int status_code) {
36 switch (status_code) {
37 case 100:
38 return "Continue"_sr;
39 case 101:
40 return "Switching Protocols"_sr;
41 case 103:
42 return "Early Hints"_sr;
43 case 200:
44 return "OK"_sr;
45 case 201:
46 return "Created"_sr;
47 case 202:
48 return "Accepted"_sr;
49 case 203:
50 return "Non-Authoritative Information"_sr;
51 case 204:
52 return "No Content"_sr;
53 case 205:
54 return "Reset Content"_sr;
55 case 206:
56 return "Partial Content"_sr;
57 case 300:
58 return "Multiple Choices"_sr;
59 case 301:
60 return "Moved Permanently"_sr;
61 case 302:
62 return "Found"_sr;
63 case 303:
64 return "See Other"_sr;
65 case 304:
66 return "Not Modified"_sr;
67 case 305:
68 return "Use Proxy"_sr;
69 // case 306: return "(Unused)"_sr;
70 case 307:
71 return "Temporary Redirect"_sr;
72 case 308:
73 return "Permanent Redirect"_sr;
74 case 400:
75 return "Bad Request"_sr;
76 case 401:
77 return "Unauthorized"_sr;
78 case 402:
79 return "Payment Required"_sr;
80 case 403:
81 return "Forbidden"_sr;
82 case 404:
83 return "Not Found"_sr;
84 case 405:
85 return "Method Not Allowed"_sr;
86 case 406:
87 return "Not Acceptable"_sr;
88 case 407:
89 return "Proxy Authentication Required"_sr;
90 case 408:
91 return "Request Timeout"_sr;
92 case 409:
93 return "Conflict"_sr;
94 case 410:
95 return "Gone"_sr;
96 case 411:
97 return "Length Required"_sr;
98 case 412:
99 return "Precondition Failed"_sr;
100 case 413:
101 return "Payload Too Large"_sr;
102 case 414:
103 return "URI Too Long"_sr;
104 case 415:
105 return "Unsupported Media Type"_sr;
106 case 416:
107 return "Requested Range Not Satisfiable"_sr;
108 case 417:
109 return "Expectation Failed"_sr;
110 case 421:
111 return "Misdirected Request"_sr;
112 case 425:
113 // https://tools.ietf.org/html/rfc8470
114 return "Too Early"_sr;
115 case 426:
116 return "Upgrade Required"_sr;
117 case 428:
118 return "Precondition Required"_sr;
119 case 429:
120 return "Too Many Requests"_sr;
121 case 431:
122 return "Request Header Fields Too Large"_sr;
123 case 451:
124 return "Unavailable For Legal Reasons"_sr;
125 case 500:
126 return "Internal Server Error"_sr;
127 case 501:
128 return "Not Implemented"_sr;
129 case 502:
130 return "Bad Gateway"_sr;
131 case 503:
132 return "Service Unavailable"_sr;
133 case 504:
134 return "Gateway Timeout"_sr;
135 case 505:
136 return "HTTP Version Not Supported"_sr;
137 case 511:
138 return "Network Authentication Required"_sr;
139 default:
140 return StringRef{};
141 }
142 }
143
stringify_status(BlockAllocator & balloc,unsigned int status_code)144 StringRef stringify_status(BlockAllocator &balloc, unsigned int status_code) {
145 switch (status_code) {
146 case 100:
147 return "100"_sr;
148 case 101:
149 return "101"_sr;
150 case 103:
151 return "103"_sr;
152 case 200:
153 return "200"_sr;
154 case 201:
155 return "201"_sr;
156 case 202:
157 return "202"_sr;
158 case 203:
159 return "203"_sr;
160 case 204:
161 return "204"_sr;
162 case 205:
163 return "205"_sr;
164 case 206:
165 return "206"_sr;
166 case 300:
167 return "300"_sr;
168 case 301:
169 return "301"_sr;
170 case 302:
171 return "302"_sr;
172 case 303:
173 return "303"_sr;
174 case 304:
175 return "304"_sr;
176 case 305:
177 return "305"_sr;
178 // case 306: return "306"_sr;
179 case 307:
180 return "307"_sr;
181 case 308:
182 return "308"_sr;
183 case 400:
184 return "400"_sr;
185 case 401:
186 return "401"_sr;
187 case 402:
188 return "402"_sr;
189 case 403:
190 return "403"_sr;
191 case 404:
192 return "404"_sr;
193 case 405:
194 return "405"_sr;
195 case 406:
196 return "406"_sr;
197 case 407:
198 return "407"_sr;
199 case 408:
200 return "408"_sr;
201 case 409:
202 return "409"_sr;
203 case 410:
204 return "410"_sr;
205 case 411:
206 return "411"_sr;
207 case 412:
208 return "412"_sr;
209 case 413:
210 return "413"_sr;
211 case 414:
212 return "414"_sr;
213 case 415:
214 return "415"_sr;
215 case 416:
216 return "416"_sr;
217 case 417:
218 return "417"_sr;
219 case 421:
220 return "421"_sr;
221 case 426:
222 return "426"_sr;
223 case 428:
224 return "428"_sr;
225 case 429:
226 return "429"_sr;
227 case 431:
228 return "431"_sr;
229 case 451:
230 return "451"_sr;
231 case 500:
232 return "500"_sr;
233 case 501:
234 return "501"_sr;
235 case 502:
236 return "502"_sr;
237 case 503:
238 return "503"_sr;
239 case 504:
240 return "504"_sr;
241 case 505:
242 return "505"_sr;
243 case 511:
244 return "511"_sr;
245 default:
246 return util::make_string_ref_uint(balloc, status_code);
247 }
248 }
249
capitalize(DefaultMemchunks * buf,const StringRef & s)250 void capitalize(DefaultMemchunks *buf, const StringRef &s) {
251 buf->append(util::upcase(s[0]));
252 for (size_t i = 1; i < s.size(); ++i) {
253 if (s[i - 1] == '-') {
254 buf->append(util::upcase(s[i]));
255 } else {
256 buf->append(s[i]);
257 }
258 }
259 }
260
lws(const char * value)261 bool lws(const char *value) {
262 for (; *value; ++value) {
263 switch (*value) {
264 case '\t':
265 case ' ':
266 continue;
267 default:
268 return false;
269 }
270 }
271 return true;
272 }
273
copy_url_component(std::string & dest,const http_parser_url * u,int field,const char * url)274 void copy_url_component(std::string &dest, const http_parser_url *u, int field,
275 const char *url) {
276 if (u->field_set & (1 << field)) {
277 dest.assign(url + u->field_data[field].off, u->field_data[field].len);
278 }
279 }
280
to_header(const StringRef & name,const StringRef & value,bool no_index,int32_t token)281 Headers::value_type to_header(const StringRef &name, const StringRef &value,
282 bool no_index, int32_t token) {
283 return Header(std::string{std::begin(name), std::end(name)},
284 std::string{std::begin(value), std::end(value)}, no_index,
285 token);
286 }
287
add_header(Headers & nva,const StringRef & name,const StringRef & value,bool no_index,int32_t token)288 void add_header(Headers &nva, const StringRef &name, const StringRef &value,
289 bool no_index, int32_t token) {
290 nva.push_back(to_header(name, value, no_index, token));
291 }
292
get_header(const Headers & nva,const char * name)293 const Headers::value_type *get_header(const Headers &nva, const char *name) {
294 const Headers::value_type *res = nullptr;
295 for (auto &nv : nva) {
296 if (nv.name == name) {
297 res = &nv;
298 }
299 }
300 return res;
301 }
302
non_empty_value(const HeaderRefs::value_type * nv)303 bool non_empty_value(const HeaderRefs::value_type *nv) {
304 return nv && !nv->value.empty();
305 }
306
307 namespace {
copy_headers_to_nva_internal(std::vector<nghttp2_nv> & nva,const HeaderRefs & headers,uint8_t nv_flags,uint32_t flags)308 void copy_headers_to_nva_internal(std::vector<nghttp2_nv> &nva,
309 const HeaderRefs &headers, uint8_t nv_flags,
310 uint32_t flags) {
311 auto it_forwarded = std::end(headers);
312 auto it_xff = std::end(headers);
313 auto it_xfp = std::end(headers);
314 auto it_via = std::end(headers);
315
316 for (auto it = std::begin(headers); it != std::end(headers); ++it) {
317 auto kv = &(*it);
318 if (kv->name.empty() || kv->name[0] == ':') {
319 continue;
320 }
321 switch (kv->token) {
322 case HD_COOKIE:
323 case HD_CONNECTION:
324 case HD_HOST:
325 case HD_HTTP2_SETTINGS:
326 case HD_KEEP_ALIVE:
327 case HD_PROXY_CONNECTION:
328 case HD_SERVER:
329 case HD_TE:
330 case HD_TRANSFER_ENCODING:
331 case HD_UPGRADE:
332 continue;
333 case HD_EARLY_DATA:
334 if (flags & HDOP_STRIP_EARLY_DATA) {
335 continue;
336 }
337 break;
338 case HD_SEC_WEBSOCKET_ACCEPT:
339 if (flags & HDOP_STRIP_SEC_WEBSOCKET_ACCEPT) {
340 continue;
341 }
342 break;
343 case HD_SEC_WEBSOCKET_KEY:
344 if (flags & HDOP_STRIP_SEC_WEBSOCKET_KEY) {
345 continue;
346 }
347 break;
348 case HD_FORWARDED:
349 if (flags & HDOP_STRIP_FORWARDED) {
350 continue;
351 }
352
353 if (it_forwarded == std::end(headers)) {
354 it_forwarded = it;
355 continue;
356 }
357
358 kv = &(*it_forwarded);
359 it_forwarded = it;
360 break;
361 case HD_X_FORWARDED_FOR:
362 if (flags & HDOP_STRIP_X_FORWARDED_FOR) {
363 continue;
364 }
365
366 if (it_xff == std::end(headers)) {
367 it_xff = it;
368 continue;
369 }
370
371 kv = &(*it_xff);
372 it_xff = it;
373 break;
374 case HD_X_FORWARDED_PROTO:
375 if (flags & HDOP_STRIP_X_FORWARDED_PROTO) {
376 continue;
377 }
378
379 if (it_xfp == std::end(headers)) {
380 it_xfp = it;
381 continue;
382 }
383
384 kv = &(*it_xfp);
385 it_xfp = it;
386 break;
387 case HD_VIA:
388 if (flags & HDOP_STRIP_VIA) {
389 continue;
390 }
391
392 if (it_via == std::end(headers)) {
393 it_via = it;
394 continue;
395 }
396
397 kv = &(*it_via);
398 it_via = it;
399 break;
400 }
401 nva.push_back(
402 make_field_flags(kv->name, kv->value, nv_flags | no_index(kv->no_index)));
403 }
404 }
405 } // namespace
406
copy_headers_to_nva(std::vector<nghttp2_nv> & nva,const HeaderRefs & headers,uint32_t flags)407 void copy_headers_to_nva(std::vector<nghttp2_nv> &nva,
408 const HeaderRefs &headers, uint32_t flags) {
409 copy_headers_to_nva_internal(nva, headers, NGHTTP2_NV_FLAG_NONE, flags);
410 }
411
copy_headers_to_nva_nocopy(std::vector<nghttp2_nv> & nva,const HeaderRefs & headers,uint32_t flags)412 void copy_headers_to_nva_nocopy(std::vector<nghttp2_nv> &nva,
413 const HeaderRefs &headers, uint32_t flags) {
414 copy_headers_to_nva_internal(
415 nva, headers, NGHTTP2_NV_FLAG_NO_COPY_NAME | NGHTTP2_NV_FLAG_NO_COPY_VALUE,
416 flags);
417 }
418
build_http1_headers_from_headers(DefaultMemchunks * buf,const HeaderRefs & headers,uint32_t flags)419 void build_http1_headers_from_headers(DefaultMemchunks *buf,
420 const HeaderRefs &headers,
421 uint32_t flags) {
422 auto it_forwarded = std::end(headers);
423 auto it_xff = std::end(headers);
424 auto it_xfp = std::end(headers);
425 auto it_via = std::end(headers);
426
427 for (auto it = std::begin(headers); it != std::end(headers); ++it) {
428 auto kv = &(*it);
429 if (kv->name.empty() || kv->name[0] == ':') {
430 continue;
431 }
432 switch (kv->token) {
433 case HD_CONNECTION:
434 case HD_COOKIE:
435 case HD_HOST:
436 case HD_HTTP2_SETTINGS:
437 case HD_KEEP_ALIVE:
438 case HD_PROXY_CONNECTION:
439 case HD_SERVER:
440 case HD_UPGRADE:
441 continue;
442 case HD_EARLY_DATA:
443 if (flags & HDOP_STRIP_EARLY_DATA) {
444 continue;
445 }
446 break;
447 case HD_TRANSFER_ENCODING:
448 if (flags & HDOP_STRIP_TRANSFER_ENCODING) {
449 continue;
450 }
451 break;
452 case HD_FORWARDED:
453 if (flags & HDOP_STRIP_FORWARDED) {
454 continue;
455 }
456
457 if (it_forwarded == std::end(headers)) {
458 it_forwarded = it;
459 continue;
460 }
461
462 kv = &(*it_forwarded);
463 it_forwarded = it;
464 break;
465 case HD_X_FORWARDED_FOR:
466 if (flags & HDOP_STRIP_X_FORWARDED_FOR) {
467 continue;
468 }
469
470 if (it_xff == std::end(headers)) {
471 it_xff = it;
472 continue;
473 }
474
475 kv = &(*it_xff);
476 it_xff = it;
477 break;
478 case HD_X_FORWARDED_PROTO:
479 if (flags & HDOP_STRIP_X_FORWARDED_PROTO) {
480 continue;
481 }
482
483 if (it_xfp == std::end(headers)) {
484 it_xfp = it;
485 continue;
486 }
487
488 kv = &(*it_xfp);
489 it_xfp = it;
490 break;
491 case HD_VIA:
492 if (flags & HDOP_STRIP_VIA) {
493 continue;
494 }
495
496 if (it_via == std::end(headers)) {
497 it_via = it;
498 continue;
499 }
500
501 kv = &(*it_via);
502 it_via = it;
503 break;
504 }
505 capitalize(buf, kv->name);
506 buf->append(": ");
507 buf->append(kv->value);
508 buf->append("\r\n");
509 }
510 }
511
determine_window_update_transmission(nghttp2_session * session,int32_t stream_id)512 int32_t determine_window_update_transmission(nghttp2_session *session,
513 int32_t stream_id) {
514 int32_t recv_length, window_size;
515 if (stream_id == 0) {
516 recv_length = nghttp2_session_get_effective_recv_data_length(session);
517 window_size = nghttp2_session_get_effective_local_window_size(session);
518 } else {
519 recv_length =
520 nghttp2_session_get_stream_effective_recv_data_length(session, stream_id);
521 window_size = nghttp2_session_get_stream_effective_local_window_size(
522 session, stream_id);
523 }
524 if (recv_length != -1 && window_size != -1) {
525 if (recv_length >= window_size / 2) {
526 return recv_length;
527 }
528 }
529 return -1;
530 }
531
dump_nv(FILE * out,const char ** nv)532 void dump_nv(FILE *out, const char **nv) {
533 for (size_t i = 0; nv[i]; i += 2) {
534 fprintf(out, "%s: %s\n", nv[i], nv[i + 1]);
535 }
536 fputc('\n', out);
537 fflush(out);
538 }
539
dump_nv(FILE * out,const nghttp2_nv * nva,size_t nvlen)540 void dump_nv(FILE *out, const nghttp2_nv *nva, size_t nvlen) {
541 auto end = nva + nvlen;
542 for (; nva != end; ++nva) {
543 fprintf(out, "%s: %s\n", nva->name, nva->value);
544 }
545 fputc('\n', out);
546 fflush(out);
547 }
548
dump_nv(FILE * out,const Headers & nva)549 void dump_nv(FILE *out, const Headers &nva) {
550 for (auto &nv : nva) {
551 fprintf(out, "%s: %s\n", nv.name.c_str(), nv.value.c_str());
552 }
553 fputc('\n', out);
554 fflush(out);
555 }
556
dump_nv(FILE * out,const HeaderRefs & nva)557 void dump_nv(FILE *out, const HeaderRefs &nva) {
558 for (auto &nv : nva) {
559 fprintf(out, "%s: %s\n", nv.name.data(), nv.value.data());
560 }
561 fputc('\n', out);
562 fflush(out);
563 }
564
erase_header(HeaderRef * hd)565 void erase_header(HeaderRef *hd) {
566 hd->name = StringRef{};
567 hd->token = -1;
568 }
569
rewrite_location_uri(BlockAllocator & balloc,const StringRef & uri,const http_parser_url & u,const StringRef & match_host,const StringRef & request_authority,const StringRef & upstream_scheme)570 StringRef rewrite_location_uri(BlockAllocator &balloc, const StringRef &uri,
571 const http_parser_url &u,
572 const StringRef &match_host,
573 const StringRef &request_authority,
574 const StringRef &upstream_scheme) {
575 // We just rewrite scheme and authority.
576 if ((u.field_set & (1 << UF_HOST)) == 0) {
577 return StringRef{};
578 }
579 auto field = &u.field_data[UF_HOST];
580 if (!util::starts_with(std::begin(match_host), std::end(match_host),
581 &uri[field->off], &uri[field->off] + field->len) ||
582 (match_host.size() != field->len && match_host[field->len] != ':')) {
583 return StringRef{};
584 }
585
586 auto len = 0;
587 if (!request_authority.empty()) {
588 len += upstream_scheme.size() + str_size("://") + request_authority.size();
589 }
590
591 if (u.field_set & (1 << UF_PATH)) {
592 field = &u.field_data[UF_PATH];
593 len += field->len;
594 }
595
596 if (u.field_set & (1 << UF_QUERY)) {
597 field = &u.field_data[UF_QUERY];
598 len += 1 + field->len;
599 }
600
601 if (u.field_set & (1 << UF_FRAGMENT)) {
602 field = &u.field_data[UF_FRAGMENT];
603 len += 1 + field->len;
604 }
605
606 auto iov = make_byte_ref(balloc, len + 1);
607 auto p = std::begin(iov);
608
609 if (!request_authority.empty()) {
610 p = std::copy(std::begin(upstream_scheme), std::end(upstream_scheme), p);
611 p = util::copy_lit(p, "://");
612 p =
613 std::copy(std::begin(request_authority), std::end(request_authority), p);
614 }
615 if (u.field_set & (1 << UF_PATH)) {
616 field = &u.field_data[UF_PATH];
617 p = std::copy_n(&uri[field->off], field->len, p);
618 }
619 if (u.field_set & (1 << UF_QUERY)) {
620 field = &u.field_data[UF_QUERY];
621 *p++ = '?';
622 p = std::copy_n(&uri[field->off], field->len, p);
623 }
624 if (u.field_set & (1 << UF_FRAGMENT)) {
625 field = &u.field_data[UF_FRAGMENT];
626 *p++ = '#';
627 p = std::copy_n(&uri[field->off], field->len, p);
628 }
629
630 *p = '\0';
631
632 return StringRef{std::span{std::begin(iov), p}};
633 }
634
parse_http_status_code(const StringRef & src)635 int parse_http_status_code(const StringRef &src) {
636 if (src.size() != 3) {
637 return -1;
638 }
639
640 int status = 0;
641 for (auto c : src) {
642 if (!isdigit(c)) {
643 return -1;
644 }
645 status *= 10;
646 status += c - '0';
647 }
648
649 if (status < 100) {
650 return -1;
651 }
652
653 return status;
654 }
655
656 // This function was generated by genheaderfunc.py. Inspired by h2o
657 // header lookup. https://github.com/h2o/h2o
lookup_token(const StringRef & name)658 int lookup_token(const StringRef &name) {
659 switch (name.size()) {
660 case 2:
661 switch (name[1]) {
662 case 'e':
663 if (util::streq("t"_sr, name, 1)) {
664 return HD_TE;
665 }
666 break;
667 }
668 break;
669 case 3:
670 switch (name[2]) {
671 case 'a':
672 if (util::streq("vi"_sr, name, 2)) {
673 return HD_VIA;
674 }
675 break;
676 }
677 break;
678 case 4:
679 switch (name[3]) {
680 case 'e':
681 if (util::streq("dat"_sr, name, 3)) {
682 return HD_DATE;
683 }
684 break;
685 case 'k':
686 if (util::streq("lin"_sr, name, 3)) {
687 return HD_LINK;
688 }
689 break;
690 case 't':
691 if (util::streq("hos"_sr, name, 3)) {
692 return HD_HOST;
693 }
694 break;
695 }
696 break;
697 case 5:
698 switch (name[4]) {
699 case 'h':
700 if (util::streq(":pat"_sr, name, 4)) {
701 return HD__PATH;
702 }
703 break;
704 case 't':
705 if (util::streq(":hos"_sr, name, 4)) {
706 return HD__HOST;
707 }
708 break;
709 }
710 break;
711 case 6:
712 switch (name[5]) {
713 case 'e':
714 if (util::streq("cooki"_sr, name, 5)) {
715 return HD_COOKIE;
716 }
717 break;
718 case 'r':
719 if (util::streq("serve"_sr, name, 5)) {
720 return HD_SERVER;
721 }
722 break;
723 case 't':
724 if (util::streq("expec"_sr, name, 5)) {
725 return HD_EXPECT;
726 }
727 break;
728 }
729 break;
730 case 7:
731 switch (name[6]) {
732 case 'c':
733 if (util::streq("alt-sv"_sr, name, 6)) {
734 return HD_ALT_SVC;
735 }
736 break;
737 case 'd':
738 if (util::streq(":metho"_sr, name, 6)) {
739 return HD__METHOD;
740 }
741 break;
742 case 'e':
743 if (util::streq(":schem"_sr, name, 6)) {
744 return HD__SCHEME;
745 }
746 if (util::streq("upgrad"_sr, name, 6)) {
747 return HD_UPGRADE;
748 }
749 break;
750 case 'r':
751 if (util::streq("traile"_sr, name, 6)) {
752 return HD_TRAILER;
753 }
754 break;
755 case 's':
756 if (util::streq(":statu"_sr, name, 6)) {
757 return HD__STATUS;
758 }
759 break;
760 }
761 break;
762 case 8:
763 switch (name[7]) {
764 case 'n':
765 if (util::streq("locatio"_sr, name, 7)) {
766 return HD_LOCATION;
767 }
768 break;
769 case 'y':
770 if (util::streq("priorit"_sr, name, 7)) {
771 return HD_PRIORITY;
772 }
773 break;
774 }
775 break;
776 case 9:
777 switch (name[8]) {
778 case 'd':
779 if (util::streq("forwarde"_sr, name, 8)) {
780 return HD_FORWARDED;
781 }
782 break;
783 case 'l':
784 if (util::streq(":protoco"_sr, name, 8)) {
785 return HD__PROTOCOL;
786 }
787 break;
788 }
789 break;
790 case 10:
791 switch (name[9]) {
792 case 'a':
793 if (util::streq("early-dat"_sr, name, 9)) {
794 return HD_EARLY_DATA;
795 }
796 break;
797 case 'e':
798 if (util::streq("keep-aliv"_sr, name, 9)) {
799 return HD_KEEP_ALIVE;
800 }
801 break;
802 case 'n':
803 if (util::streq("connectio"_sr, name, 9)) {
804 return HD_CONNECTION;
805 }
806 break;
807 case 't':
808 if (util::streq("user-agen"_sr, name, 9)) {
809 return HD_USER_AGENT;
810 }
811 break;
812 case 'y':
813 if (util::streq(":authorit"_sr, name, 9)) {
814 return HD__AUTHORITY;
815 }
816 break;
817 }
818 break;
819 case 12:
820 switch (name[11]) {
821 case 'e':
822 if (util::streq("content-typ"_sr, name, 11)) {
823 return HD_CONTENT_TYPE;
824 }
825 break;
826 }
827 break;
828 case 13:
829 switch (name[12]) {
830 case 'l':
831 if (util::streq("cache-contro"_sr, name, 12)) {
832 return HD_CACHE_CONTROL;
833 }
834 break;
835 }
836 break;
837 case 14:
838 switch (name[13]) {
839 case 'h':
840 if (util::streq("content-lengt"_sr, name, 13)) {
841 return HD_CONTENT_LENGTH;
842 }
843 break;
844 case 's':
845 if (util::streq("http2-setting"_sr, name, 13)) {
846 return HD_HTTP2_SETTINGS;
847 }
848 break;
849 }
850 break;
851 case 15:
852 switch (name[14]) {
853 case 'e':
854 if (util::streq("accept-languag"_sr, name, 14)) {
855 return HD_ACCEPT_LANGUAGE;
856 }
857 break;
858 case 'g':
859 if (util::streq("accept-encodin"_sr, name, 14)) {
860 return HD_ACCEPT_ENCODING;
861 }
862 break;
863 case 'r':
864 if (util::streq("x-forwarded-fo"_sr, name, 14)) {
865 return HD_X_FORWARDED_FOR;
866 }
867 break;
868 }
869 break;
870 case 16:
871 switch (name[15]) {
872 case 'n':
873 if (util::streq("proxy-connectio"_sr, name, 15)) {
874 return HD_PROXY_CONNECTION;
875 }
876 break;
877 }
878 break;
879 case 17:
880 switch (name[16]) {
881 case 'e':
882 if (util::streq("if-modified-sinc"_sr, name, 16)) {
883 return HD_IF_MODIFIED_SINCE;
884 }
885 break;
886 case 'g':
887 if (util::streq("transfer-encodin"_sr, name, 16)) {
888 return HD_TRANSFER_ENCODING;
889 }
890 break;
891 case 'o':
892 if (util::streq("x-forwarded-prot"_sr, name, 16)) {
893 return HD_X_FORWARDED_PROTO;
894 }
895 break;
896 case 'y':
897 if (util::streq("sec-websocket-ke"_sr, name, 16)) {
898 return HD_SEC_WEBSOCKET_KEY;
899 }
900 break;
901 }
902 break;
903 case 20:
904 switch (name[19]) {
905 case 't':
906 if (util::streq("sec-websocket-accep"_sr, name, 19)) {
907 return HD_SEC_WEBSOCKET_ACCEPT;
908 }
909 break;
910 }
911 break;
912 }
913 return -1;
914 }
915
init_hdidx(HeaderIndex & hdidx)916 void init_hdidx(HeaderIndex &hdidx) {
917 std::fill(std::begin(hdidx), std::end(hdidx), -1);
918 }
919
index_header(HeaderIndex & hdidx,int32_t token,size_t idx)920 void index_header(HeaderIndex &hdidx, int32_t token, size_t idx) {
921 if (token == -1) {
922 return;
923 }
924 assert(token < HD_MAXIDX);
925 hdidx[token] = idx;
926 }
927
get_header(const HeaderIndex & hdidx,int32_t token,const Headers & nva)928 const Headers::value_type *get_header(const HeaderIndex &hdidx, int32_t token,
929 const Headers &nva) {
930 auto i = hdidx[token];
931 if (i == -1) {
932 return nullptr;
933 }
934 return &nva[i];
935 }
936
get_header(const HeaderIndex & hdidx,int32_t token,Headers & nva)937 Headers::value_type *get_header(const HeaderIndex &hdidx, int32_t token,
938 Headers &nva) {
939 auto i = hdidx[token];
940 if (i == -1) {
941 return nullptr;
942 }
943 return &nva[i];
944 }
945
946 namespace {
skip_lws(InputIt first,InputIt last)947 template <typename InputIt> InputIt skip_lws(InputIt first, InputIt last) {
948 for (; first != last; ++first) {
949 switch (*first) {
950 case ' ':
951 case '\t':
952 continue;
953 default:
954 return first;
955 }
956 }
957 return first;
958 }
959 } // namespace
960
961 namespace {
962 template <typename InputIt>
skip_to_next_field(InputIt first,InputIt last)963 InputIt skip_to_next_field(InputIt first, InputIt last) {
964 for (; first != last; ++first) {
965 switch (*first) {
966 case ' ':
967 case '\t':
968 case ',':
969 continue;
970 default:
971 return first;
972 }
973 }
974 return first;
975 }
976 } // namespace
977
978 namespace {
979 // Skip to the right dquote ('"'), handling backslash escapes.
980 // Returns |last| if input is not terminated with '"'.
981 template <typename InputIt>
skip_to_right_dquote(InputIt first,InputIt last)982 InputIt skip_to_right_dquote(InputIt first, InputIt last) {
983 for (; first != last;) {
984 switch (*first) {
985 case '"':
986 return first;
987 // quoted-pair
988 case '\\':
989 ++first;
990 if (first == last) {
991 return first;
992 }
993
994 switch (*first) {
995 case '\t':
996 case ' ':
997 break;
998 default:
999 if ((0x21 <= *first && *first <= 0x7e) /* VCHAR */ ||
1000 (0x80 <= *first && *first <= 0xff) /* obs-text */) {
1001 break;
1002 }
1003
1004 return last;
1005 }
1006
1007 break;
1008 // qdtext
1009 case '\t':
1010 case ' ':
1011 case '!':
1012 break;
1013 default:
1014 if ((0x23 <= *first && *first <= 0x5b) ||
1015 (0x5d <= *first && *first <= 0x7e)) {
1016 break;
1017 }
1018
1019 return last;
1020 }
1021 ++first;
1022 }
1023 return first;
1024 }
1025 } // namespace
1026
1027 namespace {
1028 // Returns true if link-param does not match pattern |pat| of length
1029 // |patlen| or it has empty value (""). |pat| should be parmname
1030 // followed by "=".
check_link_param_empty(const char * first,const char * last,const char * pat,size_t patlen)1031 bool check_link_param_empty(const char *first, const char *last,
1032 const char *pat, size_t patlen) {
1033 if (first + patlen <= last) {
1034 if (std::equal(pat, pat + patlen, first, util::CaseCmp())) {
1035 // we only accept URI if pat is followed by "" (e.g.,
1036 // loadpolicy="") here.
1037 if (first + patlen + 2 <= last) {
1038 if (*(first + patlen) != '"' || *(first + patlen + 1) != '"') {
1039 return false;
1040 }
1041 } else {
1042 // here we got invalid production (anchor=") or anchor=?
1043 return false;
1044 }
1045 }
1046 }
1047 return true;
1048 }
1049 } // namespace
1050
1051 namespace {
1052 // Returns true if link-param consists of only parmname, and it
1053 // matches string [pat, pat + patlen).
check_link_param_without_value(const char * first,const char * last,const char * pat,size_t patlen)1054 bool check_link_param_without_value(const char *first, const char *last,
1055 const char *pat, size_t patlen) {
1056 if (first + patlen > last) {
1057 return false;
1058 }
1059
1060 if (first + patlen == last) {
1061 return std::equal(pat, pat + patlen, first, util::CaseCmp());
1062 }
1063
1064 switch (*(first + patlen)) {
1065 case ';':
1066 case ',':
1067 return std::equal(pat, pat + patlen, first, util::CaseCmp());
1068 }
1069
1070 return false;
1071 }
1072 } // namespace
1073
1074 namespace {
1075 std::pair<LinkHeader, const char *>
parse_next_link_header_once(const char * first,const char * last)1076 parse_next_link_header_once(const char *first, const char *last) {
1077 first = skip_to_next_field(first, last);
1078 if (first == last || *first != '<') {
1079 return {{StringRef{}}, last};
1080 }
1081 auto url_first = ++first;
1082 first = std::find(first, last, '>');
1083 if (first == last) {
1084 return {{StringRef{}}, first};
1085 }
1086 auto url_last = first++;
1087 if (first == last) {
1088 return {{StringRef{}}, first};
1089 }
1090 // we expect ';' or ',' here
1091 switch (*first) {
1092 case ',':
1093 return {{StringRef{}}, ++first};
1094 case ';':
1095 ++first;
1096 break;
1097 default:
1098 return {{StringRef{}}, last};
1099 }
1100
1101 auto ok = false;
1102 auto ign = false;
1103 for (;;) {
1104 first = skip_lws(first, last);
1105 if (first == last) {
1106 return {{StringRef{}}, first};
1107 }
1108 // we expect link-param
1109
1110 if (!ign) {
1111 if (!ok) {
1112 // rel can take several relations using quoted form.
1113 static constexpr char PLP[] = "rel=\"";
1114 static constexpr size_t PLPLEN = str_size(PLP);
1115
1116 static constexpr char PLT[] = "preload";
1117 static constexpr size_t PLTLEN = str_size(PLT);
1118 if (first + PLPLEN < last && *(first + PLPLEN - 1) == '"' &&
1119 std::equal(PLP, PLP + PLPLEN, first, util::CaseCmp())) {
1120 // we have to search preload in whitespace separated list:
1121 // rel="preload something http://example.org/foo"
1122 first += PLPLEN;
1123 auto start = first;
1124 for (; first != last;) {
1125 if (*first != ' ' && *first != '"') {
1126 ++first;
1127 continue;
1128 }
1129
1130 if (start == first) {
1131 return {{StringRef{}}, last};
1132 }
1133
1134 if (!ok && start + PLTLEN == first &&
1135 std::equal(PLT, PLT + PLTLEN, start, util::CaseCmp())) {
1136 ok = true;
1137 }
1138
1139 if (*first == '"') {
1140 break;
1141 }
1142 first = skip_lws(first, last);
1143 start = first;
1144 }
1145 if (first == last) {
1146 return {{StringRef{}}, last};
1147 }
1148 assert(*first == '"');
1149 ++first;
1150 if (first == last || *first == ',') {
1151 goto almost_done;
1152 }
1153 if (*first == ';') {
1154 ++first;
1155 // parse next link-param
1156 continue;
1157 }
1158 return {{StringRef{}}, last};
1159 }
1160 }
1161 // we are only interested in rel=preload parameter. Others are
1162 // simply skipped.
1163 static constexpr char PL[] = "rel=preload";
1164 static constexpr size_t PLLEN = str_size(PL);
1165 if (first + PLLEN == last) {
1166 if (std::equal(PL, PL + PLLEN, first, util::CaseCmp())) {
1167 // ok = true;
1168 // this is the end of sequence
1169 return {{{url_first, url_last}}, last};
1170 }
1171 } else if (first + PLLEN + 1 <= last) {
1172 switch (*(first + PLLEN)) {
1173 case ',':
1174 if (!std::equal(PL, PL + PLLEN, first, util::CaseCmp())) {
1175 break;
1176 }
1177 // ok = true;
1178 // skip including ','
1179 first += PLLEN + 1;
1180 return {{{url_first, url_last}}, first};
1181 case ';':
1182 if (!std::equal(PL, PL + PLLEN, first, util::CaseCmp())) {
1183 break;
1184 }
1185 ok = true;
1186 // skip including ';'
1187 first += PLLEN + 1;
1188 // continue parse next link-param
1189 continue;
1190 }
1191 }
1192 // we have to reject URI if we have nonempty anchor parameter.
1193 static constexpr char ANCHOR[] = "anchor=";
1194 static constexpr size_t ANCHORLEN = str_size(ANCHOR);
1195 if (!ign && !check_link_param_empty(first, last, ANCHOR, ANCHORLEN)) {
1196 ign = true;
1197 }
1198
1199 // reject URI if we have non-empty loadpolicy. This could be
1200 // tightened up to just pick up "next" or "insert".
1201 static constexpr char LOADPOLICY[] = "loadpolicy=";
1202 static constexpr size_t LOADPOLICYLEN = str_size(LOADPOLICY);
1203 if (!ign &&
1204 !check_link_param_empty(first, last, LOADPOLICY, LOADPOLICYLEN)) {
1205 ign = true;
1206 }
1207
1208 // reject URI if we have nopush attribute.
1209 static constexpr char NOPUSH[] = "nopush";
1210 static constexpr size_t NOPUSHLEN = str_size(NOPUSH);
1211 if (!ign &&
1212 check_link_param_without_value(first, last, NOPUSH, NOPUSHLEN)) {
1213 ign = true;
1214 }
1215 }
1216
1217 auto param_first = first;
1218 for (; first != last;) {
1219 if (util::in_attr_char(*first)) {
1220 ++first;
1221 continue;
1222 }
1223 // '*' is only allowed at the end of parameter name and must be
1224 // followed by '='
1225 if (last - first >= 2 && first != param_first) {
1226 if (*first == '*' && *(first + 1) == '=') {
1227 ++first;
1228 break;
1229 }
1230 }
1231 if (*first == '=' || *first == ';' || *first == ',') {
1232 break;
1233 }
1234 return {{StringRef{}}, last};
1235 }
1236 if (param_first == first) {
1237 // empty parmname
1238 return {{StringRef{}}, last};
1239 }
1240 // link-param without value is acceptable (see link-extension) if
1241 // it is not followed by '='
1242 if (first == last || *first == ',') {
1243 goto almost_done;
1244 }
1245 if (*first == ';') {
1246 ++first;
1247 // parse next link-param
1248 continue;
1249 }
1250 // now parsing link-param value
1251 assert(*first == '=');
1252 ++first;
1253 if (first == last) {
1254 // empty value is not acceptable
1255 return {{StringRef{}}, first};
1256 }
1257 if (*first == '"') {
1258 // quoted-string
1259 first = skip_to_right_dquote(first + 1, last);
1260 if (first == last) {
1261 return {{StringRef{}}, first};
1262 }
1263 ++first;
1264 if (first == last || *first == ',') {
1265 goto almost_done;
1266 }
1267 if (*first == ';') {
1268 ++first;
1269 // parse next link-param
1270 continue;
1271 }
1272 return {{StringRef{}}, last};
1273 }
1274 // not quoted-string, skip to next ',' or ';'
1275 if (*first == ',' || *first == ';') {
1276 // empty value
1277 return {{StringRef{}}, last};
1278 }
1279 for (; first != last; ++first) {
1280 if (*first == ',' || *first == ';') {
1281 break;
1282 }
1283 }
1284 if (first == last || *first == ',') {
1285 goto almost_done;
1286 }
1287 assert(*first == ';');
1288 ++first;
1289 // parse next link-param
1290 }
1291
1292 almost_done:
1293 assert(first == last || *first == ',');
1294
1295 if (first != last) {
1296 ++first;
1297 }
1298 if (ok && !ign) {
1299 return {{{url_first, url_last}}, first};
1300 }
1301 return {{StringRef{}}, first};
1302 }
1303 } // namespace
1304
parse_link_header(const StringRef & src)1305 std::vector<LinkHeader> parse_link_header(const StringRef &src) {
1306 std::vector<LinkHeader> res;
1307 for (auto first = std::begin(src); first != std::end(src);) {
1308 auto rv = parse_next_link_header_once(first, std::end(src));
1309 first = rv.second;
1310 auto &link = rv.first;
1311 if (!link.uri.empty()) {
1312 res.push_back(link);
1313 }
1314 }
1315 return res;
1316 }
1317
path_join(const StringRef & base_path,const StringRef & base_query,const StringRef & rel_path,const StringRef & rel_query)1318 std::string path_join(const StringRef &base_path, const StringRef &base_query,
1319 const StringRef &rel_path, const StringRef &rel_query) {
1320 BlockAllocator balloc(1024, 1024);
1321
1322 return std::string{
1323 path_join(balloc, base_path, base_query, rel_path, rel_query)};
1324 }
1325
expect_response_body(int status_code)1326 bool expect_response_body(int status_code) {
1327 return status_code == 101 ||
1328 (status_code / 100 != 1 && status_code != 304 && status_code != 204);
1329 }
1330
expect_response_body(const std::string & method,int status_code)1331 bool expect_response_body(const std::string &method, int status_code) {
1332 return method != "HEAD" && expect_response_body(status_code);
1333 }
1334
expect_response_body(int method_token,int status_code)1335 bool expect_response_body(int method_token, int status_code) {
1336 return method_token != HTTP_HEAD && expect_response_body(status_code);
1337 }
1338
1339 // This function was generated by genmethodfunc.py.
lookup_method_token(const StringRef & name)1340 int lookup_method_token(const StringRef &name) {
1341 switch (name.size()) {
1342 case 3:
1343 switch (name[2]) {
1344 case 'L':
1345 if (util::streq("AC"_sr, name, 2)) {
1346 return HTTP_ACL;
1347 }
1348 break;
1349 case 'T':
1350 if (util::streq("GE"_sr, name, 2)) {
1351 return HTTP_GET;
1352 }
1353 if (util::streq("PU"_sr, name, 2)) {
1354 return HTTP_PUT;
1355 }
1356 break;
1357 }
1358 break;
1359 case 4:
1360 switch (name[3]) {
1361 case 'D':
1362 if (util::streq("BIN"_sr, name, 3)) {
1363 return HTTP_BIND;
1364 }
1365 if (util::streq("HEA"_sr, name, 3)) {
1366 return HTTP_HEAD;
1367 }
1368 break;
1369 case 'E':
1370 if (util::streq("MOV"_sr, name, 3)) {
1371 return HTTP_MOVE;
1372 }
1373 break;
1374 case 'K':
1375 if (util::streq("LIN"_sr, name, 3)) {
1376 return HTTP_LINK;
1377 }
1378 if (util::streq("LOC"_sr, name, 3)) {
1379 return HTTP_LOCK;
1380 }
1381 break;
1382 case 'T':
1383 if (util::streq("POS"_sr, name, 3)) {
1384 return HTTP_POST;
1385 }
1386 break;
1387 case 'Y':
1388 if (util::streq("COP"_sr, name, 3)) {
1389 return HTTP_COPY;
1390 }
1391 break;
1392 }
1393 break;
1394 case 5:
1395 switch (name[4]) {
1396 case 'E':
1397 if (util::streq("MERG"_sr, name, 4)) {
1398 return HTTP_MERGE;
1399 }
1400 if (util::streq("PURG"_sr, name, 4)) {
1401 return HTTP_PURGE;
1402 }
1403 if (util::streq("TRAC"_sr, name, 4)) {
1404 return HTTP_TRACE;
1405 }
1406 break;
1407 case 'H':
1408 if (util::streq("PATC"_sr, name, 4)) {
1409 return HTTP_PATCH;
1410 }
1411 break;
1412 case 'L':
1413 if (util::streq("MKCO"_sr, name, 4)) {
1414 return HTTP_MKCOL;
1415 }
1416 break;
1417 }
1418 break;
1419 case 6:
1420 switch (name[5]) {
1421 case 'D':
1422 if (util::streq("REBIN"_sr, name, 5)) {
1423 return HTTP_REBIND;
1424 }
1425 if (util::streq("UNBIN"_sr, name, 5)) {
1426 return HTTP_UNBIND;
1427 }
1428 break;
1429 case 'E':
1430 if (util::streq("DELET"_sr, name, 5)) {
1431 return HTTP_DELETE;
1432 }
1433 if (util::streq("SOURC"_sr, name, 5)) {
1434 return HTTP_SOURCE;
1435 }
1436 break;
1437 case 'H':
1438 if (util::streq("SEARC"_sr, name, 5)) {
1439 return HTTP_SEARCH;
1440 }
1441 break;
1442 case 'K':
1443 if (util::streq("UNLIN"_sr, name, 5)) {
1444 return HTTP_UNLINK;
1445 }
1446 if (util::streq("UNLOC"_sr, name, 5)) {
1447 return HTTP_UNLOCK;
1448 }
1449 break;
1450 case 'T':
1451 if (util::streq("REPOR"_sr, name, 5)) {
1452 return HTTP_REPORT;
1453 }
1454 break;
1455 case 'Y':
1456 if (util::streq("NOTIF"_sr, name, 5)) {
1457 return HTTP_NOTIFY;
1458 }
1459 break;
1460 }
1461 break;
1462 case 7:
1463 switch (name[6]) {
1464 case 'H':
1465 if (util::streq("MSEARC"_sr, name, 6)) {
1466 return HTTP_MSEARCH;
1467 }
1468 break;
1469 case 'S':
1470 if (util::streq("OPTION"_sr, name, 6)) {
1471 return HTTP_OPTIONS;
1472 }
1473 break;
1474 case 'T':
1475 if (util::streq("CONNEC"_sr, name, 6)) {
1476 return HTTP_CONNECT;
1477 }
1478 break;
1479 }
1480 break;
1481 case 8:
1482 switch (name[7]) {
1483 case 'D':
1484 if (util::streq("PROPFIN"_sr, name, 7)) {
1485 return HTTP_PROPFIND;
1486 }
1487 break;
1488 case 'T':
1489 if (util::streq("CHECKOU"_sr, name, 7)) {
1490 return HTTP_CHECKOUT;
1491 }
1492 break;
1493 }
1494 break;
1495 case 9:
1496 switch (name[8]) {
1497 case 'E':
1498 if (util::streq("SUBSCRIB"_sr, name, 8)) {
1499 return HTTP_SUBSCRIBE;
1500 }
1501 break;
1502 case 'H':
1503 if (util::streq("PROPPATC"_sr, name, 8)) {
1504 return HTTP_PROPPATCH;
1505 }
1506 break;
1507 }
1508 break;
1509 case 10:
1510 switch (name[9]) {
1511 case 'R':
1512 if (util::streq("MKCALENDA"_sr, name, 9)) {
1513 return HTTP_MKCALENDAR;
1514 }
1515 break;
1516 case 'Y':
1517 if (util::streq("MKACTIVIT"_sr, name, 9)) {
1518 return HTTP_MKACTIVITY;
1519 }
1520 break;
1521 }
1522 break;
1523 case 11:
1524 switch (name[10]) {
1525 case 'E':
1526 if (util::streq("UNSUBSCRIB"_sr, name, 10)) {
1527 return HTTP_UNSUBSCRIBE;
1528 }
1529 break;
1530 }
1531 break;
1532 }
1533 return -1;
1534 }
1535
to_method_string(int method_token)1536 StringRef to_method_string(int method_token) {
1537 // we happened to use same value for method with llhttp.
1538 return StringRef{
1539 llhttp_method_name(static_cast<llhttp_method>(method_token))};
1540 }
1541
get_pure_path_component(const StringRef & uri)1542 StringRef get_pure_path_component(const StringRef &uri) {
1543 int rv;
1544
1545 http_parser_url u{};
1546 rv = http_parser_parse_url(uri.data(), uri.size(), 0, &u);
1547 if (rv != 0) {
1548 return StringRef{};
1549 }
1550
1551 if (u.field_set & (1 << UF_PATH)) {
1552 auto &f = u.field_data[UF_PATH];
1553 return StringRef{uri.data() + f.off, f.len};
1554 }
1555
1556 return "/"_sr;
1557 }
1558
construct_push_component(BlockAllocator & balloc,StringRef & scheme,StringRef & authority,StringRef & path,const StringRef & base,const StringRef & uri)1559 int construct_push_component(BlockAllocator &balloc, StringRef &scheme,
1560 StringRef &authority, StringRef &path,
1561 const StringRef &base, const StringRef &uri) {
1562 int rv;
1563 StringRef rel, relq;
1564
1565 if (uri.size() == 0) {
1566 return -1;
1567 }
1568
1569 http_parser_url u{};
1570
1571 rv = http_parser_parse_url(uri.data(), uri.size(), 0, &u);
1572
1573 if (rv != 0) {
1574 if (uri[0] == '/') {
1575 return -1;
1576 }
1577
1578 // treat link_url as relative URI.
1579 auto end = std::find(std::begin(uri), std::end(uri), '#');
1580 auto q = std::find(std::begin(uri), end, '?');
1581
1582 rel = StringRef{std::begin(uri), q};
1583 if (q != end) {
1584 relq = StringRef{q + 1, std::end(uri)};
1585 }
1586 } else {
1587 if (u.field_set & (1 << UF_SCHEMA)) {
1588 scheme = util::get_uri_field(uri.data(), u, UF_SCHEMA);
1589 }
1590
1591 if (u.field_set & (1 << UF_HOST)) {
1592 auto auth = util::get_uri_field(uri.data(), u, UF_HOST);
1593 auto len = auth.size();
1594 auto port_exists = u.field_set & (1 << UF_PORT);
1595 if (port_exists) {
1596 len += 1 + str_size("65535");
1597 }
1598 auto iov = make_byte_ref(balloc, len + 1);
1599 auto p = std::begin(iov);
1600 p = std::copy(std::begin(auth), std::end(auth), p);
1601 if (port_exists) {
1602 *p++ = ':';
1603 p = util::utos(p, u.port);
1604 }
1605 *p = '\0';
1606
1607 authority = StringRef{std::span{std::begin(iov), p}};
1608 }
1609
1610 if (u.field_set & (1 << UF_PATH)) {
1611 auto &f = u.field_data[UF_PATH];
1612 rel = StringRef{uri.data() + f.off, f.len};
1613 } else {
1614 rel = "/"_sr;
1615 }
1616
1617 if (u.field_set & (1 << UF_QUERY)) {
1618 auto &f = u.field_data[UF_QUERY];
1619 relq = StringRef{uri.data() + f.off, f.len};
1620 }
1621 }
1622
1623 path = path_join(balloc, base, StringRef{}, rel, relq);
1624
1625 return 0;
1626 }
1627
1628 namespace {
eat_file(InputIt first,InputIt last)1629 template <typename InputIt> InputIt eat_file(InputIt first, InputIt last) {
1630 if (first == last) {
1631 *first++ = '/';
1632 return first;
1633 }
1634
1635 if (*(last - 1) == '/') {
1636 return last;
1637 }
1638
1639 auto p = last;
1640 for (; p != first && *(p - 1) != '/'; --p)
1641 ;
1642 if (p == first) {
1643 // this should not happened in normal case, where we expect path
1644 // starts with '/'
1645 *first++ = '/';
1646 return first;
1647 }
1648
1649 return p;
1650 }
1651 } // namespace
1652
1653 namespace {
eat_dir(InputIt first,InputIt last)1654 template <typename InputIt> InputIt eat_dir(InputIt first, InputIt last) {
1655 auto p = eat_file(first, last);
1656
1657 --p;
1658
1659 assert(*p == '/');
1660
1661 return eat_file(first, p);
1662 }
1663 } // namespace
1664
path_join(BlockAllocator & balloc,const StringRef & base_path,const StringRef & base_query,const StringRef & rel_path,const StringRef & rel_query)1665 StringRef path_join(BlockAllocator &balloc, const StringRef &base_path,
1666 const StringRef &base_query, const StringRef &rel_path,
1667 const StringRef &rel_query) {
1668 auto res =
1669 make_byte_ref(balloc, std::max(static_cast<size_t>(1), base_path.size()) +
1670 rel_path.size() + 1 +
1671 std::max(base_query.size(), rel_query.size()) + 1);
1672 auto p = std::begin(res);
1673
1674 if (rel_path.empty()) {
1675 if (base_path.empty()) {
1676 *p++ = '/';
1677 } else {
1678 p = std::copy(std::begin(base_path), std::end(base_path), p);
1679 }
1680 if (rel_query.empty()) {
1681 if (!base_query.empty()) {
1682 *p++ = '?';
1683 p = std::copy(std::begin(base_query), std::end(base_query), p);
1684 }
1685 *p = '\0';
1686 return StringRef{std::span{std::begin(res), p}};
1687 }
1688 *p++ = '?';
1689 p = std::copy(std::begin(rel_query), std::end(rel_query), p);
1690 *p = '\0';
1691 return StringRef{std::span{std::begin(res), p}};
1692 }
1693
1694 auto first = std::begin(rel_path);
1695 auto last = std::end(rel_path);
1696
1697 if (rel_path[0] == '/') {
1698 *p++ = '/';
1699 ++first;
1700 for (; first != last && *first == '/'; ++first)
1701 ;
1702 } else if (base_path.empty()) {
1703 *p++ = '/';
1704 } else {
1705 p = std::copy(std::begin(base_path), std::end(base_path), p);
1706 }
1707
1708 for (; first != last;) {
1709 if (*first == '.') {
1710 if (first + 1 == last) {
1711 if (*(p - 1) != '/') {
1712 p = eat_file(std::begin(res), p);
1713 }
1714 break;
1715 }
1716 if (*(first + 1) == '/') {
1717 if (*(p - 1) != '/') {
1718 p = eat_file(std::begin(res), p);
1719 }
1720 first += 2;
1721 continue;
1722 }
1723 if (*(first + 1) == '.') {
1724 if (first + 2 == last) {
1725 p = eat_dir(std::begin(res), p);
1726 break;
1727 }
1728 if (*(first + 2) == '/') {
1729 p = eat_dir(std::begin(res), p);
1730 first += 3;
1731 continue;
1732 }
1733 }
1734 }
1735 if (*(p - 1) != '/') {
1736 p = eat_file(std::begin(res), p);
1737 }
1738 auto slash = std::find(first, last, '/');
1739 if (slash == last) {
1740 p = std::copy(first, last, p);
1741 break;
1742 }
1743 p = std::copy(first, slash + 1, p);
1744 first = slash + 1;
1745 for (; first != last && *first == '/'; ++first)
1746 ;
1747 }
1748 if (!rel_query.empty()) {
1749 *p++ = '?';
1750 p = std::copy(std::begin(rel_query), std::end(rel_query), p);
1751 }
1752 *p = '\0';
1753 return StringRef{std::span{std::begin(res), p}};
1754 }
1755
normalize_path(BlockAllocator & balloc,const StringRef & path,const StringRef & query)1756 StringRef normalize_path(BlockAllocator &balloc, const StringRef &path,
1757 const StringRef &query) {
1758 // First, decode %XX for unreserved characters, then do
1759 // http2::path_join
1760
1761 // We won't find %XX if length is less than 3.
1762 if (path.size() < 3 ||
1763 std::find(std::begin(path), std::end(path), '%') == std::end(path)) {
1764 return path_join(balloc, StringRef{}, StringRef{}, path, query);
1765 }
1766
1767 // includes last terminal NULL.
1768 auto result = make_byte_ref(balloc, path.size() + 1);
1769 auto p = std::begin(result);
1770
1771 auto it = std::begin(path);
1772 for (; it + 2 < std::end(path);) {
1773 if (*it == '%') {
1774 if (util::is_hex_digit(*(it + 1)) && util::is_hex_digit(*(it + 2))) {
1775 auto c =
1776 (util::hex_to_uint(*(it + 1)) << 4) + util::hex_to_uint(*(it + 2));
1777 if (util::in_rfc3986_unreserved_chars(c)) {
1778 *p++ = c;
1779
1780 it += 3;
1781
1782 continue;
1783 }
1784 *p++ = '%';
1785 *p++ = util::upcase(*(it + 1));
1786 *p++ = util::upcase(*(it + 2));
1787
1788 it += 3;
1789
1790 continue;
1791 }
1792 }
1793 *p++ = *it++;
1794 }
1795
1796 p = std::copy(it, std::end(path), p);
1797 *p = '\0';
1798
1799 return path_join(balloc, StringRef{}, StringRef{},
1800 StringRef{std::span{std::begin(result), p}}, query);
1801 }
1802
normalize_path_colon(BlockAllocator & balloc,const StringRef & path,const StringRef & query)1803 StringRef normalize_path_colon(BlockAllocator &balloc, const StringRef &path,
1804 const StringRef &query) {
1805 // First, decode %XX for unreserved characters and ':', then do
1806 // http2::path_join
1807
1808 // We won't find %XX if length is less than 3.
1809 if (path.size() < 3 ||
1810 std::find(std::begin(path), std::end(path), '%') == std::end(path)) {
1811 return path_join(balloc, StringRef{}, StringRef{}, path, query);
1812 }
1813
1814 // includes last terminal NULL.
1815 auto result = make_byte_ref(balloc, path.size() + 1);
1816 auto p = std::begin(result);
1817
1818 auto it = std::begin(path);
1819 for (; it + 2 < std::end(path);) {
1820 if (*it == '%') {
1821 if (util::is_hex_digit(*(it + 1)) && util::is_hex_digit(*(it + 2))) {
1822 auto c =
1823 (util::hex_to_uint(*(it + 1)) << 4) + util::hex_to_uint(*(it + 2));
1824 if (util::in_rfc3986_unreserved_chars(c) || c == ':') {
1825 *p++ = c;
1826
1827 it += 3;
1828
1829 continue;
1830 }
1831 *p++ = '%';
1832 *p++ = util::upcase(*(it + 1));
1833 *p++ = util::upcase(*(it + 2));
1834
1835 it += 3;
1836
1837 continue;
1838 }
1839 }
1840 *p++ = *it++;
1841 }
1842
1843 p = std::copy(it, std::end(path), p);
1844 *p = '\0';
1845
1846 return path_join(balloc, StringRef{}, StringRef{},
1847 StringRef{std::span{std::begin(result), p}}, query);
1848 }
1849
normalize_path(const StringRef & path,const StringRef & query)1850 std::string normalize_path(const StringRef &path, const StringRef &query) {
1851 BlockAllocator balloc(1024, 1024);
1852
1853 return std::string{normalize_path(balloc, path, query)};
1854 }
1855
rewrite_clean_path(BlockAllocator & balloc,const StringRef & src)1856 StringRef rewrite_clean_path(BlockAllocator &balloc, const StringRef &src) {
1857 if (src.empty() || src[0] != '/') {
1858 return src;
1859 }
1860 // probably, not necessary most of the case, but just in case.
1861 auto fragment = std::find(std::begin(src), std::end(src), '#');
1862 auto raw_query = std::find(std::begin(src), fragment, '?');
1863 auto query = raw_query;
1864 if (query != fragment) {
1865 ++query;
1866 }
1867 return normalize_path(balloc, StringRef{std::begin(src), raw_query},
1868 StringRef{query, fragment});
1869 }
1870
copy_lower(BlockAllocator & balloc,const StringRef & src)1871 StringRef copy_lower(BlockAllocator &balloc, const StringRef &src) {
1872 auto iov = make_byte_ref(balloc, src.size() + 1);
1873 auto p = std::begin(iov);
1874 p = std::copy(std::begin(src), std::end(src), p);
1875 *p = '\0';
1876 util::inp_strlower(std::begin(iov), p);
1877 return StringRef{std::span{std::begin(iov), p}};
1878 }
1879
contains_trailers(const StringRef & s)1880 bool contains_trailers(const StringRef &s) {
1881 constexpr auto trailers = "trailers"_sr;
1882
1883 for (auto p = std::begin(s), end = std::end(s);; ++p) {
1884 p = std::find_if(p, end, [](char c) { return c != ' ' && c != '\t'; });
1885 if (p == end || static_cast<size_t>(end - p) < trailers.size()) {
1886 return false;
1887 }
1888 if (util::strieq(trailers, StringRef{p, p + trailers.size()})) {
1889 // Make sure that there is no character other than white spaces
1890 // before next "," or end of string.
1891 p = std::find_if(p + trailers.size(), end,
1892 [](char c) { return c != ' ' && c != '\t'; });
1893 if (p == end || *p == ',') {
1894 return true;
1895 }
1896 }
1897 // Skip to next ",".
1898 p = std::find_if(p, end, [](char c) { return c == ','; });
1899 if (p == end) {
1900 return false;
1901 }
1902 }
1903 }
1904
make_websocket_accept_token(uint8_t * dest,const StringRef & key)1905 StringRef make_websocket_accept_token(uint8_t *dest, const StringRef &key) {
1906 static constexpr char magic[] = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
1907 std::array<char, base64::encode_length(16) + str_size(magic)> s;
1908 auto p = std::copy(std::begin(key), std::end(key), std::begin(s));
1909 std::copy_n(magic, str_size(magic), p);
1910
1911 std::array<uint8_t, 20> h;
1912 if (util::sha1(h.data(), StringRef{s}) != 0) {
1913 return StringRef{};
1914 }
1915
1916 auto end = base64::encode(std::begin(h), std::end(h), dest);
1917 return StringRef{std::span{dest, end}};
1918 }
1919
legacy_http1(int major,int minor)1920 bool legacy_http1(int major, int minor) {
1921 return major <= 0 || (major == 1 && minor == 0);
1922 }
1923
check_transfer_encoding(const StringRef & s)1924 bool check_transfer_encoding(const StringRef &s) {
1925 if (s.empty()) {
1926 return false;
1927 }
1928
1929 auto it = std::begin(s);
1930
1931 for (;;) {
1932 // token
1933 if (!util::in_token(*it)) {
1934 return false;
1935 }
1936
1937 ++it;
1938
1939 for (; it != std::end(s) && util::in_token(*it); ++it)
1940 ;
1941
1942 if (it == std::end(s)) {
1943 return true;
1944 }
1945
1946 for (;;) {
1947 // OWS
1948 it = skip_lws(it, std::end(s));
1949 if (it == std::end(s)) {
1950 return false;
1951 }
1952
1953 if (*it == ',') {
1954 ++it;
1955
1956 it = skip_lws(it, std::end(s));
1957 if (it == std::end(s)) {
1958 return false;
1959 }
1960
1961 break;
1962 }
1963
1964 if (*it != ';') {
1965 return false;
1966 }
1967
1968 ++it;
1969
1970 // transfer-parameter follows
1971
1972 // OWS
1973 it = skip_lws(it, std::end(s));
1974 if (it == std::end(s)) {
1975 return false;
1976 }
1977
1978 // token
1979 if (!util::in_token(*it)) {
1980 return false;
1981 }
1982
1983 ++it;
1984
1985 for (; it != std::end(s) && util::in_token(*it); ++it)
1986 ;
1987
1988 if (it == std::end(s)) {
1989 return false;
1990 }
1991
1992 // No BWS allowed
1993 if (*it != '=') {
1994 return false;
1995 }
1996
1997 ++it;
1998
1999 if (util::in_token(*it)) {
2000 // token
2001 ++it;
2002
2003 for (; it != std::end(s) && util::in_token(*it); ++it)
2004 ;
2005 } else if (*it == '"') {
2006 // quoted-string
2007 ++it;
2008
2009 it = skip_to_right_dquote(it, std::end(s));
2010 if (it == std::end(s)) {
2011 return false;
2012 }
2013
2014 ++it;
2015 } else {
2016 return false;
2017 }
2018
2019 if (it == std::end(s)) {
2020 return true;
2021 }
2022 }
2023 }
2024 }
2025
2026 } // namespace http2
2027
2028 } // namespace nghttp2
2029