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