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 "util.h"
26
27 #ifdef HAVE_TIME_H
28 # include <time.h>
29 #endif // HAVE_TIME_H
30 #include <sys/types.h>
31 #ifdef HAVE_SYS_SOCKET_H
32 # include <sys/socket.h>
33 #endif // HAVE_SYS_SOCKET_H
34 #ifdef HAVE_NETDB_H
35 # include <netdb.h>
36 #endif // HAVE_NETDB_H
37 #include <sys/stat.h>
38 #ifdef HAVE_FCNTL_H
39 # include <fcntl.h>
40 #endif // HAVE_FCNTL_H
41 #ifdef HAVE_NETINET_IN_H
42 # include <netinet/in.h>
43 #endif // HAVE_NETINET_IN_H
44 #ifdef _WIN32
45 # include <ws2tcpip.h>
46 # include <boost/date_time/posix_time/posix_time.hpp>
47 #else // !_WIN32
48 # include <netinet/tcp.h>
49 #endif // !_WIN32
50 #ifdef HAVE_ARPA_INET_H
51 # include <arpa/inet.h>
52 #endif // HAVE_ARPA_INET_H
53
54 #include <cmath>
55 #include <cerrno>
56 #include <cassert>
57 #include <cstdio>
58 #include <cstring>
59 #include <iostream>
60 #include <fstream>
61
62 #include <openssl/evp.h>
63
64 #include <nghttp2/nghttp2.h>
65
66 #include "ssl_compat.h"
67 #include "timegm.h"
68
69 namespace nghttp2 {
70
71 namespace util {
72
73 #ifndef _WIN32
74 namespace {
nghttp2_inet_pton(int af,const char * src,void * dst)75 int nghttp2_inet_pton(int af, const char *src, void *dst) {
76 return inet_pton(af, src, dst);
77 }
78 } // namespace
79 #else // _WIN32
80 namespace {
81 // inet_pton-wrapper for Windows
82 int nghttp2_inet_pton(int af, const char *src, void *dst) {
83 # if _WIN32_WINNT >= 0x0600
84 return InetPtonA(af, src, dst);
85 # else
86 // the function takes a 'char*', so we need to make a copy
87 char addr[INET6_ADDRSTRLEN + 1];
88 strncpy(addr, src, sizeof(addr));
89 addr[sizeof(addr) - 1] = 0;
90
91 int size = sizeof(struct in6_addr);
92
93 if (WSAStringToAddress(addr, af, NULL, (LPSOCKADDR)dst, &size) == 0)
94 return 1;
95 return 0;
96 # endif
97 }
98 } // namespace
99 #endif // _WIN32
100
101 const char UPPER_XDIGITS[] = "0123456789ABCDEF";
102
in_rfc3986_unreserved_chars(const char c)103 bool in_rfc3986_unreserved_chars(const char c) {
104 static constexpr char unreserved[] = {'-', '.', '_', '~'};
105 return is_alpha(c) || is_digit(c) ||
106 std::find(std::begin(unreserved), std::end(unreserved), c) !=
107 std::end(unreserved);
108 }
109
in_rfc3986_sub_delims(const char c)110 bool in_rfc3986_sub_delims(const char c) {
111 static constexpr char sub_delims[] = {'!', '$', '&', '\'', '(', ')',
112 '*', '+', ',', ';', '='};
113 return std::find(std::begin(sub_delims), std::end(sub_delims), c) !=
114 std::end(sub_delims);
115 }
116
percent_encode(const unsigned char * target,size_t len)117 std::string percent_encode(const unsigned char *target, size_t len) {
118 std::string dest;
119 for (size_t i = 0; i < len; ++i) {
120 unsigned char c = target[i];
121
122 if (in_rfc3986_unreserved_chars(c)) {
123 dest += c;
124 } else {
125 dest += '%';
126 dest += UPPER_XDIGITS[c >> 4];
127 dest += UPPER_XDIGITS[(c & 0x0f)];
128 }
129 }
130 return dest;
131 }
132
percent_encode(const std::string & target)133 std::string percent_encode(const std::string &target) {
134 return percent_encode(reinterpret_cast<const unsigned char *>(target.c_str()),
135 target.size());
136 }
137
percent_encode_path(const std::string & s)138 std::string percent_encode_path(const std::string &s) {
139 std::string dest;
140 for (auto c : s) {
141 if (in_rfc3986_unreserved_chars(c) || in_rfc3986_sub_delims(c) ||
142 c == '/') {
143 dest += c;
144 continue;
145 }
146
147 dest += '%';
148 dest += UPPER_XDIGITS[(c >> 4) & 0x0f];
149 dest += UPPER_XDIGITS[(c & 0x0f)];
150 }
151 return dest;
152 }
153
in_token(char c)154 bool in_token(char c) {
155 static constexpr char extra[] = {'!', '#', '$', '%', '&', '\'', '*', '+',
156 '-', '.', '^', '_', '`', '|', '~'};
157 return is_alpha(c) || is_digit(c) ||
158 std::find(std::begin(extra), std::end(extra), c) != std::end(extra);
159 }
160
in_attr_char(char c)161 bool in_attr_char(char c) {
162 static constexpr char bad[] = {'*', '\'', '%'};
163 return util::in_token(c) &&
164 std::find(std::begin(bad), std::end(bad), c) == std::end(bad);
165 }
166
percent_encode_token(BlockAllocator & balloc,const StringRef & target)167 StringRef percent_encode_token(BlockAllocator &balloc,
168 const StringRef &target) {
169 auto iov = make_byte_ref(balloc, target.size() * 3 + 1);
170 auto p = iov.base;
171
172 for (auto first = std::begin(target); first != std::end(target); ++first) {
173 uint8_t c = *first;
174
175 if (c != '%' && in_token(c)) {
176 *p++ = c;
177 continue;
178 }
179
180 *p++ = '%';
181 *p++ = UPPER_XDIGITS[c >> 4];
182 *p++ = UPPER_XDIGITS[(c & 0x0f)];
183 }
184
185 *p = '\0';
186
187 return StringRef{iov.base, p};
188 }
189
hex_to_uint(char c)190 uint32_t hex_to_uint(char c) {
191 if (c <= '9') {
192 return c - '0';
193 }
194 if (c <= 'Z') {
195 return c - 'A' + 10;
196 }
197 if (c <= 'z') {
198 return c - 'a' + 10;
199 }
200 return 256;
201 }
202
quote_string(BlockAllocator & balloc,const StringRef & target)203 StringRef quote_string(BlockAllocator &balloc, const StringRef &target) {
204 auto cnt = std::count(std::begin(target), std::end(target), '"');
205
206 if (cnt == 0) {
207 return make_string_ref(balloc, target);
208 }
209
210 auto iov = make_byte_ref(balloc, target.size() + cnt + 1);
211 auto p = iov.base;
212
213 for (auto c : target) {
214 if (c == '"') {
215 *p++ = '\\';
216 *p++ = '"';
217 } else {
218 *p++ = c;
219 }
220 }
221 *p = '\0';
222
223 return StringRef{iov.base, p};
224 }
225
226 namespace {
227 template <typename Iterator>
cpydig(Iterator d,uint32_t n,size_t len)228 Iterator cpydig(Iterator d, uint32_t n, size_t len) {
229 auto p = d + len - 1;
230
231 do {
232 *p-- = (n % 10) + '0';
233 n /= 10;
234 } while (p >= d);
235
236 return d + len;
237 }
238 } // namespace
239
240 namespace {
241 constexpr const char *MONTH[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
242 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
243 constexpr const char *DAY_OF_WEEK[] = {"Sun", "Mon", "Tue", "Wed",
244 "Thu", "Fri", "Sat"};
245 } // namespace
246
http_date(time_t t)247 std::string http_date(time_t t) {
248 /* Sat, 27 Sep 2014 06:31:15 GMT */
249 std::string res(29, 0);
250 http_date(&res[0], t);
251 return res;
252 }
253
http_date(char * res,time_t t)254 char *http_date(char *res, time_t t) {
255 struct tm tms;
256
257 if (gmtime_r(&t, &tms) == nullptr) {
258 return res;
259 }
260
261 auto p = res;
262
263 auto s = DAY_OF_WEEK[tms.tm_wday];
264 p = std::copy_n(s, 3, p);
265 *p++ = ',';
266 *p++ = ' ';
267 p = cpydig(p, tms.tm_mday, 2);
268 *p++ = ' ';
269 s = MONTH[tms.tm_mon];
270 p = std::copy_n(s, 3, p);
271 *p++ = ' ';
272 p = cpydig(p, tms.tm_year + 1900, 4);
273 *p++ = ' ';
274 p = cpydig(p, tms.tm_hour, 2);
275 *p++ = ':';
276 p = cpydig(p, tms.tm_min, 2);
277 *p++ = ':';
278 p = cpydig(p, tms.tm_sec, 2);
279 s = " GMT";
280 p = std::copy_n(s, 4, p);
281
282 return p;
283 }
284
common_log_date(time_t t)285 std::string common_log_date(time_t t) {
286 // 03/Jul/2014:00:19:38 +0900
287 std::string res(26, 0);
288 common_log_date(&res[0], t);
289 return res;
290 }
291
common_log_date(char * res,time_t t)292 char *common_log_date(char *res, time_t t) {
293 struct tm tms;
294
295 if (localtime_r(&t, &tms) == nullptr) {
296 return res;
297 }
298
299 auto p = res;
300
301 p = cpydig(p, tms.tm_mday, 2);
302 *p++ = '/';
303 auto s = MONTH[tms.tm_mon];
304 p = std::copy_n(s, 3, p);
305 *p++ = '/';
306 p = cpydig(p, tms.tm_year + 1900, 4);
307 *p++ = ':';
308 p = cpydig(p, tms.tm_hour, 2);
309 *p++ = ':';
310 p = cpydig(p, tms.tm_min, 2);
311 *p++ = ':';
312 p = cpydig(p, tms.tm_sec, 2);
313 *p++ = ' ';
314
315 #ifdef HAVE_STRUCT_TM_TM_GMTOFF
316 auto gmtoff = tms.tm_gmtoff;
317 #else // !HAVE_STRUCT_TM_TM_GMTOFF
318 auto gmtoff = nghttp2_timegm(&tms) - t;
319 #endif // !HAVE_STRUCT_TM_TM_GMTOFF
320 if (gmtoff >= 0) {
321 *p++ = '+';
322 } else {
323 *p++ = '-';
324 gmtoff = -gmtoff;
325 }
326
327 p = cpydig(p, gmtoff / 3600, 2);
328 p = cpydig(p, (gmtoff % 3600) / 60, 2);
329
330 return p;
331 }
332
iso8601_date(int64_t ms)333 std::string iso8601_date(int64_t ms) {
334 // 2014-11-15T12:58:24.741Z
335 // 2014-11-15T12:58:24.741+09:00
336 std::string res(29, 0);
337 auto p = iso8601_date(&res[0], ms);
338 res.resize(p - &res[0]);
339 return res;
340 }
341
iso8601_date(char * res,int64_t ms)342 char *iso8601_date(char *res, int64_t ms) {
343 time_t sec = ms / 1000;
344
345 tm tms;
346 if (localtime_r(&sec, &tms) == nullptr) {
347 return res;
348 }
349
350 auto p = res;
351
352 p = cpydig(p, tms.tm_year + 1900, 4);
353 *p++ = '-';
354 p = cpydig(p, tms.tm_mon + 1, 2);
355 *p++ = '-';
356 p = cpydig(p, tms.tm_mday, 2);
357 *p++ = 'T';
358 p = cpydig(p, tms.tm_hour, 2);
359 *p++ = ':';
360 p = cpydig(p, tms.tm_min, 2);
361 *p++ = ':';
362 p = cpydig(p, tms.tm_sec, 2);
363 *p++ = '.';
364 p = cpydig(p, ms % 1000, 3);
365
366 #ifdef HAVE_STRUCT_TM_TM_GMTOFF
367 auto gmtoff = tms.tm_gmtoff;
368 #else // !HAVE_STRUCT_TM_TM_GMTOFF
369 auto gmtoff = nghttp2_timegm(&tms) - sec;
370 #endif // !HAVE_STRUCT_TM_TM_GMTOFF
371 if (gmtoff == 0) {
372 *p++ = 'Z';
373 } else {
374 if (gmtoff > 0) {
375 *p++ = '+';
376 } else {
377 *p++ = '-';
378 gmtoff = -gmtoff;
379 }
380 p = cpydig(p, gmtoff / 3600, 2);
381 *p++ = ':';
382 p = cpydig(p, (gmtoff % 3600) / 60, 2);
383 }
384
385 return p;
386 }
387
388 #ifdef _WIN32
389 namespace bt = boost::posix_time;
390 // one-time definition of the locale that is used to parse UTC strings
391 // (note that the time_input_facet is ref-counted and deleted automatically)
392 static const std::locale
393 ptime_locale(std::locale::classic(),
394 new bt::time_input_facet("%a, %d %b %Y %H:%M:%S GMT"));
395 #endif //_WIN32
396
parse_http_date(const StringRef & s)397 time_t parse_http_date(const StringRef &s) {
398 #ifdef _WIN32
399 // there is no strptime - use boost
400 std::stringstream sstr(s.str());
401 sstr.imbue(ptime_locale);
402 bt::ptime ltime;
403 sstr >> ltime;
404 if (!sstr)
405 return 0;
406
407 return boost::posix_time::to_time_t(ltime);
408 #else // !_WIN32
409 tm tm{};
410 char *r = strptime(s.c_str(), "%a, %d %b %Y %H:%M:%S GMT", &tm);
411 if (r == 0) {
412 return 0;
413 }
414 return nghttp2_timegm_without_yday(&tm);
415 #endif // !_WIN32
416 }
417
parse_openssl_asn1_time_print(const StringRef & s)418 time_t parse_openssl_asn1_time_print(const StringRef &s) {
419 tm tm{};
420 auto r = strptime(s.c_str(), "%b %d %H:%M:%S %Y GMT", &tm);
421 if (r == nullptr) {
422 return 0;
423 }
424 return nghttp2_timegm_without_yday(&tm);
425 }
426
upcase(char c)427 char upcase(char c) {
428 if ('a' <= c && c <= 'z') {
429 return c - 'a' + 'A';
430 } else {
431 return c;
432 }
433 }
434
format_hex(const unsigned char * s,size_t len)435 std::string format_hex(const unsigned char *s, size_t len) {
436 std::string res;
437 res.resize(len * 2);
438
439 for (size_t i = 0; i < len; ++i) {
440 unsigned char c = s[i];
441
442 res[i * 2] = LOWER_XDIGITS[c >> 4];
443 res[i * 2 + 1] = LOWER_XDIGITS[c & 0x0f];
444 }
445 return res;
446 }
447
format_hex(BlockAllocator & balloc,const StringRef & s)448 StringRef format_hex(BlockAllocator &balloc, const StringRef &s) {
449 auto iov = make_byte_ref(balloc, s.size() * 2 + 1);
450 auto p = iov.base;
451
452 for (auto cc : s) {
453 uint8_t c = cc;
454 *p++ = LOWER_XDIGITS[c >> 4];
455 *p++ = LOWER_XDIGITS[c & 0xf];
456 }
457
458 *p = '\0';
459
460 return StringRef{iov.base, p};
461 }
462
to_token68(std::string & base64str)463 void to_token68(std::string &base64str) {
464 std::transform(std::begin(base64str), std::end(base64str),
465 std::begin(base64str), [](char c) {
466 switch (c) {
467 case '+':
468 return '-';
469 case '/':
470 return '_';
471 default:
472 return c;
473 }
474 });
475 base64str.erase(std::find(std::begin(base64str), std::end(base64str), '='),
476 std::end(base64str));
477 }
478
to_base64(BlockAllocator & balloc,const StringRef & token68str)479 StringRef to_base64(BlockAllocator &balloc, const StringRef &token68str) {
480 // At most 3 padding '='
481 auto len = token68str.size() + 3;
482 auto iov = make_byte_ref(balloc, len + 1);
483 auto p = iov.base;
484
485 p = std::transform(std::begin(token68str), std::end(token68str), p,
486 [](char c) {
487 switch (c) {
488 case '-':
489 return '+';
490 case '_':
491 return '/';
492 default:
493 return c;
494 }
495 });
496
497 auto rem = token68str.size() & 0x3;
498 if (rem) {
499 p = std::fill_n(p, 4 - rem, '=');
500 }
501
502 *p = '\0';
503
504 return StringRef{iov.base, p};
505 }
506
507 namespace {
508 // Calculates Damerau–Levenshtein distance between c-string a and b
509 // with given costs. swapcost, subcost, addcost and delcost are cost
510 // to swap 2 adjacent characters, substitute characters, add character
511 // and delete character respectively.
levenshtein(const char * a,int alen,const char * b,int blen,int swapcost,int subcost,int addcost,int delcost)512 int levenshtein(const char *a, int alen, const char *b, int blen, int swapcost,
513 int subcost, int addcost, int delcost) {
514 auto dp = std::vector<std::vector<int>>(3, std::vector<int>(blen + 1));
515 for (int i = 0; i <= blen; ++i) {
516 dp[1][i] = i;
517 }
518 for (int i = 1; i <= alen; ++i) {
519 dp[0][0] = i;
520 for (int j = 1; j <= blen; ++j) {
521 dp[0][j] = dp[1][j - 1] + (a[i - 1] == b[j - 1] ? 0 : subcost);
522 if (i >= 2 && j >= 2 && a[i - 1] != b[j - 1] && a[i - 2] == b[j - 1] &&
523 a[i - 1] == b[j - 2]) {
524 dp[0][j] = std::min(dp[0][j], dp[2][j - 2] + swapcost);
525 }
526 dp[0][j] = std::min(dp[0][j],
527 std::min(dp[1][j] + delcost, dp[0][j - 1] + addcost));
528 }
529 std::rotate(std::begin(dp), std::begin(dp) + 2, std::end(dp));
530 }
531 return dp[1][blen];
532 }
533 } // namespace
534
show_candidates(const char * unkopt,const option * options)535 void show_candidates(const char *unkopt, const option *options) {
536 for (; *unkopt == '-'; ++unkopt)
537 ;
538 if (*unkopt == '\0') {
539 return;
540 }
541 auto unkoptend = unkopt;
542 for (; *unkoptend && *unkoptend != '='; ++unkoptend)
543 ;
544 auto unkoptlen = unkoptend - unkopt;
545 if (unkoptlen == 0) {
546 return;
547 }
548 int prefix_match = 0;
549 auto cands = std::vector<std::pair<int, const char *>>();
550 for (size_t i = 0; options[i].name != nullptr; ++i) {
551 auto optnamelen = strlen(options[i].name);
552 // Use cost 0 for prefix match
553 if (istarts_with(options[i].name, options[i].name + optnamelen, unkopt,
554 unkopt + unkoptlen)) {
555 if (optnamelen == static_cast<size_t>(unkoptlen)) {
556 // Exact match, then we don't show any condidates.
557 return;
558 }
559 ++prefix_match;
560 cands.emplace_back(0, options[i].name);
561 continue;
562 }
563 // Use cost 0 for suffix match, but match at least 3 characters
564 if (unkoptlen >= 3 &&
565 iends_with(options[i].name, options[i].name + optnamelen, unkopt,
566 unkopt + unkoptlen)) {
567 cands.emplace_back(0, options[i].name);
568 continue;
569 }
570 // cost values are borrowed from git, help.c.
571 int sim =
572 levenshtein(unkopt, unkoptlen, options[i].name, optnamelen, 0, 2, 1, 3);
573 cands.emplace_back(sim, options[i].name);
574 }
575 if (prefix_match == 1 || cands.empty()) {
576 return;
577 }
578 std::sort(std::begin(cands), std::end(cands));
579 int threshold = cands[0].first;
580 // threshold value is a magic value.
581 if (threshold > 6) {
582 return;
583 }
584 std::cerr << "\nDid you mean:\n";
585 for (auto &item : cands) {
586 if (item.first > threshold) {
587 break;
588 }
589 std::cerr << "\t--" << item.second << "\n";
590 }
591 }
592
has_uri_field(const http_parser_url & u,http_parser_url_fields field)593 bool has_uri_field(const http_parser_url &u, http_parser_url_fields field) {
594 return u.field_set & (1 << field);
595 }
596
fieldeq(const char * uri1,const http_parser_url & u1,const char * uri2,const http_parser_url & u2,http_parser_url_fields field)597 bool fieldeq(const char *uri1, const http_parser_url &u1, const char *uri2,
598 const http_parser_url &u2, http_parser_url_fields field) {
599 if (!has_uri_field(u1, field)) {
600 if (!has_uri_field(u2, field)) {
601 return true;
602 } else {
603 return false;
604 }
605 } else if (!has_uri_field(u2, field)) {
606 return false;
607 }
608 if (u1.field_data[field].len != u2.field_data[field].len) {
609 return false;
610 }
611 return memcmp(uri1 + u1.field_data[field].off,
612 uri2 + u2.field_data[field].off, u1.field_data[field].len) == 0;
613 }
614
fieldeq(const char * uri,const http_parser_url & u,http_parser_url_fields field,const char * t)615 bool fieldeq(const char *uri, const http_parser_url &u,
616 http_parser_url_fields field, const char *t) {
617 return fieldeq(uri, u, field, StringRef{t});
618 }
619
fieldeq(const char * uri,const http_parser_url & u,http_parser_url_fields field,const StringRef & t)620 bool fieldeq(const char *uri, const http_parser_url &u,
621 http_parser_url_fields field, const StringRef &t) {
622 if (!has_uri_field(u, field)) {
623 return t.empty();
624 }
625 auto &f = u.field_data[field];
626 return StringRef{uri + f.off, f.len} == t;
627 }
628
get_uri_field(const char * uri,const http_parser_url & u,http_parser_url_fields field)629 StringRef get_uri_field(const char *uri, const http_parser_url &u,
630 http_parser_url_fields field) {
631 if (!util::has_uri_field(u, field)) {
632 return StringRef{};
633 }
634
635 return StringRef{uri + u.field_data[field].off, u.field_data[field].len};
636 }
637
get_default_port(const char * uri,const http_parser_url & u)638 uint16_t get_default_port(const char *uri, const http_parser_url &u) {
639 if (util::fieldeq(uri, u, UF_SCHEMA, "https")) {
640 return 443;
641 } else if (util::fieldeq(uri, u, UF_SCHEMA, "http")) {
642 return 80;
643 } else {
644 return 443;
645 }
646 }
647
porteq(const char * uri1,const http_parser_url & u1,const char * uri2,const http_parser_url & u2)648 bool porteq(const char *uri1, const http_parser_url &u1, const char *uri2,
649 const http_parser_url &u2) {
650 uint16_t port1, port2;
651 port1 =
652 util::has_uri_field(u1, UF_PORT) ? u1.port : get_default_port(uri1, u1);
653 port2 =
654 util::has_uri_field(u2, UF_PORT) ? u2.port : get_default_port(uri2, u2);
655 return port1 == port2;
656 }
657
write_uri_field(std::ostream & o,const char * uri,const http_parser_url & u,http_parser_url_fields field)658 void write_uri_field(std::ostream &o, const char *uri, const http_parser_url &u,
659 http_parser_url_fields field) {
660 if (util::has_uri_field(u, field)) {
661 o.write(uri + u.field_data[field].off, u.field_data[field].len);
662 }
663 }
664
numeric_host(const char * hostname)665 bool numeric_host(const char *hostname) {
666 return numeric_host(hostname, AF_INET) || numeric_host(hostname, AF_INET6);
667 }
668
numeric_host(const char * hostname,int family)669 bool numeric_host(const char *hostname, int family) {
670 int rv;
671 std::array<uint8_t, sizeof(struct in6_addr)> dst;
672
673 rv = nghttp2_inet_pton(family, hostname, dst.data());
674
675 return rv == 1;
676 }
677
numeric_name(const struct sockaddr * sa,socklen_t salen)678 std::string numeric_name(const struct sockaddr *sa, socklen_t salen) {
679 std::array<char, NI_MAXHOST> host;
680 auto rv = getnameinfo(sa, salen, host.data(), host.size(), nullptr, 0,
681 NI_NUMERICHOST);
682 if (rv != 0) {
683 return "unknown";
684 }
685 return host.data();
686 }
687
to_numeric_addr(const Address * addr)688 std::string to_numeric_addr(const Address *addr) {
689 auto family = addr->su.storage.ss_family;
690 #ifndef _WIN32
691 if (family == AF_UNIX) {
692 return addr->su.un.sun_path;
693 }
694 #endif // !_WIN32
695
696 std::array<char, NI_MAXHOST> host;
697 std::array<char, NI_MAXSERV> serv;
698 auto rv =
699 getnameinfo(&addr->su.sa, addr->len, host.data(), host.size(),
700 serv.data(), serv.size(), NI_NUMERICHOST | NI_NUMERICSERV);
701 if (rv != 0) {
702 return "unknown";
703 }
704
705 auto hostlen = strlen(host.data());
706 auto servlen = strlen(serv.data());
707
708 std::string s;
709 char *p;
710 if (family == AF_INET6) {
711 s.resize(hostlen + servlen + 2 + 1);
712 p = &s[0];
713 *p++ = '[';
714 p = std::copy_n(host.data(), hostlen, p);
715 *p++ = ']';
716 } else {
717 s.resize(hostlen + servlen + 1);
718 p = &s[0];
719 p = std::copy_n(host.data(), hostlen, p);
720 }
721 *p++ = ':';
722 std::copy_n(serv.data(), servlen, p);
723
724 return s;
725 }
726
set_port(Address & addr,uint16_t port)727 void set_port(Address &addr, uint16_t port) {
728 switch (addr.su.storage.ss_family) {
729 case AF_INET:
730 addr.su.in.sin_port = htons(port);
731 break;
732 case AF_INET6:
733 addr.su.in6.sin6_port = htons(port);
734 break;
735 }
736 }
737
ascii_dump(const uint8_t * data,size_t len)738 std::string ascii_dump(const uint8_t *data, size_t len) {
739 std::string res;
740
741 for (size_t i = 0; i < len; ++i) {
742 auto c = data[i];
743
744 if (c >= 0x20 && c < 0x7f) {
745 res += c;
746 } else {
747 res += '.';
748 }
749 }
750
751 return res;
752 }
753
get_exec_path(int argc,char ** const argv,const char * cwd)754 char *get_exec_path(int argc, char **const argv, const char *cwd) {
755 if (argc == 0 || cwd == nullptr) {
756 return nullptr;
757 }
758
759 auto argv0 = argv[0];
760 auto len = strlen(argv0);
761
762 char *path;
763
764 if (argv0[0] == '/') {
765 path = static_cast<char *>(malloc(len + 1));
766 if (path == nullptr) {
767 return nullptr;
768 }
769 memcpy(path, argv0, len + 1);
770 } else {
771 auto cwdlen = strlen(cwd);
772 path = static_cast<char *>(malloc(len + 1 + cwdlen + 1));
773 if (path == nullptr) {
774 return nullptr;
775 }
776 memcpy(path, cwd, cwdlen);
777 path[cwdlen] = '/';
778 memcpy(path + cwdlen + 1, argv0, len + 1);
779 }
780
781 return path;
782 }
783
check_path(const std::string & path)784 bool check_path(const std::string &path) {
785 // We don't like '\' in path.
786 return !path.empty() && path[0] == '/' &&
787 path.find('\\') == std::string::npos &&
788 path.find("/../") == std::string::npos &&
789 path.find("/./") == std::string::npos &&
790 !util::ends_with_l(path, "/..") && !util::ends_with_l(path, "/.");
791 }
792
to_time64(const timeval & tv)793 int64_t to_time64(const timeval &tv) {
794 return tv.tv_sec * 1000000 + tv.tv_usec;
795 }
796
check_h2_is_selected(const StringRef & proto)797 bool check_h2_is_selected(const StringRef &proto) {
798 return streq(NGHTTP2_H2, proto) || streq(NGHTTP2_H2_16, proto) ||
799 streq(NGHTTP2_H2_14, proto);
800 }
801
802 namespace {
select_proto(const unsigned char ** out,unsigned char * outlen,const unsigned char * in,unsigned int inlen,const StringRef & key)803 bool select_proto(const unsigned char **out, unsigned char *outlen,
804 const unsigned char *in, unsigned int inlen,
805 const StringRef &key) {
806 for (auto p = in, end = in + inlen; p + key.size() <= end; p += *p + 1) {
807 if (std::equal(std::begin(key), std::end(key), p)) {
808 *out = p + 1;
809 *outlen = *p;
810 return true;
811 }
812 }
813 return false;
814 }
815 } // namespace
816
select_h2(const unsigned char ** out,unsigned char * outlen,const unsigned char * in,unsigned int inlen)817 bool select_h2(const unsigned char **out, unsigned char *outlen,
818 const unsigned char *in, unsigned int inlen) {
819 return select_proto(out, outlen, in, inlen, NGHTTP2_H2_ALPN) ||
820 select_proto(out, outlen, in, inlen, NGHTTP2_H2_16_ALPN) ||
821 select_proto(out, outlen, in, inlen, NGHTTP2_H2_14_ALPN);
822 }
823
select_protocol(const unsigned char ** out,unsigned char * outlen,const unsigned char * in,unsigned int inlen,std::vector<std::string> proto_list)824 bool select_protocol(const unsigned char **out, unsigned char *outlen,
825 const unsigned char *in, unsigned int inlen,
826 std::vector<std::string> proto_list) {
827 for (const auto &proto : proto_list) {
828 if (select_proto(out, outlen, in, inlen, StringRef{proto})) {
829 return true;
830 }
831 }
832
833 return false;
834 }
835
get_default_alpn()836 std::vector<unsigned char> get_default_alpn() {
837 auto res = std::vector<unsigned char>(NGHTTP2_H2_ALPN.size() +
838 NGHTTP2_H2_16_ALPN.size() +
839 NGHTTP2_H2_14_ALPN.size());
840 auto p = std::begin(res);
841
842 p = std::copy_n(std::begin(NGHTTP2_H2_ALPN), NGHTTP2_H2_ALPN.size(), p);
843 p = std::copy_n(std::begin(NGHTTP2_H2_16_ALPN), NGHTTP2_H2_16_ALPN.size(), p);
844 p = std::copy_n(std::begin(NGHTTP2_H2_14_ALPN), NGHTTP2_H2_14_ALPN.size(), p);
845
846 return res;
847 }
848
split_str(const StringRef & s,char delim)849 std::vector<StringRef> split_str(const StringRef &s, char delim) {
850 size_t len = 1;
851 auto last = std::end(s);
852 StringRef::const_iterator d;
853 for (auto first = std::begin(s); (d = std::find(first, last, delim)) != last;
854 ++len, first = d + 1)
855 ;
856
857 auto list = std::vector<StringRef>(len);
858
859 len = 0;
860 for (auto first = std::begin(s);; ++len) {
861 auto stop = std::find(first, last, delim);
862 list[len] = StringRef{first, stop};
863 if (stop == last) {
864 break;
865 }
866 first = stop + 1;
867 }
868 return list;
869 }
870
parse_config_str_list(const StringRef & s,char delim)871 std::vector<std::string> parse_config_str_list(const StringRef &s, char delim) {
872 auto sublist = split_str(s, delim);
873 auto res = std::vector<std::string>();
874 res.reserve(sublist.size());
875 for (const auto &s : sublist) {
876 res.emplace_back(std::begin(s), std::end(s));
877 }
878 return res;
879 }
880
make_socket_closeonexec(int fd)881 int make_socket_closeonexec(int fd) {
882 #ifdef _WIN32
883 (void)fd;
884 return 0;
885 #else // !_WIN32
886 int flags;
887 int rv;
888 while ((flags = fcntl(fd, F_GETFD)) == -1 && errno == EINTR)
889 ;
890 while ((rv = fcntl(fd, F_SETFD, flags | FD_CLOEXEC)) == -1 && errno == EINTR)
891 ;
892 return rv;
893 #endif // !_WIN32
894 }
895
make_socket_nonblocking(int fd)896 int make_socket_nonblocking(int fd) {
897 int rv;
898
899 #ifdef _WIN32
900 u_long mode = 1;
901
902 rv = ioctlsocket(fd, FIONBIO, &mode);
903 #else // !_WIN32
904 int flags;
905 while ((flags = fcntl(fd, F_GETFL, 0)) == -1 && errno == EINTR)
906 ;
907 while ((rv = fcntl(fd, F_SETFL, flags | O_NONBLOCK)) == -1 && errno == EINTR)
908 ;
909 #endif // !_WIN32
910
911 return rv;
912 }
913
make_socket_nodelay(int fd)914 int make_socket_nodelay(int fd) {
915 int val = 1;
916 if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, reinterpret_cast<char *>(&val),
917 sizeof(val)) == -1) {
918 return -1;
919 }
920 return 0;
921 }
922
create_nonblock_socket(int family)923 int create_nonblock_socket(int family) {
924 #ifdef SOCK_NONBLOCK
925 auto fd = socket(family, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0);
926
927 if (fd == -1) {
928 return -1;
929 }
930 #else // !SOCK_NONBLOCK
931 auto fd = socket(family, SOCK_STREAM, 0);
932
933 if (fd == -1) {
934 return -1;
935 }
936
937 make_socket_nonblocking(fd);
938 make_socket_closeonexec(fd);
939 #endif // !SOCK_NONBLOCK
940
941 if (family == AF_INET || family == AF_INET6) {
942 make_socket_nodelay(fd);
943 }
944
945 return fd;
946 }
947
check_socket_connected(int fd)948 bool check_socket_connected(int fd) {
949 int error;
950 socklen_t len = sizeof(error);
951 if (getsockopt(fd, SOL_SOCKET, SO_ERROR, (char *)&error, &len) != 0) {
952 return false;
953 }
954
955 return error == 0;
956 }
957
get_socket_error(int fd)958 int get_socket_error(int fd) {
959 int error;
960 socklen_t len = sizeof(error);
961 if (getsockopt(fd, SOL_SOCKET, SO_ERROR, (char *)&error, &len) != 0) {
962 return -1;
963 }
964
965 return error;
966 }
967
ipv6_numeric_addr(const char * host)968 bool ipv6_numeric_addr(const char *host) {
969 uint8_t dst[16];
970 return nghttp2_inet_pton(AF_INET6, host, dst) == 1;
971 }
972
973 namespace {
parse_uint_digits(const void * ss,size_t len)974 std::pair<int64_t, size_t> parse_uint_digits(const void *ss, size_t len) {
975 const uint8_t *s = static_cast<const uint8_t *>(ss);
976 int64_t n = 0;
977 size_t i;
978 if (len == 0) {
979 return {-1, 0};
980 }
981 constexpr int64_t max = std::numeric_limits<int64_t>::max();
982 for (i = 0; i < len; ++i) {
983 if ('0' <= s[i] && s[i] <= '9') {
984 if (n > max / 10) {
985 return {-1, 0};
986 }
987 n *= 10;
988 if (n > max - (s[i] - '0')) {
989 return {-1, 0};
990 }
991 n += s[i] - '0';
992 continue;
993 }
994 break;
995 }
996 if (i == 0) {
997 return {-1, 0};
998 }
999 return {n, i};
1000 }
1001 } // namespace
1002
parse_uint_with_unit(const char * s)1003 int64_t parse_uint_with_unit(const char *s) {
1004 return parse_uint_with_unit(reinterpret_cast<const uint8_t *>(s), strlen(s));
1005 }
1006
parse_uint_with_unit(const StringRef & s)1007 int64_t parse_uint_with_unit(const StringRef &s) {
1008 return parse_uint_with_unit(s.byte(), s.size());
1009 }
1010
parse_uint_with_unit(const uint8_t * s,size_t len)1011 int64_t parse_uint_with_unit(const uint8_t *s, size_t len) {
1012 int64_t n;
1013 size_t i;
1014 std::tie(n, i) = parse_uint_digits(s, len);
1015 if (n == -1) {
1016 return -1;
1017 }
1018 if (i == len) {
1019 return n;
1020 }
1021 if (i + 1 != len) {
1022 return -1;
1023 }
1024 int mul = 1;
1025 switch (s[i]) {
1026 case 'K':
1027 case 'k':
1028 mul = 1 << 10;
1029 break;
1030 case 'M':
1031 case 'm':
1032 mul = 1 << 20;
1033 break;
1034 case 'G':
1035 case 'g':
1036 mul = 1 << 30;
1037 break;
1038 default:
1039 return -1;
1040 }
1041 constexpr int64_t max = std::numeric_limits<int64_t>::max();
1042 if (n > max / mul) {
1043 return -1;
1044 }
1045 return n * mul;
1046 }
1047
parse_uint(const char * s)1048 int64_t parse_uint(const char *s) {
1049 return parse_uint(reinterpret_cast<const uint8_t *>(s), strlen(s));
1050 }
1051
parse_uint(const std::string & s)1052 int64_t parse_uint(const std::string &s) {
1053 return parse_uint(reinterpret_cast<const uint8_t *>(s.c_str()), s.size());
1054 }
1055
parse_uint(const StringRef & s)1056 int64_t parse_uint(const StringRef &s) {
1057 return parse_uint(s.byte(), s.size());
1058 }
1059
parse_uint(const uint8_t * s,size_t len)1060 int64_t parse_uint(const uint8_t *s, size_t len) {
1061 int64_t n;
1062 size_t i;
1063 std::tie(n, i) = parse_uint_digits(s, len);
1064 if (n == -1 || i != len) {
1065 return -1;
1066 }
1067 return n;
1068 }
1069
parse_duration_with_unit(const char * s)1070 double parse_duration_with_unit(const char *s) {
1071 return parse_duration_with_unit(reinterpret_cast<const uint8_t *>(s),
1072 strlen(s));
1073 }
1074
parse_duration_with_unit(const StringRef & s)1075 double parse_duration_with_unit(const StringRef &s) {
1076 return parse_duration_with_unit(s.byte(), s.size());
1077 }
1078
parse_duration_with_unit(const uint8_t * s,size_t len)1079 double parse_duration_with_unit(const uint8_t *s, size_t len) {
1080 constexpr auto max = std::numeric_limits<int64_t>::max();
1081 int64_t n;
1082 size_t i;
1083
1084 std::tie(n, i) = parse_uint_digits(s, len);
1085 if (n == -1) {
1086 goto fail;
1087 }
1088 if (i == len) {
1089 return static_cast<double>(n);
1090 }
1091 switch (s[i]) {
1092 case 'S':
1093 case 's':
1094 // seconds
1095 if (i + 1 != len) {
1096 goto fail;
1097 }
1098 return static_cast<double>(n);
1099 case 'M':
1100 case 'm':
1101 if (i + 1 == len) {
1102 // minutes
1103 if (n > max / 60) {
1104 goto fail;
1105 }
1106 return static_cast<double>(n) * 60;
1107 }
1108
1109 if (i + 2 != len || (s[i + 1] != 's' && s[i + 1] != 'S')) {
1110 goto fail;
1111 }
1112 // milliseconds
1113 return static_cast<double>(n) / 1000.;
1114 case 'H':
1115 case 'h':
1116 // hours
1117 if (i + 1 != len) {
1118 goto fail;
1119 }
1120 if (n > max / 3600) {
1121 goto fail;
1122 }
1123 return static_cast<double>(n) * 3600;
1124 }
1125 fail:
1126 return std::numeric_limits<double>::infinity();
1127 }
1128
duration_str(double t)1129 std::string duration_str(double t) {
1130 if (t == 0.) {
1131 return "0";
1132 }
1133 auto frac = static_cast<int64_t>(t * 1000) % 1000;
1134 if (frac > 0) {
1135 return utos(static_cast<int64_t>(t * 1000)) + "ms";
1136 }
1137 auto v = static_cast<int64_t>(t);
1138 if (v % 60) {
1139 return utos(v) + "s";
1140 }
1141 v /= 60;
1142 if (v % 60) {
1143 return utos(v) + "m";
1144 }
1145 v /= 60;
1146 return utos(v) + "h";
1147 }
1148
format_duration(const std::chrono::microseconds & u)1149 std::string format_duration(const std::chrono::microseconds &u) {
1150 const char *unit = "us";
1151 int d = 0;
1152 auto t = u.count();
1153 if (t >= 1000000) {
1154 d = 1000000;
1155 unit = "s";
1156 } else if (t >= 1000) {
1157 d = 1000;
1158 unit = "ms";
1159 } else {
1160 return utos(t) + unit;
1161 }
1162 return dtos(static_cast<double>(t) / d) + unit;
1163 }
1164
format_duration(double t)1165 std::string format_duration(double t) {
1166 const char *unit = "us";
1167 if (t >= 1.) {
1168 unit = "s";
1169 } else if (t >= 0.001) {
1170 t *= 1000.;
1171 unit = "ms";
1172 } else {
1173 t *= 1000000.;
1174 return utos(static_cast<int64_t>(t)) + unit;
1175 }
1176 return dtos(t) + unit;
1177 }
1178
dtos(double n)1179 std::string dtos(double n) {
1180 auto m = llround(100. * n);
1181 auto f = utos(m % 100);
1182 return utos(m / 100) + "." + (f.size() == 1 ? "0" : "") + f;
1183 }
1184
make_http_hostport(BlockAllocator & balloc,const StringRef & host,uint16_t port)1185 StringRef make_http_hostport(BlockAllocator &balloc, const StringRef &host,
1186 uint16_t port) {
1187 if (port != 80 && port != 443) {
1188 return make_hostport(balloc, host, port);
1189 }
1190
1191 auto ipv6 = ipv6_numeric_addr(host.c_str());
1192
1193 auto iov = make_byte_ref(balloc, host.size() + (ipv6 ? 2 : 0) + 1);
1194 auto p = iov.base;
1195
1196 if (ipv6) {
1197 *p++ = '[';
1198 }
1199
1200 p = std::copy(std::begin(host), std::end(host), p);
1201
1202 if (ipv6) {
1203 *p++ = ']';
1204 }
1205
1206 *p = '\0';
1207
1208 return StringRef{iov.base, p};
1209 }
1210
make_hostport(const StringRef & host,uint16_t port)1211 std::string make_hostport(const StringRef &host, uint16_t port) {
1212 auto ipv6 = ipv6_numeric_addr(host.c_str());
1213 auto serv = utos(port);
1214
1215 std::string hostport;
1216 hostport.resize(host.size() + (ipv6 ? 2 : 0) + 1 + serv.size());
1217
1218 auto p = &hostport[0];
1219
1220 if (ipv6) {
1221 *p++ = '[';
1222 }
1223
1224 p = std::copy_n(host.c_str(), host.size(), p);
1225
1226 if (ipv6) {
1227 *p++ = ']';
1228 }
1229
1230 *p++ = ':';
1231 std::copy_n(serv.c_str(), serv.size(), p);
1232
1233 return hostport;
1234 }
1235
make_hostport(BlockAllocator & balloc,const StringRef & host,uint16_t port)1236 StringRef make_hostport(BlockAllocator &balloc, const StringRef &host,
1237 uint16_t port) {
1238 auto ipv6 = ipv6_numeric_addr(host.c_str());
1239 auto serv = utos(port);
1240
1241 auto iov =
1242 make_byte_ref(balloc, host.size() + (ipv6 ? 2 : 0) + 1 + serv.size());
1243 auto p = iov.base;
1244
1245 if (ipv6) {
1246 *p++ = '[';
1247 }
1248
1249 p = std::copy(std::begin(host), std::end(host), p);
1250
1251 if (ipv6) {
1252 *p++ = ']';
1253 }
1254
1255 *p++ = ':';
1256
1257 p = std::copy(std::begin(serv), std::end(serv), p);
1258
1259 *p = '\0';
1260
1261 return StringRef{iov.base, p};
1262 }
1263
1264 namespace {
hexdump8(FILE * out,const uint8_t * first,const uint8_t * last)1265 void hexdump8(FILE *out, const uint8_t *first, const uint8_t *last) {
1266 auto stop = std::min(first + 8, last);
1267 for (auto k = first; k != stop; ++k) {
1268 fprintf(out, "%02x ", *k);
1269 }
1270 // each byte needs 3 spaces (2 hex value and space)
1271 for (; stop != first + 8; ++stop) {
1272 fputs(" ", out);
1273 }
1274 // we have extra space after 8 bytes
1275 fputc(' ', out);
1276 }
1277 } // namespace
1278
hexdump(FILE * out,const uint8_t * src,size_t len)1279 void hexdump(FILE *out, const uint8_t *src, size_t len) {
1280 if (len == 0) {
1281 return;
1282 }
1283 size_t buflen = 0;
1284 auto repeated = false;
1285 std::array<uint8_t, 16> buf{};
1286 auto end = src + len;
1287 auto i = src;
1288 for (;;) {
1289 auto nextlen =
1290 std::min(static_cast<size_t>(16), static_cast<size_t>(end - i));
1291 if (nextlen == buflen &&
1292 std::equal(std::begin(buf), std::begin(buf) + buflen, i)) {
1293 // as long as adjacent 16 bytes block are the same, we just
1294 // print single '*'.
1295 if (!repeated) {
1296 repeated = true;
1297 fputs("*\n", out);
1298 }
1299 i += nextlen;
1300 continue;
1301 }
1302 repeated = false;
1303 fprintf(out, "%08lx", static_cast<unsigned long>(i - src));
1304 if (i == end) {
1305 fputc('\n', out);
1306 break;
1307 }
1308 fputs(" ", out);
1309 hexdump8(out, i, end);
1310 hexdump8(out, i + 8, std::max(i + 8, end));
1311 fputc('|', out);
1312 auto stop = std::min(i + 16, end);
1313 buflen = stop - i;
1314 auto p = buf.data();
1315 for (; i != stop; ++i) {
1316 *p++ = *i;
1317 if (0x20 <= *i && *i <= 0x7e) {
1318 fputc(*i, out);
1319 } else {
1320 fputc('.', out);
1321 }
1322 }
1323 fputs("|\n", out);
1324 }
1325 }
1326
put_uint16be(uint8_t * buf,uint16_t n)1327 void put_uint16be(uint8_t *buf, uint16_t n) {
1328 uint16_t x = htons(n);
1329 memcpy(buf, &x, sizeof(uint16_t));
1330 }
1331
put_uint32be(uint8_t * buf,uint32_t n)1332 void put_uint32be(uint8_t *buf, uint32_t n) {
1333 uint32_t x = htonl(n);
1334 memcpy(buf, &x, sizeof(uint32_t));
1335 }
1336
get_uint16(const uint8_t * data)1337 uint16_t get_uint16(const uint8_t *data) {
1338 uint16_t n;
1339 memcpy(&n, data, sizeof(uint16_t));
1340 return ntohs(n);
1341 }
1342
get_uint32(const uint8_t * data)1343 uint32_t get_uint32(const uint8_t *data) {
1344 uint32_t n;
1345 memcpy(&n, data, sizeof(uint32_t));
1346 return ntohl(n);
1347 }
1348
get_uint64(const uint8_t * data)1349 uint64_t get_uint64(const uint8_t *data) {
1350 uint64_t n = 0;
1351 n += static_cast<uint64_t>(data[0]) << 56;
1352 n += static_cast<uint64_t>(data[1]) << 48;
1353 n += static_cast<uint64_t>(data[2]) << 40;
1354 n += static_cast<uint64_t>(data[3]) << 32;
1355 n += static_cast<uint64_t>(data[4]) << 24;
1356 n += data[5] << 16;
1357 n += data[6] << 8;
1358 n += data[7];
1359 return n;
1360 }
1361
read_mime_types(std::map<std::string,std::string> & res,const char * filename)1362 int read_mime_types(std::map<std::string, std::string> &res,
1363 const char *filename) {
1364 std::ifstream infile(filename);
1365 if (!infile) {
1366 return -1;
1367 }
1368
1369 auto delim_pred = [](char c) { return c == ' ' || c == '\t'; };
1370
1371 std::string line;
1372 while (std::getline(infile, line)) {
1373 if (line.empty() || line[0] == '#') {
1374 continue;
1375 }
1376
1377 auto type_end = std::find_if(std::begin(line), std::end(line), delim_pred);
1378 if (type_end == std::begin(line)) {
1379 continue;
1380 }
1381
1382 auto ext_end = type_end;
1383 for (;;) {
1384 auto ext_start = std::find_if_not(ext_end, std::end(line), delim_pred);
1385 if (ext_start == std::end(line)) {
1386 break;
1387 }
1388 ext_end = std::find_if(ext_start, std::end(line), delim_pred);
1389 #ifdef HAVE_STD_MAP_EMPLACE
1390 res.emplace(std::string(ext_start, ext_end),
1391 std::string(std::begin(line), type_end));
1392 #else // !HAVE_STD_MAP_EMPLACE
1393 res.insert(std::make_pair(std::string(ext_start, ext_end),
1394 std::string(std::begin(line), type_end)));
1395 #endif // !HAVE_STD_MAP_EMPLACE
1396 }
1397 }
1398
1399 return 0;
1400 }
1401
percent_decode(BlockAllocator & balloc,const StringRef & src)1402 StringRef percent_decode(BlockAllocator &balloc, const StringRef &src) {
1403 auto iov = make_byte_ref(balloc, src.size() * 3 + 1);
1404 auto p = iov.base;
1405 for (auto first = std::begin(src); first != std::end(src); ++first) {
1406 if (*first != '%') {
1407 *p++ = *first;
1408 continue;
1409 }
1410
1411 if (first + 1 != std::end(src) && first + 2 != std::end(src) &&
1412 is_hex_digit(*(first + 1)) && is_hex_digit(*(first + 2))) {
1413 *p++ = (hex_to_uint(*(first + 1)) << 4) + hex_to_uint(*(first + 2));
1414 first += 2;
1415 continue;
1416 }
1417
1418 *p++ = *first;
1419 }
1420 *p = '\0';
1421 return StringRef{iov.base, p};
1422 }
1423
1424 // Returns x**y
int_pow(double x,size_t y)1425 double int_pow(double x, size_t y) {
1426 auto res = 1.;
1427 for (; y; --y) {
1428 res *= x;
1429 }
1430 return res;
1431 }
1432
hash32(const StringRef & s)1433 uint32_t hash32(const StringRef &s) {
1434 /* 32 bit FNV-1a: http://isthe.com/chongo/tech/comp/fnv/ */
1435 uint32_t h = 2166136261u;
1436 size_t i;
1437
1438 for (i = 0; i < s.size(); ++i) {
1439 h ^= s[i];
1440 h += (h << 1) + (h << 4) + (h << 7) + (h << 8) + (h << 24);
1441 }
1442
1443 return h;
1444 }
1445
1446 #if !OPENSSL_1_1_API
1447 namespace {
EVP_MD_CTX_new(void)1448 EVP_MD_CTX *EVP_MD_CTX_new(void) { return EVP_MD_CTX_create(); }
1449 } // namespace
1450
1451 namespace {
EVP_MD_CTX_free(EVP_MD_CTX * ctx)1452 void EVP_MD_CTX_free(EVP_MD_CTX *ctx) { EVP_MD_CTX_destroy(ctx); }
1453 } // namespace
1454 #endif // !OPENSSL_1_1_API
1455
1456 namespace {
message_digest(uint8_t * res,const EVP_MD * meth,const StringRef & s)1457 int message_digest(uint8_t *res, const EVP_MD *meth, const StringRef &s) {
1458 int rv;
1459
1460 auto ctx = EVP_MD_CTX_new();
1461 if (ctx == nullptr) {
1462 return -1;
1463 }
1464
1465 auto ctx_deleter = defer(EVP_MD_CTX_free, ctx);
1466
1467 rv = EVP_DigestInit_ex(ctx, meth, nullptr);
1468 if (rv != 1) {
1469 return -1;
1470 }
1471
1472 rv = EVP_DigestUpdate(ctx, s.c_str(), s.size());
1473 if (rv != 1) {
1474 return -1;
1475 }
1476
1477 unsigned int mdlen = EVP_MD_size(meth);
1478
1479 rv = EVP_DigestFinal_ex(ctx, res, &mdlen);
1480 if (rv != 1) {
1481 return -1;
1482 }
1483
1484 return 0;
1485 }
1486 } // namespace
1487
sha256(uint8_t * res,const StringRef & s)1488 int sha256(uint8_t *res, const StringRef &s) {
1489 return message_digest(res, EVP_sha256(), s);
1490 }
1491
sha1(uint8_t * res,const StringRef & s)1492 int sha1(uint8_t *res, const StringRef &s) {
1493 return message_digest(res, EVP_sha1(), s);
1494 }
1495
is_hex_string(const StringRef & s)1496 bool is_hex_string(const StringRef &s) {
1497 if (s.size() % 2) {
1498 return false;
1499 }
1500
1501 for (auto c : s) {
1502 if (!is_hex_digit(c)) {
1503 return false;
1504 }
1505 }
1506
1507 return true;
1508 }
1509
decode_hex(BlockAllocator & balloc,const StringRef & s)1510 StringRef decode_hex(BlockAllocator &balloc, const StringRef &s) {
1511 auto iov = make_byte_ref(balloc, s.size() + 1);
1512 auto p = iov.base;
1513 for (auto it = std::begin(s); it != std::end(s); it += 2) {
1514 *p++ = (hex_to_uint(*it) << 4) | hex_to_uint(*(it + 1));
1515 }
1516 *p = '\0';
1517 return StringRef{iov.base, p};
1518 }
1519
extract_host(const StringRef & hostport)1520 StringRef extract_host(const StringRef &hostport) {
1521 if (hostport[0] == '[') {
1522 // assume this is IPv6 numeric address
1523 auto p = std::find(std::begin(hostport), std::end(hostport), ']');
1524 if (p == std::end(hostport)) {
1525 return StringRef{};
1526 }
1527 if (p + 1 < std::end(hostport) && *(p + 1) != ':') {
1528 return StringRef{};
1529 }
1530 return StringRef{std::begin(hostport), p + 1};
1531 }
1532
1533 auto p = std::find(std::begin(hostport), std::end(hostport), ':');
1534 if (p == std::begin(hostport)) {
1535 return StringRef{};
1536 }
1537 return StringRef{std::begin(hostport), p};
1538 }
1539
split_hostport(const StringRef & hostport)1540 std::pair<StringRef, StringRef> split_hostport(const StringRef &hostport) {
1541 if (hostport.empty()) {
1542 return {};
1543 }
1544 if (hostport[0] == '[') {
1545 // assume this is IPv6 numeric address
1546 auto p = std::find(std::begin(hostport), std::end(hostport), ']');
1547 if (p == std::end(hostport)) {
1548 return {};
1549 }
1550 if (p + 1 == std::end(hostport)) {
1551 return {StringRef{std::begin(hostport) + 1, p}, {}};
1552 }
1553 if (*(p + 1) != ':' || p + 2 == std::end(hostport)) {
1554 return {};
1555 }
1556 return {StringRef{std::begin(hostport) + 1, p},
1557 StringRef{p + 2, std::end(hostport)}};
1558 }
1559
1560 auto p = std::find(std::begin(hostport), std::end(hostport), ':');
1561 if (p == std::begin(hostport)) {
1562 return {};
1563 }
1564 if (p == std::end(hostport)) {
1565 return {StringRef{std::begin(hostport), p}, {}};
1566 }
1567 if (p + 1 == std::end(hostport)) {
1568 return {};
1569 }
1570
1571 return {StringRef{std::begin(hostport), p},
1572 StringRef{p + 1, std::end(hostport)}};
1573 }
1574
make_mt19937()1575 std::mt19937 make_mt19937() {
1576 std::random_device rd;
1577 return std::mt19937(rd());
1578 }
1579
daemonize(int nochdir,int noclose)1580 int daemonize(int nochdir, int noclose) {
1581 #if defined(__APPLE__)
1582 pid_t pid;
1583 pid = fork();
1584 if (pid == -1) {
1585 return -1;
1586 } else if (pid > 0) {
1587 _exit(EXIT_SUCCESS);
1588 }
1589 if (setsid() == -1) {
1590 return -1;
1591 }
1592 pid = fork();
1593 if (pid == -1) {
1594 return -1;
1595 } else if (pid > 0) {
1596 _exit(EXIT_SUCCESS);
1597 }
1598 if (nochdir == 0) {
1599 if (chdir("/") == -1) {
1600 return -1;
1601 }
1602 }
1603 if (noclose == 0) {
1604 if (freopen("/dev/null", "r", stdin) == nullptr) {
1605 return -1;
1606 }
1607 if (freopen("/dev/null", "w", stdout) == nullptr) {
1608 return -1;
1609 }
1610 if (freopen("/dev/null", "w", stderr) == nullptr) {
1611 return -1;
1612 }
1613 }
1614 return 0;
1615 #else // !defined(__APPLE__)
1616 return daemon(nochdir, noclose);
1617 #endif // !defined(__APPLE__)
1618 }
1619
1620 } // namespace util
1621
1622 } // namespace nghttp2
1623