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