OSDN Git Service

[Feature] cpp-httplibの導入
[hengbandforosx/hengbandosx.git] / src / external-lib / httplib.cpp
1 #include "external-lib/include-httplib.h"
2
3 #ifdef WORLD_SCORE
4
5 #if defined(_MSC_VER)
6 #pragma warning(push, 0)
7 #endif
8 namespace httplib {
9
10 /*
11  * Implementation that will be part of the .cc file if split into .h + .cc.
12  */
13
14 namespace detail {
15
16 bool is_hex(char c, int &v) {
17   if (0x20 <= c && isdigit(c)) {
18     v = c - '0';
19     return true;
20   } else if ('A' <= c && c <= 'F') {
21     v = c - 'A' + 10;
22     return true;
23   } else if ('a' <= c && c <= 'f') {
24     v = c - 'a' + 10;
25     return true;
26   }
27   return false;
28 }
29
30 bool from_hex_to_i(const std::string &s, size_t i, size_t cnt,
31                           int &val) {
32   if (i >= s.size()) { return false; }
33
34   val = 0;
35   for (; cnt; i++, cnt--) {
36     if (!s[i]) { return false; }
37     int v = 0;
38     if (is_hex(s[i], v)) {
39       val = val * 16 + v;
40     } else {
41       return false;
42     }
43   }
44   return true;
45 }
46
47 std::string from_i_to_hex(size_t n) {
48   const char *charset = "0123456789abcdef";
49   std::string ret;
50   do {
51     ret = charset[n & 15] + ret;
52     n >>= 4;
53   } while (n > 0);
54   return ret;
55 }
56
57 size_t to_utf8(int code, char *buff) {
58   if (code < 0x0080) {
59     buff[0] = (code & 0x7F);
60     return 1;
61   } else if (code < 0x0800) {
62     buff[0] = static_cast<char>(0xC0 | ((code >> 6) & 0x1F));
63     buff[1] = static_cast<char>(0x80 | (code & 0x3F));
64     return 2;
65   } else if (code < 0xD800) {
66     buff[0] = static_cast<char>(0xE0 | ((code >> 12) & 0xF));
67     buff[1] = static_cast<char>(0x80 | ((code >> 6) & 0x3F));
68     buff[2] = static_cast<char>(0x80 | (code & 0x3F));
69     return 3;
70   } else if (code < 0xE000) { // D800 - DFFF is invalid...
71     return 0;
72   } else if (code < 0x10000) {
73     buff[0] = static_cast<char>(0xE0 | ((code >> 12) & 0xF));
74     buff[1] = static_cast<char>(0x80 | ((code >> 6) & 0x3F));
75     buff[2] = static_cast<char>(0x80 | (code & 0x3F));
76     return 3;
77   } else if (code < 0x110000) {
78     buff[0] = static_cast<char>(0xF0 | ((code >> 18) & 0x7));
79     buff[1] = static_cast<char>(0x80 | ((code >> 12) & 0x3F));
80     buff[2] = static_cast<char>(0x80 | ((code >> 6) & 0x3F));
81     buff[3] = static_cast<char>(0x80 | (code & 0x3F));
82     return 4;
83   }
84
85   // NOTREACHED
86   return 0;
87 }
88
89 // NOTE: This code came up with the following stackoverflow post:
90 // https://stackoverflow.com/questions/180947/base64-decode-snippet-in-c
91 std::string base64_encode(const std::string &in) {
92   static const auto lookup =
93       "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
94
95   std::string out;
96   out.reserve(in.size());
97
98   int val = 0;
99   int valb = -6;
100
101   for (auto c : in) {
102     val = (val << 8) + static_cast<uint8_t>(c);
103     valb += 8;
104     while (valb >= 0) {
105       out.push_back(lookup[(val >> valb) & 0x3F]);
106       valb -= 6;
107     }
108   }
109
110   if (valb > -6) { out.push_back(lookup[((val << 8) >> (valb + 8)) & 0x3F]); }
111
112   while (out.size() % 4) {
113     out.push_back('=');
114   }
115
116   return out;
117 }
118
119 bool is_file(const std::string &path) {
120 #ifdef _WIN32
121   return _access_s(path.c_str(), 0) == 0;
122 #else
123   struct stat st;
124   return stat(path.c_str(), &st) >= 0 && S_ISREG(st.st_mode);
125 #endif
126 }
127
128 bool is_dir(const std::string &path) {
129   struct stat st;
130   return stat(path.c_str(), &st) >= 0 && S_ISDIR(st.st_mode);
131 }
132
133 bool is_valid_path(const std::string &path) {
134   size_t level = 0;
135   size_t i = 0;
136
137   // Skip slash
138   while (i < path.size() && path[i] == '/') {
139     i++;
140   }
141
142   while (i < path.size()) {
143     // Read component
144     auto beg = i;
145     while (i < path.size() && path[i] != '/') {
146       i++;
147     }
148
149     auto len = i - beg;
150     assert(len > 0);
151
152     if (!path.compare(beg, len, ".")) {
153       ;
154     } else if (!path.compare(beg, len, "..")) {
155       if (level == 0) { return false; }
156       level--;
157     } else {
158       level++;
159     }
160
161     // Skip slash
162     while (i < path.size() && path[i] == '/') {
163       i++;
164     }
165   }
166
167   return true;
168 }
169
170 std::string encode_query_param(const std::string &value) {
171   std::ostringstream escaped;
172   escaped.fill('0');
173   escaped << std::hex;
174
175   for (auto c : value) {
176     if (std::isalnum(static_cast<uint8_t>(c)) || c == '-' || c == '_' ||
177         c == '.' || c == '!' || c == '~' || c == '*' || c == '\'' || c == '(' ||
178         c == ')') {
179       escaped << c;
180     } else {
181       escaped << std::uppercase;
182       escaped << '%' << std::setw(2)
183               << static_cast<int>(static_cast<unsigned char>(c));
184       escaped << std::nouppercase;
185     }
186   }
187
188   return escaped.str();
189 }
190
191 std::string encode_url(const std::string &s) {
192   std::string result;
193   result.reserve(s.size());
194
195   for (size_t i = 0; s[i]; i++) {
196     switch (s[i]) {
197     case ' ': result += "%20"; break;
198     case '+': result += "%2B"; break;
199     case '\r': result += "%0D"; break;
200     case '\n': result += "%0A"; break;
201     case '\'': result += "%27"; break;
202     case ',': result += "%2C"; break;
203     // case ':': result += "%3A"; break; // ok? probably...
204     case ';': result += "%3B"; break;
205     default:
206       auto c = static_cast<uint8_t>(s[i]);
207       if (c >= 0x80) {
208         result += '%';
209         char hex[4];
210         auto len = snprintf(hex, sizeof(hex) - 1, "%02X", c);
211         assert(len == 2);
212         result.append(hex, static_cast<size_t>(len));
213       } else {
214         result += s[i];
215       }
216       break;
217     }
218   }
219
220   return result;
221 }
222
223 std::string decode_url(const std::string &s,
224                               bool convert_plus_to_space) {
225   std::string result;
226
227   for (size_t i = 0; i < s.size(); i++) {
228     if (s[i] == '%' && i + 1 < s.size()) {
229       if (s[i + 1] == 'u') {
230         int val = 0;
231         if (from_hex_to_i(s, i + 2, 4, val)) {
232           // 4 digits Unicode codes
233           char buff[4];
234           size_t len = to_utf8(val, buff);
235           if (len > 0) { result.append(buff, len); }
236           i += 5; // 'u0000'
237         } else {
238           result += s[i];
239         }
240       } else {
241         int val = 0;
242         if (from_hex_to_i(s, i + 1, 2, val)) {
243           // 2 digits hex codes
244           result += static_cast<char>(val);
245           i += 2; // '00'
246         } else {
247           result += s[i];
248         }
249       }
250     } else if (convert_plus_to_space && s[i] == '+') {
251       result += ' ';
252     } else {
253       result += s[i];
254     }
255   }
256
257   return result;
258 }
259
260 void read_file(const std::string &path, std::string &out) {
261   std::ifstream fs(path, std::ios_base::binary);
262   fs.seekg(0, std::ios_base::end);
263   auto size = fs.tellg();
264   fs.seekg(0);
265   out.resize(static_cast<size_t>(size));
266   fs.read(&out[0], static_cast<std::streamsize>(size));
267 }
268
269 std::string file_extension(const std::string &path) {
270   std::smatch m;
271   static auto re = std::regex("\\.([a-zA-Z0-9]+)$");
272   if (std::regex_search(path, m, re)) { return m[1].str(); }
273   return std::string();
274 }
275
276 bool is_space_or_tab(char c) { return c == ' ' || c == '\t'; }
277
278 std::pair<size_t, size_t> trim(const char *b, const char *e, size_t left,
279                                       size_t right) {
280   while (b + left < e && is_space_or_tab(b[left])) {
281     left++;
282   }
283   while (right > 0 && is_space_or_tab(b[right - 1])) {
284     right--;
285   }
286   return std::make_pair(left, right);
287 }
288
289 std::string trim_copy(const std::string &s) {
290   auto r = trim(s.data(), s.data() + s.size(), 0, s.size());
291   return s.substr(r.first, r.second - r.first);
292 }
293
294 void split(const char *b, const char *e, char d,
295                   std::function<void(const char *, const char *)> fn) {
296   size_t i = 0;
297   size_t beg = 0;
298
299   while (e ? (b + i < e) : (b[i] != '\0')) {
300     if (b[i] == d) {
301       auto r = trim(b, e, beg, i);
302       if (r.first < r.second) { fn(&b[r.first], &b[r.second]); }
303       beg = i + 1;
304     }
305     i++;
306   }
307
308   if (i) {
309     auto r = trim(b, e, beg, i);
310     if (r.first < r.second) { fn(&b[r.first], &b[r.second]); }
311   }
312 }
313
314 stream_line_reader::stream_line_reader(Stream &strm, char *fixed_buffer,
315                                               size_t fixed_buffer_size)
316     : strm_(strm), fixed_buffer_(fixed_buffer),
317       fixed_buffer_size_(fixed_buffer_size) {}
318
319 const char *stream_line_reader::ptr() const {
320   if (glowable_buffer_.empty()) {
321     return fixed_buffer_;
322   } else {
323     return glowable_buffer_.data();
324   }
325 }
326
327 size_t stream_line_reader::size() const {
328   if (glowable_buffer_.empty()) {
329     return fixed_buffer_used_size_;
330   } else {
331     return glowable_buffer_.size();
332   }
333 }
334
335 bool stream_line_reader::end_with_crlf() const {
336   auto end = ptr() + size();
337   return size() >= 2 && end[-2] == '\r' && end[-1] == '\n';
338 }
339
340 bool stream_line_reader::getline() {
341   fixed_buffer_used_size_ = 0;
342   glowable_buffer_.clear();
343
344   for (size_t i = 0;; i++) {
345     char byte;
346     auto n = strm_.read(&byte, 1);
347
348     if (n < 0) {
349       return false;
350     } else if (n == 0) {
351       if (i == 0) {
352         return false;
353       } else {
354         break;
355       }
356     }
357
358     append(byte);
359
360     if (byte == '\n') { break; }
361   }
362
363   return true;
364 }
365
366 void stream_line_reader::append(char c) {
367   if (fixed_buffer_used_size_ < fixed_buffer_size_ - 1) {
368     fixed_buffer_[fixed_buffer_used_size_++] = c;
369     fixed_buffer_[fixed_buffer_used_size_] = '\0';
370   } else {
371     if (glowable_buffer_.empty()) {
372       assert(fixed_buffer_[fixed_buffer_used_size_] == '\0');
373       glowable_buffer_.assign(fixed_buffer_, fixed_buffer_used_size_);
374     }
375     glowable_buffer_ += c;
376   }
377 }
378
379 int close_socket(socket_t sock) {
380 #ifdef _WIN32
381   return closesocket(sock);
382 #else
383   return close(sock);
384 #endif
385 }
386
387 template <typename T> ssize_t handle_EINTR(T fn) {
388   ssize_t res = false;
389   while (true) {
390     res = fn();
391     if (res < 0 && errno == EINTR) { continue; }
392     break;
393   }
394   return res;
395 }
396
397 ssize_t read_socket(socket_t sock, void *ptr, size_t size, int flags) {
398   return handle_EINTR([&]() {
399     return recv(sock,
400 #ifdef _WIN32
401                 static_cast<char *>(ptr), static_cast<int>(size),
402 #else
403                 ptr, size,
404 #endif
405                 flags);
406   });
407 }
408
409 ssize_t send_socket(socket_t sock, const void *ptr, size_t size,
410                            int flags) {
411   return handle_EINTR([&]() {
412     return send(sock,
413 #ifdef _WIN32
414                 static_cast<const char *>(ptr), static_cast<int>(size),
415 #else
416                 ptr, size,
417 #endif
418                 flags);
419   });
420 }
421
422 ssize_t select_read(socket_t sock, time_t sec, time_t usec) {
423 #ifdef CPPHTTPLIB_USE_POLL
424   struct pollfd pfd_read;
425   pfd_read.fd = sock;
426   pfd_read.events = POLLIN;
427
428   auto timeout = static_cast<int>(sec * 1000 + usec / 1000);
429
430   return handle_EINTR([&]() { return poll(&pfd_read, 1, timeout); });
431 #else
432 #ifndef _WIN32
433   if (sock >= FD_SETSIZE) { return 1; }
434 #endif
435
436   fd_set fds;
437   FD_ZERO(&fds);
438   FD_SET(sock, &fds);
439
440   timeval tv;
441   tv.tv_sec = static_cast<long>(sec);
442   tv.tv_usec = static_cast<decltype(tv.tv_usec)>(usec);
443
444   return handle_EINTR([&]() {
445     return select(static_cast<int>(sock + 1), &fds, nullptr, nullptr, &tv);
446   });
447 #endif
448 }
449
450 ssize_t select_write(socket_t sock, time_t sec, time_t usec) {
451 #ifdef CPPHTTPLIB_USE_POLL
452   struct pollfd pfd_read;
453   pfd_read.fd = sock;
454   pfd_read.events = POLLOUT;
455
456   auto timeout = static_cast<int>(sec * 1000 + usec / 1000);
457
458   return handle_EINTR([&]() { return poll(&pfd_read, 1, timeout); });
459 #else
460 #ifndef _WIN32
461   if (sock >= FD_SETSIZE) { return 1; }
462 #endif
463
464   fd_set fds;
465   FD_ZERO(&fds);
466   FD_SET(sock, &fds);
467
468   timeval tv;
469   tv.tv_sec = static_cast<long>(sec);
470   tv.tv_usec = static_cast<decltype(tv.tv_usec)>(usec);
471
472   return handle_EINTR([&]() {
473     return select(static_cast<int>(sock + 1), nullptr, &fds, nullptr, &tv);
474   });
475 #endif
476 }
477
478 Error wait_until_socket_is_ready(socket_t sock, time_t sec,
479                                         time_t usec) {
480 #ifdef CPPHTTPLIB_USE_POLL
481   struct pollfd pfd_read;
482   pfd_read.fd = sock;
483   pfd_read.events = POLLIN | POLLOUT;
484
485   auto timeout = static_cast<int>(sec * 1000 + usec / 1000);
486
487   auto poll_res = handle_EINTR([&]() { return poll(&pfd_read, 1, timeout); });
488
489   if (poll_res == 0) { return Error::ConnectionTimeout; }
490
491   if (poll_res > 0 && pfd_read.revents & (POLLIN | POLLOUT)) {
492     int error = 0;
493     socklen_t len = sizeof(error);
494     auto res = getsockopt(sock, SOL_SOCKET, SO_ERROR,
495                           reinterpret_cast<char *>(&error), &len);
496     auto successful = res >= 0 && !error;
497     return successful ? Error::Success : Error::Connection;
498   }
499
500   return Error::Connection;
501 #else
502 #ifndef _WIN32
503   if (sock >= FD_SETSIZE) { return Error::Connection; }
504 #endif
505
506   fd_set fdsr;
507   FD_ZERO(&fdsr);
508   FD_SET(sock, &fdsr);
509
510   auto fdsw = fdsr;
511   auto fdse = fdsr;
512
513   timeval tv;
514   tv.tv_sec = static_cast<long>(sec);
515   tv.tv_usec = static_cast<decltype(tv.tv_usec)>(usec);
516
517   auto ret = handle_EINTR([&]() {
518     return select(static_cast<int>(sock + 1), &fdsr, &fdsw, &fdse, &tv);
519   });
520
521   if (ret == 0) { return Error::ConnectionTimeout; }
522
523   if (ret > 0 && (FD_ISSET(sock, &fdsr) || FD_ISSET(sock, &fdsw))) {
524     int error = 0;
525     socklen_t len = sizeof(error);
526     auto res = getsockopt(sock, SOL_SOCKET, SO_ERROR,
527                           reinterpret_cast<char *>(&error), &len);
528     auto successful = res >= 0 && !error;
529     return successful ? Error::Success : Error::Connection;
530   }
531   return Error::Connection;
532 #endif
533 }
534
535 bool is_socket_alive(socket_t sock) {
536   const auto val = detail::select_read(sock, 0, 0);
537   if (val == 0) {
538     return true;
539   } else if (val < 0 && errno == EBADF) {
540     return false;
541   }
542   char buf[1];
543   return detail::read_socket(sock, &buf[0], sizeof(buf), MSG_PEEK) > 0;
544 }
545
546 class SocketStream : public Stream {
547 public:
548   SocketStream(socket_t sock, time_t read_timeout_sec, time_t read_timeout_usec,
549                time_t write_timeout_sec, time_t write_timeout_usec);
550   ~SocketStream() override;
551
552   bool is_readable() const override;
553   bool is_writable() const override;
554   ssize_t read(char *ptr, size_t size) override;
555   ssize_t write(const char *ptr, size_t size) override;
556   void get_remote_ip_and_port(std::string &ip, int &port) const override;
557   void get_local_ip_and_port(std::string &ip, int &port) const override;
558   socket_t socket() const override;
559
560 private:
561   socket_t sock_;
562   time_t read_timeout_sec_;
563   time_t read_timeout_usec_;
564   time_t write_timeout_sec_;
565   time_t write_timeout_usec_;
566
567   std::vector<char> read_buff_;
568   size_t read_buff_off_ = 0;
569   size_t read_buff_content_size_ = 0;
570
571   static const size_t read_buff_size_ = 1024 * 4;
572 };
573
574 #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
575 class SSLSocketStream : public Stream {
576 public:
577   SSLSocketStream(socket_t sock, SSL *ssl, time_t read_timeout_sec,
578                   time_t read_timeout_usec, time_t write_timeout_sec,
579                   time_t write_timeout_usec);
580   ~SSLSocketStream() override;
581
582   bool is_readable() const override;
583   bool is_writable() const override;
584   ssize_t read(char *ptr, size_t size) override;
585   ssize_t write(const char *ptr, size_t size) override;
586   void get_remote_ip_and_port(std::string &ip, int &port) const override;
587   void get_local_ip_and_port(std::string &ip, int &port) const override;
588   socket_t socket() const override;
589
590 private:
591   socket_t sock_;
592   SSL *ssl_;
593   time_t read_timeout_sec_;
594   time_t read_timeout_usec_;
595   time_t write_timeout_sec_;
596   time_t write_timeout_usec_;
597 };
598 #endif
599
600 bool keep_alive(socket_t sock, time_t keep_alive_timeout_sec) {
601   using namespace std::chrono;
602   auto start = steady_clock::now();
603   while (true) {
604     auto val = select_read(sock, 0, 10000);
605     if (val < 0) {
606       return false;
607     } else if (val == 0) {
608       auto current = steady_clock::now();
609       auto duration = duration_cast<milliseconds>(current - start);
610       auto timeout = keep_alive_timeout_sec * 1000;
611       if (duration.count() > timeout) { return false; }
612       std::this_thread::sleep_for(std::chrono::milliseconds(1));
613     } else {
614       return true;
615     }
616   }
617 }
618
619 template <typename T>
620 bool
621 process_server_socket_core(const std::atomic<socket_t> &svr_sock, socket_t sock,
622                            size_t keep_alive_max_count,
623                            time_t keep_alive_timeout_sec, T callback) {
624   assert(keep_alive_max_count > 0);
625   auto ret = false;
626   auto count = keep_alive_max_count;
627   while (svr_sock != INVALID_SOCKET && count > 0 &&
628          keep_alive(sock, keep_alive_timeout_sec)) {
629     auto close_connection = count == 1;
630     auto connection_closed = false;
631     ret = callback(close_connection, connection_closed);
632     if (!ret || connection_closed) { break; }
633     count--;
634   }
635   return ret;
636 }
637
638 template <typename T>
639 bool
640 process_server_socket(const std::atomic<socket_t> &svr_sock, socket_t sock,
641                       size_t keep_alive_max_count,
642                       time_t keep_alive_timeout_sec, time_t read_timeout_sec,
643                       time_t read_timeout_usec, time_t write_timeout_sec,
644                       time_t write_timeout_usec, T callback) {
645   return process_server_socket_core(
646       svr_sock, sock, keep_alive_max_count, keep_alive_timeout_sec,
647       [&](bool close_connection, bool &connection_closed) {
648         SocketStream strm(sock, read_timeout_sec, read_timeout_usec,
649                           write_timeout_sec, write_timeout_usec);
650         return callback(strm, close_connection, connection_closed);
651       });
652 }
653
654 bool process_client_socket(socket_t sock, time_t read_timeout_sec,
655                                   time_t read_timeout_usec,
656                                   time_t write_timeout_sec,
657                                   time_t write_timeout_usec,
658                                   std::function<bool(Stream &)> callback) {
659   SocketStream strm(sock, read_timeout_sec, read_timeout_usec,
660                     write_timeout_sec, write_timeout_usec);
661   return callback(strm);
662 }
663
664 int shutdown_socket(socket_t sock) {
665 #ifdef _WIN32
666   return shutdown(sock, SD_BOTH);
667 #else
668   return shutdown(sock, SHUT_RDWR);
669 #endif
670 }
671
672 template <typename BindOrConnect>
673 socket_t create_socket(const std::string &host, const std::string &ip, int port,
674                        int address_family, int socket_flags, bool tcp_nodelay,
675                        SocketOptions socket_options,
676                        BindOrConnect bind_or_connect) {
677   // Get address info
678   const char *node = nullptr;
679   struct addrinfo hints;
680   struct addrinfo *result;
681
682   memset(&hints, 0, sizeof(struct addrinfo));
683   hints.ai_socktype = SOCK_STREAM;
684   hints.ai_protocol = 0;
685
686   if (!ip.empty()) {
687     node = ip.c_str();
688     // Ask getaddrinfo to convert IP in c-string to address
689     hints.ai_family = AF_UNSPEC;
690     hints.ai_flags = AI_NUMERICHOST;
691   } else {
692     if (!host.empty()) { node = host.c_str(); }
693     hints.ai_family = address_family;
694     hints.ai_flags = socket_flags;
695   }
696
697 #ifndef _WIN32
698   if (hints.ai_family == AF_UNIX) {
699     const auto addrlen = host.length();
700     if (addrlen > sizeof(sockaddr_un::sun_path)) return INVALID_SOCKET;
701
702     auto sock = socket(hints.ai_family, hints.ai_socktype, hints.ai_protocol);
703     if (sock != INVALID_SOCKET) {
704       sockaddr_un addr{};
705       addr.sun_family = AF_UNIX;
706       std::copy(host.begin(), host.end(), addr.sun_path);
707
708       hints.ai_addr = reinterpret_cast<sockaddr *>(&addr);
709       hints.ai_addrlen = static_cast<socklen_t>(
710           sizeof(addr) - sizeof(addr.sun_path) + addrlen);
711
712       fcntl(sock, F_SETFD, FD_CLOEXEC);
713       if (socket_options) { socket_options(sock); }
714
715       if (!bind_or_connect(sock, hints)) {
716         close_socket(sock);
717         sock = INVALID_SOCKET;
718       }
719     }
720     return sock;
721   }
722 #endif
723
724   auto service = std::to_string(port);
725
726   if (getaddrinfo(node, service.c_str(), &hints, &result)) {
727 #if defined __linux__ && !defined __ANDROID__
728     res_init();
729 #endif
730     return INVALID_SOCKET;
731   }
732
733   for (auto rp = result; rp; rp = rp->ai_next) {
734     // Create a socket
735 #ifdef _WIN32
736     auto sock =
737         WSASocketW(rp->ai_family, rp->ai_socktype, rp->ai_protocol, nullptr, 0,
738                    WSA_FLAG_NO_HANDLE_INHERIT | WSA_FLAG_OVERLAPPED);
739     /**
740      * Since the WSA_FLAG_NO_HANDLE_INHERIT is only supported on Windows 7 SP1
741      * and above the socket creation fails on older Windows Systems.
742      *
743      * Let's try to create a socket the old way in this case.
744      *
745      * Reference:
746      * https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-wsasocketa
747      *
748      * WSA_FLAG_NO_HANDLE_INHERIT:
749      * This flag is supported on Windows 7 with SP1, Windows Server 2008 R2 with
750      * SP1, and later
751      *
752      */
753     if (sock == INVALID_SOCKET) {
754       sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
755     }
756 #else
757     auto sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
758 #endif
759     if (sock == INVALID_SOCKET) { continue; }
760
761 #ifndef _WIN32
762     if (fcntl(sock, F_SETFD, FD_CLOEXEC) == -1) {
763       close_socket(sock);
764       continue;
765     }
766 #endif
767
768     if (tcp_nodelay) {
769       int yes = 1;
770       setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, reinterpret_cast<char *>(&yes),
771                  sizeof(yes));
772     }
773
774     if (socket_options) { socket_options(sock); }
775
776     if (rp->ai_family == AF_INET6) {
777       int no = 0;
778       setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, reinterpret_cast<char *>(&no),
779                  sizeof(no));
780     }
781
782     // bind or connect
783     if (bind_or_connect(sock, *rp)) {
784       freeaddrinfo(result);
785       return sock;
786     }
787
788     close_socket(sock);
789   }
790
791   freeaddrinfo(result);
792   return INVALID_SOCKET;
793 }
794
795 void set_nonblocking(socket_t sock, bool nonblocking) {
796 #ifdef _WIN32
797   auto flags = nonblocking ? 1UL : 0UL;
798   ioctlsocket(sock, FIONBIO, &flags);
799 #else
800   auto flags = fcntl(sock, F_GETFL, 0);
801   fcntl(sock, F_SETFL,
802         nonblocking ? (flags | O_NONBLOCK) : (flags & (~O_NONBLOCK)));
803 #endif
804 }
805
806 bool is_connection_error() {
807 #ifdef _WIN32
808   return WSAGetLastError() != WSAEWOULDBLOCK;
809 #else
810   return errno != EINPROGRESS;
811 #endif
812 }
813
814 bool bind_ip_address(socket_t sock, const std::string &host) {
815   struct addrinfo hints;
816   struct addrinfo *result;
817
818   memset(&hints, 0, sizeof(struct addrinfo));
819   hints.ai_family = AF_UNSPEC;
820   hints.ai_socktype = SOCK_STREAM;
821   hints.ai_protocol = 0;
822
823   if (getaddrinfo(host.c_str(), "0", &hints, &result)) { return false; }
824
825   auto ret = false;
826   for (auto rp = result; rp; rp = rp->ai_next) {
827     const auto &ai = *rp;
828     if (!::bind(sock, ai.ai_addr, static_cast<socklen_t>(ai.ai_addrlen))) {
829       ret = true;
830       break;
831     }
832   }
833
834   freeaddrinfo(result);
835   return ret;
836 }
837
838 #if !defined _WIN32 && !defined ANDROID && !defined _AIX && !defined __MVS__
839 #define USE_IF2IP
840 #endif
841
842 #ifdef USE_IF2IP
843 std::string if2ip(int address_family, const std::string &ifn) {
844   struct ifaddrs *ifap;
845   getifaddrs(&ifap);
846   std::string addr_candidate;
847   for (auto ifa = ifap; ifa; ifa = ifa->ifa_next) {
848     if (ifa->ifa_addr && ifn == ifa->ifa_name &&
849         (AF_UNSPEC == address_family ||
850          ifa->ifa_addr->sa_family == address_family)) {
851       if (ifa->ifa_addr->sa_family == AF_INET) {
852         auto sa = reinterpret_cast<struct sockaddr_in *>(ifa->ifa_addr);
853         char buf[INET_ADDRSTRLEN];
854         if (inet_ntop(AF_INET, &sa->sin_addr, buf, INET_ADDRSTRLEN)) {
855           freeifaddrs(ifap);
856           return std::string(buf, INET_ADDRSTRLEN);
857         }
858       } else if (ifa->ifa_addr->sa_family == AF_INET6) {
859         auto sa = reinterpret_cast<struct sockaddr_in6 *>(ifa->ifa_addr);
860         if (!IN6_IS_ADDR_LINKLOCAL(&sa->sin6_addr)) {
861           char buf[INET6_ADDRSTRLEN] = {};
862           if (inet_ntop(AF_INET6, &sa->sin6_addr, buf, INET6_ADDRSTRLEN)) {
863             // equivalent to mac's IN6_IS_ADDR_UNIQUE_LOCAL
864             auto s6_addr_head = sa->sin6_addr.s6_addr[0];
865             if (s6_addr_head == 0xfc || s6_addr_head == 0xfd) {
866               addr_candidate = std::string(buf, INET6_ADDRSTRLEN);
867             } else {
868               freeifaddrs(ifap);
869               return std::string(buf, INET6_ADDRSTRLEN);
870             }
871           }
872         }
873       }
874     }
875   }
876   freeifaddrs(ifap);
877   return addr_candidate;
878 }
879 #endif
880
881 socket_t create_client_socket(
882     const std::string &host, const std::string &ip, int port,
883     int address_family, bool tcp_nodelay, SocketOptions socket_options,
884     time_t connection_timeout_sec, time_t connection_timeout_usec,
885     time_t read_timeout_sec, time_t read_timeout_usec, time_t write_timeout_sec,
886     time_t write_timeout_usec, const std::string &intf, Error &error) {
887   auto sock = create_socket(
888       host, ip, port, address_family, 0, tcp_nodelay, std::move(socket_options),
889       [&](socket_t sock2, struct addrinfo &ai) -> bool {
890         if (!intf.empty()) {
891 #ifdef USE_IF2IP
892           auto ip_from_if = if2ip(address_family, intf);
893           if (ip_from_if.empty()) { ip_from_if = intf; }
894           if (!bind_ip_address(sock2, ip_from_if.c_str())) {
895             error = Error::BindIPAddress;
896             return false;
897           }
898 #endif
899         }
900
901         set_nonblocking(sock2, true);
902
903         auto ret =
904             ::connect(sock2, ai.ai_addr, static_cast<socklen_t>(ai.ai_addrlen));
905
906         if (ret < 0) {
907           if (is_connection_error()) {
908             error = Error::Connection;
909             return false;
910           }
911           error = wait_until_socket_is_ready(sock2, connection_timeout_sec,
912                                              connection_timeout_usec);
913           if (error != Error::Success) { return false; }
914         }
915
916         set_nonblocking(sock2, false);
917
918         {
919 #ifdef _WIN32
920           auto timeout = static_cast<uint32_t>(read_timeout_sec * 1000 +
921                                                read_timeout_usec / 1000);
922           setsockopt(sock2, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout,
923                      sizeof(timeout));
924 #else
925           timeval tv;
926           tv.tv_sec = static_cast<long>(read_timeout_sec);
927           tv.tv_usec = static_cast<decltype(tv.tv_usec)>(read_timeout_usec);
928           setsockopt(sock2, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(tv));
929 #endif
930         }
931         {
932
933 #ifdef _WIN32
934           auto timeout = static_cast<uint32_t>(write_timeout_sec * 1000 +
935                                                write_timeout_usec / 1000);
936           setsockopt(sock2, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout,
937                      sizeof(timeout));
938 #else
939           timeval tv;
940           tv.tv_sec = static_cast<long>(write_timeout_sec);
941           tv.tv_usec = static_cast<decltype(tv.tv_usec)>(write_timeout_usec);
942           setsockopt(sock2, SOL_SOCKET, SO_SNDTIMEO, (char *)&tv, sizeof(tv));
943 #endif
944         }
945
946         error = Error::Success;
947         return true;
948       });
949
950   if (sock != INVALID_SOCKET) {
951     error = Error::Success;
952   } else {
953     if (error == Error::Success) { error = Error::Connection; }
954   }
955
956   return sock;
957 }
958
959 bool get_ip_and_port(const struct sockaddr_storage &addr,
960                             socklen_t addr_len, std::string &ip, int &port) {
961   if (addr.ss_family == AF_INET) {
962     port = ntohs(reinterpret_cast<const struct sockaddr_in *>(&addr)->sin_port);
963   } else if (addr.ss_family == AF_INET6) {
964     port =
965         ntohs(reinterpret_cast<const struct sockaddr_in6 *>(&addr)->sin6_port);
966   } else {
967     return false;
968   }
969
970   std::array<char, NI_MAXHOST> ipstr{};
971   if (getnameinfo(reinterpret_cast<const struct sockaddr *>(&addr), addr_len,
972                   ipstr.data(), static_cast<socklen_t>(ipstr.size()), nullptr,
973                   0, NI_NUMERICHOST)) {
974     return false;
975   }
976
977   ip = ipstr.data();
978   return true;
979 }
980
981 void get_local_ip_and_port(socket_t sock, std::string &ip, int &port) {
982   struct sockaddr_storage addr;
983   socklen_t addr_len = sizeof(addr);
984   if (!getsockname(sock, reinterpret_cast<struct sockaddr *>(&addr),
985                    &addr_len)) {
986     get_ip_and_port(addr, addr_len, ip, port);
987   }
988 }
989
990 void get_remote_ip_and_port(socket_t sock, std::string &ip, int &port) {
991   struct sockaddr_storage addr;
992   socklen_t addr_len = sizeof(addr);
993
994   if (!getpeername(sock, reinterpret_cast<struct sockaddr *>(&addr),
995                    &addr_len)) {
996 #ifndef _WIN32
997     if (addr.ss_family == AF_UNIX) {
998 #if defined(__linux__)
999       struct ucred ucred;
1000       socklen_t len = sizeof(ucred);
1001       if (getsockopt(sock, SOL_SOCKET, SO_PEERCRED, &ucred, &len) == 0) {
1002         port = ucred.pid;
1003       }
1004 #elif defined(SOL_LOCAL) && defined(SO_PEERPID) // __APPLE__
1005       pid_t pid;
1006       socklen_t len = sizeof(pid);
1007       if (getsockopt(sock, SOL_LOCAL, SO_PEERPID, &pid, &len) == 0) {
1008         port = pid;
1009       }
1010 #endif
1011       return;
1012     }
1013 #endif
1014     get_ip_and_port(addr, addr_len, ip, port);
1015   }
1016 }
1017
1018 constexpr unsigned int str2tag_core(const char *s, size_t l,
1019                                            unsigned int h) {
1020   return (l == 0)
1021              ? h
1022              : str2tag_core(
1023                    s + 1, l - 1,
1024                    // Unsets the 6 high bits of h, therefore no overflow happens
1025                    (((std::numeric_limits<unsigned int>::max)() >> 6) &
1026                     h * 33) ^
1027                        static_cast<unsigned char>(*s));
1028 }
1029
1030 unsigned int str2tag(const std::string &s) {
1031   return str2tag_core(s.data(), s.size(), 0);
1032 }
1033
1034 namespace udl {
1035
1036 constexpr unsigned int operator"" _t(const char *s, size_t l) {
1037   return str2tag_core(s, l, 0);
1038 }
1039
1040 } // namespace udl
1041
1042 const char *
1043 find_content_type(const std::string &path,
1044                   const std::map<std::string, std::string> &user_data) {
1045   auto ext = file_extension(path);
1046
1047   auto it = user_data.find(ext);
1048   if (it != user_data.end()) { return it->second.c_str(); }
1049
1050   using udl::operator""_t;
1051
1052   switch (str2tag(ext)) {
1053   default: return nullptr;
1054   case "css"_t: return "text/css";
1055   case "csv"_t: return "text/csv";
1056   case "htm"_t:
1057   case "html"_t: return "text/html";
1058   case "js"_t:
1059   case "mjs"_t: return "text/javascript";
1060   case "txt"_t: return "text/plain";
1061   case "vtt"_t: return "text/vtt";
1062
1063   case "apng"_t: return "image/apng";
1064   case "avif"_t: return "image/avif";
1065   case "bmp"_t: return "image/bmp";
1066   case "gif"_t: return "image/gif";
1067   case "png"_t: return "image/png";
1068   case "svg"_t: return "image/svg+xml";
1069   case "webp"_t: return "image/webp";
1070   case "ico"_t: return "image/x-icon";
1071   case "tif"_t: return "image/tiff";
1072   case "tiff"_t: return "image/tiff";
1073   case "jpg"_t:
1074   case "jpeg"_t: return "image/jpeg";
1075
1076   case "mp4"_t: return "video/mp4";
1077   case "mpeg"_t: return "video/mpeg";
1078   case "webm"_t: return "video/webm";
1079
1080   case "mp3"_t: return "audio/mp3";
1081   case "mpga"_t: return "audio/mpeg";
1082   case "weba"_t: return "audio/webm";
1083   case "wav"_t: return "audio/wave";
1084
1085   case "otf"_t: return "font/otf";
1086   case "ttf"_t: return "font/ttf";
1087   case "woff"_t: return "font/woff";
1088   case "woff2"_t: return "font/woff2";
1089
1090   case "7z"_t: return "application/x-7z-compressed";
1091   case "atom"_t: return "application/atom+xml";
1092   case "pdf"_t: return "application/pdf";
1093   case "json"_t: return "application/json";
1094   case "rss"_t: return "application/rss+xml";
1095   case "tar"_t: return "application/x-tar";
1096   case "xht"_t:
1097   case "xhtml"_t: return "application/xhtml+xml";
1098   case "xslt"_t: return "application/xslt+xml";
1099   case "xml"_t: return "application/xml";
1100   case "gz"_t: return "application/gzip";
1101   case "zip"_t: return "application/zip";
1102   case "wasm"_t: return "application/wasm";
1103   }
1104 }
1105
1106 const char *status_message(int status) {
1107   switch (status) {
1108   case 100: return "Continue";
1109   case 101: return "Switching Protocol";
1110   case 102: return "Processing";
1111   case 103: return "Early Hints";
1112   case 200: return "OK";
1113   case 201: return "Created";
1114   case 202: return "Accepted";
1115   case 203: return "Non-Authoritative Information";
1116   case 204: return "No Content";
1117   case 205: return "Reset Content";
1118   case 206: return "Partial Content";
1119   case 207: return "Multi-Status";
1120   case 208: return "Already Reported";
1121   case 226: return "IM Used";
1122   case 300: return "Multiple Choice";
1123   case 301: return "Moved Permanently";
1124   case 302: return "Found";
1125   case 303: return "See Other";
1126   case 304: return "Not Modified";
1127   case 305: return "Use Proxy";
1128   case 306: return "unused";
1129   case 307: return "Temporary Redirect";
1130   case 308: return "Permanent Redirect";
1131   case 400: return "Bad Request";
1132   case 401: return "Unauthorized";
1133   case 402: return "Payment Required";
1134   case 403: return "Forbidden";
1135   case 404: return "Not Found";
1136   case 405: return "Method Not Allowed";
1137   case 406: return "Not Acceptable";
1138   case 407: return "Proxy Authentication Required";
1139   case 408: return "Request Timeout";
1140   case 409: return "Conflict";
1141   case 410: return "Gone";
1142   case 411: return "Length Required";
1143   case 412: return "Precondition Failed";
1144   case 413: return "Payload Too Large";
1145   case 414: return "URI Too Long";
1146   case 415: return "Unsupported Media Type";
1147   case 416: return "Range Not Satisfiable";
1148   case 417: return "Expectation Failed";
1149   case 418: return "I'm a teapot";
1150   case 421: return "Misdirected Request";
1151   case 422: return "Unprocessable Entity";
1152   case 423: return "Locked";
1153   case 424: return "Failed Dependency";
1154   case 425: return "Too Early";
1155   case 426: return "Upgrade Required";
1156   case 428: return "Precondition Required";
1157   case 429: return "Too Many Requests";
1158   case 431: return "Request Header Fields Too Large";
1159   case 451: return "Unavailable For Legal Reasons";
1160   case 501: return "Not Implemented";
1161   case 502: return "Bad Gateway";
1162   case 503: return "Service Unavailable";
1163   case 504: return "Gateway Timeout";
1164   case 505: return "HTTP Version Not Supported";
1165   case 506: return "Variant Also Negotiates";
1166   case 507: return "Insufficient Storage";
1167   case 508: return "Loop Detected";
1168   case 510: return "Not Extended";
1169   case 511: return "Network Authentication Required";
1170
1171   default:
1172   case 500: return "Internal Server Error";
1173   }
1174 }
1175
1176 bool can_compress_content_type(const std::string &content_type) {
1177   using udl::operator""_t;
1178
1179   auto tag = str2tag(content_type);
1180
1181   switch (tag) {
1182   case "image/svg+xml"_t:
1183   case "application/javascript"_t:
1184   case "application/json"_t:
1185   case "application/xml"_t:
1186   case "application/protobuf"_t:
1187   case "application/xhtml+xml"_t: return true;
1188
1189   default:
1190     return !content_type.rfind("text/", 0) && tag != "text/event-stream"_t;
1191   }
1192 }
1193
1194 EncodingType encoding_type(const Request &req, const Response &res) {
1195   auto ret =
1196       detail::can_compress_content_type(res.get_header_value("Content-Type"));
1197   if (!ret) { return EncodingType::None; }
1198
1199   const auto &s = req.get_header_value("Accept-Encoding");
1200   (void)(s);
1201
1202 #ifdef CPPHTTPLIB_BROTLI_SUPPORT
1203   // TODO: 'Accept-Encoding' has br, not br;q=0
1204   ret = s.find("br") != std::string::npos;
1205   if (ret) { return EncodingType::Brotli; }
1206 #endif
1207
1208 #ifdef CPPHTTPLIB_ZLIB_SUPPORT
1209   // TODO: 'Accept-Encoding' has gzip, not gzip;q=0
1210   ret = s.find("gzip") != std::string::npos;
1211   if (ret) { return EncodingType::Gzip; }
1212 #endif
1213
1214   return EncodingType::None;
1215 }
1216
1217 bool nocompressor::compress(const char *data, size_t data_length,
1218                                    bool /*last*/, Callback callback) {
1219   if (!data_length) { return true; }
1220   return callback(data, data_length);
1221 }
1222
1223 #ifdef CPPHTTPLIB_ZLIB_SUPPORT
1224 gzip_compressor::gzip_compressor() {
1225   std::memset(&strm_, 0, sizeof(strm_));
1226   strm_.zalloc = Z_NULL;
1227   strm_.zfree = Z_NULL;
1228   strm_.opaque = Z_NULL;
1229
1230   is_valid_ = deflateInit2(&strm_, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 31, 8,
1231                            Z_DEFAULT_STRATEGY) == Z_OK;
1232 }
1233
1234 gzip_compressor::~gzip_compressor() { deflateEnd(&strm_); }
1235
1236 bool gzip_compressor::compress(const char *data, size_t data_length,
1237                                       bool last, Callback callback) {
1238   assert(is_valid_);
1239
1240   do {
1241     constexpr size_t max_avail_in =
1242         (std::numeric_limits<decltype(strm_.avail_in)>::max)();
1243
1244     strm_.avail_in = static_cast<decltype(strm_.avail_in)>(
1245         (std::min)(data_length, max_avail_in));
1246     strm_.next_in = const_cast<Bytef *>(reinterpret_cast<const Bytef *>(data));
1247
1248     data_length -= strm_.avail_in;
1249     data += strm_.avail_in;
1250
1251     auto flush = (last && data_length == 0) ? Z_FINISH : Z_NO_FLUSH;
1252     int ret = Z_OK;
1253
1254     std::array<char, CPPHTTPLIB_COMPRESSION_BUFSIZ> buff{};
1255     do {
1256       strm_.avail_out = static_cast<uInt>(buff.size());
1257       strm_.next_out = reinterpret_cast<Bytef *>(buff.data());
1258
1259       ret = deflate(&strm_, flush);
1260       if (ret == Z_STREAM_ERROR) { return false; }
1261
1262       if (!callback(buff.data(), buff.size() - strm_.avail_out)) {
1263         return false;
1264       }
1265     } while (strm_.avail_out == 0);
1266
1267     assert((flush == Z_FINISH && ret == Z_STREAM_END) ||
1268            (flush == Z_NO_FLUSH && ret == Z_OK));
1269     assert(strm_.avail_in == 0);
1270   } while (data_length > 0);
1271
1272   return true;
1273 }
1274
1275 gzip_decompressor::gzip_decompressor() {
1276   std::memset(&strm_, 0, sizeof(strm_));
1277   strm_.zalloc = Z_NULL;
1278   strm_.zfree = Z_NULL;
1279   strm_.opaque = Z_NULL;
1280
1281   // 15 is the value of wbits, which should be at the maximum possible value
1282   // to ensure that any gzip stream can be decoded. The offset of 32 specifies
1283   // that the stream type should be automatically detected either gzip or
1284   // deflate.
1285   is_valid_ = inflateInit2(&strm_, 32 + 15) == Z_OK;
1286 }
1287
1288 gzip_decompressor::~gzip_decompressor() { inflateEnd(&strm_); }
1289
1290 bool gzip_decompressor::is_valid() const { return is_valid_; }
1291
1292 bool gzip_decompressor::decompress(const char *data, size_t data_length,
1293                                           Callback callback) {
1294   assert(is_valid_);
1295
1296   int ret = Z_OK;
1297
1298   do {
1299     constexpr size_t max_avail_in =
1300         (std::numeric_limits<decltype(strm_.avail_in)>::max)();
1301
1302     strm_.avail_in = static_cast<decltype(strm_.avail_in)>(
1303         (std::min)(data_length, max_avail_in));
1304     strm_.next_in = const_cast<Bytef *>(reinterpret_cast<const Bytef *>(data));
1305
1306     data_length -= strm_.avail_in;
1307     data += strm_.avail_in;
1308
1309     std::array<char, CPPHTTPLIB_COMPRESSION_BUFSIZ> buff{};
1310     while (strm_.avail_in > 0) {
1311       strm_.avail_out = static_cast<uInt>(buff.size());
1312       strm_.next_out = reinterpret_cast<Bytef *>(buff.data());
1313
1314       auto prev_avail_in = strm_.avail_in;
1315
1316       ret = inflate(&strm_, Z_NO_FLUSH);
1317
1318       if (prev_avail_in - strm_.avail_in == 0) { return false; }
1319
1320       assert(ret != Z_STREAM_ERROR);
1321       switch (ret) {
1322       case Z_NEED_DICT:
1323       case Z_DATA_ERROR:
1324       case Z_MEM_ERROR: inflateEnd(&strm_); return false;
1325       }
1326
1327       if (!callback(buff.data(), buff.size() - strm_.avail_out)) {
1328         return false;
1329       }
1330     }
1331
1332     if (ret != Z_OK && ret != Z_STREAM_END) return false;
1333
1334   } while (data_length > 0);
1335
1336   return true;
1337 }
1338 #endif
1339
1340 #ifdef CPPHTTPLIB_BROTLI_SUPPORT
1341 brotli_compressor::brotli_compressor() {
1342   state_ = BrotliEncoderCreateInstance(nullptr, nullptr, nullptr);
1343 }
1344
1345 brotli_compressor::~brotli_compressor() {
1346   BrotliEncoderDestroyInstance(state_);
1347 }
1348
1349 bool brotli_compressor::compress(const char *data, size_t data_length,
1350                                         bool last, Callback callback) {
1351   std::array<uint8_t, CPPHTTPLIB_COMPRESSION_BUFSIZ> buff{};
1352
1353   auto operation = last ? BROTLI_OPERATION_FINISH : BROTLI_OPERATION_PROCESS;
1354   auto available_in = data_length;
1355   auto next_in = reinterpret_cast<const uint8_t *>(data);
1356
1357   for (;;) {
1358     if (last) {
1359       if (BrotliEncoderIsFinished(state_)) { break; }
1360     } else {
1361       if (!available_in) { break; }
1362     }
1363
1364     auto available_out = buff.size();
1365     auto next_out = buff.data();
1366
1367     if (!BrotliEncoderCompressStream(state_, operation, &available_in, &next_in,
1368                                      &available_out, &next_out, nullptr)) {
1369       return false;
1370     }
1371
1372     auto output_bytes = buff.size() - available_out;
1373     if (output_bytes) {
1374       callback(reinterpret_cast<const char *>(buff.data()), output_bytes);
1375     }
1376   }
1377
1378   return true;
1379 }
1380
1381 brotli_decompressor::brotli_decompressor() {
1382   decoder_s = BrotliDecoderCreateInstance(0, 0, 0);
1383   decoder_r = decoder_s ? BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT
1384                         : BROTLI_DECODER_RESULT_ERROR;
1385 }
1386
1387 brotli_decompressor::~brotli_decompressor() {
1388   if (decoder_s) { BrotliDecoderDestroyInstance(decoder_s); }
1389 }
1390
1391 bool brotli_decompressor::is_valid() const { return decoder_s; }
1392
1393 bool brotli_decompressor::decompress(const char *data,
1394                                             size_t data_length,
1395                                             Callback callback) {
1396   if (decoder_r == BROTLI_DECODER_RESULT_SUCCESS ||
1397       decoder_r == BROTLI_DECODER_RESULT_ERROR) {
1398     return 0;
1399   }
1400
1401   const uint8_t *next_in = (const uint8_t *)data;
1402   size_t avail_in = data_length;
1403   size_t total_out;
1404
1405   decoder_r = BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT;
1406
1407   std::array<char, CPPHTTPLIB_COMPRESSION_BUFSIZ> buff{};
1408   while (decoder_r == BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT) {
1409     char *next_out = buff.data();
1410     size_t avail_out = buff.size();
1411
1412     decoder_r = BrotliDecoderDecompressStream(
1413         decoder_s, &avail_in, &next_in, &avail_out,
1414         reinterpret_cast<uint8_t **>(&next_out), &total_out);
1415
1416     if (decoder_r == BROTLI_DECODER_RESULT_ERROR) { return false; }
1417
1418     if (!callback(buff.data(), buff.size() - avail_out)) { return false; }
1419   }
1420
1421   return decoder_r == BROTLI_DECODER_RESULT_SUCCESS ||
1422          decoder_r == BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT;
1423 }
1424 #endif
1425
1426 bool has_header(const Headers &headers, const std::string &key) {
1427   return headers.find(key) != headers.end();
1428 }
1429
1430 const char *get_header_value(const Headers &headers,
1431                                     const std::string &key, size_t id,
1432                                     const char *def) {
1433   auto rng = headers.equal_range(key);
1434   auto it = rng.first;
1435   std::advance(it, static_cast<ssize_t>(id));
1436   if (it != rng.second) { return it->second.c_str(); }
1437   return def;
1438 }
1439
1440 bool compare_case_ignore(const std::string &a, const std::string &b) {
1441   if (a.size() != b.size()) { return false; }
1442   for (size_t i = 0; i < b.size(); i++) {
1443     if (::tolower(a[i]) != ::tolower(b[i])) { return false; }
1444   }
1445   return true;
1446 }
1447
1448 template <typename T>
1449 bool parse_header(const char *beg, const char *end, T fn) {
1450   // Skip trailing spaces and tabs.
1451   while (beg < end && is_space_or_tab(end[-1])) {
1452     end--;
1453   }
1454
1455   auto p = beg;
1456   while (p < end && *p != ':') {
1457     p++;
1458   }
1459
1460   if (p == end) { return false; }
1461
1462   auto key_end = p;
1463
1464   if (*p++ != ':') { return false; }
1465
1466   while (p < end && is_space_or_tab(*p)) {
1467     p++;
1468   }
1469
1470   if (p < end) {
1471     auto key = std::string(beg, key_end);
1472     auto val = compare_case_ignore(key, "Location")
1473                    ? std::string(p, end)
1474                    : decode_url(std::string(p, end), false);
1475     fn(std::move(key), std::move(val));
1476     return true;
1477   }
1478
1479   return false;
1480 }
1481
1482 bool read_headers(Stream &strm, Headers &headers) {
1483   const auto bufsiz = 2048;
1484   char buf[bufsiz];
1485   stream_line_reader line_reader(strm, buf, bufsiz);
1486
1487   for (;;) {
1488     if (!line_reader.getline()) { return false; }
1489
1490     // Check if the line ends with CRLF.
1491     auto line_terminator_len = 2;
1492     if (line_reader.end_with_crlf()) {
1493       // Blank line indicates end of headers.
1494       if (line_reader.size() == 2) { break; }
1495 #ifdef CPPHTTPLIB_ALLOW_LF_AS_LINE_TERMINATOR
1496     } else {
1497       // Blank line indicates end of headers.
1498       if (line_reader.size() == 1) { break; }
1499       line_terminator_len = 1;
1500     }
1501 #else
1502     } else {
1503       continue; // Skip invalid line.
1504     }
1505 #endif
1506
1507     if (line_reader.size() > CPPHTTPLIB_HEADER_MAX_LENGTH) { return false; }
1508
1509     // Exclude line terminator
1510     auto end = line_reader.ptr() + line_reader.size() - line_terminator_len;
1511
1512     parse_header(line_reader.ptr(), end,
1513                  [&](std::string &&key, std::string &&val) {
1514                    headers.emplace(std::move(key), std::move(val));
1515                  });
1516   }
1517
1518   return true;
1519 }
1520
1521 bool read_content_with_length(Stream &strm, uint64_t len,
1522                                      Progress progress,
1523                                      ContentReceiverWithProgress out) {
1524   char buf[CPPHTTPLIB_RECV_BUFSIZ];
1525
1526   uint64_t r = 0;
1527   while (r < len) {
1528     auto read_len = static_cast<size_t>(len - r);
1529     auto n = strm.read(buf, (std::min)(read_len, CPPHTTPLIB_RECV_BUFSIZ));
1530     if (n <= 0) { return false; }
1531
1532     if (!out(buf, static_cast<size_t>(n), r, len)) { return false; }
1533     r += static_cast<uint64_t>(n);
1534
1535     if (progress) {
1536       if (!progress(r, len)) { return false; }
1537     }
1538   }
1539
1540   return true;
1541 }
1542
1543 void skip_content_with_length(Stream &strm, uint64_t len) {
1544   char buf[CPPHTTPLIB_RECV_BUFSIZ];
1545   uint64_t r = 0;
1546   while (r < len) {
1547     auto read_len = static_cast<size_t>(len - r);
1548     auto n = strm.read(buf, (std::min)(read_len, CPPHTTPLIB_RECV_BUFSIZ));
1549     if (n <= 0) { return; }
1550     r += static_cast<uint64_t>(n);
1551   }
1552 }
1553
1554 bool read_content_without_length(Stream &strm,
1555                                         ContentReceiverWithProgress out) {
1556   char buf[CPPHTTPLIB_RECV_BUFSIZ];
1557   uint64_t r = 0;
1558   for (;;) {
1559     auto n = strm.read(buf, CPPHTTPLIB_RECV_BUFSIZ);
1560     if (n < 0) {
1561       return false;
1562     } else if (n == 0) {
1563       return true;
1564     }
1565
1566     if (!out(buf, static_cast<size_t>(n), r, 0)) { return false; }
1567     r += static_cast<uint64_t>(n);
1568   }
1569
1570   return true;
1571 }
1572
1573 template <typename T>
1574 bool read_content_chunked(Stream &strm, T &x,
1575                                  ContentReceiverWithProgress out) {
1576   const auto bufsiz = 16;
1577   char buf[bufsiz];
1578
1579   stream_line_reader line_reader(strm, buf, bufsiz);
1580
1581   if (!line_reader.getline()) { return false; }
1582
1583   unsigned long chunk_len;
1584   while (true) {
1585     char *end_ptr;
1586
1587     chunk_len = std::strtoul(line_reader.ptr(), &end_ptr, 16);
1588
1589     if (end_ptr == line_reader.ptr()) { return false; }
1590     if (chunk_len == ULONG_MAX) { return false; }
1591
1592     if (chunk_len == 0) { break; }
1593
1594     if (!read_content_with_length(strm, chunk_len, nullptr, out)) {
1595       return false;
1596     }
1597
1598     if (!line_reader.getline()) { return false; }
1599
1600     if (strcmp(line_reader.ptr(), "\r\n")) { return false; }
1601
1602     if (!line_reader.getline()) { return false; }
1603   }
1604
1605   assert(chunk_len == 0);
1606
1607   // Trailer
1608   if (!line_reader.getline()) { return false; }
1609
1610   while (strcmp(line_reader.ptr(), "\r\n")) {
1611     if (line_reader.size() > CPPHTTPLIB_HEADER_MAX_LENGTH) { return false; }
1612
1613     // Exclude line terminator
1614     constexpr auto line_terminator_len = 2;
1615     auto end = line_reader.ptr() + line_reader.size() - line_terminator_len;
1616
1617     parse_header(line_reader.ptr(), end,
1618                  [&](std::string &&key, std::string &&val) {
1619                    x.headers.emplace(std::move(key), std::move(val));
1620                  });
1621
1622     if (!line_reader.getline()) { return false; }
1623   }
1624
1625   return true;
1626 }
1627
1628 bool is_chunked_transfer_encoding(const Headers &headers) {
1629   return !strcasecmp(get_header_value(headers, "Transfer-Encoding", 0, ""),
1630                      "chunked");
1631 }
1632
1633 template <typename T, typename U>
1634 bool prepare_content_receiver(T &x, int &status,
1635                               ContentReceiverWithProgress receiver,
1636                               bool decompress, U callback) {
1637   if (decompress) {
1638     std::string encoding = x.get_header_value("Content-Encoding");
1639     std::unique_ptr<decompressor> decompressor;
1640
1641     if (encoding == "gzip" || encoding == "deflate") {
1642 #ifdef CPPHTTPLIB_ZLIB_SUPPORT
1643       decompressor = detail::make_unique<gzip_decompressor>();
1644 #else
1645       status = 415;
1646       return false;
1647 #endif
1648     } else if (encoding.find("br") != std::string::npos) {
1649 #ifdef CPPHTTPLIB_BROTLI_SUPPORT
1650       decompressor = detail::make_unique<brotli_decompressor>();
1651 #else
1652       status = 415;
1653       return false;
1654 #endif
1655     }
1656
1657     if (decompressor) {
1658       if (decompressor->is_valid()) {
1659         ContentReceiverWithProgress out = [&](const char *buf, size_t n,
1660                                               uint64_t off, uint64_t len) {
1661           return decompressor->decompress(buf, n,
1662                                           [&](const char *buf2, size_t n2) {
1663                                             return receiver(buf2, n2, off, len);
1664                                           });
1665         };
1666         return callback(std::move(out));
1667       } else {
1668         status = 500;
1669         return false;
1670       }
1671     }
1672   }
1673
1674   ContentReceiverWithProgress out = [&](const char *buf, size_t n, uint64_t off,
1675                                         uint64_t len) {
1676     return receiver(buf, n, off, len);
1677   };
1678   return callback(std::move(out));
1679 }
1680
1681 template <typename T>
1682 bool read_content(Stream &strm, T &x, size_t payload_max_length, int &status,
1683                   Progress progress, ContentReceiverWithProgress receiver,
1684                   bool decompress) {
1685   return prepare_content_receiver(
1686       x, status, std::move(receiver), decompress,
1687       [&](const ContentReceiverWithProgress &out) {
1688         auto ret = true;
1689         auto exceed_payload_max_length = false;
1690
1691         if (is_chunked_transfer_encoding(x.headers)) {
1692           ret = read_content_chunked(strm, x, out);
1693         } else if (!has_header(x.headers, "Content-Length")) {
1694           ret = read_content_without_length(strm, out);
1695         } else {
1696           auto len = get_header_value<uint64_t>(x.headers, "Content-Length");
1697           if (len > payload_max_length) {
1698             exceed_payload_max_length = true;
1699             skip_content_with_length(strm, len);
1700             ret = false;
1701           } else if (len > 0) {
1702             ret = read_content_with_length(strm, len, std::move(progress), out);
1703           }
1704         }
1705
1706         if (!ret) { status = exceed_payload_max_length ? 413 : 400; }
1707         return ret;
1708       });
1709 } // namespace detail
1710
1711 ssize_t write_headers(Stream &strm, const Headers &headers) {
1712   ssize_t write_len = 0;
1713   for (const auto &x : headers) {
1714     auto len =
1715         strm.write_format("%s: %s\r\n", x.first.c_str(), x.second.c_str());
1716     if (len < 0) { return len; }
1717     write_len += len;
1718   }
1719   auto len = strm.write("\r\n");
1720   if (len < 0) { return len; }
1721   write_len += len;
1722   return write_len;
1723 }
1724
1725 bool write_data(Stream &strm, const char *d, size_t l) {
1726   size_t offset = 0;
1727   while (offset < l) {
1728     auto length = strm.write(d + offset, l - offset);
1729     if (length < 0) { return false; }
1730     offset += static_cast<size_t>(length);
1731   }
1732   return true;
1733 }
1734
1735 template <typename T>
1736 bool write_content(Stream &strm, const ContentProvider &content_provider,
1737                           size_t offset, size_t length, T is_shutting_down,
1738                           Error &error) {
1739   size_t end_offset = offset + length;
1740   auto ok = true;
1741   DataSink data_sink;
1742
1743   data_sink.write = [&](const char *d, size_t l) -> bool {
1744     if (ok) {
1745       if (strm.is_writable() && write_data(strm, d, l)) {
1746         offset += l;
1747       } else {
1748         ok = false;
1749       }
1750     }
1751     return ok;
1752   };
1753
1754   while (offset < end_offset && !is_shutting_down()) {
1755     if (!strm.is_writable()) {
1756       error = Error::Write;
1757       return false;
1758     } else if (!content_provider(offset, end_offset - offset, data_sink)) {
1759       error = Error::Canceled;
1760       return false;
1761     } else if (!ok) {
1762       error = Error::Write;
1763       return false;
1764     }
1765   }
1766
1767   error = Error::Success;
1768   return true;
1769 }
1770
1771 template <typename T>
1772 bool write_content(Stream &strm, const ContentProvider &content_provider,
1773                           size_t offset, size_t length,
1774                           const T &is_shutting_down) {
1775   auto error = Error::Success;
1776   return write_content(strm, content_provider, offset, length, is_shutting_down,
1777                        error);
1778 }
1779
1780 template <typename T>
1781 bool
1782 write_content_without_length(Stream &strm,
1783                              const ContentProvider &content_provider,
1784                              const T &is_shutting_down) {
1785   size_t offset = 0;
1786   auto data_available = true;
1787   auto ok = true;
1788   DataSink data_sink;
1789
1790   data_sink.write = [&](const char *d, size_t l) -> bool {
1791     if (ok) {
1792       offset += l;
1793       if (!strm.is_writable() || !write_data(strm, d, l)) { ok = false; }
1794     }
1795     return ok;
1796   };
1797
1798   data_sink.done = [&](void) { data_available = false; };
1799
1800   while (data_available && !is_shutting_down()) {
1801     if (!strm.is_writable()) {
1802       return false;
1803     } else if (!content_provider(offset, 0, data_sink)) {
1804       return false;
1805     } else if (!ok) {
1806       return false;
1807     }
1808   }
1809   return true;
1810 }
1811
1812 template <typename T, typename U>
1813 bool
1814 write_content_chunked(Stream &strm, const ContentProvider &content_provider,
1815                       const T &is_shutting_down, U &compressor, Error &error) {
1816   size_t offset = 0;
1817   auto data_available = true;
1818   auto ok = true;
1819   DataSink data_sink;
1820
1821   data_sink.write = [&](const char *d, size_t l) -> bool {
1822     if (ok) {
1823       data_available = l > 0;
1824       offset += l;
1825
1826       std::string payload;
1827       if (compressor.compress(d, l, false,
1828                               [&](const char *data, size_t data_len) {
1829                                 payload.append(data, data_len);
1830                                 return true;
1831                               })) {
1832         if (!payload.empty()) {
1833           // Emit chunked response header and footer for each chunk
1834           auto chunk =
1835               from_i_to_hex(payload.size()) + "\r\n" + payload + "\r\n";
1836           if (!strm.is_writable() ||
1837               !write_data(strm, chunk.data(), chunk.size())) {
1838             ok = false;
1839           }
1840         }
1841       } else {
1842         ok = false;
1843       }
1844     }
1845     return ok;
1846   };
1847
1848   auto done_with_trailer = [&](const Headers *trailer) {
1849     if (!ok) { return; }
1850
1851     data_available = false;
1852
1853     std::string payload;
1854     if (!compressor.compress(nullptr, 0, true,
1855                              [&](const char *data, size_t data_len) {
1856                                payload.append(data, data_len);
1857                                return true;
1858                              })) {
1859       ok = false;
1860       return;
1861     }
1862
1863     if (!payload.empty()) {
1864       // Emit chunked response header and footer for each chunk
1865       auto chunk = from_i_to_hex(payload.size()) + "\r\n" + payload + "\r\n";
1866       if (!strm.is_writable() ||
1867           !write_data(strm, chunk.data(), chunk.size())) {
1868         ok = false;
1869         return;
1870       }
1871     }
1872
1873     static const std::string done_marker("0\r\n");
1874     if (!write_data(strm, done_marker.data(), done_marker.size())) {
1875       ok = false;
1876     }
1877
1878     // Trailer
1879     if (trailer) {
1880       for (const auto &kv : *trailer) {
1881         std::string field_line = kv.first + ": " + kv.second + "\r\n";
1882         if (!write_data(strm, field_line.data(), field_line.size())) {
1883           ok = false;
1884         }
1885       }
1886     }
1887
1888     static const std::string crlf("\r\n");
1889     if (!write_data(strm, crlf.data(), crlf.size())) { ok = false; }
1890   };
1891
1892   data_sink.done = [&](void) { done_with_trailer(nullptr); };
1893
1894   data_sink.done_with_trailer = [&](const Headers &trailer) {
1895     done_with_trailer(&trailer);
1896   };
1897
1898   while (data_available && !is_shutting_down()) {
1899     if (!strm.is_writable()) {
1900       error = Error::Write;
1901       return false;
1902     } else if (!content_provider(offset, 0, data_sink)) {
1903       error = Error::Canceled;
1904       return false;
1905     } else if (!ok) {
1906       error = Error::Write;
1907       return false;
1908     }
1909   }
1910
1911   error = Error::Success;
1912   return true;
1913 }
1914
1915 template <typename T, typename U>
1916 bool write_content_chunked(Stream &strm,
1917                                   const ContentProvider &content_provider,
1918                                   const T &is_shutting_down, U &compressor) {
1919   auto error = Error::Success;
1920   return write_content_chunked(strm, content_provider, is_shutting_down,
1921                                compressor, error);
1922 }
1923
1924 template <typename T>
1925 bool redirect(T &cli, Request &req, Response &res,
1926                      const std::string &path, const std::string &location,
1927                      Error &error) {
1928   Request new_req = req;
1929   new_req.path = path;
1930   new_req.redirect_count_ -= 1;
1931
1932   if (res.status == 303 && (req.method != "GET" && req.method != "HEAD")) {
1933     new_req.method = "GET";
1934     new_req.body.clear();
1935     new_req.headers.clear();
1936   }
1937
1938   Response new_res;
1939
1940   auto ret = cli.send(new_req, new_res, error);
1941   if (ret) {
1942     req = new_req;
1943     res = new_res;
1944     res.location = location;
1945   }
1946   return ret;
1947 }
1948
1949 std::string params_to_query_str(const Params &params) {
1950   std::string query;
1951
1952   for (auto it = params.begin(); it != params.end(); ++it) {
1953     if (it != params.begin()) { query += "&"; }
1954     query += it->first;
1955     query += "=";
1956     query += encode_query_param(it->second);
1957   }
1958   return query;
1959 }
1960
1961 void parse_query_text(const std::string &s, Params &params) {
1962   std::set<std::string> cache;
1963   split(s.data(), s.data() + s.size(), '&', [&](const char *b, const char *e) {
1964     std::string kv(b, e);
1965     if (cache.find(kv) != cache.end()) { return; }
1966     cache.insert(kv);
1967
1968     std::string key;
1969     std::string val;
1970     split(b, e, '=', [&](const char *b2, const char *e2) {
1971       if (key.empty()) {
1972         key.assign(b2, e2);
1973       } else {
1974         val.assign(b2, e2);
1975       }
1976     });
1977
1978     if (!key.empty()) {
1979       params.emplace(decode_url(key, true), decode_url(val, true));
1980     }
1981   });
1982 }
1983
1984 bool parse_multipart_boundary(const std::string &content_type,
1985                                      std::string &boundary) {
1986   auto boundary_keyword = "boundary=";
1987   auto pos = content_type.find(boundary_keyword);
1988   if (pos == std::string::npos) { return false; }
1989   auto end = content_type.find(';', pos);
1990   auto beg = pos + strlen(boundary_keyword);
1991   boundary = content_type.substr(beg, end - beg);
1992   if (boundary.length() >= 2 && boundary.front() == '"' &&
1993       boundary.back() == '"') {
1994     boundary = boundary.substr(1, boundary.size() - 2);
1995   }
1996   return !boundary.empty();
1997 }
1998
1999 #ifdef CPPHTTPLIB_NO_EXCEPTIONS
2000 bool parse_range_header(const std::string &s, Ranges &ranges) {
2001 #else
2002 bool parse_range_header(const std::string &s, Ranges &ranges) try {
2003 #endif
2004   static auto re_first_range = std::regex(R"(bytes=(\d*-\d*(?:,\s*\d*-\d*)*))");
2005   std::smatch m;
2006   if (std::regex_match(s, m, re_first_range)) {
2007     auto pos = static_cast<size_t>(m.position(1));
2008     auto len = static_cast<size_t>(m.length(1));
2009     bool all_valid_ranges = true;
2010     split(&s[pos], &s[pos + len], ',', [&](const char *b, const char *e) {
2011       if (!all_valid_ranges) return;
2012       static auto re_another_range = std::regex(R"(\s*(\d*)-(\d*))");
2013       std::cmatch cm;
2014       if (std::regex_match(b, e, cm, re_another_range)) {
2015         ssize_t first = -1;
2016         if (!cm.str(1).empty()) {
2017           first = static_cast<ssize_t>(std::stoll(cm.str(1)));
2018         }
2019
2020         ssize_t last = -1;
2021         if (!cm.str(2).empty()) {
2022           last = static_cast<ssize_t>(std::stoll(cm.str(2)));
2023         }
2024
2025         if (first != -1 && last != -1 && first > last) {
2026           all_valid_ranges = false;
2027           return;
2028         }
2029         ranges.emplace_back(std::make_pair(first, last));
2030       }
2031     });
2032     return all_valid_ranges;
2033   }
2034   return false;
2035 #ifdef CPPHTTPLIB_NO_EXCEPTIONS
2036 }
2037 #else
2038 } catch (...) { return false; }
2039 #endif
2040
2041 class MultipartFormDataParser {
2042 public:
2043   MultipartFormDataParser() = default;
2044
2045   void set_boundary(std::string &&boundary) {
2046     boundary_ = boundary;
2047     dash_boundary_crlf_ = dash_ + boundary_ + crlf_;
2048     crlf_dash_boundary_ = crlf_ + dash_ + boundary_;
2049   }
2050
2051   bool is_valid() const { return is_valid_; }
2052
2053   bool parse(const char *buf, size_t n, const ContentReceiver &content_callback,
2054              const MultipartContentHeader &header_callback) {
2055
2056     // TODO: support 'filename*'
2057     static const std::regex re_content_disposition(
2058         R"~(^Content-Disposition:\s*form-data;\s*name="(.*?)"(?:;\s*filename="(.*?)")?(?:;\s*filename\*=\S+)?\s*$)~",
2059         std::regex_constants::icase);
2060
2061     buf_append(buf, n);
2062
2063     while (buf_size() > 0) {
2064       switch (state_) {
2065       case 0: { // Initial boundary
2066         buf_erase(buf_find(dash_boundary_crlf_));
2067         if (dash_boundary_crlf_.size() > buf_size()) { return true; }
2068         if (!buf_start_with(dash_boundary_crlf_)) { return false; }
2069         buf_erase(dash_boundary_crlf_.size());
2070         state_ = 1;
2071         break;
2072       }
2073       case 1: { // New entry
2074         clear_file_info();
2075         state_ = 2;
2076         break;
2077       }
2078       case 2: { // Headers
2079         auto pos = buf_find(crlf_);
2080         if (pos > CPPHTTPLIB_HEADER_MAX_LENGTH) { return false; }
2081         while (pos < buf_size()) {
2082           // Empty line
2083           if (pos == 0) {
2084             if (!header_callback(file_)) {
2085               is_valid_ = false;
2086               return false;
2087             }
2088             buf_erase(crlf_.size());
2089             state_ = 3;
2090             break;
2091           }
2092
2093           static const std::string header_name = "content-type:";
2094           const auto header = buf_head(pos);
2095           if (start_with_case_ignore(header, header_name)) {
2096             file_.content_type = trim_copy(header.substr(header_name.size()));
2097           } else {
2098             std::smatch m;
2099             if (std::regex_match(header, m, re_content_disposition)) {
2100               file_.name = m[1];
2101               file_.filename = m[2];
2102             } else {
2103               is_valid_ = false;
2104               return false;
2105             }
2106           }
2107           buf_erase(pos + crlf_.size());
2108           pos = buf_find(crlf_);
2109         }
2110         if (state_ != 3) { return true; }
2111         break;
2112       }
2113       case 3: { // Body
2114         if (crlf_dash_boundary_.size() > buf_size()) { return true; }
2115         auto pos = buf_find(crlf_dash_boundary_);
2116         if (pos < buf_size()) {
2117           if (!content_callback(buf_data(), pos)) {
2118             is_valid_ = false;
2119             return false;
2120           }
2121           buf_erase(pos + crlf_dash_boundary_.size());
2122           state_ = 4;
2123         } else {
2124           auto len = buf_size() - crlf_dash_boundary_.size();
2125           if (len > 0) {
2126             if (!content_callback(buf_data(), len)) {
2127               is_valid_ = false;
2128               return false;
2129             }
2130             buf_erase(len);
2131           }
2132           return true;
2133         }
2134         break;
2135       }
2136       case 4: { // Boundary
2137         if (crlf_.size() > buf_size()) { return true; }
2138         if (buf_start_with(crlf_)) {
2139           buf_erase(crlf_.size());
2140           state_ = 1;
2141         } else {
2142           if (dash_crlf_.size() > buf_size()) { return true; }
2143           if (buf_start_with(dash_crlf_)) {
2144             buf_erase(dash_crlf_.size());
2145             is_valid_ = true;
2146             buf_erase(buf_size()); // Remove epilogue
2147           } else {
2148             return true;
2149           }
2150         }
2151         break;
2152       }
2153       }
2154     }
2155
2156     return true;
2157   }
2158
2159 private:
2160   void clear_file_info() {
2161     file_.name.clear();
2162     file_.filename.clear();
2163     file_.content_type.clear();
2164   }
2165
2166   bool start_with_case_ignore(const std::string &a,
2167                               const std::string &b) const {
2168     if (a.size() < b.size()) { return false; }
2169     for (size_t i = 0; i < b.size(); i++) {
2170       if (::tolower(a[i]) != ::tolower(b[i])) { return false; }
2171     }
2172     return true;
2173   }
2174
2175   const std::string dash_ = "--";
2176   const std::string crlf_ = "\r\n";
2177   const std::string dash_crlf_ = "--\r\n";
2178   std::string boundary_;
2179   std::string dash_boundary_crlf_;
2180   std::string crlf_dash_boundary_;
2181
2182   size_t state_ = 0;
2183   bool is_valid_ = false;
2184   MultipartFormData file_;
2185
2186   // Buffer
2187   bool start_with(const std::string &a, size_t spos, size_t epos,
2188                   const std::string &b) const {
2189     if (epos - spos < b.size()) { return false; }
2190     for (size_t i = 0; i < b.size(); i++) {
2191       if (a[i + spos] != b[i]) { return false; }
2192     }
2193     return true;
2194   }
2195
2196   size_t buf_size() const { return buf_epos_ - buf_spos_; }
2197
2198   const char *buf_data() const { return &buf_[buf_spos_]; }
2199
2200   std::string buf_head(size_t l) const { return buf_.substr(buf_spos_, l); }
2201
2202   bool buf_start_with(const std::string &s) const {
2203     return start_with(buf_, buf_spos_, buf_epos_, s);
2204   }
2205
2206   size_t buf_find(const std::string &s) const {
2207     auto c = s.front();
2208
2209     size_t off = buf_spos_;
2210     while (off < buf_epos_) {
2211       auto pos = off;
2212       while (true) {
2213         if (pos == buf_epos_) { return buf_size(); }
2214         if (buf_[pos] == c) { break; }
2215         pos++;
2216       }
2217
2218       auto remaining_size = buf_epos_ - pos;
2219       if (s.size() > remaining_size) { return buf_size(); }
2220
2221       if (start_with(buf_, pos, buf_epos_, s)) { return pos - buf_spos_; }
2222
2223       off = pos + 1;
2224     }
2225
2226     return buf_size();
2227   }
2228
2229   void buf_append(const char *data, size_t n) {
2230     auto remaining_size = buf_size();
2231     if (remaining_size > 0 && buf_spos_ > 0) {
2232       for (size_t i = 0; i < remaining_size; i++) {
2233         buf_[i] = buf_[buf_spos_ + i];
2234       }
2235     }
2236     buf_spos_ = 0;
2237     buf_epos_ = remaining_size;
2238
2239     if (remaining_size + n > buf_.size()) { buf_.resize(remaining_size + n); }
2240
2241     for (size_t i = 0; i < n; i++) {
2242       buf_[buf_epos_ + i] = data[i];
2243     }
2244     buf_epos_ += n;
2245   }
2246
2247   void buf_erase(size_t size) { buf_spos_ += size; }
2248
2249   std::string buf_;
2250   size_t buf_spos_ = 0;
2251   size_t buf_epos_ = 0;
2252 };
2253
2254 std::string to_lower(const char *beg, const char *end) {
2255   std::string out;
2256   auto it = beg;
2257   while (it != end) {
2258     out += static_cast<char>(::tolower(*it));
2259     it++;
2260   }
2261   return out;
2262 }
2263
2264 std::string make_multipart_data_boundary() {
2265   static const char data[] =
2266       "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
2267
2268   // std::random_device might actually be deterministic on some
2269   // platforms, but due to lack of support in the c++ standard library,
2270   // doing better requires either some ugly hacks or breaking portability.
2271   std::random_device seed_gen;
2272
2273   // Request 128 bits of entropy for initialization
2274   std::seed_seq seed_sequence{seed_gen(), seed_gen(), seed_gen(), seed_gen()};
2275   std::mt19937 engine(seed_sequence);
2276
2277   std::string result = "--cpp-httplib-multipart-data-";
2278
2279   for (auto i = 0; i < 16; i++) {
2280     result += data[engine() % (sizeof(data) - 1)];
2281   }
2282
2283   return result;
2284 }
2285
2286 bool is_multipart_boundary_chars_valid(const std::string &boundary) {
2287   auto valid = true;
2288   for (size_t i = 0; i < boundary.size(); i++) {
2289     auto c = boundary[i];
2290     if (!std::isalnum(c) && c != '-' && c != '_') {
2291       valid = false;
2292       break;
2293     }
2294   }
2295   return valid;
2296 }
2297
2298 template <typename T>
2299 std::string
2300 serialize_multipart_formdata_item_begin(const T &item,
2301                                         const std::string &boundary) {
2302   std::string body = "--" + boundary + "\r\n";
2303   body += "Content-Disposition: form-data; name=\"" + item.name + "\"";
2304   if (!item.filename.empty()) {
2305     body += "; filename=\"" + item.filename + "\"";
2306   }
2307   body += "\r\n";
2308   if (!item.content_type.empty()) {
2309     body += "Content-Type: " + item.content_type + "\r\n";
2310   }
2311   body += "\r\n";
2312
2313   return body;
2314 }
2315
2316 std::string serialize_multipart_formdata_item_end() { return "\r\n"; }
2317
2318 std::string
2319 serialize_multipart_formdata_finish(const std::string &boundary) {
2320   return "--" + boundary + "--\r\n";
2321 }
2322
2323 std::string
2324 serialize_multipart_formdata_get_content_type(const std::string &boundary) {
2325   return "multipart/form-data; boundary=" + boundary;
2326 }
2327
2328 std::string
2329 serialize_multipart_formdata(const MultipartFormDataItems &items,
2330                              const std::string &boundary, bool finish = true) {
2331   std::string body;
2332
2333   for (const auto &item : items) {
2334     body += serialize_multipart_formdata_item_begin(item, boundary);
2335     body += item.content + serialize_multipart_formdata_item_end();
2336   }
2337
2338   if (finish) body += serialize_multipart_formdata_finish(boundary);
2339
2340   return body;
2341 }
2342
2343 std::pair<size_t, size_t>
2344 get_range_offset_and_length(const Request &req, size_t content_length,
2345                             size_t index) {
2346   auto r = req.ranges[index];
2347
2348   if (r.first == -1 && r.second == -1) {
2349     return std::make_pair(0, content_length);
2350   }
2351
2352   auto slen = static_cast<ssize_t>(content_length);
2353
2354   if (r.first == -1) {
2355     r.first = (std::max)(static_cast<ssize_t>(0), slen - r.second);
2356     r.second = slen - 1;
2357   }
2358
2359   if (r.second == -1) { r.second = slen - 1; }
2360   return std::make_pair(r.first, static_cast<size_t>(r.second - r.first) + 1);
2361 }
2362
2363 std::string make_content_range_header_field(size_t offset, size_t length,
2364                                                    size_t content_length) {
2365   std::string field = "bytes ";
2366   field += std::to_string(offset);
2367   field += "-";
2368   field += std::to_string(offset + length - 1);
2369   field += "/";
2370   field += std::to_string(content_length);
2371   return field;
2372 }
2373
2374 template <typename SToken, typename CToken, typename Content>
2375 bool process_multipart_ranges_data(const Request &req, Response &res,
2376                                    const std::string &boundary,
2377                                    const std::string &content_type,
2378                                    SToken stoken, CToken ctoken,
2379                                    Content content) {
2380   for (size_t i = 0; i < req.ranges.size(); i++) {
2381     ctoken("--");
2382     stoken(boundary);
2383     ctoken("\r\n");
2384     if (!content_type.empty()) {
2385       ctoken("Content-Type: ");
2386       stoken(content_type);
2387       ctoken("\r\n");
2388     }
2389
2390     auto offsets = get_range_offset_and_length(req, res.body.size(), i);
2391     auto offset = offsets.first;
2392     auto length = offsets.second;
2393
2394     ctoken("Content-Range: ");
2395     stoken(make_content_range_header_field(offset, length, res.body.size()));
2396     ctoken("\r\n");
2397     ctoken("\r\n");
2398     if (!content(offset, length)) { return false; }
2399     ctoken("\r\n");
2400   }
2401
2402   ctoken("--");
2403   stoken(boundary);
2404   ctoken("--\r\n");
2405
2406   return true;
2407 }
2408
2409 bool make_multipart_ranges_data(const Request &req, Response &res,
2410                                        const std::string &boundary,
2411                                        const std::string &content_type,
2412                                        std::string &data) {
2413   return process_multipart_ranges_data(
2414       req, res, boundary, content_type,
2415       [&](const std::string &token) { data += token; },
2416       [&](const std::string &token) { data += token; },
2417       [&](size_t offset, size_t length) {
2418         if (offset < res.body.size()) {
2419           data += res.body.substr(offset, length);
2420           return true;
2421         }
2422         return false;
2423       });
2424 }
2425
2426 size_t
2427 get_multipart_ranges_data_length(const Request &req, Response &res,
2428                                  const std::string &boundary,
2429                                  const std::string &content_type) {
2430   size_t data_length = 0;
2431
2432   process_multipart_ranges_data(
2433       req, res, boundary, content_type,
2434       [&](const std::string &token) { data_length += token.size(); },
2435       [&](const std::string &token) { data_length += token.size(); },
2436       [&](size_t /*offset*/, size_t length) {
2437         data_length += length;
2438         return true;
2439       });
2440
2441   return data_length;
2442 }
2443
2444 template <typename T>
2445 bool write_multipart_ranges_data(Stream &strm, const Request &req,
2446                                         Response &res,
2447                                         const std::string &boundary,
2448                                         const std::string &content_type,
2449                                         const T &is_shutting_down) {
2450   return process_multipart_ranges_data(
2451       req, res, boundary, content_type,
2452       [&](const std::string &token) { strm.write(token); },
2453       [&](const std::string &token) { strm.write(token); },
2454       [&](size_t offset, size_t length) {
2455         return write_content(strm, res.content_provider_, offset, length,
2456                              is_shutting_down);
2457       });
2458 }
2459
2460 std::pair<size_t, size_t>
2461 get_range_offset_and_length(const Request &req, const Response &res,
2462                             size_t index) {
2463   auto r = req.ranges[index];
2464
2465   if (r.second == -1) {
2466     r.second = static_cast<ssize_t>(res.content_length_) - 1;
2467   }
2468
2469   return std::make_pair(r.first, r.second - r.first + 1);
2470 }
2471
2472 bool expect_content(const Request &req) {
2473   if (req.method == "POST" || req.method == "PUT" || req.method == "PATCH" ||
2474       req.method == "PRI" || req.method == "DELETE") {
2475     return true;
2476   }
2477   // TODO: check if Content-Length is set
2478   return false;
2479 }
2480
2481 bool has_crlf(const std::string &s) {
2482   auto p = s.c_str();
2483   while (*p) {
2484     if (*p == '\r' || *p == '\n') { return true; }
2485     p++;
2486   }
2487   return false;
2488 }
2489
2490 #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
2491 std::string message_digest(const std::string &s, const EVP_MD *algo) {
2492   auto context = std::unique_ptr<EVP_MD_CTX, decltype(&EVP_MD_CTX_free)>(
2493       EVP_MD_CTX_new(), EVP_MD_CTX_free);
2494
2495   unsigned int hash_length = 0;
2496   unsigned char hash[EVP_MAX_MD_SIZE];
2497
2498   EVP_DigestInit_ex(context.get(), algo, nullptr);
2499   EVP_DigestUpdate(context.get(), s.c_str(), s.size());
2500   EVP_DigestFinal_ex(context.get(), hash, &hash_length);
2501
2502   std::stringstream ss;
2503   for (auto i = 0u; i < hash_length; ++i) {
2504     ss << std::hex << std::setw(2) << std::setfill('0')
2505        << (unsigned int)hash[i];
2506   }
2507
2508   return ss.str();
2509 }
2510
2511 std::string MD5(const std::string &s) {
2512   return message_digest(s, EVP_md5());
2513 }
2514
2515 std::string SHA_256(const std::string &s) {
2516   return message_digest(s, EVP_sha256());
2517 }
2518
2519 std::string SHA_512(const std::string &s) {
2520   return message_digest(s, EVP_sha512());
2521 }
2522 #endif
2523
2524 #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
2525 #ifdef _WIN32
2526 // NOTE: This code came up with the following stackoverflow post:
2527 // https://stackoverflow.com/questions/9507184/can-openssl-on-windows-use-the-system-certificate-store
2528 bool load_system_certs_on_windows(X509_STORE *store) {
2529   auto hStore = CertOpenSystemStoreW((HCRYPTPROV_LEGACY)NULL, L"ROOT");
2530   if (!hStore) { return false; }
2531
2532   auto result = false;
2533   PCCERT_CONTEXT pContext = NULL;
2534   while ((pContext = CertEnumCertificatesInStore(hStore, pContext)) !=
2535          nullptr) {
2536     auto encoded_cert =
2537         static_cast<const unsigned char *>(pContext->pbCertEncoded);
2538
2539     auto x509 = d2i_X509(NULL, &encoded_cert, pContext->cbCertEncoded);
2540     if (x509) {
2541       X509_STORE_add_cert(store, x509);
2542       X509_free(x509);
2543       result = true;
2544     }
2545   }
2546
2547   CertFreeCertificateContext(pContext);
2548   CertCloseStore(hStore, 0);
2549
2550   return result;
2551 }
2552 #elif defined(CPPHTTPLIB_USE_CERTS_FROM_MACOSX_KEYCHAIN) && defined(__APPLE__)
2553 #if TARGET_OS_OSX
2554 template <typename T>
2555 using CFObjectPtr =
2556     std::unique_ptr<typename std::remove_pointer<T>::type, void (*)(CFTypeRef)>;
2557
2558 void cf_object_ptr_deleter(CFTypeRef obj) {
2559   if (obj) { CFRelease(obj); }
2560 }
2561
2562 bool retrieve_certs_from_keychain(CFObjectPtr<CFArrayRef> &certs) {
2563   CFStringRef keys[] = {kSecClass, kSecMatchLimit, kSecReturnRef};
2564   CFTypeRef values[] = {kSecClassCertificate, kSecMatchLimitAll,
2565                         kCFBooleanTrue};
2566
2567   CFObjectPtr<CFDictionaryRef> query(
2568       CFDictionaryCreate(nullptr, reinterpret_cast<const void **>(keys), values,
2569                          sizeof(keys) / sizeof(keys[0]),
2570                          &kCFTypeDictionaryKeyCallBacks,
2571                          &kCFTypeDictionaryValueCallBacks),
2572       cf_object_ptr_deleter);
2573
2574   if (!query) { return false; }
2575
2576   CFTypeRef security_items = nullptr;
2577   if (SecItemCopyMatching(query.get(), &security_items) != errSecSuccess ||
2578       CFArrayGetTypeID() != CFGetTypeID(security_items)) {
2579     return false;
2580   }
2581
2582   certs.reset(reinterpret_cast<CFArrayRef>(security_items));
2583   return true;
2584 }
2585
2586 bool retrieve_root_certs_from_keychain(CFObjectPtr<CFArrayRef> &certs) {
2587   CFArrayRef root_security_items = nullptr;
2588   if (SecTrustCopyAnchorCertificates(&root_security_items) != errSecSuccess) {
2589     return false;
2590   }
2591
2592   certs.reset(root_security_items);
2593   return true;
2594 }
2595
2596 bool add_certs_to_x509_store(CFArrayRef certs, X509_STORE *store) {
2597   auto result = false;
2598   for (int i = 0; i < CFArrayGetCount(certs); ++i) {
2599     const auto cert = reinterpret_cast<const __SecCertificate *>(
2600         CFArrayGetValueAtIndex(certs, i));
2601
2602     if (SecCertificateGetTypeID() != CFGetTypeID(cert)) { continue; }
2603
2604     CFDataRef cert_data = nullptr;
2605     if (SecItemExport(cert, kSecFormatX509Cert, 0, nullptr, &cert_data) !=
2606         errSecSuccess) {
2607       continue;
2608     }
2609
2610     CFObjectPtr<CFDataRef> cert_data_ptr(cert_data, cf_object_ptr_deleter);
2611
2612     auto encoded_cert = static_cast<const unsigned char *>(
2613         CFDataGetBytePtr(cert_data_ptr.get()));
2614
2615     auto x509 =
2616         d2i_X509(NULL, &encoded_cert, CFDataGetLength(cert_data_ptr.get()));
2617
2618     if (x509) {
2619       X509_STORE_add_cert(store, x509);
2620       X509_free(x509);
2621       result = true;
2622     }
2623   }
2624
2625   return result;
2626 }
2627
2628 bool load_system_certs_on_macos(X509_STORE *store) {
2629   auto result = false;
2630   CFObjectPtr<CFArrayRef> certs(nullptr, cf_object_ptr_deleter);
2631   if (retrieve_certs_from_keychain(certs) && certs) {
2632     result = add_certs_to_x509_store(certs.get(), store);
2633   }
2634
2635   if (retrieve_root_certs_from_keychain(certs) && certs) {
2636     result = add_certs_to_x509_store(certs.get(), store) || result;
2637   }
2638
2639   return result;
2640 }
2641 #endif // TARGET_OS_OSX
2642 #endif // _WIN32
2643 #endif // CPPHTTPLIB_OPENSSL_SUPPORT
2644
2645 #ifdef _WIN32
2646 class WSInit {
2647 public:
2648   WSInit() {
2649     WSADATA wsaData;
2650     if (WSAStartup(0x0002, &wsaData) == 0) is_valid_ = true;
2651   }
2652
2653   ~WSInit() {
2654     if (is_valid_) WSACleanup();
2655   }
2656
2657   bool is_valid_ = false;
2658 };
2659
2660 static WSInit wsinit_;
2661 #endif
2662
2663 #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
2664 std::pair<std::string, std::string> make_digest_authentication_header(
2665     const Request &req, const std::map<std::string, std::string> &auth,
2666     size_t cnonce_count, const std::string &cnonce, const std::string &username,
2667     const std::string &password, bool is_proxy = false) {
2668   std::string nc;
2669   {
2670     std::stringstream ss;
2671     ss << std::setfill('0') << std::setw(8) << std::hex << cnonce_count;
2672     nc = ss.str();
2673   }
2674
2675   std::string qop;
2676   if (auth.find("qop") != auth.end()) {
2677     qop = auth.at("qop");
2678     if (qop.find("auth-int") != std::string::npos) {
2679       qop = "auth-int";
2680     } else if (qop.find("auth") != std::string::npos) {
2681       qop = "auth";
2682     } else {
2683       qop.clear();
2684     }
2685   }
2686
2687   std::string algo = "MD5";
2688   if (auth.find("algorithm") != auth.end()) { algo = auth.at("algorithm"); }
2689
2690   std::string response;
2691   {
2692     auto H = algo == "SHA-256"   ? detail::SHA_256
2693              : algo == "SHA-512" ? detail::SHA_512
2694                                  : detail::MD5;
2695
2696     auto A1 = username + ":" + auth.at("realm") + ":" + password;
2697
2698     auto A2 = req.method + ":" + req.path;
2699     if (qop == "auth-int") { A2 += ":" + H(req.body); }
2700
2701     if (qop.empty()) {
2702       response = H(H(A1) + ":" + auth.at("nonce") + ":" + H(A2));
2703     } else {
2704       response = H(H(A1) + ":" + auth.at("nonce") + ":" + nc + ":" + cnonce +
2705                    ":" + qop + ":" + H(A2));
2706     }
2707   }
2708
2709   auto opaque = (auth.find("opaque") != auth.end()) ? auth.at("opaque") : "";
2710
2711   auto field = "Digest username=\"" + username + "\", realm=\"" +
2712                auth.at("realm") + "\", nonce=\"" + auth.at("nonce") +
2713                "\", uri=\"" + req.path + "\", algorithm=" + algo +
2714                (qop.empty() ? ", response=\""
2715                             : ", qop=" + qop + ", nc=" + nc + ", cnonce=\"" +
2716                                   cnonce + "\", response=\"") +
2717                response + "\"" +
2718                (opaque.empty() ? "" : ", opaque=\"" + opaque + "\"");
2719
2720   auto key = is_proxy ? "Proxy-Authorization" : "Authorization";
2721   return std::make_pair(key, field);
2722 }
2723 #endif
2724
2725 bool parse_www_authenticate(const Response &res,
2726                                    std::map<std::string, std::string> &auth,
2727                                    bool is_proxy) {
2728   auto auth_key = is_proxy ? "Proxy-Authenticate" : "WWW-Authenticate";
2729   if (res.has_header(auth_key)) {
2730     static auto re = std::regex(R"~((?:(?:,\s*)?(.+?)=(?:"(.*?)"|([^,]*))))~");
2731     auto s = res.get_header_value(auth_key);
2732     auto pos = s.find(' ');
2733     if (pos != std::string::npos) {
2734       auto type = s.substr(0, pos);
2735       if (type == "Basic") {
2736         return false;
2737       } else if (type == "Digest") {
2738         s = s.substr(pos + 1);
2739         auto beg = std::sregex_iterator(s.begin(), s.end(), re);
2740         for (auto i = beg; i != std::sregex_iterator(); ++i) {
2741           auto m = *i;
2742           auto key = s.substr(static_cast<size_t>(m.position(1)),
2743                               static_cast<size_t>(m.length(1)));
2744           auto val = m.length(2) > 0
2745                          ? s.substr(static_cast<size_t>(m.position(2)),
2746                                     static_cast<size_t>(m.length(2)))
2747                          : s.substr(static_cast<size_t>(m.position(3)),
2748                                     static_cast<size_t>(m.length(3)));
2749           auth[key] = val;
2750         }
2751         return true;
2752       }
2753     }
2754   }
2755   return false;
2756 }
2757
2758 // https://stackoverflow.com/questions/440133/how-do-i-create-a-random-alpha-numeric-string-in-c/440240#answer-440240
2759 std::string random_string(size_t length) {
2760   auto randchar = []() -> char {
2761     const char charset[] = "0123456789"
2762                            "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
2763                            "abcdefghijklmnopqrstuvwxyz";
2764     const size_t max_index = (sizeof(charset) - 1);
2765     return charset[static_cast<size_t>(std::rand()) % max_index];
2766   };
2767   std::string str(length, 0);
2768   std::generate_n(str.begin(), length, randchar);
2769   return str;
2770 }
2771
2772 class ContentProviderAdapter {
2773 public:
2774   explicit ContentProviderAdapter(
2775       ContentProviderWithoutLength &&content_provider)
2776       : content_provider_(content_provider) {}
2777
2778   bool operator()(size_t offset, size_t, DataSink &sink) {
2779     return content_provider_(offset, sink);
2780   }
2781
2782 private:
2783   ContentProviderWithoutLength content_provider_;
2784 };
2785
2786 } // namespace detail
2787
2788 std::string hosted_at(const std::string &hostname) {
2789   std::vector<std::string> addrs;
2790   hosted_at(hostname, addrs);
2791   if (addrs.empty()) { return std::string(); }
2792   return addrs[0];
2793 }
2794
2795 void hosted_at(const std::string &hostname,
2796                       std::vector<std::string> &addrs) {
2797   struct addrinfo hints;
2798   struct addrinfo *result;
2799
2800   memset(&hints, 0, sizeof(struct addrinfo));
2801   hints.ai_family = AF_UNSPEC;
2802   hints.ai_socktype = SOCK_STREAM;
2803   hints.ai_protocol = 0;
2804
2805   if (getaddrinfo(hostname.c_str(), nullptr, &hints, &result)) {
2806 #if defined __linux__ && !defined __ANDROID__
2807     res_init();
2808 #endif
2809     return;
2810   }
2811
2812   for (auto rp = result; rp; rp = rp->ai_next) {
2813     const auto &addr =
2814         *reinterpret_cast<struct sockaddr_storage *>(rp->ai_addr);
2815     std::string ip;
2816     int dummy = -1;
2817     if (detail::get_ip_and_port(addr, sizeof(struct sockaddr_storage), ip,
2818                                 dummy)) {
2819       addrs.push_back(ip);
2820     }
2821   }
2822
2823   freeaddrinfo(result);
2824 }
2825
2826 std::string append_query_params(const std::string &path,
2827                                        const Params &params) {
2828   std::string path_with_query = path;
2829   const static std::regex re("[^?]+\\?.*");
2830   auto delm = std::regex_match(path, re) ? '&' : '?';
2831   path_with_query += delm + detail::params_to_query_str(params);
2832   return path_with_query;
2833 }
2834
2835 // Header utilities
2836 std::pair<std::string, std::string> make_range_header(Ranges ranges) {
2837   std::string field = "bytes=";
2838   auto i = 0;
2839   for (auto r : ranges) {
2840     if (i != 0) { field += ", "; }
2841     if (r.first != -1) { field += std::to_string(r.first); }
2842     field += '-';
2843     if (r.second != -1) { field += std::to_string(r.second); }
2844     i++;
2845   }
2846   return std::make_pair("Range", std::move(field));
2847 }
2848
2849 std::pair<std::string, std::string>
2850 make_basic_authentication_header(const std::string &username,
2851                                  const std::string &password, bool is_proxy) {
2852   auto field = "Basic " + detail::base64_encode(username + ":" + password);
2853   auto key = is_proxy ? "Proxy-Authorization" : "Authorization";
2854   return std::make_pair(key, std::move(field));
2855 }
2856
2857 std::pair<std::string, std::string>
2858 make_bearer_token_authentication_header(const std::string &token,
2859                                         bool is_proxy = false) {
2860   auto field = "Bearer " + token;
2861   auto key = is_proxy ? "Proxy-Authorization" : "Authorization";
2862   return std::make_pair(key, std::move(field));
2863 }
2864
2865 // Request implementation
2866 bool Request::has_header(const std::string &key) const {
2867   return detail::has_header(headers, key);
2868 }
2869
2870 std::string Request::get_header_value(const std::string &key,
2871                                              size_t id) const {
2872   return detail::get_header_value(headers, key, id, "");
2873 }
2874
2875 size_t Request::get_header_value_count(const std::string &key) const {
2876   auto r = headers.equal_range(key);
2877   return static_cast<size_t>(std::distance(r.first, r.second));
2878 }
2879
2880 void Request::set_header(const std::string &key,
2881                                 const std::string &val) {
2882   if (!detail::has_crlf(key) && !detail::has_crlf(val)) {
2883     headers.emplace(key, val);
2884   }
2885 }
2886
2887 bool Request::has_param(const std::string &key) const {
2888   return params.find(key) != params.end();
2889 }
2890
2891 std::string Request::get_param_value(const std::string &key,
2892                                             size_t id) const {
2893   auto rng = params.equal_range(key);
2894   auto it = rng.first;
2895   std::advance(it, static_cast<ssize_t>(id));
2896   if (it != rng.second) { return it->second; }
2897   return std::string();
2898 }
2899
2900 size_t Request::get_param_value_count(const std::string &key) const {
2901   auto r = params.equal_range(key);
2902   return static_cast<size_t>(std::distance(r.first, r.second));
2903 }
2904
2905 bool Request::is_multipart_form_data() const {
2906   const auto &content_type = get_header_value("Content-Type");
2907   return !content_type.rfind("multipart/form-data", 0);
2908 }
2909
2910 bool Request::has_file(const std::string &key) const {
2911   return files.find(key) != files.end();
2912 }
2913
2914 MultipartFormData Request::get_file_value(const std::string &key) const {
2915   auto it = files.find(key);
2916   if (it != files.end()) { return it->second; }
2917   return MultipartFormData();
2918 }
2919
2920 std::vector<MultipartFormData>
2921 Request::get_file_values(const std::string &key) const {
2922   std::vector<MultipartFormData> values;
2923   auto rng = files.equal_range(key);
2924   for (auto it = rng.first; it != rng.second; it++) {
2925     values.push_back(it->second);
2926   }
2927   return values;
2928 }
2929
2930 // Response implementation
2931 bool Response::has_header(const std::string &key) const {
2932   return headers.find(key) != headers.end();
2933 }
2934
2935 std::string Response::get_header_value(const std::string &key,
2936                                               size_t id) const {
2937   return detail::get_header_value(headers, key, id, "");
2938 }
2939
2940 size_t Response::get_header_value_count(const std::string &key) const {
2941   auto r = headers.equal_range(key);
2942   return static_cast<size_t>(std::distance(r.first, r.second));
2943 }
2944
2945 void Response::set_header(const std::string &key,
2946                                  const std::string &val) {
2947   if (!detail::has_crlf(key) && !detail::has_crlf(val)) {
2948     headers.emplace(key, val);
2949   }
2950 }
2951
2952 void Response::set_redirect(const std::string &url, int stat) {
2953   if (!detail::has_crlf(url)) {
2954     set_header("Location", url);
2955     if (300 <= stat && stat < 400) {
2956       this->status = stat;
2957     } else {
2958       this->status = 302;
2959     }
2960   }
2961 }
2962
2963 void Response::set_content(const char *s, size_t n,
2964                                   const std::string &content_type) {
2965   body.assign(s, n);
2966
2967   auto rng = headers.equal_range("Content-Type");
2968   headers.erase(rng.first, rng.second);
2969   set_header("Content-Type", content_type);
2970 }
2971
2972 void Response::set_content(const std::string &s,
2973                                   const std::string &content_type) {
2974   set_content(s.data(), s.size(), content_type);
2975 }
2976
2977 void Response::set_content_provider(
2978     size_t in_length, const std::string &content_type, ContentProvider provider,
2979     ContentProviderResourceReleaser resource_releaser) {
2980   set_header("Content-Type", content_type);
2981   content_length_ = in_length;
2982   if (in_length > 0) { content_provider_ = std::move(provider); }
2983   content_provider_resource_releaser_ = resource_releaser;
2984   is_chunked_content_provider_ = false;
2985 }
2986
2987 void Response::set_content_provider(
2988     const std::string &content_type, ContentProviderWithoutLength provider,
2989     ContentProviderResourceReleaser resource_releaser) {
2990   set_header("Content-Type", content_type);
2991   content_length_ = 0;
2992   content_provider_ = detail::ContentProviderAdapter(std::move(provider));
2993   content_provider_resource_releaser_ = resource_releaser;
2994   is_chunked_content_provider_ = false;
2995 }
2996
2997 void Response::set_chunked_content_provider(
2998     const std::string &content_type, ContentProviderWithoutLength provider,
2999     ContentProviderResourceReleaser resource_releaser) {
3000   set_header("Content-Type", content_type);
3001   content_length_ = 0;
3002   content_provider_ = detail::ContentProviderAdapter(std::move(provider));
3003   content_provider_resource_releaser_ = resource_releaser;
3004   is_chunked_content_provider_ = true;
3005 }
3006
3007 // Result implementation
3008 bool Result::has_request_header(const std::string &key) const {
3009   return request_headers_.find(key) != request_headers_.end();
3010 }
3011
3012 std::string Result::get_request_header_value(const std::string &key,
3013                                                     size_t id) const {
3014   return detail::get_header_value(request_headers_, key, id, "");
3015 }
3016
3017 size_t
3018 Result::get_request_header_value_count(const std::string &key) const {
3019   auto r = request_headers_.equal_range(key);
3020   return static_cast<size_t>(std::distance(r.first, r.second));
3021 }
3022
3023 // Stream implementation
3024 ssize_t Stream::write(const char *ptr) {
3025   return write(ptr, strlen(ptr));
3026 }
3027
3028 ssize_t Stream::write(const std::string &s) {
3029   return write(s.data(), s.size());
3030 }
3031
3032 namespace detail {
3033
3034 // Socket stream implementation
3035 SocketStream::SocketStream(socket_t sock, time_t read_timeout_sec,
3036                                   time_t read_timeout_usec,
3037                                   time_t write_timeout_sec,
3038                                   time_t write_timeout_usec)
3039     : sock_(sock), read_timeout_sec_(read_timeout_sec),
3040       read_timeout_usec_(read_timeout_usec),
3041       write_timeout_sec_(write_timeout_sec),
3042       write_timeout_usec_(write_timeout_usec), read_buff_(read_buff_size_, 0) {}
3043
3044 SocketStream::~SocketStream() {}
3045
3046 bool SocketStream::is_readable() const {
3047   return select_read(sock_, read_timeout_sec_, read_timeout_usec_) > 0;
3048 }
3049
3050 bool SocketStream::is_writable() const {
3051   return select_write(sock_, write_timeout_sec_, write_timeout_usec_) > 0 &&
3052          is_socket_alive(sock_);
3053 }
3054
3055 ssize_t SocketStream::read(char *ptr, size_t size) {
3056 #ifdef _WIN32
3057   size =
3058       (std::min)(size, static_cast<size_t>((std::numeric_limits<int>::max)()));
3059 #else
3060   size = (std::min)(size,
3061                     static_cast<size_t>((std::numeric_limits<ssize_t>::max)()));
3062 #endif
3063
3064   if (read_buff_off_ < read_buff_content_size_) {
3065     auto remaining_size = read_buff_content_size_ - read_buff_off_;
3066     if (size <= remaining_size) {
3067       memcpy(ptr, read_buff_.data() + read_buff_off_, size);
3068       read_buff_off_ += size;
3069       return static_cast<ssize_t>(size);
3070     } else {
3071       memcpy(ptr, read_buff_.data() + read_buff_off_, remaining_size);
3072       read_buff_off_ += remaining_size;
3073       return static_cast<ssize_t>(remaining_size);
3074     }
3075   }
3076
3077   if (!is_readable()) { return -1; }
3078
3079   read_buff_off_ = 0;
3080   read_buff_content_size_ = 0;
3081
3082   if (size < read_buff_size_) {
3083     auto n = read_socket(sock_, read_buff_.data(), read_buff_size_,
3084                          CPPHTTPLIB_RECV_FLAGS);
3085     if (n <= 0) {
3086       return n;
3087     } else if (n <= static_cast<ssize_t>(size)) {
3088       memcpy(ptr, read_buff_.data(), static_cast<size_t>(n));
3089       return n;
3090     } else {
3091       memcpy(ptr, read_buff_.data(), size);
3092       read_buff_off_ = size;
3093       read_buff_content_size_ = static_cast<size_t>(n);
3094       return static_cast<ssize_t>(size);
3095     }
3096   } else {
3097     return read_socket(sock_, ptr, size, CPPHTTPLIB_RECV_FLAGS);
3098   }
3099 }
3100
3101 ssize_t SocketStream::write(const char *ptr, size_t size) {
3102   if (!is_writable()) { return -1; }
3103
3104 #if defined(_WIN32) && !defined(_WIN64)
3105   size =
3106       (std::min)(size, static_cast<size_t>((std::numeric_limits<int>::max)()));
3107 #endif
3108
3109   return send_socket(sock_, ptr, size, CPPHTTPLIB_SEND_FLAGS);
3110 }
3111
3112 void SocketStream::get_remote_ip_and_port(std::string &ip,
3113                                                  int &port) const {
3114   return detail::get_remote_ip_and_port(sock_, ip, port);
3115 }
3116
3117 void SocketStream::get_local_ip_and_port(std::string &ip,
3118                                                 int &port) const {
3119   return detail::get_local_ip_and_port(sock_, ip, port);
3120 }
3121
3122 socket_t SocketStream::socket() const { return sock_; }
3123
3124 // Buffer stream implementation
3125 bool BufferStream::is_readable() const { return true; }
3126
3127 bool BufferStream::is_writable() const { return true; }
3128
3129 ssize_t BufferStream::read(char *ptr, size_t size) {
3130 #if defined(_MSC_VER) && _MSC_VER < 1910
3131   auto len_read = buffer._Copy_s(ptr, size, size, position);
3132 #else
3133   auto len_read = buffer.copy(ptr, size, position);
3134 #endif
3135   position += static_cast<size_t>(len_read);
3136   return static_cast<ssize_t>(len_read);
3137 }
3138
3139 ssize_t BufferStream::write(const char *ptr, size_t size) {
3140   buffer.append(ptr, size);
3141   return static_cast<ssize_t>(size);
3142 }
3143
3144 void BufferStream::get_remote_ip_and_port(std::string & /*ip*/,
3145                                                  int & /*port*/) const {}
3146
3147 void BufferStream::get_local_ip_and_port(std::string & /*ip*/,
3148                                                 int & /*port*/) const {}
3149
3150 socket_t BufferStream::socket() const { return 0; }
3151
3152 const std::string &BufferStream::get_buffer() const { return buffer; }
3153
3154 } // namespace detail
3155
3156 // HTTP server implementation
3157 Server::Server()
3158     : new_task_queue(
3159           [] { return new ThreadPool(CPPHTTPLIB_THREAD_POOL_COUNT); }) {
3160 #ifndef _WIN32
3161   signal(SIGPIPE, SIG_IGN);
3162 #endif
3163 }
3164
3165 Server::~Server() {}
3166
3167 Server &Server::Get(const std::string &pattern, Handler handler) {
3168   get_handlers_.push_back(
3169       std::make_pair(std::regex(pattern), std::move(handler)));
3170   return *this;
3171 }
3172
3173 Server &Server::Post(const std::string &pattern, Handler handler) {
3174   post_handlers_.push_back(
3175       std::make_pair(std::regex(pattern), std::move(handler)));
3176   return *this;
3177 }
3178
3179 Server &Server::Post(const std::string &pattern,
3180                             HandlerWithContentReader handler) {
3181   post_handlers_for_content_reader_.push_back(
3182       std::make_pair(std::regex(pattern), std::move(handler)));
3183   return *this;
3184 }
3185
3186 Server &Server::Put(const std::string &pattern, Handler handler) {
3187   put_handlers_.push_back(
3188       std::make_pair(std::regex(pattern), std::move(handler)));
3189   return *this;
3190 }
3191
3192 Server &Server::Put(const std::string &pattern,
3193                            HandlerWithContentReader handler) {
3194   put_handlers_for_content_reader_.push_back(
3195       std::make_pair(std::regex(pattern), std::move(handler)));
3196   return *this;
3197 }
3198
3199 Server &Server::Patch(const std::string &pattern, Handler handler) {
3200   patch_handlers_.push_back(
3201       std::make_pair(std::regex(pattern), std::move(handler)));
3202   return *this;
3203 }
3204
3205 Server &Server::Patch(const std::string &pattern,
3206                              HandlerWithContentReader handler) {
3207   patch_handlers_for_content_reader_.push_back(
3208       std::make_pair(std::regex(pattern), std::move(handler)));
3209   return *this;
3210 }
3211
3212 Server &Server::Delete(const std::string &pattern, Handler handler) {
3213   delete_handlers_.push_back(
3214       std::make_pair(std::regex(pattern), std::move(handler)));
3215   return *this;
3216 }
3217
3218 Server &Server::Delete(const std::string &pattern,
3219                               HandlerWithContentReader handler) {
3220   delete_handlers_for_content_reader_.push_back(
3221       std::make_pair(std::regex(pattern), std::move(handler)));
3222   return *this;
3223 }
3224
3225 Server &Server::Options(const std::string &pattern, Handler handler) {
3226   options_handlers_.push_back(
3227       std::make_pair(std::regex(pattern), std::move(handler)));
3228   return *this;
3229 }
3230
3231 bool Server::set_base_dir(const std::string &dir,
3232                                  const std::string &mount_point) {
3233   return set_mount_point(mount_point, dir);
3234 }
3235
3236 bool Server::set_mount_point(const std::string &mount_point,
3237                                     const std::string &dir, Headers headers) {
3238   if (detail::is_dir(dir)) {
3239     std::string mnt = !mount_point.empty() ? mount_point : "/";
3240     if (!mnt.empty() && mnt[0] == '/') {
3241       base_dirs_.push_back({mnt, dir, std::move(headers)});
3242       return true;
3243     }
3244   }
3245   return false;
3246 }
3247
3248 bool Server::remove_mount_point(const std::string &mount_point) {
3249   for (auto it = base_dirs_.begin(); it != base_dirs_.end(); ++it) {
3250     if (it->mount_point == mount_point) {
3251       base_dirs_.erase(it);
3252       return true;
3253     }
3254   }
3255   return false;
3256 }
3257
3258 Server &
3259 Server::set_file_extension_and_mimetype_mapping(const std::string &ext,
3260                                                 const std::string &mime) {
3261   file_extension_and_mimetype_map_[ext] = mime;
3262   return *this;
3263 }
3264
3265 Server &Server::set_file_request_handler(Handler handler) {
3266   file_request_handler_ = std::move(handler);
3267   return *this;
3268 }
3269
3270 Server &Server::set_error_handler(HandlerWithResponse handler) {
3271   error_handler_ = std::move(handler);
3272   return *this;
3273 }
3274
3275 Server &Server::set_error_handler(Handler handler) {
3276   error_handler_ = [handler](const Request &req, Response &res) {
3277     handler(req, res);
3278     return HandlerResponse::Handled;
3279   };
3280   return *this;
3281 }
3282
3283 Server &Server::set_exception_handler(ExceptionHandler handler) {
3284   exception_handler_ = std::move(handler);
3285   return *this;
3286 }
3287
3288 Server &Server::set_pre_routing_handler(HandlerWithResponse handler) {
3289   pre_routing_handler_ = std::move(handler);
3290   return *this;
3291 }
3292
3293 Server &Server::set_post_routing_handler(Handler handler) {
3294   post_routing_handler_ = std::move(handler);
3295   return *this;
3296 }
3297
3298 Server &Server::set_logger(Logger logger) {
3299   logger_ = std::move(logger);
3300   return *this;
3301 }
3302
3303 Server &
3304 Server::set_expect_100_continue_handler(Expect100ContinueHandler handler) {
3305   expect_100_continue_handler_ = std::move(handler);
3306   return *this;
3307 }
3308
3309 Server &Server::set_address_family(int family) {
3310   address_family_ = family;
3311   return *this;
3312 }
3313
3314 Server &Server::set_tcp_nodelay(bool on) {
3315   tcp_nodelay_ = on;
3316   return *this;
3317 }
3318
3319 Server &Server::set_socket_options(SocketOptions socket_options) {
3320   socket_options_ = std::move(socket_options);
3321   return *this;
3322 }
3323
3324 Server &Server::set_default_headers(Headers headers) {
3325   default_headers_ = std::move(headers);
3326   return *this;
3327 }
3328
3329 Server &Server::set_keep_alive_max_count(size_t count) {
3330   keep_alive_max_count_ = count;
3331   return *this;
3332 }
3333
3334 Server &Server::set_keep_alive_timeout(time_t sec) {
3335   keep_alive_timeout_sec_ = sec;
3336   return *this;
3337 }
3338
3339 Server &Server::set_read_timeout(time_t sec, time_t usec) {
3340   read_timeout_sec_ = sec;
3341   read_timeout_usec_ = usec;
3342   return *this;
3343 }
3344
3345 Server &Server::set_write_timeout(time_t sec, time_t usec) {
3346   write_timeout_sec_ = sec;
3347   write_timeout_usec_ = usec;
3348   return *this;
3349 }
3350
3351 Server &Server::set_idle_interval(time_t sec, time_t usec) {
3352   idle_interval_sec_ = sec;
3353   idle_interval_usec_ = usec;
3354   return *this;
3355 }
3356
3357 Server &Server::set_payload_max_length(size_t length) {
3358   payload_max_length_ = length;
3359   return *this;
3360 }
3361
3362 bool Server::bind_to_port(const std::string &host, int port,
3363                                  int socket_flags) {
3364   if (bind_internal(host, port, socket_flags) < 0) return false;
3365   return true;
3366 }
3367 int Server::bind_to_any_port(const std::string &host, int socket_flags) {
3368   return bind_internal(host, 0, socket_flags);
3369 }
3370
3371 bool Server::listen_after_bind() {
3372   auto se = detail::scope_exit([&]() { done_ = true; });
3373   return listen_internal();
3374 }
3375
3376 bool Server::listen(const std::string &host, int port,
3377                            int socket_flags) {
3378   auto se = detail::scope_exit([&]() { done_ = true; });
3379   return bind_to_port(host, port, socket_flags) && listen_internal();
3380 }
3381
3382 bool Server::is_running() const { return is_running_; }
3383
3384 void Server::wait_until_ready() const {
3385   while (!is_running() && !done_) {
3386     std::this_thread::sleep_for(std::chrono::milliseconds{1});
3387   }
3388 }
3389
3390 void Server::stop() {
3391   if (is_running_) {
3392     assert(svr_sock_ != INVALID_SOCKET);
3393     std::atomic<socket_t> sock(svr_sock_.exchange(INVALID_SOCKET));
3394     detail::shutdown_socket(sock);
3395     detail::close_socket(sock);
3396   }
3397 }
3398
3399 bool Server::parse_request_line(const char *s, Request &req) {
3400   auto len = strlen(s);
3401   if (len < 2 || s[len - 2] != '\r' || s[len - 1] != '\n') { return false; }
3402   len -= 2;
3403
3404   {
3405     size_t count = 0;
3406
3407     detail::split(s, s + len, ' ', [&](const char *b, const char *e) {
3408       switch (count) {
3409       case 0: req.method = std::string(b, e); break;
3410       case 1: req.target = std::string(b, e); break;
3411       case 2: req.version = std::string(b, e); break;
3412       default: break;
3413       }
3414       count++;
3415     });
3416
3417     if (count != 3) { return false; }
3418   }
3419
3420   static const std::set<std::string> methods{
3421       "GET",     "HEAD",    "POST",  "PUT",   "DELETE",
3422       "CONNECT", "OPTIONS", "TRACE", "PATCH", "PRI"};
3423
3424   if (methods.find(req.method) == methods.end()) { return false; }
3425
3426   if (req.version != "HTTP/1.1" && req.version != "HTTP/1.0") { return false; }
3427
3428   {
3429     // Skip URL fragment
3430     for (size_t i = 0; i < req.target.size(); i++) {
3431       if (req.target[i] == '#') {
3432         req.target.erase(i);
3433         break;
3434       }
3435     }
3436
3437     size_t count = 0;
3438
3439     detail::split(req.target.data(), req.target.data() + req.target.size(), '?',
3440                   [&](const char *b, const char *e) {
3441                     switch (count) {
3442                     case 0:
3443                       req.path = detail::decode_url(std::string(b, e), false);
3444                       break;
3445                     case 1: {
3446                       if (e - b > 0) {
3447                         detail::parse_query_text(std::string(b, e), req.params);
3448                       }
3449                       break;
3450                     }
3451                     default: break;
3452                     }
3453                     count++;
3454                   });
3455
3456     if (count > 2) { return false; }
3457   }
3458
3459   return true;
3460 }
3461
3462 bool Server::write_response(Stream &strm, bool close_connection,
3463                                    const Request &req, Response &res) {
3464   return write_response_core(strm, close_connection, req, res, false);
3465 }
3466
3467 bool Server::write_response_with_content(Stream &strm,
3468                                                 bool close_connection,
3469                                                 const Request &req,
3470                                                 Response &res) {
3471   return write_response_core(strm, close_connection, req, res, true);
3472 }
3473
3474 bool Server::write_response_core(Stream &strm, bool close_connection,
3475                                         const Request &req, Response &res,
3476                                         bool need_apply_ranges) {
3477   assert(res.status != -1);
3478
3479   if (400 <= res.status && error_handler_ &&
3480       error_handler_(req, res) == HandlerResponse::Handled) {
3481     need_apply_ranges = true;
3482   }
3483
3484   std::string content_type;
3485   std::string boundary;
3486   if (need_apply_ranges) { apply_ranges(req, res, content_type, boundary); }
3487
3488   // Prepare additional headers
3489   if (close_connection || req.get_header_value("Connection") == "close") {
3490     res.set_header("Connection", "close");
3491   } else {
3492     std::stringstream ss;
3493     ss << "timeout=" << keep_alive_timeout_sec_
3494        << ", max=" << keep_alive_max_count_;
3495     res.set_header("Keep-Alive", ss.str());
3496   }
3497
3498   if (!res.has_header("Content-Type") &&
3499       (!res.body.empty() || res.content_length_ > 0 || res.content_provider_)) {
3500     res.set_header("Content-Type", "text/plain");
3501   }
3502
3503   if (!res.has_header("Content-Length") && res.body.empty() &&
3504       !res.content_length_ && !res.content_provider_) {
3505     res.set_header("Content-Length", "0");
3506   }
3507
3508   if (!res.has_header("Accept-Ranges") && req.method == "HEAD") {
3509     res.set_header("Accept-Ranges", "bytes");
3510   }
3511
3512   if (post_routing_handler_) { post_routing_handler_(req, res); }
3513
3514   // Response line and headers
3515   {
3516     detail::BufferStream bstrm;
3517
3518     if (!bstrm.write_format("HTTP/1.1 %d %s\r\n", res.status,
3519                             detail::status_message(res.status))) {
3520       return false;
3521     }
3522
3523     if (!detail::write_headers(bstrm, res.headers)) { return false; }
3524
3525     // Flush buffer
3526     auto &data = bstrm.get_buffer();
3527     detail::write_data(strm, data.data(), data.size());
3528   }
3529
3530   // Body
3531   auto ret = true;
3532   if (req.method != "HEAD") {
3533     if (!res.body.empty()) {
3534       if (!detail::write_data(strm, res.body.data(), res.body.size())) {
3535         ret = false;
3536       }
3537     } else if (res.content_provider_) {
3538       if (write_content_with_provider(strm, req, res, boundary, content_type)) {
3539         res.content_provider_success_ = true;
3540       } else {
3541         res.content_provider_success_ = false;
3542         ret = false;
3543       }
3544     }
3545   }
3546
3547   // Log
3548   if (logger_) { logger_(req, res); }
3549
3550   return ret;
3551 }
3552
3553 bool
3554 Server::write_content_with_provider(Stream &strm, const Request &req,
3555                                     Response &res, const std::string &boundary,
3556                                     const std::string &content_type) {
3557   auto is_shutting_down = [this]() {
3558     return this->svr_sock_ == INVALID_SOCKET;
3559   };
3560
3561   if (res.content_length_ > 0) {
3562     if (req.ranges.empty()) {
3563       return detail::write_content(strm, res.content_provider_, 0,
3564                                    res.content_length_, is_shutting_down);
3565     } else if (req.ranges.size() == 1) {
3566       auto offsets =
3567           detail::get_range_offset_and_length(req, res.content_length_, 0);
3568       auto offset = offsets.first;
3569       auto length = offsets.second;
3570       return detail::write_content(strm, res.content_provider_, offset, length,
3571                                    is_shutting_down);
3572     } else {
3573       return detail::write_multipart_ranges_data(
3574           strm, req, res, boundary, content_type, is_shutting_down);
3575     }
3576   } else {
3577     if (res.is_chunked_content_provider_) {
3578       auto type = detail::encoding_type(req, res);
3579
3580       std::unique_ptr<detail::compressor> compressor;
3581       if (type == detail::EncodingType::Gzip) {
3582 #ifdef CPPHTTPLIB_ZLIB_SUPPORT
3583         compressor = detail::make_unique<detail::gzip_compressor>();
3584 #endif
3585       } else if (type == detail::EncodingType::Brotli) {
3586 #ifdef CPPHTTPLIB_BROTLI_SUPPORT
3587         compressor = detail::make_unique<detail::brotli_compressor>();
3588 #endif
3589       } else {
3590         compressor = detail::make_unique<detail::nocompressor>();
3591       }
3592       assert(compressor != nullptr);
3593
3594       return detail::write_content_chunked(strm, res.content_provider_,
3595                                            is_shutting_down, *compressor);
3596     } else {
3597       return detail::write_content_without_length(strm, res.content_provider_,
3598                                                   is_shutting_down);
3599     }
3600   }
3601 }
3602
3603 bool Server::read_content(Stream &strm, Request &req, Response &res) {
3604   MultipartFormDataMap::iterator cur;
3605   auto file_count = 0;
3606   if (read_content_core(
3607           strm, req, res,
3608           // Regular
3609           [&](const char *buf, size_t n) {
3610             if (req.body.size() + n > req.body.max_size()) { return false; }
3611             req.body.append(buf, n);
3612             return true;
3613           },
3614           // Multipart
3615           [&](const MultipartFormData &file) {
3616             if (file_count++ == CPPHTTPLIB_MULTIPART_FORM_DATA_FILE_MAX_COUNT) {
3617               return false;
3618             }
3619             cur = req.files.emplace(file.name, file);
3620             return true;
3621           },
3622           [&](const char *buf, size_t n) {
3623             auto &content = cur->second.content;
3624             if (content.size() + n > content.max_size()) { return false; }
3625             content.append(buf, n);
3626             return true;
3627           })) {
3628     const auto &content_type = req.get_header_value("Content-Type");
3629     if (!content_type.find("application/x-www-form-urlencoded")) {
3630       if (req.body.size() > CPPHTTPLIB_FORM_URL_ENCODED_PAYLOAD_MAX_LENGTH) {
3631         res.status = 413; // NOTE: should be 414?
3632         return false;
3633       }
3634       detail::parse_query_text(req.body, req.params);
3635     }
3636     return true;
3637   }
3638   return false;
3639 }
3640
3641 bool Server::read_content_with_content_receiver(
3642     Stream &strm, Request &req, Response &res, ContentReceiver receiver,
3643     MultipartContentHeader multipart_header,
3644     ContentReceiver multipart_receiver) {
3645   return read_content_core(strm, req, res, std::move(receiver),
3646                            std::move(multipart_header),
3647                            std::move(multipart_receiver));
3648 }
3649
3650 bool Server::read_content_core(Stream &strm, Request &req, Response &res,
3651                                       ContentReceiver receiver,
3652                                       MultipartContentHeader multipart_header,
3653                                       ContentReceiver multipart_receiver) {
3654   detail::MultipartFormDataParser multipart_form_data_parser;
3655   ContentReceiverWithProgress out;
3656
3657   if (req.is_multipart_form_data()) {
3658     const auto &content_type = req.get_header_value("Content-Type");
3659     std::string boundary;
3660     if (!detail::parse_multipart_boundary(content_type, boundary)) {
3661       res.status = 400;
3662       return false;
3663     }
3664
3665     multipart_form_data_parser.set_boundary(std::move(boundary));
3666     out = [&](const char *buf, size_t n, uint64_t /*off*/, uint64_t /*len*/) {
3667       /* For debug
3668       size_t pos = 0;
3669       while (pos < n) {
3670         auto read_size = (std::min)<size_t>(1, n - pos);
3671         auto ret = multipart_form_data_parser.parse(
3672             buf + pos, read_size, multipart_receiver, multipart_header);
3673         if (!ret) { return false; }
3674         pos += read_size;
3675       }
3676       return true;
3677       */
3678       return multipart_form_data_parser.parse(buf, n, multipart_receiver,
3679                                               multipart_header);
3680     };
3681   } else {
3682     out = [receiver](const char *buf, size_t n, uint64_t /*off*/,
3683                      uint64_t /*len*/) { return receiver(buf, n); };
3684   }
3685
3686   if (req.method == "DELETE" && !req.has_header("Content-Length")) {
3687     return true;
3688   }
3689
3690   if (!detail::read_content(strm, req, payload_max_length_, res.status, nullptr,
3691                             out, true)) {
3692     return false;
3693   }
3694
3695   if (req.is_multipart_form_data()) {
3696     if (!multipart_form_data_parser.is_valid()) {
3697       res.status = 400;
3698       return false;
3699     }
3700   }
3701
3702   return true;
3703 }
3704
3705 bool Server::handle_file_request(const Request &req, Response &res,
3706                                         bool head) {
3707   for (const auto &entry : base_dirs_) {
3708     // Prefix match
3709     if (!req.path.compare(0, entry.mount_point.size(), entry.mount_point)) {
3710       std::string sub_path = "/" + req.path.substr(entry.mount_point.size());
3711       if (detail::is_valid_path(sub_path)) {
3712         auto path = entry.base_dir + sub_path;
3713         if (path.back() == '/') { path += "index.html"; }
3714
3715         if (detail::is_file(path)) {
3716           detail::read_file(path, res.body);
3717           auto type =
3718               detail::find_content_type(path, file_extension_and_mimetype_map_);
3719           if (type) { res.set_header("Content-Type", type); }
3720           for (const auto &kv : entry.headers) {
3721             res.set_header(kv.first.c_str(), kv.second);
3722           }
3723           res.status = req.has_header("Range") ? 206 : 200;
3724           if (!head && file_request_handler_) {
3725             file_request_handler_(req, res);
3726           }
3727           return true;
3728         }
3729       }
3730     }
3731   }
3732   return false;
3733 }
3734
3735 socket_t
3736 Server::create_server_socket(const std::string &host, int port,
3737                              int socket_flags,
3738                              SocketOptions socket_options) const {
3739   return detail::create_socket(
3740       host, std::string(), port, address_family_, socket_flags, tcp_nodelay_,
3741       std::move(socket_options),
3742       [](socket_t sock, struct addrinfo &ai) -> bool {
3743         if (::bind(sock, ai.ai_addr, static_cast<socklen_t>(ai.ai_addrlen))) {
3744           return false;
3745         }
3746         if (::listen(sock, CPPHTTPLIB_LISTEN_BACKLOG)) { return false; }
3747         return true;
3748       });
3749 }
3750
3751 int Server::bind_internal(const std::string &host, int port,
3752                                  int socket_flags) {
3753   if (!is_valid()) { return -1; }
3754
3755   svr_sock_ = create_server_socket(host, port, socket_flags, socket_options_);
3756   if (svr_sock_ == INVALID_SOCKET) { return -1; }
3757
3758   if (port == 0) {
3759     struct sockaddr_storage addr;
3760     socklen_t addr_len = sizeof(addr);
3761     if (getsockname(svr_sock_, reinterpret_cast<struct sockaddr *>(&addr),
3762                     &addr_len) == -1) {
3763       return -1;
3764     }
3765     if (addr.ss_family == AF_INET) {
3766       return ntohs(reinterpret_cast<struct sockaddr_in *>(&addr)->sin_port);
3767     } else if (addr.ss_family == AF_INET6) {
3768       return ntohs(reinterpret_cast<struct sockaddr_in6 *>(&addr)->sin6_port);
3769     } else {
3770       return -1;
3771     }
3772   } else {
3773     return port;
3774   }
3775 }
3776
3777 bool Server::listen_internal() {
3778   auto ret = true;
3779   is_running_ = true;
3780   auto se = detail::scope_exit([&]() { is_running_ = false; });
3781
3782   {
3783     std::unique_ptr<TaskQueue> task_queue(new_task_queue());
3784
3785     while (svr_sock_ != INVALID_SOCKET) {
3786 #ifndef _WIN32
3787       if (idle_interval_sec_ > 0 || idle_interval_usec_ > 0) {
3788 #endif
3789         auto val = detail::select_read(svr_sock_, idle_interval_sec_,
3790                                        idle_interval_usec_);
3791         if (val == 0) { // Timeout
3792           task_queue->on_idle();
3793           continue;
3794         }
3795 #ifndef _WIN32
3796       }
3797 #endif
3798       socket_t sock = accept(svr_sock_, nullptr, nullptr);
3799
3800       if (sock == INVALID_SOCKET) {
3801         if (errno == EMFILE) {
3802           // The per-process limit of open file descriptors has been reached.
3803           // Try to accept new connections after a short sleep.
3804           std::this_thread::sleep_for(std::chrono::milliseconds(1));
3805           continue;
3806         } else if (errno == EINTR || errno == EAGAIN) {
3807           continue;
3808         }
3809         if (svr_sock_ != INVALID_SOCKET) {
3810           detail::close_socket(svr_sock_);
3811           ret = false;
3812         } else {
3813           ; // The server socket was closed by user.
3814         }
3815         break;
3816       }
3817
3818       {
3819 #ifdef _WIN32
3820         auto timeout = static_cast<uint32_t>(read_timeout_sec_ * 1000 +
3821                                              read_timeout_usec_ / 1000);
3822         setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout,
3823                    sizeof(timeout));
3824 #else
3825         timeval tv;
3826         tv.tv_sec = static_cast<long>(read_timeout_sec_);
3827         tv.tv_usec = static_cast<decltype(tv.tv_usec)>(read_timeout_usec_);
3828         setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(tv));
3829 #endif
3830       }
3831       {
3832
3833 #ifdef _WIN32
3834         auto timeout = static_cast<uint32_t>(write_timeout_sec_ * 1000 +
3835                                              write_timeout_usec_ / 1000);
3836         setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout,
3837                    sizeof(timeout));
3838 #else
3839         timeval tv;
3840         tv.tv_sec = static_cast<long>(write_timeout_sec_);
3841         tv.tv_usec = static_cast<decltype(tv.tv_usec)>(write_timeout_usec_);
3842         setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (char *)&tv, sizeof(tv));
3843 #endif
3844       }
3845
3846       task_queue->enqueue([this, sock]() { process_and_close_socket(sock); });
3847     }
3848
3849     task_queue->shutdown();
3850   }
3851
3852   return ret;
3853 }
3854
3855 bool Server::routing(Request &req, Response &res, Stream &strm) {
3856   if (pre_routing_handler_ &&
3857       pre_routing_handler_(req, res) == HandlerResponse::Handled) {
3858     return true;
3859   }
3860
3861   // File handler
3862   bool is_head_request = req.method == "HEAD";
3863   if ((req.method == "GET" || is_head_request) &&
3864       handle_file_request(req, res, is_head_request)) {
3865     return true;
3866   }
3867
3868   if (detail::expect_content(req)) {
3869     // Content reader handler
3870     {
3871       ContentReader reader(
3872           [&](ContentReceiver receiver) {
3873             return read_content_with_content_receiver(
3874                 strm, req, res, std::move(receiver), nullptr, nullptr);
3875           },
3876           [&](MultipartContentHeader header, ContentReceiver receiver) {
3877             return read_content_with_content_receiver(strm, req, res, nullptr,
3878                                                       std::move(header),
3879                                                       std::move(receiver));
3880           });
3881
3882       if (req.method == "POST") {
3883         if (dispatch_request_for_content_reader(
3884                 req, res, std::move(reader),
3885                 post_handlers_for_content_reader_)) {
3886           return true;
3887         }
3888       } else if (req.method == "PUT") {
3889         if (dispatch_request_for_content_reader(
3890                 req, res, std::move(reader),
3891                 put_handlers_for_content_reader_)) {
3892           return true;
3893         }
3894       } else if (req.method == "PATCH") {
3895         if (dispatch_request_for_content_reader(
3896                 req, res, std::move(reader),
3897                 patch_handlers_for_content_reader_)) {
3898           return true;
3899         }
3900       } else if (req.method == "DELETE") {
3901         if (dispatch_request_for_content_reader(
3902                 req, res, std::move(reader),
3903                 delete_handlers_for_content_reader_)) {
3904           return true;
3905         }
3906       }
3907     }
3908
3909     // Read content into `req.body`
3910     if (!read_content(strm, req, res)) { return false; }
3911   }
3912
3913   // Regular handler
3914   if (req.method == "GET" || req.method == "HEAD") {
3915     return dispatch_request(req, res, get_handlers_);
3916   } else if (req.method == "POST") {
3917     return dispatch_request(req, res, post_handlers_);
3918   } else if (req.method == "PUT") {
3919     return dispatch_request(req, res, put_handlers_);
3920   } else if (req.method == "DELETE") {
3921     return dispatch_request(req, res, delete_handlers_);
3922   } else if (req.method == "OPTIONS") {
3923     return dispatch_request(req, res, options_handlers_);
3924   } else if (req.method == "PATCH") {
3925     return dispatch_request(req, res, patch_handlers_);
3926   }
3927
3928   res.status = 400;
3929   return false;
3930 }
3931
3932 bool Server::dispatch_request(Request &req, Response &res,
3933                                      const Handlers &handlers) {
3934   for (const auto &x : handlers) {
3935     const auto &pattern = x.first;
3936     const auto &handler = x.second;
3937
3938     if (std::regex_match(req.path, req.matches, pattern)) {
3939       handler(req, res);
3940       return true;
3941     }
3942   }
3943   return false;
3944 }
3945
3946 void Server::apply_ranges(const Request &req, Response &res,
3947                                  std::string &content_type,
3948                                  std::string &boundary) {
3949   if (req.ranges.size() > 1) {
3950     boundary = detail::make_multipart_data_boundary();
3951
3952     auto it = res.headers.find("Content-Type");
3953     if (it != res.headers.end()) {
3954       content_type = it->second;
3955       res.headers.erase(it);
3956     }
3957
3958     res.set_header("Content-Type",
3959                    "multipart/byteranges; boundary=" + boundary);
3960   }
3961
3962   auto type = detail::encoding_type(req, res);
3963
3964   if (res.body.empty()) {
3965     if (res.content_length_ > 0) {
3966       size_t length = 0;
3967       if (req.ranges.empty()) {
3968         length = res.content_length_;
3969       } else if (req.ranges.size() == 1) {
3970         auto offsets =
3971             detail::get_range_offset_and_length(req, res.content_length_, 0);
3972         auto offset = offsets.first;
3973         length = offsets.second;
3974         auto content_range = detail::make_content_range_header_field(
3975             offset, length, res.content_length_);
3976         res.set_header("Content-Range", content_range);
3977       } else {
3978         length = detail::get_multipart_ranges_data_length(req, res, boundary,
3979                                                           content_type);
3980       }
3981       res.set_header("Content-Length", std::to_string(length));
3982     } else {
3983       if (res.content_provider_) {
3984         if (res.is_chunked_content_provider_) {
3985           res.set_header("Transfer-Encoding", "chunked");
3986           if (type == detail::EncodingType::Gzip) {
3987             res.set_header("Content-Encoding", "gzip");
3988           } else if (type == detail::EncodingType::Brotli) {
3989             res.set_header("Content-Encoding", "br");
3990           }
3991         }
3992       }
3993     }
3994   } else {
3995     if (req.ranges.empty()) {
3996       ;
3997     } else if (req.ranges.size() == 1) {
3998       auto offsets =
3999           detail::get_range_offset_and_length(req, res.body.size(), 0);
4000       auto offset = offsets.first;
4001       auto length = offsets.second;
4002       auto content_range = detail::make_content_range_header_field(
4003           offset, length, res.body.size());
4004       res.set_header("Content-Range", content_range);
4005       if (offset < res.body.size()) {
4006         res.body = res.body.substr(offset, length);
4007       } else {
4008         res.body.clear();
4009         res.status = 416;
4010       }
4011     } else {
4012       std::string data;
4013       if (detail::make_multipart_ranges_data(req, res, boundary, content_type,
4014                                              data)) {
4015         res.body.swap(data);
4016       } else {
4017         res.body.clear();
4018         res.status = 416;
4019       }
4020     }
4021
4022     if (type != detail::EncodingType::None) {
4023       std::unique_ptr<detail::compressor> compressor;
4024       std::string content_encoding;
4025
4026       if (type == detail::EncodingType::Gzip) {
4027 #ifdef CPPHTTPLIB_ZLIB_SUPPORT
4028         compressor = detail::make_unique<detail::gzip_compressor>();
4029         content_encoding = "gzip";
4030 #endif
4031       } else if (type == detail::EncodingType::Brotli) {
4032 #ifdef CPPHTTPLIB_BROTLI_SUPPORT
4033         compressor = detail::make_unique<detail::brotli_compressor>();
4034         content_encoding = "br";
4035 #endif
4036       }
4037
4038       if (compressor) {
4039         std::string compressed;
4040         if (compressor->compress(res.body.data(), res.body.size(), true,
4041                                  [&](const char *data, size_t data_len) {
4042                                    compressed.append(data, data_len);
4043                                    return true;
4044                                  })) {
4045           res.body.swap(compressed);
4046           res.set_header("Content-Encoding", content_encoding);
4047         }
4048       }
4049     }
4050
4051     auto length = std::to_string(res.body.size());
4052     res.set_header("Content-Length", length);
4053   }
4054 }
4055
4056 bool Server::dispatch_request_for_content_reader(
4057     Request &req, Response &res, ContentReader content_reader,
4058     const HandlersForContentReader &handlers) {
4059   for (const auto &x : handlers) {
4060     const auto &pattern = x.first;
4061     const auto &handler = x.second;
4062
4063     if (std::regex_match(req.path, req.matches, pattern)) {
4064       handler(req, res, content_reader);
4065       return true;
4066     }
4067   }
4068   return false;
4069 }
4070
4071 bool
4072 Server::process_request(Stream &strm, bool close_connection,
4073                         bool &connection_closed,
4074                         const std::function<void(Request &)> &setup_request) {
4075   std::array<char, 2048> buf{};
4076
4077   detail::stream_line_reader line_reader(strm, buf.data(), buf.size());
4078
4079   // Connection has been closed on client
4080   if (!line_reader.getline()) { return false; }
4081
4082   Request req;
4083   Response res;
4084
4085   res.version = "HTTP/1.1";
4086
4087   for (const auto &header : default_headers_) {
4088     if (res.headers.find(header.first) == res.headers.end()) {
4089       res.headers.insert(header);
4090     }
4091   }
4092
4093 #ifdef _WIN32
4094   // TODO: Increase FD_SETSIZE statically (libzmq), dynamically (MySQL).
4095 #else
4096 #ifndef CPPHTTPLIB_USE_POLL
4097   // Socket file descriptor exceeded FD_SETSIZE...
4098   if (strm.socket() >= FD_SETSIZE) {
4099     Headers dummy;
4100     detail::read_headers(strm, dummy);
4101     res.status = 500;
4102     return write_response(strm, close_connection, req, res);
4103   }
4104 #endif
4105 #endif
4106
4107   // Check if the request URI doesn't exceed the limit
4108   if (line_reader.size() > CPPHTTPLIB_REQUEST_URI_MAX_LENGTH) {
4109     Headers dummy;
4110     detail::read_headers(strm, dummy);
4111     res.status = 414;
4112     return write_response(strm, close_connection, req, res);
4113   }
4114
4115   // Request line and headers
4116   if (!parse_request_line(line_reader.ptr(), req) ||
4117       !detail::read_headers(strm, req.headers)) {
4118     res.status = 400;
4119     return write_response(strm, close_connection, req, res);
4120   }
4121
4122   if (req.get_header_value("Connection") == "close") {
4123     connection_closed = true;
4124   }
4125
4126   if (req.version == "HTTP/1.0" &&
4127       req.get_header_value("Connection") != "Keep-Alive") {
4128     connection_closed = true;
4129   }
4130
4131   strm.get_remote_ip_and_port(req.remote_addr, req.remote_port);
4132   req.set_header("REMOTE_ADDR", req.remote_addr);
4133   req.set_header("REMOTE_PORT", std::to_string(req.remote_port));
4134
4135   strm.get_local_ip_and_port(req.local_addr, req.local_port);
4136   req.set_header("LOCAL_ADDR", req.local_addr);
4137   req.set_header("LOCAL_PORT", std::to_string(req.local_port));
4138
4139   if (req.has_header("Range")) {
4140     const auto &range_header_value = req.get_header_value("Range");
4141     if (!detail::parse_range_header(range_header_value, req.ranges)) {
4142       res.status = 416;
4143       return write_response(strm, close_connection, req, res);
4144     }
4145   }
4146
4147   if (setup_request) { setup_request(req); }
4148
4149   if (req.get_header_value("Expect") == "100-continue") {
4150     auto status = 100;
4151     if (expect_100_continue_handler_) {
4152       status = expect_100_continue_handler_(req, res);
4153     }
4154     switch (status) {
4155     case 100:
4156     case 417:
4157       strm.write_format("HTTP/1.1 %d %s\r\n\r\n", status,
4158                         detail::status_message(status));
4159       break;
4160     default: return write_response(strm, close_connection, req, res);
4161     }
4162   }
4163
4164   // Rounting
4165   bool routed = false;
4166 #ifdef CPPHTTPLIB_NO_EXCEPTIONS
4167   routed = routing(req, res, strm);
4168 #else
4169   try {
4170     routed = routing(req, res, strm);
4171   } catch (std::exception &e) {
4172     if (exception_handler_) {
4173       auto ep = std::current_exception();
4174       exception_handler_(req, res, ep);
4175       routed = true;
4176     } else {
4177       res.status = 500;
4178       std::string val;
4179       auto s = e.what();
4180       for (size_t i = 0; s[i]; i++) {
4181         switch (s[i]) {
4182         case '\r': val += "\\r"; break;
4183         case '\n': val += "\\n"; break;
4184         default: val += s[i]; break;
4185         }
4186       }
4187       res.set_header("EXCEPTION_WHAT", val);
4188     }
4189   } catch (...) {
4190     if (exception_handler_) {
4191       auto ep = std::current_exception();
4192       exception_handler_(req, res, ep);
4193       routed = true;
4194     } else {
4195       res.status = 500;
4196       res.set_header("EXCEPTION_WHAT", "UNKNOWN");
4197     }
4198   }
4199 #endif
4200
4201   if (routed) {
4202     if (res.status == -1) { res.status = req.ranges.empty() ? 200 : 206; }
4203     return write_response_with_content(strm, close_connection, req, res);
4204   } else {
4205     if (res.status == -1) { res.status = 404; }
4206     return write_response(strm, close_connection, req, res);
4207   }
4208 }
4209
4210 bool Server::is_valid() const { return true; }
4211
4212 bool Server::process_and_close_socket(socket_t sock) {
4213   auto ret = detail::process_server_socket(
4214       svr_sock_, sock, keep_alive_max_count_, keep_alive_timeout_sec_,
4215       read_timeout_sec_, read_timeout_usec_, write_timeout_sec_,
4216       write_timeout_usec_,
4217       [this](Stream &strm, bool close_connection, bool &connection_closed) {
4218         return process_request(strm, close_connection, connection_closed,
4219                                nullptr);
4220       });
4221
4222   detail::shutdown_socket(sock);
4223   detail::close_socket(sock);
4224   return ret;
4225 }
4226
4227 // HTTP client implementation
4228 ClientImpl::ClientImpl(const std::string &host)
4229     : ClientImpl(host, 80, std::string(), std::string()) {}
4230
4231 ClientImpl::ClientImpl(const std::string &host, int port)
4232     : ClientImpl(host, port, std::string(), std::string()) {}
4233
4234 ClientImpl::ClientImpl(const std::string &host, int port,
4235                               const std::string &client_cert_path,
4236                               const std::string &client_key_path)
4237     : host_(host), port_(port),
4238       host_and_port_(adjust_host_string(host) + ":" + std::to_string(port)),
4239       client_cert_path_(client_cert_path), client_key_path_(client_key_path) {}
4240
4241 ClientImpl::~ClientImpl() {
4242   std::lock_guard<std::mutex> guard(socket_mutex_);
4243   shutdown_socket(socket_);
4244   close_socket(socket_);
4245 }
4246
4247 bool ClientImpl::is_valid() const { return true; }
4248
4249 void ClientImpl::copy_settings(const ClientImpl &rhs) {
4250   client_cert_path_ = rhs.client_cert_path_;
4251   client_key_path_ = rhs.client_key_path_;
4252   connection_timeout_sec_ = rhs.connection_timeout_sec_;
4253   read_timeout_sec_ = rhs.read_timeout_sec_;
4254   read_timeout_usec_ = rhs.read_timeout_usec_;
4255   write_timeout_sec_ = rhs.write_timeout_sec_;
4256   write_timeout_usec_ = rhs.write_timeout_usec_;
4257   basic_auth_username_ = rhs.basic_auth_username_;
4258   basic_auth_password_ = rhs.basic_auth_password_;
4259   bearer_token_auth_token_ = rhs.bearer_token_auth_token_;
4260 #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
4261   digest_auth_username_ = rhs.digest_auth_username_;
4262   digest_auth_password_ = rhs.digest_auth_password_;
4263 #endif
4264   keep_alive_ = rhs.keep_alive_;
4265   follow_location_ = rhs.follow_location_;
4266   url_encode_ = rhs.url_encode_;
4267   address_family_ = rhs.address_family_;
4268   tcp_nodelay_ = rhs.tcp_nodelay_;
4269   socket_options_ = rhs.socket_options_;
4270   compress_ = rhs.compress_;
4271   decompress_ = rhs.decompress_;
4272   interface_ = rhs.interface_;
4273   proxy_host_ = rhs.proxy_host_;
4274   proxy_port_ = rhs.proxy_port_;
4275   proxy_basic_auth_username_ = rhs.proxy_basic_auth_username_;
4276   proxy_basic_auth_password_ = rhs.proxy_basic_auth_password_;
4277   proxy_bearer_token_auth_token_ = rhs.proxy_bearer_token_auth_token_;
4278 #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
4279   proxy_digest_auth_username_ = rhs.proxy_digest_auth_username_;
4280   proxy_digest_auth_password_ = rhs.proxy_digest_auth_password_;
4281 #endif
4282 #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
4283   ca_cert_file_path_ = rhs.ca_cert_file_path_;
4284   ca_cert_dir_path_ = rhs.ca_cert_dir_path_;
4285   ca_cert_store_ = rhs.ca_cert_store_;
4286 #endif
4287 #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
4288   server_certificate_verification_ = rhs.server_certificate_verification_;
4289 #endif
4290   logger_ = rhs.logger_;
4291 }
4292
4293 socket_t ClientImpl::create_client_socket(Error &error) const {
4294   if (!proxy_host_.empty() && proxy_port_ != -1) {
4295     return detail::create_client_socket(
4296         proxy_host_, std::string(), proxy_port_, address_family_, tcp_nodelay_,
4297         socket_options_, connection_timeout_sec_, connection_timeout_usec_,
4298         read_timeout_sec_, read_timeout_usec_, write_timeout_sec_,
4299         write_timeout_usec_, interface_, error);
4300   }
4301
4302   // Check is custom IP specified for host_
4303   std::string ip;
4304   auto it = addr_map_.find(host_);
4305   if (it != addr_map_.end()) ip = it->second;
4306
4307   return detail::create_client_socket(
4308       host_, ip, port_, address_family_, tcp_nodelay_, socket_options_,
4309       connection_timeout_sec_, connection_timeout_usec_, read_timeout_sec_,
4310       read_timeout_usec_, write_timeout_sec_, write_timeout_usec_, interface_,
4311       error);
4312 }
4313
4314 bool ClientImpl::create_and_connect_socket(Socket &socket,
4315                                                   Error &error) {
4316   auto sock = create_client_socket(error);
4317   if (sock == INVALID_SOCKET) { return false; }
4318   socket.sock = sock;
4319   return true;
4320 }
4321
4322 void ClientImpl::shutdown_ssl(Socket & /*socket*/,
4323                                      bool /*shutdown_gracefully*/) {
4324   // If there are any requests in flight from threads other than us, then it's
4325   // a thread-unsafe race because individual ssl* objects are not thread-safe.
4326   assert(socket_requests_in_flight_ == 0 ||
4327          socket_requests_are_from_thread_ == std::this_thread::get_id());
4328 }
4329
4330 void ClientImpl::shutdown_socket(Socket &socket) {
4331   if (socket.sock == INVALID_SOCKET) { return; }
4332   detail::shutdown_socket(socket.sock);
4333 }
4334
4335 void ClientImpl::close_socket(Socket &socket) {
4336   // If there are requests in flight in another thread, usually closing
4337   // the socket will be fine and they will simply receive an error when
4338   // using the closed socket, but it is still a bug since rarely the OS
4339   // may reassign the socket id to be used for a new socket, and then
4340   // suddenly they will be operating on a live socket that is different
4341   // than the one they intended!
4342   assert(socket_requests_in_flight_ == 0 ||
4343          socket_requests_are_from_thread_ == std::this_thread::get_id());
4344
4345   // It is also a bug if this happens while SSL is still active
4346 #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
4347   assert(socket.ssl == nullptr);
4348 #endif
4349   if (socket.sock == INVALID_SOCKET) { return; }
4350   detail::close_socket(socket.sock);
4351   socket.sock = INVALID_SOCKET;
4352 }
4353
4354 bool ClientImpl::read_response_line(Stream &strm, const Request &req,
4355                                            Response &res) {
4356   std::array<char, 2048> buf{};
4357
4358   detail::stream_line_reader line_reader(strm, buf.data(), buf.size());
4359
4360   if (!line_reader.getline()) { return false; }
4361
4362 #ifdef CPPHTTPLIB_ALLOW_LF_AS_LINE_TERMINATOR
4363   const static std::regex re("(HTTP/1\\.[01]) (\\d{3})(?: (.*?))?\r\n");
4364 #else
4365   const static std::regex re("(HTTP/1\\.[01]) (\\d{3})(?: (.*?))?\r?\n");
4366 #endif
4367
4368   std::cmatch m;
4369   if (!std::regex_match(line_reader.ptr(), m, re)) {
4370     return req.method == "CONNECT";
4371   }
4372   res.version = std::string(m[1]);
4373   res.status = std::stoi(std::string(m[2]));
4374   res.reason = std::string(m[3]);
4375
4376   // Ignore '100 Continue'
4377   while (res.status == 100) {
4378     if (!line_reader.getline()) { return false; } // CRLF
4379     if (!line_reader.getline()) { return false; } // next response line
4380
4381     if (!std::regex_match(line_reader.ptr(), m, re)) { return false; }
4382     res.version = std::string(m[1]);
4383     res.status = std::stoi(std::string(m[2]));
4384     res.reason = std::string(m[3]);
4385   }
4386
4387   return true;
4388 }
4389
4390 bool ClientImpl::send(Request &req, Response &res, Error &error) {
4391   std::lock_guard<std::recursive_mutex> request_mutex_guard(request_mutex_);
4392   auto ret = send_(req, res, error);
4393   if (error == Error::SSLPeerCouldBeClosed_) {
4394     assert(!ret);
4395     ret = send_(req, res, error);
4396   }
4397   return ret;
4398 }
4399
4400 bool ClientImpl::send_(Request &req, Response &res, Error &error) {
4401   {
4402     std::lock_guard<std::mutex> guard(socket_mutex_);
4403
4404     // Set this to false immediately - if it ever gets set to true by the end of
4405     // the request, we know another thread instructed us to close the socket.
4406     socket_should_be_closed_when_request_is_done_ = false;
4407
4408     auto is_alive = false;
4409     if (socket_.is_open()) {
4410       is_alive = detail::is_socket_alive(socket_.sock);
4411       if (!is_alive) {
4412         // Attempt to avoid sigpipe by shutting down nongracefully if it seems
4413         // like the other side has already closed the connection Also, there
4414         // cannot be any requests in flight from other threads since we locked
4415         // request_mutex_, so safe to close everything immediately
4416         const bool shutdown_gracefully = false;
4417         shutdown_ssl(socket_, shutdown_gracefully);
4418         shutdown_socket(socket_);
4419         close_socket(socket_);
4420       }
4421     }
4422
4423     if (!is_alive) {
4424       if (!create_and_connect_socket(socket_, error)) { return false; }
4425
4426 #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
4427       // TODO: refactoring
4428       if (is_ssl()) {
4429         auto &scli = static_cast<SSLClient &>(*this);
4430         if (!proxy_host_.empty() && proxy_port_ != -1) {
4431           auto success = false;
4432           if (!scli.connect_with_proxy(socket_, res, success, error)) {
4433             return success;
4434           }
4435         }
4436
4437         if (!scli.initialize_ssl(socket_, error)) { return false; }
4438       }
4439 #endif
4440     }
4441
4442     // Mark the current socket as being in use so that it cannot be closed by
4443     // anyone else while this request is ongoing, even though we will be
4444     // releasing the mutex.
4445     if (socket_requests_in_flight_ > 1) {
4446       assert(socket_requests_are_from_thread_ == std::this_thread::get_id());
4447     }
4448     socket_requests_in_flight_ += 1;
4449     socket_requests_are_from_thread_ = std::this_thread::get_id();
4450   }
4451
4452   for (const auto &header : default_headers_) {
4453     if (req.headers.find(header.first) == req.headers.end()) {
4454       req.headers.insert(header);
4455     }
4456   }
4457
4458   auto ret = false;
4459   auto close_connection = !keep_alive_;
4460
4461   auto se = detail::scope_exit([&]() {
4462     // Briefly lock mutex in order to mark that a request is no longer ongoing
4463     std::lock_guard<std::mutex> guard(socket_mutex_);
4464     socket_requests_in_flight_ -= 1;
4465     if (socket_requests_in_flight_ <= 0) {
4466       assert(socket_requests_in_flight_ == 0);
4467       socket_requests_are_from_thread_ = std::thread::id();
4468     }
4469
4470     if (socket_should_be_closed_when_request_is_done_ || close_connection ||
4471         !ret) {
4472       shutdown_ssl(socket_, true);
4473       shutdown_socket(socket_);
4474       close_socket(socket_);
4475     }
4476   });
4477
4478   ret = process_socket(socket_, [&](Stream &strm) {
4479     return handle_request(strm, req, res, close_connection, error);
4480   });
4481
4482   if (!ret) {
4483     if (error == Error::Success) { error = Error::Unknown; }
4484   }
4485
4486   return ret;
4487 }
4488
4489 Result ClientImpl::send(const Request &req) {
4490   auto req2 = req;
4491   return send_(std::move(req2));
4492 }
4493
4494 Result ClientImpl::send_(Request &&req) {
4495   auto res = detail::make_unique<Response>();
4496   auto error = Error::Success;
4497   auto ret = send(req, *res, error);
4498   return Result{ret ? std::move(res) : nullptr, error, std::move(req.headers)};
4499 }
4500
4501 bool ClientImpl::handle_request(Stream &strm, Request &req,
4502                                        Response &res, bool close_connection,
4503                                        Error &error) {
4504   if (req.path.empty()) {
4505     error = Error::Connection;
4506     return false;
4507   }
4508
4509   auto req_save = req;
4510
4511   bool ret;
4512
4513   if (!is_ssl() && !proxy_host_.empty() && proxy_port_ != -1) {
4514     auto req2 = req;
4515     req2.path = "http://" + host_and_port_ + req.path;
4516     ret = process_request(strm, req2, res, close_connection, error);
4517     req = req2;
4518     req.path = req_save.path;
4519   } else {
4520     ret = process_request(strm, req, res, close_connection, error);
4521   }
4522
4523   if (!ret) { return false; }
4524
4525   if (300 < res.status && res.status < 400 && follow_location_) {
4526     req = req_save;
4527     ret = redirect(req, res, error);
4528   }
4529
4530 #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
4531   if ((res.status == 401 || res.status == 407) &&
4532       req.authorization_count_ < 5) {
4533     auto is_proxy = res.status == 407;
4534     const auto &username =
4535         is_proxy ? proxy_digest_auth_username_ : digest_auth_username_;
4536     const auto &password =
4537         is_proxy ? proxy_digest_auth_password_ : digest_auth_password_;
4538
4539     if (!username.empty() && !password.empty()) {
4540       std::map<std::string, std::string> auth;
4541       if (detail::parse_www_authenticate(res, auth, is_proxy)) {
4542         Request new_req = req;
4543         new_req.authorization_count_ += 1;
4544         new_req.headers.erase(is_proxy ? "Proxy-Authorization"
4545                                        : "Authorization");
4546         new_req.headers.insert(detail::make_digest_authentication_header(
4547             req, auth, new_req.authorization_count_, detail::random_string(10),
4548             username, password, is_proxy));
4549
4550         Response new_res;
4551
4552         ret = send(new_req, new_res, error);
4553         if (ret) { res = new_res; }
4554       }
4555     }
4556   }
4557 #endif
4558
4559   return ret;
4560 }
4561
4562 bool ClientImpl::redirect(Request &req, Response &res, Error &error) {
4563   if (req.redirect_count_ == 0) {
4564     error = Error::ExceedRedirectCount;
4565     return false;
4566   }
4567
4568   auto location = res.get_header_value("location");
4569   if (location.empty()) { return false; }
4570
4571   const static std::regex re(
4572       R"((?:(https?):)?(?://(?:\[([\d:]+)\]|([^:/?#]+))(?::(\d+))?)?([^?#]*)(\?[^#]*)?(?:#.*)?)");
4573
4574   std::smatch m;
4575   if (!std::regex_match(location, m, re)) { return false; }
4576
4577   auto scheme = is_ssl() ? "https" : "http";
4578
4579   auto next_scheme = m[1].str();
4580   auto next_host = m[2].str();
4581   if (next_host.empty()) { next_host = m[3].str(); }
4582   auto port_str = m[4].str();
4583   auto next_path = m[5].str();
4584   auto next_query = m[6].str();
4585
4586   auto next_port = port_;
4587   if (!port_str.empty()) {
4588     next_port = std::stoi(port_str);
4589   } else if (!next_scheme.empty()) {
4590     next_port = next_scheme == "https" ? 443 : 80;
4591   }
4592
4593   if (next_scheme.empty()) { next_scheme = scheme; }
4594   if (next_host.empty()) { next_host = host_; }
4595   if (next_path.empty()) { next_path = "/"; }
4596
4597   auto path = detail::decode_url(next_path, true) + next_query;
4598
4599   if (next_scheme == scheme && next_host == host_ && next_port == port_) {
4600     return detail::redirect(*this, req, res, path, location, error);
4601   } else {
4602     if (next_scheme == "https") {
4603 #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
4604       SSLClient cli(next_host.c_str(), next_port);
4605       cli.copy_settings(*this);
4606       if (ca_cert_store_) { cli.set_ca_cert_store(ca_cert_store_); }
4607       return detail::redirect(cli, req, res, path, location, error);
4608 #else
4609       return false;
4610 #endif
4611     } else {
4612       ClientImpl cli(next_host.c_str(), next_port);
4613       cli.copy_settings(*this);
4614       return detail::redirect(cli, req, res, path, location, error);
4615     }
4616   }
4617 }
4618
4619 bool ClientImpl::write_content_with_provider(Stream &strm,
4620                                                     const Request &req,
4621                                                     Error &error) {
4622   auto is_shutting_down = []() { return false; };
4623
4624   if (req.is_chunked_content_provider_) {
4625     // TODO: Brotli support
4626     std::unique_ptr<detail::compressor> compressor;
4627 #ifdef CPPHTTPLIB_ZLIB_SUPPORT
4628     if (compress_) {
4629       compressor = detail::make_unique<detail::gzip_compressor>();
4630     } else
4631 #endif
4632     {
4633       compressor = detail::make_unique<detail::nocompressor>();
4634     }
4635
4636     return detail::write_content_chunked(strm, req.content_provider_,
4637                                          is_shutting_down, *compressor, error);
4638   } else {
4639     return detail::write_content(strm, req.content_provider_, 0,
4640                                  req.content_length_, is_shutting_down, error);
4641   }
4642 }
4643
4644 bool ClientImpl::write_request(Stream &strm, Request &req,
4645                                       bool close_connection, Error &error) {
4646   // Prepare additional headers
4647   if (close_connection) {
4648     if (!req.has_header("Connection")) {
4649       req.set_header("Connection", "close");
4650     }
4651   }
4652
4653   if (!req.has_header("Host")) {
4654     if (is_ssl()) {
4655       if (port_ == 443) {
4656         req.set_header("Host", host_);
4657       } else {
4658         req.set_header("Host", host_and_port_);
4659       }
4660     } else {
4661       if (port_ == 80) {
4662         req.set_header("Host", host_);
4663       } else {
4664         req.set_header("Host", host_and_port_);
4665       }
4666     }
4667   }
4668
4669   if (!req.has_header("Accept")) { req.set_header("Accept", "*/*"); }
4670
4671 #ifndef CPPHTTPLIB_NO_DEFAULT_USER_AGENT
4672   if (!req.has_header("User-Agent")) {
4673     auto agent = std::string("cpp-httplib/") + CPPHTTPLIB_VERSION;
4674     req.set_header("User-Agent", agent);
4675   }
4676 #endif
4677
4678   if (req.body.empty()) {
4679     if (req.content_provider_) {
4680       if (!req.is_chunked_content_provider_) {
4681         if (!req.has_header("Content-Length")) {
4682           auto length = std::to_string(req.content_length_);
4683           req.set_header("Content-Length", length);
4684         }
4685       }
4686     } else {
4687       if (req.method == "POST" || req.method == "PUT" ||
4688           req.method == "PATCH") {
4689         req.set_header("Content-Length", "0");
4690       }
4691     }
4692   } else {
4693     if (!req.has_header("Content-Type")) {
4694       req.set_header("Content-Type", "text/plain");
4695     }
4696
4697     if (!req.has_header("Content-Length")) {
4698       auto length = std::to_string(req.body.size());
4699       req.set_header("Content-Length", length);
4700     }
4701   }
4702
4703   if (!basic_auth_password_.empty() || !basic_auth_username_.empty()) {
4704     if (!req.has_header("Authorization")) {
4705       req.headers.insert(make_basic_authentication_header(
4706           basic_auth_username_, basic_auth_password_, false));
4707     }
4708   }
4709
4710   if (!proxy_basic_auth_username_.empty() &&
4711       !proxy_basic_auth_password_.empty()) {
4712     if (!req.has_header("Proxy-Authorization")) {
4713       req.headers.insert(make_basic_authentication_header(
4714           proxy_basic_auth_username_, proxy_basic_auth_password_, true));
4715     }
4716   }
4717
4718   if (!bearer_token_auth_token_.empty()) {
4719     if (!req.has_header("Authorization")) {
4720       req.headers.insert(make_bearer_token_authentication_header(
4721           bearer_token_auth_token_, false));
4722     }
4723   }
4724
4725   if (!proxy_bearer_token_auth_token_.empty()) {
4726     if (!req.has_header("Proxy-Authorization")) {
4727       req.headers.insert(make_bearer_token_authentication_header(
4728           proxy_bearer_token_auth_token_, true));
4729     }
4730   }
4731
4732   // Request line and headers
4733   {
4734     detail::BufferStream bstrm;
4735
4736     const auto &path = url_encode_ ? detail::encode_url(req.path) : req.path;
4737     bstrm.write_format("%s %s HTTP/1.1\r\n", req.method.c_str(), path.c_str());
4738
4739     detail::write_headers(bstrm, req.headers);
4740
4741     // Flush buffer
4742     auto &data = bstrm.get_buffer();
4743     if (!detail::write_data(strm, data.data(), data.size())) {
4744       error = Error::Write;
4745       return false;
4746     }
4747   }
4748
4749   // Body
4750   if (req.body.empty()) {
4751     return write_content_with_provider(strm, req, error);
4752   }
4753
4754   if (!detail::write_data(strm, req.body.data(), req.body.size())) {
4755     error = Error::Write;
4756     return false;
4757   }
4758
4759   return true;
4760 }
4761
4762 std::unique_ptr<Response> ClientImpl::send_with_content_provider(
4763     Request &req, const char *body, size_t content_length,
4764     ContentProvider content_provider,
4765     ContentProviderWithoutLength content_provider_without_length,
4766     const std::string &content_type, Error &error) {
4767   if (!content_type.empty()) { req.set_header("Content-Type", content_type); }
4768
4769 #ifdef CPPHTTPLIB_ZLIB_SUPPORT
4770   if (compress_) { req.set_header("Content-Encoding", "gzip"); }
4771 #endif
4772
4773 #ifdef CPPHTTPLIB_ZLIB_SUPPORT
4774   if (compress_ && !content_provider_without_length) {
4775     // TODO: Brotli support
4776     detail::gzip_compressor compressor;
4777
4778     if (content_provider) {
4779       auto ok = true;
4780       size_t offset = 0;
4781       DataSink data_sink;
4782
4783       data_sink.write = [&](const char *data, size_t data_len) -> bool {
4784         if (ok) {
4785           auto last = offset + data_len == content_length;
4786
4787           auto ret = compressor.compress(
4788               data, data_len, last,
4789               [&](const char *compressed_data, size_t compressed_data_len) {
4790                 req.body.append(compressed_data, compressed_data_len);
4791                 return true;
4792               });
4793
4794           if (ret) {
4795             offset += data_len;
4796           } else {
4797             ok = false;
4798           }
4799         }
4800         return ok;
4801       };
4802
4803       while (ok && offset < content_length) {
4804         if (!content_provider(offset, content_length - offset, data_sink)) {
4805           error = Error::Canceled;
4806           return nullptr;
4807         }
4808       }
4809     } else {
4810       if (!compressor.compress(body, content_length, true,
4811                                [&](const char *data, size_t data_len) {
4812                                  req.body.append(data, data_len);
4813                                  return true;
4814                                })) {
4815         error = Error::Compression;
4816         return nullptr;
4817       }
4818     }
4819   } else
4820 #endif
4821   {
4822     if (content_provider) {
4823       req.content_length_ = content_length;
4824       req.content_provider_ = std::move(content_provider);
4825       req.is_chunked_content_provider_ = false;
4826     } else if (content_provider_without_length) {
4827       req.content_length_ = 0;
4828       req.content_provider_ = detail::ContentProviderAdapter(
4829           std::move(content_provider_without_length));
4830       req.is_chunked_content_provider_ = true;
4831       req.set_header("Transfer-Encoding", "chunked");
4832     } else {
4833       req.body.assign(body, content_length);
4834     }
4835   }
4836
4837   auto res = detail::make_unique<Response>();
4838   return send(req, *res, error) ? std::move(res) : nullptr;
4839 }
4840
4841 Result ClientImpl::send_with_content_provider(
4842     const std::string &method, const std::string &path, const Headers &headers,
4843     const char *body, size_t content_length, ContentProvider content_provider,
4844     ContentProviderWithoutLength content_provider_without_length,
4845     const std::string &content_type) {
4846   Request req;
4847   req.method = method;
4848   req.headers = headers;
4849   req.path = path;
4850
4851   auto error = Error::Success;
4852
4853   auto res = send_with_content_provider(
4854       req, body, content_length, std::move(content_provider),
4855       std::move(content_provider_without_length), content_type, error);
4856
4857   return Result{std::move(res), error, std::move(req.headers)};
4858 }
4859
4860 std::string
4861 ClientImpl::adjust_host_string(const std::string &host) const {
4862   if (host.find(':') != std::string::npos) { return "[" + host + "]"; }
4863   return host;
4864 }
4865
4866 bool ClientImpl::process_request(Stream &strm, Request &req,
4867                                         Response &res, bool close_connection,
4868                                         Error &error) {
4869   // Send request
4870   if (!write_request(strm, req, close_connection, error)) { return false; }
4871
4872 #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
4873   if (is_ssl()) {
4874     auto is_proxy_enabled = !proxy_host_.empty() && proxy_port_ != -1;
4875     if (!is_proxy_enabled) {
4876       char buf[1];
4877       if (SSL_peek(socket_.ssl, buf, 1) == 0 &&
4878           SSL_get_error(socket_.ssl, 0) == SSL_ERROR_ZERO_RETURN) {
4879         error = Error::SSLPeerCouldBeClosed_;
4880         return false;
4881       }
4882     }
4883   }
4884 #endif
4885
4886   // Receive response and headers
4887   if (!read_response_line(strm, req, res) ||
4888       !detail::read_headers(strm, res.headers)) {
4889     error = Error::Read;
4890     return false;
4891   }
4892
4893   // Body
4894   if ((res.status != 204) && req.method != "HEAD" && req.method != "CONNECT") {
4895     auto redirect = 300 < res.status && res.status < 400 && follow_location_;
4896
4897     if (req.response_handler && !redirect) {
4898       if (!req.response_handler(res)) {
4899         error = Error::Canceled;
4900         return false;
4901       }
4902     }
4903
4904     auto out =
4905         req.content_receiver
4906             ? static_cast<ContentReceiverWithProgress>(
4907                   [&](const char *buf, size_t n, uint64_t off, uint64_t len) {
4908                     if (redirect) { return true; }
4909                     auto ret = req.content_receiver(buf, n, off, len);
4910                     if (!ret) { error = Error::Canceled; }
4911                     return ret;
4912                   })
4913             : static_cast<ContentReceiverWithProgress>(
4914                   [&](const char *buf, size_t n, uint64_t /*off*/,
4915                       uint64_t /*len*/) {
4916                     if (res.body.size() + n > res.body.max_size()) {
4917                       return false;
4918                     }
4919                     res.body.append(buf, n);
4920                     return true;
4921                   });
4922
4923     auto progress = [&](uint64_t current, uint64_t total) {
4924       if (!req.progress || redirect) { return true; }
4925       auto ret = req.progress(current, total);
4926       if (!ret) { error = Error::Canceled; }
4927       return ret;
4928     };
4929
4930     int dummy_status;
4931     if (!detail::read_content(strm, res, (std::numeric_limits<size_t>::max)(),
4932                               dummy_status, std::move(progress), std::move(out),
4933                               decompress_)) {
4934       if (error != Error::Canceled) { error = Error::Read; }
4935       return false;
4936     }
4937   }
4938
4939   if (res.get_header_value("Connection") == "close" ||
4940       (res.version == "HTTP/1.0" && res.reason != "Connection established")) {
4941     // TODO this requires a not-entirely-obvious chain of calls to be correct
4942     // for this to be safe. Maybe a code refactor (such as moving this out to
4943     // the send function and getting rid of the recursiveness of the mutex)
4944     // could make this more obvious.
4945
4946     // This is safe to call because process_request is only called by
4947     // handle_request which is only called by send, which locks the request
4948     // mutex during the process. It would be a bug to call it from a different
4949     // thread since it's a thread-safety issue to do these things to the socket
4950     // if another thread is using the socket.
4951     std::lock_guard<std::mutex> guard(socket_mutex_);
4952     shutdown_ssl(socket_, true);
4953     shutdown_socket(socket_);
4954     close_socket(socket_);
4955   }
4956
4957   // Log
4958   if (logger_) { logger_(req, res); }
4959
4960   return true;
4961 }
4962
4963 ContentProviderWithoutLength ClientImpl::get_multipart_content_provider(
4964     const std::string &boundary, const MultipartFormDataItems &items,
4965     const MultipartFormDataProviderItems &provider_items) {
4966   size_t cur_item = 0, cur_start = 0;
4967   // cur_item and cur_start are copied to within the std::function and maintain
4968   // state between successive calls
4969   return [&, cur_item, cur_start](size_t offset,
4970                                   DataSink &sink) mutable -> bool {
4971     if (!offset && items.size()) {
4972       sink.os << detail::serialize_multipart_formdata(items, boundary, false);
4973       return true;
4974     } else if (cur_item < provider_items.size()) {
4975       if (!cur_start) {
4976         const auto &begin = detail::serialize_multipart_formdata_item_begin(
4977             provider_items[cur_item], boundary);
4978         offset += begin.size();
4979         cur_start = offset;
4980         sink.os << begin;
4981       }
4982
4983       DataSink cur_sink;
4984       bool has_data = true;
4985       cur_sink.write = sink.write;
4986       cur_sink.done = [&]() { has_data = false; };
4987
4988       if (!provider_items[cur_item].provider(offset - cur_start, cur_sink))
4989         return false;
4990
4991       if (!has_data) {
4992         sink.os << detail::serialize_multipart_formdata_item_end();
4993         cur_item++;
4994         cur_start = 0;
4995       }
4996       return true;
4997     } else {
4998       sink.os << detail::serialize_multipart_formdata_finish(boundary);
4999       sink.done();
5000       return true;
5001     }
5002   };
5003 }
5004
5005 bool
5006 ClientImpl::process_socket(const Socket &socket,
5007                            std::function<bool(Stream &strm)> callback) {
5008   return detail::process_client_socket(
5009       socket.sock, read_timeout_sec_, read_timeout_usec_, write_timeout_sec_,
5010       write_timeout_usec_, std::move(callback));
5011 }
5012
5013 bool ClientImpl::is_ssl() const { return false; }
5014
5015 Result ClientImpl::Get(const std::string &path) {
5016   return Get(path, Headers(), Progress());
5017 }
5018
5019 Result ClientImpl::Get(const std::string &path, Progress progress) {
5020   return Get(path, Headers(), std::move(progress));
5021 }
5022
5023 Result ClientImpl::Get(const std::string &path, const Headers &headers) {
5024   return Get(path, headers, Progress());
5025 }
5026
5027 Result ClientImpl::Get(const std::string &path, const Headers &headers,
5028                               Progress progress) {
5029   Request req;
5030   req.method = "GET";
5031   req.path = path;
5032   req.headers = headers;
5033   req.progress = std::move(progress);
5034
5035   return send_(std::move(req));
5036 }
5037
5038 Result ClientImpl::Get(const std::string &path,
5039                               ContentReceiver content_receiver) {
5040   return Get(path, Headers(), nullptr, std::move(content_receiver), nullptr);
5041 }
5042
5043 Result ClientImpl::Get(const std::string &path,
5044                               ContentReceiver content_receiver,
5045                               Progress progress) {
5046   return Get(path, Headers(), nullptr, std::move(content_receiver),
5047              std::move(progress));
5048 }
5049
5050 Result ClientImpl::Get(const std::string &path, const Headers &headers,
5051                               ContentReceiver content_receiver) {
5052   return Get(path, headers, nullptr, std::move(content_receiver), nullptr);
5053 }
5054
5055 Result ClientImpl::Get(const std::string &path, const Headers &headers,
5056                               ContentReceiver content_receiver,
5057                               Progress progress) {
5058   return Get(path, headers, nullptr, std::move(content_receiver),
5059              std::move(progress));
5060 }
5061
5062 Result ClientImpl::Get(const std::string &path,
5063                               ResponseHandler response_handler,
5064                               ContentReceiver content_receiver) {
5065   return Get(path, Headers(), std::move(response_handler),
5066              std::move(content_receiver), nullptr);
5067 }
5068
5069 Result ClientImpl::Get(const std::string &path, const Headers &headers,
5070                               ResponseHandler response_handler,
5071                               ContentReceiver content_receiver) {
5072   return Get(path, headers, std::move(response_handler),
5073              std::move(content_receiver), nullptr);
5074 }
5075
5076 Result ClientImpl::Get(const std::string &path,
5077                               ResponseHandler response_handler,
5078                               ContentReceiver content_receiver,
5079                               Progress progress) {
5080   return Get(path, Headers(), std::move(response_handler),
5081              std::move(content_receiver), std::move(progress));
5082 }
5083
5084 Result ClientImpl::Get(const std::string &path, const Headers &headers,
5085                               ResponseHandler response_handler,
5086                               ContentReceiver content_receiver,
5087                               Progress progress) {
5088   Request req;
5089   req.method = "GET";
5090   req.path = path;
5091   req.headers = headers;
5092   req.response_handler = std::move(response_handler);
5093   req.content_receiver =
5094       [content_receiver](const char *data, size_t data_length,
5095                          uint64_t /*offset*/, uint64_t /*total_length*/) {
5096         return content_receiver(data, data_length);
5097       };
5098   req.progress = std::move(progress);
5099
5100   return send_(std::move(req));
5101 }
5102
5103 Result ClientImpl::Get(const std::string &path, const Params &params,
5104                               const Headers &headers, Progress progress) {
5105   if (params.empty()) { return Get(path, headers); }
5106
5107   std::string path_with_query = append_query_params(path, params);
5108   return Get(path_with_query.c_str(), headers, progress);
5109 }
5110
5111 Result ClientImpl::Get(const std::string &path, const Params &params,
5112                               const Headers &headers,
5113                               ContentReceiver content_receiver,
5114                               Progress progress) {
5115   return Get(path, params, headers, nullptr, content_receiver, progress);
5116 }
5117
5118 Result ClientImpl::Get(const std::string &path, const Params &params,
5119                               const Headers &headers,
5120                               ResponseHandler response_handler,
5121                               ContentReceiver content_receiver,
5122                               Progress progress) {
5123   if (params.empty()) {
5124     return Get(path, headers, response_handler, content_receiver, progress);
5125   }
5126
5127   std::string path_with_query = append_query_params(path, params);
5128   return Get(path_with_query.c_str(), headers, response_handler,
5129              content_receiver, progress);
5130 }
5131
5132 Result ClientImpl::Head(const std::string &path) {
5133   return Head(path, Headers());
5134 }
5135
5136 Result ClientImpl::Head(const std::string &path,
5137                                const Headers &headers) {
5138   Request req;
5139   req.method = "HEAD";
5140   req.headers = headers;
5141   req.path = path;
5142
5143   return send_(std::move(req));
5144 }
5145
5146 Result ClientImpl::Post(const std::string &path) {
5147   return Post(path, std::string(), std::string());
5148 }
5149
5150 Result ClientImpl::Post(const std::string &path,
5151                                const Headers &headers) {
5152   return Post(path, headers, nullptr, 0, std::string());
5153 }
5154
5155 Result ClientImpl::Post(const std::string &path, const char *body,
5156                                size_t content_length,
5157                                const std::string &content_type) {
5158   return Post(path, Headers(), body, content_length, content_type);
5159 }
5160
5161 Result ClientImpl::Post(const std::string &path, const Headers &headers,
5162                                const char *body, size_t content_length,
5163                                const std::string &content_type) {
5164   return send_with_content_provider("POST", path, headers, body, content_length,
5165                                     nullptr, nullptr, content_type);
5166 }
5167
5168 Result ClientImpl::Post(const std::string &path, const std::string &body,
5169                                const std::string &content_type) {
5170   return Post(path, Headers(), body, content_type);
5171 }
5172
5173 Result ClientImpl::Post(const std::string &path, const Headers &headers,
5174                                const std::string &body,
5175                                const std::string &content_type) {
5176   return send_with_content_provider("POST", path, headers, body.data(),
5177                                     body.size(), nullptr, nullptr,
5178                                     content_type);
5179 }
5180
5181 Result ClientImpl::Post(const std::string &path, const Params &params) {
5182   return Post(path, Headers(), params);
5183 }
5184
5185 Result ClientImpl::Post(const std::string &path, size_t content_length,
5186                                ContentProvider content_provider,
5187                                const std::string &content_type) {
5188   return Post(path, Headers(), content_length, std::move(content_provider),
5189               content_type);
5190 }
5191
5192 Result ClientImpl::Post(const std::string &path,
5193                                ContentProviderWithoutLength content_provider,
5194                                const std::string &content_type) {
5195   return Post(path, Headers(), std::move(content_provider), content_type);
5196 }
5197
5198 Result ClientImpl::Post(const std::string &path, const Headers &headers,
5199                                size_t content_length,
5200                                ContentProvider content_provider,
5201                                const std::string &content_type) {
5202   return send_with_content_provider("POST", path, headers, nullptr,
5203                                     content_length, std::move(content_provider),
5204                                     nullptr, content_type);
5205 }
5206
5207 Result ClientImpl::Post(const std::string &path, const Headers &headers,
5208                                ContentProviderWithoutLength content_provider,
5209                                const std::string &content_type) {
5210   return send_with_content_provider("POST", path, headers, nullptr, 0, nullptr,
5211                                     std::move(content_provider), content_type);
5212 }
5213
5214 Result ClientImpl::Post(const std::string &path, const Headers &headers,
5215                                const Params &params) {
5216   auto query = detail::params_to_query_str(params);
5217   return Post(path, headers, query, "application/x-www-form-urlencoded");
5218 }
5219
5220 Result ClientImpl::Post(const std::string &path,
5221                                const MultipartFormDataItems &items) {
5222   return Post(path, Headers(), items);
5223 }
5224
5225 Result ClientImpl::Post(const std::string &path, const Headers &headers,
5226                                const MultipartFormDataItems &items) {
5227   const auto &boundary = detail::make_multipart_data_boundary();
5228   const auto &content_type =
5229       detail::serialize_multipart_formdata_get_content_type(boundary);
5230   const auto &body = detail::serialize_multipart_formdata(items, boundary);
5231   return Post(path, headers, body, content_type.c_str());
5232 }
5233
5234 Result ClientImpl::Post(const std::string &path, const Headers &headers,
5235                                const MultipartFormDataItems &items,
5236                                const std::string &boundary) {
5237   if (!detail::is_multipart_boundary_chars_valid(boundary)) {
5238     return Result{nullptr, Error::UnsupportedMultipartBoundaryChars};
5239   }
5240
5241   const auto &content_type =
5242       detail::serialize_multipart_formdata_get_content_type(boundary);
5243   const auto &body = detail::serialize_multipart_formdata(items, boundary);
5244   return Post(path, headers, body, content_type.c_str());
5245 }
5246
5247 Result
5248 ClientImpl::Post(const std::string &path, const Headers &headers,
5249                  const MultipartFormDataItems &items,
5250                  const MultipartFormDataProviderItems &provider_items) {
5251   const auto &boundary = detail::make_multipart_data_boundary();
5252   const auto &content_type =
5253       detail::serialize_multipart_formdata_get_content_type(boundary);
5254   return send_with_content_provider(
5255       "POST", path, headers, nullptr, 0, nullptr,
5256       get_multipart_content_provider(boundary, items, provider_items),
5257       content_type);
5258 }
5259
5260 Result ClientImpl::Put(const std::string &path) {
5261   return Put(path, std::string(), std::string());
5262 }
5263
5264 Result ClientImpl::Put(const std::string &path, const char *body,
5265                               size_t content_length,
5266                               const std::string &content_type) {
5267   return Put(path, Headers(), body, content_length, content_type);
5268 }
5269
5270 Result ClientImpl::Put(const std::string &path, const Headers &headers,
5271                               const char *body, size_t content_length,
5272                               const std::string &content_type) {
5273   return send_with_content_provider("PUT", path, headers, body, content_length,
5274                                     nullptr, nullptr, content_type);
5275 }
5276
5277 Result ClientImpl::Put(const std::string &path, const std::string &body,
5278                               const std::string &content_type) {
5279   return Put(path, Headers(), body, content_type);
5280 }
5281
5282 Result ClientImpl::Put(const std::string &path, const Headers &headers,
5283                               const std::string &body,
5284                               const std::string &content_type) {
5285   return send_with_content_provider("PUT", path, headers, body.data(),
5286                                     body.size(), nullptr, nullptr,
5287                                     content_type);
5288 }
5289
5290 Result ClientImpl::Put(const std::string &path, size_t content_length,
5291                               ContentProvider content_provider,
5292                               const std::string &content_type) {
5293   return Put(path, Headers(), content_length, std::move(content_provider),
5294              content_type);
5295 }
5296
5297 Result ClientImpl::Put(const std::string &path,
5298                               ContentProviderWithoutLength content_provider,
5299                               const std::string &content_type) {
5300   return Put(path, Headers(), std::move(content_provider), content_type);
5301 }
5302
5303 Result ClientImpl::Put(const std::string &path, const Headers &headers,
5304                               size_t content_length,
5305                               ContentProvider content_provider,
5306                               const std::string &content_type) {
5307   return send_with_content_provider("PUT", path, headers, nullptr,
5308                                     content_length, std::move(content_provider),
5309                                     nullptr, content_type);
5310 }
5311
5312 Result ClientImpl::Put(const std::string &path, const Headers &headers,
5313                               ContentProviderWithoutLength content_provider,
5314                               const std::string &content_type) {
5315   return send_with_content_provider("PUT", path, headers, nullptr, 0, nullptr,
5316                                     std::move(content_provider), content_type);
5317 }
5318
5319 Result ClientImpl::Put(const std::string &path, const Params &params) {
5320   return Put(path, Headers(), params);
5321 }
5322
5323 Result ClientImpl::Put(const std::string &path, const Headers &headers,
5324                               const Params &params) {
5325   auto query = detail::params_to_query_str(params);
5326   return Put(path, headers, query, "application/x-www-form-urlencoded");
5327 }
5328
5329 Result ClientImpl::Put(const std::string &path,
5330                               const MultipartFormDataItems &items) {
5331   return Put(path, Headers(), items);
5332 }
5333
5334 Result ClientImpl::Put(const std::string &path, const Headers &headers,
5335                               const MultipartFormDataItems &items) {
5336   const auto &boundary = detail::make_multipart_data_boundary();
5337   const auto &content_type =
5338       detail::serialize_multipart_formdata_get_content_type(boundary);
5339   const auto &body = detail::serialize_multipart_formdata(items, boundary);
5340   return Put(path, headers, body, content_type);
5341 }
5342
5343 Result ClientImpl::Put(const std::string &path, const Headers &headers,
5344                               const MultipartFormDataItems &items,
5345                               const std::string &boundary) {
5346   if (!detail::is_multipart_boundary_chars_valid(boundary)) {
5347     return Result{nullptr, Error::UnsupportedMultipartBoundaryChars};
5348   }
5349
5350   const auto &content_type =
5351       detail::serialize_multipart_formdata_get_content_type(boundary);
5352   const auto &body = detail::serialize_multipart_formdata(items, boundary);
5353   return Put(path, headers, body, content_type);
5354 }
5355
5356 Result
5357 ClientImpl::Put(const std::string &path, const Headers &headers,
5358                 const MultipartFormDataItems &items,
5359                 const MultipartFormDataProviderItems &provider_items) {
5360   const auto &boundary = detail::make_multipart_data_boundary();
5361   const auto &content_type =
5362       detail::serialize_multipart_formdata_get_content_type(boundary);
5363   return send_with_content_provider(
5364       "PUT", path, headers, nullptr, 0, nullptr,
5365       get_multipart_content_provider(boundary, items, provider_items),
5366       content_type);
5367 }
5368 Result ClientImpl::Patch(const std::string &path) {
5369   return Patch(path, std::string(), std::string());
5370 }
5371
5372 Result ClientImpl::Patch(const std::string &path, const char *body,
5373                                 size_t content_length,
5374                                 const std::string &content_type) {
5375   return Patch(path, Headers(), body, content_length, content_type);
5376 }
5377
5378 Result ClientImpl::Patch(const std::string &path, const Headers &headers,
5379                                 const char *body, size_t content_length,
5380                                 const std::string &content_type) {
5381   return send_with_content_provider("PATCH", path, headers, body,
5382                                     content_length, nullptr, nullptr,
5383                                     content_type);
5384 }
5385
5386 Result ClientImpl::Patch(const std::string &path,
5387                                 const std::string &body,
5388                                 const std::string &content_type) {
5389   return Patch(path, Headers(), body, content_type);
5390 }
5391
5392 Result ClientImpl::Patch(const std::string &path, const Headers &headers,
5393                                 const std::string &body,
5394                                 const std::string &content_type) {
5395   return send_with_content_provider("PATCH", path, headers, body.data(),
5396                                     body.size(), nullptr, nullptr,
5397                                     content_type);
5398 }
5399
5400 Result ClientImpl::Patch(const std::string &path, size_t content_length,
5401                                 ContentProvider content_provider,
5402                                 const std::string &content_type) {
5403   return Patch(path, Headers(), content_length, std::move(content_provider),
5404                content_type);
5405 }
5406
5407 Result ClientImpl::Patch(const std::string &path,
5408                                 ContentProviderWithoutLength content_provider,
5409                                 const std::string &content_type) {
5410   return Patch(path, Headers(), std::move(content_provider), content_type);
5411 }
5412
5413 Result ClientImpl::Patch(const std::string &path, const Headers &headers,
5414                                 size_t content_length,
5415                                 ContentProvider content_provider,
5416                                 const std::string &content_type) {
5417   return send_with_content_provider("PATCH", path, headers, nullptr,
5418                                     content_length, std::move(content_provider),
5419                                     nullptr, content_type);
5420 }
5421
5422 Result ClientImpl::Patch(const std::string &path, const Headers &headers,
5423                                 ContentProviderWithoutLength content_provider,
5424                                 const std::string &content_type) {
5425   return send_with_content_provider("PATCH", path, headers, nullptr, 0, nullptr,
5426                                     std::move(content_provider), content_type);
5427 }
5428
5429 Result ClientImpl::Delete(const std::string &path) {
5430   return Delete(path, Headers(), std::string(), std::string());
5431 }
5432
5433 Result ClientImpl::Delete(const std::string &path,
5434                                  const Headers &headers) {
5435   return Delete(path, headers, std::string(), std::string());
5436 }
5437
5438 Result ClientImpl::Delete(const std::string &path, const char *body,
5439                                  size_t content_length,
5440                                  const std::string &content_type) {
5441   return Delete(path, Headers(), body, content_length, content_type);
5442 }
5443
5444 Result ClientImpl::Delete(const std::string &path,
5445                                  const Headers &headers, const char *body,
5446                                  size_t content_length,
5447                                  const std::string &content_type) {
5448   Request req;
5449   req.method = "DELETE";
5450   req.headers = headers;
5451   req.path = path;
5452
5453   if (!content_type.empty()) { req.set_header("Content-Type", content_type); }
5454   req.body.assign(body, content_length);
5455
5456   return send_(std::move(req));
5457 }
5458
5459 Result ClientImpl::Delete(const std::string &path,
5460                                  const std::string &body,
5461                                  const std::string &content_type) {
5462   return Delete(path, Headers(), body.data(), body.size(), content_type);
5463 }
5464
5465 Result ClientImpl::Delete(const std::string &path,
5466                                  const Headers &headers,
5467                                  const std::string &body,
5468                                  const std::string &content_type) {
5469   return Delete(path, headers, body.data(), body.size(), content_type);
5470 }
5471
5472 Result ClientImpl::Options(const std::string &path) {
5473   return Options(path, Headers());
5474 }
5475
5476 Result ClientImpl::Options(const std::string &path,
5477                                   const Headers &headers) {
5478   Request req;
5479   req.method = "OPTIONS";
5480   req.headers = headers;
5481   req.path = path;
5482
5483   return send_(std::move(req));
5484 }
5485
5486 size_t ClientImpl::is_socket_open() const {
5487   std::lock_guard<std::mutex> guard(socket_mutex_);
5488   return socket_.is_open();
5489 }
5490
5491 socket_t ClientImpl::socket() const { return socket_.sock; }
5492
5493 void ClientImpl::stop() {
5494   std::lock_guard<std::mutex> guard(socket_mutex_);
5495
5496   // If there is anything ongoing right now, the ONLY thread-safe thing we can
5497   // do is to shutdown_socket, so that threads using this socket suddenly
5498   // discover they can't read/write any more and error out. Everything else
5499   // (closing the socket, shutting ssl down) is unsafe because these actions are
5500   // not thread-safe.
5501   if (socket_requests_in_flight_ > 0) {
5502     shutdown_socket(socket_);
5503
5504     // Aside from that, we set a flag for the socket to be closed when we're
5505     // done.
5506     socket_should_be_closed_when_request_is_done_ = true;
5507     return;
5508   }
5509
5510   // Otherwise, still holding the mutex, we can shut everything down ourselves
5511   shutdown_ssl(socket_, true);
5512   shutdown_socket(socket_);
5513   close_socket(socket_);
5514 }
5515
5516 void ClientImpl::set_connection_timeout(time_t sec, time_t usec) {
5517   connection_timeout_sec_ = sec;
5518   connection_timeout_usec_ = usec;
5519 }
5520
5521 void ClientImpl::set_read_timeout(time_t sec, time_t usec) {
5522   read_timeout_sec_ = sec;
5523   read_timeout_usec_ = usec;
5524 }
5525
5526 void ClientImpl::set_write_timeout(time_t sec, time_t usec) {
5527   write_timeout_sec_ = sec;
5528   write_timeout_usec_ = usec;
5529 }
5530
5531 void ClientImpl::set_basic_auth(const std::string &username,
5532                                        const std::string &password) {
5533   basic_auth_username_ = username;
5534   basic_auth_password_ = password;
5535 }
5536
5537 void ClientImpl::set_bearer_token_auth(const std::string &token) {
5538   bearer_token_auth_token_ = token;
5539 }
5540
5541 #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
5542 void ClientImpl::set_digest_auth(const std::string &username,
5543                                         const std::string &password) {
5544   digest_auth_username_ = username;
5545   digest_auth_password_ = password;
5546 }
5547 #endif
5548
5549 void ClientImpl::set_keep_alive(bool on) { keep_alive_ = on; }
5550
5551 void ClientImpl::set_follow_location(bool on) { follow_location_ = on; }
5552
5553 void ClientImpl::set_url_encode(bool on) { url_encode_ = on; }
5554
5555 void
5556 ClientImpl::set_hostname_addr_map(std::map<std::string, std::string> addr_map) {
5557   addr_map_ = std::move(addr_map);
5558 }
5559
5560 void ClientImpl::set_default_headers(Headers headers) {
5561   default_headers_ = std::move(headers);
5562 }
5563
5564 void ClientImpl::set_address_family(int family) {
5565   address_family_ = family;
5566 }
5567
5568 void ClientImpl::set_tcp_nodelay(bool on) { tcp_nodelay_ = on; }
5569
5570 void ClientImpl::set_socket_options(SocketOptions socket_options) {
5571   socket_options_ = std::move(socket_options);
5572 }
5573
5574 void ClientImpl::set_compress(bool on) { compress_ = on; }
5575
5576 void ClientImpl::set_decompress(bool on) { decompress_ = on; }
5577
5578 void ClientImpl::set_interface(const std::string &intf) {
5579   interface_ = intf;
5580 }
5581
5582 void ClientImpl::set_proxy(const std::string &host, int port) {
5583   proxy_host_ = host;
5584   proxy_port_ = port;
5585 }
5586
5587 void ClientImpl::set_proxy_basic_auth(const std::string &username,
5588                                              const std::string &password) {
5589   proxy_basic_auth_username_ = username;
5590   proxy_basic_auth_password_ = password;
5591 }
5592
5593 void ClientImpl::set_proxy_bearer_token_auth(const std::string &token) {
5594   proxy_bearer_token_auth_token_ = token;
5595 }
5596
5597 #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
5598 void ClientImpl::set_proxy_digest_auth(const std::string &username,
5599                                               const std::string &password) {
5600   proxy_digest_auth_username_ = username;
5601   proxy_digest_auth_password_ = password;
5602 }
5603
5604 void ClientImpl::set_ca_cert_path(const std::string &ca_cert_file_path,
5605                                          const std::string &ca_cert_dir_path) {
5606   ca_cert_file_path_ = ca_cert_file_path;
5607   ca_cert_dir_path_ = ca_cert_dir_path;
5608 }
5609
5610 void ClientImpl::set_ca_cert_store(X509_STORE *ca_cert_store) {
5611   if (ca_cert_store && ca_cert_store != ca_cert_store_) {
5612     ca_cert_store_ = ca_cert_store;
5613   }
5614 }
5615
5616 X509_STORE *ClientImpl::create_ca_cert_store(const char *ca_cert,
5617                                                     std::size_t size) {
5618   auto mem = BIO_new_mem_buf(ca_cert, static_cast<int>(size));
5619   if (!mem) return nullptr;
5620
5621   auto inf = PEM_X509_INFO_read_bio(mem, nullptr, nullptr, nullptr);
5622   if (!inf) {
5623     BIO_free_all(mem);
5624     return nullptr;
5625   }
5626
5627   auto cts = X509_STORE_new();
5628   if (cts) {
5629     for (auto first = 0, last = sk_X509_INFO_num(inf); first < last; ++first) {
5630       auto itmp = sk_X509_INFO_value(inf, first);
5631       if (!itmp) { continue; }
5632
5633       if (itmp->x509) { X509_STORE_add_cert(cts, itmp->x509); }
5634       if (itmp->crl) { X509_STORE_add_crl(cts, itmp->crl); }
5635     }
5636   }
5637
5638   sk_X509_INFO_pop_free(inf, X509_INFO_free);
5639   BIO_free_all(mem);
5640   return cts;
5641 }
5642
5643 void ClientImpl::enable_server_certificate_verification(bool enabled) {
5644   server_certificate_verification_ = enabled;
5645 }
5646 #endif
5647
5648 void ClientImpl::set_logger(Logger logger) {
5649   logger_ = std::move(logger);
5650 }
5651
5652 /*
5653  * SSL Implementation
5654  */
5655 #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
5656 namespace detail {
5657
5658 template <typename U, typename V>
5659 SSL *ssl_new(socket_t sock, SSL_CTX *ctx, std::mutex &ctx_mutex,
5660                     U SSL_connect_or_accept, V setup) {
5661   SSL *ssl = nullptr;
5662   {
5663     std::lock_guard<std::mutex> guard(ctx_mutex);
5664     ssl = SSL_new(ctx);
5665   }
5666
5667   if (ssl) {
5668     set_nonblocking(sock, true);
5669     auto bio = BIO_new_socket(static_cast<int>(sock), BIO_NOCLOSE);
5670     BIO_set_nbio(bio, 1);
5671     SSL_set_bio(ssl, bio, bio);
5672
5673     if (!setup(ssl) || SSL_connect_or_accept(ssl) != 1) {
5674       SSL_shutdown(ssl);
5675       {
5676         std::lock_guard<std::mutex> guard(ctx_mutex);
5677         SSL_free(ssl);
5678       }
5679       set_nonblocking(sock, false);
5680       return nullptr;
5681     }
5682     BIO_set_nbio(bio, 0);
5683     set_nonblocking(sock, false);
5684   }
5685
5686   return ssl;
5687 }
5688
5689 void ssl_delete(std::mutex &ctx_mutex, SSL *ssl,
5690                        bool shutdown_gracefully) {
5691   // sometimes we may want to skip this to try to avoid SIGPIPE if we know
5692   // the remote has closed the network connection
5693   // Note that it is not always possible to avoid SIGPIPE, this is merely a
5694   // best-efforts.
5695   if (shutdown_gracefully) { SSL_shutdown(ssl); }
5696
5697   std::lock_guard<std::mutex> guard(ctx_mutex);
5698   SSL_free(ssl);
5699 }
5700
5701 template <typename U>
5702 bool ssl_connect_or_accept_nonblocking(socket_t sock, SSL *ssl,
5703                                        U ssl_connect_or_accept,
5704                                        time_t timeout_sec,
5705                                        time_t timeout_usec) {
5706   int res = 0;
5707   while ((res = ssl_connect_or_accept(ssl)) != 1) {
5708     auto err = SSL_get_error(ssl, res);
5709     switch (err) {
5710     case SSL_ERROR_WANT_READ:
5711       if (select_read(sock, timeout_sec, timeout_usec) > 0) { continue; }
5712       break;
5713     case SSL_ERROR_WANT_WRITE:
5714       if (select_write(sock, timeout_sec, timeout_usec) > 0) { continue; }
5715       break;
5716     default: break;
5717     }
5718     return false;
5719   }
5720   return true;
5721 }
5722
5723 template <typename T>
5724 bool process_server_socket_ssl(
5725     const std::atomic<socket_t> &svr_sock, SSL *ssl, socket_t sock,
5726     size_t keep_alive_max_count, time_t keep_alive_timeout_sec,
5727     time_t read_timeout_sec, time_t read_timeout_usec, time_t write_timeout_sec,
5728     time_t write_timeout_usec, T callback) {
5729   return process_server_socket_core(
5730       svr_sock, sock, keep_alive_max_count, keep_alive_timeout_sec,
5731       [&](bool close_connection, bool &connection_closed) {
5732         SSLSocketStream strm(sock, ssl, read_timeout_sec, read_timeout_usec,
5733                              write_timeout_sec, write_timeout_usec);
5734         return callback(strm, close_connection, connection_closed);
5735       });
5736 }
5737
5738 template <typename T>
5739 bool
5740 process_client_socket_ssl(SSL *ssl, socket_t sock, time_t read_timeout_sec,
5741                           time_t read_timeout_usec, time_t write_timeout_sec,
5742                           time_t write_timeout_usec, T callback) {
5743   SSLSocketStream strm(sock, ssl, read_timeout_sec, read_timeout_usec,
5744                        write_timeout_sec, write_timeout_usec);
5745   return callback(strm);
5746 }
5747
5748 class SSLInit {
5749 public:
5750   SSLInit() {
5751     OPENSSL_init_ssl(
5752         OPENSSL_INIT_LOAD_SSL_STRINGS | OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL);
5753   }
5754 };
5755
5756 // SSL socket stream implementation
5757 SSLSocketStream::SSLSocketStream(socket_t sock, SSL *ssl,
5758                                         time_t read_timeout_sec,
5759                                         time_t read_timeout_usec,
5760                                         time_t write_timeout_sec,
5761                                         time_t write_timeout_usec)
5762     : sock_(sock), ssl_(ssl), read_timeout_sec_(read_timeout_sec),
5763       read_timeout_usec_(read_timeout_usec),
5764       write_timeout_sec_(write_timeout_sec),
5765       write_timeout_usec_(write_timeout_usec) {
5766   SSL_clear_mode(ssl, SSL_MODE_AUTO_RETRY);
5767 }
5768
5769 SSLSocketStream::~SSLSocketStream() {}
5770
5771 bool SSLSocketStream::is_readable() const {
5772   return detail::select_read(sock_, read_timeout_sec_, read_timeout_usec_) > 0;
5773 }
5774
5775 bool SSLSocketStream::is_writable() const {
5776   return select_write(sock_, write_timeout_sec_, write_timeout_usec_) > 0 &&
5777          is_socket_alive(sock_);
5778 }
5779
5780 ssize_t SSLSocketStream::read(char *ptr, size_t size) {
5781   if (SSL_pending(ssl_) > 0) {
5782     return SSL_read(ssl_, ptr, static_cast<int>(size));
5783   } else if (is_readable()) {
5784     auto ret = SSL_read(ssl_, ptr, static_cast<int>(size));
5785     if (ret < 0) {
5786       auto err = SSL_get_error(ssl_, ret);
5787       int n = 1000;
5788 #ifdef _WIN32
5789       while (--n >= 0 && (err == SSL_ERROR_WANT_READ ||
5790                           (err == SSL_ERROR_SYSCALL &&
5791                            WSAGetLastError() == WSAETIMEDOUT))) {
5792 #else
5793       while (--n >= 0 && err == SSL_ERROR_WANT_READ) {
5794 #endif
5795         if (SSL_pending(ssl_) > 0) {
5796           return SSL_read(ssl_, ptr, static_cast<int>(size));
5797         } else if (is_readable()) {
5798           std::this_thread::sleep_for(std::chrono::milliseconds(1));
5799           ret = SSL_read(ssl_, ptr, static_cast<int>(size));
5800           if (ret >= 0) { return ret; }
5801           err = SSL_get_error(ssl_, ret);
5802         } else {
5803           return -1;
5804         }
5805       }
5806     }
5807     return ret;
5808   }
5809   return -1;
5810 }
5811
5812 ssize_t SSLSocketStream::write(const char *ptr, size_t size) {
5813   if (is_writable()) {
5814     auto handle_size = static_cast<int>(
5815         std::min<size_t>(size, (std::numeric_limits<int>::max)()));
5816
5817     auto ret = SSL_write(ssl_, ptr, static_cast<int>(handle_size));
5818     if (ret < 0) {
5819       auto err = SSL_get_error(ssl_, ret);
5820       int n = 1000;
5821 #ifdef _WIN32
5822       while (--n >= 0 && (err == SSL_ERROR_WANT_WRITE ||
5823                           (err == SSL_ERROR_SYSCALL &&
5824                            WSAGetLastError() == WSAETIMEDOUT))) {
5825 #else
5826       while (--n >= 0 && err == SSL_ERROR_WANT_WRITE) {
5827 #endif
5828         if (is_writable()) {
5829           std::this_thread::sleep_for(std::chrono::milliseconds(1));
5830           ret = SSL_write(ssl_, ptr, static_cast<int>(handle_size));
5831           if (ret >= 0) { return ret; }
5832           err = SSL_get_error(ssl_, ret);
5833         } else {
5834           return -1;
5835         }
5836       }
5837     }
5838     return ret;
5839   }
5840   return -1;
5841 }
5842
5843 void SSLSocketStream::get_remote_ip_and_port(std::string &ip,
5844                                                     int &port) const {
5845   detail::get_remote_ip_and_port(sock_, ip, port);
5846 }
5847
5848 void SSLSocketStream::get_local_ip_and_port(std::string &ip,
5849                                                    int &port) const {
5850   detail::get_local_ip_and_port(sock_, ip, port);
5851 }
5852
5853 socket_t SSLSocketStream::socket() const { return sock_; }
5854
5855 static SSLInit sslinit_;
5856
5857 } // namespace detail
5858
5859 // SSL HTTP server implementation
5860 SSLServer::SSLServer(const char *cert_path, const char *private_key_path,
5861                             const char *client_ca_cert_file_path,
5862                             const char *client_ca_cert_dir_path,
5863                             const char *private_key_password) {
5864   ctx_ = SSL_CTX_new(TLS_server_method());
5865
5866   if (ctx_) {
5867     SSL_CTX_set_options(ctx_,
5868                         SSL_OP_NO_COMPRESSION |
5869                             SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION);
5870
5871     SSL_CTX_set_min_proto_version(ctx_, TLS1_1_VERSION);
5872
5873     // add default password callback before opening encrypted private key
5874     if (private_key_password != nullptr && (private_key_password[0] != '\0')) {
5875       SSL_CTX_set_default_passwd_cb_userdata(ctx_,
5876                                              (char *)private_key_password);
5877     }
5878
5879     if (SSL_CTX_use_certificate_chain_file(ctx_, cert_path) != 1 ||
5880         SSL_CTX_use_PrivateKey_file(ctx_, private_key_path, SSL_FILETYPE_PEM) !=
5881             1) {
5882       SSL_CTX_free(ctx_);
5883       ctx_ = nullptr;
5884     } else if (client_ca_cert_file_path || client_ca_cert_dir_path) {
5885       SSL_CTX_load_verify_locations(ctx_, client_ca_cert_file_path,
5886                                     client_ca_cert_dir_path);
5887
5888       SSL_CTX_set_verify(
5889           ctx_, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, nullptr);
5890     }
5891   }
5892 }
5893
5894 SSLServer::SSLServer(X509 *cert, EVP_PKEY *private_key,
5895                             X509_STORE *client_ca_cert_store) {
5896   ctx_ = SSL_CTX_new(TLS_server_method());
5897
5898   if (ctx_) {
5899     SSL_CTX_set_options(ctx_,
5900                         SSL_OP_NO_COMPRESSION |
5901                             SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION);
5902
5903     SSL_CTX_set_min_proto_version(ctx_, TLS1_1_VERSION);
5904
5905     if (SSL_CTX_use_certificate(ctx_, cert) != 1 ||
5906         SSL_CTX_use_PrivateKey(ctx_, private_key) != 1) {
5907       SSL_CTX_free(ctx_);
5908       ctx_ = nullptr;
5909     } else if (client_ca_cert_store) {
5910       SSL_CTX_set_cert_store(ctx_, client_ca_cert_store);
5911
5912       SSL_CTX_set_verify(
5913           ctx_, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, nullptr);
5914     }
5915   }
5916 }
5917
5918 SSLServer::SSLServer(
5919     const std::function<bool(SSL_CTX &ssl_ctx)> &setup_ssl_ctx_callback) {
5920   ctx_ = SSL_CTX_new(TLS_method());
5921   if (ctx_) {
5922     if (!setup_ssl_ctx_callback(*ctx_)) {
5923       SSL_CTX_free(ctx_);
5924       ctx_ = nullptr;
5925     }
5926   }
5927 }
5928
5929 SSLServer::~SSLServer() {
5930   if (ctx_) { SSL_CTX_free(ctx_); }
5931 }
5932
5933 bool SSLServer::is_valid() const { return ctx_; }
5934
5935 SSL_CTX *SSLServer::ssl_context() const { return ctx_; }
5936
5937 bool SSLServer::process_and_close_socket(socket_t sock) {
5938   auto ssl = detail::ssl_new(
5939       sock, ctx_, ctx_mutex_,
5940       [&](SSL *ssl2) {
5941         return detail::ssl_connect_or_accept_nonblocking(
5942             sock, ssl2, SSL_accept, read_timeout_sec_, read_timeout_usec_);
5943       },
5944       [](SSL * /*ssl2*/) { return true; });
5945
5946   auto ret = false;
5947   if (ssl) {
5948     ret = detail::process_server_socket_ssl(
5949         svr_sock_, ssl, sock, keep_alive_max_count_, keep_alive_timeout_sec_,
5950         read_timeout_sec_, read_timeout_usec_, write_timeout_sec_,
5951         write_timeout_usec_,
5952         [this, ssl](Stream &strm, bool close_connection,
5953                     bool &connection_closed) {
5954           return process_request(strm, close_connection, connection_closed,
5955                                  [&](Request &req) { req.ssl = ssl; });
5956         });
5957
5958     // Shutdown gracefully if the result seemed successful, non-gracefully if
5959     // the connection appeared to be closed.
5960     const bool shutdown_gracefully = ret;
5961     detail::ssl_delete(ctx_mutex_, ssl, shutdown_gracefully);
5962   }
5963
5964   detail::shutdown_socket(sock);
5965   detail::close_socket(sock);
5966   return ret;
5967 }
5968
5969 // SSL HTTP client implementation
5970 SSLClient::SSLClient(const std::string &host)
5971     : SSLClient(host, 443, std::string(), std::string()) {}
5972
5973 SSLClient::SSLClient(const std::string &host, int port)
5974     : SSLClient(host, port, std::string(), std::string()) {}
5975
5976 SSLClient::SSLClient(const std::string &host, int port,
5977                             const std::string &client_cert_path,
5978                             const std::string &client_key_path)
5979     : ClientImpl(host, port, client_cert_path, client_key_path) {
5980   ctx_ = SSL_CTX_new(TLS_client_method());
5981
5982   detail::split(&host_[0], &host_[host_.size()], '.',
5983                 [&](const char *b, const char *e) {
5984                   host_components_.emplace_back(std::string(b, e));
5985                 });
5986
5987   if (!client_cert_path.empty() && !client_key_path.empty()) {
5988     if (SSL_CTX_use_certificate_file(ctx_, client_cert_path.c_str(),
5989                                      SSL_FILETYPE_PEM) != 1 ||
5990         SSL_CTX_use_PrivateKey_file(ctx_, client_key_path.c_str(),
5991                                     SSL_FILETYPE_PEM) != 1) {
5992       SSL_CTX_free(ctx_);
5993       ctx_ = nullptr;
5994     }
5995   }
5996 }
5997
5998 SSLClient::SSLClient(const std::string &host, int port,
5999                             X509 *client_cert, EVP_PKEY *client_key)
6000     : ClientImpl(host, port) {
6001   ctx_ = SSL_CTX_new(TLS_client_method());
6002
6003   detail::split(&host_[0], &host_[host_.size()], '.',
6004                 [&](const char *b, const char *e) {
6005                   host_components_.emplace_back(std::string(b, e));
6006                 });
6007
6008   if (client_cert != nullptr && client_key != nullptr) {
6009     if (SSL_CTX_use_certificate(ctx_, client_cert) != 1 ||
6010         SSL_CTX_use_PrivateKey(ctx_, client_key) != 1) {
6011       SSL_CTX_free(ctx_);
6012       ctx_ = nullptr;
6013     }
6014   }
6015 }
6016
6017 SSLClient::~SSLClient() {
6018   if (ctx_) { SSL_CTX_free(ctx_); }
6019   // Make sure to shut down SSL since shutdown_ssl will resolve to the
6020   // base function rather than the derived function once we get to the
6021   // base class destructor, and won't free the SSL (causing a leak).
6022   shutdown_ssl_impl(socket_, true);
6023 }
6024
6025 bool SSLClient::is_valid() const { return ctx_; }
6026
6027 void SSLClient::set_ca_cert_store(X509_STORE *ca_cert_store) {
6028   if (ca_cert_store) {
6029     if (ctx_) {
6030       if (SSL_CTX_get_cert_store(ctx_) != ca_cert_store) {
6031         // Free memory allocated for old cert and use new store `ca_cert_store`
6032         SSL_CTX_set_cert_store(ctx_, ca_cert_store);
6033       }
6034     } else {
6035       X509_STORE_free(ca_cert_store);
6036     }
6037   }
6038 }
6039
6040 void SSLClient::load_ca_cert_store(const char *ca_cert,
6041                                           std::size_t size) {
6042   set_ca_cert_store(ClientImpl::create_ca_cert_store(ca_cert, size));
6043 }
6044
6045 long SSLClient::get_openssl_verify_result() const {
6046   return verify_result_;
6047 }
6048
6049 SSL_CTX *SSLClient::ssl_context() const { return ctx_; }
6050
6051 bool SSLClient::create_and_connect_socket(Socket &socket, Error &error) {
6052   return is_valid() && ClientImpl::create_and_connect_socket(socket, error);
6053 }
6054
6055 // Assumes that socket_mutex_ is locked and that there are no requests in flight
6056 bool SSLClient::connect_with_proxy(Socket &socket, Response &res,
6057                                           bool &success, Error &error) {
6058   success = true;
6059   Response res2;
6060   if (!detail::process_client_socket(
6061           socket.sock, read_timeout_sec_, read_timeout_usec_,
6062           write_timeout_sec_, write_timeout_usec_, [&](Stream &strm) {
6063             Request req2;
6064             req2.method = "CONNECT";
6065             req2.path = host_and_port_;
6066             return process_request(strm, req2, res2, false, error);
6067           })) {
6068     // Thread-safe to close everything because we are assuming there are no
6069     // requests in flight
6070     shutdown_ssl(socket, true);
6071     shutdown_socket(socket);
6072     close_socket(socket);
6073     success = false;
6074     return false;
6075   }
6076
6077   if (res2.status == 407) {
6078     if (!proxy_digest_auth_username_.empty() &&
6079         !proxy_digest_auth_password_.empty()) {
6080       std::map<std::string, std::string> auth;
6081       if (detail::parse_www_authenticate(res2, auth, true)) {
6082         Response res3;
6083         if (!detail::process_client_socket(
6084                 socket.sock, read_timeout_sec_, read_timeout_usec_,
6085                 write_timeout_sec_, write_timeout_usec_, [&](Stream &strm) {
6086                   Request req3;
6087                   req3.method = "CONNECT";
6088                   req3.path = host_and_port_;
6089                   req3.headers.insert(detail::make_digest_authentication_header(
6090                       req3, auth, 1, detail::random_string(10),
6091                       proxy_digest_auth_username_, proxy_digest_auth_password_,
6092                       true));
6093                   return process_request(strm, req3, res3, false, error);
6094                 })) {
6095           // Thread-safe to close everything because we are assuming there are
6096           // no requests in flight
6097           shutdown_ssl(socket, true);
6098           shutdown_socket(socket);
6099           close_socket(socket);
6100           success = false;
6101           return false;
6102         }
6103       }
6104     } else {
6105       res = res2;
6106       return false;
6107     }
6108   }
6109
6110   return true;
6111 }
6112
6113 bool SSLClient::load_certs() {
6114   bool ret = true;
6115
6116   std::call_once(initialize_cert_, [&]() {
6117     std::lock_guard<std::mutex> guard(ctx_mutex_);
6118     if (!ca_cert_file_path_.empty()) {
6119       if (!SSL_CTX_load_verify_locations(ctx_, ca_cert_file_path_.c_str(),
6120                                          nullptr)) {
6121         ret = false;
6122       }
6123     } else if (!ca_cert_dir_path_.empty()) {
6124       if (!SSL_CTX_load_verify_locations(ctx_, nullptr,
6125                                          ca_cert_dir_path_.c_str())) {
6126         ret = false;
6127       }
6128     } else {
6129       auto loaded = false;
6130 #ifdef _WIN32
6131       loaded =
6132           detail::load_system_certs_on_windows(SSL_CTX_get_cert_store(ctx_));
6133 #elif defined(CPPHTTPLIB_USE_CERTS_FROM_MACOSX_KEYCHAIN) && defined(__APPLE__)
6134 #if TARGET_OS_OSX
6135       loaded = detail::load_system_certs_on_macos(SSL_CTX_get_cert_store(ctx_));
6136 #endif // TARGET_OS_OSX
6137 #endif // _WIN32
6138       if (!loaded) { SSL_CTX_set_default_verify_paths(ctx_); }
6139     }
6140   });
6141
6142   return ret;
6143 }
6144
6145 bool SSLClient::initialize_ssl(Socket &socket, Error &error) {
6146   auto ssl = detail::ssl_new(
6147       socket.sock, ctx_, ctx_mutex_,
6148       [&](SSL *ssl2) {
6149         if (server_certificate_verification_) {
6150           if (!load_certs()) {
6151             error = Error::SSLLoadingCerts;
6152             return false;
6153           }
6154           SSL_set_verify(ssl2, SSL_VERIFY_NONE, nullptr);
6155         }
6156
6157         if (!detail::ssl_connect_or_accept_nonblocking(
6158                 socket.sock, ssl2, SSL_connect, connection_timeout_sec_,
6159                 connection_timeout_usec_)) {
6160           error = Error::SSLConnection;
6161           return false;
6162         }
6163
6164         if (server_certificate_verification_) {
6165           verify_result_ = SSL_get_verify_result(ssl2);
6166
6167           if (verify_result_ != X509_V_OK) {
6168             error = Error::SSLServerVerification;
6169             return false;
6170           }
6171
6172           auto server_cert = SSL_get1_peer_certificate(ssl2);
6173
6174           if (server_cert == nullptr) {
6175             error = Error::SSLServerVerification;
6176             return false;
6177           }
6178
6179           if (!verify_host(server_cert)) {
6180             X509_free(server_cert);
6181             error = Error::SSLServerVerification;
6182             return false;
6183           }
6184           X509_free(server_cert);
6185         }
6186
6187         return true;
6188       },
6189       [&](SSL *ssl2) {
6190         SSL_set_tlsext_host_name(ssl2, host_.c_str());
6191         return true;
6192       });
6193
6194   if (ssl) {
6195     socket.ssl = ssl;
6196     return true;
6197   }
6198
6199   shutdown_socket(socket);
6200   close_socket(socket);
6201   return false;
6202 }
6203
6204 void SSLClient::shutdown_ssl(Socket &socket, bool shutdown_gracefully) {
6205   shutdown_ssl_impl(socket, shutdown_gracefully);
6206 }
6207
6208 void SSLClient::shutdown_ssl_impl(Socket &socket,
6209                                          bool shutdown_gracefully) {
6210   if (socket.sock == INVALID_SOCKET) {
6211     assert(socket.ssl == nullptr);
6212     return;
6213   }
6214   if (socket.ssl) {
6215     detail::ssl_delete(ctx_mutex_, socket.ssl, shutdown_gracefully);
6216     socket.ssl = nullptr;
6217   }
6218   assert(socket.ssl == nullptr);
6219 }
6220
6221 bool
6222 SSLClient::process_socket(const Socket &socket,
6223                           std::function<bool(Stream &strm)> callback) {
6224   assert(socket.ssl);
6225   return detail::process_client_socket_ssl(
6226       socket.ssl, socket.sock, read_timeout_sec_, read_timeout_usec_,
6227       write_timeout_sec_, write_timeout_usec_, std::move(callback));
6228 }
6229
6230 bool SSLClient::is_ssl() const { return true; }
6231
6232 bool SSLClient::verify_host(X509 *server_cert) const {
6233   /* Quote from RFC2818 section 3.1 "Server Identity"
6234
6235      If a subjectAltName extension of type dNSName is present, that MUST
6236      be used as the identity. Otherwise, the (most specific) Common Name
6237      field in the Subject field of the certificate MUST be used. Although
6238      the use of the Common Name is existing practice, it is deprecated and
6239      Certification Authorities are encouraged to use the dNSName instead.
6240
6241      Matching is performed using the matching rules specified by
6242      [RFC2459].  If more than one identity of a given type is present in
6243      the certificate (e.g., more than one dNSName name, a match in any one
6244      of the set is considered acceptable.) Names may contain the wildcard
6245      character * which is considered to match any single domain name
6246      component or component fragment. E.g., *.a.com matches foo.a.com but
6247      not bar.foo.a.com. f*.com matches foo.com but not bar.com.
6248
6249      In some cases, the URI is specified as an IP address rather than a
6250      hostname. In this case, the iPAddress subjectAltName must be present
6251      in the certificate and must exactly match the IP in the URI.
6252
6253   */
6254   return verify_host_with_subject_alt_name(server_cert) ||
6255          verify_host_with_common_name(server_cert);
6256 }
6257
6258 bool
6259 SSLClient::verify_host_with_subject_alt_name(X509 *server_cert) const {
6260   auto ret = false;
6261
6262   auto type = GEN_DNS;
6263
6264   struct in6_addr addr6;
6265   struct in_addr addr;
6266   size_t addr_len = 0;
6267
6268 #ifndef __MINGW32__
6269   if (inet_pton(AF_INET6, host_.c_str(), &addr6)) {
6270     type = GEN_IPADD;
6271     addr_len = sizeof(struct in6_addr);
6272   } else if (inet_pton(AF_INET, host_.c_str(), &addr)) {
6273     type = GEN_IPADD;
6274     addr_len = sizeof(struct in_addr);
6275   }
6276 #endif
6277
6278   auto alt_names = static_cast<const struct stack_st_GENERAL_NAME *>(
6279       X509_get_ext_d2i(server_cert, NID_subject_alt_name, nullptr, nullptr));
6280
6281   if (alt_names) {
6282     auto dsn_matched = false;
6283     auto ip_matched = false;
6284
6285     auto count = sk_GENERAL_NAME_num(alt_names);
6286
6287     for (decltype(count) i = 0; i < count && !dsn_matched; i++) {
6288       auto val = sk_GENERAL_NAME_value(alt_names, i);
6289       if (val->type == type) {
6290         auto name = (const char *)ASN1_STRING_get0_data(val->d.ia5);
6291         auto name_len = (size_t)ASN1_STRING_length(val->d.ia5);
6292
6293         switch (type) {
6294         case GEN_DNS: dsn_matched = check_host_name(name, name_len); break;
6295
6296         case GEN_IPADD:
6297           if (!memcmp(&addr6, name, addr_len) ||
6298               !memcmp(&addr, name, addr_len)) {
6299             ip_matched = true;
6300           }
6301           break;
6302         }
6303       }
6304     }
6305
6306     if (dsn_matched || ip_matched) { ret = true; }
6307   }
6308
6309   GENERAL_NAMES_free((STACK_OF(GENERAL_NAME) *)alt_names);
6310   return ret;
6311 }
6312
6313 bool SSLClient::verify_host_with_common_name(X509 *server_cert) const {
6314   const auto subject_name = X509_get_subject_name(server_cert);
6315
6316   if (subject_name != nullptr) {
6317     char name[BUFSIZ];
6318     auto name_len = X509_NAME_get_text_by_NID(subject_name, NID_commonName,
6319                                               name, sizeof(name));
6320
6321     if (name_len != -1) {
6322       return check_host_name(name, static_cast<size_t>(name_len));
6323     }
6324   }
6325
6326   return false;
6327 }
6328
6329 bool SSLClient::check_host_name(const char *pattern,
6330                                        size_t pattern_len) const {
6331   if (host_.size() == pattern_len && host_ == pattern) { return true; }
6332
6333   // Wildcard match
6334   // https://bugs.launchpad.net/ubuntu/+source/firefox-3.0/+bug/376484
6335   std::vector<std::string> pattern_components;
6336   detail::split(&pattern[0], &pattern[pattern_len], '.',
6337                 [&](const char *b, const char *e) {
6338                   pattern_components.emplace_back(std::string(b, e));
6339                 });
6340
6341   if (host_components_.size() != pattern_components.size()) { return false; }
6342
6343   auto itr = pattern_components.begin();
6344   for (const auto &h : host_components_) {
6345     auto &p = *itr;
6346     if (p != h && p != "*") {
6347       auto partial_match = (p.size() > 0 && p[p.size() - 1] == '*' &&
6348                             !p.compare(0, p.size() - 1, h));
6349       if (!partial_match) { return false; }
6350     }
6351     ++itr;
6352   }
6353
6354   return true;
6355 }
6356 #endif
6357
6358 // Universal client implementation
6359 Client::Client(const std::string &scheme_host_port)
6360     : Client(scheme_host_port, std::string(), std::string()) {}
6361
6362 Client::Client(const std::string &scheme_host_port,
6363                       const std::string &client_cert_path,
6364                       const std::string &client_key_path) {
6365   const static std::regex re(
6366       R"((?:([a-z]+):\/\/)?(?:\[([\d:]+)\]|([^:/?#]+))(?::(\d+))?)");
6367
6368   std::smatch m;
6369   if (std::regex_match(scheme_host_port, m, re)) {
6370     auto scheme = m[1].str();
6371
6372 #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
6373     if (!scheme.empty() && (scheme != "http" && scheme != "https")) {
6374 #else
6375     if (!scheme.empty() && scheme != "http") {
6376 #endif
6377 #ifndef CPPHTTPLIB_NO_EXCEPTIONS
6378       std::string msg = "'" + scheme + "' scheme is not supported.";
6379       throw std::invalid_argument(msg);
6380 #endif
6381       return;
6382     }
6383
6384     auto is_ssl = scheme == "https";
6385
6386     auto host = m[2].str();
6387     if (host.empty()) { host = m[3].str(); }
6388
6389     auto port_str = m[4].str();
6390     auto port = !port_str.empty() ? std::stoi(port_str) : (is_ssl ? 443 : 80);
6391
6392     if (is_ssl) {
6393 #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
6394       cli_ = detail::make_unique<SSLClient>(host, port, client_cert_path,
6395                                             client_key_path);
6396       is_ssl_ = is_ssl;
6397 #endif
6398     } else {
6399       cli_ = detail::make_unique<ClientImpl>(host, port, client_cert_path,
6400                                              client_key_path);
6401     }
6402   } else {
6403     cli_ = detail::make_unique<ClientImpl>(scheme_host_port, 80,
6404                                            client_cert_path, client_key_path);
6405   }
6406 }
6407
6408 Client::Client(const std::string &host, int port)
6409     : cli_(detail::make_unique<ClientImpl>(host, port)) {}
6410
6411 Client::Client(const std::string &host, int port,
6412                       const std::string &client_cert_path,
6413                       const std::string &client_key_path)
6414     : cli_(detail::make_unique<ClientImpl>(host, port, client_cert_path,
6415                                            client_key_path)) {}
6416
6417 Client::~Client() {}
6418
6419 bool Client::is_valid() const {
6420   return cli_ != nullptr && cli_->is_valid();
6421 }
6422
6423 Result Client::Get(const std::string &path) { return cli_->Get(path); }
6424 Result Client::Get(const std::string &path, const Headers &headers) {
6425   return cli_->Get(path, headers);
6426 }
6427 Result Client::Get(const std::string &path, Progress progress) {
6428   return cli_->Get(path, std::move(progress));
6429 }
6430 Result Client::Get(const std::string &path, const Headers &headers,
6431                           Progress progress) {
6432   return cli_->Get(path, headers, std::move(progress));
6433 }
6434 Result Client::Get(const std::string &path,
6435                           ContentReceiver content_receiver) {
6436   return cli_->Get(path, std::move(content_receiver));
6437 }
6438 Result Client::Get(const std::string &path, const Headers &headers,
6439                           ContentReceiver content_receiver) {
6440   return cli_->Get(path, headers, std::move(content_receiver));
6441 }
6442 Result Client::Get(const std::string &path,
6443                           ContentReceiver content_receiver, Progress progress) {
6444   return cli_->Get(path, std::move(content_receiver), std::move(progress));
6445 }
6446 Result Client::Get(const std::string &path, const Headers &headers,
6447                           ContentReceiver content_receiver, Progress progress) {
6448   return cli_->Get(path, headers, std::move(content_receiver),
6449                    std::move(progress));
6450 }
6451 Result Client::Get(const std::string &path,
6452                           ResponseHandler response_handler,
6453                           ContentReceiver content_receiver) {
6454   return cli_->Get(path, std::move(response_handler),
6455                    std::move(content_receiver));
6456 }
6457 Result Client::Get(const std::string &path, const Headers &headers,
6458                           ResponseHandler response_handler,
6459                           ContentReceiver content_receiver) {
6460   return cli_->Get(path, headers, std::move(response_handler),
6461                    std::move(content_receiver));
6462 }
6463 Result Client::Get(const std::string &path,
6464                           ResponseHandler response_handler,
6465                           ContentReceiver content_receiver, Progress progress) {
6466   return cli_->Get(path, std::move(response_handler),
6467                    std::move(content_receiver), std::move(progress));
6468 }
6469 Result Client::Get(const std::string &path, const Headers &headers,
6470                           ResponseHandler response_handler,
6471                           ContentReceiver content_receiver, Progress progress) {
6472   return cli_->Get(path, headers, std::move(response_handler),
6473                    std::move(content_receiver), std::move(progress));
6474 }
6475 Result Client::Get(const std::string &path, const Params &params,
6476                           const Headers &headers, Progress progress) {
6477   return cli_->Get(path, params, headers, progress);
6478 }
6479 Result Client::Get(const std::string &path, const Params &params,
6480                           const Headers &headers,
6481                           ContentReceiver content_receiver, Progress progress) {
6482   return cli_->Get(path, params, headers, content_receiver, progress);
6483 }
6484 Result Client::Get(const std::string &path, const Params &params,
6485                           const Headers &headers,
6486                           ResponseHandler response_handler,
6487                           ContentReceiver content_receiver, Progress progress) {
6488   return cli_->Get(path, params, headers, response_handler, content_receiver,
6489                    progress);
6490 }
6491
6492 Result Client::Head(const std::string &path) { return cli_->Head(path); }
6493 Result Client::Head(const std::string &path, const Headers &headers) {
6494   return cli_->Head(path, headers);
6495 }
6496
6497 Result Client::Post(const std::string &path) { return cli_->Post(path); }
6498 Result Client::Post(const std::string &path, const Headers &headers) {
6499   return cli_->Post(path, headers);
6500 }
6501 Result Client::Post(const std::string &path, const char *body,
6502                            size_t content_length,
6503                            const std::string &content_type) {
6504   return cli_->Post(path, body, content_length, content_type);
6505 }
6506 Result Client::Post(const std::string &path, const Headers &headers,
6507                            const char *body, size_t content_length,
6508                            const std::string &content_type) {
6509   return cli_->Post(path, headers, body, content_length, content_type);
6510 }
6511 Result Client::Post(const std::string &path, const std::string &body,
6512                            const std::string &content_type) {
6513   return cli_->Post(path, body, content_type);
6514 }
6515 Result Client::Post(const std::string &path, const Headers &headers,
6516                            const std::string &body,
6517                            const std::string &content_type) {
6518   return cli_->Post(path, headers, body, content_type);
6519 }
6520 Result Client::Post(const std::string &path, size_t content_length,
6521                            ContentProvider content_provider,
6522                            const std::string &content_type) {
6523   return cli_->Post(path, content_length, std::move(content_provider),
6524                     content_type);
6525 }
6526 Result Client::Post(const std::string &path,
6527                            ContentProviderWithoutLength content_provider,
6528                            const std::string &content_type) {
6529   return cli_->Post(path, std::move(content_provider), content_type);
6530 }
6531 Result Client::Post(const std::string &path, const Headers &headers,
6532                            size_t content_length,
6533                            ContentProvider content_provider,
6534                            const std::string &content_type) {
6535   return cli_->Post(path, headers, content_length, std::move(content_provider),
6536                     content_type);
6537 }
6538 Result Client::Post(const std::string &path, const Headers &headers,
6539                            ContentProviderWithoutLength content_provider,
6540                            const std::string &content_type) {
6541   return cli_->Post(path, headers, std::move(content_provider), content_type);
6542 }
6543 Result Client::Post(const std::string &path, const Params &params) {
6544   return cli_->Post(path, params);
6545 }
6546 Result Client::Post(const std::string &path, const Headers &headers,
6547                            const Params &params) {
6548   return cli_->Post(path, headers, params);
6549 }
6550 Result Client::Post(const std::string &path,
6551                            const MultipartFormDataItems &items) {
6552   return cli_->Post(path, items);
6553 }
6554 Result Client::Post(const std::string &path, const Headers &headers,
6555                            const MultipartFormDataItems &items) {
6556   return cli_->Post(path, headers, items);
6557 }
6558 Result Client::Post(const std::string &path, const Headers &headers,
6559                            const MultipartFormDataItems &items,
6560                            const std::string &boundary) {
6561   return cli_->Post(path, headers, items, boundary);
6562 }
6563 Result
6564 Client::Post(const std::string &path, const Headers &headers,
6565              const MultipartFormDataItems &items,
6566              const MultipartFormDataProviderItems &provider_items) {
6567   return cli_->Post(path, headers, items, provider_items);
6568 }
6569 Result Client::Put(const std::string &path) { return cli_->Put(path); }
6570 Result Client::Put(const std::string &path, const char *body,
6571                           size_t content_length,
6572                           const std::string &content_type) {
6573   return cli_->Put(path, body, content_length, content_type);
6574 }
6575 Result Client::Put(const std::string &path, const Headers &headers,
6576                           const char *body, size_t content_length,
6577                           const std::string &content_type) {
6578   return cli_->Put(path, headers, body, content_length, content_type);
6579 }
6580 Result Client::Put(const std::string &path, const std::string &body,
6581                           const std::string &content_type) {
6582   return cli_->Put(path, body, content_type);
6583 }
6584 Result Client::Put(const std::string &path, const Headers &headers,
6585                           const std::string &body,
6586                           const std::string &content_type) {
6587   return cli_->Put(path, headers, body, content_type);
6588 }
6589 Result Client::Put(const std::string &path, size_t content_length,
6590                           ContentProvider content_provider,
6591                           const std::string &content_type) {
6592   return cli_->Put(path, content_length, std::move(content_provider),
6593                    content_type);
6594 }
6595 Result Client::Put(const std::string &path,
6596                           ContentProviderWithoutLength content_provider,
6597                           const std::string &content_type) {
6598   return cli_->Put(path, std::move(content_provider), content_type);
6599 }
6600 Result Client::Put(const std::string &path, const Headers &headers,
6601                           size_t content_length,
6602                           ContentProvider content_provider,
6603                           const std::string &content_type) {
6604   return cli_->Put(path, headers, content_length, std::move(content_provider),
6605                    content_type);
6606 }
6607 Result Client::Put(const std::string &path, const Headers &headers,
6608                           ContentProviderWithoutLength content_provider,
6609                           const std::string &content_type) {
6610   return cli_->Put(path, headers, std::move(content_provider), content_type);
6611 }
6612 Result Client::Put(const std::string &path, const Params &params) {
6613   return cli_->Put(path, params);
6614 }
6615 Result Client::Put(const std::string &path, const Headers &headers,
6616                           const Params &params) {
6617   return cli_->Put(path, headers, params);
6618 }
6619 Result Client::Put(const std::string &path,
6620                           const MultipartFormDataItems &items) {
6621   return cli_->Put(path, items);
6622 }
6623 Result Client::Put(const std::string &path, const Headers &headers,
6624                           const MultipartFormDataItems &items) {
6625   return cli_->Put(path, headers, items);
6626 }
6627 Result Client::Put(const std::string &path, const Headers &headers,
6628                           const MultipartFormDataItems &items,
6629                           const std::string &boundary) {
6630   return cli_->Put(path, headers, items, boundary);
6631 }
6632 Result
6633 Client::Put(const std::string &path, const Headers &headers,
6634             const MultipartFormDataItems &items,
6635             const MultipartFormDataProviderItems &provider_items) {
6636   return cli_->Put(path, headers, items, provider_items);
6637 }
6638 Result Client::Patch(const std::string &path) {
6639   return cli_->Patch(path);
6640 }
6641 Result Client::Patch(const std::string &path, const char *body,
6642                             size_t content_length,
6643                             const std::string &content_type) {
6644   return cli_->Patch(path, body, content_length, content_type);
6645 }
6646 Result Client::Patch(const std::string &path, const Headers &headers,
6647                             const char *body, size_t content_length,
6648                             const std::string &content_type) {
6649   return cli_->Patch(path, headers, body, content_length, content_type);
6650 }
6651 Result Client::Patch(const std::string &path, const std::string &body,
6652                             const std::string &content_type) {
6653   return cli_->Patch(path, body, content_type);
6654 }
6655 Result Client::Patch(const std::string &path, const Headers &headers,
6656                             const std::string &body,
6657                             const std::string &content_type) {
6658   return cli_->Patch(path, headers, body, content_type);
6659 }
6660 Result Client::Patch(const std::string &path, size_t content_length,
6661                             ContentProvider content_provider,
6662                             const std::string &content_type) {
6663   return cli_->Patch(path, content_length, std::move(content_provider),
6664                      content_type);
6665 }
6666 Result Client::Patch(const std::string &path,
6667                             ContentProviderWithoutLength content_provider,
6668                             const std::string &content_type) {
6669   return cli_->Patch(path, std::move(content_provider), content_type);
6670 }
6671 Result Client::Patch(const std::string &path, const Headers &headers,
6672                             size_t content_length,
6673                             ContentProvider content_provider,
6674                             const std::string &content_type) {
6675   return cli_->Patch(path, headers, content_length, std::move(content_provider),
6676                      content_type);
6677 }
6678 Result Client::Patch(const std::string &path, const Headers &headers,
6679                             ContentProviderWithoutLength content_provider,
6680                             const std::string &content_type) {
6681   return cli_->Patch(path, headers, std::move(content_provider), content_type);
6682 }
6683 Result Client::Delete(const std::string &path) {
6684   return cli_->Delete(path);
6685 }
6686 Result Client::Delete(const std::string &path, const Headers &headers) {
6687   return cli_->Delete(path, headers);
6688 }
6689 Result Client::Delete(const std::string &path, const char *body,
6690                              size_t content_length,
6691                              const std::string &content_type) {
6692   return cli_->Delete(path, body, content_length, content_type);
6693 }
6694 Result Client::Delete(const std::string &path, const Headers &headers,
6695                              const char *body, size_t content_length,
6696                              const std::string &content_type) {
6697   return cli_->Delete(path, headers, body, content_length, content_type);
6698 }
6699 Result Client::Delete(const std::string &path, const std::string &body,
6700                              const std::string &content_type) {
6701   return cli_->Delete(path, body, content_type);
6702 }
6703 Result Client::Delete(const std::string &path, const Headers &headers,
6704                              const std::string &body,
6705                              const std::string &content_type) {
6706   return cli_->Delete(path, headers, body, content_type);
6707 }
6708 Result Client::Options(const std::string &path) {
6709   return cli_->Options(path);
6710 }
6711 Result Client::Options(const std::string &path, const Headers &headers) {
6712   return cli_->Options(path, headers);
6713 }
6714
6715 bool Client::send(Request &req, Response &res, Error &error) {
6716   return cli_->send(req, res, error);
6717 }
6718
6719 Result Client::send(const Request &req) { return cli_->send(req); }
6720
6721 size_t Client::is_socket_open() const { return cli_->is_socket_open(); }
6722
6723 socket_t Client::socket() const { return cli_->socket(); }
6724
6725 void Client::stop() { cli_->stop(); }
6726
6727 void
6728 Client::set_hostname_addr_map(std::map<std::string, std::string> addr_map) {
6729   cli_->set_hostname_addr_map(std::move(addr_map));
6730 }
6731
6732 void Client::set_default_headers(Headers headers) {
6733   cli_->set_default_headers(std::move(headers));
6734 }
6735
6736 void Client::set_address_family(int family) {
6737   cli_->set_address_family(family);
6738 }
6739
6740 void Client::set_tcp_nodelay(bool on) { cli_->set_tcp_nodelay(on); }
6741
6742 void Client::set_socket_options(SocketOptions socket_options) {
6743   cli_->set_socket_options(std::move(socket_options));
6744 }
6745
6746 void Client::set_connection_timeout(time_t sec, time_t usec) {
6747   cli_->set_connection_timeout(sec, usec);
6748 }
6749
6750 void Client::set_read_timeout(time_t sec, time_t usec) {
6751   cli_->set_read_timeout(sec, usec);
6752 }
6753
6754 void Client::set_write_timeout(time_t sec, time_t usec) {
6755   cli_->set_write_timeout(sec, usec);
6756 }
6757
6758 void Client::set_basic_auth(const std::string &username,
6759                                    const std::string &password) {
6760   cli_->set_basic_auth(username, password);
6761 }
6762 void Client::set_bearer_token_auth(const std::string &token) {
6763   cli_->set_bearer_token_auth(token);
6764 }
6765 #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
6766 void Client::set_digest_auth(const std::string &username,
6767                                     const std::string &password) {
6768   cli_->set_digest_auth(username, password);
6769 }
6770 #endif
6771
6772 void Client::set_keep_alive(bool on) { cli_->set_keep_alive(on); }
6773 void Client::set_follow_location(bool on) {
6774   cli_->set_follow_location(on);
6775 }
6776
6777 void Client::set_url_encode(bool on) { cli_->set_url_encode(on); }
6778
6779 void Client::set_compress(bool on) { cli_->set_compress(on); }
6780
6781 void Client::set_decompress(bool on) { cli_->set_decompress(on); }
6782
6783 void Client::set_interface(const std::string &intf) {
6784   cli_->set_interface(intf);
6785 }
6786
6787 void Client::set_proxy(const std::string &host, int port) {
6788   cli_->set_proxy(host, port);
6789 }
6790 void Client::set_proxy_basic_auth(const std::string &username,
6791                                          const std::string &password) {
6792   cli_->set_proxy_basic_auth(username, password);
6793 }
6794 void Client::set_proxy_bearer_token_auth(const std::string &token) {
6795   cli_->set_proxy_bearer_token_auth(token);
6796 }
6797 #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
6798 void Client::set_proxy_digest_auth(const std::string &username,
6799                                           const std::string &password) {
6800   cli_->set_proxy_digest_auth(username, password);
6801 }
6802 #endif
6803
6804 #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
6805 void Client::enable_server_certificate_verification(bool enabled) {
6806   cli_->enable_server_certificate_verification(enabled);
6807 }
6808 #endif
6809
6810 void Client::set_logger(Logger logger) {
6811   cli_->set_logger(std::move(logger));
6812 }
6813
6814 #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
6815 void Client::set_ca_cert_path(const std::string &ca_cert_file_path,
6816                                      const std::string &ca_cert_dir_path) {
6817   cli_->set_ca_cert_path(ca_cert_file_path, ca_cert_dir_path);
6818 }
6819
6820 void Client::set_ca_cert_store(X509_STORE *ca_cert_store) {
6821   if (is_ssl_) {
6822     static_cast<SSLClient &>(*cli_).set_ca_cert_store(ca_cert_store);
6823   } else {
6824     cli_->set_ca_cert_store(ca_cert_store);
6825   }
6826 }
6827
6828 void Client::load_ca_cert_store(const char *ca_cert, std::size_t size) {
6829   set_ca_cert_store(cli_->create_ca_cert_store(ca_cert, size));
6830 }
6831
6832 long Client::get_openssl_verify_result() const {
6833   if (is_ssl_) {
6834     return static_cast<SSLClient &>(*cli_).get_openssl_verify_result();
6835   }
6836   return -1; // NOTE: -1 doesn't match any of X509_V_ERR_???
6837 }
6838
6839 SSL_CTX *Client::ssl_context() const {
6840   if (is_ssl_) { return static_cast<SSLClient &>(*cli_).ssl_context(); }
6841   return nullptr;
6842 }
6843 #endif
6844
6845 } // namespace httplib
6846
6847 #endif // WORLD_SCORE