2 * nghttp2 - HTTP/2 C Library
4 * Copyright (c) 2012 Tatsuhiro Tsujikawa
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:
14 * The above copyright notice and this permission notice shall be
15 * included in all copies or substantial portions of the Software.
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.
30 #include <sys/types.h>
31 #ifdef HAVE_SYS_SOCKET_H
32 # include <sys/socket.h>
33 #endif // HAVE_SYS_SOCKET_H
36 #endif // HAVE_NETDB_H
40 #endif // HAVE_FCNTL_H
41 #ifdef HAVE_NETINET_IN_H
42 # include <netinet/in.h>
43 #endif // HAVE_NETINET_IN_H
45 # include <ws2tcpip.h>
46 # include <boost/date_time/posix_time/posix_time.hpp>
48 # include <netinet/tcp.h>
50 #ifdef HAVE_ARPA_INET_H
51 # include <arpa/inet.h>
52 #endif // HAVE_ARPA_INET_H
62 #include <openssl/evp.h>
64 #include <nghttp2/nghttp2.h>
66 #include "ssl_compat.h"
75 int nghttp2_inet_pton(int af, const char *src, void *dst) {
76 return inet_pton(af, src, dst);
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);
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;
91 int size = sizeof(struct in6_addr);
93 if (WSAStringToAddress(addr, af, NULL, (LPSOCKADDR)dst, &size) == 0)
101 const char UPPER_XDIGITS[] = "0123456789ABCDEF";
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);
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);
117 std::string percent_encode(const unsigned char *target, size_t len) {
119 for (size_t i = 0; i < len; ++i) {
120 unsigned char c = target[i];
122 if (in_rfc3986_unreserved_chars(c)) {
126 dest += UPPER_XDIGITS[c >> 4];
127 dest += UPPER_XDIGITS[(c & 0x0f)];
133 std::string percent_encode(const std::string &target) {
134 return percent_encode(reinterpret_cast<const unsigned char *>(target.c_str()),
138 std::string percent_encode_path(const std::string &s) {
141 if (in_rfc3986_unreserved_chars(c) || in_rfc3986_sub_delims(c) ||
148 dest += UPPER_XDIGITS[(c >> 4) & 0x0f];
149 dest += UPPER_XDIGITS[(c & 0x0f)];
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);
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);
167 StringRef percent_encode_token(BlockAllocator &balloc,
168 const StringRef &target) {
169 auto iov = make_byte_ref(balloc, target.size() * 3 + 1);
172 for (auto first = std::begin(target); first != std::end(target); ++first) {
175 if (c != '%' && in_token(c)) {
181 *p++ = UPPER_XDIGITS[c >> 4];
182 *p++ = UPPER_XDIGITS[(c & 0x0f)];
187 return StringRef{iov.base, p};
190 uint32_t hex_to_uint(char c) {
203 StringRef quote_string(BlockAllocator &balloc, const StringRef &target) {
204 auto cnt = std::count(std::begin(target), std::end(target), '"');
207 return make_string_ref(balloc, target);
210 auto iov = make_byte_ref(balloc, target.size() + cnt + 1);
213 for (auto c : target) {
223 return StringRef{iov.base, p};
227 template <typename Iterator>
228 Iterator cpydig(Iterator d, uint32_t n, size_t len) {
229 auto p = d + len - 1;
232 *p-- = (n % 10) + '0';
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"};
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);
254 char *http_date(char *res, time_t t) {
257 if (gmtime_r(&t, &tms) == nullptr) {
263 auto s = DAY_OF_WEEK[tms.tm_wday];
264 p = std::copy_n(s, 3, p);
267 p = cpydig(p, tms.tm_mday, 2);
269 s = MONTH[tms.tm_mon];
270 p = std::copy_n(s, 3, p);
272 p = cpydig(p, tms.tm_year + 1900, 4);
274 p = cpydig(p, tms.tm_hour, 2);
276 p = cpydig(p, tms.tm_min, 2);
278 p = cpydig(p, tms.tm_sec, 2);
280 p = std::copy_n(s, 4, p);
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);
292 char *common_log_date(char *res, time_t t) {
295 if (localtime_r(&t, &tms) == nullptr) {
301 p = cpydig(p, tms.tm_mday, 2);
303 auto s = MONTH[tms.tm_mon];
304 p = std::copy_n(s, 3, p);
306 p = cpydig(p, tms.tm_year + 1900, 4);
308 p = cpydig(p, tms.tm_hour, 2);
310 p = cpydig(p, tms.tm_min, 2);
312 p = cpydig(p, tms.tm_sec, 2);
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
327 p = cpydig(p, gmtoff / 3600, 2);
328 p = cpydig(p, (gmtoff % 3600) / 60, 2);
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]);
342 char *iso8601_date(char *res, int64_t ms) {
343 time_t sec = ms / 1000;
346 if (localtime_r(&sec, &tms) == nullptr) {
352 p = cpydig(p, tms.tm_year + 1900, 4);
354 p = cpydig(p, tms.tm_mon + 1, 2);
356 p = cpydig(p, tms.tm_mday, 2);
358 p = cpydig(p, tms.tm_hour, 2);
360 p = cpydig(p, tms.tm_min, 2);
362 p = cpydig(p, tms.tm_sec, 2);
364 p = cpydig(p, ms % 1000, 3);
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
380 p = cpydig(p, gmtoff / 3600, 2);
382 p = cpydig(p, (gmtoff % 3600) / 60, 2);
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"));
397 time_t parse_http_date(const StringRef &s) {
399 // there is no strptime - use boost
400 std::stringstream sstr(s.str());
401 sstr.imbue(ptime_locale);
407 return boost::posix_time::to_time_t(ltime);
410 char *r = strptime(s.c_str(), "%a, %d %b %Y %H:%M:%S GMT", &tm);
414 return nghttp2_timegm_without_yday(&tm);
418 time_t parse_openssl_asn1_time_print(const StringRef &s) {
420 auto r = strptime(s.c_str(), "%b %d %H:%M:%S %Y GMT", &tm);
424 return nghttp2_timegm_without_yday(&tm);
427 char upcase(char c) {
428 if ('a' <= c && c <= 'z') {
429 return c - 'a' + 'A';
435 std::string format_hex(const unsigned char *s, size_t len) {
439 for (size_t i = 0; i < len; ++i) {
440 unsigned char c = s[i];
442 res[i * 2] = LOWER_XDIGITS[c >> 4];
443 res[i * 2 + 1] = LOWER_XDIGITS[c & 0x0f];
448 StringRef format_hex(BlockAllocator &balloc, const StringRef &s) {
449 auto iov = make_byte_ref(balloc, s.size() * 2 + 1);
454 *p++ = LOWER_XDIGITS[c >> 4];
455 *p++ = LOWER_XDIGITS[c & 0xf];
460 return StringRef{iov.base, p};
463 void to_token68(std::string &base64str) {
464 std::transform(std::begin(base64str), std::end(base64str),
465 std::begin(base64str), [](char c) {
475 base64str.erase(std::find(std::begin(base64str), std::end(base64str), '='),
476 std::end(base64str));
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);
485 p = std::transform(std::begin(token68str), std::end(token68str), p,
497 auto rem = token68str.size() & 0x3;
499 p = std::fill_n(p, 4 - rem, '=');
504 return StringRef{iov.base, p};
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.
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) {
518 for (int i = 1; i <= alen; ++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);
526 dp[0][j] = std::min(dp[0][j],
527 std::min(dp[1][j] + delcost, dp[0][j - 1] + addcost));
529 std::rotate(std::begin(dp), std::begin(dp) + 2, std::end(dp));
535 void show_candidates(const char *unkopt, const option *options) {
536 for (; *unkopt == '-'; ++unkopt)
538 if (*unkopt == '\0') {
541 auto unkoptend = unkopt;
542 for (; *unkoptend && *unkoptend != '='; ++unkoptend)
544 auto unkoptlen = unkoptend - unkopt;
545 if (unkoptlen == 0) {
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.
560 cands.emplace_back(0, options[i].name);
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);
570 // cost values are borrowed from git, help.c.
572 levenshtein(unkopt, unkoptlen, options[i].name, optnamelen, 0, 2, 1, 3);
573 cands.emplace_back(sim, options[i].name);
575 if (prefix_match == 1 || cands.empty()) {
578 std::sort(std::begin(cands), std::end(cands));
579 int threshold = cands[0].first;
580 // threshold value is a magic value.
584 std::cerr << "\nDid you mean:\n";
585 for (auto &item : cands) {
586 if (item.first > threshold) {
589 std::cerr << "\t--" << item.second << "\n";
593 bool has_uri_field(const http_parser_url &u, http_parser_url_fields field) {
594 return u.field_set & (1 << 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)) {
605 } else if (!has_uri_field(u2, field)) {
608 if (u1.field_data[field].len != u2.field_data[field].len) {
611 return memcmp(uri1 + u1.field_data[field].off,
612 uri2 + u2.field_data[field].off, u1.field_data[field].len) == 0;
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});
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)) {
625 auto &f = u.field_data[field];
626 return StringRef{uri + f.off, f.len} == t;
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)) {
635 return StringRef{uri + u.field_data[field].off, u.field_data[field].len};
638 uint16_t get_default_port(const char *uri, const http_parser_url &u) {
639 if (util::fieldeq(uri, u, UF_SCHEMA, "https")) {
641 } else if (util::fieldeq(uri, u, UF_SCHEMA, "http")) {
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;
652 util::has_uri_field(u1, UF_PORT) ? u1.port : get_default_port(uri1, u1);
654 util::has_uri_field(u2, UF_PORT) ? u2.port : get_default_port(uri2, u2);
655 return port1 == port2;
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);
665 bool numeric_host(const char *hostname) {
666 return numeric_host(hostname, AF_INET) || numeric_host(hostname, AF_INET6);
669 bool numeric_host(const char *hostname, int family) {
671 std::array<uint8_t, sizeof(struct in6_addr)> dst;
673 rv = nghttp2_inet_pton(family, hostname, dst.data());
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,
688 std::string to_numeric_addr(const Address *addr) {
689 auto family = addr->su.storage.ss_family;
691 if (family == AF_UNIX) {
692 return addr->su.un.sun_path;
696 std::array<char, NI_MAXHOST> host;
697 std::array<char, NI_MAXSERV> serv;
699 getnameinfo(&addr->su.sa, addr->len, host.data(), host.size(),
700 serv.data(), serv.size(), NI_NUMERICHOST | NI_NUMERICSERV);
705 auto hostlen = strlen(host.data());
706 auto servlen = strlen(serv.data());
710 if (family == AF_INET6) {
711 s.resize(hostlen + servlen + 2 + 1);
714 p = std::copy_n(host.data(), hostlen, p);
717 s.resize(hostlen + servlen + 1);
719 p = std::copy_n(host.data(), hostlen, p);
722 std::copy_n(serv.data(), servlen, p);
727 void set_port(Address &addr, uint16_t port) {
728 switch (addr.su.storage.ss_family) {
730 addr.su.in.sin_port = htons(port);
733 addr.su.in6.sin6_port = htons(port);
738 std::string ascii_dump(const uint8_t *data, size_t len) {
741 for (size_t i = 0; i < len; ++i) {
744 if (c >= 0x20 && c < 0x7f) {
754 char *get_exec_path(int argc, char **const argv, const char *cwd) {
755 if (argc == 0 || cwd == nullptr) {
759 auto argv0 = argv[0];
760 auto len = strlen(argv0);
764 if (argv0[0] == '/') {
765 path = static_cast<char *>(malloc(len + 1));
766 if (path == nullptr) {
769 memcpy(path, argv0, len + 1);
771 auto cwdlen = strlen(cwd);
772 path = static_cast<char *>(malloc(len + 1 + cwdlen + 1));
773 if (path == nullptr) {
776 memcpy(path, cwd, cwdlen);
778 memcpy(path + cwdlen + 1, argv0, len + 1);
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, "/.");
793 int64_t to_time64(const timeval &tv) {
794 return tv.tv_sec * 1000000 + tv.tv_usec;
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);
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)) {
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);
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})) {
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);
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);
849 std::vector<StringRef> split_str(const StringRef &s, char delim) {
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)
857 auto list = std::vector<StringRef>(len);
860 for (auto first = std::begin(s);; ++len) {
861 auto stop = std::find(first, last, delim);
862 list[len] = StringRef{first, stop};
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));
881 int make_socket_closeonexec(int fd) {
888 while ((flags = fcntl(fd, F_GETFD)) == -1 && errno == EINTR)
890 while ((rv = fcntl(fd, F_SETFD, flags | FD_CLOEXEC)) == -1 && errno == EINTR)
896 int make_socket_nonblocking(int fd) {
902 rv = ioctlsocket(fd, FIONBIO, &mode);
905 while ((flags = fcntl(fd, F_GETFL, 0)) == -1 && errno == EINTR)
907 while ((rv = fcntl(fd, F_SETFL, flags | O_NONBLOCK)) == -1 && errno == EINTR)
914 int make_socket_nodelay(int fd) {
916 if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, reinterpret_cast<char *>(&val),
917 sizeof(val)) == -1) {
923 int create_nonblock_socket(int family) {
925 auto fd = socket(family, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0);
930 #else // !SOCK_NONBLOCK
931 auto fd = socket(family, SOCK_STREAM, 0);
937 make_socket_nonblocking(fd);
938 make_socket_closeonexec(fd);
939 #endif // !SOCK_NONBLOCK
941 if (family == AF_INET || family == AF_INET6) {
942 make_socket_nodelay(fd);
948 bool check_socket_connected(int fd) {
950 socklen_t len = sizeof(error);
951 if (getsockopt(fd, SOL_SOCKET, SO_ERROR, (char *)&error, &len) != 0) {
958 int get_socket_error(int fd) {
960 socklen_t len = sizeof(error);
961 if (getsockopt(fd, SOL_SOCKET, SO_ERROR, (char *)&error, &len) != 0) {
968 bool ipv6_numeric_addr(const char *host) {
970 return nghttp2_inet_pton(AF_INET6, host, dst) == 1;
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);
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') {
988 if (n > max - (s[i] - '0')) {
1003 int64_t parse_uint_with_unit(const char *s) {
1004 return parse_uint_with_unit(reinterpret_cast<const uint8_t *>(s), strlen(s));
1007 int64_t parse_uint_with_unit(const StringRef &s) {
1008 return parse_uint_with_unit(s.byte(), s.size());
1011 int64_t parse_uint_with_unit(const uint8_t *s, size_t len) {
1014 std::tie(n, i) = parse_uint_digits(s, len);
1041 constexpr int64_t max = std::numeric_limits<int64_t>::max();
1042 if (n > max / mul) {
1048 int64_t parse_uint(const char *s) {
1049 return parse_uint(reinterpret_cast<const uint8_t *>(s), strlen(s));
1052 int64_t parse_uint(const std::string &s) {
1053 return parse_uint(reinterpret_cast<const uint8_t *>(s.c_str()), s.size());
1056 int64_t parse_uint(const StringRef &s) {
1057 return parse_uint(s.byte(), s.size());
1060 int64_t parse_uint(const uint8_t *s, size_t len) {
1063 std::tie(n, i) = parse_uint_digits(s, len);
1064 if (n == -1 || i != len) {
1070 double parse_duration_with_unit(const char *s) {
1071 return parse_duration_with_unit(reinterpret_cast<const uint8_t *>(s),
1075 double parse_duration_with_unit(const StringRef &s) {
1076 return parse_duration_with_unit(s.byte(), s.size());
1079 double parse_duration_with_unit(const uint8_t *s, size_t len) {
1080 constexpr auto max = std::numeric_limits<int64_t>::max();
1084 std::tie(n, i) = parse_uint_digits(s, len);
1089 return static_cast<double>(n);
1098 return static_cast<double>(n);
1106 return static_cast<double>(n) * 60;
1109 if (i + 2 != len || (s[i + 1] != 's' && s[i + 1] != 'S')) {
1113 return static_cast<double>(n) / 1000.;
1120 if (n > max / 3600) {
1123 return static_cast<double>(n) * 3600;
1126 return std::numeric_limits<double>::infinity();
1129 std::string duration_str(double t) {
1133 auto frac = static_cast<int64_t>(t * 1000) % 1000;
1135 return utos(static_cast<int64_t>(t * 1000)) + "ms";
1137 auto v = static_cast<int64_t>(t);
1139 return utos(v) + "s";
1143 return utos(v) + "m";
1146 return utos(v) + "h";
1149 std::string format_duration(const std::chrono::microseconds &u) {
1150 const char *unit = "us";
1156 } else if (t >= 1000) {
1160 return utos(t) + unit;
1162 return dtos(static_cast<double>(t) / d) + unit;
1165 std::string format_duration(double t) {
1166 const char *unit = "us";
1169 } else if (t >= 0.001) {
1174 return utos(static_cast<int64_t>(t)) + unit;
1176 return dtos(t) + unit;
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;
1185 StringRef make_http_hostport(BlockAllocator &balloc, const StringRef &host,
1187 if (port != 80 && port != 443) {
1188 return make_hostport(balloc, host, port);
1191 auto ipv6 = ipv6_numeric_addr(host.c_str());
1193 auto iov = make_byte_ref(balloc, host.size() + (ipv6 ? 2 : 0) + 1);
1200 p = std::copy(std::begin(host), std::end(host), p);
1208 return StringRef{iov.base, p};
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);
1215 std::string hostport;
1216 hostport.resize(host.size() + (ipv6 ? 2 : 0) + 1 + serv.size());
1218 auto p = &hostport[0];
1224 p = std::copy_n(host.c_str(), host.size(), p);
1231 std::copy_n(serv.c_str(), serv.size(), p);
1236 StringRef make_hostport(BlockAllocator &balloc, const StringRef &host,
1238 auto ipv6 = ipv6_numeric_addr(host.c_str());
1239 auto serv = utos(port);
1242 make_byte_ref(balloc, host.size() + (ipv6 ? 2 : 0) + 1 + serv.size());
1249 p = std::copy(std::begin(host), std::end(host), p);
1257 p = std::copy(std::begin(serv), std::end(serv), p);
1261 return StringRef{iov.base, p};
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);
1270 // each byte needs 3 spaces (2 hex value and space)
1271 for (; stop != first + 8; ++stop) {
1274 // we have extra space after 8 bytes
1279 void hexdump(FILE *out, const uint8_t *src, size_t len) {
1284 auto repeated = false;
1285 std::array<uint8_t, 16> buf{};
1286 auto end = src + len;
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 '*'.
1303 fprintf(out, "%08lx", static_cast<unsigned long>(i - src));
1309 hexdump8(out, i, end);
1310 hexdump8(out, i + 8, std::max(i + 8, end));
1312 auto stop = std::min(i + 16, end);
1314 auto p = buf.data();
1315 for (; i != stop; ++i) {
1317 if (0x20 <= *i && *i <= 0x7e) {
1327 void put_uint16be(uint8_t *buf, uint16_t n) {
1328 uint16_t x = htons(n);
1329 memcpy(buf, &x, sizeof(uint16_t));
1332 void put_uint32be(uint8_t *buf, uint32_t n) {
1333 uint32_t x = htonl(n);
1334 memcpy(buf, &x, sizeof(uint32_t));
1337 uint16_t get_uint16(const uint8_t *data) {
1339 memcpy(&n, data, sizeof(uint16_t));
1343 uint32_t get_uint32(const uint8_t *data) {
1345 memcpy(&n, data, sizeof(uint32_t));
1349 uint64_t get_uint64(const uint8_t *data) {
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;
1362 int read_mime_types(std::map<std::string, std::string> &res,
1363 const char *filename) {
1364 std::ifstream infile(filename);
1369 auto delim_pred = [](char c) { return c == ' ' || c == '\t'; };
1372 while (std::getline(infile, line)) {
1373 if (line.empty() || line[0] == '#') {
1377 auto type_end = std::find_if(std::begin(line), std::end(line), delim_pred);
1378 if (type_end == std::begin(line)) {
1382 auto ext_end = type_end;
1384 auto ext_start = std::find_if_not(ext_end, std::end(line), delim_pred);
1385 if (ext_start == std::end(line)) {
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
1402 StringRef percent_decode(BlockAllocator &balloc, const StringRef &src) {
1403 auto iov = make_byte_ref(balloc, src.size() * 3 + 1);
1405 for (auto first = std::begin(src); first != std::end(src); ++first) {
1406 if (*first != '%') {
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));
1421 return StringRef{iov.base, p};
1425 double int_pow(double x, size_t y) {
1433 uint32_t hash32(const StringRef &s) {
1434 /* 32 bit FNV-1a: http://isthe.com/chongo/tech/comp/fnv/ */
1435 uint32_t h = 2166136261u;
1438 for (i = 0; i < s.size(); ++i) {
1440 h += (h << 1) + (h << 4) + (h << 7) + (h << 8) + (h << 24);
1446 #if !OPENSSL_1_1_API
1448 EVP_MD_CTX *EVP_MD_CTX_new(void) { return EVP_MD_CTX_create(); }
1452 void EVP_MD_CTX_free(EVP_MD_CTX *ctx) { EVP_MD_CTX_destroy(ctx); }
1454 #endif // !OPENSSL_1_1_API
1457 int message_digest(uint8_t *res, const EVP_MD *meth, const StringRef &s) {
1460 auto ctx = EVP_MD_CTX_new();
1461 if (ctx == nullptr) {
1465 auto ctx_deleter = defer(EVP_MD_CTX_free, ctx);
1467 rv = EVP_DigestInit_ex(ctx, meth, nullptr);
1472 rv = EVP_DigestUpdate(ctx, s.c_str(), s.size());
1477 unsigned int mdlen = EVP_MD_size(meth);
1479 rv = EVP_DigestFinal_ex(ctx, res, &mdlen);
1488 int sha256(uint8_t *res, const StringRef &s) {
1489 return message_digest(res, EVP_sha256(), s);
1492 int sha1(uint8_t *res, const StringRef &s) {
1493 return message_digest(res, EVP_sha1(), s);
1496 bool is_hex_string(const StringRef &s) {
1502 if (!is_hex_digit(c)) {
1510 StringRef decode_hex(BlockAllocator &balloc, const StringRef &s) {
1511 auto iov = make_byte_ref(balloc, s.size() + 1);
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));
1517 return StringRef{iov.base, p};
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)) {
1527 if (p + 1 < std::end(hostport) && *(p + 1) != ':') {
1530 return StringRef{std::begin(hostport), p + 1};
1533 auto p = std::find(std::begin(hostport), std::end(hostport), ':');
1534 if (p == std::begin(hostport)) {
1537 return StringRef{std::begin(hostport), p};
1540 std::pair<StringRef, StringRef> split_hostport(const StringRef &hostport) {
1541 if (hostport.empty()) {
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)) {
1550 if (p + 1 == std::end(hostport)) {
1551 return {StringRef{std::begin(hostport) + 1, p}, {}};
1553 if (*(p + 1) != ':' || p + 2 == std::end(hostport)) {
1556 return {StringRef{std::begin(hostport) + 1, p},
1557 StringRef{p + 2, std::end(hostport)}};
1560 auto p = std::find(std::begin(hostport), std::end(hostport), ':');
1561 if (p == std::begin(hostport)) {
1564 if (p == std::end(hostport)) {
1565 return {StringRef{std::begin(hostport), p}, {}};
1567 if (p + 1 == std::end(hostport)) {
1571 return {StringRef{std::begin(hostport), p},
1572 StringRef{p + 1, std::end(hostport)}};
1575 std::mt19937 make_mt19937() {
1576 std::random_device rd;
1577 return std::mt19937(rd());
1580 int daemonize(int nochdir, int noclose) {
1581 #if defined(__APPLE__)
1586 } else if (pid > 0) {
1587 _exit(EXIT_SUCCESS);
1589 if (setsid() == -1) {
1595 } else if (pid > 0) {
1596 _exit(EXIT_SUCCESS);
1599 if (chdir("/") == -1) {
1604 if (freopen("/dev/null", "r", stdin) == nullptr) {
1607 if (freopen("/dev/null", "w", stdout) == nullptr) {
1610 if (freopen("/dev/null", "w", stderr) == nullptr) {
1615 #else // !defined(__APPLE__)
1616 return daemon(nochdir, noclose);
1617 #endif // !defined(__APPLE__)
1622 } // namespace nghttp2