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