httplib.h
Go to the documentation of this file.
1 //
2 // httplib.h
3 //
4 // Copyright (c) 2024 Yuji Hirose. All rights reserved.
5 // MIT License
6 //
7 
8 #ifndef CPPHTTPLIB_HTTPLIB_H
9 #define CPPHTTPLIB_HTTPLIB_H
10 
11 #define CPPHTTPLIB_VERSION "0.18.3"
12 
13 /*
14  * Configuration
15  */
16 
17 #ifndef CPPHTTPLIB_KEEPALIVE_TIMEOUT_SECOND
18 #define CPPHTTPLIB_KEEPALIVE_TIMEOUT_SECOND 5
19 #endif
20 
21 #ifndef CPPHTTPLIB_KEEPALIVE_TIMEOUT_CHECK_INTERVAL_USECOND
22 #define CPPHTTPLIB_KEEPALIVE_TIMEOUT_CHECK_INTERVAL_USECOND 10000
23 #endif
24 
25 #ifndef CPPHTTPLIB_KEEPALIVE_MAX_COUNT
26 #define CPPHTTPLIB_KEEPALIVE_MAX_COUNT 100
27 #endif
28 
29 #ifndef CPPHTTPLIB_CONNECTION_TIMEOUT_SECOND
30 #define CPPHTTPLIB_CONNECTION_TIMEOUT_SECOND 300
31 #endif
32 
33 #ifndef CPPHTTPLIB_CONNECTION_TIMEOUT_USECOND
34 #define CPPHTTPLIB_CONNECTION_TIMEOUT_USECOND 0
35 #endif
36 
37 #ifndef CPPHTTPLIB_SERVER_READ_TIMEOUT_SECOND
38 #define CPPHTTPLIB_SERVER_READ_TIMEOUT_SECOND 5
39 #endif
40 
41 #ifndef CPPHTTPLIB_SERVER_READ_TIMEOUT_USECOND
42 #define CPPHTTPLIB_SERVER_READ_TIMEOUT_USECOND 0
43 #endif
44 
45 #ifndef CPPHTTPLIB_SERVER_WRITE_TIMEOUT_SECOND
46 #define CPPHTTPLIB_SERVER_WRITE_TIMEOUT_SECOND 5
47 #endif
48 
49 #ifndef CPPHTTPLIB_SERVER_WRITE_TIMEOUT_USECOND
50 #define CPPHTTPLIB_SERVER_WRITE_TIMEOUT_USECOND 0
51 #endif
52 
53 #ifndef CPPHTTPLIB_CLIENT_READ_TIMEOUT_SECOND
54 #define CPPHTTPLIB_CLIENT_READ_TIMEOUT_SECOND 300
55 #endif
56 
57 #ifndef CPPHTTPLIB_CLIENT_READ_TIMEOUT_USECOND
58 #define CPPHTTPLIB_CLIENT_READ_TIMEOUT_USECOND 0
59 #endif
60 
61 #ifndef CPPHTTPLIB_CLIENT_WRITE_TIMEOUT_SECOND
62 #define CPPHTTPLIB_CLIENT_WRITE_TIMEOUT_SECOND 5
63 #endif
64 
65 #ifndef CPPHTTPLIB_CLIENT_WRITE_TIMEOUT_USECOND
66 #define CPPHTTPLIB_CLIENT_WRITE_TIMEOUT_USECOND 0
67 #endif
68 
69 #ifndef CPPHTTPLIB_IDLE_INTERVAL_SECOND
70 #define CPPHTTPLIB_IDLE_INTERVAL_SECOND 0
71 #endif
72 
73 #ifndef CPPHTTPLIB_IDLE_INTERVAL_USECOND
74 #ifdef _WIN32
75 #define CPPHTTPLIB_IDLE_INTERVAL_USECOND 10000
76 #else
77 #define CPPHTTPLIB_IDLE_INTERVAL_USECOND 0
78 #endif
79 #endif
80 
81 #ifndef CPPHTTPLIB_REQUEST_URI_MAX_LENGTH
82 #define CPPHTTPLIB_REQUEST_URI_MAX_LENGTH 8192
83 #endif
84 
85 #ifndef CPPHTTPLIB_HEADER_MAX_LENGTH
86 #define CPPHTTPLIB_HEADER_MAX_LENGTH 8192
87 #endif
88 
89 #ifndef CPPHTTPLIB_REDIRECT_MAX_COUNT
90 #define CPPHTTPLIB_REDIRECT_MAX_COUNT 20
91 #endif
92 
93 #ifndef CPPHTTPLIB_MULTIPART_FORM_DATA_FILE_MAX_COUNT
94 #define CPPHTTPLIB_MULTIPART_FORM_DATA_FILE_MAX_COUNT 1024
95 #endif
96 
97 #ifndef CPPHTTPLIB_PAYLOAD_MAX_LENGTH
98 #define CPPHTTPLIB_PAYLOAD_MAX_LENGTH ((std::numeric_limits<size_t>::max)())
99 #endif
100 
101 #ifndef CPPHTTPLIB_FORM_URL_ENCODED_PAYLOAD_MAX_LENGTH
102 #define CPPHTTPLIB_FORM_URL_ENCODED_PAYLOAD_MAX_LENGTH 8192
103 #endif
104 
105 #ifndef CPPHTTPLIB_RANGE_MAX_COUNT
106 #define CPPHTTPLIB_RANGE_MAX_COUNT 1024
107 #endif
108 
109 #ifndef CPPHTTPLIB_TCP_NODELAY
110 #define CPPHTTPLIB_TCP_NODELAY false
111 #endif
112 
113 #ifndef CPPHTTPLIB_IPV6_V6ONLY
114 #define CPPHTTPLIB_IPV6_V6ONLY false
115 #endif
116 
117 #ifndef CPPHTTPLIB_RECV_BUFSIZ
118 #define CPPHTTPLIB_RECV_BUFSIZ size_t(16384u)
119 #endif
120 
121 #ifndef CPPHTTPLIB_COMPRESSION_BUFSIZ
122 #define CPPHTTPLIB_COMPRESSION_BUFSIZ size_t(16384u)
123 #endif
124 
125 #ifndef CPPHTTPLIB_THREAD_POOL_COUNT
126 #define CPPHTTPLIB_THREAD_POOL_COUNT \
127  ((std::max)(8u, std::thread::hardware_concurrency() > 0 \
128  ? std::thread::hardware_concurrency() - 1 \
129  : 0))
130 #endif
131 
132 #ifndef CPPHTTPLIB_RECV_FLAGS
133 #define CPPHTTPLIB_RECV_FLAGS 0
134 #endif
135 
136 #ifndef CPPHTTPLIB_SEND_FLAGS
137 #define CPPHTTPLIB_SEND_FLAGS 0
138 #endif
139 
140 #ifndef CPPHTTPLIB_LISTEN_BACKLOG
141 #define CPPHTTPLIB_LISTEN_BACKLOG 5
142 #endif
143 
144 /*
145  * Headers
146  */
147 
148 #ifdef _WIN32
149 #ifndef _CRT_SECURE_NO_WARNINGS
150 #define _CRT_SECURE_NO_WARNINGS
151 #endif //_CRT_SECURE_NO_WARNINGS
152 
153 #ifndef _CRT_NONSTDC_NO_DEPRECATE
154 #define _CRT_NONSTDC_NO_DEPRECATE
155 #endif //_CRT_NONSTDC_NO_DEPRECATE
156 
157 #if defined(_MSC_VER)
158 #if _MSC_VER < 1900
159 #error Sorry, Visual Studio versions prior to 2015 are not supported
160 #endif
161 
162 #pragma comment(lib, "ws2_32.lib")
163 
164 #ifdef _WIN64
165 using ssize_t = __int64;
166 #else
167 using ssize_t = long;
168 #endif
169 #endif // _MSC_VER
170 
171 #ifndef S_ISREG
172 #define S_ISREG(m) (((m) & S_IFREG) == S_IFREG)
173 #endif // S_ISREG
174 
175 #ifndef S_ISDIR
176 #define S_ISDIR(m) (((m) & S_IFDIR) == S_IFDIR)
177 #endif // S_ISDIR
178 
179 #ifndef NOMINMAX
180 #define NOMINMAX
181 #endif // NOMINMAX
182 
183 #include <io.h>
184 #include <winsock2.h>
185 #include <ws2tcpip.h>
186 
187 #ifndef WSA_FLAG_NO_HANDLE_INHERIT
188 #define WSA_FLAG_NO_HANDLE_INHERIT 0x80
189 #endif
190 
191 using socket_t = SOCKET;
192 #ifdef CPPHTTPLIB_USE_POLL
193 #define poll(fds, nfds, timeout) WSAPoll(fds, nfds, timeout)
194 #endif
195 
196 #else // not _WIN32
197 
198 #include <arpa/inet.h>
199 #if !defined(_AIX) && !defined(__MVS__)
200 #include <ifaddrs.h>
201 #endif
202 #ifdef __MVS__
203 #include <strings.h>
204 #ifndef NI_MAXHOST
205 #define NI_MAXHOST 1025
206 #endif
207 #endif
208 #include <net/if.h>
209 #include <netdb.h>
210 #include <netinet/in.h>
211 #ifdef __linux__
212 #include <resolv.h>
213 #endif
214 #include <netinet/tcp.h>
215 #ifdef CPPHTTPLIB_USE_POLL
216 #include <poll.h>
217 #endif
218 #include <csignal>
219 #include <pthread.h>
220 #include <sys/mman.h>
221 #include <sys/select.h>
222 #include <sys/socket.h>
223 #include <sys/un.h>
224 #include <unistd.h>
225 
226 using socket_t = int;
227 #ifndef INVALID_SOCKET
228 #define INVALID_SOCKET (-1)
229 #endif
230 #endif //_WIN32
231 
232 #include <algorithm>
233 #include <array>
234 #include <atomic>
235 #include <cassert>
236 #include <cctype>
237 #include <climits>
238 #include <condition_variable>
239 #include <cstring>
240 #include <errno.h>
241 #include <exception>
242 #include <fcntl.h>
243 #include <fstream>
244 #include <functional>
245 #include <iomanip>
246 #include <iostream>
247 #include <list>
248 #include <map>
249 #include <memory>
250 #include <mutex>
251 #include <random>
252 #include <regex>
253 #include <set>
254 #include <sstream>
255 #include <string>
256 #include <sys/stat.h>
257 #include <thread>
258 #include <unordered_map>
259 #include <unordered_set>
260 #include <utility>
261 
262 #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
263 #ifdef _WIN32
264 #include <wincrypt.h>
265 
266 // these are defined in wincrypt.h and it breaks compilation if BoringSSL is
267 // used
268 #undef X509_NAME
269 #undef X509_CERT_PAIR
270 #undef X509_EXTENSIONS
271 #undef PKCS7_SIGNER_INFO
272 
273 #ifdef _MSC_VER
274 #pragma comment(lib, "crypt32.lib")
275 #endif
276 #elif defined(CPPHTTPLIB_USE_CERTS_FROM_MACOSX_KEYCHAIN) && defined(__APPLE__)
277 #include <TargetConditionals.h>
278 #if TARGET_OS_OSX
279 #include <CoreFoundation/CoreFoundation.h>
280 #include <Security/Security.h>
281 #endif // TARGET_OS_OSX
282 #endif // _WIN32
283 
284 #include <openssl/err.h>
285 #include <openssl/evp.h>
286 #include <openssl/ssl.h>
287 #include <openssl/x509v3.h>
288 
289 #if defined(_WIN32) && defined(OPENSSL_USE_APPLINK)
290 #include <openssl/applink.c>
291 #endif
292 
293 #include <iostream>
294 #include <sstream>
295 
296 #if defined(OPENSSL_IS_BORINGSSL) || defined(LIBRESSL_VERSION_NUMBER)
297 #if OPENSSL_VERSION_NUMBER < 0x1010107f
298 #error Please use OpenSSL or a current version of BoringSSL
299 #endif
300 #define SSL_get1_peer_certificate SSL_get_peer_certificate
301 #elif OPENSSL_VERSION_NUMBER < 0x30000000L
302 #error Sorry, OpenSSL versions prior to 3.0.0 are not supported
303 #endif
304 
305 #endif
306 
307 #ifdef CPPHTTPLIB_ZLIB_SUPPORT
308 #include <zlib.h>
309 #endif
310 
311 #ifdef CPPHTTPLIB_BROTLI_SUPPORT
312 #include <brotli/decode.h>
313 #include <brotli/encode.h>
314 #endif
315 
316 /*
317  * Declaration
318  */
319 namespace httplib {
320 
321 namespace detail {
322 
323 /*
324  * Backport std::make_unique from C++14.
325  *
326  * NOTE: This code came up with the following stackoverflow post:
327  * https://stackoverflow.com/questions/10149840/c-arrays-and-make-unique
328  *
329  */
330 
331 template <class T, class... Args>
332 typename std::enable_if<!std::is_array<T>::value, std::unique_ptr<T>>::type
333 make_unique(Args &&...args) {
334  return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
335 }
336 
337 template <class T>
338 typename std::enable_if<std::is_array<T>::value, std::unique_ptr<T>>::type
339 make_unique(std::size_t n) {
340  typedef typename std::remove_extent<T>::type RT;
341  return std::unique_ptr<T>(new RT[n]);
342 }
343 
344 namespace case_ignore {
345 
346 inline unsigned char to_lower(int c) {
347  const static unsigned char table[256] = {
348  0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
349  15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
350  30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44,
351  45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
352  60, 61, 62, 63, 64, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106,
353  107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121,
354  122, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104,
355  105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119,
356  120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134,
357  135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149,
358  150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164,
359  165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179,
360  180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 224, 225, 226,
361  227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241,
362  242, 243, 244, 245, 246, 215, 248, 249, 250, 251, 252, 253, 254, 223, 224,
363  225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239,
364  240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254,
365  255,
366  };
367  return table[(unsigned char)(char)c];
368 }
369 
370 inline bool equal(const std::string &a, const std::string &b) {
371  return a.size() == b.size() &&
372  std::equal(a.begin(), a.end(), b.begin(), [](char ca, char cb) {
373  return to_lower(ca) == to_lower(cb);
374  });
375 }
376 
377 struct equal_to {
378  bool operator()(const std::string &a, const std::string &b) const {
379  return equal(a, b);
380  }
381 };
382 
383 struct hash {
384  size_t operator()(const std::string &key) const {
385  return hash_core(key.data(), key.size(), 0);
386  }
387 
388  size_t hash_core(const char *s, size_t l, size_t h) const {
389  return (l == 0) ? h
390  : hash_core(s + 1, l - 1,
391  // Unsets the 6 high bits of h, therefore no
392  // overflow happens
394  h * 33) ^
395  static_cast<unsigned char>(to_lower(*s)));
396  }
397 };
398 
399 } // namespace case_ignore
400 
401 // This is based on
402 // "http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4189".
403 
404 struct scope_exit {
405  explicit scope_exit(std::function<void(void)> &&f)
406  : exit_function(std::move(f)), execute_on_destruction{true} {}
407 
408  scope_exit(scope_exit &&rhs) noexcept
409  : exit_function(std::move(rhs.exit_function)),
410  execute_on_destruction{rhs.execute_on_destruction} {
411  rhs.release();
412  }
413 
415  if (execute_on_destruction) { this->exit_function(); }
416  }
417 
418  void release() { this->execute_on_destruction = false; }
419 
420 private:
421  scope_exit(const scope_exit &) = delete;
422  void operator=(const scope_exit &) = delete;
423  scope_exit &operator=(scope_exit &&) = delete;
424 
425  std::function<void(void)> exit_function;
426  bool execute_on_destruction;
427 };
428 
429 } // namespace detail
430 
432  // Information responses
437 
438  // Successful responses
439  OK_200 = 200,
440  Created_201 = 201,
448  IMUsed_226 = 226,
449 
450  // Redirection messages
453  Found_302 = 302,
457  unused_306 = 306,
460 
461  // Client error responses
472  Gone_410 = 410,
483  Locked_423 = 423,
491 
492  // Server error responses
504 };
505 
506 using Headers =
507  std::unordered_multimap<std::string, std::string, detail::case_ignore::hash,
509 
510 using Params = std::multimap<std::string, std::string>;
511 using Match = std::smatch;
512 
513 using Progress = std::function<bool(uint64_t current, uint64_t total)>;
514 
515 struct Response;
516 using ResponseHandler = std::function<bool(const Response &response)>;
517 
519  std::string name;
520  std::string content;
521  std::string filename;
522  std::string content_type;
523 };
524 using MultipartFormDataItems = std::vector<MultipartFormData>;
525 using MultipartFormDataMap = std::multimap<std::string, MultipartFormData>;
526 
527 class DataSink {
528 public:
529  DataSink() : os(&sb_), sb_(*this) {}
530 
531  DataSink(const DataSink &) = delete;
532  DataSink &operator=(const DataSink &) = delete;
533  DataSink(DataSink &&) = delete;
534  DataSink &operator=(DataSink &&) = delete;
535 
536  std::function<bool(const char *data, size_t data_len)> write;
537  std::function<bool()> is_writable;
538  std::function<void()> done;
539  std::function<void(const Headers &trailer)> done_with_trailer;
540  std::ostream os;
541 
542 private:
543  class data_sink_streambuf final : public std::streambuf {
544  public:
545  explicit data_sink_streambuf(DataSink &sink) : sink_(sink) {}
546 
547  protected:
548  std::streamsize xsputn(const char *s, std::streamsize n) override {
549  sink_.write(s, static_cast<size_t>(n));
550  return n;
551  }
552 
553  private:
554  DataSink &sink_;
555  };
556 
557  data_sink_streambuf sb_;
558 };
559 
560 using ContentProvider =
561  std::function<bool(size_t offset, size_t length, DataSink &sink)>;
562 
564  std::function<bool(size_t offset, DataSink &sink)>;
565 
566 using ContentProviderResourceReleaser = std::function<void(bool success)>;
567 
569  std::string name;
571  std::string filename;
572  std::string content_type;
573 };
574 using MultipartFormDataProviderItems = std::vector<MultipartFormDataProvider>;
575 
577  std::function<bool(const char *data, size_t data_length, uint64_t offset,
578  uint64_t total_length)>;
579 
580 using ContentReceiver =
581  std::function<bool(const char *data, size_t data_length)>;
582 
584  std::function<bool(const MultipartFormData &file)>;
585 
587 public:
588  using Reader = std::function<bool(ContentReceiver receiver)>;
589  using MultipartReader = std::function<bool(MultipartContentHeader header,
590  ContentReceiver receiver)>;
591 
592  ContentReader(Reader reader, MultipartReader multipart_reader)
593  : reader_(std::move(reader)),
594  multipart_reader_(std::move(multipart_reader)) {}
595 
597  ContentReceiver receiver) const {
598  return multipart_reader_(std::move(header), std::move(receiver));
599  }
600 
601  bool operator()(ContentReceiver receiver) const {
602  return reader_(std::move(receiver));
603  }
604 
607 };
608 
609 using Range = std::pair<ssize_t, ssize_t>;
610 using Ranges = std::vector<Range>;
611 
612 struct Request {
613  std::string method;
614  std::string path;
617  std::string body;
618 
619  std::string remote_addr;
620  int remote_port = -1;
621  std::string local_addr;
622  int local_port = -1;
623 
624  // for server
625  std::string version;
626  std::string target;
630  std::unordered_map<std::string, std::string> path_params;
631 
632  // for client
636 #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
637  const SSL *ssl = nullptr;
638 #endif
639 
640  bool has_header(const std::string &key) const;
641  std::string get_header_value(const std::string &key, const char *def = "",
642  size_t id = 0) const;
643  uint64_t get_header_value_u64(const std::string &key, uint64_t def = 0,
644  size_t id = 0) const;
645  size_t get_header_value_count(const std::string &key) const;
646  void set_header(const std::string &key, const std::string &val);
647 
648  bool has_param(const std::string &key) const;
649  std::string get_param_value(const std::string &key, size_t id = 0) const;
650  size_t get_param_value_count(const std::string &key) const;
651 
652  bool is_multipart_form_data() const;
653 
654  bool has_file(const std::string &key) const;
655  MultipartFormData get_file_value(const std::string &key) const;
656  std::vector<MultipartFormData> get_file_values(const std::string &key) const;
657 
658  // private members...
660  size_t content_length_ = 0;
664 };
665 
666 struct Response {
667  std::string version;
668  int status = -1;
669  std::string reason;
671  std::string body;
672  std::string location; // Redirect location
673 
674  bool has_header(const std::string &key) const;
675  std::string get_header_value(const std::string &key, const char *def = "",
676  size_t id = 0) const;
677  uint64_t get_header_value_u64(const std::string &key, uint64_t def = 0,
678  size_t id = 0) const;
679  size_t get_header_value_count(const std::string &key) const;
680  void set_header(const std::string &key, const std::string &val);
681 
682  void set_redirect(const std::string &url, int status = StatusCode::Found_302);
683  void set_content(const char *s, size_t n, const std::string &content_type);
684  void set_content(const std::string &s, const std::string &content_type);
685  void set_content(std::string &&s, const std::string &content_type);
686 
688  size_t length, const std::string &content_type, ContentProvider provider,
689  ContentProviderResourceReleaser resource_releaser = nullptr);
690 
692  const std::string &content_type, ContentProviderWithoutLength provider,
693  ContentProviderResourceReleaser resource_releaser = nullptr);
694 
696  const std::string &content_type, ContentProviderWithoutLength provider,
697  ContentProviderResourceReleaser resource_releaser = nullptr);
698 
699  void set_file_content(const std::string &path,
700  const std::string &content_type);
701  void set_file_content(const std::string &path);
702 
703  Response() = default;
704  Response(const Response &) = default;
705  Response &operator=(const Response &) = default;
706  Response(Response &&) = default;
707  Response &operator=(Response &&) = default;
711  }
712  }
713 
714  // private members...
715  size_t content_length_ = 0;
720  std::string file_content_path_;
722 };
723 
724 class Stream {
725 public:
726  virtual ~Stream() = default;
727 
728  virtual bool is_readable() const = 0;
729  virtual bool is_writable() const = 0;
730 
731  virtual ssize_t read(char *ptr, size_t size) = 0;
732  virtual ssize_t write(const char *ptr, size_t size) = 0;
733  virtual void get_remote_ip_and_port(std::string &ip, int &port) const = 0;
734  virtual void get_local_ip_and_port(std::string &ip, int &port) const = 0;
735  virtual socket_t socket() const = 0;
736 
737  ssize_t write(const char *ptr);
738  ssize_t write(const std::string &s);
739 };
740 
741 class TaskQueue {
742 public:
743  TaskQueue() = default;
744  virtual ~TaskQueue() = default;
745 
746  virtual bool enqueue(std::function<void()> fn) = 0;
747  virtual void shutdown() = 0;
748 
749  virtual void on_idle() {}
750 };
751 
752 class ThreadPool final : public TaskQueue {
753 public:
754  explicit ThreadPool(size_t n, size_t mqr = 0)
755  : shutdown_(false), max_queued_requests_(mqr) {
756  while (n) {
757  threads_.emplace_back(worker(*this));
758  n--;
759  }
760  }
761 
762  ThreadPool(const ThreadPool &) = delete;
763  ~ThreadPool() override = default;
764 
765  bool enqueue(std::function<void()> fn) override {
766  {
767  std::unique_lock<std::mutex> lock(mutex_);
768  if (max_queued_requests_ > 0 && jobs_.size() >= max_queued_requests_) {
769  return false;
770  }
771  jobs_.push_back(std::move(fn));
772  }
773 
774  cond_.notify_one();
775  return true;
776  }
777 
778  void shutdown() override {
779  // Stop all worker threads...
780  {
781  std::unique_lock<std::mutex> lock(mutex_);
782  shutdown_ = true;
783  }
784 
785  cond_.notify_all();
786 
787  // Join...
788  for (auto &t : threads_) {
789  t.join();
790  }
791  }
792 
793 private:
794  struct worker {
795  explicit worker(ThreadPool &pool) : pool_(pool) {}
796 
797  void operator()() {
798  for (;;) {
799  std::function<void()> fn;
800  {
801  std::unique_lock<std::mutex> lock(pool_.mutex_);
802 
803  pool_.cond_.wait(
804  lock, [&] { return !pool_.jobs_.empty() || pool_.shutdown_; });
805 
806  if (pool_.shutdown_ && pool_.jobs_.empty()) { break; }
807 
808  fn = pool_.jobs_.front();
809  pool_.jobs_.pop_front();
810  }
811 
812  assert(true == static_cast<bool>(fn));
813  fn();
814  }
815 
816 #if defined(CPPHTTPLIB_OPENSSL_SUPPORT) && !defined(OPENSSL_IS_BORINGSSL) && \
817  !defined(LIBRESSL_VERSION_NUMBER)
818  OPENSSL_thread_stop();
819 #endif
820  }
821 
822  ThreadPool &pool_;
823  };
824  friend struct worker;
825 
826  std::vector<std::thread> threads_;
827  std::list<std::function<void()>> jobs_;
828 
829  bool shutdown_;
830  size_t max_queued_requests_ = 0;
831 
832  std::condition_variable cond_;
833  std::mutex mutex_;
834 };
835 
836 using Logger = std::function<void(const Request &, const Response &)>;
837 
838 using SocketOptions = std::function<void(socket_t sock)>;
839 
841 
842 const char *status_message(int status);
843 
844 std::string get_bearer_token_auth(const Request &req);
845 
846 namespace detail {
847 
848 class MatcherBase {
849 public:
850  virtual ~MatcherBase() = default;
851 
852  // Match request path and populate its matches and
853  virtual bool match(Request &request) const = 0;
854 };
855 
856 /**
857  * Captures parameters in request path and stores them in Request::path_params
858  *
859  * Capture name is a substring of a pattern from : to /.
860  * The rest of the pattern is matched agains the request path directly
861  * Parameters are captured starting from the next character after
862  * the end of the last matched static pattern fragment until the next /.
863  *
864  * Example pattern:
865  * "/path/fragments/:capture/more/fragments/:second_capture"
866  * Static fragments:
867  * "/path/fragments/", "more/fragments/"
868  *
869  * Given the following request path:
870  * "/path/fragments/:1/more/fragments/:2"
871  * the resulting capture will be
872  * {{"capture", "1"}, {"second_capture", "2"}}
873  */
874 class PathParamsMatcher final : public MatcherBase {
875 public:
876  PathParamsMatcher(const std::string &pattern);
877 
878  bool match(Request &request) const override;
879 
880 private:
881  // Treat segment separators as the end of path parameter capture
882  // Does not need to handle query parameters as they are parsed before path
883  // matching
884  static constexpr char separator = '/';
885 
886  // Contains static path fragments to match against, excluding the '/' after
887  // path params
888  // Fragments are separated by path params
889  std::vector<std::string> static_fragments_;
890  // Stores the names of the path parameters to be used as keys in the
891  // Request::path_params map
892  std::vector<std::string> param_names_;
893 };
894 
895 /**
896  * Performs std::regex_match on request path
897  * and stores the result in Request::matches
898  *
899  * Note that regex match is performed directly on the whole request.
900  * This means that wildcard patterns may match multiple path segments with /:
901  * "/begin/(.*)/end" will match both "/begin/middle/end" and "/begin/1/2/end".
902  */
903 class RegexMatcher final : public MatcherBase {
904 public:
905  RegexMatcher(const std::string &pattern) : regex_(pattern) {}
906 
907  bool match(Request &request) const override;
908 
909 private:
910  std::regex regex_;
911 };
912 
913 ssize_t write_headers(Stream &strm, const Headers &headers);
914 
915 } // namespace detail
916 
917 class Server {
918 public:
919  using Handler = std::function<void(const Request &, Response &)>;
920 
921  using ExceptionHandler =
922  std::function<void(const Request &, Response &, std::exception_ptr ep)>;
923 
924  enum class HandlerResponse {
925  Handled,
926  Unhandled,
927  };
928  using HandlerWithResponse =
929  std::function<HandlerResponse(const Request &, Response &)>;
930 
931  using HandlerWithContentReader = std::function<void(
932  const Request &, Response &, const ContentReader &content_reader)>;
933 
935  std::function<int(const Request &, Response &)>;
936 
937  Server();
938 
939  virtual ~Server();
940 
941  virtual bool is_valid() const;
942 
943  Server &Get(const std::string &pattern, Handler handler);
944  Server &Post(const std::string &pattern, Handler handler);
945  Server &Post(const std::string &pattern, HandlerWithContentReader handler);
946  Server &Put(const std::string &pattern, Handler handler);
947  Server &Put(const std::string &pattern, HandlerWithContentReader handler);
948  Server &Patch(const std::string &pattern, Handler handler);
949  Server &Patch(const std::string &pattern, HandlerWithContentReader handler);
950  Server &Delete(const std::string &pattern, Handler handler);
951  Server &Delete(const std::string &pattern, HandlerWithContentReader handler);
952  Server &Options(const std::string &pattern, Handler handler);
953 
954  bool set_base_dir(const std::string &dir,
955  const std::string &mount_point = std::string());
956  bool set_mount_point(const std::string &mount_point, const std::string &dir,
957  Headers headers = Headers());
958  bool remove_mount_point(const std::string &mount_point);
959  Server &set_file_extension_and_mimetype_mapping(const std::string &ext,
960  const std::string &mime);
961  Server &set_default_file_mimetype(const std::string &mime);
963 
964  template <class ErrorHandlerFunc>
965  Server &set_error_handler(ErrorHandlerFunc &&handler) {
966  return set_error_handler_core(
967  std::forward<ErrorHandlerFunc>(handler),
968  std::is_convertible<ErrorHandlerFunc, HandlerWithResponse>{});
969  }
970 
974 
976  Server &set_logger(Logger logger);
977 
978  Server &set_address_family(int family);
979  Server &set_tcp_nodelay(bool on);
980  Server &set_ipv6_v6only(bool on);
981  Server &set_socket_options(SocketOptions socket_options);
982 
984  Server &
985  set_header_writer(std::function<ssize_t(Stream &, Headers &)> const &writer);
986 
987  Server &set_keep_alive_max_count(size_t count);
988  Server &set_keep_alive_timeout(time_t sec);
989 
990  Server &set_read_timeout(time_t sec, time_t usec = 0);
991  template <class Rep, class Period>
992  Server &set_read_timeout(const std::chrono::duration<Rep, Period> &duration);
993 
994  Server &set_write_timeout(time_t sec, time_t usec = 0);
995  template <class Rep, class Period>
996  Server &set_write_timeout(const std::chrono::duration<Rep, Period> &duration);
997 
998  Server &set_idle_interval(time_t sec, time_t usec = 0);
999  template <class Rep, class Period>
1000  Server &set_idle_interval(const std::chrono::duration<Rep, Period> &duration);
1001 
1002  Server &set_payload_max_length(size_t length);
1003 
1004  bool bind_to_port(const std::string &host, int port, int socket_flags = 0);
1005  int bind_to_any_port(const std::string &host, int socket_flags = 0);
1006  bool listen_after_bind();
1007 
1008  bool listen(const std::string &host, int port, int socket_flags = 0);
1009 
1010  bool is_running() const;
1011  void wait_until_ready() const;
1012  void stop();
1013  void decommission();
1014 
1015  std::function<TaskQueue *(void)> new_task_queue;
1016 
1017 protected:
1018  bool process_request(Stream &strm, const std::string &remote_addr,
1019  int remote_port, const std::string &local_addr,
1020  int local_port, bool close_connection,
1021  bool &connection_closed,
1022  const std::function<void(Request &)> &setup_request);
1023 
1024  std::atomic<socket_t> svr_sock_{INVALID_SOCKET};
1034 
1035 private:
1036  using Handlers =
1037  std::vector<std::pair<std::unique_ptr<detail::MatcherBase>, Handler>>;
1038  using HandlersForContentReader =
1039  std::vector<std::pair<std::unique_ptr<detail::MatcherBase>,
1041 
1042  static std::unique_ptr<detail::MatcherBase>
1043  make_matcher(const std::string &pattern);
1044 
1045  Server &set_error_handler_core(HandlerWithResponse handler, std::true_type);
1046  Server &set_error_handler_core(Handler handler, std::false_type);
1047 
1048  socket_t create_server_socket(const std::string &host, int port,
1049  int socket_flags,
1050  SocketOptions socket_options) const;
1051  int bind_internal(const std::string &host, int port, int socket_flags);
1052  bool listen_internal();
1053 
1054  bool routing(Request &req, Response &res, Stream &strm);
1055  bool handle_file_request(const Request &req, Response &res,
1056  bool head = false);
1057  bool dispatch_request(Request &req, Response &res,
1058  const Handlers &handlers) const;
1059  bool dispatch_request_for_content_reader(
1060  Request &req, Response &res, ContentReader content_reader,
1061  const HandlersForContentReader &handlers) const;
1062 
1063  bool parse_request_line(const char *s, Request &req) const;
1064  void apply_ranges(const Request &req, Response &res,
1065  std::string &content_type, std::string &boundary) const;
1066  bool write_response(Stream &strm, bool close_connection, Request &req,
1067  Response &res);
1068  bool write_response_with_content(Stream &strm, bool close_connection,
1069  const Request &req, Response &res);
1070  bool write_response_core(Stream &strm, bool close_connection,
1071  const Request &req, Response &res,
1072  bool need_apply_ranges);
1073  bool write_content_with_provider(Stream &strm, const Request &req,
1074  Response &res, const std::string &boundary,
1075  const std::string &content_type);
1076  bool read_content(Stream &strm, Request &req, Response &res);
1077  bool
1078  read_content_with_content_receiver(Stream &strm, Request &req, Response &res,
1079  ContentReceiver receiver,
1080  MultipartContentHeader multipart_header,
1081  ContentReceiver multipart_receiver);
1082  bool read_content_core(Stream &strm, Request &req, Response &res,
1083  ContentReceiver receiver,
1084  MultipartContentHeader multipart_header,
1085  ContentReceiver multipart_receiver) const;
1086 
1087  virtual bool process_and_close_socket(socket_t sock);
1088 
1089  std::atomic<bool> is_running_{false};
1090  std::atomic<bool> is_decommisioned{false};
1091 
1092  struct MountPointEntry {
1093  std::string mount_point;
1094  std::string base_dir;
1095  Headers headers;
1096  };
1097  std::vector<MountPointEntry> base_dirs_;
1098  std::map<std::string, std::string> file_extension_and_mimetype_map_;
1099  std::string default_file_mimetype_ = "application/octet-stream";
1100  Handler file_request_handler_;
1101 
1102  Handlers get_handlers_;
1103  Handlers post_handlers_;
1104  HandlersForContentReader post_handlers_for_content_reader_;
1105  Handlers put_handlers_;
1106  HandlersForContentReader put_handlers_for_content_reader_;
1107  Handlers patch_handlers_;
1108  HandlersForContentReader patch_handlers_for_content_reader_;
1109  Handlers delete_handlers_;
1110  HandlersForContentReader delete_handlers_for_content_reader_;
1111  Handlers options_handlers_;
1112 
1113  HandlerWithResponse error_handler_;
1114  ExceptionHandler exception_handler_;
1115  HandlerWithResponse pre_routing_handler_;
1116  Handler post_routing_handler_;
1117  Expect100ContinueHandler expect_100_continue_handler_;
1118 
1119  Logger logger_;
1120 
1121  int address_family_ = AF_UNSPEC;
1122  bool tcp_nodelay_ = CPPHTTPLIB_TCP_NODELAY;
1123  bool ipv6_v6only_ = CPPHTTPLIB_IPV6_V6ONLY;
1124  SocketOptions socket_options_ = default_socket_options;
1125 
1126  Headers default_headers_;
1127  std::function<ssize_t(Stream &, Headers &)> header_writer_ =
1129 };
1130 
1131 enum class Error {
1132  Success = 0,
1133  Unknown,
1134  Connection,
1135  BindIPAddress,
1136  Read,
1137  Write,
1139  Canceled,
1140  SSLConnection,
1145  Compression,
1148 
1149  // For internal use only
1151 };
1152 
1153 std::string to_string(Error error);
1154 
1155 std::ostream &operator<<(std::ostream &os, const Error &obj);
1156 
1157 class Result {
1158 public:
1159  Result() = default;
1160  Result(std::unique_ptr<Response> &&res, Error err,
1161  Headers &&request_headers = Headers{})
1162  : res_(std::move(res)), err_(err),
1163  request_headers_(std::move(request_headers)) {}
1164  // Response
1165  operator bool() const { return res_ != nullptr; }
1166  bool operator==(std::nullptr_t) const { return res_ == nullptr; }
1167  bool operator!=(std::nullptr_t) const { return res_ != nullptr; }
1168  const Response &value() const { return *res_; }
1169  Response &value() { return *res_; }
1170  const Response &operator*() const { return *res_; }
1171  Response &operator*() { return *res_; }
1172  const Response *operator->() const { return res_.get(); }
1173  Response *operator->() { return res_.get(); }
1174 
1175  // Error
1176  Error error() const { return err_; }
1177 
1178  // Request Headers
1179  bool has_request_header(const std::string &key) const;
1180  std::string get_request_header_value(const std::string &key,
1181  const char *def = "",
1182  size_t id = 0) const;
1183  uint64_t get_request_header_value_u64(const std::string &key,
1184  uint64_t def = 0, size_t id = 0) const;
1185  size_t get_request_header_value_count(const std::string &key) const;
1186 
1187 private:
1188  std::unique_ptr<Response> res_;
1189  Error err_ = Error::Unknown;
1190  Headers request_headers_;
1191 };
1192 
1193 class ClientImpl {
1194 public:
1195  explicit ClientImpl(const std::string &host);
1196 
1197  explicit ClientImpl(const std::string &host, int port);
1198 
1199  explicit ClientImpl(const std::string &host, int port,
1200  const std::string &client_cert_path,
1201  const std::string &client_key_path);
1202 
1203  virtual ~ClientImpl();
1204 
1205  virtual bool is_valid() const;
1206 
1207  Result Get(const std::string &path);
1208  Result Get(const std::string &path, const Headers &headers);
1209  Result Get(const std::string &path, Progress progress);
1210  Result Get(const std::string &path, const Headers &headers,
1211  Progress progress);
1212  Result Get(const std::string &path, ContentReceiver content_receiver);
1213  Result Get(const std::string &path, const Headers &headers,
1214  ContentReceiver content_receiver);
1215  Result Get(const std::string &path, ContentReceiver content_receiver,
1216  Progress progress);
1217  Result Get(const std::string &path, const Headers &headers,
1218  ContentReceiver content_receiver, Progress progress);
1219  Result Get(const std::string &path, ResponseHandler response_handler,
1220  ContentReceiver content_receiver);
1221  Result Get(const std::string &path, const Headers &headers,
1222  ResponseHandler response_handler,
1223  ContentReceiver content_receiver);
1224  Result Get(const std::string &path, ResponseHandler response_handler,
1225  ContentReceiver content_receiver, Progress progress);
1226  Result Get(const std::string &path, const Headers &headers,
1227  ResponseHandler response_handler, ContentReceiver content_receiver,
1228  Progress progress);
1229 
1230  Result Get(const std::string &path, const Params &params,
1231  const Headers &headers, Progress progress = nullptr);
1232  Result Get(const std::string &path, const Params &params,
1233  const Headers &headers, ContentReceiver content_receiver,
1234  Progress progress = nullptr);
1235  Result Get(const std::string &path, const Params &params,
1236  const Headers &headers, ResponseHandler response_handler,
1237  ContentReceiver content_receiver, Progress progress = nullptr);
1238 
1239  Result Head(const std::string &path);
1240  Result Head(const std::string &path, const Headers &headers);
1241 
1242  Result Post(const std::string &path);
1243  Result Post(const std::string &path, const Headers &headers);
1244  Result Post(const std::string &path, const char *body, size_t content_length,
1245  const std::string &content_type);
1246  Result Post(const std::string &path, const Headers &headers, const char *body,
1247  size_t content_length, const std::string &content_type);
1248  Result Post(const std::string &path, const Headers &headers, const char *body,
1249  size_t content_length, const std::string &content_type,
1250  Progress progress);
1251  Result Post(const std::string &path, const std::string &body,
1252  const std::string &content_type);
1253  Result Post(const std::string &path, const std::string &body,
1254  const std::string &content_type, Progress progress);
1255  Result Post(const std::string &path, const Headers &headers,
1256  const std::string &body, const std::string &content_type);
1257  Result Post(const std::string &path, const Headers &headers,
1258  const std::string &body, const std::string &content_type,
1259  Progress progress);
1260  Result Post(const std::string &path, size_t content_length,
1261  ContentProvider content_provider,
1262  const std::string &content_type);
1263  Result Post(const std::string &path,
1264  ContentProviderWithoutLength content_provider,
1265  const std::string &content_type);
1266  Result Post(const std::string &path, const Headers &headers,
1267  size_t content_length, ContentProvider content_provider,
1268  const std::string &content_type);
1269  Result Post(const std::string &path, const Headers &headers,
1270  ContentProviderWithoutLength content_provider,
1271  const std::string &content_type);
1272  Result Post(const std::string &path, const Params &params);
1273  Result Post(const std::string &path, const Headers &headers,
1274  const Params &params);
1275  Result Post(const std::string &path, const Headers &headers,
1276  const Params &params, Progress progress);
1277  Result Post(const std::string &path, const MultipartFormDataItems &items);
1278  Result Post(const std::string &path, const Headers &headers,
1279  const MultipartFormDataItems &items);
1280  Result Post(const std::string &path, const Headers &headers,
1281  const MultipartFormDataItems &items, const std::string &boundary);
1282  Result Post(const std::string &path, const Headers &headers,
1283  const MultipartFormDataItems &items,
1284  const MultipartFormDataProviderItems &provider_items);
1285 
1286  Result Put(const std::string &path);
1287  Result Put(const std::string &path, const char *body, size_t content_length,
1288  const std::string &content_type);
1289  Result Put(const std::string &path, const Headers &headers, const char *body,
1290  size_t content_length, const std::string &content_type);
1291  Result Put(const std::string &path, const Headers &headers, const char *body,
1292  size_t content_length, const std::string &content_type,
1293  Progress progress);
1294  Result Put(const std::string &path, const std::string &body,
1295  const std::string &content_type);
1296  Result Put(const std::string &path, const std::string &body,
1297  const std::string &content_type, Progress progress);
1298  Result Put(const std::string &path, const Headers &headers,
1299  const std::string &body, const std::string &content_type);
1300  Result Put(const std::string &path, const Headers &headers,
1301  const std::string &body, const std::string &content_type,
1302  Progress progress);
1303  Result Put(const std::string &path, size_t content_length,
1304  ContentProvider content_provider, const std::string &content_type);
1305  Result Put(const std::string &path,
1306  ContentProviderWithoutLength content_provider,
1307  const std::string &content_type);
1308  Result Put(const std::string &path, const Headers &headers,
1309  size_t content_length, ContentProvider content_provider,
1310  const std::string &content_type);
1311  Result Put(const std::string &path, const Headers &headers,
1312  ContentProviderWithoutLength content_provider,
1313  const std::string &content_type);
1314  Result Put(const std::string &path, const Params &params);
1315  Result Put(const std::string &path, const Headers &headers,
1316  const Params &params);
1317  Result Put(const std::string &path, const Headers &headers,
1318  const Params &params, Progress progress);
1319  Result Put(const std::string &path, const MultipartFormDataItems &items);
1320  Result Put(const std::string &path, const Headers &headers,
1321  const MultipartFormDataItems &items);
1322  Result Put(const std::string &path, const Headers &headers,
1323  const MultipartFormDataItems &items, const std::string &boundary);
1324  Result Put(const std::string &path, const Headers &headers,
1325  const MultipartFormDataItems &items,
1326  const MultipartFormDataProviderItems &provider_items);
1327 
1328  Result Patch(const std::string &path);
1329  Result Patch(const std::string &path, const char *body, size_t content_length,
1330  const std::string &content_type);
1331  Result Patch(const std::string &path, const char *body, size_t content_length,
1332  const std::string &content_type, Progress progress);
1333  Result Patch(const std::string &path, const Headers &headers,
1334  const char *body, size_t content_length,
1335  const std::string &content_type);
1336  Result Patch(const std::string &path, const Headers &headers,
1337  const char *body, size_t content_length,
1338  const std::string &content_type, Progress progress);
1339  Result Patch(const std::string &path, const std::string &body,
1340  const std::string &content_type);
1341  Result Patch(const std::string &path, const std::string &body,
1342  const std::string &content_type, Progress progress);
1343  Result Patch(const std::string &path, const Headers &headers,
1344  const std::string &body, const std::string &content_type);
1345  Result Patch(const std::string &path, const Headers &headers,
1346  const std::string &body, const std::string &content_type,
1347  Progress progress);
1348  Result Patch(const std::string &path, size_t content_length,
1349  ContentProvider content_provider,
1350  const std::string &content_type);
1351  Result Patch(const std::string &path,
1352  ContentProviderWithoutLength content_provider,
1353  const std::string &content_type);
1354  Result Patch(const std::string &path, const Headers &headers,
1355  size_t content_length, ContentProvider content_provider,
1356  const std::string &content_type);
1357  Result Patch(const std::string &path, const Headers &headers,
1358  ContentProviderWithoutLength content_provider,
1359  const std::string &content_type);
1360 
1361  Result Delete(const std::string &path);
1362  Result Delete(const std::string &path, const Headers &headers);
1363  Result Delete(const std::string &path, const char *body,
1364  size_t content_length, const std::string &content_type);
1365  Result Delete(const std::string &path, const char *body,
1366  size_t content_length, const std::string &content_type,
1367  Progress progress);
1368  Result Delete(const std::string &path, const Headers &headers,
1369  const char *body, size_t content_length,
1370  const std::string &content_type);
1371  Result Delete(const std::string &path, const Headers &headers,
1372  const char *body, size_t content_length,
1373  const std::string &content_type, Progress progress);
1374  Result Delete(const std::string &path, const std::string &body,
1375  const std::string &content_type);
1376  Result Delete(const std::string &path, const std::string &body,
1377  const std::string &content_type, Progress progress);
1378  Result Delete(const std::string &path, const Headers &headers,
1379  const std::string &body, const std::string &content_type);
1380  Result Delete(const std::string &path, const Headers &headers,
1381  const std::string &body, const std::string &content_type,
1382  Progress progress);
1383 
1384  Result Options(const std::string &path);
1385  Result Options(const std::string &path, const Headers &headers);
1386 
1387  bool send(Request &req, Response &res, Error &error);
1388  Result send(const Request &req);
1389 
1390  void stop();
1391 
1392  std::string host() const;
1393  int port() const;
1394 
1395  size_t is_socket_open() const;
1396  socket_t socket() const;
1397 
1398  void set_hostname_addr_map(std::map<std::string, std::string> addr_map);
1399 
1400  void set_default_headers(Headers headers);
1401 
1402  void
1403  set_header_writer(std::function<ssize_t(Stream &, Headers &)> const &writer);
1404 
1405  void set_address_family(int family);
1406  void set_tcp_nodelay(bool on);
1407  void set_ipv6_v6only(bool on);
1408  void set_socket_options(SocketOptions socket_options);
1409 
1410  void set_connection_timeout(time_t sec, time_t usec = 0);
1411  template <class Rep, class Period>
1412  void
1413  set_connection_timeout(const std::chrono::duration<Rep, Period> &duration);
1414 
1415  void set_read_timeout(time_t sec, time_t usec = 0);
1416  template <class Rep, class Period>
1417  void set_read_timeout(const std::chrono::duration<Rep, Period> &duration);
1418 
1419  void set_write_timeout(time_t sec, time_t usec = 0);
1420  template <class Rep, class Period>
1421  void set_write_timeout(const std::chrono::duration<Rep, Period> &duration);
1422 
1423  void set_basic_auth(const std::string &username, const std::string &password);
1424  void set_bearer_token_auth(const std::string &token);
1425 #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
1426  void set_digest_auth(const std::string &username,
1427  const std::string &password);
1428 #endif
1429 
1430  void set_keep_alive(bool on);
1431  void set_follow_location(bool on);
1432 
1433  void set_url_encode(bool on);
1434 
1435  void set_compress(bool on);
1436 
1437  void set_decompress(bool on);
1438 
1439  void set_interface(const std::string &intf);
1440 
1441  void set_proxy(const std::string &host, int port);
1442  void set_proxy_basic_auth(const std::string &username,
1443  const std::string &password);
1444  void set_proxy_bearer_token_auth(const std::string &token);
1445 #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
1446  void set_proxy_digest_auth(const std::string &username,
1447  const std::string &password);
1448 #endif
1449 
1450 #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
1451  void set_ca_cert_path(const std::string &ca_cert_file_path,
1452  const std::string &ca_cert_dir_path = std::string());
1453  void set_ca_cert_store(X509_STORE *ca_cert_store);
1454  X509_STORE *create_ca_cert_store(const char *ca_cert, std::size_t size) const;
1455 #endif
1456 
1457 #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
1458  void enable_server_certificate_verification(bool enabled);
1459  void enable_server_hostname_verification(bool enabled);
1460  void set_server_certificate_verifier(std::function<bool(SSL *ssl)> verifier);
1461 #endif
1462 
1463  void set_logger(Logger logger);
1464 
1465 protected:
1466  struct Socket {
1468 #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
1469  SSL *ssl = nullptr;
1470 #endif
1471 
1472  bool is_open() const { return sock != INVALID_SOCKET; }
1473  };
1474 
1475  virtual bool create_and_connect_socket(Socket &socket, Error &error);
1476 
1477  // All of:
1478  // shutdown_ssl
1479  // shutdown_socket
1480  // close_socket
1481  // should ONLY be called when socket_mutex_ is locked.
1482  // Also, shutdown_ssl and close_socket should also NOT be called concurrently
1483  // with a DIFFERENT thread sending requests using that socket.
1484  virtual void shutdown_ssl(Socket &socket, bool shutdown_gracefully);
1485  void shutdown_socket(Socket &socket) const;
1486  void close_socket(Socket &socket);
1487 
1488  bool process_request(Stream &strm, Request &req, Response &res,
1489  bool close_connection, Error &error);
1490 
1491  bool write_content_with_provider(Stream &strm, const Request &req,
1492  Error &error) const;
1493 
1494  void copy_settings(const ClientImpl &rhs);
1495 
1496  // Socket endpoint information
1497  const std::string host_;
1498  const int port_;
1499  const std::string host_and_port_;
1500 
1501  // Current open socket
1503  mutable std::mutex socket_mutex_;
1504  std::recursive_mutex request_mutex_;
1505 
1506  // These are all protected under socket_mutex
1508  std::thread::id socket_requests_are_from_thread_ = std::thread::id();
1510 
1511  // Hostname-IP map
1512  std::map<std::string, std::string> addr_map_;
1513 
1514  // Default headers
1516 
1517  // Header writer
1518  std::function<ssize_t(Stream &, Headers &)> header_writer_ =
1520 
1521  // Settings
1522  std::string client_cert_path_;
1523  std::string client_key_path_;
1524 
1531 
1535 #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
1536  std::string digest_auth_username_;
1537  std::string digest_auth_password_;
1538 #endif
1539 
1540  bool keep_alive_ = false;
1541  bool follow_location_ = false;
1542 
1543  bool url_encode_ = true;
1544 
1545  int address_family_ = AF_UNSPEC;
1549 
1550  bool compress_ = false;
1551  bool decompress_ = true;
1552 
1553  std::string interface_;
1554 
1555  std::string proxy_host_;
1556  int proxy_port_ = -1;
1557 
1561 #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
1562  std::string proxy_digest_auth_username_;
1563  std::string proxy_digest_auth_password_;
1564 #endif
1565 
1566 #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
1567  std::string ca_cert_file_path_;
1568  std::string ca_cert_dir_path_;
1569 
1570  X509_STORE *ca_cert_store_ = nullptr;
1571 #endif
1572 
1573 #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
1574  bool server_certificate_verification_ = true;
1575  bool server_hostname_verification_ = true;
1576  std::function<bool(SSL *ssl)> server_certificate_verifier_;
1577 #endif
1578 
1580 
1581 private:
1582  bool send_(Request &req, Response &res, Error &error);
1583  Result send_(Request &&req);
1584 
1585 #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
1586  bool is_ssl_peer_could_be_closed(SSL *ssl) const;
1587 #endif
1588  socket_t create_client_socket(Error &error) const;
1589  bool read_response_line(Stream &strm, const Request &req,
1590  Response &res) const;
1591  bool write_request(Stream &strm, Request &req, bool close_connection,
1592  Error &error);
1593  bool redirect(Request &req, Response &res, Error &error);
1594  bool handle_request(Stream &strm, Request &req, Response &res,
1595  bool close_connection, Error &error);
1596  std::unique_ptr<Response> send_with_content_provider(
1597  Request &req, const char *body, size_t content_length,
1598  ContentProvider content_provider,
1599  ContentProviderWithoutLength content_provider_without_length,
1600  const std::string &content_type, Error &error);
1601  Result send_with_content_provider(
1602  const std::string &method, const std::string &path,
1603  const Headers &headers, const char *body, size_t content_length,
1604  ContentProvider content_provider,
1605  ContentProviderWithoutLength content_provider_without_length,
1606  const std::string &content_type, Progress progress);
1607  ContentProviderWithoutLength get_multipart_content_provider(
1608  const std::string &boundary, const MultipartFormDataItems &items,
1609  const MultipartFormDataProviderItems &provider_items) const;
1610 
1611  std::string adjust_host_string(const std::string &host) const;
1612 
1613  virtual bool process_socket(const Socket &socket,
1614  std::function<bool(Stream &strm)> callback);
1615  virtual bool is_ssl() const;
1616 };
1617 
1618 class Client {
1619 public:
1620  // Universal interface
1621  explicit Client(const std::string &scheme_host_port);
1622 
1623  explicit Client(const std::string &scheme_host_port,
1624  const std::string &client_cert_path,
1625  const std::string &client_key_path);
1626 
1627  // HTTP only interface
1628  explicit Client(const std::string &host, int port);
1629 
1630  explicit Client(const std::string &host, int port,
1631  const std::string &client_cert_path,
1632  const std::string &client_key_path);
1633 
1634  Client(Client &&) = default;
1635  Client &operator=(Client &&) = default;
1636 
1637  ~Client();
1638 
1639  bool is_valid() const;
1640 
1641  Result Get(const std::string &path);
1642  Result Get(const std::string &path, const Headers &headers);
1643  Result Get(const std::string &path, Progress progress);
1644  Result Get(const std::string &path, const Headers &headers,
1645  Progress progress);
1646  Result Get(const std::string &path, ContentReceiver content_receiver);
1647  Result Get(const std::string &path, const Headers &headers,
1648  ContentReceiver content_receiver);
1649  Result Get(const std::string &path, ContentReceiver content_receiver,
1650  Progress progress);
1651  Result Get(const std::string &path, const Headers &headers,
1652  ContentReceiver content_receiver, Progress progress);
1653  Result Get(const std::string &path, ResponseHandler response_handler,
1654  ContentReceiver content_receiver);
1655  Result Get(const std::string &path, const Headers &headers,
1656  ResponseHandler response_handler,
1657  ContentReceiver content_receiver);
1658  Result Get(const std::string &path, const Headers &headers,
1659  ResponseHandler response_handler, ContentReceiver content_receiver,
1660  Progress progress);
1661  Result Get(const std::string &path, ResponseHandler response_handler,
1662  ContentReceiver content_receiver, Progress progress);
1663 
1664  Result Get(const std::string &path, const Params &params,
1665  const Headers &headers, Progress progress = nullptr);
1666  Result Get(const std::string &path, const Params &params,
1667  const Headers &headers, ContentReceiver content_receiver,
1668  Progress progress = nullptr);
1669  Result Get(const std::string &path, const Params &params,
1670  const Headers &headers, ResponseHandler response_handler,
1671  ContentReceiver content_receiver, Progress progress = nullptr);
1672 
1673  Result Head(const std::string &path);
1674  Result Head(const std::string &path, const Headers &headers);
1675 
1676  Result Post(const std::string &path);
1677  Result Post(const std::string &path, const Headers &headers);
1678  Result Post(const std::string &path, const char *body, size_t content_length,
1679  const std::string &content_type);
1680  Result Post(const std::string &path, const Headers &headers, const char *body,
1681  size_t content_length, const std::string &content_type);
1682  Result Post(const std::string &path, const Headers &headers, const char *body,
1683  size_t content_length, const std::string &content_type,
1684  Progress progress);
1685  Result Post(const std::string &path, const std::string &body,
1686  const std::string &content_type);
1687  Result Post(const std::string &path, const std::string &body,
1688  const std::string &content_type, Progress progress);
1689  Result Post(const std::string &path, const Headers &headers,
1690  const std::string &body, const std::string &content_type);
1691  Result Post(const std::string &path, const Headers &headers,
1692  const std::string &body, const std::string &content_type,
1693  Progress progress);
1694  Result Post(const std::string &path, size_t content_length,
1695  ContentProvider content_provider,
1696  const std::string &content_type);
1697  Result Post(const std::string &path,
1698  ContentProviderWithoutLength content_provider,
1699  const std::string &content_type);
1700  Result Post(const std::string &path, const Headers &headers,
1701  size_t content_length, ContentProvider content_provider,
1702  const std::string &content_type);
1703  Result Post(const std::string &path, const Headers &headers,
1704  ContentProviderWithoutLength content_provider,
1705  const std::string &content_type);
1706  Result Post(const std::string &path, const Params &params);
1707  Result Post(const std::string &path, const Headers &headers,
1708  const Params &params);
1709  Result Post(const std::string &path, const Headers &headers,
1710  const Params &params, Progress progress);
1711  Result Post(const std::string &path, const MultipartFormDataItems &items);
1712  Result Post(const std::string &path, const Headers &headers,
1713  const MultipartFormDataItems &items);
1714  Result Post(const std::string &path, const Headers &headers,
1715  const MultipartFormDataItems &items, const std::string &boundary);
1716  Result Post(const std::string &path, const Headers &headers,
1717  const MultipartFormDataItems &items,
1718  const MultipartFormDataProviderItems &provider_items);
1719 
1720  Result Put(const std::string &path);
1721  Result Put(const std::string &path, const char *body, size_t content_length,
1722  const std::string &content_type);
1723  Result Put(const std::string &path, const Headers &headers, const char *body,
1724  size_t content_length, const std::string &content_type);
1725  Result Put(const std::string &path, const Headers &headers, const char *body,
1726  size_t content_length, const std::string &content_type,
1727  Progress progress);
1728  Result Put(const std::string &path, const std::string &body,
1729  const std::string &content_type);
1730  Result Put(const std::string &path, const std::string &body,
1731  const std::string &content_type, Progress progress);
1732  Result Put(const std::string &path, const Headers &headers,
1733  const std::string &body, const std::string &content_type);
1734  Result Put(const std::string &path, const Headers &headers,
1735  const std::string &body, const std::string &content_type,
1736  Progress progress);
1737  Result Put(const std::string &path, size_t content_length,
1738  ContentProvider content_provider, const std::string &content_type);
1739  Result Put(const std::string &path,
1740  ContentProviderWithoutLength content_provider,
1741  const std::string &content_type);
1742  Result Put(const std::string &path, const Headers &headers,
1743  size_t content_length, ContentProvider content_provider,
1744  const std::string &content_type);
1745  Result Put(const std::string &path, const Headers &headers,
1746  ContentProviderWithoutLength content_provider,
1747  const std::string &content_type);
1748  Result Put(const std::string &path, const Params &params);
1749  Result Put(const std::string &path, const Headers &headers,
1750  const Params &params);
1751  Result Put(const std::string &path, const Headers &headers,
1752  const Params &params, Progress progress);
1753  Result Put(const std::string &path, const MultipartFormDataItems &items);
1754  Result Put(const std::string &path, const Headers &headers,
1755  const MultipartFormDataItems &items);
1756  Result Put(const std::string &path, const Headers &headers,
1757  const MultipartFormDataItems &items, const std::string &boundary);
1758  Result Put(const std::string &path, const Headers &headers,
1759  const MultipartFormDataItems &items,
1760  const MultipartFormDataProviderItems &provider_items);
1761 
1762  Result Patch(const std::string &path);
1763  Result Patch(const std::string &path, const char *body, size_t content_length,
1764  const std::string &content_type);
1765  Result Patch(const std::string &path, const char *body, size_t content_length,
1766  const std::string &content_type, Progress progress);
1767  Result Patch(const std::string &path, const Headers &headers,
1768  const char *body, size_t content_length,
1769  const std::string &content_type);
1770  Result Patch(const std::string &path, const Headers &headers,
1771  const char *body, size_t content_length,
1772  const std::string &content_type, Progress progress);
1773  Result Patch(const std::string &path, const std::string &body,
1774  const std::string &content_type);
1775  Result Patch(const std::string &path, const std::string &body,
1776  const std::string &content_type, Progress progress);
1777  Result Patch(const std::string &path, const Headers &headers,
1778  const std::string &body, const std::string &content_type);
1779  Result Patch(const std::string &path, const Headers &headers,
1780  const std::string &body, const std::string &content_type,
1781  Progress progress);
1782  Result Patch(const std::string &path, size_t content_length,
1783  ContentProvider content_provider,
1784  const std::string &content_type);
1785  Result Patch(const std::string &path,
1786  ContentProviderWithoutLength content_provider,
1787  const std::string &content_type);
1788  Result Patch(const std::string &path, const Headers &headers,
1789  size_t content_length, ContentProvider content_provider,
1790  const std::string &content_type);
1791  Result Patch(const std::string &path, const Headers &headers,
1792  ContentProviderWithoutLength content_provider,
1793  const std::string &content_type);
1794 
1795  Result Delete(const std::string &path);
1796  Result Delete(const std::string &path, const Headers &headers);
1797  Result Delete(const std::string &path, const char *body,
1798  size_t content_length, const std::string &content_type);
1799  Result Delete(const std::string &path, const char *body,
1800  size_t content_length, const std::string &content_type,
1801  Progress progress);
1802  Result Delete(const std::string &path, const Headers &headers,
1803  const char *body, size_t content_length,
1804  const std::string &content_type);
1805  Result Delete(const std::string &path, const Headers &headers,
1806  const char *body, size_t content_length,
1807  const std::string &content_type, Progress progress);
1808  Result Delete(const std::string &path, const std::string &body,
1809  const std::string &content_type);
1810  Result Delete(const std::string &path, const std::string &body,
1811  const std::string &content_type, Progress progress);
1812  Result Delete(const std::string &path, const Headers &headers,
1813  const std::string &body, const std::string &content_type);
1814  Result Delete(const std::string &path, const Headers &headers,
1815  const std::string &body, const std::string &content_type,
1816  Progress progress);
1817 
1818  Result Options(const std::string &path);
1819  Result Options(const std::string &path, const Headers &headers);
1820 
1821  bool send(Request &req, Response &res, Error &error);
1822  Result send(const Request &req);
1823 
1824  void stop();
1825 
1826  std::string host() const;
1827  int port() const;
1828 
1829  size_t is_socket_open() const;
1830  socket_t socket() const;
1831 
1832  void set_hostname_addr_map(std::map<std::string, std::string> addr_map);
1833 
1834  void set_default_headers(Headers headers);
1835 
1836  void
1837  set_header_writer(std::function<ssize_t(Stream &, Headers &)> const &writer);
1838 
1839  void set_address_family(int family);
1840  void set_tcp_nodelay(bool on);
1841  void set_socket_options(SocketOptions socket_options);
1842 
1843  void set_connection_timeout(time_t sec, time_t usec = 0);
1844  template <class Rep, class Period>
1845  void
1846  set_connection_timeout(const std::chrono::duration<Rep, Period> &duration);
1847 
1848  void set_read_timeout(time_t sec, time_t usec = 0);
1849  template <class Rep, class Period>
1850  void set_read_timeout(const std::chrono::duration<Rep, Period> &duration);
1851 
1852  void set_write_timeout(time_t sec, time_t usec = 0);
1853  template <class Rep, class Period>
1854  void set_write_timeout(const std::chrono::duration<Rep, Period> &duration);
1855 
1856  void set_basic_auth(const std::string &username, const std::string &password);
1857  void set_bearer_token_auth(const std::string &token);
1858 #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
1859  void set_digest_auth(const std::string &username,
1860  const std::string &password);
1861 #endif
1862 
1863  void set_keep_alive(bool on);
1864  void set_follow_location(bool on);
1865 
1866  void set_url_encode(bool on);
1867 
1868  void set_compress(bool on);
1869 
1870  void set_decompress(bool on);
1871 
1872  void set_interface(const std::string &intf);
1873 
1874  void set_proxy(const std::string &host, int port);
1875  void set_proxy_basic_auth(const std::string &username,
1876  const std::string &password);
1877  void set_proxy_bearer_token_auth(const std::string &token);
1878 #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
1879  void set_proxy_digest_auth(const std::string &username,
1880  const std::string &password);
1881 #endif
1882 
1883 #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
1884  void enable_server_certificate_verification(bool enabled);
1885  void enable_server_hostname_verification(bool enabled);
1886  void set_server_certificate_verifier(std::function<bool(SSL *ssl)> verifier);
1887 #endif
1888 
1889  void set_logger(Logger logger);
1890 
1891  // SSL
1892 #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
1893  void set_ca_cert_path(const std::string &ca_cert_file_path,
1894  const std::string &ca_cert_dir_path = std::string());
1895 
1896  void set_ca_cert_store(X509_STORE *ca_cert_store);
1897  void load_ca_cert_store(const char *ca_cert, std::size_t size);
1898 
1899  long get_openssl_verify_result() const;
1900 
1901  SSL_CTX *ssl_context() const;
1902 #endif
1903 
1904 private:
1905  std::unique_ptr<ClientImpl> cli_;
1906 
1907 #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
1908  bool is_ssl_ = false;
1909 #endif
1910 };
1911 
1912 #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
1913 class SSLServer : public Server {
1914 public:
1915  SSLServer(const char *cert_path, const char *private_key_path,
1916  const char *client_ca_cert_file_path = nullptr,
1917  const char *client_ca_cert_dir_path = nullptr,
1918  const char *private_key_password = nullptr);
1919 
1920  SSLServer(X509 *cert, EVP_PKEY *private_key,
1921  X509_STORE *client_ca_cert_store = nullptr);
1922 
1923  SSLServer(
1924  const std::function<bool(SSL_CTX &ssl_ctx)> &setup_ssl_ctx_callback);
1925 
1926  ~SSLServer() override;
1927 
1928  bool is_valid() const override;
1929 
1930  SSL_CTX *ssl_context() const;
1931 
1932  void update_certs(X509 *cert, EVP_PKEY *private_key,
1933  X509_STORE *client_ca_cert_store = nullptr);
1934 
1935 private:
1936  bool process_and_close_socket(socket_t sock) override;
1937 
1938  SSL_CTX *ctx_;
1939  std::mutex ctx_mutex_;
1940 };
1941 
1942 class SSLClient final : public ClientImpl {
1943 public:
1944  explicit SSLClient(const std::string &host);
1945 
1946  explicit SSLClient(const std::string &host, int port);
1947 
1948  explicit SSLClient(const std::string &host, int port,
1949  const std::string &client_cert_path,
1950  const std::string &client_key_path,
1951  const std::string &private_key_password = std::string());
1952 
1953  explicit SSLClient(const std::string &host, int port, X509 *client_cert,
1954  EVP_PKEY *client_key,
1955  const std::string &private_key_password = std::string());
1956 
1957  ~SSLClient() override;
1958 
1959  bool is_valid() const override;
1960 
1961  void set_ca_cert_store(X509_STORE *ca_cert_store);
1962  void load_ca_cert_store(const char *ca_cert, std::size_t size);
1963 
1964  long get_openssl_verify_result() const;
1965 
1966  SSL_CTX *ssl_context() const;
1967 
1968 private:
1969  bool create_and_connect_socket(Socket &socket, Error &error) override;
1970  void shutdown_ssl(Socket &socket, bool shutdown_gracefully) override;
1971  void shutdown_ssl_impl(Socket &socket, bool shutdown_gracefully);
1972 
1973  bool process_socket(const Socket &socket,
1974  std::function<bool(Stream &strm)> callback) override;
1975  bool is_ssl() const override;
1976 
1977  bool connect_with_proxy(Socket &sock, Response &res, bool &success,
1978  Error &error);
1979  bool initialize_ssl(Socket &socket, Error &error);
1980 
1981  bool load_certs();
1982 
1983  bool verify_host(X509 *server_cert) const;
1984  bool verify_host_with_subject_alt_name(X509 *server_cert) const;
1985  bool verify_host_with_common_name(X509 *server_cert) const;
1986  bool check_host_name(const char *pattern, size_t pattern_len) const;
1987 
1988  SSL_CTX *ctx_;
1989  std::mutex ctx_mutex_;
1990  std::once_flag initialize_cert_;
1991 
1992  std::vector<std::string> host_components_;
1993 
1994  long verify_result_ = 0;
1995 
1996  friend class ClientImpl;
1997 };
1998 #endif
1999 
2000 /*
2001  * Implementation of template methods.
2002  */
2003 
2004 namespace detail {
2005 
2006 template <typename T, typename U>
2007 inline void duration_to_sec_and_usec(const T &duration, U callback) {
2008  auto sec = std::chrono::duration_cast<std::chrono::seconds>(duration).count();
2009  auto usec = std::chrono::duration_cast<std::chrono::microseconds>(
2010  duration - std::chrono::seconds(sec))
2011  .count();
2012  callback(static_cast<time_t>(sec), static_cast<time_t>(usec));
2013 }
2014 
2015 inline uint64_t get_header_value_u64(const Headers &headers,
2016  const std::string &key, uint64_t def,
2017  size_t id) {
2018  auto rng = headers.equal_range(key);
2019  auto it = rng.first;
2020  std::advance(it, static_cast<ssize_t>(id));
2021  if (it != rng.second) {
2022  return std::strtoull(it->second.data(), nullptr, 10);
2023  }
2024  return def;
2025 }
2026 
2027 } // namespace detail
2028 
2029 inline uint64_t Request::get_header_value_u64(const std::string &key,
2030  uint64_t def, size_t id) const {
2031  return detail::get_header_value_u64(headers, key, def, id);
2032 }
2033 
2034 inline uint64_t Response::get_header_value_u64(const std::string &key,
2035  uint64_t def, size_t id) const {
2036  return detail::get_header_value_u64(headers, key, def, id);
2037 }
2038 
2040  int opt = 1;
2041 #ifdef _WIN32
2042  setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
2043  reinterpret_cast<const char *>(&opt), sizeof(opt));
2044  setsockopt(sock, SOL_SOCKET, SO_EXCLUSIVEADDRUSE,
2045  reinterpret_cast<const char *>(&opt), sizeof(opt));
2046 #else
2047 #ifdef SO_REUSEPORT
2048  setsockopt(sock, SOL_SOCKET, SO_REUSEPORT,
2049  reinterpret_cast<const void *>(&opt), sizeof(opt));
2050 #else
2051  setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
2052  reinterpret_cast<const void *>(&opt), sizeof(opt));
2053 #endif
2054 #endif
2055 }
2056 
2057 inline const char *status_message(int status) {
2058  switch (status) {
2059  case StatusCode::Continue_100: return "Continue";
2060  case StatusCode::SwitchingProtocol_101: return "Switching Protocol";
2061  case StatusCode::Processing_102: return "Processing";
2062  case StatusCode::EarlyHints_103: return "Early Hints";
2063  case StatusCode::OK_200: return "OK";
2064  case StatusCode::Created_201: return "Created";
2065  case StatusCode::Accepted_202: return "Accepted";
2067  return "Non-Authoritative Information";
2068  case StatusCode::NoContent_204: return "No Content";
2069  case StatusCode::ResetContent_205: return "Reset Content";
2070  case StatusCode::PartialContent_206: return "Partial Content";
2071  case StatusCode::MultiStatus_207: return "Multi-Status";
2072  case StatusCode::AlreadyReported_208: return "Already Reported";
2073  case StatusCode::IMUsed_226: return "IM Used";
2074  case StatusCode::MultipleChoices_300: return "Multiple Choices";
2075  case StatusCode::MovedPermanently_301: return "Moved Permanently";
2076  case StatusCode::Found_302: return "Found";
2077  case StatusCode::SeeOther_303: return "See Other";
2078  case StatusCode::NotModified_304: return "Not Modified";
2079  case StatusCode::UseProxy_305: return "Use Proxy";
2080  case StatusCode::unused_306: return "unused";
2081  case StatusCode::TemporaryRedirect_307: return "Temporary Redirect";
2082  case StatusCode::PermanentRedirect_308: return "Permanent Redirect";
2083  case StatusCode::BadRequest_400: return "Bad Request";
2084  case StatusCode::Unauthorized_401: return "Unauthorized";
2085  case StatusCode::PaymentRequired_402: return "Payment Required";
2086  case StatusCode::Forbidden_403: return "Forbidden";
2087  case StatusCode::NotFound_404: return "Not Found";
2088  case StatusCode::MethodNotAllowed_405: return "Method Not Allowed";
2089  case StatusCode::NotAcceptable_406: return "Not Acceptable";
2091  return "Proxy Authentication Required";
2092  case StatusCode::RequestTimeout_408: return "Request Timeout";
2093  case StatusCode::Conflict_409: return "Conflict";
2094  case StatusCode::Gone_410: return "Gone";
2095  case StatusCode::LengthRequired_411: return "Length Required";
2096  case StatusCode::PreconditionFailed_412: return "Precondition Failed";
2097  case StatusCode::PayloadTooLarge_413: return "Payload Too Large";
2098  case StatusCode::UriTooLong_414: return "URI Too Long";
2099  case StatusCode::UnsupportedMediaType_415: return "Unsupported Media Type";
2100  case StatusCode::RangeNotSatisfiable_416: return "Range Not Satisfiable";
2101  case StatusCode::ExpectationFailed_417: return "Expectation Failed";
2102  case StatusCode::ImATeapot_418: return "I'm a teapot";
2103  case StatusCode::MisdirectedRequest_421: return "Misdirected Request";
2104  case StatusCode::UnprocessableContent_422: return "Unprocessable Content";
2105  case StatusCode::Locked_423: return "Locked";
2106  case StatusCode::FailedDependency_424: return "Failed Dependency";
2107  case StatusCode::TooEarly_425: return "Too Early";
2108  case StatusCode::UpgradeRequired_426: return "Upgrade Required";
2109  case StatusCode::PreconditionRequired_428: return "Precondition Required";
2110  case StatusCode::TooManyRequests_429: return "Too Many Requests";
2112  return "Request Header Fields Too Large";
2114  return "Unavailable For Legal Reasons";
2115  case StatusCode::NotImplemented_501: return "Not Implemented";
2116  case StatusCode::BadGateway_502: return "Bad Gateway";
2117  case StatusCode::ServiceUnavailable_503: return "Service Unavailable";
2118  case StatusCode::GatewayTimeout_504: return "Gateway Timeout";
2120  return "HTTP Version Not Supported";
2121  case StatusCode::VariantAlsoNegotiates_506: return "Variant Also Negotiates";
2122  case StatusCode::InsufficientStorage_507: return "Insufficient Storage";
2123  case StatusCode::LoopDetected_508: return "Loop Detected";
2124  case StatusCode::NotExtended_510: return "Not Extended";
2126  return "Network Authentication Required";
2127 
2128  default:
2129  case StatusCode::InternalServerError_500: return "Internal Server Error";
2130  }
2131 }
2132 
2133 inline std::string get_bearer_token_auth(const Request &req) {
2134  if (req.has_header("Authorization")) {
2135  static std::string BearerHeaderPrefix = "Bearer ";
2136  return req.get_header_value("Authorization")
2137  .substr(BearerHeaderPrefix.length());
2138  }
2139  return "";
2140 }
2141 
2142 template <class Rep, class Period>
2143 inline Server &
2144 Server::set_read_timeout(const std::chrono::duration<Rep, Period> &duration) {
2146  duration, [&](time_t sec, time_t usec) { set_read_timeout(sec, usec); });
2147  return *this;
2148 }
2149 
2150 template <class Rep, class Period>
2151 inline Server &
2152 Server::set_write_timeout(const std::chrono::duration<Rep, Period> &duration) {
2154  duration, [&](time_t sec, time_t usec) { set_write_timeout(sec, usec); });
2155  return *this;
2156 }
2157 
2158 template <class Rep, class Period>
2159 inline Server &
2160 Server::set_idle_interval(const std::chrono::duration<Rep, Period> &duration) {
2162  duration, [&](time_t sec, time_t usec) { set_idle_interval(sec, usec); });
2163  return *this;
2164 }
2165 
2166 inline std::string to_string(const Error error) {
2167  switch (error) {
2168  case Error::Success: return "Success (no error)";
2169  case Error::Connection: return "Could not establish connection";
2170  case Error::BindIPAddress: return "Failed to bind IP address";
2171  case Error::Read: return "Failed to read connection";
2172  case Error::Write: return "Failed to write connection";
2173  case Error::ExceedRedirectCount: return "Maximum redirect count exceeded";
2174  case Error::Canceled: return "Connection handling canceled";
2175  case Error::SSLConnection: return "SSL connection failed";
2176  case Error::SSLLoadingCerts: return "SSL certificate loading failed";
2177  case Error::SSLServerVerification: return "SSL server verification failed";
2179  return "SSL server hostname verification failed";
2181  return "Unsupported HTTP multipart boundary characters";
2182  case Error::Compression: return "Compression failed";
2183  case Error::ConnectionTimeout: return "Connection timed out";
2184  case Error::ProxyConnection: return "Proxy connection failed";
2185  case Error::Unknown: return "Unknown";
2186  default: break;
2187  }
2188 
2189  return "Invalid";
2190 }
2191 
2192 inline std::ostream &operator<<(std::ostream &os, const Error &obj) {
2193  os << to_string(obj);
2194  os << " (" << static_cast<std::underlying_type<Error>::type>(obj) << ')';
2195  return os;
2196 }
2197 
2198 inline uint64_t Result::get_request_header_value_u64(const std::string &key,
2199  uint64_t def,
2200  size_t id) const {
2201  return detail::get_header_value_u64(request_headers_, key, def, id);
2202 }
2203 
2204 template <class Rep, class Period>
2206  const std::chrono::duration<Rep, Period> &duration) {
2207  detail::duration_to_sec_and_usec(duration, [&](time_t sec, time_t usec) {
2208  set_connection_timeout(sec, usec);
2209  });
2210 }
2211 
2212 template <class Rep, class Period>
2214  const std::chrono::duration<Rep, Period> &duration) {
2216  duration, [&](time_t sec, time_t usec) { set_read_timeout(sec, usec); });
2217 }
2218 
2219 template <class Rep, class Period>
2221  const std::chrono::duration<Rep, Period> &duration) {
2223  duration, [&](time_t sec, time_t usec) { set_write_timeout(sec, usec); });
2224 }
2225 
2226 template <class Rep, class Period>
2228  const std::chrono::duration<Rep, Period> &duration) {
2229  cli_->set_connection_timeout(duration);
2230 }
2231 
2232 template <class Rep, class Period>
2233 inline void
2234 Client::set_read_timeout(const std::chrono::duration<Rep, Period> &duration) {
2235  cli_->set_read_timeout(duration);
2236 }
2237 
2238 template <class Rep, class Period>
2239 inline void
2240 Client::set_write_timeout(const std::chrono::duration<Rep, Period> &duration) {
2241  cli_->set_write_timeout(duration);
2242 }
2243 
2244 /*
2245  * Forward declarations and types that will be part of the .h file if split into
2246  * .h + .cc.
2247  */
2248 
2249 std::string hosted_at(const std::string &hostname);
2250 
2251 void hosted_at(const std::string &hostname, std::vector<std::string> &addrs);
2252 
2253 std::string append_query_params(const std::string &path, const Params &params);
2254 
2255 std::pair<std::string, std::string> make_range_header(const Ranges &ranges);
2256 
2257 std::pair<std::string, std::string>
2258 make_basic_authentication_header(const std::string &username,
2259  const std::string &password,
2260  bool is_proxy = false);
2261 
2262 namespace detail {
2263 
2264 #if defined(_WIN32)
2265 inline std::wstring u8string_to_wstring(const char *s) {
2266  std::wstring ws;
2267  auto len = static_cast<int>(strlen(s));
2268  auto wlen = ::MultiByteToWideChar(CP_UTF8, 0, s, len, nullptr, 0);
2269  if (wlen > 0) {
2270  ws.resize(wlen);
2271  wlen = ::MultiByteToWideChar(
2272  CP_UTF8, 0, s, len,
2273  const_cast<LPWSTR>(reinterpret_cast<LPCWSTR>(ws.data())), wlen);
2274  if (wlen != static_cast<int>(ws.size())) { ws.clear(); }
2275  }
2276  return ws;
2277 }
2278 #endif
2279 
2280 struct FileStat {
2281  FileStat(const std::string &path);
2282  bool is_file() const;
2283  bool is_dir() const;
2284 
2285 private:
2286 #if defined(_WIN32)
2287  struct _stat st_;
2288 #else
2289  struct stat st_;
2290 #endif
2291  int ret_ = -1;
2292 };
2293 
2294 std::string encode_query_param(const std::string &value);
2295 
2296 std::string decode_url(const std::string &s, bool convert_plus_to_space);
2297 
2298 void read_file(const std::string &path, std::string &out);
2299 
2300 std::string trim_copy(const std::string &s);
2301 
2302 void divide(
2303  const char *data, std::size_t size, char d,
2304  std::function<void(const char *, std::size_t, const char *, std::size_t)>
2305  fn);
2306 
2307 void divide(
2308  const std::string &str, char d,
2309  std::function<void(const char *, std::size_t, const char *, std::size_t)>
2310  fn);
2311 
2312 void split(const char *b, const char *e, char d,
2313  std::function<void(const char *, const char *)> fn);
2314 
2315 void split(const char *b, const char *e, char d, size_t m,
2316  std::function<void(const char *, const char *)> fn);
2317 
2318 bool process_client_socket(socket_t sock, time_t read_timeout_sec,
2319  time_t read_timeout_usec, time_t write_timeout_sec,
2320  time_t write_timeout_usec,
2321  std::function<bool(Stream &)> callback);
2322 
2323 socket_t create_client_socket(const std::string &host, const std::string &ip,
2324  int port, int address_family, bool tcp_nodelay,
2325  bool ipv6_v6only, SocketOptions socket_options,
2326  time_t connection_timeout_sec,
2327  time_t connection_timeout_usec,
2328  time_t read_timeout_sec, time_t read_timeout_usec,
2329  time_t write_timeout_sec,
2330  time_t write_timeout_usec,
2331  const std::string &intf, Error &error);
2332 
2333 const char *get_header_value(const Headers &headers, const std::string &key,
2334  const char *def, size_t id);
2335 
2336 std::string params_to_query_str(const Params &params);
2337 
2338 void parse_query_text(const char *data, std::size_t size, Params &params);
2339 
2340 void parse_query_text(const std::string &s, Params &params);
2341 
2342 bool parse_multipart_boundary(const std::string &content_type,
2343  std::string &boundary);
2344 
2345 bool parse_range_header(const std::string &s, Ranges &ranges);
2346 
2347 int close_socket(socket_t sock);
2348 
2349 ssize_t send_socket(socket_t sock, const void *ptr, size_t size, int flags);
2350 
2351 ssize_t read_socket(socket_t sock, void *ptr, size_t size, int flags);
2352 
2353 enum class EncodingType { None = 0, Gzip, Brotli };
2354 
2355 EncodingType encoding_type(const Request &req, const Response &res);
2356 
2357 class BufferStream final : public Stream {
2358 public:
2359  BufferStream() = default;
2360  ~BufferStream() override = default;
2361 
2362  bool is_readable() const override;
2363  bool is_writable() const override;
2364  ssize_t read(char *ptr, size_t size) override;
2365  ssize_t write(const char *ptr, size_t size) override;
2366  void get_remote_ip_and_port(std::string &ip, int &port) const override;
2367  void get_local_ip_and_port(std::string &ip, int &port) const override;
2368  socket_t socket() const override;
2369 
2370  const std::string &get_buffer() const;
2371 
2372 private:
2373  std::string buffer;
2374  size_t position = 0;
2375 };
2376 
2377 class compressor {
2378 public:
2379  virtual ~compressor() = default;
2380 
2381  typedef std::function<bool(const char *data, size_t data_len)> Callback;
2382  virtual bool compress(const char *data, size_t data_length, bool last,
2383  Callback callback) = 0;
2384 };
2385 
2387 public:
2388  virtual ~decompressor() = default;
2389 
2390  virtual bool is_valid() const = 0;
2391 
2392  typedef std::function<bool(const char *data, size_t data_len)> Callback;
2393  virtual bool decompress(const char *data, size_t data_length,
2394  Callback callback) = 0;
2395 };
2396 
2397 class nocompressor final : public compressor {
2398 public:
2399  ~nocompressor() override = default;
2400 
2401  bool compress(const char *data, size_t data_length, bool /*last*/,
2402  Callback callback) override;
2403 };
2404 
2405 #ifdef CPPHTTPLIB_ZLIB_SUPPORT
2406 class gzip_compressor final : public compressor {
2407 public:
2408  gzip_compressor();
2409  ~gzip_compressor() override;
2410 
2411  bool compress(const char *data, size_t data_length, bool last,
2412  Callback callback) override;
2413 
2414 private:
2415  bool is_valid_ = false;
2416  z_stream strm_;
2417 };
2418 
2419 class gzip_decompressor final : public decompressor {
2420 public:
2421  gzip_decompressor();
2422  ~gzip_decompressor() override;
2423 
2424  bool is_valid() const override;
2425 
2426  bool decompress(const char *data, size_t data_length,
2427  Callback callback) override;
2428 
2429 private:
2430  bool is_valid_ = false;
2431  z_stream strm_;
2432 };
2433 #endif
2434 
2435 #ifdef CPPHTTPLIB_BROTLI_SUPPORT
2436 class brotli_compressor final : public compressor {
2437 public:
2438  brotli_compressor();
2439  ~brotli_compressor();
2440 
2441  bool compress(const char *data, size_t data_length, bool last,
2442  Callback callback) override;
2443 
2444 private:
2445  BrotliEncoderState *state_ = nullptr;
2446 };
2447 
2448 class brotli_decompressor final : public decompressor {
2449 public:
2450  brotli_decompressor();
2451  ~brotli_decompressor();
2452 
2453  bool is_valid() const override;
2454 
2455  bool decompress(const char *data, size_t data_length,
2456  Callback callback) override;
2457 
2458 private:
2459  BrotliDecoderResult decoder_r;
2460  BrotliDecoderState *decoder_s = nullptr;
2461 };
2462 #endif
2463 
2464 // NOTE: until the read size reaches `fixed_buffer_size`, use `fixed_buffer`
2465 // to store data. The call can set memory on stack for performance.
2467 public:
2468  stream_line_reader(Stream &strm, char *fixed_buffer,
2469  size_t fixed_buffer_size);
2470  const char *ptr() const;
2471  size_t size() const;
2472  bool end_with_crlf() const;
2473  bool getline();
2474 
2475 private:
2476  void append(char c);
2477 
2478  Stream &strm_;
2479  char *fixed_buffer_;
2480  const size_t fixed_buffer_size_;
2481  size_t fixed_buffer_used_size_ = 0;
2482  std::string glowable_buffer_;
2483 };
2484 
2485 class mmap {
2486 public:
2487  mmap(const char *path);
2488  ~mmap();
2489 
2490  bool open(const char *path);
2491  void close();
2492 
2493  bool is_open() const;
2494  size_t size() const;
2495  const char *data() const;
2496 
2497 private:
2498 #if defined(_WIN32)
2499  HANDLE hFile_ = NULL;
2500  HANDLE hMapping_ = NULL;
2501 #else
2502  int fd_ = -1;
2503 #endif
2504  size_t size_ = 0;
2505  void *addr_ = nullptr;
2506  bool is_open_empty_file = false;
2507 };
2508 
2509 } // namespace detail
2510 
2511 // ----------------------------------------------------------------------------
2512 
2513 /*
2514  * Implementation that will be part of the .cc file if split into .h + .cc.
2515  */
2516 
2517 namespace detail {
2518 
2519 inline bool is_hex(char c, int &v) {
2520  if (0x20 <= c && isdigit(c)) {
2521  v = c - '0';
2522  return true;
2523  } else if ('A' <= c && c <= 'F') {
2524  v = c - 'A' + 10;
2525  return true;
2526  } else if ('a' <= c && c <= 'f') {
2527  v = c - 'a' + 10;
2528  return true;
2529  }
2530  return false;
2531 }
2532 
2533 inline bool from_hex_to_i(const std::string &s, size_t i, size_t cnt,
2534  int &val) {
2535  if (i >= s.size()) { return false; }
2536 
2537  val = 0;
2538  for (; cnt; i++, cnt--) {
2539  if (!s[i]) { return false; }
2540  auto v = 0;
2541  if (is_hex(s[i], v)) {
2542  val = val * 16 + v;
2543  } else {
2544  return false;
2545  }
2546  }
2547  return true;
2548 }
2549 
2550 inline std::string from_i_to_hex(size_t n) {
2551  static const auto charset = "0123456789abcdef";
2552  std::string ret;
2553  do {
2554  ret = charset[n & 15] + ret;
2555  n >>= 4;
2556  } while (n > 0);
2557  return ret;
2558 }
2559 
2560 inline size_t to_utf8(int code, char *buff) {
2561  if (code < 0x0080) {
2562  buff[0] = static_cast<char>(code & 0x7F);
2563  return 1;
2564  } else if (code < 0x0800) {
2565  buff[0] = static_cast<char>(0xC0 | ((code >> 6) & 0x1F));
2566  buff[1] = static_cast<char>(0x80 | (code & 0x3F));
2567  return 2;
2568  } else if (code < 0xD800) {
2569  buff[0] = static_cast<char>(0xE0 | ((code >> 12) & 0xF));
2570  buff[1] = static_cast<char>(0x80 | ((code >> 6) & 0x3F));
2571  buff[2] = static_cast<char>(0x80 | (code & 0x3F));
2572  return 3;
2573  } else if (code < 0xE000) { // D800 - DFFF is invalid...
2574  return 0;
2575  } else if (code < 0x10000) {
2576  buff[0] = static_cast<char>(0xE0 | ((code >> 12) & 0xF));
2577  buff[1] = static_cast<char>(0x80 | ((code >> 6) & 0x3F));
2578  buff[2] = static_cast<char>(0x80 | (code & 0x3F));
2579  return 3;
2580  } else if (code < 0x110000) {
2581  buff[0] = static_cast<char>(0xF0 | ((code >> 18) & 0x7));
2582  buff[1] = static_cast<char>(0x80 | ((code >> 12) & 0x3F));
2583  buff[2] = static_cast<char>(0x80 | ((code >> 6) & 0x3F));
2584  buff[3] = static_cast<char>(0x80 | (code & 0x3F));
2585  return 4;
2586  }
2587 
2588  // NOTREACHED
2589  return 0;
2590 }
2591 
2592 // NOTE: This code came up with the following stackoverflow post:
2593 // https://stackoverflow.com/questions/180947/base64-decode-snippet-in-c
2594 inline std::string base64_encode(const std::string &in) {
2595  static const auto lookup =
2596  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
2597 
2598  std::string out;
2599  out.reserve(in.size());
2600 
2601  auto val = 0;
2602  auto valb = -6;
2603 
2604  for (auto c : in) {
2605  val = (val << 8) + static_cast<uint8_t>(c);
2606  valb += 8;
2607  while (valb >= 0) {
2608  out.push_back(lookup[(val >> valb) & 0x3F]);
2609  valb -= 6;
2610  }
2611  }
2612 
2613  if (valb > -6) { out.push_back(lookup[((val << 8) >> (valb + 8)) & 0x3F]); }
2614 
2615  while (out.size() % 4) {
2616  out.push_back('=');
2617  }
2618 
2619  return out;
2620 }
2621 
2622 inline bool is_valid_path(const std::string &path) {
2623  size_t level = 0;
2624  size_t i = 0;
2625 
2626  // Skip slash
2627  while (i < path.size() && path[i] == '/') {
2628  i++;
2629  }
2630 
2631  while (i < path.size()) {
2632  // Read component
2633  auto beg = i;
2634  while (i < path.size() && path[i] != '/') {
2635  if (path[i] == '\0') {
2636  return false;
2637  } else if (path[i] == '\\') {
2638  return false;
2639  }
2640  i++;
2641  }
2642 
2643  auto len = i - beg;
2644  assert(len > 0);
2645 
2646  if (!path.compare(beg, len, ".")) {
2647  ;
2648  } else if (!path.compare(beg, len, "..")) {
2649  if (level == 0) { return false; }
2650  level--;
2651  } else {
2652  level++;
2653  }
2654 
2655  // Skip slash
2656  while (i < path.size() && path[i] == '/') {
2657  i++;
2658  }
2659  }
2660 
2661  return true;
2662 }
2663 
2664 inline FileStat::FileStat(const std::string &path) {
2665 #if defined(_WIN32)
2666  auto wpath = u8string_to_wstring(path.c_str());
2667  ret_ = _wstat(wpath.c_str(), &st_);
2668 #else
2669  ret_ = stat(path.c_str(), &st_);
2670 #endif
2671 }
2672 inline bool FileStat::is_file() const {
2673  return ret_ >= 0 && S_ISREG(st_.st_mode);
2674 }
2675 inline bool FileStat::is_dir() const {
2676  return ret_ >= 0 && S_ISDIR(st_.st_mode);
2677 }
2678 
2679 inline std::string encode_query_param(const std::string &value) {
2680  std::ostringstream escaped;
2681  escaped.fill('0');
2682  escaped << std::hex;
2683 
2684  for (auto c : value) {
2685  if (std::isalnum(static_cast<uint8_t>(c)) || c == '-' || c == '_' ||
2686  c == '.' || c == '!' || c == '~' || c == '*' || c == '\'' || c == '(' ||
2687  c == ')') {
2688  escaped << c;
2689  } else {
2690  escaped << std::uppercase;
2691  escaped << '%' << std::setw(2)
2692  << static_cast<int>(static_cast<unsigned char>(c));
2693  escaped << std::nouppercase;
2694  }
2695  }
2696 
2697  return escaped.str();
2698 }
2699 
2700 inline std::string encode_url(const std::string &s) {
2701  std::string result;
2702  result.reserve(s.size());
2703 
2704  for (size_t i = 0; s[i]; i++) {
2705  switch (s[i]) {
2706  case ' ': result += "%20"; break;
2707  case '+': result += "%2B"; break;
2708  case '\r': result += "%0D"; break;
2709  case '\n': result += "%0A"; break;
2710  case '\'': result += "%27"; break;
2711  case ',': result += "%2C"; break;
2712  // case ':': result += "%3A"; break; // ok? probably...
2713  case ';': result += "%3B"; break;
2714  default:
2715  auto c = static_cast<uint8_t>(s[i]);
2716  if (c >= 0x80) {
2717  result += '%';
2718  char hex[4];
2719  auto len = snprintf(hex, sizeof(hex) - 1, "%02X", c);
2720  assert(len == 2);
2721  result.append(hex, static_cast<size_t>(len));
2722  } else {
2723  result += s[i];
2724  }
2725  break;
2726  }
2727  }
2728 
2729  return result;
2730 }
2731 
2732 inline std::string decode_url(const std::string &s,
2733  bool convert_plus_to_space) {
2734  std::string result;
2735 
2736  for (size_t i = 0; i < s.size(); i++) {
2737  if (s[i] == '%' && i + 1 < s.size()) {
2738  if (s[i + 1] == 'u') {
2739  auto val = 0;
2740  if (from_hex_to_i(s, i + 2, 4, val)) {
2741  // 4 digits Unicode codes
2742  char buff[4];
2743  size_t len = to_utf8(val, buff);
2744  if (len > 0) { result.append(buff, len); }
2745  i += 5; // 'u0000'
2746  } else {
2747  result += s[i];
2748  }
2749  } else {
2750  auto val = 0;
2751  if (from_hex_to_i(s, i + 1, 2, val)) {
2752  // 2 digits hex codes
2753  result += static_cast<char>(val);
2754  i += 2; // '00'
2755  } else {
2756  result += s[i];
2757  }
2758  }
2759  } else if (convert_plus_to_space && s[i] == '+') {
2760  result += ' ';
2761  } else {
2762  result += s[i];
2763  }
2764  }
2765 
2766  return result;
2767 }
2768 
2769 inline void read_file(const std::string &path, std::string &out) {
2770  std::ifstream fs(path, std::ios_base::binary);
2771  fs.seekg(0, std::ios_base::end);
2772  auto size = fs.tellg();
2773  fs.seekg(0);
2774  out.resize(static_cast<size_t>(size));
2775  fs.read(&out[0], static_cast<std::streamsize>(size));
2776 }
2777 
2778 inline std::string file_extension(const std::string &path) {
2779  std::smatch m;
2780  static auto re = std::regex("\\.([a-zA-Z0-9]+)$");
2781  if (std::regex_search(path, m, re)) { return m[1].str(); }
2782  return std::string();
2783 }
2784 
2785 inline bool is_space_or_tab(char c) { return c == ' ' || c == '\t'; }
2786 
2787 inline std::pair<size_t, size_t> trim(const char *b, const char *e, size_t left,
2788  size_t right) {
2789  while (b + left < e && is_space_or_tab(b[left])) {
2790  left++;
2791  }
2792  while (right > 0 && is_space_or_tab(b[right - 1])) {
2793  right--;
2794  }
2795  return std::make_pair(left, right);
2796 }
2797 
2798 inline std::string trim_copy(const std::string &s) {
2799  auto r = trim(s.data(), s.data() + s.size(), 0, s.size());
2800  return s.substr(r.first, r.second - r.first);
2801 }
2802 
2803 inline std::string trim_double_quotes_copy(const std::string &s) {
2804  if (s.length() >= 2 && s.front() == '"' && s.back() == '"') {
2805  return s.substr(1, s.size() - 2);
2806  }
2807  return s;
2808 }
2809 
2810 inline void
2811 divide(const char *data, std::size_t size, char d,
2812  std::function<void(const char *, std::size_t, const char *, std::size_t)>
2813  fn) {
2814  const auto it = std::find(data, data + size, d);
2815  const auto found = static_cast<std::size_t>(it != data + size);
2816  const auto lhs_data = data;
2817  const auto lhs_size = static_cast<std::size_t>(it - data);
2818  const auto rhs_data = it + found;
2819  const auto rhs_size = size - lhs_size - found;
2820 
2821  fn(lhs_data, lhs_size, rhs_data, rhs_size);
2822 }
2823 
2824 inline void
2825 divide(const std::string &str, char d,
2826  std::function<void(const char *, std::size_t, const char *, std::size_t)>
2827  fn) {
2828  divide(str.data(), str.size(), d, std::move(fn));
2829 }
2830 
2831 inline void split(const char *b, const char *e, char d,
2832  std::function<void(const char *, const char *)> fn) {
2833  return split(b, e, d, (std::numeric_limits<size_t>::max)(), std::move(fn));
2834 }
2835 
2836 inline void split(const char *b, const char *e, char d, size_t m,
2837  std::function<void(const char *, const char *)> fn) {
2838  size_t i = 0;
2839  size_t beg = 0;
2840  size_t count = 1;
2841 
2842  while (e ? (b + i < e) : (b[i] != '\0')) {
2843  if (b[i] == d && count < m) {
2844  auto r = trim(b, e, beg, i);
2845  if (r.first < r.second) { fn(&b[r.first], &b[r.second]); }
2846  beg = i + 1;
2847  count++;
2848  }
2849  i++;
2850  }
2851 
2852  if (i) {
2853  auto r = trim(b, e, beg, i);
2854  if (r.first < r.second) { fn(&b[r.first], &b[r.second]); }
2855  }
2856 }
2857 
2858 inline stream_line_reader::stream_line_reader(Stream &strm, char *fixed_buffer,
2859  size_t fixed_buffer_size)
2860  : strm_(strm), fixed_buffer_(fixed_buffer),
2861  fixed_buffer_size_(fixed_buffer_size) {}
2862 
2863 inline const char *stream_line_reader::ptr() const {
2864  if (glowable_buffer_.empty()) {
2865  return fixed_buffer_;
2866  } else {
2867  return glowable_buffer_.data();
2868  }
2869 }
2870 
2871 inline size_t stream_line_reader::size() const {
2872  if (glowable_buffer_.empty()) {
2873  return fixed_buffer_used_size_;
2874  } else {
2875  return glowable_buffer_.size();
2876  }
2877 }
2878 
2880  auto end = ptr() + size();
2881  return size() >= 2 && end[-2] == '\r' && end[-1] == '\n';
2882 }
2883 
2885  fixed_buffer_used_size_ = 0;
2886  glowable_buffer_.clear();
2887 
2888 #ifndef CPPHTTPLIB_ALLOW_LF_AS_LINE_TERMINATOR
2889  char prev_byte = 0;
2890 #endif
2891 
2892  for (size_t i = 0;; i++) {
2893  char byte;
2894  auto n = strm_.read(&byte, 1);
2895 
2896  if (n < 0) {
2897  return false;
2898  } else if (n == 0) {
2899  if (i == 0) {
2900  return false;
2901  } else {
2902  break;
2903  }
2904  }
2905 
2906  append(byte);
2907 
2908 #ifdef CPPHTTPLIB_ALLOW_LF_AS_LINE_TERMINATOR
2909  if (byte == '\n') { break; }
2910 #else
2911  if (prev_byte == '\r' && byte == '\n') { break; }
2912  prev_byte = byte;
2913 #endif
2914  }
2915 
2916  return true;
2917 }
2918 
2919 inline void stream_line_reader::append(char c) {
2920  if (fixed_buffer_used_size_ < fixed_buffer_size_ - 1) {
2921  fixed_buffer_[fixed_buffer_used_size_++] = c;
2922  fixed_buffer_[fixed_buffer_used_size_] = '\0';
2923  } else {
2924  if (glowable_buffer_.empty()) {
2925  assert(fixed_buffer_[fixed_buffer_used_size_] == '\0');
2926  glowable_buffer_.assign(fixed_buffer_, fixed_buffer_used_size_);
2927  }
2928  glowable_buffer_ += c;
2929  }
2930 }
2931 
2932 inline mmap::mmap(const char *path) { open(path); }
2933 
2934 inline mmap::~mmap() { close(); }
2935 
2936 inline bool mmap::open(const char *path) {
2937  close();
2938 
2939 #if defined(_WIN32)
2940  auto wpath = u8string_to_wstring(path);
2941  if (wpath.empty()) { return false; }
2942 
2943 #if _WIN32_WINNT >= _WIN32_WINNT_WIN8
2944  hFile_ = ::CreateFile2(wpath.c_str(), GENERIC_READ, FILE_SHARE_READ,
2945  OPEN_EXISTING, NULL);
2946 #else
2947  hFile_ = ::CreateFileW(wpath.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL,
2948  OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
2949 #endif
2950 
2951  if (hFile_ == INVALID_HANDLE_VALUE) { return false; }
2952 
2953  LARGE_INTEGER size{};
2954  if (!::GetFileSizeEx(hFile_, &size)) { return false; }
2955  // If the following line doesn't compile due to QuadPart, update Windows SDK.
2956  // See:
2957  // https://github.com/yhirose/cpp-httplib/issues/1903#issuecomment-2316520721
2958  if (static_cast<ULONGLONG>(size.QuadPart) >
2959  (std::numeric_limits<decltype(size_)>::max)()) {
2960  // `size_t` might be 32-bits, on 32-bits Windows.
2961  return false;
2962  }
2963  size_ = static_cast<size_t>(size.QuadPart);
2964 
2965 #if _WIN32_WINNT >= _WIN32_WINNT_WIN8
2966  hMapping_ =
2967  ::CreateFileMappingFromApp(hFile_, NULL, PAGE_READONLY, size_, NULL);
2968 #else
2969  hMapping_ = ::CreateFileMappingW(hFile_, NULL, PAGE_READONLY, 0, 0, NULL);
2970 #endif
2971 
2972  // Special treatment for an empty file...
2973  if (hMapping_ == NULL && size_ == 0) {
2974  close();
2975  is_open_empty_file = true;
2976  return true;
2977  }
2978 
2979  if (hMapping_ == NULL) {
2980  close();
2981  return false;
2982  }
2983 
2984 #if _WIN32_WINNT >= _WIN32_WINNT_WIN8
2985  addr_ = ::MapViewOfFileFromApp(hMapping_, FILE_MAP_READ, 0, 0);
2986 #else
2987  addr_ = ::MapViewOfFile(hMapping_, FILE_MAP_READ, 0, 0, 0);
2988 #endif
2989 
2990  if (addr_ == nullptr) {
2991  close();
2992  return false;
2993  }
2994 #else
2995  fd_ = ::open(path, O_RDONLY);
2996  if (fd_ == -1) { return false; }
2997 
2998  struct stat sb;
2999  if (fstat(fd_, &sb) == -1) {
3000  close();
3001  return false;
3002  }
3003  size_ = static_cast<size_t>(sb.st_size);
3004 
3005  addr_ = ::mmap(NULL, size_, PROT_READ, MAP_PRIVATE, fd_, 0);
3006 
3007  // Special treatment for an empty file...
3008  if (addr_ == MAP_FAILED && size_ == 0) {
3009  close();
3010  is_open_empty_file = true;
3011  return false;
3012  }
3013 #endif
3014 
3015  return true;
3016 }
3017 
3018 inline bool mmap::is_open() const {
3019  return is_open_empty_file ? true : addr_ != nullptr;
3020 }
3021 
3022 inline size_t mmap::size() const { return size_; }
3023 
3024 inline const char *mmap::data() const {
3025  return is_open_empty_file ? "" : static_cast<const char *>(addr_);
3026 }
3027 
3028 inline void mmap::close() {
3029 #if defined(_WIN32)
3030  if (addr_) {
3031  ::UnmapViewOfFile(addr_);
3032  addr_ = nullptr;
3033  }
3034 
3035  if (hMapping_) {
3036  ::CloseHandle(hMapping_);
3037  hMapping_ = NULL;
3038  }
3039 
3040  if (hFile_ != INVALID_HANDLE_VALUE) {
3041  ::CloseHandle(hFile_);
3042  hFile_ = INVALID_HANDLE_VALUE;
3043  }
3044 
3045  is_open_empty_file = false;
3046 #else
3047  if (addr_ != nullptr) {
3048  munmap(addr_, size_);
3049  addr_ = nullptr;
3050  }
3051 
3052  if (fd_ != -1) {
3053  ::close(fd_);
3054  fd_ = -1;
3055  }
3056 #endif
3057  size_ = 0;
3058 }
3059 inline int close_socket(socket_t sock) {
3060 #ifdef _WIN32
3061  return closesocket(sock);
3062 #else
3063  return close(sock);
3064 #endif
3065 }
3066 
3067 template <typename T> inline ssize_t handle_EINTR(T fn) {
3068  ssize_t res = 0;
3069  while (true) {
3070  res = fn();
3071  if (res < 0 && errno == EINTR) {
3072  std::this_thread::sleep_for(std::chrono::microseconds{1});
3073  continue;
3074  }
3075  break;
3076  }
3077  return res;
3078 }
3079 
3080 inline ssize_t read_socket(socket_t sock, void *ptr, size_t size, int flags) {
3081  return handle_EINTR([&]() {
3082  return recv(sock,
3083 #ifdef _WIN32
3084  static_cast<char *>(ptr), static_cast<int>(size),
3085 #else
3086  ptr, size,
3087 #endif
3088  flags);
3089  });
3090 }
3091 
3092 inline ssize_t send_socket(socket_t sock, const void *ptr, size_t size,
3093  int flags) {
3094  return handle_EINTR([&]() {
3095  return send(sock,
3096 #ifdef _WIN32
3097  static_cast<const char *>(ptr), static_cast<int>(size),
3098 #else
3099  ptr, size,
3100 #endif
3101  flags);
3102  });
3103 }
3104 
3105 inline ssize_t select_read(socket_t sock, time_t sec, time_t usec) {
3106 #ifdef CPPHTTPLIB_USE_POLL
3107  struct pollfd pfd_read;
3108  pfd_read.fd = sock;
3109  pfd_read.events = POLLIN;
3110 
3111  auto timeout = static_cast<int>(sec * 1000 + usec / 1000);
3112 
3113  return handle_EINTR([&]() { return poll(&pfd_read, 1, timeout); });
3114 #else
3115 #ifndef _WIN32
3116  if (sock >= FD_SETSIZE) { return -1; }
3117 #endif
3118 
3119  fd_set fds;
3120  FD_ZERO(&fds);
3121  FD_SET(sock, &fds);
3122 
3123  timeval tv;
3124  tv.tv_sec = static_cast<long>(sec);
3125  tv.tv_usec = static_cast<decltype(tv.tv_usec)>(usec);
3126 
3127  return handle_EINTR([&]() {
3128  return select(static_cast<int>(sock + 1), &fds, nullptr, nullptr, &tv);
3129  });
3130 #endif
3131 }
3132 
3133 inline ssize_t select_write(socket_t sock, time_t sec, time_t usec) {
3134 #ifdef CPPHTTPLIB_USE_POLL
3135  struct pollfd pfd_read;
3136  pfd_read.fd = sock;
3137  pfd_read.events = POLLOUT;
3138 
3139  auto timeout = static_cast<int>(sec * 1000 + usec / 1000);
3140 
3141  return handle_EINTR([&]() { return poll(&pfd_read, 1, timeout); });
3142 #else
3143 #ifndef _WIN32
3144  if (sock >= FD_SETSIZE) { return -1; }
3145 #endif
3146 
3147  fd_set fds;
3148  FD_ZERO(&fds);
3149  FD_SET(sock, &fds);
3150 
3151  timeval tv;
3152  tv.tv_sec = static_cast<long>(sec);
3153  tv.tv_usec = static_cast<decltype(tv.tv_usec)>(usec);
3154 
3155  return handle_EINTR([&]() {
3156  return select(static_cast<int>(sock + 1), nullptr, &fds, nullptr, &tv);
3157  });
3158 #endif
3159 }
3160 
3162  time_t usec) {
3163 #ifdef CPPHTTPLIB_USE_POLL
3164  struct pollfd pfd_read;
3165  pfd_read.fd = sock;
3166  pfd_read.events = POLLIN | POLLOUT;
3167 
3168  auto timeout = static_cast<int>(sec * 1000 + usec / 1000);
3169 
3170  auto poll_res = handle_EINTR([&]() { return poll(&pfd_read, 1, timeout); });
3171 
3172  if (poll_res == 0) { return Error::ConnectionTimeout; }
3173 
3174  if (poll_res > 0 && pfd_read.revents & (POLLIN | POLLOUT)) {
3175  auto error = 0;
3176  socklen_t len = sizeof(error);
3177  auto res = getsockopt(sock, SOL_SOCKET, SO_ERROR,
3178  reinterpret_cast<char *>(&error), &len);
3179  auto successful = res >= 0 && !error;
3180  return successful ? Error::Success : Error::Connection;
3181  }
3182 
3183  return Error::Connection;
3184 #else
3185 #ifndef _WIN32
3186  if (sock >= FD_SETSIZE) { return Error::Connection; }
3187 #endif
3188 
3189  fd_set fdsr;
3190  FD_ZERO(&fdsr);
3191  FD_SET(sock, &fdsr);
3192 
3193  auto fdsw = fdsr;
3194  auto fdse = fdsr;
3195 
3196  timeval tv;
3197  tv.tv_sec = static_cast<long>(sec);
3198  tv.tv_usec = static_cast<decltype(tv.tv_usec)>(usec);
3199 
3200  auto ret = handle_EINTR([&]() {
3201  return select(static_cast<int>(sock + 1), &fdsr, &fdsw, &fdse, &tv);
3202  });
3203 
3204  if (ret == 0) { return Error::ConnectionTimeout; }
3205 
3206  if (ret > 0 && (FD_ISSET(sock, &fdsr) || FD_ISSET(sock, &fdsw))) {
3207  auto error = 0;
3208  socklen_t len = sizeof(error);
3209  auto res = getsockopt(sock, SOL_SOCKET, SO_ERROR,
3210  reinterpret_cast<char *>(&error), &len);
3211  auto successful = res >= 0 && !error;
3212  return successful ? Error::Success : Error::Connection;
3213  }
3214  return Error::Connection;
3215 #endif
3216 }
3217 
3218 inline bool is_socket_alive(socket_t sock) {
3219  const auto val = detail::select_read(sock, 0, 0);
3220  if (val == 0) {
3221  return true;
3222  } else if (val < 0 && errno == EBADF) {
3223  return false;
3224  }
3225  char buf[1];
3226  return detail::read_socket(sock, &buf[0], sizeof(buf), MSG_PEEK) > 0;
3227 }
3228 
3229 class SocketStream final : public Stream {
3230 public:
3231  SocketStream(socket_t sock, time_t read_timeout_sec, time_t read_timeout_usec,
3232  time_t write_timeout_sec, time_t write_timeout_usec);
3233  ~SocketStream() override;
3234 
3235  bool is_readable() const override;
3236  bool is_writable() const override;
3237  ssize_t read(char *ptr, size_t size) override;
3238  ssize_t write(const char *ptr, size_t size) override;
3239  void get_remote_ip_and_port(std::string &ip, int &port) const override;
3240  void get_local_ip_and_port(std::string &ip, int &port) const override;
3241  socket_t socket() const override;
3242 
3243 private:
3244  socket_t sock_;
3245  time_t read_timeout_sec_;
3246  time_t read_timeout_usec_;
3247  time_t write_timeout_sec_;
3248  time_t write_timeout_usec_;
3249 
3250  std::vector<char> read_buff_;
3251  size_t read_buff_off_ = 0;
3252  size_t read_buff_content_size_ = 0;
3253 
3254  static const size_t read_buff_size_ = 1024l * 4;
3255 };
3256 
3257 #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
3258 class SSLSocketStream final : public Stream {
3259 public:
3260  SSLSocketStream(socket_t sock, SSL *ssl, time_t read_timeout_sec,
3261  time_t read_timeout_usec, time_t write_timeout_sec,
3262  time_t write_timeout_usec);
3263  ~SSLSocketStream() override;
3264 
3265  bool is_readable() const override;
3266  bool is_writable() const override;
3267  ssize_t read(char *ptr, size_t size) override;
3268  ssize_t write(const char *ptr, size_t size) override;
3269  void get_remote_ip_and_port(std::string &ip, int &port) const override;
3270  void get_local_ip_and_port(std::string &ip, int &port) const override;
3271  socket_t socket() const override;
3272 
3273 private:
3274  socket_t sock_;
3275  SSL *ssl_;
3276  time_t read_timeout_sec_;
3277  time_t read_timeout_usec_;
3278  time_t write_timeout_sec_;
3279  time_t write_timeout_usec_;
3280 };
3281 #endif
3282 
3283 inline bool keep_alive(const std::atomic<socket_t> &svr_sock, socket_t sock,
3284  time_t keep_alive_timeout_sec) {
3285  using namespace std::chrono;
3286 
3287  const auto interval_usec =
3289 
3290  // Avoid expensive `steady_clock::now()` call for the first time
3291  if (select_read(sock, 0, interval_usec) > 0) { return true; }
3292 
3293  const auto start = steady_clock::now() - microseconds{interval_usec};
3294  const auto timeout = seconds{keep_alive_timeout_sec};
3295 
3296  while (true) {
3297  if (svr_sock == INVALID_SOCKET) {
3298  break; // Server socket is closed
3299  }
3300 
3301  auto val = select_read(sock, 0, interval_usec);
3302  if (val < 0) {
3303  break; // Ssocket error
3304  } else if (val == 0) {
3305  if (steady_clock::now() - start > timeout) {
3306  break; // Timeout
3307  }
3308  } else {
3309  return true; // Ready for read
3310  }
3311  }
3312 
3313  return false;
3314 }
3315 
3316 template <typename T>
3317 inline bool
3318 process_server_socket_core(const std::atomic<socket_t> &svr_sock, socket_t sock,
3319  size_t keep_alive_max_count,
3320  time_t keep_alive_timeout_sec, T callback) {
3321  assert(keep_alive_max_count > 0);
3322  auto ret = false;
3323  auto count = keep_alive_max_count;
3324  while (count > 0 && keep_alive(svr_sock, sock, keep_alive_timeout_sec)) {
3325  auto close_connection = count == 1;
3326  auto connection_closed = false;
3327  ret = callback(close_connection, connection_closed);
3328  if (!ret || connection_closed) { break; }
3329  count--;
3330  }
3331  return ret;
3332 }
3333 
3334 template <typename T>
3335 inline bool
3336 process_server_socket(const std::atomic<socket_t> &svr_sock, socket_t sock,
3337  size_t keep_alive_max_count,
3338  time_t keep_alive_timeout_sec, time_t read_timeout_sec,
3339  time_t read_timeout_usec, time_t write_timeout_sec,
3340  time_t write_timeout_usec, T callback) {
3342  svr_sock, sock, keep_alive_max_count, keep_alive_timeout_sec,
3343  [&](bool close_connection, bool &connection_closed) {
3344  SocketStream strm(sock, read_timeout_sec, read_timeout_usec,
3345  write_timeout_sec, write_timeout_usec);
3346  return callback(strm, close_connection, connection_closed);
3347  });
3348 }
3349 
3350 inline bool process_client_socket(socket_t sock, time_t read_timeout_sec,
3351  time_t read_timeout_usec,
3352  time_t write_timeout_sec,
3353  time_t write_timeout_usec,
3354  std::function<bool(Stream &)> callback) {
3355  SocketStream strm(sock, read_timeout_sec, read_timeout_usec,
3356  write_timeout_sec, write_timeout_usec);
3357  return callback(strm);
3358 }
3359 
3360 inline int shutdown_socket(socket_t sock) {
3361 #ifdef _WIN32
3362  return shutdown(sock, SD_BOTH);
3363 #else
3364  return shutdown(sock, SHUT_RDWR);
3365 #endif
3366 }
3367 
3368 inline std::string escape_abstract_namespace_unix_domain(const std::string &s) {
3369  if (s.size() > 1 && s[0] == '\0') {
3370  auto ret = s;
3371  ret[0] = '@';
3372  return ret;
3373  }
3374  return s;
3375 }
3376 
3377 inline std::string
3379  if (s.size() > 1 && s[0] == '@') {
3380  auto ret = s;
3381  ret[0] = '\0';
3382  return ret;
3383  }
3384  return s;
3385 }
3386 
3387 template <typename BindOrConnect>
3388 socket_t create_socket(const std::string &host, const std::string &ip, int port,
3389  int address_family, int socket_flags, bool tcp_nodelay,
3390  bool ipv6_v6only, SocketOptions socket_options,
3391  BindOrConnect bind_or_connect) {
3392  // Get address info
3393  const char *node = nullptr;
3394  struct addrinfo hints;
3395  struct addrinfo *result;
3396 
3397  memset(&hints, 0, sizeof(struct addrinfo));
3398  hints.ai_socktype = SOCK_STREAM;
3399  hints.ai_protocol = IPPROTO_IP;
3400 
3401  if (!ip.empty()) {
3402  node = ip.c_str();
3403  // Ask getaddrinfo to convert IP in c-string to address
3404  hints.ai_family = AF_UNSPEC;
3405  hints.ai_flags = AI_NUMERICHOST;
3406  } else {
3407  if (!host.empty()) { node = host.c_str(); }
3408  hints.ai_family = address_family;
3409  hints.ai_flags = socket_flags;
3410  }
3411 
3412 #ifndef _WIN32
3413  if (hints.ai_family == AF_UNIX) {
3414  const auto addrlen = host.length();
3415  if (addrlen > sizeof(sockaddr_un::sun_path)) { return INVALID_SOCKET; }
3416 
3417 #ifdef SOCK_CLOEXEC
3418  auto sock = socket(hints.ai_family, hints.ai_socktype | SOCK_CLOEXEC,
3419  hints.ai_protocol);
3420 #else
3421  auto sock = socket(hints.ai_family, hints.ai_socktype, hints.ai_protocol);
3422 #endif
3423 
3424  if (sock != INVALID_SOCKET) {
3425  sockaddr_un addr{};
3426  addr.sun_family = AF_UNIX;
3427 
3428  auto unescaped_host = unescape_abstract_namespace_unix_domain(host);
3429  std::copy(unescaped_host.begin(), unescaped_host.end(), addr.sun_path);
3430 
3431  hints.ai_addr = reinterpret_cast<sockaddr *>(&addr);
3432  hints.ai_addrlen = static_cast<socklen_t>(
3433  sizeof(addr) - sizeof(addr.sun_path) + addrlen);
3434 
3435 #ifndef SOCK_CLOEXEC
3436  fcntl(sock, F_SETFD, FD_CLOEXEC);
3437 #endif
3438 
3439  if (socket_options) { socket_options(sock); }
3440 
3441  bool dummy;
3442  if (!bind_or_connect(sock, hints, dummy)) {
3443  close_socket(sock);
3444  sock = INVALID_SOCKET;
3445  }
3446  }
3447  return sock;
3448  }
3449 #endif
3450 
3451  auto service = std::to_string(port);
3452 
3453  if (getaddrinfo(node, service.c_str(), &hints, &result)) {
3454 #if defined __linux__ && !defined __ANDROID__
3455  res_init();
3456 #endif
3457  return INVALID_SOCKET;
3458  }
3459  auto se = detail::scope_exit([&] { freeaddrinfo(result); });
3460 
3461  for (auto rp = result; rp; rp = rp->ai_next) {
3462  // Create a socket
3463 #ifdef _WIN32
3464  auto sock =
3465  WSASocketW(rp->ai_family, rp->ai_socktype, rp->ai_protocol, nullptr, 0,
3466  WSA_FLAG_NO_HANDLE_INHERIT | WSA_FLAG_OVERLAPPED);
3467  /**
3468  * Since the WSA_FLAG_NO_HANDLE_INHERIT is only supported on Windows 7 SP1
3469  * and above the socket creation fails on older Windows Systems.
3470  *
3471  * Let's try to create a socket the old way in this case.
3472  *
3473  * Reference:
3474  * https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-wsasocketa
3475  *
3476  * WSA_FLAG_NO_HANDLE_INHERIT:
3477  * This flag is supported on Windows 7 with SP1, Windows Server 2008 R2 with
3478  * SP1, and later
3479  *
3480  */
3481  if (sock == INVALID_SOCKET) {
3482  sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
3483  }
3484 #else
3485 
3486 #ifdef SOCK_CLOEXEC
3487  auto sock =
3488  socket(rp->ai_family, rp->ai_socktype | SOCK_CLOEXEC, rp->ai_protocol);
3489 #else
3490  auto sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
3491 #endif
3492 
3493 #endif
3494  if (sock == INVALID_SOCKET) { continue; }
3495 
3496 #if !defined _WIN32 && !defined SOCK_CLOEXEC
3497  if (fcntl(sock, F_SETFD, FD_CLOEXEC) == -1) {
3498  close_socket(sock);
3499  continue;
3500  }
3501 #endif
3502 
3503  if (tcp_nodelay) {
3504  auto opt = 1;
3505 #ifdef _WIN32
3506  setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,
3507  reinterpret_cast<const char *>(&opt), sizeof(opt));
3508 #else
3509  setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,
3510  reinterpret_cast<const void *>(&opt), sizeof(opt));
3511 #endif
3512  }
3513 
3514  if (rp->ai_family == AF_INET6) {
3515  auto opt = ipv6_v6only ? 1 : 0;
3516 #ifdef _WIN32
3517  setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY,
3518  reinterpret_cast<const char *>(&opt), sizeof(opt));
3519 #else
3520  setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY,
3521  reinterpret_cast<const void *>(&opt), sizeof(opt));
3522 #endif
3523  }
3524 
3525  if (socket_options) { socket_options(sock); }
3526 
3527  // bind or connect
3528  auto quit = false;
3529  if (bind_or_connect(sock, *rp, quit)) { return sock; }
3530 
3531  close_socket(sock);
3532 
3533  if (quit) { break; }
3534  }
3535 
3536  return INVALID_SOCKET;
3537 }
3538 
3539 inline void set_nonblocking(socket_t sock, bool nonblocking) {
3540 #ifdef _WIN32
3541  auto flags = nonblocking ? 1UL : 0UL;
3542  ioctlsocket(sock, FIONBIO, &flags);
3543 #else
3544  auto flags = fcntl(sock, F_GETFL, 0);
3545  fcntl(sock, F_SETFL,
3546  nonblocking ? (flags | O_NONBLOCK) : (flags & (~O_NONBLOCK)));
3547 #endif
3548 }
3549 
3550 inline bool is_connection_error() {
3551 #ifdef _WIN32
3552  return WSAGetLastError() != WSAEWOULDBLOCK;
3553 #else
3554  return errno != EINPROGRESS;
3555 #endif
3556 }
3557 
3558 inline bool bind_ip_address(socket_t sock, const std::string &host) {
3559  struct addrinfo hints;
3560  struct addrinfo *result;
3561 
3562  memset(&hints, 0, sizeof(struct addrinfo));
3563  hints.ai_family = AF_UNSPEC;
3564  hints.ai_socktype = SOCK_STREAM;
3565  hints.ai_protocol = 0;
3566 
3567  if (getaddrinfo(host.c_str(), "0", &hints, &result)) { return false; }
3568  auto se = detail::scope_exit([&] { freeaddrinfo(result); });
3569 
3570  auto ret = false;
3571  for (auto rp = result; rp; rp = rp->ai_next) {
3572  const auto &ai = *rp;
3573  if (!::bind(sock, ai.ai_addr, static_cast<socklen_t>(ai.ai_addrlen))) {
3574  ret = true;
3575  break;
3576  }
3577  }
3578 
3579  return ret;
3580 }
3581 
3582 #if !defined _WIN32 && !defined ANDROID && !defined _AIX && !defined __MVS__
3583 #define USE_IF2IP
3584 #endif
3585 
3586 #ifdef USE_IF2IP
3587 inline std::string if2ip(int address_family, const std::string &ifn) {
3588  struct ifaddrs *ifap;
3589  getifaddrs(&ifap);
3590  auto se = detail::scope_exit([&] { freeifaddrs(ifap); });
3591 
3592  std::string addr_candidate;
3593  for (auto ifa = ifap; ifa; ifa = ifa->ifa_next) {
3594  if (ifa->ifa_addr && ifn == ifa->ifa_name &&
3595  (AF_UNSPEC == address_family ||
3596  ifa->ifa_addr->sa_family == address_family)) {
3597  if (ifa->ifa_addr->sa_family == AF_INET) {
3598  auto sa = reinterpret_cast<struct sockaddr_in *>(ifa->ifa_addr);
3599  char buf[INET_ADDRSTRLEN];
3600  if (inet_ntop(AF_INET, &sa->sin_addr, buf, INET_ADDRSTRLEN)) {
3601  return std::string(buf, INET_ADDRSTRLEN);
3602  }
3603  } else if (ifa->ifa_addr->sa_family == AF_INET6) {
3604  auto sa = reinterpret_cast<struct sockaddr_in6 *>(ifa->ifa_addr);
3605  if (!IN6_IS_ADDR_LINKLOCAL(&sa->sin6_addr)) {
3606  char buf[INET6_ADDRSTRLEN] = {};
3607  if (inet_ntop(AF_INET6, &sa->sin6_addr, buf, INET6_ADDRSTRLEN)) {
3608  // equivalent to mac's IN6_IS_ADDR_UNIQUE_LOCAL
3609  auto s6_addr_head = sa->sin6_addr.s6_addr[0];
3610  if (s6_addr_head == 0xfc || s6_addr_head == 0xfd) {
3611  addr_candidate = std::string(buf, INET6_ADDRSTRLEN);
3612  } else {
3613  return std::string(buf, INET6_ADDRSTRLEN);
3614  }
3615  }
3616  }
3617  }
3618  }
3619  }
3620  return addr_candidate;
3621 }
3622 #endif
3623 
3625  const std::string &host, const std::string &ip, int port,
3626  int address_family, bool tcp_nodelay, bool ipv6_v6only,
3627  SocketOptions socket_options, time_t connection_timeout_sec,
3628  time_t connection_timeout_usec, time_t read_timeout_sec,
3629  time_t read_timeout_usec, time_t write_timeout_sec,
3630  time_t write_timeout_usec, const std::string &intf, Error &error) {
3631  auto sock = create_socket(
3632  host, ip, port, address_family, 0, tcp_nodelay, ipv6_v6only,
3633  std::move(socket_options),
3634  [&](socket_t sock2, struct addrinfo &ai, bool &quit) -> bool {
3635  if (!intf.empty()) {
3636 #ifdef USE_IF2IP
3637  auto ip_from_if = if2ip(address_family, intf);
3638  if (ip_from_if.empty()) { ip_from_if = intf; }
3639  if (!bind_ip_address(sock2, ip_from_if)) {
3640  error = Error::BindIPAddress;
3641  return false;
3642  }
3643 #endif
3644  }
3645 
3646  set_nonblocking(sock2, true);
3647 
3648  auto ret =
3649  ::connect(sock2, ai.ai_addr, static_cast<socklen_t>(ai.ai_addrlen));
3650 
3651  if (ret < 0) {
3652  if (is_connection_error()) {
3653  error = Error::Connection;
3654  return false;
3655  }
3656  error = wait_until_socket_is_ready(sock2, connection_timeout_sec,
3657  connection_timeout_usec);
3658  if (error != Error::Success) {
3659  if (error == Error::ConnectionTimeout) { quit = true; }
3660  return false;
3661  }
3662  }
3663 
3664  set_nonblocking(sock2, false);
3665 
3666  {
3667 #ifdef _WIN32
3668  auto timeout = static_cast<uint32_t>(read_timeout_sec * 1000 +
3669  read_timeout_usec / 1000);
3670  setsockopt(sock2, SOL_SOCKET, SO_RCVTIMEO,
3671  reinterpret_cast<const char *>(&timeout), sizeof(timeout));
3672 #else
3673  timeval tv;
3674  tv.tv_sec = static_cast<long>(read_timeout_sec);
3675  tv.tv_usec = static_cast<decltype(tv.tv_usec)>(read_timeout_usec);
3676  setsockopt(sock2, SOL_SOCKET, SO_RCVTIMEO,
3677  reinterpret_cast<const void *>(&tv), sizeof(tv));
3678 #endif
3679  }
3680  {
3681 
3682 #ifdef _WIN32
3683  auto timeout = static_cast<uint32_t>(write_timeout_sec * 1000 +
3684  write_timeout_usec / 1000);
3685  setsockopt(sock2, SOL_SOCKET, SO_SNDTIMEO,
3686  reinterpret_cast<const char *>(&timeout), sizeof(timeout));
3687 #else
3688  timeval tv;
3689  tv.tv_sec = static_cast<long>(write_timeout_sec);
3690  tv.tv_usec = static_cast<decltype(tv.tv_usec)>(write_timeout_usec);
3691  setsockopt(sock2, SOL_SOCKET, SO_SNDTIMEO,
3692  reinterpret_cast<const void *>(&tv), sizeof(tv));
3693 #endif
3694  }
3695 
3696  error = Error::Success;
3697  return true;
3698  });
3699 
3700  if (sock != INVALID_SOCKET) {
3701  error = Error::Success;
3702  } else {
3703  if (error == Error::Success) { error = Error::Connection; }
3704  }
3705 
3706  return sock;
3707 }
3708 
3709 inline bool get_ip_and_port(const struct sockaddr_storage &addr,
3710  socklen_t addr_len, std::string &ip, int &port) {
3711  if (addr.ss_family == AF_INET) {
3712  port = ntohs(reinterpret_cast<const struct sockaddr_in *>(&addr)->sin_port);
3713  } else if (addr.ss_family == AF_INET6) {
3714  port =
3715  ntohs(reinterpret_cast<const struct sockaddr_in6 *>(&addr)->sin6_port);
3716  } else {
3717  return false;
3718  }
3719 
3720  std::array<char, NI_MAXHOST> ipstr{};
3721  if (getnameinfo(reinterpret_cast<const struct sockaddr *>(&addr), addr_len,
3722  ipstr.data(), static_cast<socklen_t>(ipstr.size()), nullptr,
3723  0, NI_NUMERICHOST)) {
3724  return false;
3725  }
3726 
3727  ip = ipstr.data();
3728  return true;
3729 }
3730 
3731 inline void get_local_ip_and_port(socket_t sock, std::string &ip, int &port) {
3732  struct sockaddr_storage addr;
3733  socklen_t addr_len = sizeof(addr);
3734  if (!getsockname(sock, reinterpret_cast<struct sockaddr *>(&addr),
3735  &addr_len)) {
3736  get_ip_and_port(addr, addr_len, ip, port);
3737  }
3738 }
3739 
3740 inline void get_remote_ip_and_port(socket_t sock, std::string &ip, int &port) {
3741  struct sockaddr_storage addr;
3742  socklen_t addr_len = sizeof(addr);
3743 
3744  if (!getpeername(sock, reinterpret_cast<struct sockaddr *>(&addr),
3745  &addr_len)) {
3746 #ifndef _WIN32
3747  if (addr.ss_family == AF_UNIX) {
3748 #if defined(__linux__)
3749  struct ucred ucred;
3750  socklen_t len = sizeof(ucred);
3751  if (getsockopt(sock, SOL_SOCKET, SO_PEERCRED, &ucred, &len) == 0) {
3752  port = ucred.pid;
3753  }
3754 #elif defined(SOL_LOCAL) && defined(SO_PEERPID) // __APPLE__
3755  pid_t pid;
3756  socklen_t len = sizeof(pid);
3757  if (getsockopt(sock, SOL_LOCAL, SO_PEERPID, &pid, &len) == 0) {
3758  port = pid;
3759  }
3760 #endif
3761  return;
3762  }
3763 #endif
3764  get_ip_and_port(addr, addr_len, ip, port);
3765  }
3766 }
3767 
3768 inline constexpr unsigned int str2tag_core(const char *s, size_t l,
3769  unsigned int h) {
3770  return (l == 0)
3771  ? h
3772  : str2tag_core(
3773  s + 1, l - 1,
3774  // Unsets the 6 high bits of h, therefore no overflow happens
3776  h * 33) ^
3777  static_cast<unsigned char>(*s));
3778 }
3779 
3780 inline unsigned int str2tag(const std::string &s) {
3781  return str2tag_core(s.data(), s.size(), 0);
3782 }
3783 
3784 namespace udl {
3785 
3786 inline constexpr unsigned int operator""_t(const char *s, size_t l) {
3787  return str2tag_core(s, l, 0);
3788 }
3789 
3790 } // namespace udl
3791 
3792 inline std::string
3793 find_content_type(const std::string &path,
3794  const std::map<std::string, std::string> &user_data,
3795  const std::string &default_content_type) {
3796  auto ext = file_extension(path);
3797 
3798  auto it = user_data.find(ext);
3799  if (it != user_data.end()) { return it->second; }
3800 
3801  using udl::operator""_t;
3802 
3803  switch (str2tag(ext)) {
3804  default: return default_content_type;
3805 
3806  case "css"_t: return "text/css";
3807  case "csv"_t: return "text/csv";
3808  case "htm"_t:
3809  case "html"_t: return "text/html";
3810  case "js"_t:
3811  case "mjs"_t: return "text/javascript";
3812  case "txt"_t: return "text/plain";
3813  case "vtt"_t: return "text/vtt";
3814 
3815  case "apng"_t: return "image/apng";
3816  case "avif"_t: return "image/avif";
3817  case "bmp"_t: return "image/bmp";
3818  case "gif"_t: return "image/gif";
3819  case "png"_t: return "image/png";
3820  case "svg"_t: return "image/svg+xml";
3821  case "webp"_t: return "image/webp";
3822  case "ico"_t: return "image/x-icon";
3823  case "tif"_t: return "image/tiff";
3824  case "tiff"_t: return "image/tiff";
3825  case "jpg"_t:
3826  case "jpeg"_t: return "image/jpeg";
3827 
3828  case "mp4"_t: return "video/mp4";
3829  case "mpeg"_t: return "video/mpeg";
3830  case "webm"_t: return "video/webm";
3831 
3832  case "mp3"_t: return "audio/mp3";
3833  case "mpga"_t: return "audio/mpeg";
3834  case "weba"_t: return "audio/webm";
3835  case "wav"_t: return "audio/wave";
3836 
3837  case "otf"_t: return "font/otf";
3838  case "ttf"_t: return "font/ttf";
3839  case "woff"_t: return "font/woff";
3840  case "woff2"_t: return "font/woff2";
3841 
3842  case "7z"_t: return "application/x-7z-compressed";
3843  case "atom"_t: return "application/atom+xml";
3844  case "pdf"_t: return "application/pdf";
3845  case "json"_t: return "application/json";
3846  case "rss"_t: return "application/rss+xml";
3847  case "tar"_t: return "application/x-tar";
3848  case "xht"_t:
3849  case "xhtml"_t: return "application/xhtml+xml";
3850  case "xslt"_t: return "application/xslt+xml";
3851  case "xml"_t: return "application/xml";
3852  case "gz"_t: return "application/gzip";
3853  case "zip"_t: return "application/zip";
3854  case "wasm"_t: return "application/wasm";
3855  }
3856 }
3857 
3858 inline bool can_compress_content_type(const std::string &content_type) {
3859  using udl::operator""_t;
3860 
3861  auto tag = str2tag(content_type);
3862 
3863  switch (tag) {
3864  case "image/svg+xml"_t:
3865  case "application/javascript"_t:
3866  case "application/json"_t:
3867  case "application/xml"_t:
3868  case "application/protobuf"_t:
3869  case "application/xhtml+xml"_t: return true;
3870 
3871  case "text/event-stream"_t: return false;
3872 
3873  default: return !content_type.rfind("text/", 0);
3874  }
3875 }
3876 
3877 inline EncodingType encoding_type(const Request &req, const Response &res) {
3878  auto ret =
3880  if (!ret) { return EncodingType::None; }
3881 
3882  const auto &s = req.get_header_value("Accept-Encoding");
3883  (void)(s);
3884 
3885 #ifdef CPPHTTPLIB_BROTLI_SUPPORT
3886  // TODO: 'Accept-Encoding' has br, not br;q=0
3887  ret = s.find("br") != std::string::npos;
3888  if (ret) { return EncodingType::Brotli; }
3889 #endif
3890 
3891 #ifdef CPPHTTPLIB_ZLIB_SUPPORT
3892  // TODO: 'Accept-Encoding' has gzip, not gzip;q=0
3893  ret = s.find("gzip") != std::string::npos;
3894  if (ret) { return EncodingType::Gzip; }
3895 #endif
3896 
3897  return EncodingType::None;
3898 }
3899 
3900 inline bool nocompressor::compress(const char *data, size_t data_length,
3901  bool /*last*/, Callback callback) {
3902  if (!data_length) { return true; }
3903  return callback(data, data_length);
3904 }
3905 
3906 #ifdef CPPHTTPLIB_ZLIB_SUPPORT
3907 inline gzip_compressor::gzip_compressor() {
3908  std::memset(&strm_, 0, sizeof(strm_));
3909  strm_.zalloc = Z_NULL;
3910  strm_.zfree = Z_NULL;
3911  strm_.opaque = Z_NULL;
3912 
3913  is_valid_ = deflateInit2(&strm_, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 31, 8,
3914  Z_DEFAULT_STRATEGY) == Z_OK;
3915 }
3916 
3917 inline gzip_compressor::~gzip_compressor() { deflateEnd(&strm_); }
3918 
3919 inline bool gzip_compressor::compress(const char *data, size_t data_length,
3920  bool last, Callback callback) {
3921  assert(is_valid_);
3922 
3923  do {
3924  constexpr size_t max_avail_in =
3925  (std::numeric_limits<decltype(strm_.avail_in)>::max)();
3926 
3927  strm_.avail_in = static_cast<decltype(strm_.avail_in)>(
3928  (std::min)(data_length, max_avail_in));
3929  strm_.next_in = const_cast<Bytef *>(reinterpret_cast<const Bytef *>(data));
3930 
3931  data_length -= strm_.avail_in;
3932  data += strm_.avail_in;
3933 
3934  auto flush = (last && data_length == 0) ? Z_FINISH : Z_NO_FLUSH;
3935  auto ret = Z_OK;
3936 
3937  std::array<char, CPPHTTPLIB_COMPRESSION_BUFSIZ> buff{};
3938  do {
3939  strm_.avail_out = static_cast<uInt>(buff.size());
3940  strm_.next_out = reinterpret_cast<Bytef *>(buff.data());
3941 
3942  ret = deflate(&strm_, flush);
3943  if (ret == Z_STREAM_ERROR) { return false; }
3944 
3945  if (!callback(buff.data(), buff.size() - strm_.avail_out)) {
3946  return false;
3947  }
3948  } while (strm_.avail_out == 0);
3949 
3950  assert((flush == Z_FINISH && ret == Z_STREAM_END) ||
3951  (flush == Z_NO_FLUSH && ret == Z_OK));
3952  assert(strm_.avail_in == 0);
3953  } while (data_length > 0);
3954 
3955  return true;
3956 }
3957 
3958 inline gzip_decompressor::gzip_decompressor() {
3959  std::memset(&strm_, 0, sizeof(strm_));
3960  strm_.zalloc = Z_NULL;
3961  strm_.zfree = Z_NULL;
3962  strm_.opaque = Z_NULL;
3963 
3964  // 15 is the value of wbits, which should be at the maximum possible value
3965  // to ensure that any gzip stream can be decoded. The offset of 32 specifies
3966  // that the stream type should be automatically detected either gzip or
3967  // deflate.
3968  is_valid_ = inflateInit2(&strm_, 32 + 15) == Z_OK;
3969 }
3970 
3971 inline gzip_decompressor::~gzip_decompressor() { inflateEnd(&strm_); }
3972 
3973 inline bool gzip_decompressor::is_valid() const { return is_valid_; }
3974 
3975 inline bool gzip_decompressor::decompress(const char *data, size_t data_length,
3976  Callback callback) {
3977  assert(is_valid_);
3978 
3979  auto ret = Z_OK;
3980 
3981  do {
3982  constexpr size_t max_avail_in =
3983  (std::numeric_limits<decltype(strm_.avail_in)>::max)();
3984 
3985  strm_.avail_in = static_cast<decltype(strm_.avail_in)>(
3986  (std::min)(data_length, max_avail_in));
3987  strm_.next_in = const_cast<Bytef *>(reinterpret_cast<const Bytef *>(data));
3988 
3989  data_length -= strm_.avail_in;
3990  data += strm_.avail_in;
3991 
3992  std::array<char, CPPHTTPLIB_COMPRESSION_BUFSIZ> buff{};
3993  while (strm_.avail_in > 0 && ret == Z_OK) {
3994  strm_.avail_out = static_cast<uInt>(buff.size());
3995  strm_.next_out = reinterpret_cast<Bytef *>(buff.data());
3996 
3997  ret = inflate(&strm_, Z_NO_FLUSH);
3998 
3999  assert(ret != Z_STREAM_ERROR);
4000  switch (ret) {
4001  case Z_NEED_DICT:
4002  case Z_DATA_ERROR:
4003  case Z_MEM_ERROR: inflateEnd(&strm_); return false;
4004  }
4005 
4006  if (!callback(buff.data(), buff.size() - strm_.avail_out)) {
4007  return false;
4008  }
4009  }
4010 
4011  if (ret != Z_OK && ret != Z_STREAM_END) { return false; }
4012 
4013  } while (data_length > 0);
4014 
4015  return true;
4016 }
4017 #endif
4018 
4019 #ifdef CPPHTTPLIB_BROTLI_SUPPORT
4020 inline brotli_compressor::brotli_compressor() {
4021  state_ = BrotliEncoderCreateInstance(nullptr, nullptr, nullptr);
4022 }
4023 
4024 inline brotli_compressor::~brotli_compressor() {
4025  BrotliEncoderDestroyInstance(state_);
4026 }
4027 
4028 inline bool brotli_compressor::compress(const char *data, size_t data_length,
4029  bool last, Callback callback) {
4030  std::array<uint8_t, CPPHTTPLIB_COMPRESSION_BUFSIZ> buff{};
4031 
4032  auto operation = last ? BROTLI_OPERATION_FINISH : BROTLI_OPERATION_PROCESS;
4033  auto available_in = data_length;
4034  auto next_in = reinterpret_cast<const uint8_t *>(data);
4035 
4036  for (;;) {
4037  if (last) {
4038  if (BrotliEncoderIsFinished(state_)) { break; }
4039  } else {
4040  if (!available_in) { break; }
4041  }
4042 
4043  auto available_out = buff.size();
4044  auto next_out = buff.data();
4045 
4046  if (!BrotliEncoderCompressStream(state_, operation, &available_in, &next_in,
4047  &available_out, &next_out, nullptr)) {
4048  return false;
4049  }
4050 
4051  auto output_bytes = buff.size() - available_out;
4052  if (output_bytes) {
4053  callback(reinterpret_cast<const char *>(buff.data()), output_bytes);
4054  }
4055  }
4056 
4057  return true;
4058 }
4059 
4060 inline brotli_decompressor::brotli_decompressor() {
4061  decoder_s = BrotliDecoderCreateInstance(0, 0, 0);
4062  decoder_r = decoder_s ? BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT
4063  : BROTLI_DECODER_RESULT_ERROR;
4064 }
4065 
4066 inline brotli_decompressor::~brotli_decompressor() {
4067  if (decoder_s) { BrotliDecoderDestroyInstance(decoder_s); }
4068 }
4069 
4070 inline bool brotli_decompressor::is_valid() const { return decoder_s; }
4071 
4072 inline bool brotli_decompressor::decompress(const char *data,
4073  size_t data_length,
4074  Callback callback) {
4075  if (decoder_r == BROTLI_DECODER_RESULT_SUCCESS ||
4076  decoder_r == BROTLI_DECODER_RESULT_ERROR) {
4077  return 0;
4078  }
4079 
4080  auto next_in = reinterpret_cast<const uint8_t *>(data);
4081  size_t avail_in = data_length;
4082  size_t total_out;
4083 
4084  decoder_r = BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT;
4085 
4086  std::array<char, CPPHTTPLIB_COMPRESSION_BUFSIZ> buff{};
4087  while (decoder_r == BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT) {
4088  char *next_out = buff.data();
4089  size_t avail_out = buff.size();
4090 
4091  decoder_r = BrotliDecoderDecompressStream(
4092  decoder_s, &avail_in, &next_in, &avail_out,
4093  reinterpret_cast<uint8_t **>(&next_out), &total_out);
4094 
4095  if (decoder_r == BROTLI_DECODER_RESULT_ERROR) { return false; }
4096 
4097  if (!callback(buff.data(), buff.size() - avail_out)) { return false; }
4098  }
4099 
4100  return decoder_r == BROTLI_DECODER_RESULT_SUCCESS ||
4101  decoder_r == BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT;
4102 }
4103 #endif
4104 
4105 inline bool has_header(const Headers &headers, const std::string &key) {
4106  return headers.find(key) != headers.end();
4107 }
4108 
4109 inline const char *get_header_value(const Headers &headers,
4110  const std::string &key, const char *def,
4111  size_t id) {
4112  auto rng = headers.equal_range(key);
4113  auto it = rng.first;
4114  std::advance(it, static_cast<ssize_t>(id));
4115  if (it != rng.second) { return it->second.c_str(); }
4116  return def;
4117 }
4118 
4119 template <typename T>
4120 inline bool parse_header(const char *beg, const char *end, T fn) {
4121  // Skip trailing spaces and tabs.
4122  while (beg < end && is_space_or_tab(end[-1])) {
4123  end--;
4124  }
4125 
4126  auto p = beg;
4127  while (p < end && *p != ':') {
4128  p++;
4129  }
4130 
4131  if (p == end) { return false; }
4132 
4133  auto key_end = p;
4134 
4135  if (*p++ != ':') { return false; }
4136 
4137  while (p < end && is_space_or_tab(*p)) {
4138  p++;
4139  }
4140 
4141  if (p <= end) {
4142  auto key_len = key_end - beg;
4143  if (!key_len) { return false; }
4144 
4145  auto key = std::string(beg, key_end);
4146  auto val = case_ignore::equal(key, "Location")
4147  ? std::string(p, end)
4148  : decode_url(std::string(p, end), false);
4149 
4150  // NOTE: From RFC 9110:
4151  // Field values containing CR, LF, or NUL characters are
4152  // invalid and dangerous, due to the varying ways that
4153  // implementations might parse and interpret those
4154  // characters; a recipient of CR, LF, or NUL within a field
4155  // value MUST either reject the message or replace each of
4156  // those characters with SP before further processing or
4157  // forwarding of that message.
4158  static const std::string CR_LF_NUL("\r\n\0", 3);
4159  if (val.find_first_of(CR_LF_NUL) != std::string::npos) { return false; }
4160 
4161  fn(key, val);
4162  return true;
4163  }
4164 
4165  return false;
4166 }
4167 
4168 inline bool read_headers(Stream &strm, Headers &headers) {
4169  const auto bufsiz = 2048;
4170  char buf[bufsiz];
4171  stream_line_reader line_reader(strm, buf, bufsiz);
4172 
4173  for (;;) {
4174  if (!line_reader.getline()) { return false; }
4175 
4176  // Check if the line ends with CRLF.
4177  auto line_terminator_len = 2;
4178  if (line_reader.end_with_crlf()) {
4179  // Blank line indicates end of headers.
4180  if (line_reader.size() == 2) { break; }
4181  } else {
4182 #ifdef CPPHTTPLIB_ALLOW_LF_AS_LINE_TERMINATOR
4183  // Blank line indicates end of headers.
4184  if (line_reader.size() == 1) { break; }
4185  line_terminator_len = 1;
4186 #else
4187  continue; // Skip invalid line.
4188 #endif
4189  }
4190 
4191  if (line_reader.size() > CPPHTTPLIB_HEADER_MAX_LENGTH) { return false; }
4192 
4193  // Exclude line terminator
4194  auto end = line_reader.ptr() + line_reader.size() - line_terminator_len;
4195 
4196  if (!parse_header(line_reader.ptr(), end,
4197  [&](const std::string &key, std::string &val) {
4198  headers.emplace(key, val);
4199  })) {
4200  return false;
4201  }
4202  }
4203 
4204  return true;
4205 }
4206 
4207 inline bool read_content_with_length(Stream &strm, uint64_t len,
4208  Progress progress,
4210  char buf[CPPHTTPLIB_RECV_BUFSIZ];
4211 
4212  uint64_t r = 0;
4213  while (r < len) {
4214  auto read_len = static_cast<size_t>(len - r);
4215  auto n = strm.read(buf, (std::min)(read_len, CPPHTTPLIB_RECV_BUFSIZ));
4216  if (n <= 0) { return false; }
4217 
4218  if (!out(buf, static_cast<size_t>(n), r, len)) { return false; }
4219  r += static_cast<uint64_t>(n);
4220 
4221  if (progress) {
4222  if (!progress(r, len)) { return false; }
4223  }
4224  }
4225 
4226  return true;
4227 }
4228 
4229 inline void skip_content_with_length(Stream &strm, uint64_t len) {
4230  char buf[CPPHTTPLIB_RECV_BUFSIZ];
4231  uint64_t r = 0;
4232  while (r < len) {
4233  auto read_len = static_cast<size_t>(len - r);
4234  auto n = strm.read(buf, (std::min)(read_len, CPPHTTPLIB_RECV_BUFSIZ));
4235  if (n <= 0) { return; }
4236  r += static_cast<uint64_t>(n);
4237  }
4238 }
4239 
4242  char buf[CPPHTTPLIB_RECV_BUFSIZ];
4243  uint64_t r = 0;
4244  for (;;) {
4245  auto n = strm.read(buf, CPPHTTPLIB_RECV_BUFSIZ);
4246  if (n <= 0) { return true; }
4247 
4248  if (!out(buf, static_cast<size_t>(n), r, 0)) { return false; }
4249  r += static_cast<uint64_t>(n);
4250  }
4251 
4252  return true;
4253 }
4254 
4255 template <typename T>
4256 inline bool read_content_chunked(Stream &strm, T &x,
4258  const auto bufsiz = 16;
4259  char buf[bufsiz];
4260 
4261  stream_line_reader line_reader(strm, buf, bufsiz);
4262 
4263  if (!line_reader.getline()) { return false; }
4264 
4265  unsigned long chunk_len;
4266  while (true) {
4267  char *end_ptr;
4268 
4269  chunk_len = std::strtoul(line_reader.ptr(), &end_ptr, 16);
4270 
4271  if (end_ptr == line_reader.ptr()) { return false; }
4272  if (chunk_len == ULONG_MAX) { return false; }
4273 
4274  if (chunk_len == 0) { break; }
4275 
4276  if (!read_content_with_length(strm, chunk_len, nullptr, out)) {
4277  return false;
4278  }
4279 
4280  if (!line_reader.getline()) { return false; }
4281 
4282  if (strcmp(line_reader.ptr(), "\r\n") != 0) { return false; }
4283 
4284  if (!line_reader.getline()) { return false; }
4285  }
4286 
4287  assert(chunk_len == 0);
4288 
4289  // NOTE: In RFC 9112, '7.1 Chunked Transfer Coding' mentiones "The chunked
4290  // transfer coding is complete when a chunk with a chunk-size of zero is
4291  // received, possibly followed by a trailer section, and finally terminated by
4292  // an empty line". https://www.rfc-editor.org/rfc/rfc9112.html#section-7.1
4293  //
4294  // In '7.1.3. Decoding Chunked', however, the pseudo-code in the section
4295  // does't care for the existence of the final CRLF. In other words, it seems
4296  // to be ok whether the final CRLF exists or not in the chunked data.
4297  // https://www.rfc-editor.org/rfc/rfc9112.html#section-7.1.3
4298  //
4299  // According to the reference code in RFC 9112, cpp-htpplib now allows
4300  // chuncked transfer coding data without the final CRLF.
4301  if (!line_reader.getline()) { return true; }
4302 
4303  while (strcmp(line_reader.ptr(), "\r\n") != 0) {
4304  if (line_reader.size() > CPPHTTPLIB_HEADER_MAX_LENGTH) { return false; }
4305 
4306  // Exclude line terminator
4307  constexpr auto line_terminator_len = 2;
4308  auto end = line_reader.ptr() + line_reader.size() - line_terminator_len;
4309 
4310  parse_header(line_reader.ptr(), end,
4311  [&](const std::string &key, const std::string &val) {
4312  x.headers.emplace(key, val);
4313  });
4314 
4315  if (!line_reader.getline()) { return false; }
4316  }
4317 
4318  return true;
4319 }
4320 
4321 inline bool is_chunked_transfer_encoding(const Headers &headers) {
4322  return case_ignore::equal(
4323  get_header_value(headers, "Transfer-Encoding", "", 0), "chunked");
4324 }
4325 
4326 template <typename T, typename U>
4328  ContentReceiverWithProgress receiver,
4329  bool decompress, U callback) {
4330  if (decompress) {
4331  std::string encoding = x.get_header_value("Content-Encoding");
4332  std::unique_ptr<decompressor> decompressor;
4333 
4334  if (encoding == "gzip" || encoding == "deflate") {
4335 #ifdef CPPHTTPLIB_ZLIB_SUPPORT
4336  decompressor = detail::make_unique<gzip_decompressor>();
4337 #else
4339  return false;
4340 #endif
4341  } else if (encoding.find("br") != std::string::npos) {
4342 #ifdef CPPHTTPLIB_BROTLI_SUPPORT
4343  decompressor = detail::make_unique<brotli_decompressor>();
4344 #else
4346  return false;
4347 #endif
4348  }
4349 
4350  if (decompressor) {
4351  if (decompressor->is_valid()) {
4352  ContentReceiverWithProgress out = [&](const char *buf, size_t n,
4353  uint64_t off, uint64_t len) {
4354  return decompressor->decompress(buf, n,
4355  [&](const char *buf2, size_t n2) {
4356  return receiver(buf2, n2, off, len);
4357  });
4358  };
4359  return callback(std::move(out));
4360  } else {
4362  return false;
4363  }
4364  }
4365  }
4366 
4367  ContentReceiverWithProgress out = [&](const char *buf, size_t n, uint64_t off,
4368  uint64_t len) {
4369  return receiver(buf, n, off, len);
4370  };
4371  return callback(std::move(out));
4372 }
4373 
4374 template <typename T>
4375 bool read_content(Stream &strm, T &x, size_t payload_max_length, int &status,
4376  Progress progress, ContentReceiverWithProgress receiver,
4377  bool decompress) {
4378  return prepare_content_receiver(
4379  x, status, std::move(receiver), decompress,
4380  [&](const ContentReceiverWithProgress &out) {
4381  auto ret = true;
4382  auto exceed_payload_max_length = false;
4383 
4384  if (is_chunked_transfer_encoding(x.headers)) {
4385  ret = read_content_chunked(strm, x, out);
4386  } else if (!has_header(x.headers, "Content-Length")) {
4387  ret = read_content_without_length(strm, out);
4388  } else {
4389  auto len = get_header_value_u64(x.headers, "Content-Length", 0, 0);
4390  if (len > payload_max_length) {
4391  exceed_payload_max_length = true;
4392  skip_content_with_length(strm, len);
4393  ret = false;
4394  } else if (len > 0) {
4395  ret = read_content_with_length(strm, len, std::move(progress), out);
4396  }
4397  }
4398 
4399  if (!ret) {
4400  status = exceed_payload_max_length ? StatusCode::PayloadTooLarge_413
4402  }
4403  return ret;
4404  });
4405 }
4406 
4407 inline ssize_t write_request_line(Stream &strm, const std::string &method,
4408  const std::string &path) {
4409  std::string s = method;
4410  s += " ";
4411  s += path;
4412  s += " HTTP/1.1\r\n";
4413  return strm.write(s.data(), s.size());
4414 }
4415 
4416 inline ssize_t write_response_line(Stream &strm, int status) {
4417  std::string s = "HTTP/1.1 ";
4418  s += std::to_string(status);
4419  s += " ";
4421  s += "\r\n";
4422  return strm.write(s.data(), s.size());
4423 }
4424 
4425 inline ssize_t write_headers(Stream &strm, const Headers &headers) {
4426  ssize_t write_len = 0;
4427  for (const auto &x : headers) {
4428  std::string s;
4429  s = x.first;
4430  s += ": ";
4431  s += x.second;
4432  s += "\r\n";
4433 
4434  auto len = strm.write(s.data(), s.size());
4435  if (len < 0) { return len; }
4436  write_len += len;
4437  }
4438  auto len = strm.write("\r\n");
4439  if (len < 0) { return len; }
4440  write_len += len;
4441  return write_len;
4442 }
4443 
4444 inline bool write_data(Stream &strm, const char *d, size_t l) {
4445  size_t offset = 0;
4446  while (offset < l) {
4447  auto length = strm.write(d + offset, l - offset);
4448  if (length < 0) { return false; }
4449  offset += static_cast<size_t>(length);
4450  }
4451  return true;
4452 }
4453 
4454 template <typename T>
4455 inline bool write_content(Stream &strm, const ContentProvider &content_provider,
4456  size_t offset, size_t length, T is_shutting_down,
4457  Error &error) {
4458  size_t end_offset = offset + length;
4459  auto ok = true;
4460  DataSink data_sink;
4461 
4462  data_sink.write = [&](const char *d, size_t l) -> bool {
4463  if (ok) {
4464  if (strm.is_writable() && write_data(strm, d, l)) {
4465  offset += l;
4466  } else {
4467  ok = false;
4468  }
4469  }
4470  return ok;
4471  };
4472 
4473  data_sink.is_writable = [&]() -> bool { return strm.is_writable(); };
4474 
4475  while (offset < end_offset && !is_shutting_down()) {
4476  if (!strm.is_writable()) {
4477  error = Error::Write;
4478  return false;
4479  } else if (!content_provider(offset, end_offset - offset, data_sink)) {
4480  error = Error::Canceled;
4481  return false;
4482  } else if (!ok) {
4483  error = Error::Write;
4484  return false;
4485  }
4486  }
4487 
4488  error = Error::Success;
4489  return true;
4490 }
4491 
4492 template <typename T>
4493 inline bool write_content(Stream &strm, const ContentProvider &content_provider,
4494  size_t offset, size_t length,
4495  const T &is_shutting_down) {
4496  auto error = Error::Success;
4497  return write_content(strm, content_provider, offset, length, is_shutting_down,
4498  error);
4499 }
4500 
4501 template <typename T>
4502 inline bool
4504  const ContentProvider &content_provider,
4505  const T &is_shutting_down) {
4506  size_t offset = 0;
4507  auto data_available = true;
4508  auto ok = true;
4509  DataSink data_sink;
4510 
4511  data_sink.write = [&](const char *d, size_t l) -> bool {
4512  if (ok) {
4513  offset += l;
4514  if (!strm.is_writable() || !write_data(strm, d, l)) { ok = false; }
4515  }
4516  return ok;
4517  };
4518 
4519  data_sink.is_writable = [&]() -> bool { return strm.is_writable(); };
4520 
4521  data_sink.done = [&](void) { data_available = false; };
4522 
4523  while (data_available && !is_shutting_down()) {
4524  if (!strm.is_writable()) {
4525  return false;
4526  } else if (!content_provider(offset, 0, data_sink)) {
4527  return false;
4528  } else if (!ok) {
4529  return false;
4530  }
4531  }
4532  return true;
4533 }
4534 
4535 template <typename T, typename U>
4536 inline bool
4537 write_content_chunked(Stream &strm, const ContentProvider &content_provider,
4538  const T &is_shutting_down, U &compressor, Error &error) {
4539  size_t offset = 0;
4540  auto data_available = true;
4541  auto ok = true;
4542  DataSink data_sink;
4543 
4544  data_sink.write = [&](const char *d, size_t l) -> bool {
4545  if (ok) {
4546  data_available = l > 0;
4547  offset += l;
4548 
4549  std::string payload;
4550  if (compressor.compress(d, l, false,
4551  [&](const char *data, size_t data_len) {
4552  payload.append(data, data_len);
4553  return true;
4554  })) {
4555  if (!payload.empty()) {
4556  // Emit chunked response header and footer for each chunk
4557  auto chunk =
4558  from_i_to_hex(payload.size()) + "\r\n" + payload + "\r\n";
4559  if (!strm.is_writable() ||
4560  !write_data(strm, chunk.data(), chunk.size())) {
4561  ok = false;
4562  }
4563  }
4564  } else {
4565  ok = false;
4566  }
4567  }
4568  return ok;
4569  };
4570 
4571  data_sink.is_writable = [&]() -> bool { return strm.is_writable(); };
4572 
4573  auto done_with_trailer = [&](const Headers *trailer) {
4574  if (!ok) { return; }
4575 
4576  data_available = false;
4577 
4578  std::string payload;
4579  if (!compressor.compress(nullptr, 0, true,
4580  [&](const char *data, size_t data_len) {
4581  payload.append(data, data_len);
4582  return true;
4583  })) {
4584  ok = false;
4585  return;
4586  }
4587 
4588  if (!payload.empty()) {
4589  // Emit chunked response header and footer for each chunk
4590  auto chunk = from_i_to_hex(payload.size()) + "\r\n" + payload + "\r\n";
4591  if (!strm.is_writable() ||
4592  !write_data(strm, chunk.data(), chunk.size())) {
4593  ok = false;
4594  return;
4595  }
4596  }
4597 
4598  static const std::string done_marker("0\r\n");
4599  if (!write_data(strm, done_marker.data(), done_marker.size())) {
4600  ok = false;
4601  }
4602 
4603  // Trailer
4604  if (trailer) {
4605  for (const auto &kv : *trailer) {
4606  std::string field_line = kv.first + ": " + kv.second + "\r\n";
4607  if (!write_data(strm, field_line.data(), field_line.size())) {
4608  ok = false;
4609  }
4610  }
4611  }
4612 
4613  static const std::string crlf("\r\n");
4614  if (!write_data(strm, crlf.data(), crlf.size())) { ok = false; }
4615  };
4616 
4617  data_sink.done = [&](void) { done_with_trailer(nullptr); };
4618 
4619  data_sink.done_with_trailer = [&](const Headers &trailer) {
4620  done_with_trailer(&trailer);
4621  };
4622 
4623  while (data_available && !is_shutting_down()) {
4624  if (!strm.is_writable()) {
4625  error = Error::Write;
4626  return false;
4627  } else if (!content_provider(offset, 0, data_sink)) {
4628  error = Error::Canceled;
4629  return false;
4630  } else if (!ok) {
4631  error = Error::Write;
4632  return false;
4633  }
4634  }
4635 
4636  error = Error::Success;
4637  return true;
4638 }
4639 
4640 template <typename T, typename U>
4641 inline bool write_content_chunked(Stream &strm,
4642  const ContentProvider &content_provider,
4643  const T &is_shutting_down, U &compressor) {
4644  auto error = Error::Success;
4645  return write_content_chunked(strm, content_provider, is_shutting_down,
4646  compressor, error);
4647 }
4648 
4649 template <typename T>
4650 inline bool redirect(T &cli, Request &req, Response &res,
4651  const std::string &path, const std::string &location,
4652  Error &error) {
4653  Request new_req = req;
4654  new_req.path = path;
4655  new_req.redirect_count_ -= 1;
4656 
4657  if (res.status == StatusCode::SeeOther_303 &&
4658  (req.method != "GET" && req.method != "HEAD")) {
4659  new_req.method = "GET";
4660  new_req.body.clear();
4661  new_req.headers.clear();
4662  }
4663 
4664  Response new_res;
4665 
4666  auto ret = cli.send(new_req, new_res, error);
4667  if (ret) {
4668  req = new_req;
4669  res = new_res;
4670 
4671  if (res.location.empty()) { res.location = location; }
4672  }
4673  return ret;
4674 }
4675 
4676 inline std::string params_to_query_str(const Params &params) {
4677  std::string query;
4678 
4679  for (auto it = params.begin(); it != params.end(); ++it) {
4680  if (it != params.begin()) { query += "&"; }
4681  query += it->first;
4682  query += "=";
4683  query += encode_query_param(it->second);
4684  }
4685  return query;
4686 }
4687 
4688 inline void parse_query_text(const char *data, std::size_t size,
4689  Params &params) {
4690  std::set<std::string> cache;
4691  split(data, data + size, '&', [&](const char *b, const char *e) {
4692  std::string kv(b, e);
4693  if (cache.find(kv) != cache.end()) { return; }
4694  cache.insert(std::move(kv));
4695 
4696  std::string key;
4697  std::string val;
4698  divide(b, static_cast<std::size_t>(e - b), '=',
4699  [&](const char *lhs_data, std::size_t lhs_size, const char *rhs_data,
4700  std::size_t rhs_size) {
4701  key.assign(lhs_data, lhs_size);
4702  val.assign(rhs_data, rhs_size);
4703  });
4704 
4705  if (!key.empty()) {
4706  params.emplace(decode_url(key, true), decode_url(val, true));
4707  }
4708  });
4709 }
4710 
4711 inline void parse_query_text(const std::string &s, Params &params) {
4712  parse_query_text(s.data(), s.size(), params);
4713 }
4714 
4715 inline bool parse_multipart_boundary(const std::string &content_type,
4716  std::string &boundary) {
4717  auto boundary_keyword = "boundary=";
4718  auto pos = content_type.find(boundary_keyword);
4719  if (pos == std::string::npos) { return false; }
4720  auto end = content_type.find(';', pos);
4721  auto beg = pos + strlen(boundary_keyword);
4722  boundary = trim_double_quotes_copy(content_type.substr(beg, end - beg));
4723  return !boundary.empty();
4724 }
4725 
4726 inline void parse_disposition_params(const std::string &s, Params &params) {
4727  std::set<std::string> cache;
4728  split(s.data(), s.data() + s.size(), ';', [&](const char *b, const char *e) {
4729  std::string kv(b, e);
4730  if (cache.find(kv) != cache.end()) { return; }
4731  cache.insert(kv);
4732 
4733  std::string key;
4734  std::string val;
4735  split(b, e, '=', [&](const char *b2, const char *e2) {
4736  if (key.empty()) {
4737  key.assign(b2, e2);
4738  } else {
4739  val.assign(b2, e2);
4740  }
4741  });
4742 
4743  if (!key.empty()) {
4744  params.emplace(trim_double_quotes_copy((key)),
4745  trim_double_quotes_copy((val)));
4746  }
4747  });
4748 }
4749 
4750 #ifdef CPPHTTPLIB_NO_EXCEPTIONS
4751 inline bool parse_range_header(const std::string &s, Ranges &ranges) {
4752 #else
4753 inline bool parse_range_header(const std::string &s, Ranges &ranges) try {
4754 #endif
4755  auto is_valid = [](const std::string &str) {
4756  return std::all_of(str.cbegin(), str.cend(),
4757  [](unsigned char c) { return std::isdigit(c); });
4758  };
4759 
4760  if (s.size() > 7 && s.compare(0, 6, "bytes=") == 0) {
4761  const auto pos = static_cast<size_t>(6);
4762  const auto len = static_cast<size_t>(s.size() - 6);
4763  auto all_valid_ranges = true;
4764  split(&s[pos], &s[pos + len], ',', [&](const char *b, const char *e) {
4765  if (!all_valid_ranges) { return; }
4766 
4767  const auto it = std::find(b, e, '-');
4768  if (it == e) {
4769  all_valid_ranges = false;
4770  return;
4771  }
4772 
4773  const auto lhs = std::string(b, it);
4774  const auto rhs = std::string(it + 1, e);
4775  if (!is_valid(lhs) || !is_valid(rhs)) {
4776  all_valid_ranges = false;
4777  return;
4778  }
4779 
4780  const auto first =
4781  static_cast<ssize_t>(lhs.empty() ? -1 : std::stoll(lhs));
4782  const auto last =
4783  static_cast<ssize_t>(rhs.empty() ? -1 : std::stoll(rhs));
4784  if ((first == -1 && last == -1) ||
4785  (first != -1 && last != -1 && first > last)) {
4786  all_valid_ranges = false;
4787  return;
4788  }
4789 
4790  ranges.emplace_back(first, last);
4791  });
4792  return all_valid_ranges && !ranges.empty();
4793  }
4794  return false;
4795 #ifdef CPPHTTPLIB_NO_EXCEPTIONS
4796 }
4797 #else
4798 } catch (...) { return false; }
4799 #endif
4800 
4802 public:
4803  MultipartFormDataParser() = default;
4804 
4805  void set_boundary(std::string &&boundary) {
4806  boundary_ = boundary;
4807  dash_boundary_crlf_ = dash_ + boundary_ + crlf_;
4808  crlf_dash_boundary_ = crlf_ + dash_ + boundary_;
4809  }
4810 
4811  bool is_valid() const { return is_valid_; }
4812 
4813  bool parse(const char *buf, size_t n, const ContentReceiver &content_callback,
4814  const MultipartContentHeader &header_callback) {
4815 
4816  buf_append(buf, n);
4817 
4818  while (buf_size() > 0) {
4819  switch (state_) {
4820  case 0: { // Initial boundary
4821  buf_erase(buf_find(dash_boundary_crlf_));
4822  if (dash_boundary_crlf_.size() > buf_size()) { return true; }
4823  if (!buf_start_with(dash_boundary_crlf_)) { return false; }
4824  buf_erase(dash_boundary_crlf_.size());
4825  state_ = 1;
4826  break;
4827  }
4828  case 1: { // New entry
4829  clear_file_info();
4830  state_ = 2;
4831  break;
4832  }
4833  case 2: { // Headers
4834  auto pos = buf_find(crlf_);
4835  if (pos > CPPHTTPLIB_HEADER_MAX_LENGTH) { return false; }
4836  while (pos < buf_size()) {
4837  // Empty line
4838  if (pos == 0) {
4839  if (!header_callback(file_)) {
4840  is_valid_ = false;
4841  return false;
4842  }
4843  buf_erase(crlf_.size());
4844  state_ = 3;
4845  break;
4846  }
4847 
4848  const auto header = buf_head(pos);
4849 
4850  if (!parse_header(header.data(), header.data() + header.size(),
4851  [&](const std::string &, const std::string &) {})) {
4852  is_valid_ = false;
4853  return false;
4854  }
4855 
4856  static const std::string header_content_type = "Content-Type:";
4857 
4858  if (start_with_case_ignore(header, header_content_type)) {
4859  file_.content_type =
4860  trim_copy(header.substr(header_content_type.size()));
4861  } else {
4862  static const std::regex re_content_disposition(
4863  R"~(^Content-Disposition:\s*form-data;\s*(.*)$)~",
4864  std::regex_constants::icase);
4865 
4866  std::smatch m;
4867  if (std::regex_match(header, m, re_content_disposition)) {
4868  Params params;
4869  parse_disposition_params(m[1], params);
4870 
4871  auto it = params.find("name");
4872  if (it != params.end()) {
4873  file_.name = it->second;
4874  } else {
4875  is_valid_ = false;
4876  return false;
4877  }
4878 
4879  it = params.find("filename");
4880  if (it != params.end()) { file_.filename = it->second; }
4881 
4882  it = params.find("filename*");
4883  if (it != params.end()) {
4884  // Only allow UTF-8 enconnding...
4885  static const std::regex re_rfc5987_encoding(
4886  R"~(^UTF-8''(.+?)$)~", std::regex_constants::icase);
4887 
4888  std::smatch m2;
4889  if (std::regex_match(it->second, m2, re_rfc5987_encoding)) {
4890  file_.filename = decode_url(m2[1], false); // override...
4891  } else {
4892  is_valid_ = false;
4893  return false;
4894  }
4895  }
4896  }
4897  }
4898  buf_erase(pos + crlf_.size());
4899  pos = buf_find(crlf_);
4900  }
4901  if (state_ != 3) { return true; }
4902  break;
4903  }
4904  case 3: { // Body
4905  if (crlf_dash_boundary_.size() > buf_size()) { return true; }
4906  auto pos = buf_find(crlf_dash_boundary_);
4907  if (pos < buf_size()) {
4908  if (!content_callback(buf_data(), pos)) {
4909  is_valid_ = false;
4910  return false;
4911  }
4912  buf_erase(pos + crlf_dash_boundary_.size());
4913  state_ = 4;
4914  } else {
4915  auto len = buf_size() - crlf_dash_boundary_.size();
4916  if (len > 0) {
4917  if (!content_callback(buf_data(), len)) {
4918  is_valid_ = false;
4919  return false;
4920  }
4921  buf_erase(len);
4922  }
4923  return true;
4924  }
4925  break;
4926  }
4927  case 4: { // Boundary
4928  if (crlf_.size() > buf_size()) { return true; }
4929  if (buf_start_with(crlf_)) {
4930  buf_erase(crlf_.size());
4931  state_ = 1;
4932  } else {
4933  if (dash_.size() > buf_size()) { return true; }
4934  if (buf_start_with(dash_)) {
4935  buf_erase(dash_.size());
4936  is_valid_ = true;
4937  buf_erase(buf_size()); // Remove epilogue
4938  } else {
4939  return true;
4940  }
4941  }
4942  break;
4943  }
4944  }
4945  }
4946 
4947  return true;
4948  }
4949 
4950 private:
4951  void clear_file_info() {
4952  file_.name.clear();
4953  file_.filename.clear();
4954  file_.content_type.clear();
4955  }
4956 
4957  bool start_with_case_ignore(const std::string &a,
4958  const std::string &b) const {
4959  if (a.size() < b.size()) { return false; }
4960  for (size_t i = 0; i < b.size(); i++) {
4961  if (case_ignore::to_lower(a[i]) != case_ignore::to_lower(b[i])) {
4962  return false;
4963  }
4964  }
4965  return true;
4966  }
4967 
4968  const std::string dash_ = "--";
4969  const std::string crlf_ = "\r\n";
4970  std::string boundary_;
4971  std::string dash_boundary_crlf_;
4972  std::string crlf_dash_boundary_;
4973 
4974  size_t state_ = 0;
4975  bool is_valid_ = false;
4976  MultipartFormData file_;
4977 
4978  // Buffer
4979  bool start_with(const std::string &a, size_t spos, size_t epos,
4980  const std::string &b) const {
4981  if (epos - spos < b.size()) { return false; }
4982  for (size_t i = 0; i < b.size(); i++) {
4983  if (a[i + spos] != b[i]) { return false; }
4984  }
4985  return true;
4986  }
4987 
4988  size_t buf_size() const { return buf_epos_ - buf_spos_; }
4989 
4990  const char *buf_data() const { return &buf_[buf_spos_]; }
4991 
4992  std::string buf_head(size_t l) const { return buf_.substr(buf_spos_, l); }
4993 
4994  bool buf_start_with(const std::string &s) const {
4995  return start_with(buf_, buf_spos_, buf_epos_, s);
4996  }
4997 
4998  size_t buf_find(const std::string &s) const {
4999  auto c = s.front();
5000 
5001  size_t off = buf_spos_;
5002  while (off < buf_epos_) {
5003  auto pos = off;
5004  while (true) {
5005  if (pos == buf_epos_) { return buf_size(); }
5006  if (buf_[pos] == c) { break; }
5007  pos++;
5008  }
5009 
5010  auto remaining_size = buf_epos_ - pos;
5011  if (s.size() > remaining_size) { return buf_size(); }
5012 
5013  if (start_with(buf_, pos, buf_epos_, s)) { return pos - buf_spos_; }
5014 
5015  off = pos + 1;
5016  }
5017 
5018  return buf_size();
5019  }
5020 
5021  void buf_append(const char *data, size_t n) {
5022  auto remaining_size = buf_size();
5023  if (remaining_size > 0 && buf_spos_ > 0) {
5024  for (size_t i = 0; i < remaining_size; i++) {
5025  buf_[i] = buf_[buf_spos_ + i];
5026  }
5027  }
5028  buf_spos_ = 0;
5029  buf_epos_ = remaining_size;
5030 
5031  if (remaining_size + n > buf_.size()) { buf_.resize(remaining_size + n); }
5032 
5033  for (size_t i = 0; i < n; i++) {
5034  buf_[buf_epos_ + i] = data[i];
5035  }
5036  buf_epos_ += n;
5037  }
5038 
5039  void buf_erase(size_t size) { buf_spos_ += size; }
5040 
5041  std::string buf_;
5042  size_t buf_spos_ = 0;
5043  size_t buf_epos_ = 0;
5044 };
5045 
5046 inline std::string random_string(size_t length) {
5047  static const char data[] =
5048  "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
5049 
5050  // std::random_device might actually be deterministic on some
5051  // platforms, but due to lack of support in the c++ standard library,
5052  // doing better requires either some ugly hacks or breaking portability.
5053  static std::random_device seed_gen;
5054 
5055  // Request 128 bits of entropy for initialization
5056  static std::seed_seq seed_sequence{seed_gen(), seed_gen(), seed_gen(),
5057  seed_gen()};
5058 
5059  static std::mt19937 engine(seed_sequence);
5060 
5061  std::string result;
5062  for (size_t i = 0; i < length; i++) {
5063  result += data[engine() % (sizeof(data) - 1)];
5064  }
5065  return result;
5066 }
5067 
5068 inline std::string make_multipart_data_boundary() {
5069  return "--cpp-httplib-multipart-data-" + detail::random_string(16);
5070 }
5071 
5072 inline bool is_multipart_boundary_chars_valid(const std::string &boundary) {
5073  auto valid = true;
5074  for (size_t i = 0; i < boundary.size(); i++) {
5075  auto c = boundary[i];
5076  if (!std::isalnum(c) && c != '-' && c != '_') {
5077  valid = false;
5078  break;
5079  }
5080  }
5081  return valid;
5082 }
5083 
5084 template <typename T>
5085 inline std::string
5087  const std::string &boundary) {
5088  std::string body = "--" + boundary + "\r\n";
5089  body += "Content-Disposition: form-data; name=\"" + item.name + "\"";
5090  if (!item.filename.empty()) {
5091  body += "; filename=\"" + item.filename + "\"";
5092  }
5093  body += "\r\n";
5094  if (!item.content_type.empty()) {
5095  body += "Content-Type: " + item.content_type + "\r\n";
5096  }
5097  body += "\r\n";
5098 
5099  return body;
5100 }
5101 
5102 inline std::string serialize_multipart_formdata_item_end() { return "\r\n"; }
5103 
5104 inline std::string
5105 serialize_multipart_formdata_finish(const std::string &boundary) {
5106  return "--" + boundary + "--\r\n";
5107 }
5108 
5109 inline std::string
5111  return "multipart/form-data; boundary=" + boundary;
5112 }
5113 
5114 inline std::string
5116  const std::string &boundary, bool finish = true) {
5117  std::string body;
5118 
5119  for (const auto &item : items) {
5120  body += serialize_multipart_formdata_item_begin(item, boundary);
5121  body += item.content + serialize_multipart_formdata_item_end();
5122  }
5123 
5124  if (finish) { body += serialize_multipart_formdata_finish(boundary); }
5125 
5126  return body;
5127 }
5128 
5129 inline bool range_error(Request &req, Response &res) {
5130  if (!req.ranges.empty() && 200 <= res.status && res.status < 300) {
5131  ssize_t contant_len = static_cast<ssize_t>(
5132  res.content_length_ ? res.content_length_ : res.body.size());
5133 
5134  ssize_t prev_first_pos = -1;
5135  ssize_t prev_last_pos = -1;
5136  size_t overwrapping_count = 0;
5137 
5138  // NOTE: The following Range check is based on '14.2. Range' in RFC 9110
5139  // 'HTTP Semantics' to avoid potential denial-of-service attacks.
5140  // https://www.rfc-editor.org/rfc/rfc9110#section-14.2
5141 
5142  // Too many ranges
5143  if (req.ranges.size() > CPPHTTPLIB_RANGE_MAX_COUNT) { return true; }
5144 
5145  for (auto &r : req.ranges) {
5146  auto &first_pos = r.first;
5147  auto &last_pos = r.second;
5148 
5149  if (first_pos == -1 && last_pos == -1) {
5150  first_pos = 0;
5151  last_pos = contant_len;
5152  }
5153 
5154  if (first_pos == -1) {
5155  first_pos = contant_len - last_pos;
5156  last_pos = contant_len - 1;
5157  }
5158 
5159  if (last_pos == -1) { last_pos = contant_len - 1; }
5160 
5161  // Range must be within content length
5162  if (!(0 <= first_pos && first_pos <= last_pos &&
5163  last_pos <= contant_len - 1)) {
5164  return true;
5165  }
5166 
5167  // Ranges must be in ascending order
5168  if (first_pos <= prev_first_pos) { return true; }
5169 
5170  // Request must not have more than two overlapping ranges
5171  if (first_pos <= prev_last_pos) {
5172  overwrapping_count++;
5173  if (overwrapping_count > 2) { return true; }
5174  }
5175 
5176  prev_first_pos = (std::max)(prev_first_pos, first_pos);
5177  prev_last_pos = (std::max)(prev_last_pos, last_pos);
5178  }
5179  }
5180 
5181  return false;
5182 }
5183 
5184 inline std::pair<size_t, size_t>
5185 get_range_offset_and_length(Range r, size_t content_length) {
5186  assert(r.first != -1 && r.second != -1);
5187  assert(0 <= r.first && r.first < static_cast<ssize_t>(content_length));
5188  assert(r.first <= r.second &&
5189  r.second < static_cast<ssize_t>(content_length));
5190  (void)(content_length);
5191  return std::make_pair(r.first, static_cast<size_t>(r.second - r.first) + 1);
5192 }
5193 
5195  const std::pair<size_t, size_t> &offset_and_length, size_t content_length) {
5196  auto st = offset_and_length.first;
5197  auto ed = st + offset_and_length.second - 1;
5198 
5199  std::string field = "bytes ";
5200  field += std::to_string(st);
5201  field += "-";
5202  field += std::to_string(ed);
5203  field += "/";
5204  field += std::to_string(content_length);
5205  return field;
5206 }
5207 
5208 template <typename SToken, typename CToken, typename Content>
5210  const std::string &boundary,
5211  const std::string &content_type,
5212  size_t content_length, SToken stoken,
5213  CToken ctoken, Content content) {
5214  for (size_t i = 0; i < req.ranges.size(); i++) {
5215  ctoken("--");
5216  stoken(boundary);
5217  ctoken("\r\n");
5218  if (!content_type.empty()) {
5219  ctoken("Content-Type: ");
5220  stoken(content_type);
5221  ctoken("\r\n");
5222  }
5223 
5224  auto offset_and_length =
5225  get_range_offset_and_length(req.ranges[i], content_length);
5226 
5227  ctoken("Content-Range: ");
5228  stoken(make_content_range_header_field(offset_and_length, content_length));
5229  ctoken("\r\n");
5230  ctoken("\r\n");
5231 
5232  if (!content(offset_and_length.first, offset_and_length.second)) {
5233  return false;
5234  }
5235  ctoken("\r\n");
5236  }
5237 
5238  ctoken("--");
5239  stoken(boundary);
5240  ctoken("--");
5241 
5242  return true;
5243 }
5244 
5245 inline void make_multipart_ranges_data(const Request &req, Response &res,
5246  const std::string &boundary,
5247  const std::string &content_type,
5248  size_t content_length,
5249  std::string &data) {
5251  req, boundary, content_type, content_length,
5252  [&](const std::string &token) { data += token; },
5253  [&](const std::string &token) { data += token; },
5254  [&](size_t offset, size_t length) {
5255  assert(offset + length <= content_length);
5256  data += res.body.substr(offset, length);
5257  return true;
5258  });
5259 }
5260 
5262  const std::string &boundary,
5263  const std::string &content_type,
5264  size_t content_length) {
5265  size_t data_length = 0;
5266 
5268  req, boundary, content_type, content_length,
5269  [&](const std::string &token) { data_length += token.size(); },
5270  [&](const std::string &token) { data_length += token.size(); },
5271  [&](size_t /*offset*/, size_t length) {
5272  data_length += length;
5273  return true;
5274  });
5275 
5276  return data_length;
5277 }
5278 
5279 template <typename T>
5280 inline bool
5282  const std::string &boundary,
5283  const std::string &content_type,
5284  size_t content_length, const T &is_shutting_down) {
5286  req, boundary, content_type, content_length,
5287  [&](const std::string &token) { strm.write(token); },
5288  [&](const std::string &token) { strm.write(token); },
5289  [&](size_t offset, size_t length) {
5290  return write_content(strm, res.content_provider_, offset, length,
5291  is_shutting_down);
5292  });
5293 }
5294 
5295 inline bool expect_content(const Request &req) {
5296  if (req.method == "POST" || req.method == "PUT" || req.method == "PATCH" ||
5297  req.method == "PRI" || req.method == "DELETE") {
5298  return true;
5299  }
5300  // TODO: check if Content-Length is set
5301  return false;
5302 }
5303 
5304 inline bool has_crlf(const std::string &s) {
5305  auto p = s.c_str();
5306  while (*p) {
5307  if (*p == '\r' || *p == '\n') { return true; }
5308  p++;
5309  }
5310  return false;
5311 }
5312 
5313 #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
5314 inline std::string message_digest(const std::string &s, const EVP_MD *algo) {
5315  auto context = std::unique_ptr<EVP_MD_CTX, decltype(&EVP_MD_CTX_free)>(
5316  EVP_MD_CTX_new(), EVP_MD_CTX_free);
5317 
5318  unsigned int hash_length = 0;
5319  unsigned char hash[EVP_MAX_MD_SIZE];
5320 
5321  EVP_DigestInit_ex(context.get(), algo, nullptr);
5322  EVP_DigestUpdate(context.get(), s.c_str(), s.size());
5323  EVP_DigestFinal_ex(context.get(), hash, &hash_length);
5324 
5325  std::stringstream ss;
5326  for (auto i = 0u; i < hash_length; ++i) {
5327  ss << std::hex << std::setw(2) << std::setfill('0')
5328  << static_cast<unsigned int>(hash[i]);
5329  }
5330 
5331  return ss.str();
5332 }
5333 
5334 inline std::string MD5(const std::string &s) {
5335  return message_digest(s, EVP_md5());
5336 }
5337 
5338 inline std::string SHA_256(const std::string &s) {
5339  return message_digest(s, EVP_sha256());
5340 }
5341 
5342 inline std::string SHA_512(const std::string &s) {
5343  return message_digest(s, EVP_sha512());
5344 }
5345 #endif
5346 
5347 #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
5348 #ifdef _WIN32
5349 // NOTE: This code came up with the following stackoverflow post:
5350 // https://stackoverflow.com/questions/9507184/can-openssl-on-windows-use-the-system-certificate-store
5351 inline bool load_system_certs_on_windows(X509_STORE *store) {
5352  auto hStore = CertOpenSystemStoreW((HCRYPTPROV_LEGACY)NULL, L"ROOT");
5353  if (!hStore) { return false; }
5354 
5355  auto result = false;
5356  PCCERT_CONTEXT pContext = NULL;
5357  while ((pContext = CertEnumCertificatesInStore(hStore, pContext)) !=
5358  nullptr) {
5359  auto encoded_cert =
5360  static_cast<const unsigned char *>(pContext->pbCertEncoded);
5361 
5362  auto x509 = d2i_X509(NULL, &encoded_cert, pContext->cbCertEncoded);
5363  if (x509) {
5364  X509_STORE_add_cert(store, x509);
5365  X509_free(x509);
5366  result = true;
5367  }
5368  }
5369 
5370  CertFreeCertificateContext(pContext);
5371  CertCloseStore(hStore, 0);
5372 
5373  return result;
5374 }
5375 #elif defined(CPPHTTPLIB_USE_CERTS_FROM_MACOSX_KEYCHAIN) && defined(__APPLE__)
5376 #if TARGET_OS_OSX
5377 template <typename T>
5378 using CFObjectPtr =
5379  std::unique_ptr<typename std::remove_pointer<T>::type, void (*)(CFTypeRef)>;
5380 
5381 inline void cf_object_ptr_deleter(CFTypeRef obj) {
5382  if (obj) { CFRelease(obj); }
5383 }
5384 
5385 inline bool retrieve_certs_from_keychain(CFObjectPtr<CFArrayRef> &certs) {
5386  CFStringRef keys[] = {kSecClass, kSecMatchLimit, kSecReturnRef};
5387  CFTypeRef values[] = {kSecClassCertificate, kSecMatchLimitAll,
5388  kCFBooleanTrue};
5389 
5390  CFObjectPtr<CFDictionaryRef> query(
5391  CFDictionaryCreate(nullptr, reinterpret_cast<const void **>(keys), values,
5392  sizeof(keys) / sizeof(keys[0]),
5393  &kCFTypeDictionaryKeyCallBacks,
5394  &kCFTypeDictionaryValueCallBacks),
5395  cf_object_ptr_deleter);
5396 
5397  if (!query) { return false; }
5398 
5399  CFTypeRef security_items = nullptr;
5400  if (SecItemCopyMatching(query.get(), &security_items) != errSecSuccess ||
5401  CFArrayGetTypeID() != CFGetTypeID(security_items)) {
5402  return false;
5403  }
5404 
5405  certs.reset(reinterpret_cast<CFArrayRef>(security_items));
5406  return true;
5407 }
5408 
5409 inline bool retrieve_root_certs_from_keychain(CFObjectPtr<CFArrayRef> &certs) {
5410  CFArrayRef root_security_items = nullptr;
5411  if (SecTrustCopyAnchorCertificates(&root_security_items) != errSecSuccess) {
5412  return false;
5413  }
5414 
5415  certs.reset(root_security_items);
5416  return true;
5417 }
5418 
5419 inline bool add_certs_to_x509_store(CFArrayRef certs, X509_STORE *store) {
5420  auto result = false;
5421  for (auto i = 0; i < CFArrayGetCount(certs); ++i) {
5422  const auto cert = reinterpret_cast<const __SecCertificate *>(
5423  CFArrayGetValueAtIndex(certs, i));
5424 
5425  if (SecCertificateGetTypeID() != CFGetTypeID(cert)) { continue; }
5426 
5427  CFDataRef cert_data = nullptr;
5428  if (SecItemExport(cert, kSecFormatX509Cert, 0, nullptr, &cert_data) !=
5429  errSecSuccess) {
5430  continue;
5431  }
5432 
5433  CFObjectPtr<CFDataRef> cert_data_ptr(cert_data, cf_object_ptr_deleter);
5434 
5435  auto encoded_cert = static_cast<const unsigned char *>(
5436  CFDataGetBytePtr(cert_data_ptr.get()));
5437 
5438  auto x509 =
5439  d2i_X509(NULL, &encoded_cert, CFDataGetLength(cert_data_ptr.get()));
5440 
5441  if (x509) {
5442  X509_STORE_add_cert(store, x509);
5443  X509_free(x509);
5444  result = true;
5445  }
5446  }
5447 
5448  return result;
5449 }
5450 
5451 inline bool load_system_certs_on_macos(X509_STORE *store) {
5452  auto result = false;
5453  CFObjectPtr<CFArrayRef> certs(nullptr, cf_object_ptr_deleter);
5454  if (retrieve_certs_from_keychain(certs) && certs) {
5455  result = add_certs_to_x509_store(certs.get(), store);
5456  }
5457 
5458  if (retrieve_root_certs_from_keychain(certs) && certs) {
5459  result = add_certs_to_x509_store(certs.get(), store) || result;
5460  }
5461 
5462  return result;
5463 }
5464 #endif // TARGET_OS_OSX
5465 #endif // _WIN32
5466 #endif // CPPHTTPLIB_OPENSSL_SUPPORT
5467 
5468 #ifdef _WIN32
5469 class WSInit {
5470 public:
5471  WSInit() {
5472  WSADATA wsaData;
5473  if (WSAStartup(0x0002, &wsaData) == 0) is_valid_ = true;
5474  }
5475 
5476  ~WSInit() {
5477  if (is_valid_) WSACleanup();
5478  }
5479 
5480  bool is_valid_ = false;
5481 };
5482 
5483 static WSInit wsinit_;
5484 #endif
5485 
5486 #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
5487 inline std::pair<std::string, std::string> make_digest_authentication_header(
5488  const Request &req, const std::map<std::string, std::string> &auth,
5489  size_t cnonce_count, const std::string &cnonce, const std::string &username,
5490  const std::string &password, bool is_proxy = false) {
5491  std::string nc;
5492  {
5493  std::stringstream ss;
5494  ss << std::setfill('0') << std::setw(8) << std::hex << cnonce_count;
5495  nc = ss.str();
5496  }
5497 
5498  std::string qop;
5499  if (auth.find("qop") != auth.end()) {
5500  qop = auth.at("qop");
5501  if (qop.find("auth-int") != std::string::npos) {
5502  qop = "auth-int";
5503  } else if (qop.find("auth") != std::string::npos) {
5504  qop = "auth";
5505  } else {
5506  qop.clear();
5507  }
5508  }
5509 
5510  std::string algo = "MD5";
5511  if (auth.find("algorithm") != auth.end()) { algo = auth.at("algorithm"); }
5512 
5513  std::string response;
5514  {
5515  auto H = algo == "SHA-256" ? detail::SHA_256
5516  : algo == "SHA-512" ? detail::SHA_512
5517  : detail::MD5;
5518 
5519  auto A1 = username + ":" + auth.at("realm") + ":" + password;
5520 
5521  auto A2 = req.method + ":" + req.path;
5522  if (qop == "auth-int") { A2 += ":" + H(req.body); }
5523 
5524  if (qop.empty()) {
5525  response = H(H(A1) + ":" + auth.at("nonce") + ":" + H(A2));
5526  } else {
5527  response = H(H(A1) + ":" + auth.at("nonce") + ":" + nc + ":" + cnonce +
5528  ":" + qop + ":" + H(A2));
5529  }
5530  }
5531 
5532  auto opaque = (auth.find("opaque") != auth.end()) ? auth.at("opaque") : "";
5533 
5534  auto field = "Digest username=\"" + username + "\", realm=\"" +
5535  auth.at("realm") + "\", nonce=\"" + auth.at("nonce") +
5536  "\", uri=\"" + req.path + "\", algorithm=" + algo +
5537  (qop.empty() ? ", response=\""
5538  : ", qop=" + qop + ", nc=" + nc + ", cnonce=\"" +
5539  cnonce + "\", response=\"") +
5540  response + "\"" +
5541  (opaque.empty() ? "" : ", opaque=\"" + opaque + "\"");
5542 
5543  auto key = is_proxy ? "Proxy-Authorization" : "Authorization";
5544  return std::make_pair(key, field);
5545 }
5546 #endif
5547 
5548 inline bool parse_www_authenticate(const Response &res,
5549  std::map<std::string, std::string> &auth,
5550  bool is_proxy) {
5551  auto auth_key = is_proxy ? "Proxy-Authenticate" : "WWW-Authenticate";
5552  if (res.has_header(auth_key)) {
5553  static auto re = std::regex(R"~((?:(?:,\s*)?(.+?)=(?:"(.*?)"|([^,]*))))~");
5554  auto s = res.get_header_value(auth_key);
5555  auto pos = s.find(' ');
5556  if (pos != std::string::npos) {
5557  auto type = s.substr(0, pos);
5558  if (type == "Basic") {
5559  return false;
5560  } else if (type == "Digest") {
5561  s = s.substr(pos + 1);
5562  auto beg = std::sregex_iterator(s.begin(), s.end(), re);
5563  for (auto i = beg; i != std::sregex_iterator(); ++i) {
5564  const auto &m = *i;
5565  auto key = s.substr(static_cast<size_t>(m.position(1)),
5566  static_cast<size_t>(m.length(1)));
5567  auto val = m.length(2) > 0
5568  ? s.substr(static_cast<size_t>(m.position(2)),
5569  static_cast<size_t>(m.length(2)))
5570  : s.substr(static_cast<size_t>(m.position(3)),
5571  static_cast<size_t>(m.length(3)));
5572  auth[key] = val;
5573  }
5574  return true;
5575  }
5576  }
5577  }
5578  return false;
5579 }
5580 
5582 public:
5584  ContentProviderWithoutLength &&content_provider)
5585  : content_provider_(content_provider) {}
5586 
5587  bool operator()(size_t offset, size_t, DataSink &sink) {
5588  return content_provider_(offset, sink);
5589  }
5590 
5591 private:
5592  ContentProviderWithoutLength content_provider_;
5593 };
5594 
5595 } // namespace detail
5596 
5597 inline std::string hosted_at(const std::string &hostname) {
5598  std::vector<std::string> addrs;
5599  hosted_at(hostname, addrs);
5600  if (addrs.empty()) { return std::string(); }
5601  return addrs[0];
5602 }
5603 
5604 inline void hosted_at(const std::string &hostname,
5605  std::vector<std::string> &addrs) {
5606  struct addrinfo hints;
5607  struct addrinfo *result;
5608 
5609  memset(&hints, 0, sizeof(struct addrinfo));
5610  hints.ai_family = AF_UNSPEC;
5611  hints.ai_socktype = SOCK_STREAM;
5612  hints.ai_protocol = 0;
5613 
5614  if (getaddrinfo(hostname.c_str(), nullptr, &hints, &result)) {
5615 #if defined __linux__ && !defined __ANDROID__
5616  res_init();
5617 #endif
5618  return;
5619  }
5620  auto se = detail::scope_exit([&] { freeaddrinfo(result); });
5621 
5622  for (auto rp = result; rp; rp = rp->ai_next) {
5623  const auto &addr =
5624  *reinterpret_cast<struct sockaddr_storage *>(rp->ai_addr);
5625  std::string ip;
5626  auto dummy = -1;
5627  if (detail::get_ip_and_port(addr, sizeof(struct sockaddr_storage), ip,
5628  dummy)) {
5629  addrs.push_back(ip);
5630  }
5631  }
5632 }
5633 
5634 inline std::string append_query_params(const std::string &path,
5635  const Params &params) {
5636  std::string path_with_query = path;
5637  const static std::regex re("[^?]+\\?.*");
5638  auto delm = std::regex_match(path, re) ? '&' : '?';
5639  path_with_query += delm + detail::params_to_query_str(params);
5640  return path_with_query;
5641 }
5642 
5643 // Header utilities
5644 inline std::pair<std::string, std::string>
5645 make_range_header(const Ranges &ranges) {
5646  std::string field = "bytes=";
5647  auto i = 0;
5648  for (const auto &r : ranges) {
5649  if (i != 0) { field += ", "; }
5650  if (r.first != -1) { field += std::to_string(r.first); }
5651  field += '-';
5652  if (r.second != -1) { field += std::to_string(r.second); }
5653  i++;
5654  }
5655  return std::make_pair("Range", std::move(field));
5656 }
5657 
5658 inline std::pair<std::string, std::string>
5659 make_basic_authentication_header(const std::string &username,
5660  const std::string &password, bool is_proxy) {
5661  auto field = "Basic " + detail::base64_encode(username + ":" + password);
5662  auto key = is_proxy ? "Proxy-Authorization" : "Authorization";
5663  return std::make_pair(key, std::move(field));
5664 }
5665 
5666 inline std::pair<std::string, std::string>
5668  bool is_proxy = false) {
5669  auto field = "Bearer " + token;
5670  auto key = is_proxy ? "Proxy-Authorization" : "Authorization";
5671  return std::make_pair(key, std::move(field));
5672 }
5673 
5674 // Request implementation
5675 inline bool Request::has_header(const std::string &key) const {
5676  return detail::has_header(headers, key);
5677 }
5678 
5679 inline std::string Request::get_header_value(const std::string &key,
5680  const char *def, size_t id) const {
5681  return detail::get_header_value(headers, key, def, id);
5682 }
5683 
5684 inline size_t Request::get_header_value_count(const std::string &key) const {
5685  auto r = headers.equal_range(key);
5686  return static_cast<size_t>(std::distance(r.first, r.second));
5687 }
5688 
5689 inline void Request::set_header(const std::string &key,
5690  const std::string &val) {
5691  if (!detail::has_crlf(key) && !detail::has_crlf(val)) {
5692  headers.emplace(key, val);
5693  }
5694 }
5695 
5696 inline bool Request::has_param(const std::string &key) const {
5697  return params.find(key) != params.end();
5698 }
5699 
5700 inline std::string Request::get_param_value(const std::string &key,
5701  size_t id) const {
5702  auto rng = params.equal_range(key);
5703  auto it = rng.first;
5704  std::advance(it, static_cast<ssize_t>(id));
5705  if (it != rng.second) { return it->second; }
5706  return std::string();
5707 }
5708 
5709 inline size_t Request::get_param_value_count(const std::string &key) const {
5710  auto r = params.equal_range(key);
5711  return static_cast<size_t>(std::distance(r.first, r.second));
5712 }
5713 
5714 inline bool Request::is_multipart_form_data() const {
5715  const auto &content_type = get_header_value("Content-Type");
5716  return !content_type.rfind("multipart/form-data", 0);
5717 }
5718 
5719 inline bool Request::has_file(const std::string &key) const {
5720  return files.find(key) != files.end();
5721 }
5722 
5723 inline MultipartFormData Request::get_file_value(const std::string &key) const {
5724  auto it = files.find(key);
5725  if (it != files.end()) { return it->second; }
5726  return MultipartFormData();
5727 }
5728 
5729 inline std::vector<MultipartFormData>
5730 Request::get_file_values(const std::string &key) const {
5731  std::vector<MultipartFormData> values;
5732  auto rng = files.equal_range(key);
5733  for (auto it = rng.first; it != rng.second; it++) {
5734  values.push_back(it->second);
5735  }
5736  return values;
5737 }
5738 
5739 // Response implementation
5740 inline bool Response::has_header(const std::string &key) const {
5741  return headers.find(key) != headers.end();
5742 }
5743 
5744 inline std::string Response::get_header_value(const std::string &key,
5745  const char *def,
5746  size_t id) const {
5747  return detail::get_header_value(headers, key, def, id);
5748 }
5749 
5750 inline size_t Response::get_header_value_count(const std::string &key) const {
5751  auto r = headers.equal_range(key);
5752  return static_cast<size_t>(std::distance(r.first, r.second));
5753 }
5754 
5755 inline void Response::set_header(const std::string &key,
5756  const std::string &val) {
5757  if (!detail::has_crlf(key) && !detail::has_crlf(val)) {
5758  headers.emplace(key, val);
5759  }
5760 }
5761 
5762 inline void Response::set_redirect(const std::string &url, int stat) {
5763  if (!detail::has_crlf(url)) {
5764  set_header("Location", url);
5765  if (300 <= stat && stat < 400) {
5766  this->status = stat;
5767  } else {
5768  this->status = StatusCode::Found_302;
5769  }
5770  }
5771 }
5772 
5773 inline void Response::set_content(const char *s, size_t n,
5774  const std::string &content_type) {
5775  body.assign(s, n);
5776 
5777  auto rng = headers.equal_range("Content-Type");
5778  headers.erase(rng.first, rng.second);
5779  set_header("Content-Type", content_type);
5780 }
5781 
5782 inline void Response::set_content(const std::string &s,
5783  const std::string &content_type) {
5784  set_content(s.data(), s.size(), content_type);
5785 }
5786 
5787 inline void Response::set_content(std::string &&s,
5788  const std::string &content_type) {
5789  body = std::move(s);
5790 
5791  auto rng = headers.equal_range("Content-Type");
5792  headers.erase(rng.first, rng.second);
5793  set_header("Content-Type", content_type);
5794 }
5795 
5796 inline void Response::set_content_provider(
5797  size_t in_length, const std::string &content_type, ContentProvider provider,
5798  ContentProviderResourceReleaser resource_releaser) {
5799  set_header("Content-Type", content_type);
5800  content_length_ = in_length;
5801  if (in_length > 0) { content_provider_ = std::move(provider); }
5802  content_provider_resource_releaser_ = std::move(resource_releaser);
5803  is_chunked_content_provider_ = false;
5804 }
5805 
5806 inline void Response::set_content_provider(
5807  const std::string &content_type, ContentProviderWithoutLength provider,
5808  ContentProviderResourceReleaser resource_releaser) {
5809  set_header("Content-Type", content_type);
5810  content_length_ = 0;
5811  content_provider_ = detail::ContentProviderAdapter(std::move(provider));
5812  content_provider_resource_releaser_ = std::move(resource_releaser);
5813  is_chunked_content_provider_ = false;
5814 }
5815 
5816 inline void Response::set_chunked_content_provider(
5817  const std::string &content_type, ContentProviderWithoutLength provider,
5818  ContentProviderResourceReleaser resource_releaser) {
5819  set_header("Content-Type", content_type);
5820  content_length_ = 0;
5821  content_provider_ = detail::ContentProviderAdapter(std::move(provider));
5822  content_provider_resource_releaser_ = std::move(resource_releaser);
5823  is_chunked_content_provider_ = true;
5824 }
5825 
5826 inline void Response::set_file_content(const std::string &path,
5827  const std::string &content_type) {
5828  file_content_path_ = path;
5829  file_content_content_type_ = content_type;
5830 }
5831 
5832 inline void Response::set_file_content(const std::string &path) {
5833  file_content_path_ = path;
5834 }
5835 
5836 // Result implementation
5837 inline bool Result::has_request_header(const std::string &key) const {
5838  return request_headers_.find(key) != request_headers_.end();
5839 }
5840 
5841 inline std::string Result::get_request_header_value(const std::string &key,
5842  const char *def,
5843  size_t id) const {
5844  return detail::get_header_value(request_headers_, key, def, id);
5845 }
5846 
5847 inline size_t
5848 Result::get_request_header_value_count(const std::string &key) const {
5849  auto r = request_headers_.equal_range(key);
5850  return static_cast<size_t>(std::distance(r.first, r.second));
5851 }
5852 
5853 // Stream implementation
5854 inline ssize_t Stream::write(const char *ptr) {
5855  return write(ptr, strlen(ptr));
5856 }
5857 
5858 inline ssize_t Stream::write(const std::string &s) {
5859  return write(s.data(), s.size());
5860 }
5861 
5862 namespace detail {
5863 
5864 // Socket stream implementation
5865 inline SocketStream::SocketStream(socket_t sock, time_t read_timeout_sec,
5866  time_t read_timeout_usec,
5867  time_t write_timeout_sec,
5868  time_t write_timeout_usec)
5869  : sock_(sock), read_timeout_sec_(read_timeout_sec),
5870  read_timeout_usec_(read_timeout_usec),
5871  write_timeout_sec_(write_timeout_sec),
5872  write_timeout_usec_(write_timeout_usec), read_buff_(read_buff_size_, 0) {}
5873 
5874 inline SocketStream::~SocketStream() = default;
5875 
5876 inline bool SocketStream::is_readable() const {
5877  return select_read(sock_, read_timeout_sec_, read_timeout_usec_) > 0;
5878 }
5879 
5880 inline bool SocketStream::is_writable() const {
5881  return select_write(sock_, write_timeout_sec_, write_timeout_usec_) > 0 &&
5882  is_socket_alive(sock_);
5883 }
5884 
5885 inline ssize_t SocketStream::read(char *ptr, size_t size) {
5886 #ifdef _WIN32
5887  size =
5888  (std::min)(size, static_cast<size_t>((std::numeric_limits<int>::max)()));
5889 #else
5890  size = (std::min)(size,
5891  static_cast<size_t>((std::numeric_limits<ssize_t>::max)()));
5892 #endif
5893 
5894  if (read_buff_off_ < read_buff_content_size_) {
5895  auto remaining_size = read_buff_content_size_ - read_buff_off_;
5896  if (size <= remaining_size) {
5897  memcpy(ptr, read_buff_.data() + read_buff_off_, size);
5898  read_buff_off_ += size;
5899  return static_cast<ssize_t>(size);
5900  } else {
5901  memcpy(ptr, read_buff_.data() + read_buff_off_, remaining_size);
5902  read_buff_off_ += remaining_size;
5903  return static_cast<ssize_t>(remaining_size);
5904  }
5905  }
5906 
5907  if (!is_readable()) { return -1; }
5908 
5909  read_buff_off_ = 0;
5910  read_buff_content_size_ = 0;
5911 
5912  if (size < read_buff_size_) {
5913  auto n = read_socket(sock_, read_buff_.data(), read_buff_size_,
5915  if (n <= 0) {
5916  return n;
5917  } else if (n <= static_cast<ssize_t>(size)) {
5918  memcpy(ptr, read_buff_.data(), static_cast<size_t>(n));
5919  return n;
5920  } else {
5921  memcpy(ptr, read_buff_.data(), size);
5922  read_buff_off_ = size;
5923  read_buff_content_size_ = static_cast<size_t>(n);
5924  return static_cast<ssize_t>(size);
5925  }
5926  } else {
5927  return read_socket(sock_, ptr, size, CPPHTTPLIB_RECV_FLAGS);
5928  }
5929 }
5930 
5931 inline ssize_t SocketStream::write(const char *ptr, size_t size) {
5932  if (!is_writable()) { return -1; }
5933 
5934 #if defined(_WIN32) && !defined(_WIN64)
5935  size =
5936  (std::min)(size, static_cast<size_t>((std::numeric_limits<int>::max)()));
5937 #endif
5938 
5939  return send_socket(sock_, ptr, size, CPPHTTPLIB_SEND_FLAGS);
5940 }
5941 
5942 inline void SocketStream::get_remote_ip_and_port(std::string &ip,
5943  int &port) const {
5944  return detail::get_remote_ip_and_port(sock_, ip, port);
5945 }
5946 
5947 inline void SocketStream::get_local_ip_and_port(std::string &ip,
5948  int &port) const {
5949  return detail::get_local_ip_and_port(sock_, ip, port);
5950 }
5951 
5952 inline socket_t SocketStream::socket() const { return sock_; }
5953 
5954 // Buffer stream implementation
5955 inline bool BufferStream::is_readable() const { return true; }
5956 
5957 inline bool BufferStream::is_writable() const { return true; }
5958 
5959 inline ssize_t BufferStream::read(char *ptr, size_t size) {
5960 #if defined(_MSC_VER) && _MSC_VER < 1910
5961  auto len_read = buffer._Copy_s(ptr, size, size, position);
5962 #else
5963  auto len_read = buffer.copy(ptr, size, position);
5964 #endif
5965  position += static_cast<size_t>(len_read);
5966  return static_cast<ssize_t>(len_read);
5967 }
5968 
5969 inline ssize_t BufferStream::write(const char *ptr, size_t size) {
5970  buffer.append(ptr, size);
5971  return static_cast<ssize_t>(size);
5972 }
5973 
5974 inline void BufferStream::get_remote_ip_and_port(std::string & /*ip*/,
5975  int & /*port*/) const {}
5976 
5977 inline void BufferStream::get_local_ip_and_port(std::string & /*ip*/,
5978  int & /*port*/) const {}
5979 
5980 inline socket_t BufferStream::socket() const { return 0; }
5981 
5982 inline const std::string &BufferStream::get_buffer() const { return buffer; }
5983 
5984 inline PathParamsMatcher::PathParamsMatcher(const std::string &pattern) {
5985  static constexpr char marker[] = "/:";
5986 
5987  // One past the last ending position of a path param substring
5988  std::size_t last_param_end = 0;
5989 
5990 #ifndef CPPHTTPLIB_NO_EXCEPTIONS
5991  // Needed to ensure that parameter names are unique during matcher
5992  // construction
5993  // If exceptions are disabled, only last duplicate path
5994  // parameter will be set
5995  std::unordered_set<std::string> param_name_set;
5996 #endif
5997 
5998  while (true) {
5999  const auto marker_pos = pattern.find(
6000  marker, last_param_end == 0 ? last_param_end : last_param_end - 1);
6001  if (marker_pos == std::string::npos) { break; }
6002 
6003  static_fragments_.push_back(
6004  pattern.substr(last_param_end, marker_pos - last_param_end + 1));
6005 
6006  const auto param_name_start = marker_pos + 2;
6007 
6008  auto sep_pos = pattern.find(separator, param_name_start);
6009  if (sep_pos == std::string::npos) { sep_pos = pattern.length(); }
6010 
6011  auto param_name =
6012  pattern.substr(param_name_start, sep_pos - param_name_start);
6013 
6014 #ifndef CPPHTTPLIB_NO_EXCEPTIONS
6015  if (param_name_set.find(param_name) != param_name_set.cend()) {
6016  std::string msg = "Encountered path parameter '" + param_name +
6017  "' multiple times in route pattern '" + pattern + "'.";
6018  throw std::invalid_argument(msg);
6019  }
6020 #endif
6021 
6022  param_names_.push_back(std::move(param_name));
6023 
6024  last_param_end = sep_pos + 1;
6025  }
6026 
6027  if (last_param_end < pattern.length()) {
6028  static_fragments_.push_back(pattern.substr(last_param_end));
6029  }
6030 }
6031 
6032 inline bool PathParamsMatcher::match(Request &request) const {
6033  request.matches = std::smatch();
6034  request.path_params.clear();
6035  request.path_params.reserve(param_names_.size());
6036 
6037  // One past the position at which the path matched the pattern last time
6038  std::size_t starting_pos = 0;
6039  for (size_t i = 0; i < static_fragments_.size(); ++i) {
6040  const auto &fragment = static_fragments_[i];
6041 
6042  if (starting_pos + fragment.length() > request.path.length()) {
6043  return false;
6044  }
6045 
6046  // Avoid unnecessary allocation by using strncmp instead of substr +
6047  // comparison
6048  if (std::strncmp(request.path.c_str() + starting_pos, fragment.c_str(),
6049  fragment.length()) != 0) {
6050  return false;
6051  }
6052 
6053  starting_pos += fragment.length();
6054 
6055  // Should only happen when we have a static fragment after a param
6056  // Example: '/users/:id/subscriptions'
6057  // The 'subscriptions' fragment here does not have a corresponding param
6058  if (i >= param_names_.size()) { continue; }
6059 
6060  auto sep_pos = request.path.find(separator, starting_pos);
6061  if (sep_pos == std::string::npos) { sep_pos = request.path.length(); }
6062 
6063  const auto &param_name = param_names_[i];
6064 
6065  request.path_params.emplace(
6066  param_name, request.path.substr(starting_pos, sep_pos - starting_pos));
6067 
6068  // Mark everything up to '/' as matched
6069  starting_pos = sep_pos + 1;
6070  }
6071  // Returns false if the path is longer than the pattern
6072  return starting_pos >= request.path.length();
6073 }
6074 
6075 inline bool RegexMatcher::match(Request &request) const {
6076  request.path_params.clear();
6077  return std::regex_match(request.path, request.matches, regex_);
6078 }
6079 
6080 } // namespace detail
6081 
6082 // HTTP server implementation
6084  : new_task_queue(
6085  [] { return new ThreadPool(CPPHTTPLIB_THREAD_POOL_COUNT); }) {
6086 #ifndef _WIN32
6087  signal(SIGPIPE, SIG_IGN);
6088 #endif
6089 }
6090 
6091 inline Server::~Server() = default;
6092 
6093 inline std::unique_ptr<detail::MatcherBase>
6094 Server::make_matcher(const std::string &pattern) {
6095  if (pattern.find("/:") != std::string::npos) {
6096  return detail::make_unique<detail::PathParamsMatcher>(pattern);
6097  } else {
6098  return detail::make_unique<detail::RegexMatcher>(pattern);
6099  }
6100 }
6101 
6102 inline Server &Server::Get(const std::string &pattern, Handler handler) {
6103  get_handlers_.emplace_back(make_matcher(pattern), std::move(handler));
6104  return *this;
6105 }
6106 
6107 inline Server &Server::Post(const std::string &pattern, Handler handler) {
6108  post_handlers_.emplace_back(make_matcher(pattern), std::move(handler));
6109  return *this;
6110 }
6111 
6112 inline Server &Server::Post(const std::string &pattern,
6113  HandlerWithContentReader handler) {
6114  post_handlers_for_content_reader_.emplace_back(make_matcher(pattern),
6115  std::move(handler));
6116  return *this;
6117 }
6118 
6119 inline Server &Server::Put(const std::string &pattern, Handler handler) {
6120  put_handlers_.emplace_back(make_matcher(pattern), std::move(handler));
6121  return *this;
6122 }
6123 
6124 inline Server &Server::Put(const std::string &pattern,
6125  HandlerWithContentReader handler) {
6126  put_handlers_for_content_reader_.emplace_back(make_matcher(pattern),
6127  std::move(handler));
6128  return *this;
6129 }
6130 
6131 inline Server &Server::Patch(const std::string &pattern, Handler handler) {
6132  patch_handlers_.emplace_back(make_matcher(pattern), std::move(handler));
6133  return *this;
6134 }
6135 
6136 inline Server &Server::Patch(const std::string &pattern,
6137  HandlerWithContentReader handler) {
6138  patch_handlers_for_content_reader_.emplace_back(make_matcher(pattern),
6139  std::move(handler));
6140  return *this;
6141 }
6142 
6143 inline Server &Server::Delete(const std::string &pattern, Handler handler) {
6144  delete_handlers_.emplace_back(make_matcher(pattern), std::move(handler));
6145  return *this;
6146 }
6147 
6148 inline Server &Server::Delete(const std::string &pattern,
6149  HandlerWithContentReader handler) {
6150  delete_handlers_for_content_reader_.emplace_back(make_matcher(pattern),
6151  std::move(handler));
6152  return *this;
6153 }
6154 
6155 inline Server &Server::Options(const std::string &pattern, Handler handler) {
6156  options_handlers_.emplace_back(make_matcher(pattern), std::move(handler));
6157  return *this;
6158 }
6159 
6160 inline bool Server::set_base_dir(const std::string &dir,
6161  const std::string &mount_point) {
6162  return set_mount_point(mount_point, dir);
6163 }
6164 
6165 inline bool Server::set_mount_point(const std::string &mount_point,
6166  const std::string &dir, Headers headers) {
6167  detail::FileStat stat(dir);
6168  if (stat.is_dir()) {
6169  std::string mnt = !mount_point.empty() ? mount_point : "/";
6170  if (!mnt.empty() && mnt[0] == '/') {
6171  base_dirs_.push_back({mnt, dir, std::move(headers)});
6172  return true;
6173  }
6174  }
6175  return false;
6176 }
6177 
6178 inline bool Server::remove_mount_point(const std::string &mount_point) {
6179  for (auto it = base_dirs_.begin(); it != base_dirs_.end(); ++it) {
6180  if (it->mount_point == mount_point) {
6181  base_dirs_.erase(it);
6182  return true;
6183  }
6184  }
6185  return false;
6186 }
6187 
6188 inline Server &
6190  const std::string &mime) {
6191  file_extension_and_mimetype_map_[ext] = mime;
6192  return *this;
6193 }
6194 
6195 inline Server &Server::set_default_file_mimetype(const std::string &mime) {
6196  default_file_mimetype_ = mime;
6197  return *this;
6198 }
6199 
6201  file_request_handler_ = std::move(handler);
6202  return *this;
6203 }
6204 
6205 inline Server &Server::set_error_handler_core(HandlerWithResponse handler,
6206  std::true_type) {
6207  error_handler_ = std::move(handler);
6208  return *this;
6209 }
6210 
6211 inline Server &Server::set_error_handler_core(Handler handler,
6212  std::false_type) {
6213  error_handler_ = [handler](const Request &req, Response &res) {
6214  handler(req, res);
6215  return HandlerResponse::Handled;
6216  };
6217  return *this;
6218 }
6219 
6221  exception_handler_ = std::move(handler);
6222  return *this;
6223 }
6224 
6226  pre_routing_handler_ = std::move(handler);
6227  return *this;
6228 }
6229 
6231  post_routing_handler_ = std::move(handler);
6232  return *this;
6233 }
6234 
6236  logger_ = std::move(logger);
6237  return *this;
6238 }
6239 
6240 inline Server &
6242  expect_100_continue_handler_ = std::move(handler);
6243  return *this;
6244 }
6245 
6246 inline Server &Server::set_address_family(int family) {
6247  address_family_ = family;
6248  return *this;
6249 }
6250 
6252  tcp_nodelay_ = on;
6253  return *this;
6254 }
6255 
6257  ipv6_v6only_ = on;
6258  return *this;
6259 }
6260 
6262  socket_options_ = std::move(socket_options);
6263  return *this;
6264 }
6265 
6267  default_headers_ = std::move(headers);
6268  return *this;
6269 }
6270 
6272  std::function<ssize_t(Stream &, Headers &)> const &writer) {
6273  header_writer_ = writer;
6274  return *this;
6275 }
6276 
6278  keep_alive_max_count_ = count;
6279  return *this;
6280 }
6281 
6284  return *this;
6285 }
6286 
6287 inline Server &Server::set_read_timeout(time_t sec, time_t usec) {
6288  read_timeout_sec_ = sec;
6289  read_timeout_usec_ = usec;
6290  return *this;
6291 }
6292 
6293 inline Server &Server::set_write_timeout(time_t sec, time_t usec) {
6294  write_timeout_sec_ = sec;
6295  write_timeout_usec_ = usec;
6296  return *this;
6297 }
6298 
6299 inline Server &Server::set_idle_interval(time_t sec, time_t usec) {
6300  idle_interval_sec_ = sec;
6301  idle_interval_usec_ = usec;
6302  return *this;
6303 }
6304 
6305 inline Server &Server::set_payload_max_length(size_t length) {
6306  payload_max_length_ = length;
6307  return *this;
6308 }
6309 
6310 inline bool Server::bind_to_port(const std::string &host, int port,
6311  int socket_flags) {
6312  auto ret = bind_internal(host, port, socket_flags);
6313  if (ret == -1) { is_decommisioned = true; }
6314  return ret >= 0;
6315 }
6316 inline int Server::bind_to_any_port(const std::string &host, int socket_flags) {
6317  auto ret = bind_internal(host, 0, socket_flags);
6318  if (ret == -1) { is_decommisioned = true; }
6319  return ret;
6320 }
6321 
6322 inline bool Server::listen_after_bind() { return listen_internal(); }
6323 
6324 inline bool Server::listen(const std::string &host, int port,
6325  int socket_flags) {
6326  return bind_to_port(host, port, socket_flags) && listen_internal();
6327 }
6328 
6329 inline bool Server::is_running() const { return is_running_; }
6330 
6331 inline void Server::wait_until_ready() const {
6332  while (!is_running_ && !is_decommisioned) {
6333  std::this_thread::sleep_for(std::chrono::milliseconds{1});
6334  }
6335 }
6336 
6337 inline void Server::stop() {
6338  if (is_running_) {
6339  assert(svr_sock_ != INVALID_SOCKET);
6340  std::atomic<socket_t> sock(svr_sock_.exchange(INVALID_SOCKET));
6342  detail::close_socket(sock);
6343  }
6344  is_decommisioned = false;
6345 }
6346 
6347 inline void Server::decommission() { is_decommisioned = true; }
6348 
6349 inline bool Server::parse_request_line(const char *s, Request &req) const {
6350  auto len = strlen(s);
6351  if (len < 2 || s[len - 2] != '\r' || s[len - 1] != '\n') { return false; }
6352  len -= 2;
6353 
6354  {
6355  size_t count = 0;
6356 
6357  detail::split(s, s + len, ' ', [&](const char *b, const char *e) {
6358  switch (count) {
6359  case 0: req.method = std::string(b, e); break;
6360  case 1: req.target = std::string(b, e); break;
6361  case 2: req.version = std::string(b, e); break;
6362  default: break;
6363  }
6364  count++;
6365  });
6366 
6367  if (count != 3) { return false; }
6368  }
6369 
6370  static const std::set<std::string> methods{
6371  "GET", "HEAD", "POST", "PUT", "DELETE",
6372  "CONNECT", "OPTIONS", "TRACE", "PATCH", "PRI"};
6373 
6374  if (methods.find(req.method) == methods.end()) { return false; }
6375 
6376  if (req.version != "HTTP/1.1" && req.version != "HTTP/1.0") { return false; }
6377 
6378  {
6379  // Skip URL fragment
6380  for (size_t i = 0; i < req.target.size(); i++) {
6381  if (req.target[i] == '#') {
6382  req.target.erase(i);
6383  break;
6384  }
6385  }
6386 
6387  detail::divide(req.target, '?',
6388  [&](const char *lhs_data, std::size_t lhs_size,
6389  const char *rhs_data, std::size_t rhs_size) {
6390  req.path = detail::decode_url(
6391  std::string(lhs_data, lhs_size), false);
6392  detail::parse_query_text(rhs_data, rhs_size, req.params);
6393  });
6394  }
6395 
6396  return true;
6397 }
6398 
6399 inline bool Server::write_response(Stream &strm, bool close_connection,
6400  Request &req, Response &res) {
6401  // NOTE: `req.ranges` should be empty, otherwise it will be applied
6402  // incorrectly to the error content.
6403  req.ranges.clear();
6404  return write_response_core(strm, close_connection, req, res, false);
6405 }
6406 
6407 inline bool Server::write_response_with_content(Stream &strm,
6408  bool close_connection,
6409  const Request &req,
6410  Response &res) {
6411  return write_response_core(strm, close_connection, req, res, true);
6412 }
6413 
6414 inline bool Server::write_response_core(Stream &strm, bool close_connection,
6415  const Request &req, Response &res,
6416  bool need_apply_ranges) {
6417  assert(res.status != -1);
6418 
6419  if (400 <= res.status && error_handler_ &&
6420  error_handler_(req, res) == HandlerResponse::Handled) {
6421  need_apply_ranges = true;
6422  }
6423 
6424  std::string content_type;
6425  std::string boundary;
6426  if (need_apply_ranges) { apply_ranges(req, res, content_type, boundary); }
6427 
6428  // Prepare additional headers
6429  if (close_connection || req.get_header_value("Connection") == "close") {
6430  res.set_header("Connection", "close");
6431  } else {
6432  std::string s = "timeout=";
6434  s += ", max=";
6436  res.set_header("Keep-Alive", s);
6437  }
6438 
6439  if ((!res.body.empty() || res.content_length_ > 0 || res.content_provider_) &&
6440  !res.has_header("Content-Type")) {
6441  res.set_header("Content-Type", "text/plain");
6442  }
6443 
6444  if (res.body.empty() && !res.content_length_ && !res.content_provider_ &&
6445  !res.has_header("Content-Length")) {
6446  res.set_header("Content-Length", "0");
6447  }
6448 
6449  if (req.method == "HEAD" && !res.has_header("Accept-Ranges")) {
6450  res.set_header("Accept-Ranges", "bytes");
6451  }
6452 
6453  if (post_routing_handler_) { post_routing_handler_(req, res); }
6454 
6455  // Response line and headers
6456  {
6457  detail::BufferStream bstrm;
6458  if (!detail::write_response_line(bstrm, res.status)) { return false; }
6459  if (!header_writer_(bstrm, res.headers)) { return false; }
6460 
6461  // Flush buffer
6462  auto &data = bstrm.get_buffer();
6463  detail::write_data(strm, data.data(), data.size());
6464  }
6465 
6466  // Body
6467  auto ret = true;
6468  if (req.method != "HEAD") {
6469  if (!res.body.empty()) {
6470  if (!detail::write_data(strm, res.body.data(), res.body.size())) {
6471  ret = false;
6472  }
6473  } else if (res.content_provider_) {
6474  if (write_content_with_provider(strm, req, res, boundary, content_type)) {
6475  res.content_provider_success_ = true;
6476  } else {
6477  ret = false;
6478  }
6479  }
6480  }
6481 
6482  // Log
6483  if (logger_) { logger_(req, res); }
6484 
6485  return ret;
6486 }
6487 
6488 inline bool
6489 Server::write_content_with_provider(Stream &strm, const Request &req,
6490  Response &res, const std::string &boundary,
6491  const std::string &content_type) {
6492  auto is_shutting_down = [this]() {
6493  return this->svr_sock_ == INVALID_SOCKET;
6494  };
6495 
6496  if (res.content_length_ > 0) {
6497  if (req.ranges.empty()) {
6498  return detail::write_content(strm, res.content_provider_, 0,
6499  res.content_length_, is_shutting_down);
6500  } else if (req.ranges.size() == 1) {
6501  auto offset_and_length = detail::get_range_offset_and_length(
6502  req.ranges[0], res.content_length_);
6503 
6504  return detail::write_content(strm, res.content_provider_,
6505  offset_and_length.first,
6506  offset_and_length.second, is_shutting_down);
6507  } else {
6509  strm, req, res, boundary, content_type, res.content_length_,
6510  is_shutting_down);
6511  }
6512  } else {
6513  if (res.is_chunked_content_provider_) {
6514  auto type = detail::encoding_type(req, res);
6515 
6516  std::unique_ptr<detail::compressor> compressor;
6517  if (type == detail::EncodingType::Gzip) {
6518 #ifdef CPPHTTPLIB_ZLIB_SUPPORT
6519  compressor = detail::make_unique<detail::gzip_compressor>();
6520 #endif
6521  } else if (type == detail::EncodingType::Brotli) {
6522 #ifdef CPPHTTPLIB_BROTLI_SUPPORT
6523  compressor = detail::make_unique<detail::brotli_compressor>();
6524 #endif
6525  } else {
6526  compressor = detail::make_unique<detail::nocompressor>();
6527  }
6528  assert(compressor != nullptr);
6529 
6530  return detail::write_content_chunked(strm, res.content_provider_,
6531  is_shutting_down, *compressor);
6532  } else {
6533  return detail::write_content_without_length(strm, res.content_provider_,
6534  is_shutting_down);
6535  }
6536  }
6537 }
6538 
6539 inline bool Server::read_content(Stream &strm, Request &req, Response &res) {
6540  MultipartFormDataMap::iterator cur;
6541  auto file_count = 0;
6542  if (read_content_core(
6543  strm, req, res,
6544  // Regular
6545  [&](const char *buf, size_t n) {
6546  if (req.body.size() + n > req.body.max_size()) { return false; }
6547  req.body.append(buf, n);
6548  return true;
6549  },
6550  // Multipart
6551  [&](const MultipartFormData &file) {
6552  if (file_count++ == CPPHTTPLIB_MULTIPART_FORM_DATA_FILE_MAX_COUNT) {
6553  return false;
6554  }
6555  cur = req.files.emplace(file.name, file);
6556  return true;
6557  },
6558  [&](const char *buf, size_t n) {
6559  auto &content = cur->second.content;
6560  if (content.size() + n > content.max_size()) { return false; }
6561  content.append(buf, n);
6562  return true;
6563  })) {
6564  const auto &content_type = req.get_header_value("Content-Type");
6565  if (!content_type.find("application/x-www-form-urlencoded")) {
6566  if (req.body.size() > CPPHTTPLIB_FORM_URL_ENCODED_PAYLOAD_MAX_LENGTH) {
6567  res.status = StatusCode::PayloadTooLarge_413; // NOTE: should be 414?
6568  return false;
6569  }
6570  detail::parse_query_text(req.body, req.params);
6571  }
6572  return true;
6573  }
6574  return false;
6575 }
6576 
6577 inline bool Server::read_content_with_content_receiver(
6578  Stream &strm, Request &req, Response &res, ContentReceiver receiver,
6579  MultipartContentHeader multipart_header,
6580  ContentReceiver multipart_receiver) {
6581  return read_content_core(strm, req, res, std::move(receiver),
6582  std::move(multipart_header),
6583  std::move(multipart_receiver));
6584 }
6585 
6586 inline bool
6587 Server::read_content_core(Stream &strm, Request &req, Response &res,
6588  ContentReceiver receiver,
6589  MultipartContentHeader multipart_header,
6590  ContentReceiver multipart_receiver) const {
6591  detail::MultipartFormDataParser multipart_form_data_parser;
6593 
6594  if (req.is_multipart_form_data()) {
6595  const auto &content_type = req.get_header_value("Content-Type");
6596  std::string boundary;
6597  if (!detail::parse_multipart_boundary(content_type, boundary)) {
6599  return false;
6600  }
6601 
6602  multipart_form_data_parser.set_boundary(std::move(boundary));
6603  out = [&](const char *buf, size_t n, uint64_t /*off*/, uint64_t /*len*/) {
6604  /* For debug
6605  size_t pos = 0;
6606  while (pos < n) {
6607  auto read_size = (std::min)<size_t>(1, n - pos);
6608  auto ret = multipart_form_data_parser.parse(
6609  buf + pos, read_size, multipart_receiver, multipart_header);
6610  if (!ret) { return false; }
6611  pos += read_size;
6612  }
6613  return true;
6614  */
6615  return multipart_form_data_parser.parse(buf, n, multipart_receiver,
6616  multipart_header);
6617  };
6618  } else {
6619  out = [receiver](const char *buf, size_t n, uint64_t /*off*/,
6620  uint64_t /*len*/) { return receiver(buf, n); };
6621  }
6622 
6623  if (req.method == "DELETE" && !req.has_header("Content-Length")) {
6624  return true;
6625  }
6626 
6627  if (!detail::read_content(strm, req, payload_max_length_, res.status, nullptr,
6628  out, true)) {
6629  return false;
6630  }
6631 
6632  if (req.is_multipart_form_data()) {
6633  if (!multipart_form_data_parser.is_valid()) {
6635  return false;
6636  }
6637  }
6638 
6639  return true;
6640 }
6641 
6642 inline bool Server::handle_file_request(const Request &req, Response &res,
6643  bool head) {
6644  for (const auto &entry : base_dirs_) {
6645  // Prefix match
6646  if (!req.path.compare(0, entry.mount_point.size(), entry.mount_point)) {
6647  std::string sub_path = "/" + req.path.substr(entry.mount_point.size());
6648  if (detail::is_valid_path(sub_path)) {
6649  auto path = entry.base_dir + sub_path;
6650  if (path.back() == '/') { path += "index.html"; }
6651 
6652  detail::FileStat stat(path);
6653 
6654  if (stat.is_dir()) {
6655  res.set_redirect(sub_path + "/", StatusCode::MovedPermanently_301);
6656  return true;
6657  }
6658 
6659  if (stat.is_file()) {
6660  for (const auto &kv : entry.headers) {
6661  res.set_header(kv.first, kv.second);
6662  }
6663 
6664  auto mm = std::make_shared<detail::mmap>(path.c_str());
6665  if (!mm->is_open()) { return false; }
6666 
6667  res.set_content_provider(
6668  mm->size(),
6669  detail::find_content_type(path, file_extension_and_mimetype_map_,
6670  default_file_mimetype_),
6671  [mm](size_t offset, size_t length, DataSink &sink) -> bool {
6672  sink.write(mm->data() + offset, length);
6673  return true;
6674  });
6675 
6676  if (!head && file_request_handler_) {
6677  file_request_handler_(req, res);
6678  }
6679 
6680  return true;
6681  }
6682  }
6683  }
6684  }
6685  return false;
6686 }
6687 
6688 inline socket_t
6689 Server::create_server_socket(const std::string &host, int port,
6690  int socket_flags,
6691  SocketOptions socket_options) const {
6692  return detail::create_socket(
6693  host, std::string(), port, address_family_, socket_flags, tcp_nodelay_,
6694  ipv6_v6only_, std::move(socket_options),
6695  [](socket_t sock, struct addrinfo &ai, bool & /*quit*/) -> bool {
6696  if (::bind(sock, ai.ai_addr, static_cast<socklen_t>(ai.ai_addrlen))) {
6697  return false;
6698  }
6699  if (::listen(sock, CPPHTTPLIB_LISTEN_BACKLOG)) { return false; }
6700  return true;
6701  });
6702 }
6703 
6704 inline int Server::bind_internal(const std::string &host, int port,
6705  int socket_flags) {
6706  if (is_decommisioned) { return -1; }
6707 
6708  if (!is_valid()) { return -1; }
6709 
6710  svr_sock_ = create_server_socket(host, port, socket_flags, socket_options_);
6711  if (svr_sock_ == INVALID_SOCKET) { return -1; }
6712 
6713  if (port == 0) {
6714  struct sockaddr_storage addr;
6715  socklen_t addr_len = sizeof(addr);
6716  if (getsockname(svr_sock_, reinterpret_cast<struct sockaddr *>(&addr),
6717  &addr_len) == -1) {
6718  return -1;
6719  }
6720  if (addr.ss_family == AF_INET) {
6721  return ntohs(reinterpret_cast<struct sockaddr_in *>(&addr)->sin_port);
6722  } else if (addr.ss_family == AF_INET6) {
6723  return ntohs(reinterpret_cast<struct sockaddr_in6 *>(&addr)->sin6_port);
6724  } else {
6725  return -1;
6726  }
6727  } else {
6728  return port;
6729  }
6730 }
6731 
6732 inline bool Server::listen_internal() {
6733  if (is_decommisioned) { return false; }
6734 
6735  auto ret = true;
6736  is_running_ = true;
6737  auto se = detail::scope_exit([&]() { is_running_ = false; });
6738 
6739  {
6740  std::unique_ptr<TaskQueue> task_queue(new_task_queue());
6741 
6742  while (svr_sock_ != INVALID_SOCKET) {
6743 #ifndef _WIN32
6744  if (idle_interval_sec_ > 0 || idle_interval_usec_ > 0) {
6745 #endif
6748  if (val == 0) { // Timeout
6749  task_queue->on_idle();
6750  continue;
6751  }
6752 #ifndef _WIN32
6753  }
6754 #endif
6755 
6756 #if defined _WIN32
6757  // sockets conneced via WASAccept inherit flags NO_HANDLE_INHERIT,
6758  // OVERLAPPED
6759  socket_t sock = WSAAccept(svr_sock_, nullptr, nullptr, nullptr, 0);
6760 #elif defined SOCK_CLOEXEC
6761  socket_t sock = accept4(svr_sock_, nullptr, nullptr, SOCK_CLOEXEC);
6762 #else
6763  socket_t sock = accept(svr_sock_, nullptr, nullptr);
6764 #endif
6765 
6766  if (sock == INVALID_SOCKET) {
6767  if (errno == EMFILE) {
6768  // The per-process limit of open file descriptors has been reached.
6769  // Try to accept new connections after a short sleep.
6770  std::this_thread::sleep_for(std::chrono::microseconds{1});
6771  continue;
6772  } else if (errno == EINTR || errno == EAGAIN) {
6773  continue;
6774  }
6775  if (svr_sock_ != INVALID_SOCKET) {
6777  ret = false;
6778  } else {
6779  ; // The server socket was closed by user.
6780  }
6781  break;
6782  }
6783 
6784  {
6785 #ifdef _WIN32
6786  auto timeout = static_cast<uint32_t>(read_timeout_sec_ * 1000 +
6787  read_timeout_usec_ / 1000);
6788  setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO,
6789  reinterpret_cast<const char *>(&timeout), sizeof(timeout));
6790 #else
6791  timeval tv;
6792  tv.tv_sec = static_cast<long>(read_timeout_sec_);
6793  tv.tv_usec = static_cast<decltype(tv.tv_usec)>(read_timeout_usec_);
6794  setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO,
6795  reinterpret_cast<const void *>(&tv), sizeof(tv));
6796 #endif
6797  }
6798  {
6799 
6800 #ifdef _WIN32
6801  auto timeout = static_cast<uint32_t>(write_timeout_sec_ * 1000 +
6802  write_timeout_usec_ / 1000);
6803  setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO,
6804  reinterpret_cast<const char *>(&timeout), sizeof(timeout));
6805 #else
6806  timeval tv;
6807  tv.tv_sec = static_cast<long>(write_timeout_sec_);
6808  tv.tv_usec = static_cast<decltype(tv.tv_usec)>(write_timeout_usec_);
6809  setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO,
6810  reinterpret_cast<const void *>(&tv), sizeof(tv));
6811 #endif
6812  }
6813 
6814  if (!task_queue->enqueue(
6815  [this, sock]() { process_and_close_socket(sock); })) {
6817  detail::close_socket(sock);
6818  }
6819  }
6820 
6821  task_queue->shutdown();
6822  }
6823 
6824  is_decommisioned = !ret;
6825  return ret;
6826 }
6827 
6828 inline bool Server::routing(Request &req, Response &res, Stream &strm) {
6829  if (pre_routing_handler_ &&
6830  pre_routing_handler_(req, res) == HandlerResponse::Handled) {
6831  return true;
6832  }
6833 
6834  // File handler
6835  auto is_head_request = req.method == "HEAD";
6836  if ((req.method == "GET" || is_head_request) &&
6837  handle_file_request(req, res, is_head_request)) {
6838  return true;
6839  }
6840 
6841  if (detail::expect_content(req)) {
6842  // Content reader handler
6843  {
6844  ContentReader reader(
6845  [&](ContentReceiver receiver) {
6846  return read_content_with_content_receiver(
6847  strm, req, res, std::move(receiver), nullptr, nullptr);
6848  },
6849  [&](MultipartContentHeader header, ContentReceiver receiver) {
6850  return read_content_with_content_receiver(strm, req, res, nullptr,
6851  std::move(header),
6852  std::move(receiver));
6853  });
6854 
6855  if (req.method == "POST") {
6856  if (dispatch_request_for_content_reader(
6857  req, res, std::move(reader),
6858  post_handlers_for_content_reader_)) {
6859  return true;
6860  }
6861  } else if (req.method == "PUT") {
6862  if (dispatch_request_for_content_reader(
6863  req, res, std::move(reader),
6864  put_handlers_for_content_reader_)) {
6865  return true;
6866  }
6867  } else if (req.method == "PATCH") {
6868  if (dispatch_request_for_content_reader(
6869  req, res, std::move(reader),
6870  patch_handlers_for_content_reader_)) {
6871  return true;
6872  }
6873  } else if (req.method == "DELETE") {
6874  if (dispatch_request_for_content_reader(
6875  req, res, std::move(reader),
6876  delete_handlers_for_content_reader_)) {
6877  return true;
6878  }
6879  }
6880  }
6881 
6882  // Read content into `req.body`
6883  if (!read_content(strm, req, res)) { return false; }
6884  }
6885 
6886  // Regular handler
6887  if (req.method == "GET" || req.method == "HEAD") {
6888  return dispatch_request(req, res, get_handlers_);
6889  } else if (req.method == "POST") {
6890  return dispatch_request(req, res, post_handlers_);
6891  } else if (req.method == "PUT") {
6892  return dispatch_request(req, res, put_handlers_);
6893  } else if (req.method == "DELETE") {
6894  return dispatch_request(req, res, delete_handlers_);
6895  } else if (req.method == "OPTIONS") {
6896  return dispatch_request(req, res, options_handlers_);
6897  } else if (req.method == "PATCH") {
6898  return dispatch_request(req, res, patch_handlers_);
6899  }
6900 
6902  return false;
6903 }
6904 
6905 inline bool Server::dispatch_request(Request &req, Response &res,
6906  const Handlers &handlers) const {
6907  for (const auto &x : handlers) {
6908  const auto &matcher = x.first;
6909  const auto &handler = x.second;
6910 
6911  if (matcher->match(req)) {
6912  handler(req, res);
6913  return true;
6914  }
6915  }
6916  return false;
6917 }
6918 
6919 inline void Server::apply_ranges(const Request &req, Response &res,
6920  std::string &content_type,
6921  std::string &boundary) const {
6922  if (req.ranges.size() > 1 && res.status == StatusCode::PartialContent_206) {
6923  auto it = res.headers.find("Content-Type");
6924  if (it != res.headers.end()) {
6925  content_type = it->second;
6926  res.headers.erase(it);
6927  }
6928 
6930 
6931  res.set_header("Content-Type",
6932  "multipart/byteranges; boundary=" + boundary);
6933  }
6934 
6935  auto type = detail::encoding_type(req, res);
6936 
6937  if (res.body.empty()) {
6938  if (res.content_length_ > 0) {
6939  size_t length = 0;
6940  if (req.ranges.empty() || res.status != StatusCode::PartialContent_206) {
6941  length = res.content_length_;
6942  } else if (req.ranges.size() == 1) {
6943  auto offset_and_length = detail::get_range_offset_and_length(
6944  req.ranges[0], res.content_length_);
6945 
6946  length = offset_and_length.second;
6947 
6948  auto content_range = detail::make_content_range_header_field(
6949  offset_and_length, res.content_length_);
6950  res.set_header("Content-Range", content_range);
6951  } else {
6953  req, boundary, content_type, res.content_length_);
6954  }
6955  res.set_header("Content-Length", std::to_string(length));
6956  } else {
6957  if (res.content_provider_) {
6958  if (res.is_chunked_content_provider_) {
6959  res.set_header("Transfer-Encoding", "chunked");
6960  if (type == detail::EncodingType::Gzip) {
6961  res.set_header("Content-Encoding", "gzip");
6962  } else if (type == detail::EncodingType::Brotli) {
6963  res.set_header("Content-Encoding", "br");
6964  }
6965  }
6966  }
6967  }
6968  } else {
6969  if (req.ranges.empty() || res.status != StatusCode::PartialContent_206) {
6970  ;
6971  } else if (req.ranges.size() == 1) {
6972  auto offset_and_length =
6973  detail::get_range_offset_and_length(req.ranges[0], res.body.size());
6974  auto offset = offset_and_length.first;
6975  auto length = offset_and_length.second;
6976 
6977  auto content_range = detail::make_content_range_header_field(
6978  offset_and_length, res.body.size());
6979  res.set_header("Content-Range", content_range);
6980 
6981  assert(offset + length <= res.body.size());
6982  res.body = res.body.substr(offset, length);
6983  } else {
6984  std::string data;
6985  detail::make_multipart_ranges_data(req, res, boundary, content_type,
6986  res.body.size(), data);
6987  res.body.swap(data);
6988  }
6989 
6990  if (type != detail::EncodingType::None) {
6991  std::unique_ptr<detail::compressor> compressor;
6992  std::string content_encoding;
6993 
6994  if (type == detail::EncodingType::Gzip) {
6995 #ifdef CPPHTTPLIB_ZLIB_SUPPORT
6996  compressor = detail::make_unique<detail::gzip_compressor>();
6997  content_encoding = "gzip";
6998 #endif
6999  } else if (type == detail::EncodingType::Brotli) {
7000 #ifdef CPPHTTPLIB_BROTLI_SUPPORT
7001  compressor = detail::make_unique<detail::brotli_compressor>();
7002  content_encoding = "br";
7003 #endif
7004  }
7005 
7006  if (compressor) {
7007  std::string compressed;
7008  if (compressor->compress(res.body.data(), res.body.size(), true,
7009  [&](const char *data, size_t data_len) {
7010  compressed.append(data, data_len);
7011  return true;
7012  })) {
7013  res.body.swap(compressed);
7014  res.set_header("Content-Encoding", content_encoding);
7015  }
7016  }
7017  }
7018 
7019  auto length = std::to_string(res.body.size());
7020  res.set_header("Content-Length", length);
7021  }
7022 }
7023 
7024 inline bool Server::dispatch_request_for_content_reader(
7025  Request &req, Response &res, ContentReader content_reader,
7026  const HandlersForContentReader &handlers) const {
7027  for (const auto &x : handlers) {
7028  const auto &matcher = x.first;
7029  const auto &handler = x.second;
7030 
7031  if (matcher->match(req)) {
7032  handler(req, res, content_reader);
7033  return true;
7034  }
7035  }
7036  return false;
7037 }
7038 
7039 inline bool
7040 Server::process_request(Stream &strm, const std::string &remote_addr,
7041  int remote_port, const std::string &local_addr,
7042  int local_port, bool close_connection,
7043  bool &connection_closed,
7044  const std::function<void(Request &)> &setup_request) {
7045  std::array<char, 2048> buf{};
7046 
7047  detail::stream_line_reader line_reader(strm, buf.data(), buf.size());
7048 
7049  // Connection has been closed on client
7050  if (!line_reader.getline()) { return false; }
7051 
7052  Request req;
7053 
7054  Response res;
7055  res.version = "HTTP/1.1";
7056  res.headers = default_headers_;
7057 
7058 #ifdef _WIN32
7059  // TODO: Increase FD_SETSIZE statically (libzmq), dynamically (MySQL).
7060 #else
7061 #ifndef CPPHTTPLIB_USE_POLL
7062  // Socket file descriptor exceeded FD_SETSIZE...
7063  if (strm.socket() >= FD_SETSIZE) {
7064  Headers dummy;
7065  detail::read_headers(strm, dummy);
7067  return write_response(strm, close_connection, req, res);
7068  }
7069 #endif
7070 #endif
7071 
7072  // Check if the request URI doesn't exceed the limit
7073  if (line_reader.size() > CPPHTTPLIB_REQUEST_URI_MAX_LENGTH) {
7074  Headers dummy;
7075  detail::read_headers(strm, dummy);
7077  return write_response(strm, close_connection, req, res);
7078  }
7079 
7080  // Request line and headers
7081  if (!parse_request_line(line_reader.ptr(), req) ||
7082  !detail::read_headers(strm, req.headers)) {
7084  return write_response(strm, close_connection, req, res);
7085  }
7086 
7087  if (req.get_header_value("Connection") == "close") {
7088  connection_closed = true;
7089  }
7090 
7091  if (req.version == "HTTP/1.0" &&
7092  req.get_header_value("Connection") != "Keep-Alive") {
7093  connection_closed = true;
7094  }
7095 
7096  req.remote_addr = remote_addr;
7097  req.remote_port = remote_port;
7098  req.set_header("REMOTE_ADDR", req.remote_addr);
7099  req.set_header("REMOTE_PORT", std::to_string(req.remote_port));
7100 
7101  req.local_addr = local_addr;
7102  req.local_port = local_port;
7103  req.set_header("LOCAL_ADDR", req.local_addr);
7104  req.set_header("LOCAL_PORT", std::to_string(req.local_port));
7105 
7106  if (req.has_header("Range")) {
7107  const auto &range_header_value = req.get_header_value("Range");
7108  if (!detail::parse_range_header(range_header_value, req.ranges)) {
7110  return write_response(strm, close_connection, req, res);
7111  }
7112  }
7113 
7114  if (setup_request) { setup_request(req); }
7115 
7116  if (req.get_header_value("Expect") == "100-continue") {
7118  if (expect_100_continue_handler_) {
7119  status = expect_100_continue_handler_(req, res);
7120  }
7121  switch (status) {
7125  strm.write("\r\n");
7126  break;
7127  default:
7128  connection_closed = true;
7129  return write_response(strm, true, req, res);
7130  }
7131  }
7132 
7133  // Routing
7134  auto routed = false;
7135 #ifdef CPPHTTPLIB_NO_EXCEPTIONS
7136  routed = routing(req, res, strm);
7137 #else
7138  try {
7139  routed = routing(req, res, strm);
7140  } catch (std::exception &e) {
7141  if (exception_handler_) {
7142  auto ep = std::current_exception();
7143  exception_handler_(req, res, ep);
7144  routed = true;
7145  } else {
7147  std::string val;
7148  auto s = e.what();
7149  for (size_t i = 0; s[i]; i++) {
7150  switch (s[i]) {
7151  case '\r': val += "\\r"; break;
7152  case '\n': val += "\\n"; break;
7153  default: val += s[i]; break;
7154  }
7155  }
7156  res.set_header("EXCEPTION_WHAT", val);
7157  }
7158  } catch (...) {
7159  if (exception_handler_) {
7160  auto ep = std::current_exception();
7161  exception_handler_(req, res, ep);
7162  routed = true;
7163  } else {
7165  res.set_header("EXCEPTION_WHAT", "UNKNOWN");
7166  }
7167  }
7168 #endif
7169  if (routed) {
7170  if (res.status == -1) {
7171  res.status = req.ranges.empty() ? StatusCode::OK_200
7173  }
7174 
7175  if (detail::range_error(req, res)) {
7176  res.body.clear();
7177  res.content_length_ = 0;
7178  res.content_provider_ = nullptr;
7180  return write_response(strm, close_connection, req, res);
7181  }
7182 
7183  // Serve file content by using a content provider
7184  if (!res.file_content_path_.empty()) {
7185  const auto &path = res.file_content_path_;
7186  auto mm = std::make_shared<detail::mmap>(path.c_str());
7187  if (!mm->is_open()) {
7188  res.body.clear();
7189  res.content_length_ = 0;
7190  res.content_provider_ = nullptr;
7192  return write_response(strm, close_connection, req, res);
7193  }
7194 
7195  auto content_type = res.file_content_content_type_;
7196  if (content_type.empty()) {
7197  content_type = detail::find_content_type(
7198  path, file_extension_and_mimetype_map_, default_file_mimetype_);
7199  }
7200 
7202  mm->size(), content_type,
7203  [mm](size_t offset, size_t length, DataSink &sink) -> bool {
7204  sink.write(mm->data() + offset, length);
7205  return true;
7206  });
7207  }
7208 
7209  return write_response_with_content(strm, close_connection, req, res);
7210  } else {
7211  if (res.status == -1) { res.status = StatusCode::NotFound_404; }
7212 
7213  return write_response(strm, close_connection, req, res);
7214  }
7215 }
7216 
7217 inline bool Server::is_valid() const { return true; }
7218 
7219 inline bool Server::process_and_close_socket(socket_t sock) {
7220  std::string remote_addr;
7221  int remote_port = 0;
7222  detail::get_remote_ip_and_port(sock, remote_addr, remote_port);
7223 
7224  std::string local_addr;
7225  int local_port = 0;
7226  detail::get_local_ip_and_port(sock, local_addr, local_port);
7227 
7232  [&](Stream &strm, bool close_connection, bool &connection_closed) {
7233  return process_request(strm, remote_addr, remote_port, local_addr,
7234  local_port, close_connection, connection_closed,
7235  nullptr);
7236  });
7237 
7239  detail::close_socket(sock);
7240  return ret;
7241 }
7242 
7243 // HTTP client implementation
7244 inline ClientImpl::ClientImpl(const std::string &host)
7245  : ClientImpl(host, 80, std::string(), std::string()) {}
7246 
7247 inline ClientImpl::ClientImpl(const std::string &host, int port)
7248  : ClientImpl(host, port, std::string(), std::string()) {}
7249 
7250 inline ClientImpl::ClientImpl(const std::string &host, int port,
7251  const std::string &client_cert_path,
7252  const std::string &client_key_path)
7253  : host_(detail::escape_abstract_namespace_unix_domain(host)), port_(port),
7254  host_and_port_(adjust_host_string(host_) + ":" + std::to_string(port)),
7255  client_cert_path_(client_cert_path), client_key_path_(client_key_path) {}
7256 
7258  std::lock_guard<std::mutex> guard(socket_mutex_);
7261 }
7262 
7263 inline bool ClientImpl::is_valid() const { return true; }
7264 
7265 inline void ClientImpl::copy_settings(const ClientImpl &rhs) {
7276 #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
7277  digest_auth_username_ = rhs.digest_auth_username_;
7278  digest_auth_password_ = rhs.digest_auth_password_;
7279 #endif
7280  keep_alive_ = rhs.keep_alive_;
7282  url_encode_ = rhs.url_encode_;
7284  tcp_nodelay_ = rhs.tcp_nodelay_;
7285  ipv6_v6only_ = rhs.ipv6_v6only_;
7287  compress_ = rhs.compress_;
7288  decompress_ = rhs.decompress_;
7289  interface_ = rhs.interface_;
7290  proxy_host_ = rhs.proxy_host_;
7291  proxy_port_ = rhs.proxy_port_;
7295 #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
7296  proxy_digest_auth_username_ = rhs.proxy_digest_auth_username_;
7297  proxy_digest_auth_password_ = rhs.proxy_digest_auth_password_;
7298 #endif
7299 #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
7300  ca_cert_file_path_ = rhs.ca_cert_file_path_;
7301  ca_cert_dir_path_ = rhs.ca_cert_dir_path_;
7302  ca_cert_store_ = rhs.ca_cert_store_;
7303 #endif
7304 #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
7305  server_certificate_verification_ = rhs.server_certificate_verification_;
7306  server_hostname_verification_ = rhs.server_hostname_verification_;
7307  server_certificate_verifier_ = rhs.server_certificate_verifier_;
7308 #endif
7309  logger_ = rhs.logger_;
7310 }
7311 
7312 inline socket_t ClientImpl::create_client_socket(Error &error) const {
7313  if (!proxy_host_.empty() && proxy_port_ != -1) {
7319  }
7320 
7321  // Check is custom IP specified for host_
7322  std::string ip;
7323  auto it = addr_map_.find(host_);
7324  if (it != addr_map_.end()) { ip = it->second; }
7325 
7331 }
7332 
7334  Error &error) {
7335  auto sock = create_client_socket(error);
7336  if (sock == INVALID_SOCKET) { return false; }
7337  socket.sock = sock;
7338  return true;
7339 }
7340 
7341 inline void ClientImpl::shutdown_ssl(Socket & /*socket*/,
7342  bool /*shutdown_gracefully*/) {
7343  // If there are any requests in flight from threads other than us, then it's
7344  // a thread-unsafe race because individual ssl* objects are not thread-safe.
7345  assert(socket_requests_in_flight_ == 0 ||
7346  socket_requests_are_from_thread_ == std::this_thread::get_id());
7347 }
7348 
7349 inline void ClientImpl::shutdown_socket(Socket &socket) const {
7350  if (socket.sock == INVALID_SOCKET) { return; }
7352 }
7353 
7354 inline void ClientImpl::close_socket(Socket &socket) {
7355  // If there are requests in flight in another thread, usually closing
7356  // the socket will be fine and they will simply receive an error when
7357  // using the closed socket, but it is still a bug since rarely the OS
7358  // may reassign the socket id to be used for a new socket, and then
7359  // suddenly they will be operating on a live socket that is different
7360  // than the one they intended!
7361  assert(socket_requests_in_flight_ == 0 ||
7362  socket_requests_are_from_thread_ == std::this_thread::get_id());
7363 
7364  // It is also a bug if this happens while SSL is still active
7365 #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
7366  assert(socket.ssl == nullptr);
7367 #endif
7368  if (socket.sock == INVALID_SOCKET) { return; }
7370  socket.sock = INVALID_SOCKET;
7371 }
7372 
7373 inline bool ClientImpl::read_response_line(Stream &strm, const Request &req,
7374  Response &res) const {
7375  std::array<char, 2048> buf{};
7376 
7377  detail::stream_line_reader line_reader(strm, buf.data(), buf.size());
7378 
7379  if (!line_reader.getline()) { return false; }
7380 
7381 #ifdef CPPHTTPLIB_ALLOW_LF_AS_LINE_TERMINATOR
7382  const static std::regex re("(HTTP/1\\.[01]) (\\d{3})(?: (.*?))?\r?\n");
7383 #else
7384  const static std::regex re("(HTTP/1\\.[01]) (\\d{3})(?: (.*?))?\r\n");
7385 #endif
7386 
7387  std::cmatch m;
7388  if (!std::regex_match(line_reader.ptr(), m, re)) {
7389  return req.method == "CONNECT";
7390  }
7391  res.version = std::string(m[1]);
7392  res.status = std::stoi(std::string(m[2]));
7393  res.reason = std::string(m[3]);
7394 
7395  // Ignore '100 Continue'
7396  while (res.status == StatusCode::Continue_100) {
7397  if (!line_reader.getline()) { return false; } // CRLF
7398  if (!line_reader.getline()) { return false; } // next response line
7399 
7400  if (!std::regex_match(line_reader.ptr(), m, re)) { return false; }
7401  res.version = std::string(m[1]);
7402  res.status = std::stoi(std::string(m[2]));
7403  res.reason = std::string(m[3]);
7404  }
7405 
7406  return true;
7407 }
7408 
7409 inline bool ClientImpl::send(Request &req, Response &res, Error &error) {
7410  std::lock_guard<std::recursive_mutex> request_mutex_guard(request_mutex_);
7411  auto ret = send_(req, res, error);
7412  if (error == Error::SSLPeerCouldBeClosed_) {
7413  assert(!ret);
7414  ret = send_(req, res, error);
7415  }
7416  return ret;
7417 }
7418 
7419 #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
7420 inline bool ClientImpl::is_ssl_peer_could_be_closed(SSL *ssl) const {
7422  auto se = detail::scope_exit(
7423  [&]() { detail::set_nonblocking(socket_.sock, false); });
7424 
7425  char buf[1];
7426  return !SSL_peek(ssl, buf, 1) &&
7427  SSL_get_error(ssl, 0) == SSL_ERROR_ZERO_RETURN;
7428 }
7429 #endif
7430 
7431 inline bool ClientImpl::send_(Request &req, Response &res, Error &error) {
7432  {
7433  std::lock_guard<std::mutex> guard(socket_mutex_);
7434 
7435  // Set this to false immediately - if it ever gets set to true by the end of
7436  // the request, we know another thread instructed us to close the socket.
7438 
7439  auto is_alive = false;
7440  if (socket_.is_open()) {
7441  is_alive = detail::is_socket_alive(socket_.sock);
7442 
7443 #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
7444  if (is_alive && is_ssl()) {
7445  if (is_ssl_peer_could_be_closed(socket_.ssl)) { is_alive = false; }
7446  }
7447 #endif
7448 
7449  if (!is_alive) {
7450  // Attempt to avoid sigpipe by shutting down nongracefully if it seems
7451  // like the other side has already closed the connection Also, there
7452  // cannot be any requests in flight from other threads since we locked
7453  // request_mutex_, so safe to close everything immediately
7454  const bool shutdown_gracefully = false;
7455  shutdown_ssl(socket_, shutdown_gracefully);
7458  }
7459  }
7460 
7461  if (!is_alive) {
7462  if (!create_and_connect_socket(socket_, error)) { return false; }
7463 
7464 #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
7465  // TODO: refactoring
7466  if (is_ssl()) {
7467  auto &scli = static_cast<SSLClient &>(*this);
7468  if (!proxy_host_.empty() && proxy_port_ != -1) {
7469  auto success = false;
7470  if (!scli.connect_with_proxy(socket_, res, success, error)) {
7471  return success;
7472  }
7473  }
7474 
7475  if (!scli.initialize_ssl(socket_, error)) { return false; }
7476  }
7477 #endif
7478  }
7479 
7480  // Mark the current socket as being in use so that it cannot be closed by
7481  // anyone else while this request is ongoing, even though we will be
7482  // releasing the mutex.
7483  if (socket_requests_in_flight_ > 1) {
7484  assert(socket_requests_are_from_thread_ == std::this_thread::get_id());
7485  }
7487  socket_requests_are_from_thread_ = std::this_thread::get_id();
7488  }
7489 
7490  for (const auto &header : default_headers_) {
7491  if (req.headers.find(header.first) == req.headers.end()) {
7492  req.headers.insert(header);
7493  }
7494  }
7495 
7496  auto ret = false;
7497  auto close_connection = !keep_alive_;
7498 
7499  auto se = detail::scope_exit([&]() {
7500  // Briefly lock mutex in order to mark that a request is no longer ongoing
7501  std::lock_guard<std::mutex> guard(socket_mutex_);
7503  if (socket_requests_in_flight_ <= 0) {
7504  assert(socket_requests_in_flight_ == 0);
7505  socket_requests_are_from_thread_ = std::thread::id();
7506  }
7507 
7508  if (socket_should_be_closed_when_request_is_done_ || close_connection ||
7509  !ret) {
7510  shutdown_ssl(socket_, true);
7513  }
7514  });
7515 
7516  ret = process_socket(socket_, [&](Stream &strm) {
7517  return handle_request(strm, req, res, close_connection, error);
7518  });
7519 
7520  if (!ret) {
7521  if (error == Error::Success) { error = Error::Unknown; }
7522  }
7523 
7524  return ret;
7525 }
7526 
7527 inline Result ClientImpl::send(const Request &req) {
7528  auto req2 = req;
7529  return send_(std::move(req2));
7530 }
7531 
7532 inline Result ClientImpl::send_(Request &&req) {
7533  auto res = detail::make_unique<Response>();
7534  auto error = Error::Success;
7535  auto ret = send(req, *res, error);
7536  return Result{ret ? std::move(res) : nullptr, error, std::move(req.headers)};
7537 }
7538 
7539 inline bool ClientImpl::handle_request(Stream &strm, Request &req,
7540  Response &res, bool close_connection,
7541  Error &error) {
7542  if (req.path.empty()) {
7543  error = Error::Connection;
7544  return false;
7545  }
7546 
7547  auto req_save = req;
7548 
7549  bool ret;
7550 
7551  if (!is_ssl() && !proxy_host_.empty() && proxy_port_ != -1) {
7552  auto req2 = req;
7553  req2.path = "http://" + host_and_port_ + req.path;
7554  ret = process_request(strm, req2, res, close_connection, error);
7555  req = req2;
7556  req.path = req_save.path;
7557  } else {
7558  ret = process_request(strm, req, res, close_connection, error);
7559  }
7560 
7561  if (!ret) { return false; }
7562 
7563  if (res.get_header_value("Connection") == "close" ||
7564  (res.version == "HTTP/1.0" && res.reason != "Connection established")) {
7565  // TODO this requires a not-entirely-obvious chain of calls to be correct
7566  // for this to be safe.
7567 
7568  // This is safe to call because handle_request is only called by send_
7569  // which locks the request mutex during the process. It would be a bug
7570  // to call it from a different thread since it's a thread-safety issue
7571  // to do these things to the socket if another thread is using the socket.
7572  std::lock_guard<std::mutex> guard(socket_mutex_);
7573  shutdown_ssl(socket_, true);
7576  }
7577 
7578  if (300 < res.status && res.status < 400 && follow_location_) {
7579  req = req_save;
7580  ret = redirect(req, res, error);
7581  }
7582 
7583 #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
7584  if ((res.status == StatusCode::Unauthorized_401 ||
7586  req.authorization_count_ < 5) {
7587  auto is_proxy = res.status == StatusCode::ProxyAuthenticationRequired_407;
7588  const auto &username =
7589  is_proxy ? proxy_digest_auth_username_ : digest_auth_username_;
7590  const auto &password =
7591  is_proxy ? proxy_digest_auth_password_ : digest_auth_password_;
7592 
7593  if (!username.empty() && !password.empty()) {
7594  std::map<std::string, std::string> auth;
7595  if (detail::parse_www_authenticate(res, auth, is_proxy)) {
7596  Request new_req = req;
7597  new_req.authorization_count_ += 1;
7598  new_req.headers.erase(is_proxy ? "Proxy-Authorization"
7599  : "Authorization");
7600  new_req.headers.insert(detail::make_digest_authentication_header(
7601  req, auth, new_req.authorization_count_, detail::random_string(10),
7602  username, password, is_proxy));
7603 
7604  Response new_res;
7605 
7606  ret = send(new_req, new_res, error);
7607  if (ret) { res = new_res; }
7608  }
7609  }
7610  }
7611 #endif
7612 
7613  return ret;
7614 }
7615 
7616 inline bool ClientImpl::redirect(Request &req, Response &res, Error &error) {
7617  if (req.redirect_count_ == 0) {
7619  return false;
7620  }
7621 
7622  auto location = res.get_header_value("location");
7623  if (location.empty()) { return false; }
7624 
7625  const static std::regex re(
7626  R"((?:(https?):)?(?://(?:\[([a-fA-F\d:]+)\]|([^:/?#]+))(?::(\d+))?)?([^?#]*)(\?[^#]*)?(?:#.*)?)");
7627 
7628  std::smatch m;
7629  if (!std::regex_match(location, m, re)) { return false; }
7630 
7631  auto scheme = is_ssl() ? "https" : "http";
7632 
7633  auto next_scheme = m[1].str();
7634  auto next_host = m[2].str();
7635  if (next_host.empty()) { next_host = m[3].str(); }
7636  auto port_str = m[4].str();
7637  auto next_path = m[5].str();
7638  auto next_query = m[6].str();
7639 
7640  auto next_port = port_;
7641  if (!port_str.empty()) {
7642  next_port = std::stoi(port_str);
7643  } else if (!next_scheme.empty()) {
7644  next_port = next_scheme == "https" ? 443 : 80;
7645  }
7646 
7647  if (next_scheme.empty()) { next_scheme = scheme; }
7648  if (next_host.empty()) { next_host = host_; }
7649  if (next_path.empty()) { next_path = "/"; }
7650 
7651  auto path = detail::decode_url(next_path, true) + next_query;
7652 
7653  if (next_scheme == scheme && next_host == host_ && next_port == port_) {
7654  return detail::redirect(*this, req, res, path, location, error);
7655  } else {
7656  if (next_scheme == "https") {
7657 #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
7658  SSLClient cli(next_host, next_port);
7659  cli.copy_settings(*this);
7660  if (ca_cert_store_) { cli.set_ca_cert_store(ca_cert_store_); }
7661  return detail::redirect(cli, req, res, path, location, error);
7662 #else
7663  return false;
7664 #endif
7665  } else {
7666  ClientImpl cli(next_host, next_port);
7667  cli.copy_settings(*this);
7668  return detail::redirect(cli, req, res, path, location, error);
7669  }
7670  }
7671 }
7672 
7674  const Request &req,
7675  Error &error) const {
7676  auto is_shutting_down = []() { return false; };
7677 
7678  if (req.is_chunked_content_provider_) {
7679  // TODO: Brotli support
7680  std::unique_ptr<detail::compressor> compressor;
7681 #ifdef CPPHTTPLIB_ZLIB_SUPPORT
7682  if (compress_) {
7683  compressor = detail::make_unique<detail::gzip_compressor>();
7684  } else
7685 #endif
7686  {
7687  compressor = detail::make_unique<detail::nocompressor>();
7688  }
7689 
7691  is_shutting_down, *compressor, error);
7692  } else {
7693  return detail::write_content(strm, req.content_provider_, 0,
7694  req.content_length_, is_shutting_down, error);
7695  }
7696 }
7697 
7698 inline bool ClientImpl::write_request(Stream &strm, Request &req,
7699  bool close_connection, Error &error) {
7700  // Prepare additional headers
7701  if (close_connection) {
7702  if (!req.has_header("Connection")) {
7703  req.set_header("Connection", "close");
7704  }
7705  }
7706 
7707  if (!req.has_header("Host")) {
7708  if (is_ssl()) {
7709  if (port_ == 443) {
7710  req.set_header("Host", host_);
7711  } else {
7712  req.set_header("Host", host_and_port_);
7713  }
7714  } else {
7715  if (port_ == 80) {
7716  req.set_header("Host", host_);
7717  } else {
7718  req.set_header("Host", host_and_port_);
7719  }
7720  }
7721  }
7722 
7723  if (!req.has_header("Accept")) { req.set_header("Accept", "*/*"); }
7724 
7725  if (!req.content_receiver) {
7726  if (!req.has_header("Accept-Encoding")) {
7727  std::string accept_encoding;
7728 #ifdef CPPHTTPLIB_BROTLI_SUPPORT
7729  accept_encoding = "br";
7730 #endif
7731 #ifdef CPPHTTPLIB_ZLIB_SUPPORT
7732  if (!accept_encoding.empty()) { accept_encoding += ", "; }
7733  accept_encoding += "gzip, deflate";
7734 #endif
7735  req.set_header("Accept-Encoding", accept_encoding);
7736  }
7737 
7738 #ifndef CPPHTTPLIB_NO_DEFAULT_USER_AGENT
7739  if (!req.has_header("User-Agent")) {
7740  auto agent = std::string("cpp-httplib/") + CPPHTTPLIB_VERSION;
7741  req.set_header("User-Agent", agent);
7742  }
7743 #endif
7744  };
7745 
7746  if (req.body.empty()) {
7747  if (req.content_provider_) {
7748  if (!req.is_chunked_content_provider_) {
7749  if (!req.has_header("Content-Length")) {
7750  auto length = std::to_string(req.content_length_);
7751  req.set_header("Content-Length", length);
7752  }
7753  }
7754  } else {
7755  if (req.method == "POST" || req.method == "PUT" ||
7756  req.method == "PATCH") {
7757  req.set_header("Content-Length", "0");
7758  }
7759  }
7760  } else {
7761  if (!req.has_header("Content-Type")) {
7762  req.set_header("Content-Type", "text/plain");
7763  }
7764 
7765  if (!req.has_header("Content-Length")) {
7766  auto length = std::to_string(req.body.size());
7767  req.set_header("Content-Length", length);
7768  }
7769  }
7770 
7771  if (!basic_auth_password_.empty() || !basic_auth_username_.empty()) {
7772  if (!req.has_header("Authorization")) {
7775  }
7776  }
7777 
7778  if (!proxy_basic_auth_username_.empty() &&
7779  !proxy_basic_auth_password_.empty()) {
7780  if (!req.has_header("Proxy-Authorization")) {
7783  }
7784  }
7785 
7786  if (!bearer_token_auth_token_.empty()) {
7787  if (!req.has_header("Authorization")) {
7789  bearer_token_auth_token_, false));
7790  }
7791  }
7792 
7793  if (!proxy_bearer_token_auth_token_.empty()) {
7794  if (!req.has_header("Proxy-Authorization")) {
7797  }
7798  }
7799 
7800  // Request line and headers
7801  {
7802  detail::BufferStream bstrm;
7803 
7804  const auto &path_with_query =
7805  req.params.empty() ? req.path
7806  : append_query_params(req.path, req.params);
7807 
7808  const auto &path =
7809  url_encode_ ? detail::encode_url(path_with_query) : path_with_query;
7810 
7811  detail::write_request_line(bstrm, req.method, path);
7812 
7813  header_writer_(bstrm, req.headers);
7814 
7815  // Flush buffer
7816  auto &data = bstrm.get_buffer();
7817  if (!detail::write_data(strm, data.data(), data.size())) {
7818  error = Error::Write;
7819  return false;
7820  }
7821  }
7822 
7823  // Body
7824  if (req.body.empty()) {
7825  return write_content_with_provider(strm, req, error);
7826  }
7827 
7828  if (!detail::write_data(strm, req.body.data(), req.body.size())) {
7829  error = Error::Write;
7830  return false;
7831  }
7832 
7833  return true;
7834 }
7835 
7836 inline std::unique_ptr<Response> ClientImpl::send_with_content_provider(
7837  Request &req, const char *body, size_t content_length,
7838  ContentProvider content_provider,
7839  ContentProviderWithoutLength content_provider_without_length,
7840  const std::string &content_type, Error &error) {
7841  if (!content_type.empty()) { req.set_header("Content-Type", content_type); }
7842 
7843 #ifdef CPPHTTPLIB_ZLIB_SUPPORT
7844  if (compress_) { req.set_header("Content-Encoding", "gzip"); }
7845 #endif
7846 
7847 #ifdef CPPHTTPLIB_ZLIB_SUPPORT
7848  if (compress_ && !content_provider_without_length) {
7849  // TODO: Brotli support
7850  detail::gzip_compressor compressor;
7851 
7852  if (content_provider) {
7853  auto ok = true;
7854  size_t offset = 0;
7855  DataSink data_sink;
7856 
7857  data_sink.write = [&](const char *data, size_t data_len) -> bool {
7858  if (ok) {
7859  auto last = offset + data_len == content_length;
7860 
7861  auto ret = compressor.compress(
7862  data, data_len, last,
7863  [&](const char *compressed_data, size_t compressed_data_len) {
7864  req.body.append(compressed_data, compressed_data_len);
7865  return true;
7866  });
7867 
7868  if (ret) {
7869  offset += data_len;
7870  } else {
7871  ok = false;
7872  }
7873  }
7874  return ok;
7875  };
7876 
7877  while (ok && offset < content_length) {
7878  if (!content_provider(offset, content_length - offset, data_sink)) {
7879  error = Error::Canceled;
7880  return nullptr;
7881  }
7882  }
7883  } else {
7884  if (!compressor.compress(body, content_length, true,
7885  [&](const char *data, size_t data_len) {
7886  req.body.append(data, data_len);
7887  return true;
7888  })) {
7889  error = Error::Compression;
7890  return nullptr;
7891  }
7892  }
7893  } else
7894 #endif
7895  {
7896  if (content_provider) {
7897  req.content_length_ = content_length;
7898  req.content_provider_ = std::move(content_provider);
7899  req.is_chunked_content_provider_ = false;
7900  } else if (content_provider_without_length) {
7901  req.content_length_ = 0;
7902  req.content_provider_ = detail::ContentProviderAdapter(
7903  std::move(content_provider_without_length));
7904  req.is_chunked_content_provider_ = true;
7905  req.set_header("Transfer-Encoding", "chunked");
7906  } else {
7907  req.body.assign(body, content_length);
7908  }
7909  }
7910 
7911  auto res = detail::make_unique<Response>();
7912  return send(req, *res, error) ? std::move(res) : nullptr;
7913 }
7914 
7915 inline Result ClientImpl::send_with_content_provider(
7916  const std::string &method, const std::string &path, const Headers &headers,
7917  const char *body, size_t content_length, ContentProvider content_provider,
7918  ContentProviderWithoutLength content_provider_without_length,
7919  const std::string &content_type, Progress progress) {
7920  Request req;
7921  req.method = method;
7922  req.headers = headers;
7923  req.path = path;
7924  req.progress = progress;
7925 
7926  auto error = Error::Success;
7927 
7928  auto res = send_with_content_provider(
7929  req, body, content_length, std::move(content_provider),
7930  std::move(content_provider_without_length), content_type, error);
7931 
7932  return Result{std::move(res), error, std::move(req.headers)};
7933 }
7934 
7935 inline std::string
7936 ClientImpl::adjust_host_string(const std::string &host) const {
7937  if (host.find(':') != std::string::npos) { return "[" + host + "]"; }
7938  return host;
7939 }
7940 
7942  Response &res, bool close_connection,
7943  Error &error) {
7944  // Send request
7945  if (!write_request(strm, req, close_connection, error)) { return false; }
7946 
7947 #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
7948  if (is_ssl()) {
7949  auto is_proxy_enabled = !proxy_host_.empty() && proxy_port_ != -1;
7950  if (!is_proxy_enabled) {
7951  if (is_ssl_peer_could_be_closed(socket_.ssl)) {
7953  return false;
7954  }
7955  }
7956  }
7957 #endif
7958 
7959  // Receive response and headers
7960  if (!read_response_line(strm, req, res) ||
7961  !detail::read_headers(strm, res.headers)) {
7962  error = Error::Read;
7963  return false;
7964  }
7965 
7966  // Body
7967  if ((res.status != StatusCode::NoContent_204) && req.method != "HEAD" &&
7968  req.method != "CONNECT") {
7969  auto redirect = 300 < res.status && res.status < 400 &&
7972 
7973  if (req.response_handler && !redirect) {
7974  if (!req.response_handler(res)) {
7975  error = Error::Canceled;
7976  return false;
7977  }
7978  }
7979 
7980  auto out =
7981  req.content_receiver
7982  ? static_cast<ContentReceiverWithProgress>(
7983  [&](const char *buf, size_t n, uint64_t off, uint64_t len) {
7984  if (redirect) { return true; }
7985  auto ret = req.content_receiver(buf, n, off, len);
7986  if (!ret) { error = Error::Canceled; }
7987  return ret;
7988  })
7989  : static_cast<ContentReceiverWithProgress>(
7990  [&](const char *buf, size_t n, uint64_t /*off*/,
7991  uint64_t /*len*/) {
7992  assert(res.body.size() + n <= res.body.max_size());
7993  res.body.append(buf, n);
7994  return true;
7995  });
7996 
7997  auto progress = [&](uint64_t current, uint64_t total) {
7998  if (!req.progress || redirect) { return true; }
7999  auto ret = req.progress(current, total);
8000  if (!ret) { error = Error::Canceled; }
8001  return ret;
8002  };
8003 
8004  if (res.has_header("Content-Length")) {
8005  if (!req.content_receiver) {
8006  auto len = res.get_header_value_u64("Content-Length");
8007  if (len > res.body.max_size()) {
8008  error = Error::Read;
8009  return false;
8010  }
8011  res.body.reserve(static_cast<size_t>(len));
8012  }
8013  }
8014 
8015  if (res.status != StatusCode::NotModified_304) {
8016  int dummy_status;
8018  dummy_status, std::move(progress),
8019  std::move(out), decompress_)) {
8020  if (error != Error::Canceled) { error = Error::Read; }
8021  return false;
8022  }
8023  }
8024  }
8025 
8026  // Log
8027  if (logger_) { logger_(req, res); }
8028 
8029  return true;
8030 }
8031 
8032 inline ContentProviderWithoutLength ClientImpl::get_multipart_content_provider(
8033  const std::string &boundary, const MultipartFormDataItems &items,
8034  const MultipartFormDataProviderItems &provider_items) const {
8035  size_t cur_item = 0;
8036  size_t cur_start = 0;
8037  // cur_item and cur_start are copied to within the std::function and maintain
8038  // state between successive calls
8039  return [&, cur_item, cur_start](size_t offset,
8040  DataSink &sink) mutable -> bool {
8041  if (!offset && !items.empty()) {
8042  sink.os << detail::serialize_multipart_formdata(items, boundary, false);
8043  return true;
8044  } else if (cur_item < provider_items.size()) {
8045  if (!cur_start) {
8047  provider_items[cur_item], boundary);
8048  offset += begin.size();
8049  cur_start = offset;
8050  sink.os << begin;
8051  }
8052 
8053  DataSink cur_sink;
8054  auto has_data = true;
8055  cur_sink.write = sink.write;
8056  cur_sink.done = [&]() { has_data = false; };
8057 
8058  if (!provider_items[cur_item].provider(offset - cur_start, cur_sink)) {
8059  return false;
8060  }
8061 
8062  if (!has_data) {
8064  cur_item++;
8065  cur_start = 0;
8066  }
8067  return true;
8068  } else {
8069  sink.os << detail::serialize_multipart_formdata_finish(boundary);
8070  sink.done();
8071  return true;
8072  }
8073  };
8074 }
8075 
8076 inline bool
8077 ClientImpl::process_socket(const Socket &socket,
8078  std::function<bool(Stream &strm)> callback) {
8081  write_timeout_usec_, std::move(callback));
8082 }
8083 
8084 inline bool ClientImpl::is_ssl() const { return false; }
8085 
8086 inline Result ClientImpl::Get(const std::string &path) {
8087  return Get(path, Headers(), Progress());
8088 }
8089 
8090 inline Result ClientImpl::Get(const std::string &path, Progress progress) {
8091  return Get(path, Headers(), std::move(progress));
8092 }
8093 
8094 inline Result ClientImpl::Get(const std::string &path, const Headers &headers) {
8095  return Get(path, headers, Progress());
8096 }
8097 
8098 inline Result ClientImpl::Get(const std::string &path, const Headers &headers,
8099  Progress progress) {
8100  Request req;
8101  req.method = "GET";
8102  req.path = path;
8103  req.headers = headers;
8104  req.progress = std::move(progress);
8105 
8106  return send_(std::move(req));
8107 }
8108 
8109 inline Result ClientImpl::Get(const std::string &path,
8110  ContentReceiver content_receiver) {
8111  return Get(path, Headers(), nullptr, std::move(content_receiver), nullptr);
8112 }
8113 
8114 inline Result ClientImpl::Get(const std::string &path,
8115  ContentReceiver content_receiver,
8116  Progress progress) {
8117  return Get(path, Headers(), nullptr, std::move(content_receiver),
8118  std::move(progress));
8119 }
8120 
8121 inline Result ClientImpl::Get(const std::string &path, const Headers &headers,
8122  ContentReceiver content_receiver) {
8123  return Get(path, headers, nullptr, std::move(content_receiver), nullptr);
8124 }
8125 
8126 inline Result ClientImpl::Get(const std::string &path, const Headers &headers,
8127  ContentReceiver content_receiver,
8128  Progress progress) {
8129  return Get(path, headers, nullptr, std::move(content_receiver),
8130  std::move(progress));
8131 }
8132 
8133 inline Result ClientImpl::Get(const std::string &path,
8134  ResponseHandler response_handler,
8135  ContentReceiver content_receiver) {
8136  return Get(path, Headers(), std::move(response_handler),
8137  std::move(content_receiver), nullptr);
8138 }
8139 
8140 inline Result ClientImpl::Get(const std::string &path, const Headers &headers,
8141  ResponseHandler response_handler,
8142  ContentReceiver content_receiver) {
8143  return Get(path, headers, std::move(response_handler),
8144  std::move(content_receiver), nullptr);
8145 }
8146 
8147 inline Result ClientImpl::Get(const std::string &path,
8148  ResponseHandler response_handler,
8149  ContentReceiver content_receiver,
8150  Progress progress) {
8151  return Get(path, Headers(), std::move(response_handler),
8152  std::move(content_receiver), std::move(progress));
8153 }
8154 
8155 inline Result ClientImpl::Get(const std::string &path, const Headers &headers,
8156  ResponseHandler response_handler,
8157  ContentReceiver content_receiver,
8158  Progress progress) {
8159  Request req;
8160  req.method = "GET";
8161  req.path = path;
8162  req.headers = headers;
8163  req.response_handler = std::move(response_handler);
8164  req.content_receiver =
8165  [content_receiver](const char *data, size_t data_length,
8166  uint64_t /*offset*/, uint64_t /*total_length*/) {
8167  return content_receiver(data, data_length);
8168  };
8169  req.progress = std::move(progress);
8170 
8171  return send_(std::move(req));
8172 }
8173 
8174 inline Result ClientImpl::Get(const std::string &path, const Params &params,
8175  const Headers &headers, Progress progress) {
8176  if (params.empty()) { return Get(path, headers); }
8177 
8178  std::string path_with_query = append_query_params(path, params);
8179  return Get(path_with_query, headers, std::move(progress));
8180 }
8181 
8182 inline Result ClientImpl::Get(const std::string &path, const Params &params,
8183  const Headers &headers,
8184  ContentReceiver content_receiver,
8185  Progress progress) {
8186  return Get(path, params, headers, nullptr, std::move(content_receiver),
8187  std::move(progress));
8188 }
8189 
8190 inline Result ClientImpl::Get(const std::string &path, const Params &params,
8191  const Headers &headers,
8192  ResponseHandler response_handler,
8193  ContentReceiver content_receiver,
8194  Progress progress) {
8195  if (params.empty()) {
8196  return Get(path, headers, std::move(response_handler),
8197  std::move(content_receiver), std::move(progress));
8198  }
8199 
8200  std::string path_with_query = append_query_params(path, params);
8201  return Get(path_with_query, headers, std::move(response_handler),
8202  std::move(content_receiver), std::move(progress));
8203 }
8204 
8205 inline Result ClientImpl::Head(const std::string &path) {
8206  return Head(path, Headers());
8207 }
8208 
8209 inline Result ClientImpl::Head(const std::string &path,
8210  const Headers &headers) {
8211  Request req;
8212  req.method = "HEAD";
8213  req.headers = headers;
8214  req.path = path;
8215 
8216  return send_(std::move(req));
8217 }
8218 
8219 inline Result ClientImpl::Post(const std::string &path) {
8220  return Post(path, std::string(), std::string());
8221 }
8222 
8223 inline Result ClientImpl::Post(const std::string &path,
8224  const Headers &headers) {
8225  return Post(path, headers, nullptr, 0, std::string());
8226 }
8227 
8228 inline Result ClientImpl::Post(const std::string &path, const char *body,
8229  size_t content_length,
8230  const std::string &content_type) {
8231  return Post(path, Headers(), body, content_length, content_type, nullptr);
8232 }
8233 
8234 inline Result ClientImpl::Post(const std::string &path, const Headers &headers,
8235  const char *body, size_t content_length,
8236  const std::string &content_type) {
8237  return send_with_content_provider("POST", path, headers, body, content_length,
8238  nullptr, nullptr, content_type, nullptr);
8239 }
8240 
8241 inline Result ClientImpl::Post(const std::string &path, const Headers &headers,
8242  const char *body, size_t content_length,
8243  const std::string &content_type,
8244  Progress progress) {
8245  return send_with_content_provider("POST", path, headers, body, content_length,
8246  nullptr, nullptr, content_type, progress);
8247 }
8248 
8249 inline Result ClientImpl::Post(const std::string &path, const std::string &body,
8250  const std::string &content_type) {
8251  return Post(path, Headers(), body, content_type);
8252 }
8253 
8254 inline Result ClientImpl::Post(const std::string &path, const std::string &body,
8255  const std::string &content_type,
8256  Progress progress) {
8257  return Post(path, Headers(), body, content_type, progress);
8258 }
8259 
8260 inline Result ClientImpl::Post(const std::string &path, const Headers &headers,
8261  const std::string &body,
8262  const std::string &content_type) {
8263  return send_with_content_provider("POST", path, headers, body.data(),
8264  body.size(), nullptr, nullptr, content_type,
8265  nullptr);
8266 }
8267 
8268 inline Result ClientImpl::Post(const std::string &path, const Headers &headers,
8269  const std::string &body,
8270  const std::string &content_type,
8271  Progress progress) {
8272  return send_with_content_provider("POST", path, headers, body.data(),
8273  body.size(), nullptr, nullptr, content_type,
8274  progress);
8275 }
8276 
8277 inline Result ClientImpl::Post(const std::string &path, const Params &params) {
8278  return Post(path, Headers(), params);
8279 }
8280 
8281 inline Result ClientImpl::Post(const std::string &path, size_t content_length,
8282  ContentProvider content_provider,
8283  const std::string &content_type) {
8284  return Post(path, Headers(), content_length, std::move(content_provider),
8285  content_type);
8286 }
8287 
8288 inline Result ClientImpl::Post(const std::string &path,
8289  ContentProviderWithoutLength content_provider,
8290  const std::string &content_type) {
8291  return Post(path, Headers(), std::move(content_provider), content_type);
8292 }
8293 
8294 inline Result ClientImpl::Post(const std::string &path, const Headers &headers,
8295  size_t content_length,
8296  ContentProvider content_provider,
8297  const std::string &content_type) {
8298  return send_with_content_provider("POST", path, headers, nullptr,
8299  content_length, std::move(content_provider),
8300  nullptr, content_type, nullptr);
8301 }
8302 
8303 inline Result ClientImpl::Post(const std::string &path, const Headers &headers,
8304  ContentProviderWithoutLength content_provider,
8305  const std::string &content_type) {
8306  return send_with_content_provider("POST", path, headers, nullptr, 0, nullptr,
8307  std::move(content_provider), content_type,
8308  nullptr);
8309 }
8310 
8311 inline Result ClientImpl::Post(const std::string &path, const Headers &headers,
8312  const Params &params) {
8313  auto query = detail::params_to_query_str(params);
8314  return Post(path, headers, query, "application/x-www-form-urlencoded");
8315 }
8316 
8317 inline Result ClientImpl::Post(const std::string &path, const Headers &headers,
8318  const Params &params, Progress progress) {
8319  auto query = detail::params_to_query_str(params);
8320  return Post(path, headers, query, "application/x-www-form-urlencoded",
8321  progress);
8322 }
8323 
8324 inline Result ClientImpl::Post(const std::string &path,
8325  const MultipartFormDataItems &items) {
8326  return Post(path, Headers(), items);
8327 }
8328 
8329 inline Result ClientImpl::Post(const std::string &path, const Headers &headers,
8330  const MultipartFormDataItems &items) {
8331  const auto &boundary = detail::make_multipart_data_boundary();
8332  const auto &content_type =
8334  const auto &body = detail::serialize_multipart_formdata(items, boundary);
8335  return Post(path, headers, body, content_type);
8336 }
8337 
8338 inline Result ClientImpl::Post(const std::string &path, const Headers &headers,
8339  const MultipartFormDataItems &items,
8340  const std::string &boundary) {
8343  }
8344 
8345  const auto &content_type =
8347  const auto &body = detail::serialize_multipart_formdata(items, boundary);
8348  return Post(path, headers, body, content_type);
8349 }
8350 
8351 inline Result
8352 ClientImpl::Post(const std::string &path, const Headers &headers,
8353  const MultipartFormDataItems &items,
8354  const MultipartFormDataProviderItems &provider_items) {
8355  const auto &boundary = detail::make_multipart_data_boundary();
8356  const auto &content_type =
8358  return send_with_content_provider(
8359  "POST", path, headers, nullptr, 0, nullptr,
8360  get_multipart_content_provider(boundary, items, provider_items),
8361  content_type, nullptr);
8362 }
8363 
8364 inline Result ClientImpl::Put(const std::string &path) {
8365  return Put(path, std::string(), std::string());
8366 }
8367 
8368 inline Result ClientImpl::Put(const std::string &path, const char *body,
8369  size_t content_length,
8370  const std::string &content_type) {
8371  return Put(path, Headers(), body, content_length, content_type);
8372 }
8373 
8374 inline Result ClientImpl::Put(const std::string &path, const Headers &headers,
8375  const char *body, size_t content_length,
8376  const std::string &content_type) {
8377  return send_with_content_provider("PUT", path, headers, body, content_length,
8378  nullptr, nullptr, content_type, nullptr);
8379 }
8380 
8381 inline Result ClientImpl::Put(const std::string &path, const Headers &headers,
8382  const char *body, size_t content_length,
8383  const std::string &content_type,
8384  Progress progress) {
8385  return send_with_content_provider("PUT", path, headers, body, content_length,
8386  nullptr, nullptr, content_type, progress);
8387 }
8388 
8389 inline Result ClientImpl::Put(const std::string &path, const std::string &body,
8390  const std::string &content_type) {
8391  return Put(path, Headers(), body, content_type);
8392 }
8393 
8394 inline Result ClientImpl::Put(const std::string &path, const std::string &body,
8395  const std::string &content_type,
8396  Progress progress) {
8397  return Put(path, Headers(), body, content_type, progress);
8398 }
8399 
8400 inline Result ClientImpl::Put(const std::string &path, const Headers &headers,
8401  const std::string &body,
8402  const std::string &content_type) {
8403  return send_with_content_provider("PUT", path, headers, body.data(),
8404  body.size(), nullptr, nullptr, content_type,
8405  nullptr);
8406 }
8407 
8408 inline Result ClientImpl::Put(const std::string &path, const Headers &headers,
8409  const std::string &body,
8410  const std::string &content_type,
8411  Progress progress) {
8412  return send_with_content_provider("PUT", path, headers, body.data(),
8413  body.size(), nullptr, nullptr, content_type,
8414  progress);
8415 }
8416 
8417 inline Result ClientImpl::Put(const std::string &path, size_t content_length,
8418  ContentProvider content_provider,
8419  const std::string &content_type) {
8420  return Put(path, Headers(), content_length, std::move(content_provider),
8421  content_type);
8422 }
8423 
8424 inline Result ClientImpl::Put(const std::string &path,
8425  ContentProviderWithoutLength content_provider,
8426  const std::string &content_type) {
8427  return Put(path, Headers(), std::move(content_provider), content_type);
8428 }
8429 
8430 inline Result ClientImpl::Put(const std::string &path, const Headers &headers,
8431  size_t content_length,
8432  ContentProvider content_provider,
8433  const std::string &content_type) {
8434  return send_with_content_provider("PUT", path, headers, nullptr,
8435  content_length, std::move(content_provider),
8436  nullptr, content_type, nullptr);
8437 }
8438 
8439 inline Result ClientImpl::Put(const std::string &path, const Headers &headers,
8440  ContentProviderWithoutLength content_provider,
8441  const std::string &content_type) {
8442  return send_with_content_provider("PUT", path, headers, nullptr, 0, nullptr,
8443  std::move(content_provider), content_type,
8444  nullptr);
8445 }
8446 
8447 inline Result ClientImpl::Put(const std::string &path, const Params &params) {
8448  return Put(path, Headers(), params);
8449 }
8450 
8451 inline Result ClientImpl::Put(const std::string &path, const Headers &headers,
8452  const Params &params) {
8453  auto query = detail::params_to_query_str(params);
8454  return Put(path, headers, query, "application/x-www-form-urlencoded");
8455 }
8456 
8457 inline Result ClientImpl::Put(const std::string &path, const Headers &headers,
8458  const Params &params, Progress progress) {
8459  auto query = detail::params_to_query_str(params);
8460  return Put(path, headers, query, "application/x-www-form-urlencoded",
8461  progress);
8462 }
8463 
8464 inline Result ClientImpl::Put(const std::string &path,
8465  const MultipartFormDataItems &items) {
8466  return Put(path, Headers(), items);
8467 }
8468 
8469 inline Result ClientImpl::Put(const std::string &path, const Headers &headers,
8470  const MultipartFormDataItems &items) {
8471  const auto &boundary = detail::make_multipart_data_boundary();
8472  const auto &content_type =
8474  const auto &body = detail::serialize_multipart_formdata(items, boundary);
8475  return Put(path, headers, body, content_type);
8476 }
8477 
8478 inline Result ClientImpl::Put(const std::string &path, const Headers &headers,
8479  const MultipartFormDataItems &items,
8480  const std::string &boundary) {
8483  }
8484 
8485  const auto &content_type =
8487  const auto &body = detail::serialize_multipart_formdata(items, boundary);
8488  return Put(path, headers, body, content_type);
8489 }
8490 
8491 inline Result
8492 ClientImpl::Put(const std::string &path, const Headers &headers,
8493  const MultipartFormDataItems &items,
8494  const MultipartFormDataProviderItems &provider_items) {
8495  const auto &boundary = detail::make_multipart_data_boundary();
8496  const auto &content_type =
8498  return send_with_content_provider(
8499  "PUT", path, headers, nullptr, 0, nullptr,
8500  get_multipart_content_provider(boundary, items, provider_items),
8501  content_type, nullptr);
8502 }
8503 inline Result ClientImpl::Patch(const std::string &path) {
8504  return Patch(path, std::string(), std::string());
8505 }
8506 
8507 inline Result ClientImpl::Patch(const std::string &path, const char *body,
8508  size_t content_length,
8509  const std::string &content_type) {
8510  return Patch(path, Headers(), body, content_length, content_type);
8511 }
8512 
8513 inline Result ClientImpl::Patch(const std::string &path, const char *body,
8514  size_t content_length,
8515  const std::string &content_type,
8516  Progress progress) {
8517  return Patch(path, Headers(), body, content_length, content_type, progress);
8518 }
8519 
8520 inline Result ClientImpl::Patch(const std::string &path, const Headers &headers,
8521  const char *body, size_t content_length,
8522  const std::string &content_type) {
8523  return Patch(path, headers, body, content_length, content_type, nullptr);
8524 }
8525 
8526 inline Result ClientImpl::Patch(const std::string &path, const Headers &headers,
8527  const char *body, size_t content_length,
8528  const std::string &content_type,
8529  Progress progress) {
8530  return send_with_content_provider("PATCH", path, headers, body,
8531  content_length, nullptr, nullptr,
8532  content_type, progress);
8533 }
8534 
8535 inline Result ClientImpl::Patch(const std::string &path,
8536  const std::string &body,
8537  const std::string &content_type) {
8538  return Patch(path, Headers(), body, content_type);
8539 }
8540 
8541 inline Result ClientImpl::Patch(const std::string &path,
8542  const std::string &body,
8543  const std::string &content_type,
8544  Progress progress) {
8545  return Patch(path, Headers(), body, content_type, progress);
8546 }
8547 
8548 inline Result ClientImpl::Patch(const std::string &path, const Headers &headers,
8549  const std::string &body,
8550  const std::string &content_type) {
8551  return Patch(path, headers, body, content_type, nullptr);
8552 }
8553 
8554 inline Result ClientImpl::Patch(const std::string &path, const Headers &headers,
8555  const std::string &body,
8556  const std::string &content_type,
8557  Progress progress) {
8558  return send_with_content_provider("PATCH", path, headers, body.data(),
8559  body.size(), nullptr, nullptr, content_type,
8560  progress);
8561 }
8562 
8563 inline Result ClientImpl::Patch(const std::string &path, size_t content_length,
8564  ContentProvider content_provider,
8565  const std::string &content_type) {
8566  return Patch(path, Headers(), content_length, std::move(content_provider),
8567  content_type);
8568 }
8569 
8570 inline Result ClientImpl::Patch(const std::string &path,
8571  ContentProviderWithoutLength content_provider,
8572  const std::string &content_type) {
8573  return Patch(path, Headers(), std::move(content_provider), content_type);
8574 }
8575 
8576 inline Result ClientImpl::Patch(const std::string &path, const Headers &headers,
8577  size_t content_length,
8578  ContentProvider content_provider,
8579  const std::string &content_type) {
8580  return send_with_content_provider("PATCH", path, headers, nullptr,
8581  content_length, std::move(content_provider),
8582  nullptr, content_type, nullptr);
8583 }
8584 
8585 inline Result ClientImpl::Patch(const std::string &path, const Headers &headers,
8586  ContentProviderWithoutLength content_provider,
8587  const std::string &content_type) {
8588  return send_with_content_provider("PATCH", path, headers, nullptr, 0, nullptr,
8589  std::move(content_provider), content_type,
8590  nullptr);
8591 }
8592 
8593 inline Result ClientImpl::Delete(const std::string &path) {
8594  return Delete(path, Headers(), std::string(), std::string());
8595 }
8596 
8597 inline Result ClientImpl::Delete(const std::string &path,
8598  const Headers &headers) {
8599  return Delete(path, headers, std::string(), std::string());
8600 }
8601 
8602 inline Result ClientImpl::Delete(const std::string &path, const char *body,
8603  size_t content_length,
8604  const std::string &content_type) {
8605  return Delete(path, Headers(), body, content_length, content_type);
8606 }
8607 
8608 inline Result ClientImpl::Delete(const std::string &path, const char *body,
8609  size_t content_length,
8610  const std::string &content_type,
8611  Progress progress) {
8612  return Delete(path, Headers(), body, content_length, content_type, progress);
8613 }
8614 
8615 inline Result ClientImpl::Delete(const std::string &path,
8616  const Headers &headers, const char *body,
8617  size_t content_length,
8618  const std::string &content_type) {
8619  return Delete(path, headers, body, content_length, content_type, nullptr);
8620 }
8621 
8622 inline Result ClientImpl::Delete(const std::string &path,
8623  const Headers &headers, const char *body,
8624  size_t content_length,
8625  const std::string &content_type,
8626  Progress progress) {
8627  Request req;
8628  req.method = "DELETE";
8629  req.headers = headers;
8630  req.path = path;
8631  req.progress = progress;
8632 
8633  if (!content_type.empty()) { req.set_header("Content-Type", content_type); }
8634  req.body.assign(body, content_length);
8635 
8636  return send_(std::move(req));
8637 }
8638 
8639 inline Result ClientImpl::Delete(const std::string &path,
8640  const std::string &body,
8641  const std::string &content_type) {
8642  return Delete(path, Headers(), body.data(), body.size(), content_type);
8643 }
8644 
8645 inline Result ClientImpl::Delete(const std::string &path,
8646  const std::string &body,
8647  const std::string &content_type,
8648  Progress progress) {
8649  return Delete(path, Headers(), body.data(), body.size(), content_type,
8650  progress);
8651 }
8652 
8653 inline Result ClientImpl::Delete(const std::string &path,
8654  const Headers &headers,
8655  const std::string &body,
8656  const std::string &content_type) {
8657  return Delete(path, headers, body.data(), body.size(), content_type);
8658 }
8659 
8660 inline Result ClientImpl::Delete(const std::string &path,
8661  const Headers &headers,
8662  const std::string &body,
8663  const std::string &content_type,
8664  Progress progress) {
8665  return Delete(path, headers, body.data(), body.size(), content_type,
8666  progress);
8667 }
8668 
8669 inline Result ClientImpl::Options(const std::string &path) {
8670  return Options(path, Headers());
8671 }
8672 
8673 inline Result ClientImpl::Options(const std::string &path,
8674  const Headers &headers) {
8675  Request req;
8676  req.method = "OPTIONS";
8677  req.headers = headers;
8678  req.path = path;
8679 
8680  return send_(std::move(req));
8681 }
8682 
8683 inline void ClientImpl::stop() {
8684  std::lock_guard<std::mutex> guard(socket_mutex_);
8685 
8686  // If there is anything ongoing right now, the ONLY thread-safe thing we can
8687  // do is to shutdown_socket, so that threads using this socket suddenly
8688  // discover they can't read/write any more and error out. Everything else
8689  // (closing the socket, shutting ssl down) is unsafe because these actions are
8690  // not thread-safe.
8691  if (socket_requests_in_flight_ > 0) {
8693 
8694  // Aside from that, we set a flag for the socket to be closed when we're
8695  // done.
8697  return;
8698  }
8699 
8700  // Otherwise, still holding the mutex, we can shut everything down ourselves
8701  shutdown_ssl(socket_, true);
8704 }
8705 
8706 inline std::string ClientImpl::host() const { return host_; }
8707 
8708 inline int ClientImpl::port() const { return port_; }
8709 
8710 inline size_t ClientImpl::is_socket_open() const {
8711  std::lock_guard<std::mutex> guard(socket_mutex_);
8712  return socket_.is_open();
8713 }
8714 
8715 inline socket_t ClientImpl::socket() const { return socket_.sock; }
8716 
8717 inline void ClientImpl::set_connection_timeout(time_t sec, time_t usec) {
8719  connection_timeout_usec_ = usec;
8720 }
8721 
8722 inline void ClientImpl::set_read_timeout(time_t sec, time_t usec) {
8723  read_timeout_sec_ = sec;
8724  read_timeout_usec_ = usec;
8725 }
8726 
8727 inline void ClientImpl::set_write_timeout(time_t sec, time_t usec) {
8728  write_timeout_sec_ = sec;
8729  write_timeout_usec_ = usec;
8730 }
8731 
8732 inline void ClientImpl::set_basic_auth(const std::string &username,
8733  const std::string &password) {
8734  basic_auth_username_ = username;
8735  basic_auth_password_ = password;
8736 }
8737 
8738 inline void ClientImpl::set_bearer_token_auth(const std::string &token) {
8739  bearer_token_auth_token_ = token;
8740 }
8741 
8742 #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
8743 inline void ClientImpl::set_digest_auth(const std::string &username,
8744  const std::string &password) {
8745  digest_auth_username_ = username;
8746  digest_auth_password_ = password;
8747 }
8748 #endif
8749 
8750 inline void ClientImpl::set_keep_alive(bool on) { keep_alive_ = on; }
8751 
8753 
8754 inline void ClientImpl::set_url_encode(bool on) { url_encode_ = on; }
8755 
8756 inline void
8757 ClientImpl::set_hostname_addr_map(std::map<std::string, std::string> addr_map) {
8758  addr_map_ = std::move(addr_map);
8759 }
8760 
8762  default_headers_ = std::move(headers);
8763 }
8764 
8766  std::function<ssize_t(Stream &, Headers &)> const &writer) {
8767  header_writer_ = writer;
8768 }
8769 
8770 inline void ClientImpl::set_address_family(int family) {
8771  address_family_ = family;
8772 }
8773 
8774 inline void ClientImpl::set_tcp_nodelay(bool on) { tcp_nodelay_ = on; }
8775 
8776 inline void ClientImpl::set_ipv6_v6only(bool on) { ipv6_v6only_ = on; }
8777 
8778 inline void ClientImpl::set_socket_options(SocketOptions socket_options) {
8779  socket_options_ = std::move(socket_options);
8780 }
8781 
8782 inline void ClientImpl::set_compress(bool on) { compress_ = on; }
8783 
8784 inline void ClientImpl::set_decompress(bool on) { decompress_ = on; }
8785 
8786 inline void ClientImpl::set_interface(const std::string &intf) {
8787  interface_ = intf;
8788 }
8789 
8790 inline void ClientImpl::set_proxy(const std::string &host, int port) {
8791  proxy_host_ = host;
8792  proxy_port_ = port;
8793 }
8794 
8795 inline void ClientImpl::set_proxy_basic_auth(const std::string &username,
8796  const std::string &password) {
8797  proxy_basic_auth_username_ = username;
8798  proxy_basic_auth_password_ = password;
8799 }
8800 
8801 inline void ClientImpl::set_proxy_bearer_token_auth(const std::string &token) {
8803 }
8804 
8805 #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
8806 inline void ClientImpl::set_proxy_digest_auth(const std::string &username,
8807  const std::string &password) {
8808  proxy_digest_auth_username_ = username;
8809  proxy_digest_auth_password_ = password;
8810 }
8811 
8812 inline void ClientImpl::set_ca_cert_path(const std::string &ca_cert_file_path,
8813  const std::string &ca_cert_dir_path) {
8814  ca_cert_file_path_ = ca_cert_file_path;
8815  ca_cert_dir_path_ = ca_cert_dir_path;
8816 }
8817 
8818 inline void ClientImpl::set_ca_cert_store(X509_STORE *ca_cert_store) {
8819  if (ca_cert_store && ca_cert_store != ca_cert_store_) {
8820  ca_cert_store_ = ca_cert_store;
8821  }
8822 }
8823 
8824 inline X509_STORE *ClientImpl::create_ca_cert_store(const char *ca_cert,
8825  std::size_t size) const {
8826  auto mem = BIO_new_mem_buf(ca_cert, static_cast<int>(size));
8827  auto se = detail::scope_exit([&] { BIO_free_all(mem); });
8828  if (!mem) { return nullptr; }
8829 
8830  auto inf = PEM_X509_INFO_read_bio(mem, nullptr, nullptr, nullptr);
8831  if (!inf) { return nullptr; }
8832 
8833  auto cts = X509_STORE_new();
8834  if (cts) {
8835  for (auto i = 0; i < static_cast<int>(sk_X509_INFO_num(inf)); i++) {
8836  auto itmp = sk_X509_INFO_value(inf, i);
8837  if (!itmp) { continue; }
8838 
8839  if (itmp->x509) { X509_STORE_add_cert(cts, itmp->x509); }
8840  if (itmp->crl) { X509_STORE_add_crl(cts, itmp->crl); }
8841  }
8842  }
8843 
8844  sk_X509_INFO_pop_free(inf, X509_INFO_free);
8845  return cts;
8846 }
8847 
8848 inline void ClientImpl::enable_server_certificate_verification(bool enabled) {
8849  server_certificate_verification_ = enabled;
8850 }
8851 
8852 inline void ClientImpl::enable_server_hostname_verification(bool enabled) {
8853  server_hostname_verification_ = enabled;
8854 }
8855 
8856 inline void ClientImpl::set_server_certificate_verifier(
8857  std::function<bool(SSL *ssl)> verifier) {
8858  server_certificate_verifier_ = verifier;
8859 }
8860 #endif
8861 
8862 inline void ClientImpl::set_logger(Logger logger) {
8863  logger_ = std::move(logger);
8864 }
8865 
8866 /*
8867  * SSL Implementation
8868  */
8869 #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
8870 namespace detail {
8871 
8872 template <typename U, typename V>
8873 inline SSL *ssl_new(socket_t sock, SSL_CTX *ctx, std::mutex &ctx_mutex,
8874  U SSL_connect_or_accept, V setup) {
8875  SSL *ssl = nullptr;
8876  {
8877  std::lock_guard<std::mutex> guard(ctx_mutex);
8878  ssl = SSL_new(ctx);
8879  }
8880 
8881  if (ssl) {
8882  set_nonblocking(sock, true);
8883  auto bio = BIO_new_socket(static_cast<int>(sock), BIO_NOCLOSE);
8884  BIO_set_nbio(bio, 1);
8885  SSL_set_bio(ssl, bio, bio);
8886 
8887  if (!setup(ssl) || SSL_connect_or_accept(ssl) != 1) {
8888  SSL_shutdown(ssl);
8889  {
8890  std::lock_guard<std::mutex> guard(ctx_mutex);
8891  SSL_free(ssl);
8892  }
8893  set_nonblocking(sock, false);
8894  return nullptr;
8895  }
8896  BIO_set_nbio(bio, 0);
8897  set_nonblocking(sock, false);
8898  }
8899 
8900  return ssl;
8901 }
8902 
8903 inline void ssl_delete(std::mutex &ctx_mutex, SSL *ssl, socket_t sock,
8904  bool shutdown_gracefully) {
8905  // sometimes we may want to skip this to try to avoid SIGPIPE if we know
8906  // the remote has closed the network connection
8907  // Note that it is not always possible to avoid SIGPIPE, this is merely a
8908  // best-efforts.
8909  if (shutdown_gracefully) {
8910 #ifdef _WIN32
8911  SSL_shutdown(ssl);
8912 #else
8913  timeval tv;
8914  tv.tv_sec = 1;
8915  tv.tv_usec = 0;
8916  setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO,
8917  reinterpret_cast<const void *>(&tv), sizeof(tv));
8918 
8919  auto ret = SSL_shutdown(ssl);
8920  while (ret == 0) {
8921  std::this_thread::sleep_for(std::chrono::milliseconds{100});
8922  ret = SSL_shutdown(ssl);
8923  }
8924 #endif
8925  }
8926 
8927  std::lock_guard<std::mutex> guard(ctx_mutex);
8928  SSL_free(ssl);
8929 }
8930 
8931 template <typename U>
8932 bool ssl_connect_or_accept_nonblocking(socket_t sock, SSL *ssl,
8933  U ssl_connect_or_accept,
8934  time_t timeout_sec,
8935  time_t timeout_usec) {
8936  auto res = 0;
8937  while ((res = ssl_connect_or_accept(ssl)) != 1) {
8938  auto err = SSL_get_error(ssl, res);
8939  switch (err) {
8940  case SSL_ERROR_WANT_READ:
8941  if (select_read(sock, timeout_sec, timeout_usec) > 0) { continue; }
8942  break;
8943  case SSL_ERROR_WANT_WRITE:
8944  if (select_write(sock, timeout_sec, timeout_usec) > 0) { continue; }
8945  break;
8946  default: break;
8947  }
8948  return false;
8949  }
8950  return true;
8951 }
8952 
8953 template <typename T>
8954 inline bool process_server_socket_ssl(
8955  const std::atomic<socket_t> &svr_sock, SSL *ssl, socket_t sock,
8956  size_t keep_alive_max_count, time_t keep_alive_timeout_sec,
8957  time_t read_timeout_sec, time_t read_timeout_usec, time_t write_timeout_sec,
8958  time_t write_timeout_usec, T callback) {
8960  svr_sock, sock, keep_alive_max_count, keep_alive_timeout_sec,
8961  [&](bool close_connection, bool &connection_closed) {
8962  SSLSocketStream strm(sock, ssl, read_timeout_sec, read_timeout_usec,
8963  write_timeout_sec, write_timeout_usec);
8964  return callback(strm, close_connection, connection_closed);
8965  });
8966 }
8967 
8968 template <typename T>
8969 inline bool
8970 process_client_socket_ssl(SSL *ssl, socket_t sock, time_t read_timeout_sec,
8971  time_t read_timeout_usec, time_t write_timeout_sec,
8972  time_t write_timeout_usec, T callback) {
8973  SSLSocketStream strm(sock, ssl, read_timeout_sec, read_timeout_usec,
8974  write_timeout_sec, write_timeout_usec);
8975  return callback(strm);
8976 }
8977 
8978 class SSLInit {
8979 public:
8980  SSLInit() {
8981  OPENSSL_init_ssl(
8982  OPENSSL_INIT_LOAD_SSL_STRINGS | OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL);
8983  }
8984 };
8985 
8986 // SSL socket stream implementation
8987 inline SSLSocketStream::SSLSocketStream(socket_t sock, SSL *ssl,
8988  time_t read_timeout_sec,
8989  time_t read_timeout_usec,
8990  time_t write_timeout_sec,
8991  time_t write_timeout_usec)
8992  : sock_(sock), ssl_(ssl), read_timeout_sec_(read_timeout_sec),
8993  read_timeout_usec_(read_timeout_usec),
8994  write_timeout_sec_(write_timeout_sec),
8995  write_timeout_usec_(write_timeout_usec) {
8996  SSL_clear_mode(ssl, SSL_MODE_AUTO_RETRY);
8997 }
8998 
8999 inline SSLSocketStream::~SSLSocketStream() = default;
9000 
9001 inline bool SSLSocketStream::is_readable() const {
9002  return detail::select_read(sock_, read_timeout_sec_, read_timeout_usec_) > 0;
9003 }
9004 
9005 inline bool SSLSocketStream::is_writable() const {
9006  return select_write(sock_, write_timeout_sec_, write_timeout_usec_) > 0 &&
9007  is_socket_alive(sock_);
9008 }
9009 
9010 inline ssize_t SSLSocketStream::read(char *ptr, size_t size) {
9011  if (SSL_pending(ssl_) > 0) {
9012  return SSL_read(ssl_, ptr, static_cast<int>(size));
9013  } else if (is_readable()) {
9014  auto ret = SSL_read(ssl_, ptr, static_cast<int>(size));
9015  if (ret < 0) {
9016  auto err = SSL_get_error(ssl_, ret);
9017  auto n = 1000;
9018 #ifdef _WIN32
9019  while (--n >= 0 && (err == SSL_ERROR_WANT_READ ||
9020  (err == SSL_ERROR_SYSCALL &&
9021  WSAGetLastError() == WSAETIMEDOUT))) {
9022 #else
9023  while (--n >= 0 && err == SSL_ERROR_WANT_READ) {
9024 #endif
9025  if (SSL_pending(ssl_) > 0) {
9026  return SSL_read(ssl_, ptr, static_cast<int>(size));
9027  } else if (is_readable()) {
9028  std::this_thread::sleep_for(std::chrono::microseconds{10});
9029  ret = SSL_read(ssl_, ptr, static_cast<int>(size));
9030  if (ret >= 0) { return ret; }
9031  err = SSL_get_error(ssl_, ret);
9032  } else {
9033  return -1;
9034  }
9035  }
9036  }
9037  return ret;
9038  }
9039  return -1;
9040 }
9041 
9042 inline ssize_t SSLSocketStream::write(const char *ptr, size_t size) {
9043  if (is_writable()) {
9044  auto handle_size = static_cast<int>(
9045  std::min<size_t>(size, (std::numeric_limits<int>::max)()));
9046 
9047  auto ret = SSL_write(ssl_, ptr, static_cast<int>(handle_size));
9048  if (ret < 0) {
9049  auto err = SSL_get_error(ssl_, ret);
9050  auto n = 1000;
9051 #ifdef _WIN32
9052  while (--n >= 0 && (err == SSL_ERROR_WANT_WRITE ||
9053  (err == SSL_ERROR_SYSCALL &&
9054  WSAGetLastError() == WSAETIMEDOUT))) {
9055 #else
9056  while (--n >= 0 && err == SSL_ERROR_WANT_WRITE) {
9057 #endif
9058  if (is_writable()) {
9059  std::this_thread::sleep_for(std::chrono::microseconds{10});
9060  ret = SSL_write(ssl_, ptr, static_cast<int>(handle_size));
9061  if (ret >= 0) { return ret; }
9062  err = SSL_get_error(ssl_, ret);
9063  } else {
9064  return -1;
9065  }
9066  }
9067  }
9068  return ret;
9069  }
9070  return -1;
9071 }
9072 
9073 inline void SSLSocketStream::get_remote_ip_and_port(std::string &ip,
9074  int &port) const {
9075  detail::get_remote_ip_and_port(sock_, ip, port);
9076 }
9077 
9078 inline void SSLSocketStream::get_local_ip_and_port(std::string &ip,
9079  int &port) const {
9080  detail::get_local_ip_and_port(sock_, ip, port);
9081 }
9082 
9083 inline socket_t SSLSocketStream::socket() const { return sock_; }
9084 
9085 static SSLInit sslinit_;
9086 
9087 } // namespace detail
9088 
9089 // SSL HTTP server implementation
9090 inline SSLServer::SSLServer(const char *cert_path, const char *private_key_path,
9091  const char *client_ca_cert_file_path,
9092  const char *client_ca_cert_dir_path,
9093  const char *private_key_password) {
9094  ctx_ = SSL_CTX_new(TLS_server_method());
9095 
9096  if (ctx_) {
9097  SSL_CTX_set_options(ctx_,
9098  SSL_OP_NO_COMPRESSION |
9099  SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION);
9100 
9101  SSL_CTX_set_min_proto_version(ctx_, TLS1_2_VERSION);
9102 
9103  if (private_key_password != nullptr && (private_key_password[0] != '\0')) {
9104  SSL_CTX_set_default_passwd_cb_userdata(
9105  ctx_,
9106  reinterpret_cast<void *>(const_cast<char *>(private_key_password)));
9107  }
9108 
9109  if (SSL_CTX_use_certificate_chain_file(ctx_, cert_path) != 1 ||
9110  SSL_CTX_use_PrivateKey_file(ctx_, private_key_path, SSL_FILETYPE_PEM) !=
9111  1 ||
9112  SSL_CTX_check_private_key(ctx_) != 1) {
9113  SSL_CTX_free(ctx_);
9114  ctx_ = nullptr;
9115  } else if (client_ca_cert_file_path || client_ca_cert_dir_path) {
9116  SSL_CTX_load_verify_locations(ctx_, client_ca_cert_file_path,
9117  client_ca_cert_dir_path);
9118 
9119  SSL_CTX_set_verify(
9120  ctx_, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, nullptr);
9121  }
9122  }
9123 }
9124 
9125 inline SSLServer::SSLServer(X509 *cert, EVP_PKEY *private_key,
9126  X509_STORE *client_ca_cert_store) {
9127  ctx_ = SSL_CTX_new(TLS_server_method());
9128 
9129  if (ctx_) {
9130  SSL_CTX_set_options(ctx_,
9131  SSL_OP_NO_COMPRESSION |
9132  SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION);
9133 
9134  SSL_CTX_set_min_proto_version(ctx_, TLS1_2_VERSION);
9135 
9136  if (SSL_CTX_use_certificate(ctx_, cert) != 1 ||
9137  SSL_CTX_use_PrivateKey(ctx_, private_key) != 1) {
9138  SSL_CTX_free(ctx_);
9139  ctx_ = nullptr;
9140  } else if (client_ca_cert_store) {
9141  SSL_CTX_set_cert_store(ctx_, client_ca_cert_store);
9142 
9143  SSL_CTX_set_verify(
9144  ctx_, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, nullptr);
9145  }
9146  }
9147 }
9148 
9149 inline SSLServer::SSLServer(
9150  const std::function<bool(SSL_CTX &ssl_ctx)> &setup_ssl_ctx_callback) {
9151  ctx_ = SSL_CTX_new(TLS_method());
9152  if (ctx_) {
9153  if (!setup_ssl_ctx_callback(*ctx_)) {
9154  SSL_CTX_free(ctx_);
9155  ctx_ = nullptr;
9156  }
9157  }
9158 }
9159 
9160 inline SSLServer::~SSLServer() {
9161  if (ctx_) { SSL_CTX_free(ctx_); }
9162 }
9163 
9164 inline bool SSLServer::is_valid() const { return ctx_; }
9165 
9166 inline SSL_CTX *SSLServer::ssl_context() const { return ctx_; }
9167 
9168 inline void SSLServer::update_certs(X509 *cert, EVP_PKEY *private_key,
9169  X509_STORE *client_ca_cert_store) {
9170 
9171  std::lock_guard<std::mutex> guard(ctx_mutex_);
9172 
9173  SSL_CTX_use_certificate(ctx_, cert);
9174  SSL_CTX_use_PrivateKey(ctx_, private_key);
9175 
9176  if (client_ca_cert_store != nullptr) {
9177  SSL_CTX_set_cert_store(ctx_, client_ca_cert_store);
9178  }
9179 }
9180 
9181 inline bool SSLServer::process_and_close_socket(socket_t sock) {
9182  auto ssl = detail::ssl_new(
9183  sock, ctx_, ctx_mutex_,
9184  [&](SSL *ssl2) {
9185  return detail::ssl_connect_or_accept_nonblocking(
9186  sock, ssl2, SSL_accept, read_timeout_sec_, read_timeout_usec_);
9187  },
9188  [](SSL * /*ssl2*/) { return true; });
9189 
9190  auto ret = false;
9191  if (ssl) {
9192  std::string remote_addr;
9193  int remote_port = 0;
9194  detail::get_remote_ip_and_port(sock, remote_addr, remote_port);
9195 
9196  std::string local_addr;
9197  int local_port = 0;
9198  detail::get_local_ip_and_port(sock, local_addr, local_port);
9199 
9200  ret = detail::process_server_socket_ssl(
9201  svr_sock_, ssl, sock, keep_alive_max_count_, keep_alive_timeout_sec_,
9202  read_timeout_sec_, read_timeout_usec_, write_timeout_sec_,
9203  write_timeout_usec_,
9204  [&](Stream &strm, bool close_connection, bool &connection_closed) {
9205  return process_request(strm, remote_addr, remote_port, local_addr,
9206  local_port, close_connection,
9207  connection_closed,
9208  [&](Request &req) { req.ssl = ssl; });
9209  });
9210 
9211  // Shutdown gracefully if the result seemed successful, non-gracefully if
9212  // the connection appeared to be closed.
9213  const bool shutdown_gracefully = ret;
9214  detail::ssl_delete(ctx_mutex_, ssl, sock, shutdown_gracefully);
9215  }
9216 
9218  detail::close_socket(sock);
9219  return ret;
9220 }
9221 
9222 // SSL HTTP client implementation
9223 inline SSLClient::SSLClient(const std::string &host)
9224  : SSLClient(host, 443, std::string(), std::string()) {}
9225 
9226 inline SSLClient::SSLClient(const std::string &host, int port)
9227  : SSLClient(host, port, std::string(), std::string()) {}
9228 
9229 inline SSLClient::SSLClient(const std::string &host, int port,
9230  const std::string &client_cert_path,
9231  const std::string &client_key_path,
9232  const std::string &private_key_password)
9233  : ClientImpl(host, port, client_cert_path, client_key_path) {
9234  ctx_ = SSL_CTX_new(TLS_client_method());
9235 
9236  SSL_CTX_set_min_proto_version(ctx_, TLS1_2_VERSION);
9237 
9238  detail::split(&host_[0], &host_[host_.size()], '.',
9239  [&](const char *b, const char *e) {
9240  host_components_.emplace_back(b, e);
9241  });
9242 
9243  if (!client_cert_path.empty() && !client_key_path.empty()) {
9244  if (!private_key_password.empty()) {
9245  SSL_CTX_set_default_passwd_cb_userdata(
9246  ctx_, reinterpret_cast<void *>(
9247  const_cast<char *>(private_key_password.c_str())));
9248  }
9249 
9250  if (SSL_CTX_use_certificate_file(ctx_, client_cert_path.c_str(),
9251  SSL_FILETYPE_PEM) != 1 ||
9252  SSL_CTX_use_PrivateKey_file(ctx_, client_key_path.c_str(),
9253  SSL_FILETYPE_PEM) != 1) {
9254  SSL_CTX_free(ctx_);
9255  ctx_ = nullptr;
9256  }
9257  }
9258 }
9259 
9260 inline SSLClient::SSLClient(const std::string &host, int port,
9261  X509 *client_cert, EVP_PKEY *client_key,
9262  const std::string &private_key_password)
9263  : ClientImpl(host, port) {
9264  ctx_ = SSL_CTX_new(TLS_client_method());
9265 
9266  detail::split(&host_[0], &host_[host_.size()], '.',
9267  [&](const char *b, const char *e) {
9268  host_components_.emplace_back(b, e);
9269  });
9270 
9271  if (client_cert != nullptr && client_key != nullptr) {
9272  if (!private_key_password.empty()) {
9273  SSL_CTX_set_default_passwd_cb_userdata(
9274  ctx_, reinterpret_cast<void *>(
9275  const_cast<char *>(private_key_password.c_str())));
9276  }
9277 
9278  if (SSL_CTX_use_certificate(ctx_, client_cert) != 1 ||
9279  SSL_CTX_use_PrivateKey(ctx_, client_key) != 1) {
9280  SSL_CTX_free(ctx_);
9281  ctx_ = nullptr;
9282  }
9283  }
9284 }
9285 
9286 inline SSLClient::~SSLClient() {
9287  if (ctx_) { SSL_CTX_free(ctx_); }
9288  // Make sure to shut down SSL since shutdown_ssl will resolve to the
9289  // base function rather than the derived function once we get to the
9290  // base class destructor, and won't free the SSL (causing a leak).
9291  shutdown_ssl_impl(socket_, true);
9292 }
9293 
9294 inline bool SSLClient::is_valid() const { return ctx_; }
9295 
9296 inline void SSLClient::set_ca_cert_store(X509_STORE *ca_cert_store) {
9297  if (ca_cert_store) {
9298  if (ctx_) {
9299  if (SSL_CTX_get_cert_store(ctx_) != ca_cert_store) {
9300  // Free memory allocated for old cert and use new store `ca_cert_store`
9301  SSL_CTX_set_cert_store(ctx_, ca_cert_store);
9302  }
9303  } else {
9304  X509_STORE_free(ca_cert_store);
9305  }
9306  }
9307 }
9308 
9309 inline void SSLClient::load_ca_cert_store(const char *ca_cert,
9310  std::size_t size) {
9311  set_ca_cert_store(ClientImpl::create_ca_cert_store(ca_cert, size));
9312 }
9313 
9314 inline long SSLClient::get_openssl_verify_result() const {
9315  return verify_result_;
9316 }
9317 
9318 inline SSL_CTX *SSLClient::ssl_context() const { return ctx_; }
9319 
9320 inline bool SSLClient::create_and_connect_socket(Socket &socket, Error &error) {
9321  return is_valid() && ClientImpl::create_and_connect_socket(socket, error);
9322 }
9323 
9324 // Assumes that socket_mutex_ is locked and that there are no requests in flight
9325 inline bool SSLClient::connect_with_proxy(Socket &socket, Response &res,
9326  bool &success, Error &error) {
9327  success = true;
9328  Response proxy_res;
9330  socket.sock, read_timeout_sec_, read_timeout_usec_,
9331  write_timeout_sec_, write_timeout_usec_, [&](Stream &strm) {
9332  Request req2;
9333  req2.method = "CONNECT";
9334  req2.path = host_and_port_;
9335  return process_request(strm, req2, proxy_res, false, error);
9336  })) {
9337  // Thread-safe to close everything because we are assuming there are no
9338  // requests in flight
9339  shutdown_ssl(socket, true);
9340  shutdown_socket(socket);
9341  close_socket(socket);
9342  success = false;
9343  return false;
9344  }
9345 
9347  if (!proxy_digest_auth_username_.empty() &&
9348  !proxy_digest_auth_password_.empty()) {
9349  std::map<std::string, std::string> auth;
9350  if (detail::parse_www_authenticate(proxy_res, auth, true)) {
9351  proxy_res = Response();
9353  socket.sock, read_timeout_sec_, read_timeout_usec_,
9354  write_timeout_sec_, write_timeout_usec_, [&](Stream &strm) {
9355  Request req3;
9356  req3.method = "CONNECT";
9357  req3.path = host_and_port_;
9358  req3.headers.insert(detail::make_digest_authentication_header(
9359  req3, auth, 1, detail::random_string(10),
9360  proxy_digest_auth_username_, proxy_digest_auth_password_,
9361  true));
9362  return process_request(strm, req3, proxy_res, false, error);
9363  })) {
9364  // Thread-safe to close everything because we are assuming there are
9365  // no requests in flight
9366  shutdown_ssl(socket, true);
9367  shutdown_socket(socket);
9368  close_socket(socket);
9369  success = false;
9370  return false;
9371  }
9372  }
9373  }
9374  }
9375 
9376  // If status code is not 200, proxy request is failed.
9377  // Set error to ProxyConnection and return proxy response
9378  // as the response of the request
9379  if (proxy_res.status != StatusCode::OK_200) {
9380  error = Error::ProxyConnection;
9381  res = std::move(proxy_res);
9382  // Thread-safe to close everything because we are assuming there are
9383  // no requests in flight
9384  shutdown_ssl(socket, true);
9385  shutdown_socket(socket);
9386  close_socket(socket);
9387  return false;
9388  }
9389 
9390  return true;
9391 }
9392 
9393 inline bool SSLClient::load_certs() {
9394  auto ret = true;
9395 
9396  std::call_once(initialize_cert_, [&]() {
9397  std::lock_guard<std::mutex> guard(ctx_mutex_);
9398  if (!ca_cert_file_path_.empty()) {
9399  if (!SSL_CTX_load_verify_locations(ctx_, ca_cert_file_path_.c_str(),
9400  nullptr)) {
9401  ret = false;
9402  }
9403  } else if (!ca_cert_dir_path_.empty()) {
9404  if (!SSL_CTX_load_verify_locations(ctx_, nullptr,
9405  ca_cert_dir_path_.c_str())) {
9406  ret = false;
9407  }
9408  } else {
9409  auto loaded = false;
9410 #ifdef _WIN32
9411  loaded =
9412  detail::load_system_certs_on_windows(SSL_CTX_get_cert_store(ctx_));
9413 #elif defined(CPPHTTPLIB_USE_CERTS_FROM_MACOSX_KEYCHAIN) && defined(__APPLE__)
9414 #if TARGET_OS_OSX
9415  loaded = detail::load_system_certs_on_macos(SSL_CTX_get_cert_store(ctx_));
9416 #endif // TARGET_OS_OSX
9417 #endif // _WIN32
9418  if (!loaded) { SSL_CTX_set_default_verify_paths(ctx_); }
9419  }
9420  });
9421 
9422  return ret;
9423 }
9424 
9425 inline bool SSLClient::initialize_ssl(Socket &socket, Error &error) {
9426  auto ssl = detail::ssl_new(
9427  socket.sock, ctx_, ctx_mutex_,
9428  [&](SSL *ssl2) {
9429  if (server_certificate_verification_) {
9430  if (!load_certs()) {
9431  error = Error::SSLLoadingCerts;
9432  return false;
9433  }
9434  SSL_set_verify(ssl2, SSL_VERIFY_NONE, nullptr);
9435  }
9436 
9437  if (!detail::ssl_connect_or_accept_nonblocking(
9438  socket.sock, ssl2, SSL_connect, connection_timeout_sec_,
9439  connection_timeout_usec_)) {
9440  error = Error::SSLConnection;
9441  return false;
9442  }
9443 
9444  if (server_certificate_verification_) {
9445  if (server_certificate_verifier_) {
9446  if (!server_certificate_verifier_(ssl2)) {
9448  return false;
9449  }
9450  } else {
9451  verify_result_ = SSL_get_verify_result(ssl2);
9452 
9453  if (verify_result_ != X509_V_OK) {
9455  return false;
9456  }
9457 
9458  auto server_cert = SSL_get1_peer_certificate(ssl2);
9459  auto se = detail::scope_exit([&] { X509_free(server_cert); });
9460 
9461  if (server_cert == nullptr) {
9463  return false;
9464  }
9465 
9466  if (server_hostname_verification_) {
9467  if (!verify_host(server_cert)) {
9469  return false;
9470  }
9471  }
9472  }
9473  }
9474 
9475  return true;
9476  },
9477  [&](SSL *ssl2) {
9478 #if defined(OPENSSL_IS_BORINGSSL)
9479  SSL_set_tlsext_host_name(ssl2, host_.c_str());
9480 #else
9481  // NOTE: Direct call instead of using the OpenSSL macro to suppress
9482  // -Wold-style-cast warning
9483  SSL_ctrl(ssl2, SSL_CTRL_SET_TLSEXT_HOSTNAME, TLSEXT_NAMETYPE_host_name,
9484  static_cast<void *>(const_cast<char *>(host_.c_str())));
9485 #endif
9486  return true;
9487  });
9488 
9489  if (ssl) {
9490  socket.ssl = ssl;
9491  return true;
9492  }
9493 
9494  shutdown_socket(socket);
9495  close_socket(socket);
9496  return false;
9497 }
9498 
9499 inline void SSLClient::shutdown_ssl(Socket &socket, bool shutdown_gracefully) {
9500  shutdown_ssl_impl(socket, shutdown_gracefully);
9501 }
9502 
9503 inline void SSLClient::shutdown_ssl_impl(Socket &socket,
9504  bool shutdown_gracefully) {
9505  if (socket.sock == INVALID_SOCKET) {
9506  assert(socket.ssl == nullptr);
9507  return;
9508  }
9509  if (socket.ssl) {
9510  detail::ssl_delete(ctx_mutex_, socket.ssl, socket.sock,
9511  shutdown_gracefully);
9512  socket.ssl = nullptr;
9513  }
9514  assert(socket.ssl == nullptr);
9515 }
9516 
9517 inline bool
9518 SSLClient::process_socket(const Socket &socket,
9519  std::function<bool(Stream &strm)> callback) {
9520  assert(socket.ssl);
9521  return detail::process_client_socket_ssl(
9522  socket.ssl, socket.sock, read_timeout_sec_, read_timeout_usec_,
9523  write_timeout_sec_, write_timeout_usec_, std::move(callback));
9524 }
9525 
9526 inline bool SSLClient::is_ssl() const { return true; }
9527 
9528 inline bool SSLClient::verify_host(X509 *server_cert) const {
9529  /* Quote from RFC2818 section 3.1 "Server Identity"
9530 
9531  If a subjectAltName extension of type dNSName is present, that MUST
9532  be used as the identity. Otherwise, the (most specific) Common Name
9533  field in the Subject field of the certificate MUST be used. Although
9534  the use of the Common Name is existing practice, it is deprecated and
9535  Certification Authorities are encouraged to use the dNSName instead.
9536 
9537  Matching is performed using the matching rules specified by
9538  [RFC2459]. If more than one identity of a given type is present in
9539  the certificate (e.g., more than one dNSName name, a match in any one
9540  of the set is considered acceptable.) Names may contain the wildcard
9541  character * which is considered to match any single domain name
9542  component or component fragment. E.g., *.a.com matches foo.a.com but
9543  not bar.foo.a.com. f*.com matches foo.com but not bar.com.
9544 
9545  In some cases, the URI is specified as an IP address rather than a
9546  hostname. In this case, the iPAddress subjectAltName must be present
9547  in the certificate and must exactly match the IP in the URI.
9548 
9549  */
9550  return verify_host_with_subject_alt_name(server_cert) ||
9551  verify_host_with_common_name(server_cert);
9552 }
9553 
9554 inline bool
9555 SSLClient::verify_host_with_subject_alt_name(X509 *server_cert) const {
9556  auto ret = false;
9557 
9558  auto type = GEN_DNS;
9559 
9560  struct in6_addr addr6{};
9561  struct in_addr addr{};
9562  size_t addr_len = 0;
9563 
9564 #ifndef __MINGW32__
9565  if (inet_pton(AF_INET6, host_.c_str(), &addr6)) {
9566  type = GEN_IPADD;
9567  addr_len = sizeof(struct in6_addr);
9568  } else if (inet_pton(AF_INET, host_.c_str(), &addr)) {
9569  type = GEN_IPADD;
9570  addr_len = sizeof(struct in_addr);
9571  }
9572 #endif
9573 
9574  auto alt_names = static_cast<const struct stack_st_GENERAL_NAME *>(
9575  X509_get_ext_d2i(server_cert, NID_subject_alt_name, nullptr, nullptr));
9576 
9577  if (alt_names) {
9578  auto dsn_matched = false;
9579  auto ip_matched = false;
9580 
9581  auto count = sk_GENERAL_NAME_num(alt_names);
9582 
9583  for (decltype(count) i = 0; i < count && !dsn_matched; i++) {
9584  auto val = sk_GENERAL_NAME_value(alt_names, i);
9585  if (val->type == type) {
9586  auto name =
9587  reinterpret_cast<const char *>(ASN1_STRING_get0_data(val->d.ia5));
9588  auto name_len = static_cast<size_t>(ASN1_STRING_length(val->d.ia5));
9589 
9590  switch (type) {
9591  case GEN_DNS: dsn_matched = check_host_name(name, name_len); break;
9592 
9593  case GEN_IPADD:
9594  if (!memcmp(&addr6, name, addr_len) ||
9595  !memcmp(&addr, name, addr_len)) {
9596  ip_matched = true;
9597  }
9598  break;
9599  }
9600  }
9601  }
9602 
9603  if (dsn_matched || ip_matched) { ret = true; }
9604  }
9605 
9606  GENERAL_NAMES_free(const_cast<STACK_OF(GENERAL_NAME) *>(
9607  reinterpret_cast<const STACK_OF(GENERAL_NAME) *>(alt_names)));
9608  return ret;
9609 }
9610 
9611 inline bool SSLClient::verify_host_with_common_name(X509 *server_cert) const {
9612  const auto subject_name = X509_get_subject_name(server_cert);
9613 
9614  if (subject_name != nullptr) {
9615  char name[BUFSIZ];
9616  auto name_len = X509_NAME_get_text_by_NID(subject_name, NID_commonName,
9617  name, sizeof(name));
9618 
9619  if (name_len != -1) {
9620  return check_host_name(name, static_cast<size_t>(name_len));
9621  }
9622  }
9623 
9624  return false;
9625 }
9626 
9627 inline bool SSLClient::check_host_name(const char *pattern,
9628  size_t pattern_len) const {
9629  if (host_.size() == pattern_len && host_ == pattern) { return true; }
9630 
9631  // Wildcard match
9632  // https://bugs.launchpad.net/ubuntu/+source/firefox-3.0/+bug/376484
9633  std::vector<std::string> pattern_components;
9634  detail::split(&pattern[0], &pattern[pattern_len], '.',
9635  [&](const char *b, const char *e) {
9636  pattern_components.emplace_back(b, e);
9637  });
9638 
9639  if (host_components_.size() != pattern_components.size()) { return false; }
9640 
9641  auto itr = pattern_components.begin();
9642  for (const auto &h : host_components_) {
9643  auto &p = *itr;
9644  if (p != h && p != "*") {
9645  auto partial_match = (p.size() > 0 && p[p.size() - 1] == '*' &&
9646  !p.compare(0, p.size() - 1, h));
9647  if (!partial_match) { return false; }
9648  }
9649  ++itr;
9650  }
9651 
9652  return true;
9653 }
9654 #endif
9655 
9656 // Universal client implementation
9657 inline Client::Client(const std::string &scheme_host_port)
9658  : Client(scheme_host_port, std::string(), std::string()) {}
9659 
9660 inline Client::Client(const std::string &scheme_host_port,
9661  const std::string &client_cert_path,
9662  const std::string &client_key_path) {
9663  const static std::regex re(
9664  R"((?:([a-z]+):\/\/)?(?:\[([a-fA-F\d:]+)\]|([^:/?#]+))(?::(\d+))?)");
9665 
9666  std::smatch m;
9667  if (std::regex_match(scheme_host_port, m, re)) {
9668  auto scheme = m[1].str();
9669 
9670 #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
9671  if (!scheme.empty() && (scheme != "http" && scheme != "https")) {
9672 #else
9673  if (!scheme.empty() && scheme != "http") {
9674 #endif
9675 #ifndef CPPHTTPLIB_NO_EXCEPTIONS
9676  std::string msg = "'" + scheme + "' scheme is not supported.";
9677  throw std::invalid_argument(msg);
9678 #endif
9679  return;
9680  }
9681 
9682  auto is_ssl = scheme == "https";
9683 
9684  auto host = m[2].str();
9685  if (host.empty()) { host = m[3].str(); }
9686 
9687  auto port_str = m[4].str();
9688  auto port = !port_str.empty() ? std::stoi(port_str) : (is_ssl ? 443 : 80);
9689 
9690  if (is_ssl) {
9691 #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
9692  cli_ = detail::make_unique<SSLClient>(host, port, client_cert_path,
9693  client_key_path);
9694  is_ssl_ = is_ssl;
9695 #endif
9696  } else {
9697  cli_ = detail::make_unique<ClientImpl>(host, port, client_cert_path,
9698  client_key_path);
9699  }
9700  } else {
9701  // NOTE: Update TEST(UniversalClientImplTest, Ipv6LiteralAddress)
9702  // if port param below changes.
9703  cli_ = detail::make_unique<ClientImpl>(scheme_host_port, 80,
9704  client_cert_path, client_key_path);
9705  }
9706 } // namespace detail
9707 
9708 inline Client::Client(const std::string &host, int port)
9709  : cli_(detail::make_unique<ClientImpl>(host, port)) {}
9710 
9711 inline Client::Client(const std::string &host, int port,
9712  const std::string &client_cert_path,
9713  const std::string &client_key_path)
9714  : cli_(detail::make_unique<ClientImpl>(host, port, client_cert_path,
9715  client_key_path)) {}
9716 
9717 inline Client::~Client() = default;
9718 
9719 inline bool Client::is_valid() const {
9720  return cli_ != nullptr && cli_->is_valid();
9721 }
9722 
9723 inline Result Client::Get(const std::string &path) { return cli_->Get(path); }
9724 inline Result Client::Get(const std::string &path, const Headers &headers) {
9725  return cli_->Get(path, headers);
9726 }
9727 inline Result Client::Get(const std::string &path, Progress progress) {
9728  return cli_->Get(path, std::move(progress));
9729 }
9730 inline Result Client::Get(const std::string &path, const Headers &headers,
9731  Progress progress) {
9732  return cli_->Get(path, headers, std::move(progress));
9733 }
9734 inline Result Client::Get(const std::string &path,
9735  ContentReceiver content_receiver) {
9736  return cli_->Get(path, std::move(content_receiver));
9737 }
9738 inline Result Client::Get(const std::string &path, const Headers &headers,
9739  ContentReceiver content_receiver) {
9740  return cli_->Get(path, headers, std::move(content_receiver));
9741 }
9742 inline Result Client::Get(const std::string &path,
9743  ContentReceiver content_receiver, Progress progress) {
9744  return cli_->Get(path, std::move(content_receiver), std::move(progress));
9745 }
9746 inline Result Client::Get(const std::string &path, const Headers &headers,
9747  ContentReceiver content_receiver, Progress progress) {
9748  return cli_->Get(path, headers, std::move(content_receiver),
9749  std::move(progress));
9750 }
9751 inline Result Client::Get(const std::string &path,
9752  ResponseHandler response_handler,
9753  ContentReceiver content_receiver) {
9754  return cli_->Get(path, std::move(response_handler),
9755  std::move(content_receiver));
9756 }
9757 inline Result Client::Get(const std::string &path, const Headers &headers,
9758  ResponseHandler response_handler,
9759  ContentReceiver content_receiver) {
9760  return cli_->Get(path, headers, std::move(response_handler),
9761  std::move(content_receiver));
9762 }
9763 inline Result Client::Get(const std::string &path,
9764  ResponseHandler response_handler,
9765  ContentReceiver content_receiver, Progress progress) {
9766  return cli_->Get(path, std::move(response_handler),
9767  std::move(content_receiver), std::move(progress));
9768 }
9769 inline Result Client::Get(const std::string &path, const Headers &headers,
9770  ResponseHandler response_handler,
9771  ContentReceiver content_receiver, Progress progress) {
9772  return cli_->Get(path, headers, std::move(response_handler),
9773  std::move(content_receiver), std::move(progress));
9774 }
9775 inline Result Client::Get(const std::string &path, const Params &params,
9776  const Headers &headers, Progress progress) {
9777  return cli_->Get(path, params, headers, std::move(progress));
9778 }
9779 inline Result Client::Get(const std::string &path, const Params &params,
9780  const Headers &headers,
9781  ContentReceiver content_receiver, Progress progress) {
9782  return cli_->Get(path, params, headers, std::move(content_receiver),
9783  std::move(progress));
9784 }
9785 inline Result Client::Get(const std::string &path, const Params &params,
9786  const Headers &headers,
9787  ResponseHandler response_handler,
9788  ContentReceiver content_receiver, Progress progress) {
9789  return cli_->Get(path, params, headers, std::move(response_handler),
9790  std::move(content_receiver), std::move(progress));
9791 }
9792 
9793 inline Result Client::Head(const std::string &path) { return cli_->Head(path); }
9794 inline Result Client::Head(const std::string &path, const Headers &headers) {
9795  return cli_->Head(path, headers);
9796 }
9797 
9798 inline Result Client::Post(const std::string &path) { return cli_->Post(path); }
9799 inline Result Client::Post(const std::string &path, const Headers &headers) {
9800  return cli_->Post(path, headers);
9801 }
9802 inline Result Client::Post(const std::string &path, const char *body,
9803  size_t content_length,
9804  const std::string &content_type) {
9805  return cli_->Post(path, body, content_length, content_type);
9806 }
9807 inline Result Client::Post(const std::string &path, const Headers &headers,
9808  const char *body, size_t content_length,
9809  const std::string &content_type) {
9810  return cli_->Post(path, headers, body, content_length, content_type);
9811 }
9812 inline Result Client::Post(const std::string &path, const Headers &headers,
9813  const char *body, size_t content_length,
9814  const std::string &content_type, Progress progress) {
9815  return cli_->Post(path, headers, body, content_length, content_type,
9816  progress);
9817 }
9818 inline Result Client::Post(const std::string &path, const std::string &body,
9819  const std::string &content_type) {
9820  return cli_->Post(path, body, content_type);
9821 }
9822 inline Result Client::Post(const std::string &path, const std::string &body,
9823  const std::string &content_type, Progress progress) {
9824  return cli_->Post(path, body, content_type, progress);
9825 }
9826 inline Result Client::Post(const std::string &path, const Headers &headers,
9827  const std::string &body,
9828  const std::string &content_type) {
9829  return cli_->Post(path, headers, body, content_type);
9830 }
9831 inline Result Client::Post(const std::string &path, const Headers &headers,
9832  const std::string &body,
9833  const std::string &content_type, Progress progress) {
9834  return cli_->Post(path, headers, body, content_type, progress);
9835 }
9836 inline Result Client::Post(const std::string &path, size_t content_length,
9837  ContentProvider content_provider,
9838  const std::string &content_type) {
9839  return cli_->Post(path, content_length, std::move(content_provider),
9840  content_type);
9841 }
9842 inline Result Client::Post(const std::string &path,
9843  ContentProviderWithoutLength content_provider,
9844  const std::string &content_type) {
9845  return cli_->Post(path, std::move(content_provider), content_type);
9846 }
9847 inline Result Client::Post(const std::string &path, const Headers &headers,
9848  size_t content_length,
9849  ContentProvider content_provider,
9850  const std::string &content_type) {
9851  return cli_->Post(path, headers, content_length, std::move(content_provider),
9852  content_type);
9853 }
9854 inline Result Client::Post(const std::string &path, const Headers &headers,
9855  ContentProviderWithoutLength content_provider,
9856  const std::string &content_type) {
9857  return cli_->Post(path, headers, std::move(content_provider), content_type);
9858 }
9859 inline Result Client::Post(const std::string &path, const Params &params) {
9860  return cli_->Post(path, params);
9861 }
9862 inline Result Client::Post(const std::string &path, const Headers &headers,
9863  const Params &params) {
9864  return cli_->Post(path, headers, params);
9865 }
9866 inline Result Client::Post(const std::string &path, const Headers &headers,
9867  const Params &params, Progress progress) {
9868  return cli_->Post(path, headers, params, progress);
9869 }
9870 inline Result Client::Post(const std::string &path,
9871  const MultipartFormDataItems &items) {
9872  return cli_->Post(path, items);
9873 }
9874 inline Result Client::Post(const std::string &path, const Headers &headers,
9875  const MultipartFormDataItems &items) {
9876  return cli_->Post(path, headers, items);
9877 }
9878 inline Result Client::Post(const std::string &path, const Headers &headers,
9879  const MultipartFormDataItems &items,
9880  const std::string &boundary) {
9881  return cli_->Post(path, headers, items, boundary);
9882 }
9883 inline Result
9884 Client::Post(const std::string &path, const Headers &headers,
9885  const MultipartFormDataItems &items,
9886  const MultipartFormDataProviderItems &provider_items) {
9887  return cli_->Post(path, headers, items, provider_items);
9888 }
9889 inline Result Client::Put(const std::string &path) { return cli_->Put(path); }
9890 inline Result Client::Put(const std::string &path, const char *body,
9891  size_t content_length,
9892  const std::string &content_type) {
9893  return cli_->Put(path, body, content_length, content_type);
9894 }
9895 inline Result Client::Put(const std::string &path, const Headers &headers,
9896  const char *body, size_t content_length,
9897  const std::string &content_type) {
9898  return cli_->Put(path, headers, body, content_length, content_type);
9899 }
9900 inline Result Client::Put(const std::string &path, const Headers &headers,
9901  const char *body, size_t content_length,
9902  const std::string &content_type, Progress progress) {
9903  return cli_->Put(path, headers, body, content_length, content_type, progress);
9904 }
9905 inline Result Client::Put(const std::string &path, const std::string &body,
9906  const std::string &content_type) {
9907  return cli_->Put(path, body, content_type);
9908 }
9909 inline Result Client::Put(const std::string &path, const std::string &body,
9910  const std::string &content_type, Progress progress) {
9911  return cli_->Put(path, body, content_type, progress);
9912 }
9913 inline Result Client::Put(const std::string &path, const Headers &headers,
9914  const std::string &body,
9915  const std::string &content_type) {
9916  return cli_->Put(path, headers, body, content_type);
9917 }
9918 inline Result Client::Put(const std::string &path, const Headers &headers,
9919  const std::string &body,
9920  const std::string &content_type, Progress progress) {
9921  return cli_->Put(path, headers, body, content_type, progress);
9922 }
9923 inline Result Client::Put(const std::string &path, size_t content_length,
9924  ContentProvider content_provider,
9925  const std::string &content_type) {
9926  return cli_->Put(path, content_length, std::move(content_provider),
9927  content_type);
9928 }
9929 inline Result Client::Put(const std::string &path,
9930  ContentProviderWithoutLength content_provider,
9931  const std::string &content_type) {
9932  return cli_->Put(path, std::move(content_provider), content_type);
9933 }
9934 inline Result Client::Put(const std::string &path, const Headers &headers,
9935  size_t content_length,
9936  ContentProvider content_provider,
9937  const std::string &content_type) {
9938  return cli_->Put(path, headers, content_length, std::move(content_provider),
9939  content_type);
9940 }
9941 inline Result Client::Put(const std::string &path, const Headers &headers,
9942  ContentProviderWithoutLength content_provider,
9943  const std::string &content_type) {
9944  return cli_->Put(path, headers, std::move(content_provider), content_type);
9945 }
9946 inline Result Client::Put(const std::string &path, const Params &params) {
9947  return cli_->Put(path, params);
9948 }
9949 inline Result Client::Put(const std::string &path, const Headers &headers,
9950  const Params &params) {
9951  return cli_->Put(path, headers, params);
9952 }
9953 inline Result Client::Put(const std::string &path, const Headers &headers,
9954  const Params &params, Progress progress) {
9955  return cli_->Put(path, headers, params, progress);
9956 }
9957 inline Result Client::Put(const std::string &path,
9958  const MultipartFormDataItems &items) {
9959  return cli_->Put(path, items);
9960 }
9961 inline Result Client::Put(const std::string &path, const Headers &headers,
9962  const MultipartFormDataItems &items) {
9963  return cli_->Put(path, headers, items);
9964 }
9965 inline Result Client::Put(const std::string &path, const Headers &headers,
9966  const MultipartFormDataItems &items,
9967  const std::string &boundary) {
9968  return cli_->Put(path, headers, items, boundary);
9969 }
9970 inline Result
9971 Client::Put(const std::string &path, const Headers &headers,
9972  const MultipartFormDataItems &items,
9973  const MultipartFormDataProviderItems &provider_items) {
9974  return cli_->Put(path, headers, items, provider_items);
9975 }
9976 inline Result Client::Patch(const std::string &path) {
9977  return cli_->Patch(path);
9978 }
9979 inline Result Client::Patch(const std::string &path, const char *body,
9980  size_t content_length,
9981  const std::string &content_type) {
9982  return cli_->Patch(path, body, content_length, content_type);
9983 }
9984 inline Result Client::Patch(const std::string &path, const char *body,
9985  size_t content_length,
9986  const std::string &content_type,
9987  Progress progress) {
9988  return cli_->Patch(path, body, content_length, content_type, progress);
9989 }
9990 inline Result Client::Patch(const std::string &path, const Headers &headers,
9991  const char *body, size_t content_length,
9992  const std::string &content_type) {
9993  return cli_->Patch(path, headers, body, content_length, content_type);
9994 }
9995 inline Result Client::Patch(const std::string &path, const Headers &headers,
9996  const char *body, size_t content_length,
9997  const std::string &content_type,
9998  Progress progress) {
9999  return cli_->Patch(path, headers, body, content_length, content_type,
10000  progress);
10001 }
10002 inline Result Client::Patch(const std::string &path, const std::string &body,
10003  const std::string &content_type) {
10004  return cli_->Patch(path, body, content_type);
10005 }
10006 inline Result Client::Patch(const std::string &path, const std::string &body,
10007  const std::string &content_type,
10008  Progress progress) {
10009  return cli_->Patch(path, body, content_type, progress);
10010 }
10011 inline Result Client::Patch(const std::string &path, const Headers &headers,
10012  const std::string &body,
10013  const std::string &content_type) {
10014  return cli_->Patch(path, headers, body, content_type);
10015 }
10016 inline Result Client::Patch(const std::string &path, const Headers &headers,
10017  const std::string &body,
10018  const std::string &content_type,
10019  Progress progress) {
10020  return cli_->Patch(path, headers, body, content_type, progress);
10021 }
10022 inline Result Client::Patch(const std::string &path, size_t content_length,
10023  ContentProvider content_provider,
10024  const std::string &content_type) {
10025  return cli_->Patch(path, content_length, std::move(content_provider),
10026  content_type);
10027 }
10028 inline Result Client::Patch(const std::string &path,
10029  ContentProviderWithoutLength content_provider,
10030  const std::string &content_type) {
10031  return cli_->Patch(path, std::move(content_provider), content_type);
10032 }
10033 inline Result Client::Patch(const std::string &path, const Headers &headers,
10034  size_t content_length,
10035  ContentProvider content_provider,
10036  const std::string &content_type) {
10037  return cli_->Patch(path, headers, content_length, std::move(content_provider),
10038  content_type);
10039 }
10040 inline Result Client::Patch(const std::string &path, const Headers &headers,
10041  ContentProviderWithoutLength content_provider,
10042  const std::string &content_type) {
10043  return cli_->Patch(path, headers, std::move(content_provider), content_type);
10044 }
10045 inline Result Client::Delete(const std::string &path) {
10046  return cli_->Delete(path);
10047 }
10048 inline Result Client::Delete(const std::string &path, const Headers &headers) {
10049  return cli_->Delete(path, headers);
10050 }
10051 inline Result Client::Delete(const std::string &path, const char *body,
10052  size_t content_length,
10053  const std::string &content_type) {
10054  return cli_->Delete(path, body, content_length, content_type);
10055 }
10056 inline Result Client::Delete(const std::string &path, const char *body,
10057  size_t content_length,
10058  const std::string &content_type,
10059  Progress progress) {
10060  return cli_->Delete(path, body, content_length, content_type, progress);
10061 }
10062 inline Result Client::Delete(const std::string &path, const Headers &headers,
10063  const char *body, size_t content_length,
10064  const std::string &content_type) {
10065  return cli_->Delete(path, headers, body, content_length, content_type);
10066 }
10067 inline Result Client::Delete(const std::string &path, const Headers &headers,
10068  const char *body, size_t content_length,
10069  const std::string &content_type,
10070  Progress progress) {
10071  return cli_->Delete(path, headers, body, content_length, content_type,
10072  progress);
10073 }
10074 inline Result Client::Delete(const std::string &path, const std::string &body,
10075  const std::string &content_type) {
10076  return cli_->Delete(path, body, content_type);
10077 }
10078 inline Result Client::Delete(const std::string &path, const std::string &body,
10079  const std::string &content_type,
10080  Progress progress) {
10081  return cli_->Delete(path, body, content_type, progress);
10082 }
10083 inline Result Client::Delete(const std::string &path, const Headers &headers,
10084  const std::string &body,
10085  const std::string &content_type) {
10086  return cli_->Delete(path, headers, body, content_type);
10087 }
10088 inline Result Client::Delete(const std::string &path, const Headers &headers,
10089  const std::string &body,
10090  const std::string &content_type,
10091  Progress progress) {
10092  return cli_->Delete(path, headers, body, content_type, progress);
10093 }
10094 inline Result Client::Options(const std::string &path) {
10095  return cli_->Options(path);
10096 }
10097 inline Result Client::Options(const std::string &path, const Headers &headers) {
10098  return cli_->Options(path, headers);
10099 }
10100 
10101 inline bool Client::send(Request &req, Response &res, Error &error) {
10102  return cli_->send(req, res, error);
10103 }
10104 
10105 inline Result Client::send(const Request &req) { return cli_->send(req); }
10106 
10107 inline void Client::stop() { cli_->stop(); }
10108 
10109 inline std::string Client::host() const { return cli_->host(); }
10110 
10111 inline int Client::port() const { return cli_->port(); }
10112 
10113 inline size_t Client::is_socket_open() const { return cli_->is_socket_open(); }
10114 
10115 inline socket_t Client::socket() const { return cli_->socket(); }
10116 
10117 inline void
10118 Client::set_hostname_addr_map(std::map<std::string, std::string> addr_map) {
10119  cli_->set_hostname_addr_map(std::move(addr_map));
10120 }
10121 
10122 inline void Client::set_default_headers(Headers headers) {
10123  cli_->set_default_headers(std::move(headers));
10124 }
10125 
10127  std::function<ssize_t(Stream &, Headers &)> const &writer) {
10128  cli_->set_header_writer(writer);
10129 }
10130 
10131 inline void Client::set_address_family(int family) {
10132  cli_->set_address_family(family);
10133 }
10134 
10135 inline void Client::set_tcp_nodelay(bool on) { cli_->set_tcp_nodelay(on); }
10136 
10137 inline void Client::set_socket_options(SocketOptions socket_options) {
10138  cli_->set_socket_options(std::move(socket_options));
10139 }
10140 
10141 inline void Client::set_connection_timeout(time_t sec, time_t usec) {
10142  cli_->set_connection_timeout(sec, usec);
10143 }
10144 
10145 inline void Client::set_read_timeout(time_t sec, time_t usec) {
10146  cli_->set_read_timeout(sec, usec);
10147 }
10148 
10149 inline void Client::set_write_timeout(time_t sec, time_t usec) {
10150  cli_->set_write_timeout(sec, usec);
10151 }
10152 
10153 inline void Client::set_basic_auth(const std::string &username,
10154  const std::string &password) {
10155  cli_->set_basic_auth(username, password);
10156 }
10157 inline void Client::set_bearer_token_auth(const std::string &token) {
10158  cli_->set_bearer_token_auth(token);
10159 }
10160 #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
10161 inline void Client::set_digest_auth(const std::string &username,
10162  const std::string &password) {
10163  cli_->set_digest_auth(username, password);
10164 }
10165 #endif
10166 
10167 inline void Client::set_keep_alive(bool on) { cli_->set_keep_alive(on); }
10168 inline void Client::set_follow_location(bool on) {
10169  cli_->set_follow_location(on);
10170 }
10171 
10172 inline void Client::set_url_encode(bool on) { cli_->set_url_encode(on); }
10173 
10174 inline void Client::set_compress(bool on) { cli_->set_compress(on); }
10175 
10176 inline void Client::set_decompress(bool on) { cli_->set_decompress(on); }
10177 
10178 inline void Client::set_interface(const std::string &intf) {
10179  cli_->set_interface(intf);
10180 }
10181 
10182 inline void Client::set_proxy(const std::string &host, int port) {
10183  cli_->set_proxy(host, port);
10184 }
10185 inline void Client::set_proxy_basic_auth(const std::string &username,
10186  const std::string &password) {
10187  cli_->set_proxy_basic_auth(username, password);
10188 }
10189 inline void Client::set_proxy_bearer_token_auth(const std::string &token) {
10190  cli_->set_proxy_bearer_token_auth(token);
10191 }
10192 #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
10193 inline void Client::set_proxy_digest_auth(const std::string &username,
10194  const std::string &password) {
10195  cli_->set_proxy_digest_auth(username, password);
10196 }
10197 #endif
10198 
10199 #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
10200 inline void Client::enable_server_certificate_verification(bool enabled) {
10201  cli_->enable_server_certificate_verification(enabled);
10202 }
10203 
10204 inline void Client::enable_server_hostname_verification(bool enabled) {
10205  cli_->enable_server_hostname_verification(enabled);
10206 }
10207 
10208 inline void Client::set_server_certificate_verifier(
10209  std::function<bool(SSL *ssl)> verifier) {
10210  cli_->set_server_certificate_verifier(verifier);
10211 }
10212 #endif
10213 
10214 inline void Client::set_logger(Logger logger) {
10215  cli_->set_logger(std::move(logger));
10216 }
10217 
10218 #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
10219 inline void Client::set_ca_cert_path(const std::string &ca_cert_file_path,
10220  const std::string &ca_cert_dir_path) {
10221  cli_->set_ca_cert_path(ca_cert_file_path, ca_cert_dir_path);
10222 }
10223 
10224 inline void Client::set_ca_cert_store(X509_STORE *ca_cert_store) {
10225  if (is_ssl_) {
10226  static_cast<SSLClient &>(*cli_).set_ca_cert_store(ca_cert_store);
10227  } else {
10228  cli_->set_ca_cert_store(ca_cert_store);
10229  }
10230 }
10231 
10232 inline void Client::load_ca_cert_store(const char *ca_cert, std::size_t size) {
10233  set_ca_cert_store(cli_->create_ca_cert_store(ca_cert, size));
10234 }
10235 
10236 inline long Client::get_openssl_verify_result() const {
10237  if (is_ssl_) {
10238  return static_cast<SSLClient &>(*cli_).get_openssl_verify_result();
10239  }
10240  return -1; // NOTE: -1 doesn't match any of X509_V_ERR_???
10241 }
10242 
10243 inline SSL_CTX *Client::ssl_context() const {
10244  if (is_ssl_) { return static_cast<SSLClient &>(*cli_).ssl_context(); }
10245  return nullptr;
10246 }
10247 #endif
10248 
10249 // ----------------------------------------------------------------------------
10250 
10251 } // namespace httplib
10252 
10253 #if defined(_WIN32) && defined(CPPHTTPLIB_USE_POLL)
10254 #undef poll
10255 #endif
10256 
10257 #endif // CPPHTTPLIB_HTTPLIB_H
httplib::detail::PathParamsMatcher
Captures parameters in request path and stores them in Request::path_params.
Definition: httplib.h:874
httplib::Logger
std::function< void(const Request &, const Response &)> Logger
Definition: httplib.h:836
files
Use of this software is granted under one of the following two to be chosen freely by the user Boost Software License Version Marcin Kalicinski Permission is hereby free of to any person or organization obtaining a copy of the software and accompanying documentation covered by this and transmit the and to prepare derivative works of the and to permit third parties to whom the Software is furnished to do all subject to the including the above license this restriction and the following must be included in all copies of the in whole or in and all derivative works of the unless such copies or derivative works are solely in the form of machine executable object code generated by a source language processor THE SOFTWARE IS PROVIDED AS WITHOUT WARRANTY OF ANY EXPRESS OR INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF FITNESS FOR A PARTICULAR TITLE AND NON INFRINGEMENT IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR OTHER WHETHER IN TORT OR ARISING OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE The MIT Marcin Kalicinski Permission is hereby free of to any person obtaining a copy of this software and associated documentation files(the "Software")
httplib::Error::SSLServerVerification
@ SSLServerVerification
httplib::Response::headers
Headers headers
Definition: httplib.h:670
httplib::Response::content_provider_success_
bool content_provider_success_
Definition: httplib.h:719
httplib::Response::get_header_value_u64
uint64_t get_header_value_u64(const std::string &key, uint64_t def=0, size_t id=0) const
Definition: httplib.h:2034
httplib::Server::decommission
void decommission()
Definition: httplib.h:6347
httplib::detail::decompressor::~decompressor
virtual ~decompressor()=default
httplib::make_range_header
std::pair< std::string, std::string > make_range_header(const Ranges &ranges)
Definition: httplib.h:5645
httplib::detail::create_client_socket
socket_t create_client_socket(const std::string &host, const std::string &ip, int port, int address_family, bool tcp_nodelay, bool ipv6_v6only, SocketOptions socket_options, time_t connection_timeout_sec, time_t connection_timeout_usec, time_t read_timeout_sec, time_t read_timeout_usec, time_t write_timeout_sec, time_t write_timeout_usec, const std::string &intf, Error &error)
Definition: httplib.h:3624
httplib::Client::Delete
Result Delete(const std::string &path)
Definition: httplib.h:10045
httplib::ClientImpl::set_proxy
void set_proxy(const std::string &host, int port)
Definition: httplib.h:8790
httplib::Server::set_file_request_handler
Server & set_file_request_handler(Handler handler)
Definition: httplib.h:6200
CPPHTTPLIB_RANGE_MAX_COUNT
#define CPPHTTPLIB_RANGE_MAX_COUNT
Definition: httplib.h:106
armarx::view_selection::skills::direction::state::right
state::Type right(state::Type previous)
Definition: LookDirection.cpp:264
httplib::Request::files
MultipartFormDataMap files
Definition: httplib.h:627
httplib::MethodNotAllowed_405
@ MethodNotAllowed_405
Definition: httplib.h:467
httplib::Client::set_proxy_basic_auth
void set_proxy_basic_auth(const std::string &username, const std::string &password)
Definition: httplib.h:10185
httplib::ClientImpl::set_basic_auth
void set_basic_auth(const std::string &username, const std::string &password)
Definition: httplib.h:8732
httplib::Server::is_valid
virtual bool is_valid() const
Definition: httplib.h:7217
httplib::ClientImpl::process_request
bool process_request(Stream &strm, Request &req, Response &res, bool close_connection, Error &error)
Definition: httplib.h:7941
httplib::detail::case_ignore::equal_to
Definition: httplib.h:377
httplib::detail::mmap::open
bool open(const char *path)
Definition: httplib.h:2936
httplib::ResetContent_205
@ ResetContent_205
Definition: httplib.h:444
httplib::PaymentRequired_402
@ PaymentRequired_402
Definition: httplib.h:464
httplib::detail::SocketStream
Definition: httplib.h:3229
httplib::detail::nocompressor::~nocompressor
~nocompressor() override=default
httplib::Response::body
std::string body
Definition: httplib.h:671
httplib::Client::set_tcp_nodelay
void set_tcp_nodelay(bool on)
Definition: httplib.h:10135
httplib::Request::has_header
bool has_header(const std::string &key) const
Definition: httplib.h:5675
httplib::make_bearer_token_authentication_header
std::pair< std::string, std::string > make_bearer_token_authentication_header(const std::string &token, bool is_proxy=false)
Definition: httplib.h:5667
httplib::detail::wait_until_socket_is_ready
Error wait_until_socket_is_ready(socket_t sock, time_t sec, time_t usec)
Definition: httplib.h:3161
httplib::Request::ranges
Ranges ranges
Definition: httplib.h:628
httplib::detail::mmap::mmap
mmap(const char *path)
Definition: httplib.h:2932
httplib::detail::BufferStream::write
ssize_t write(const char *ptr, size_t size) override
Definition: httplib.h:5969
httplib::detail::case_ignore::hash::hash_core
size_t hash_core(const char *s, size_t l, size_t h) const
Definition: httplib.h:388
httplib::ClientImpl::set_header_writer
void set_header_writer(std::function< ssize_t(Stream &, Headers &)> const &writer)
Definition: httplib.h:8765
httplib::append_query_params
std::string append_query_params(const std::string &path, const Params &params)
Definition: httplib.h:5634
httplib::Conflict_409
@ Conflict_409
Definition: httplib.h:471
httplib::ClientImpl::set_proxy_basic_auth
void set_proxy_basic_auth(const std::string &username, const std::string &password)
Definition: httplib.h:8795
httplib::detail::str2tag
unsigned int str2tag(const std::string &s)
Definition: httplib.h:3780
httplib::Response::get_header_value
std::string get_header_value(const std::string &key, const char *def="", size_t id=0) const
Definition: httplib.h:5744
httplib::Client::set_keep_alive
void set_keep_alive(bool on)
Definition: httplib.h:10167
httplib::Request::get_file_values
std::vector< MultipartFormData > get_file_values(const std::string &key) const
Definition: httplib.h:5730
str
std::string str(const T &t)
Definition: UserAssistedSegmenterGuiWidgetController.cpp:43
armarx::aron::ret
ReaderT::InputType T & ret
Definition: rw.h:13
httplib::InternalServerError_500
@ InternalServerError_500
Definition: httplib.h:493
httplib::GatewayTimeout_504
@ GatewayTimeout_504
Definition: httplib.h:497
httplib::ClientImpl::set_bearer_token_auth
void set_bearer_token_auth(const std::string &token)
Definition: httplib.h:8738
httplib::Result::get_request_header_value_count
size_t get_request_header_value_count(const std::string &key) const
Definition: httplib.h:5848
httplib::ResponseHandler
std::function< bool(const Response &response)> ResponseHandler
Definition: httplib.h:516
httplib::Error::UnsupportedMultipartBoundaryChars
@ UnsupportedMultipartBoundaryChars
httplib::RangeNotSatisfiable_416
@ RangeNotSatisfiable_416
Definition: httplib.h:478
httplib::Server::remove_mount_point
bool remove_mount_point(const std::string &mount_point)
Definition: httplib.h:6178
Response::data
std::vector< unsigned char > data
Definition: Response.h:107
httplib::detail::from_hex_to_i
bool from_hex_to_i(const std::string &s, size_t i, size_t cnt, int &val)
Definition: httplib.h:2533
httplib::ClientImpl::write_timeout_sec_
time_t write_timeout_sec_
Definition: httplib.h:1529
httplib::NotFound_404
@ NotFound_404
Definition: httplib.h:466
httplib::Response::~Response
~Response()
Definition: httplib.h:708
httplib::Error::Write
@ Write
httplib::ClientImpl::decompress_
bool decompress_
Definition: httplib.h:1551
httplib::ClientImpl::set_interface
void set_interface(const std::string &intf)
Definition: httplib.h:8786
httplib::ClientImpl::set_hostname_addr_map
void set_hostname_addr_map(std::map< std::string, std::string > addr_map)
Definition: httplib.h:8757
httplib::ClientImpl::close_socket
void close_socket(Socket &socket)
Definition: httplib.h:7354
httplib::detail::read_content_chunked
bool read_content_chunked(Stream &strm, T &x, ContentReceiverWithProgress out)
Definition: httplib.h:4256
httplib::Server::read_timeout_sec_
time_t read_timeout_sec_
Definition: httplib.h:1027
httplib::ClientImpl::ClientImpl
ClientImpl(const std::string &host)
Definition: httplib.h:7244
httplib::LoopDetected_508
@ LoopDetected_508
Definition: httplib.h:501
httplib::ClientImpl::Patch
Result Patch(const std::string &path)
Definition: httplib.h:8503
httplib::Client::Post
Result Post(const std::string &path)
Definition: httplib.h:9798
CPPHTTPLIB_KEEPALIVE_MAX_COUNT
#define CPPHTTPLIB_KEEPALIVE_MAX_COUNT
Definition: httplib.h:26
httplib::Stream::write
virtual ssize_t write(const char *ptr, size_t size)=0
httplib::ClientImpl::set_decompress
void set_decompress(bool on)
Definition: httplib.h:8784
httplib::Server::set_default_file_mimetype
Server & set_default_file_mimetype(const std::string &mime)
Definition: httplib.h:6195
httplib::detail::get_local_ip_and_port
void get_local_ip_and_port(socket_t sock, std::string &ip, int &port)
Definition: httplib.h:3731
httplib::detail::case_ignore::equal_to::operator()
bool operator()(const std::string &a, const std::string &b) const
Definition: httplib.h:378
httplib::Response::status
int status
Definition: httplib.h:668
httplib::hosted_at
std::string hosted_at(const std::string &hostname)
Definition: httplib.h:5597
httplib::Server::process_request
bool process_request(Stream &strm, const std::string &remote_addr, int remote_port, const std::string &local_addr, int local_port, bool close_connection, bool &connection_closed, const std::function< void(Request &)> &setup_request)
Definition: httplib.h:7040
httplib::ClientImpl::socket_should_be_closed_when_request_is_done_
bool socket_should_be_closed_when_request_is_done_
Definition: httplib.h:1509
httplib::ContentProvider
std::function< bool(size_t offset, size_t length, DataSink &sink)> ContentProvider
Definition: httplib.h:561
httplib::Request::matches
Match matches
Definition: httplib.h:629
httplib::detail::range_error
bool range_error(Request &req, Response &res)
Definition: httplib.h:5129
httplib::ClientImpl::host
std::string host() const
Definition: httplib.h:8706
httplib::Request::authorization_count_
size_t authorization_count_
Definition: httplib.h:663
httplib::MultipartFormData::name
std::string name
Definition: httplib.h:519
httplib::Server::set_pre_routing_handler
Server & set_pre_routing_handler(HandlerWithResponse handler)
Definition: httplib.h:6225
httplib::ClientImpl::header_writer_
std::function< ssize_t(Stream &, Headers &)> header_writer_
Definition: httplib.h:1518
httplib::ClientImpl::socket_requests_in_flight_
size_t socket_requests_in_flight_
Definition: httplib.h:1507
httplib::ClientImpl::set_default_headers
void set_default_headers(Headers headers)
Definition: httplib.h:8761
httplib::detail::serialize_multipart_formdata
std::string serialize_multipart_formdata(const MultipartFormDataItems &items, const std::string &boundary, bool finish=true)
Definition: httplib.h:5115
httplib::UseProxy_305
@ UseProxy_305
Definition: httplib.h:456
CPPHTTPLIB_FORM_URL_ENCODED_PAYLOAD_MAX_LENGTH
#define CPPHTTPLIB_FORM_URL_ENCODED_PAYLOAD_MAX_LENGTH
Definition: httplib.h:102
httplib::Error::BindIPAddress
@ BindIPAddress
httplib::TaskQueue::on_idle
virtual void on_idle()
Definition: httplib.h:749
httplib::Client::socket
socket_t socket() const
Definition: httplib.h:10115
httplib::detail::write_content_chunked
bool write_content_chunked(Stream &strm, const ContentProvider &content_provider, const T &is_shutting_down, U &compressor, Error &error)
Definition: httplib.h:4537
httplib::Request::response_handler
ResponseHandler response_handler
Definition: httplib.h:633
httplib::ClientImpl::set_ipv6_v6only
void set_ipv6_v6only(bool on)
Definition: httplib.h:8776
httplib::Error::SSLServerHostnameVerification
@ SSLServerHostnameVerification
httplib::ClientImpl::request_mutex_
std::recursive_mutex request_mutex_
Definition: httplib.h:1504
httplib::ClientImpl::write_timeout_usec_
time_t write_timeout_usec_
Definition: httplib.h:1530
httplib::Server::bind_to_port
bool bind_to_port(const std::string &host, int port, int socket_flags=0)
Definition: httplib.h:6310
CPPHTTPLIB_CONNECTION_TIMEOUT_USECOND
#define CPPHTTPLIB_CONNECTION_TIMEOUT_USECOND
Definition: httplib.h:34
httplib::TaskQueue::enqueue
virtual bool enqueue(std::function< void()> fn)=0
httplib::ClientImpl::proxy_basic_auth_password_
std::string proxy_basic_auth_password_
Definition: httplib.h:1559
httplib::detail::compressor::compress
virtual bool compress(const char *data, size_t data_length, bool last, Callback callback)=0
httplib::ClientImpl::client_cert_path_
std::string client_cert_path_
Definition: httplib.h:1522
httplib::ThreadPool::~ThreadPool
~ThreadPool() override=default
httplib::Stream::is_writable
virtual bool is_writable() const =0
list
list(APPEND SOURCES ${QT_RESOURCES}) set(COMPONENT_LIBS ArmarXGui ArmarXCoreObservers ArmarXCoreEigen3Variants PlotterController $
Definition: CMakeLists.txt:49
httplib::RequestHeaderFieldsTooLarge_431
@ RequestHeaderFieldsTooLarge_431
Definition: httplib.h:489
httplib::Found_302
@ Found_302
Definition: httplib.h:453
httplib::Request::get_header_value_u64
uint64_t get_header_value_u64(const std::string &key, uint64_t def=0, size_t id=0) const
Definition: httplib.h:2029
httplib::DataSink
Definition: httplib.h:527
httplib::detail::ContentProviderAdapter::operator()
bool operator()(size_t offset, size_t, DataSink &sink)
Definition: httplib.h:5587
httplib::NotAcceptable_406
@ NotAcceptable_406
Definition: httplib.h:468
httplib::detail::encode_query_param
std::string encode_query_param(const std::string &value)
Definition: httplib.h:2679
httplib::Client::set_proxy
void set_proxy(const std::string &host, int port)
Definition: httplib.h:10182
httplib::Client::set_decompress
void set_decompress(bool on)
Definition: httplib.h:10176
httplib::UriTooLong_414
@ UriTooLong_414
Definition: httplib.h:476
httplib::detail::if2ip
std::string if2ip(int address_family, const std::string &ifn)
Definition: httplib.h:3587
httplib::ClientImpl::proxy_basic_auth_username_
std::string proxy_basic_auth_username_
Definition: httplib.h:1558
httplib::Client::Put
Result Put(const std::string &path)
Definition: httplib.h:9889
httplib::detail::is_space_or_tab
bool is_space_or_tab(char c)
Definition: httplib.h:2785
httplib::ClientImpl::read_timeout_usec_
time_t read_timeout_usec_
Definition: httplib.h:1528
CPPHTTPLIB_IPV6_V6ONLY
#define CPPHTTPLIB_IPV6_V6ONLY
Definition: httplib.h:114
httplib::detail::scope_exit::release
void release()
Definition: httplib.h:418
httplib::Response::set_chunked_content_provider
void set_chunked_content_provider(const std::string &content_type, ContentProviderWithoutLength provider, ContentProviderResourceReleaser resource_releaser=nullptr)
Definition: httplib.h:5816
httplib::TemporaryRedirect_307
@ TemporaryRedirect_307
Definition: httplib.h:458
httplib::TaskQueue::shutdown
virtual void shutdown()=0
httplib::detail::RegexMatcher::match
bool match(Request &request) const override
Definition: httplib.h:6075
httplib::Server::Delete
Server & Delete(const std::string &pattern, Handler handler)
Definition: httplib.h:6143
httplib::get_bearer_token_auth
std::string get_bearer_token_auth(const Request &req)
Definition: httplib.h:2133
httplib::Client::set_socket_options
void set_socket_options(SocketOptions socket_options)
Definition: httplib.h:10137
httplib::detail::EncodingType
EncodingType
Definition: httplib.h:2353
CPPHTTPLIB_IDLE_INTERVAL_SECOND
#define CPPHTTPLIB_IDLE_INTERVAL_SECOND
Definition: httplib.h:70
httplib::detail::write_content_chunked
bool write_content_chunked(Stream &strm, const ContentProvider &content_provider, const T &is_shutting_down, U &compressor)
Definition: httplib.h:4641
httplib::Server::svr_sock_
std::atomic< socket_t > svr_sock_
Definition: httplib.h:1024
httplib::detail::scope_exit
Definition: httplib.h:404
httplib::Request::has_param
bool has_param(const std::string &key) const
Definition: httplib.h:5696
httplib::Request::body
std::string body
Definition: httplib.h:617
httplib::ServiceUnavailable_503
@ ServiceUnavailable_503
Definition: httplib.h:496
httplib::NonAuthoritativeInformation_203
@ NonAuthoritativeInformation_203
Definition: httplib.h:442
httplib::ClientImpl::is_socket_open
size_t is_socket_open() const
Definition: httplib.h:8710
httplib::Client::set_hostname_addr_map
void set_hostname_addr_map(std::map< std::string, std::string > addr_map)
Definition: httplib.h:10118
httplib::Server::Options
Server & Options(const std::string &pattern, Handler handler)
Definition: httplib.h:6155
INVALID_SOCKET
#define INVALID_SOCKET
Definition: httplib.h:228
ProsthesisInterface.values
values
Definition: ProsthesisInterface.py:190
httplib::detail::select_read
ssize_t select_read(socket_t sock, time_t sec, time_t usec)
Definition: httplib.h:3105
httplib::ClientImpl::basic_auth_username_
std::string basic_auth_username_
Definition: httplib.h:1532
httplib::ClientImpl::Options
Result Options(const std::string &path)
Definition: httplib.h:8669
httplib::ClientImpl::proxy_port_
int proxy_port_
Definition: httplib.h:1556
httplib::Result::value
const Response & value() const
Definition: httplib.h:1168
httplib::detail::SocketStream::is_readable
bool is_readable() const override
Definition: httplib.h:5876
detail
Definition: OpenCVUtil.cpp:128
httplib::PartialContent_206
@ PartialContent_206
Definition: httplib.h:445
httplib::Server::set_logger
Server & set_logger(Logger logger)
Definition: httplib.h:6235
httplib::MultipartFormData::content
std::string content
Definition: httplib.h:520
httplib::ClientImpl
Definition: httplib.h:1193
httplib::Server::keep_alive_max_count_
size_t keep_alive_max_count_
Definition: httplib.h:1025
httplib::Result::Result
Result(std::unique_ptr< Response > &&res, Error err, Headers &&request_headers=Headers{})
Definition: httplib.h:1160
httplib::detail::read_file
void read_file(const std::string &path, std::string &out)
Definition: httplib.h:2769
httplib::Server::set_write_timeout
Server & set_write_timeout(time_t sec, time_t usec=0)
Definition: httplib.h:6293
httplib::unused_306
@ unused_306
Definition: httplib.h:457
httplib::Server::set_tcp_nodelay
Server & set_tcp_nodelay(bool on)
Definition: httplib.h:6251
httplib::detail::write_multipart_ranges_data
bool write_multipart_ranges_data(Stream &strm, const Request &req, Response &res, const std::string &boundary, const std::string &content_type, size_t content_length, const T &is_shutting_down)
Definition: httplib.h:5281
httplib::Error::SSLPeerCouldBeClosed_
@ SSLPeerCouldBeClosed_
c
constexpr T c
Definition: UnscentedKalmanFilterTest.cpp:46
CPPHTTPLIB_TCP_NODELAY
#define CPPHTTPLIB_TCP_NODELAY
Definition: httplib.h:110
httplib::ImATeapot_418
@ ImATeapot_418
Definition: httplib.h:480
httplib::detail::is_multipart_boundary_chars_valid
bool is_multipart_boundary_chars_valid(const std::string &boundary)
Definition: httplib.h:5072
httplib::Result::get_request_header_value_u64
uint64_t get_request_header_value_u64(const std::string &key, uint64_t def=0, size_t id=0) const
Definition: httplib.h:2198
httplib::detail::mmap::is_open
bool is_open() const
Definition: httplib.h:3018
httplib::detail::make_multipart_ranges_data
void make_multipart_ranges_data(const Request &req, Response &res, const std::string &boundary, const std::string &content_type, size_t content_length, std::string &data)
Definition: httplib.h:5245
httplib::detail::find_content_type
std::string find_content_type(const std::string &path, const std::map< std::string, std::string > &user_data, const std::string &default_content_type)
Definition: httplib.h:3793
httplib::Server::set_keep_alive_max_count
Server & set_keep_alive_max_count(size_t count)
Definition: httplib.h:6277
httplib::Response::file_content_path_
std::string file_content_path_
Definition: httplib.h:720
httplib::MultipartFormData::content_type
std::string content_type
Definition: httplib.h:522
httplib::Locked_423
@ Locked_423
Definition: httplib.h:483
httplib::MultipartFormDataProvider::provider
ContentProviderWithoutLength provider
Definition: httplib.h:570
httplib::detail::compressor::~compressor
virtual ~compressor()=default
httplib::VariantAlsoNegotiates_506
@ VariantAlsoNegotiates_506
Definition: httplib.h:499
httplib::detail::parse_query_text
void parse_query_text(const std::string &s, Params &params)
Definition: httplib.h:4711
CPPHTTPLIB_THREAD_POOL_COUNT
#define CPPHTTPLIB_THREAD_POOL_COUNT
Definition: httplib.h:126
httplib
Definition: httplib.h:319
httplib::detail::stream_line_reader::getline
bool getline()
Definition: httplib.h:2884
httplib::Continue_100
@ Continue_100
Definition: httplib.h:433
httplib::Client::set_follow_location
void set_follow_location(bool on)
Definition: httplib.h:10168
httplib::Request::remote_port
int remote_port
Definition: httplib.h:620
httplib::Params
std::multimap< std::string, std::string > Params
Definition: httplib.h:510
httplib::detail::make_multipart_data_boundary
std::string make_multipart_data_boundary()
Definition: httplib.h:5068
httplib::NotModified_304
@ NotModified_304
Definition: httplib.h:455
httplib::detail::random_string
std::string random_string(size_t length)
Definition: httplib.h:5046
httplib::Client
Definition: httplib.h:1618
httplib::Request::is_multipart_form_data
bool is_multipart_form_data() const
Definition: httplib.h:5714
httplib::ContentReader::operator()
bool operator()(ContentReceiver receiver) const
Definition: httplib.h:601
httplib::ClientImpl::~ClientImpl
virtual ~ClientImpl()
Definition: httplib.h:7257
httplib::detail::write_response_line
ssize_t write_response_line(Stream &strm, int status)
Definition: httplib.h:4416
httplib::MultipartFormDataProviderItems
std::vector< MultipartFormDataProvider > MultipartFormDataProviderItems
Definition: httplib.h:574
httplib::detail::FileStat
Definition: httplib.h:2280
httplib::UnsupportedMediaType_415
@ UnsupportedMediaType_415
Definition: httplib.h:477
httplib::ClientImpl::copy_settings
void copy_settings(const ClientImpl &rhs)
Definition: httplib.h:7265
httplib::TaskQueue::TaskQueue
TaskQueue()=default
httplib::Request::is_chunked_content_provider_
bool is_chunked_content_provider_
Definition: httplib.h:662
httplib::ClientImpl::socket_mutex_
std::mutex socket_mutex_
Definition: httplib.h:1503
magic_enum::detail::n
constexpr auto n() noexcept
Definition: magic_enum.hpp:418
httplib::detail::SocketStream::is_writable
bool is_writable() const override
Definition: httplib.h:5880
httplib::Client::operator=
Client & operator=(Client &&)=default
httplib::MultiStatus_207
@ MultiStatus_207
Definition: httplib.h:446
httplib::detail::mmap
Definition: httplib.h:2485
httplib::detail::MultipartFormDataParser
Definition: httplib.h:4801
httplib::detail::case_ignore::to_lower
unsigned char to_lower(int c)
Definition: httplib.h:346
httplib::Unauthorized_401
@ Unauthorized_401
Definition: httplib.h:463
httplib::ClientImpl::Socket
Definition: httplib.h:1466
httplib::UnprocessableContent_422
@ UnprocessableContent_422
Definition: httplib.h:482
httplib::ThreadPool::ThreadPool
ThreadPool(size_t n, size_t mqr=0)
Definition: httplib.h:754
httplib::ClientImpl::send
bool send(Request &req, Response &res, Error &error)
Definition: httplib.h:7409
httplib::Server::stop
void stop()
Definition: httplib.h:6337
httplib::detail::process_client_socket
bool 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, std::function< bool(Stream &)> callback)
Definition: httplib.h:3350
httplib::hosted_at
void hosted_at(const std::string &hostname, std::vector< std::string > &addrs)
Definition: httplib.h:5604
httplib::Error::Unknown
@ Unknown
httplib::ContentReader::multipart_reader_
MultipartReader multipart_reader_
Definition: httplib.h:606
visionx::imrecman::ok
@ ok
Definition: ImageRecordingManagerInterface.ice:45
httplib::ClientImpl::keep_alive_
bool keep_alive_
Definition: httplib.h:1540
httplib::Created_201
@ Created_201
Definition: httplib.h:440
httplib::detail::PathParamsMatcher::match
bool match(Request &request) const override
Definition: httplib.h:6032
httplib::operator<<
std::ostream & operator<<(std::ostream &os, const Error &obj)
Definition: httplib.h:2192
httplib::detail::read_content
bool read_content(Stream &strm, T &x, size_t payload_max_length, int &status, Progress progress, ContentReceiverWithProgress receiver, bool decompress)
Definition: httplib.h:4375
httplib::Result::operator!=
bool operator!=(std::nullptr_t) const
Definition: httplib.h:1167
httplib::DataSink::DataSink
DataSink()
Definition: httplib.h:529
httplib::ThreadPool::enqueue
bool enqueue(std::function< void()> fn) override
Definition: httplib.h:765
httplib::Server::Expect100ContinueHandler
std::function< int(const Request &, Response &)> Expect100ContinueHandler
Definition: httplib.h:935
httplib::ClientImpl::follow_location_
bool follow_location_
Definition: httplib.h:1541
httplib::OK_200
@ OK_200
Definition: httplib.h:439
httplib::detail::get_multipart_ranges_data_length
size_t get_multipart_ranges_data_length(const Request &req, const std::string &boundary, const std::string &content_type, size_t content_length)
Definition: httplib.h:5261
httplib::Response::get_header_value_count
size_t get_header_value_count(const std::string &key) const
Definition: httplib.h:5750
httplib::MultipartFormDataProvider::name
std::string name
Definition: httplib.h:569
httplib::ClientImpl::Head
Result Head(const std::string &path)
Definition: httplib.h:8205
httplib::detail::has_header
bool has_header(const Headers &headers, const std::string &key)
Definition: httplib.h:4105
httplib::detail::read_socket
ssize_t read_socket(socket_t sock, void *ptr, size_t size, int flags)
Definition: httplib.h:3080
httplib::Request::path
std::string path
Definition: httplib.h:614
httplib::detail::parse_header
bool parse_header(const char *beg, const char *end, T fn)
Definition: httplib.h:4120
httplib::Request::progress
Progress progress
Definition: httplib.h:635
httplib::detail::create_socket
socket_t create_socket(const std::string &host, const std::string &ip, int port, int address_family, int socket_flags, bool tcp_nodelay, bool ipv6_v6only, SocketOptions socket_options, BindOrConnect bind_or_connect)
Definition: httplib.h:3388
httplib::detail::parse_query_text
void parse_query_text(const char *data, std::size_t size, Params &params)
Definition: httplib.h:4688
httplib::Server::listen
bool listen(const std::string &host, int port, int socket_flags=0)
Definition: httplib.h:6324
httplib::ClientImpl::bearer_token_auth_token_
std::string bearer_token_auth_token_
Definition: httplib.h:1534
httplib::DataSink::done_with_trailer
std::function< void(const Headers &trailer)> done_with_trailer
Definition: httplib.h:539
httplib::Request::headers
Headers headers
Definition: httplib.h:616
httplib::Server::Patch
Server & Patch(const std::string &pattern, Handler handler)
Definition: httplib.h:6131
httplib::detail::FileStat::is_dir
bool is_dir() const
Definition: httplib.h:2675
CPPHTTPLIB_CLIENT_WRITE_TIMEOUT_SECOND
#define CPPHTTPLIB_CLIENT_WRITE_TIMEOUT_SECOND
Definition: httplib.h:62
httplib::Server::set_header_writer
Server & set_header_writer(std::function< ssize_t(Stream &, Headers &)> const &writer)
Definition: httplib.h:6271
httplib::Response::version
std::string version
Definition: httplib.h:667
httplib::Result::has_request_header
bool has_request_header(const std::string &key) const
Definition: httplib.h:5837
httplib::Request::set_header
void set_header(const std::string &key, const std::string &val)
Definition: httplib.h:5689
httplib::Client::set_read_timeout
void set_read_timeout(time_t sec, time_t usec=0)
Definition: httplib.h:10145
httplib::Progress
std::function< bool(uint64_t current, uint64_t total)> Progress
Definition: httplib.h:513
CPPHTTPLIB_VERSION
#define CPPHTTPLIB_VERSION
Definition: httplib.h:11
httplib::DataSink::write
std::function< bool(const char *data, size_t data_len)> write
Definition: httplib.h:536
httplib::MultipartFormData::filename
std::string filename
Definition: httplib.h:521
httplib::detail::send_socket
ssize_t send_socket(socket_t sock, const void *ptr, size_t size, int flags)
Definition: httplib.h:3092
httplib::detail::encode_url
std::string encode_url(const std::string &s)
Definition: httplib.h:2700
CPPHTTPLIB_CLIENT_READ_TIMEOUT_USECOND
#define CPPHTTPLIB_CLIENT_READ_TIMEOUT_USECOND
Definition: httplib.h:58
httplib::ClientImpl::host_and_port_
const std::string host_and_port_
Definition: httplib.h:1499
httplib::Error::ProxyConnection
@ ProxyConnection
CPPHTTPLIB_RECV_FLAGS
#define CPPHTTPLIB_RECV_FLAGS
Definition: httplib.h:133
httplib::detail::duration_to_sec_and_usec
void duration_to_sec_and_usec(const T &duration, U callback)
Definition: httplib.h:2007
httplib::Request::get_header_value
std::string get_header_value(const std::string &key, const char *def="", size_t id=0) const
Definition: httplib.h:5679
httplib::BadGateway_502
@ BadGateway_502
Definition: httplib.h:495
httplib::detail::parse_range_header
bool parse_range_header(const std::string &s, Ranges &ranges)
Definition: httplib.h:4753
httplib::Client::set_default_headers
void set_default_headers(Headers headers)
Definition: httplib.h:10122
armarx::armem::server::ltm::mongodb::util::store
void store(const mongocxx::database &db, const armem::wm::Memory &m)
Definition: operations.cpp:260
httplib::Result::get_request_header_value
std::string get_request_header_value(const std::string &key, const char *def="", size_t id=0) const
Definition: httplib.h:5841
httplib::Stream::get_local_ip_and_port
virtual void get_local_ip_and_port(std::string &ip, int &port) const =0
httplib::Request::content_provider_
ContentProvider content_provider_
Definition: httplib.h:661
httplib::Client::Options
Result Options(const std::string &path)
Definition: httplib.h:10094
httplib::detail::divide
void divide(const char *data, std::size_t size, char d, std::function< void(const char *, std::size_t, const char *, std::size_t)> fn)
Definition: httplib.h:2811
httplib::MisdirectedRequest_421
@ MisdirectedRequest_421
Definition: httplib.h:481
httplib::Client::set_header_writer
void set_header_writer(std::function< ssize_t(Stream &, Headers &)> const &writer)
Definition: httplib.h:10126
httplib::Error::Read
@ Read
httplib::detail::split
void split(const char *b, const char *e, char d, size_t m, std::function< void(const char *, const char *)> fn)
Definition: httplib.h:2836
armarx::status
status
Definition: FiniteStateMachine.h:244
httplib::detail::MultipartFormDataParser::is_valid
bool is_valid() const
Definition: httplib.h:4811
httplib::ClientImpl::set_logger
void set_logger(Logger logger)
Definition: httplib.h:8862
httplib::ClientImpl::Delete
Result Delete(const std::string &path)
Definition: httplib.h:8593
httplib::detail::SocketStream::read
ssize_t read(char *ptr, size_t size) override
Definition: httplib.h:5885
httplib::ClientImpl::client_key_path_
std::string client_key_path_
Definition: httplib.h:1523
httplib::detail::MatcherBase
Definition: httplib.h:848
httplib::detail::case_ignore::hash
Definition: httplib.h:383
httplib::Request::method
std::string method
Definition: httplib.h:613
httplib::detail::parse_disposition_params
void parse_disposition_params(const std::string &s, Params &params)
Definition: httplib.h:4726
httplib::Client::is_socket_open
size_t is_socket_open() const
Definition: httplib.h:10113
httplib::Client::set_write_timeout
void set_write_timeout(time_t sec, time_t usec=0)
Definition: httplib.h:10149
httplib::Server::wait_until_ready
void wait_until_ready() const
Definition: httplib.h:6331
httplib::PermanentRedirect_308
@ PermanentRedirect_308
Definition: httplib.h:459
httplib::detail::mmap::size
size_t size() const
Definition: httplib.h:3022
armarx::ctrlutil::a
double a(double t, double a0, double j)
Definition: CtrlUtil.h:45
httplib::MultipartFormDataProvider::content_type
std::string content_type
Definition: httplib.h:572
httplib::ExpectationFailed_417
@ ExpectationFailed_417
Definition: httplib.h:479
httplib::detail::PathParamsMatcher::PathParamsMatcher
PathParamsMatcher(const std::string &pattern)
Definition: httplib.h:5984
httplib::Client::Client
Client(const std::string &scheme_host_port)
Definition: httplib.h:9657
httplib::detail::trim_double_quotes_copy
std::string trim_double_quotes_copy(const std::string &s)
Definition: httplib.h:2803
cxxopts::value
std::shared_ptr< Value > value()
Definition: cxxopts.hpp:855
httplib::Client::set_interface
void set_interface(const std::string &intf)
Definition: httplib.h:10178
httplib::ClientImpl::port_
const int port_
Definition: httplib.h:1498
httplib::detail::base64_encode
std::string base64_encode(const std::string &in)
Definition: httplib.h:2594
httplib::detail::read_content_without_length
bool read_content_without_length(Stream &strm, ContentReceiverWithProgress out)
Definition: httplib.h:4240
CPPHTTPLIB_SERVER_WRITE_TIMEOUT_SECOND
#define CPPHTTPLIB_SERVER_WRITE_TIMEOUT_SECOND
Definition: httplib.h:46
httplib::ClientImpl::Socket::is_open
bool is_open() const
Definition: httplib.h:1472
httplib::detail::compressor::Callback
std::function< bool(const char *data, size_t data_len)> Callback
Definition: httplib.h:2381
httplib::ClientImpl::stop
void stop()
Definition: httplib.h:8683
httplib::detail::SocketStream::~SocketStream
~SocketStream() override
httplib::detail::stream_line_reader::ptr
const char * ptr() const
Definition: httplib.h:2863
Response::status
status_t status
Definition: Response.h:106
CPPHTTPLIB_IDLE_INTERVAL_USECOND
#define CPPHTTPLIB_IDLE_INTERVAL_USECOND
Definition: httplib.h:77
httplib::ClientImpl::set_socket_options
void set_socket_options(SocketOptions socket_options)
Definition: httplib.h:8778
httplib::detail::case_ignore::equal
bool equal(const std::string &a, const std::string &b)
Definition: httplib.h:370
httplib::ClientImpl::set_compress
void set_compress(bool on)
Definition: httplib.h:8782
httplib::ClientImpl::set_address_family
void set_address_family(int family)
Definition: httplib.h:8770
httplib::detail::is_valid_path
bool is_valid_path(const std::string &path)
Definition: httplib.h:2622
copy
Use of this software is granted under one of the following two to be chosen freely by the user Boost Software License Version Marcin Kalicinski Permission is hereby free of to any person or organization obtaining a copy of the software and accompanying documentation covered by this and transmit the and to prepare derivative works of the and to permit third parties to whom the Software is furnished to do all subject to the including the above license this restriction and the following must be included in all copies of the in whole or in and all derivative works of the unless such copies or derivative works are solely in the form of machine executable object code generated by a source language processor THE SOFTWARE IS PROVIDED AS WITHOUT WARRANTY OF ANY EXPRESS OR INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF FITNESS FOR A PARTICULAR TITLE AND NON INFRINGEMENT IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR OTHER WHETHER IN TORT OR ARISING OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE The MIT Marcin Kalicinski Permission is hereby free of to any person obtaining a copy of this software and associated documentation to deal in the Software without including without limitation the rights to copy
Definition: license.txt:39
httplib::detail::keep_alive
bool keep_alive(const std::atomic< socket_t > &svr_sock, socket_t sock, time_t keep_alive_timeout_sec)
Definition: httplib.h:3283
httplib::Server::set_mount_point
bool set_mount_point(const std::string &mount_point, const std::string &dir, Headers headers=Headers())
Definition: httplib.h:6165
httplib::ClientImpl::shutdown_socket
void shutdown_socket(Socket &socket) const
Definition: httplib.h:7349
httplib::detail::serialize_multipart_formdata_item_begin
std::string serialize_multipart_formdata_item_begin(const T &item, const std::string &boundary)
Definition: httplib.h:5086
httplib::Response::set_content_provider
void set_content_provider(size_t length, const std::string &content_type, ContentProvider provider, ContentProviderResourceReleaser resource_releaser=nullptr)
Definition: httplib.h:5796
httplib::detail::BufferStream::socket
socket_t socket() const override
Definition: httplib.h:5980
httplib::Error::ConnectionTimeout
@ ConnectionTimeout
if
if(!yyvaluep)
Definition: Grammar.cpp:645
httplib::BadRequest_400
@ BadRequest_400
Definition: httplib.h:462
httplib::Client::stop
void stop()
Definition: httplib.h:10107
httplib::ClientImpl::set_keep_alive
void set_keep_alive(bool on)
Definition: httplib.h:8750
httplib::Error::Connection
@ Connection
httplib::MultipartFormData
Definition: httplib.h:518
httplib::Client::is_valid
bool is_valid() const
Definition: httplib.h:9719
httplib::Server::ExceptionHandler
std::function< void(const Request &, Response &, std::exception_ptr ep)> ExceptionHandler
Definition: httplib.h:922
httplib::ClientImpl::logger_
Logger logger_
Definition: httplib.h:1579
httplib::FailedDependency_424
@ FailedDependency_424
Definition: httplib.h:484
httplib::Accepted_202
@ Accepted_202
Definition: httplib.h:441
httplib::detail::redirect
bool redirect(T &cli, Request &req, Response &res, const std::string &path, const std::string &location, Error &error)
Definition: httplib.h:4650
armarx::flush
const LogSender::manipulator flush
Definition: LogSender.h:251
httplib::detail::mmap::data
const char * data() const
Definition: httplib.h:3024
httplib::detail::BufferStream::BufferStream
BufferStream()=default
data
uint8_t data[1]
Definition: EtherCATFrame.h:68
httplib::detail::stream_line_reader::size
size_t size() const
Definition: httplib.h:2871
CPPHTTPLIB_HEADER_MAX_LENGTH
#define CPPHTTPLIB_HEADER_MAX_LENGTH
Definition: httplib.h:86
httplib::ClientImpl::set_write_timeout
void set_write_timeout(time_t sec, time_t usec=0)
Definition: httplib.h:8727
httplib::Error::ExceedRedirectCount
@ ExceedRedirectCount
httplib::Client::~Client
~Client()
httplib::Server::set_address_family
Server & set_address_family(int family)
Definition: httplib.h:6246
httplib::detail::FileStat::is_file
bool is_file() const
Definition: httplib.h:2672
httplib::Server::set_keep_alive_timeout
Server & set_keep_alive_timeout(time_t sec)
Definition: httplib.h:6282
httplib::ClientImpl::proxy_host_
std::string proxy_host_
Definition: httplib.h:1555
Stream
Definition: StreamProviderI.cpp:38
httplib::ClientImpl::set_url_encode
void set_url_encode(bool on)
Definition: httplib.h:8754
httplib::Server::set_expect_100_continue_handler
Server & set_expect_100_continue_handler(Expect100ContinueHandler handler)
Definition: httplib.h:6241
httplib::NotExtended_510
@ NotExtended_510
Definition: httplib.h:502
httplib::detail::parse_www_authenticate
bool parse_www_authenticate(const Response &res, std::map< std::string, std::string > &auth, bool is_proxy)
Definition: httplib.h:5548
httplib::Client::Get
Result Get(const std::string &path)
Definition: httplib.h:9723
httplib::detail::compressor
Definition: httplib.h:2377
httplib::detail::serialize_multipart_formdata_finish
std::string serialize_multipart_formdata_finish(const std::string &boundary)
Definition: httplib.h:5105
httplib::SwitchingProtocol_101
@ SwitchingProtocol_101
Definition: httplib.h:434
httplib::Server::set_read_timeout
Server & set_read_timeout(time_t sec, time_t usec=0)
Definition: httplib.h:6287
httplib::Response::has_header
bool has_header(const std::string &key) const
Definition: httplib.h:5740
socket_t
int socket_t
Definition: httplib.h:226
httplib::ClientImpl::Post
Result Post(const std::string &path)
Definition: httplib.h:8219
httplib::to_string
std::string to_string(Error error)
Definition: httplib.h:2166
armarx::read
void read(auto &eigen, auto *table)
Definition: FTSensorCalibrationGuiWidgetController.cpp:503
enabled
std::atomic< bool > * enabled
Definition: RemoteGuiWidgetController.cpp:75
httplib::detail::stream_line_reader::end_with_crlf
bool end_with_crlf() const
Definition: httplib.h:2879
httplib::detail::skip_content_with_length
void skip_content_with_length(Stream &strm, uint64_t len)
Definition: httplib.h:4229
httplib::Server::Get
Server & Get(const std::string &pattern, Handler handler)
Definition: httplib.h:6102
httplib::detail::decompressor::decompress
virtual bool decompress(const char *data, size_t data_length, Callback callback)=0
httplib::Stream::~Stream
virtual ~Stream()=default
httplib::detail::process_server_socket
bool process_server_socket(const std::atomic< socket_t > &svr_sock, 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)
Definition: httplib.h:3336
httplib::detail::escape_abstract_namespace_unix_domain
std::string escape_abstract_namespace_unix_domain(const std::string &s)
Definition: httplib.h:3368
httplib::Response::reason
std::string reason
Definition: httplib.h:669
httplib::detail::split
void split(const char *b, const char *e, char d, std::function< void(const char *, const char *)> fn)
Definition: httplib.h:2831
httplib::detail::get_remote_ip_and_port
void get_remote_ip_and_port(socket_t sock, std::string &ip, int &port)
Definition: httplib.h:3740
httplib::NotImplemented_501
@ NotImplemented_501
Definition: httplib.h:494
httplib::detail::shutdown_socket
int shutdown_socket(socket_t sock)
Definition: httplib.h:3360
httplib::Client::set_address_family
void set_address_family(int family)
Definition: httplib.h:10131
httplib::MultipartFormDataProvider::filename
std::string filename
Definition: httplib.h:571
CPPHTTPLIB_SERVER_READ_TIMEOUT_SECOND
#define CPPHTTPLIB_SERVER_READ_TIMEOUT_SECOND
Definition: httplib.h:38
httplib::ClientImpl::ipv6_v6only_
bool ipv6_v6only_
Definition: httplib.h:1547
httplib::Server::listen_after_bind
bool listen_after_bind()
Definition: httplib.h:6322
httplib::detail::decompressor
Definition: httplib.h:2386
httplib::Server::write_timeout_sec_
time_t write_timeout_sec_
Definition: httplib.h:1029
httplib::Client::set_basic_auth
void set_basic_auth(const std::string &username, const std::string &password)
Definition: httplib.h:10153
httplib::ClientImpl::shutdown_ssl
virtual void shutdown_ssl(Socket &socket, bool shutdown_gracefully)
Definition: httplib.h:7341
httplib::Server::Put
Server & Put(const std::string &pattern, Handler handler)
Definition: httplib.h:6119
httplib::detail::scope_exit::~scope_exit
~scope_exit()
Definition: httplib.h:414
httplib::Server::set_payload_max_length
Server & set_payload_max_length(size_t length)
Definition: httplib.h:6305
httplib::MultipartFormDataProvider
Definition: httplib.h:568
httplib::ThreadPool::worker
friend struct worker
Definition: httplib.h:824
httplib::UpgradeRequired_426
@ UpgradeRequired_426
Definition: httplib.h:486
max
T max(T t1, T t2)
Definition: gdiam.h:51
httplib::Client::set_bearer_token_auth
void set_bearer_token_auth(const std::string &token)
Definition: httplib.h:10157
httplib::Request::get_header_value_count
size_t get_header_value_count(const std::string &key) const
Definition: httplib.h:5684
httplib::SocketOptions
std::function< void(socket_t sock)> SocketOptions
Definition: httplib.h:838
httplib::detail::SocketStream::get_remote_ip_and_port
void get_remote_ip_and_port(std::string &ip, int &port) const override
Definition: httplib.h:5942
httplib::Gone_410
@ Gone_410
Definition: httplib.h:472
httplib::ClientImpl::socket
socket_t socket() const
Definition: httplib.h:8715
httplib::Response::set_header
void set_header(const std::string &key, const std::string &val)
Definition: httplib.h:5755
httplib::detail::decompressor::Callback
std::function< bool(const char *data, size_t data_len)> Callback
Definition: httplib.h:2392
httplib::SeeOther_303
@ SeeOther_303
Definition: httplib.h:454
CPPHTTPLIB_SERVER_READ_TIMEOUT_USECOND
#define CPPHTTPLIB_SERVER_READ_TIMEOUT_USECOND
Definition: httplib.h:42
httplib::ClientImpl::Get
Result Get(const std::string &path)
Definition: httplib.h:8086
httplib::Result::error
Error error() const
Definition: httplib.h:1176
httplib::detail::close_socket
int close_socket(socket_t sock)
Definition: httplib.h:3059
httplib::Server::write_timeout_usec_
time_t write_timeout_usec_
Definition: httplib.h:1030
httplib::MultipartFormDataMap
std::multimap< std::string, MultipartFormData > MultipartFormDataMap
Definition: httplib.h:525
httplib::detail::BufferStream::is_writable
bool is_writable() const override
Definition: httplib.h:5957
httplib::Response::set_file_content
void set_file_content(const std::string &path, const std::string &content_type)
Definition: httplib.h:5826
httplib::DataSink::operator=
DataSink & operator=(const DataSink &)=delete
CPPHTTPLIB_REQUEST_URI_MAX_LENGTH
#define CPPHTTPLIB_REQUEST_URI_MAX_LENGTH
Definition: httplib.h:82
httplib::Server::set_exception_handler
Server & set_exception_handler(ExceptionHandler handler)
Definition: httplib.h:6220
httplib::ClientImpl::read_timeout_sec_
time_t read_timeout_sec_
Definition: httplib.h:1527
httplib::detail::BufferStream
Definition: httplib.h:2357
httplib::detail::unescape_abstract_namespace_unix_domain
std::string unescape_abstract_namespace_unix_domain(const std::string &s)
Definition: httplib.h:3378
httplib::ClientImpl::set_connection_timeout
void set_connection_timeout(time_t sec, time_t usec=0)
Definition: httplib.h:8717
httplib::ThreadPool::shutdown
void shutdown() override
Definition: httplib.h:778
httplib::detail::process_multipart_ranges_data
bool process_multipart_ranges_data(const Request &req, const std::string &boundary, const std::string &content_type, size_t content_length, SToken stoken, CToken ctoken, Content content)
Definition: httplib.h:5209
httplib::Response::Response
Response()=default
httplib::detail::process_server_socket_core
bool process_server_socket_core(const std::atomic< socket_t > &svr_sock, socket_t sock, size_t keep_alive_max_count, time_t keep_alive_timeout_sec, T callback)
Definition: httplib.h:3318
httplib::Request::local_addr
std::string local_addr
Definition: httplib.h:621
CPPHTTPLIB_PAYLOAD_MAX_LENGTH
#define CPPHTTPLIB_PAYLOAD_MAX_LENGTH
Definition: httplib.h:98
httplib::Range
std::pair< ssize_t, ssize_t > Range
Definition: httplib.h:609
CPPHTTPLIB_CLIENT_WRITE_TIMEOUT_USECOND
#define CPPHTTPLIB_CLIENT_WRITE_TIMEOUT_USECOND
Definition: httplib.h:66
httplib::Client::set_logger
void set_logger(Logger logger)
Definition: httplib.h:10214
httplib::detail::SocketStream::SocketStream
SocketStream(socket_t sock, time_t read_timeout_sec, time_t read_timeout_usec, time_t write_timeout_sec, time_t write_timeout_usec)
Definition: httplib.h:5865
CPPHTTPLIB_REDIRECT_MAX_COUNT
#define CPPHTTPLIB_REDIRECT_MAX_COUNT
Definition: httplib.h:90
httplib::ClientImpl::set_follow_location
void set_follow_location(bool on)
Definition: httplib.h:8752
httplib::detail::bind_ip_address
bool bind_ip_address(socket_t sock, const std::string &host)
Definition: httplib.h:3558
httplib::detail::file_extension
std::string file_extension(const std::string &path)
Definition: httplib.h:2778
CPPHTTPLIB_CLIENT_READ_TIMEOUT_SECOND
#define CPPHTTPLIB_CLIENT_READ_TIMEOUT_SECOND
Definition: httplib.h:54
httplib::TooEarly_425
@ TooEarly_425
Definition: httplib.h:485
httplib::Server::set_socket_options
Server & set_socket_options(SocketOptions socket_options)
Definition: httplib.h:6261
httplib::Result::operator*
const Response & operator*() const
Definition: httplib.h:1170
httplib::detail::write_content
bool write_content(Stream &strm, const ContentProvider &content_provider, size_t offset, size_t length, T is_shutting_down, Error &error)
Definition: httplib.h:4455
httplib::DataSink::done
std::function< void()> done
Definition: httplib.h:538
httplib::Client::set_connection_timeout
void set_connection_timeout(time_t sec, time_t usec=0)
Definition: httplib.h:10141
httplib::ContentReceiver
std::function< bool(const char *data, size_t data_length)> ContentReceiver
Definition: httplib.h:581
httplib::StatusCode
StatusCode
Definition: httplib.h:431
httplib::detail::BufferStream::get_buffer
const std::string & get_buffer() const
Definition: httplib.h:5982
httplib::Server::set_idle_interval
Server & set_idle_interval(time_t sec, time_t usec=0)
Definition: httplib.h:6299
httplib::Response::operator=
Response & operator=(const Response &)=default
httplib::DataSink::is_writable
std::function< bool()> is_writable
Definition: httplib.h:537
httplib::detail::MatcherBase::match
virtual bool match(Request &request) const =0
httplib::Server::HandlerWithContentReader
std::function< void(const Request &, Response &, const ContentReader &content_reader)> HandlerWithContentReader
Definition: httplib.h:932
httplib::detail::decode_url
std::string decode_url(const std::string &s, bool convert_plus_to_space)
Definition: httplib.h:2732
httplib::Result::operator->
const Response * operator->() const
Definition: httplib.h:1172
httplib::Request::get_param_value
std::string get_param_value(const std::string &key, size_t id=0) const
Definition: httplib.h:5700
httplib::detail::get_range_offset_and_length
std::pair< size_t, size_t > get_range_offset_and_length(Range r, size_t content_length)
Definition: httplib.h:5185
httplib::Request::remote_addr
std::string remote_addr
Definition: httplib.h:619
httplib::detail::get_header_value
const char * get_header_value(const Headers &headers, const std::string &key, const char *def, size_t id)
Definition: httplib.h:4109
httplib::ClientImpl::interface_
std::string interface_
Definition: httplib.h:1553
httplib::detail::encoding_type
EncodingType encoding_type(const Request &req, const Response &res)
Definition: httplib.h:3877
httplib::detail::decompressor::is_valid
virtual bool is_valid() const =0
httplib::LengthRequired_411
@ LengthRequired_411
Definition: httplib.h:473
httplib::Server::set_error_handler
Server & set_error_handler(ErrorHandlerFunc &&handler)
Definition: httplib.h:965
httplib::Request::path_params
std::unordered_map< std::string, std::string > path_params
Definition: httplib.h:630
CPPHTTPLIB_SEND_FLAGS
#define CPPHTTPLIB_SEND_FLAGS
Definition: httplib.h:137
httplib::detail::BufferStream::is_readable
bool is_readable() const override
Definition: httplib.h:5955
httplib::ProxyAuthenticationRequired_407
@ ProxyAuthenticationRequired_407
Definition: httplib.h:469
httplib::detail::prepare_content_receiver
bool prepare_content_receiver(T &x, int &status, ContentReceiverWithProgress receiver, bool decompress, U callback)
Definition: httplib.h:4327
httplib::detail::write_headers
ssize_t write_headers(Stream &strm, const Headers &headers)
Definition: httplib.h:4425
armarx::ctrlutil::v
double v(double t, double v0, double a0, double j)
Definition: CtrlUtil.h:39
httplib::Response::set_content
void set_content(const char *s, size_t n, const std::string &content_type)
Definition: httplib.h:5773
httplib::detail::MultipartFormDataParser::set_boundary
void set_boundary(std::string &&boundary)
Definition: httplib.h:4805
httplib::IMUsed_226
@ IMUsed_226
Definition: httplib.h:448
httplib::detail::BufferStream::read
ssize_t read(char *ptr, size_t size) override
Definition: httplib.h:5959
httplib::detail::stream_line_reader
Definition: httplib.h:2466
httplib::Server::HandlerWithResponse
std::function< HandlerResponse(const Request &, Response &)> HandlerWithResponse
Definition: httplib.h:929
httplib::ClientImpl::address_family_
int address_family_
Definition: httplib.h:1545
httplib::Server::set_base_dir
bool set_base_dir(const std::string &dir, const std::string &mount_point=std::string())
Definition: httplib.h:6160
httplib::TooManyRequests_429
@ TooManyRequests_429
Definition: httplib.h:488
httplib::Server::read_timeout_usec_
time_t read_timeout_usec_
Definition: httplib.h:1028
httplib::detail::nocompressor
Definition: httplib.h:2397
httplib::detail::BufferStream::get_local_ip_and_port
void get_local_ip_and_port(std::string &ip, int &port) const override
Definition: httplib.h:5977
httplib::detail::is_chunked_transfer_encoding
bool is_chunked_transfer_encoding(const Headers &headers)
Definition: httplib.h:4321
httplib::detail::is_socket_alive
bool is_socket_alive(socket_t sock)
Definition: httplib.h:3218
httplib::detail::SocketStream::write
ssize_t write(const char *ptr, size_t size) override
Definition: httplib.h:5931
httplib::ClientImpl::host_
const std::string host_
Definition: httplib.h:1497
httplib::ContentReader::MultipartReader
std::function< bool(MultipartContentHeader header, ContentReceiver receiver)> MultipartReader
Definition: httplib.h:590
httplib::detail::from_i_to_hex
std::string from_i_to_hex(size_t n)
Definition: httplib.h:2550
httplib::detail::expect_content
bool expect_content(const Request &req)
Definition: httplib.h:5295
httplib::Match
std::smatch Match
Definition: httplib.h:511
Response
Definition: Response.h:36
std
Definition: Application.h:66
httplib::ClientImpl::create_and_connect_socket
virtual bool create_and_connect_socket(Socket &socket, Error &error)
Definition: httplib.h:7333
httplib::ClientImpl::basic_auth_password_
std::string basic_auth_password_
Definition: httplib.h:1533
httplib::Stream::is_readable
virtual bool is_readable() const =0
httplib::ClientImpl::addr_map_
std::map< std::string, std::string > addr_map_
Definition: httplib.h:1512
httplib::Client::host
std::string host() const
Definition: httplib.h:10109
httplib::detail::make_unique
std::enable_if< std::is_array< T >::value, std::unique_ptr< T > >::type make_unique(std::size_t n)
Definition: httplib.h:339
httplib::detail::RegexMatcher
Performs std::regex_match on request path and stores the result in Request::matches.
Definition: httplib.h:903
httplib::ThreadPool
Definition: httplib.h:752
magic_enum::detail::find
constexpr std::size_t find(string_view str, char_type c) noexcept
Definition: magic_enum.hpp:309
httplib::NoContent_204
@ NoContent_204
Definition: httplib.h:443
httplib::ClientImpl::tcp_nodelay_
bool tcp_nodelay_
Definition: httplib.h:1546
httplib::detail::BufferStream::get_remote_ip_and_port
void get_remote_ip_and_port(std::string &ip, int &port) const override
Definition: httplib.h:5974
httplib::ClientImpl::Put
Result Put(const std::string &path)
Definition: httplib.h:8364
httplib::default_socket_options
void default_socket_options(socket_t sock)
Definition: httplib.h:2039
httplib::ClientImpl::port
int port() const
Definition: httplib.h:8708
httplib::detail::SocketStream::get_local_ip_and_port
void get_local_ip_and_port(std::string &ip, int &port) const override
Definition: httplib.h:5947
httplib::MultipleChoices_300
@ MultipleChoices_300
Definition: httplib.h:451
httplib::detail::to_utf8
size_t to_utf8(int code, char *buff)
Definition: httplib.h:2560
httplib::Server::Post
Server & Post(const std::string &pattern, Handler handler)
Definition: httplib.h:6107
httplib::Error::SSLLoadingCerts
@ SSLLoadingCerts
httplib::Server::HandlerResponse::Unhandled
@ Unhandled
httplib::ClientImpl::connection_timeout_usec_
time_t connection_timeout_usec_
Definition: httplib.h:1526
httplib::detail::has_crlf
bool has_crlf(const std::string &s)
Definition: httplib.h:5304
httplib::detail::MultipartFormDataParser::parse
bool parse(const char *buf, size_t n, const ContentReceiver &content_callback, const MultipartContentHeader &header_callback)
Definition: httplib.h:4813
httplib::detail::read_content_with_length
bool read_content_with_length(Stream &strm, uint64_t len, Progress progress, ContentReceiverWithProgress out)
Definition: httplib.h:4207
httplib::Server::Server
Server()
Definition: httplib.h:6083
httplib::ClientImpl::url_encode_
bool url_encode_
Definition: httplib.h:1543
httplib::Server::HandlerResponse::Handled
@ Handled
CPPHTTPLIB_SERVER_WRITE_TIMEOUT_USECOND
#define CPPHTTPLIB_SERVER_WRITE_TIMEOUT_USECOND
Definition: httplib.h:50
httplib::ContentReader
Definition: httplib.h:586
httplib::detail::can_compress_content_type
bool can_compress_content_type(const std::string &content_type)
Definition: httplib.h:3858
httplib::Server::Handler
std::function< void(const Request &, Response &)> Handler
Definition: httplib.h:919
httplib::ClientImpl::set_tcp_nodelay
void set_tcp_nodelay(bool on)
Definition: httplib.h:8774
httplib::PreconditionFailed_412
@ PreconditionFailed_412
Definition: httplib.h:474
httplib::Client::Head
Result Head(const std::string &path)
Definition: httplib.h:9793
httplib::Server::bind_to_any_port
int bind_to_any_port(const std::string &host, int socket_flags=0)
Definition: httplib.h:6316
httplib::Server::new_task_queue
std::function< TaskQueue *(void)> new_task_queue
Definition: httplib.h:1015
httplib::ClientImpl::Socket::sock
socket_t sock
Definition: httplib.h:1467
httplib::Request::get_file_value
MultipartFormData get_file_value(const std::string &key) const
Definition: httplib.h:5723
httplib::detail::write_data
bool write_data(Stream &strm, const char *d, size_t l)
Definition: httplib.h:4444
httplib::detail::mmap::close
void close()
Definition: httplib.h:3028
httplib::Result::value
Response & value()
Definition: httplib.h:1169
httplib::Stream::read
virtual ssize_t read(char *ptr, size_t size)=0
httplib::MultipartContentHeader
std::function< bool(const MultipartFormData &file)> MultipartContentHeader
Definition: httplib.h:584
CPPHTTPLIB_KEEPALIVE_TIMEOUT_SECOND
#define CPPHTTPLIB_KEEPALIVE_TIMEOUT_SECOND
Definition: httplib.h:18
httplib::DataSink::os
std::ostream os
Definition: httplib.h:540
httplib::Result::operator->
Response * operator->()
Definition: httplib.h:1173
httplib::detail::parse_multipart_boundary
bool parse_multipart_boundary(const std::string &content_type, std::string &boundary)
Definition: httplib.h:4715
httplib::Processing_102
@ Processing_102
Definition: httplib.h:435
httplib::Server::is_running
bool is_running() const
Definition: httplib.h:6329
httplib::detail::stream_line_reader::stream_line_reader
stream_line_reader(Stream &strm, char *fixed_buffer, size_t fixed_buffer_size)
Definition: httplib.h:2858
httplib::NetworkAuthenticationRequired_511
@ NetworkAuthenticationRequired_511
Definition: httplib.h:503
httplib::Response::content_provider_
ContentProvider content_provider_
Definition: httplib.h:716
httplib::MultipartFormDataItems
std::vector< MultipartFormData > MultipartFormDataItems
Definition: httplib.h:524
armarx::aron::write
requires data::isWriter< WriterT > void write(WriterT &aron_w, const Eigen::Matrix< EigenT, rows, cols, options > &input, typename WriterT::ReturnType &ret, const armarx::aron::Path &aron_p=armarx::aron::Path())
Definition: eigen.h:138
httplib::Server::set_post_routing_handler
Server & set_post_routing_handler(Handler handler)
Definition: httplib.h:6230
httplib::detail::trim_copy
std::string trim_copy(const std::string &s)
Definition: httplib.h:2798
httplib::AlreadyReported_208
@ AlreadyReported_208
Definition: httplib.h:447
httplib::detail::make_content_range_header_field
std::string make_content_range_header_field(const std::pair< size_t, size_t > &offset_and_length, size_t content_length)
Definition: httplib.h:5194
httplib::ContentProviderWithoutLength
std::function< bool(size_t offset, DataSink &sink)> ContentProviderWithoutLength
Definition: httplib.h:564
httplib::Result::operator==
bool operator==(std::nullptr_t) const
Definition: httplib.h:1166
httplib::Forbidden_403
@ Forbidden_403
Definition: httplib.h:465
httplib::detail::ContentProviderAdapter::ContentProviderAdapter
ContentProviderAdapter(ContentProviderWithoutLength &&content_provider)
Definition: httplib.h:5583
httplib::ClientImpl::connection_timeout_sec_
time_t connection_timeout_sec_
Definition: httplib.h:1525
httplib::TaskQueue
Definition: httplib.h:741
httplib::detail::mmap::~mmap
~mmap()
Definition: httplib.h:2934
httplib::detail::RegexMatcher::RegexMatcher
RegexMatcher(const std::string &pattern)
Definition: httplib.h:905
httplib::ClientImpl::socket_requests_are_from_thread_
std::thread::id socket_requests_are_from_thread_
Definition: httplib.h:1508
httplib::ContentProviderResourceReleaser
std::function< void(bool success)> ContentProviderResourceReleaser
Definition: httplib.h:566
httplib::detail::nocompressor::compress
bool compress(const char *data, size_t data_length, bool, Callback callback) override
Definition: httplib.h:3900
distance
double distance(const Point &a, const Point &b)
Definition: point.hpp:95
httplib::detail::ContentProviderAdapter
Definition: httplib.h:5581
httplib::ClientImpl::compress_
bool compress_
Definition: httplib.h:1550
magic_enum::detail::is_valid
constexpr bool is_valid() noexcept
Definition: magic_enum.hpp:592
httplib::ClientImpl::set_proxy_bearer_token_auth
void set_proxy_bearer_token_auth(const std::string &token)
Definition: httplib.h:8801
httplib::Request::target
std::string target
Definition: httplib.h:626
httplib::detail::trim
std::pair< size_t, size_t > trim(const char *b, const char *e, size_t left, size_t right)
Definition: httplib.h:2787
httplib::Request::has_file
bool has_file(const std::string &key) const
Definition: httplib.h:5719
armarx::view_selection::skills::direction::state::left
state::Type left(state::Type previous)
Definition: LookDirection.cpp:258
httplib::Headers
std::unordered_multimap< std::string, std::string, detail::case_ignore::hash, detail::case_ignore::equal_to > Headers
Definition: httplib.h:508
httplib::detail::str2tag_core
constexpr unsigned int str2tag_core(const char *s, size_t l, unsigned int h)
Definition: httplib.h:3768
httplib::ClientImpl::socket_
Socket socket_
Definition: httplib.h:1502
httplib::Server::keep_alive_timeout_sec_
time_t keep_alive_timeout_sec_
Definition: httplib.h:1026
httplib::ClientImpl::socket_options_
SocketOptions socket_options_
Definition: httplib.h:1548
httplib::TaskQueue::~TaskQueue
virtual ~TaskQueue()=default
httplib::Client::set_proxy_bearer_token_auth
void set_proxy_bearer_token_auth(const std::string &token)
Definition: httplib.h:10189
httplib::MovedPermanently_301
@ MovedPermanently_301
Definition: httplib.h:452
httplib::Server::HandlerResponse
HandlerResponse
Definition: httplib.h:924
httplib::Client::port
int port() const
Definition: httplib.h:10111
httplib::detail::params_to_query_str
std::string params_to_query_str(const Params &params)
Definition: httplib.h:4676
httplib::Stream::socket
virtual socket_t socket() const =0
T
float T
Definition: UnscentedKalmanFilterTest.cpp:38
httplib::detail::is_connection_error
bool is_connection_error()
Definition: httplib.h:3550
httplib::Client::set_compress
void set_compress(bool on)
Definition: httplib.h:10174
httplib::ClientImpl::is_valid
virtual bool is_valid() const
Definition: httplib.h:7263
httplib::Server::set_ipv6_v6only
Server & set_ipv6_v6only(bool on)
Definition: httplib.h:6256
min
T min(T t1, T t2)
Definition: gdiam.h:44
httplib::InsufficientStorage_507
@ InsufficientStorage_507
Definition: httplib.h:500
httplib::detail::EncodingType::Gzip
@ Gzip
CPPHTTPLIB_CONNECTION_TIMEOUT_SECOND
#define CPPHTTPLIB_CONNECTION_TIMEOUT_SECOND
Definition: httplib.h:30
httplib::detail::EncodingType::Brotli
@ Brotli
httplib::RequestTimeout_408
@ RequestTimeout_408
Definition: httplib.h:470
httplib::Error::Compression
@ Compression
httplib::Client::send
bool send(Request &req, Response &res, Error &error)
Definition: httplib.h:10101
httplib::detail::read_headers
bool read_headers(Stream &strm, Headers &headers)
Definition: httplib.h:4168
httplib::PayloadTooLarge_413
@ PayloadTooLarge_413
Definition: httplib.h:475
httplib::Client::Patch
Result Patch(const std::string &path)
Definition: httplib.h:9976
httplib::ClientImpl::proxy_bearer_token_auth_token_
std::string proxy_bearer_token_auth_token_
Definition: httplib.h:1560
httplib::Response::is_chunked_content_provider_
bool is_chunked_content_provider_
Definition: httplib.h:718
httplib::detail::make_unique
std::enable_if<!std::is_array< T >::value, std::unique_ptr< T > >::type make_unique(Args &&...args)
Definition: httplib.h:333
httplib::Error::SSLConnection
@ SSLConnection
httplib::detail::SocketStream::socket
socket_t socket() const override
Definition: httplib.h:5952
httplib::detail::write_request_line
ssize_t write_request_line(Stream &strm, const std::string &method, const std::string &path)
Definition: httplib.h:4407
endif
endif() find_package(Simox QUIET) armarx_build_if(Simox_FOUND "Simox not available") find_package(PythonLibs 3.6 QUIET) armarx_build_if(PYTHONLIBS_FOUND "Python libs not available") if(PYTHONLIBS_FOUND) include_directories($
Definition: CMakeLists.txt:10
httplib::Response::content_provider_resource_releaser_
ContentProviderResourceReleaser content_provider_resource_releaser_
Definition: httplib.h:717
httplib::status_message
const char * status_message(int status)
Definition: httplib.h:2057
httplib::PreconditionRequired_428
@ PreconditionRequired_428
Definition: httplib.h:487
httplib::Server::~Server
virtual ~Server()
httplib::Result
Definition: httplib.h:1157
httplib::detail::handle_EINTR
ssize_t handle_EINTR(T fn)
Definition: httplib.h:3067
CPPHTTPLIB_RECV_BUFSIZ
#define CPPHTTPLIB_RECV_BUFSIZ
Definition: httplib.h:118
httplib::detail::write_content_without_length
bool write_content_without_length(Stream &strm, const ContentProvider &content_provider, const T &is_shutting_down)
Definition: httplib.h:4503
httplib::detail::get_header_value_u64
uint64_t get_header_value_u64(const Headers &headers, const std::string &key, uint64_t def, size_t id)
Definition: httplib.h:2015
httplib::ContentReader::ContentReader
ContentReader(Reader reader, MultipartReader multipart_reader)
Definition: httplib.h:592
httplib::UnavailableForLegalReasons_451
@ UnavailableForLegalReasons_451
Definition: httplib.h:490
httplib::ContentReader::Reader
std::function< bool(ContentReceiver receiver)> Reader
Definition: httplib.h:588
httplib::Request::get_param_value_count
size_t get_param_value_count(const std::string &key) const
Definition: httplib.h:5709
httplib::Error
Error
Definition: httplib.h:1131
httplib::Server::payload_max_length_
size_t payload_max_length_
Definition: httplib.h:1033
httplib::ClientImpl::write_content_with_provider
bool write_content_with_provider(Stream &strm, const Request &req, Error &error) const
Definition: httplib.h:7673
httplib::Response::location
std::string location
Definition: httplib.h:672
CPPHTTPLIB_LISTEN_BACKLOG
#define CPPHTTPLIB_LISTEN_BACKLOG
Definition: httplib.h:141
httplib::Result::operator*
Response & operator*()
Definition: httplib.h:1171
httplib::HttpVersionNotSupported_505
@ HttpVersionNotSupported_505
Definition: httplib.h:498
httplib::Request::content_receiver
ContentReceiverWithProgress content_receiver
Definition: httplib.h:634
httplib::Server::idle_interval_sec_
time_t idle_interval_sec_
Definition: httplib.h:1031
httplib::make_basic_authentication_header
std::pair< std::string, std::string > make_basic_authentication_header(const std::string &username, const std::string &password, bool is_proxy=false)
Definition: httplib.h:5659
armarx::ctrlutil::s
double s(double t, double s0, double v0, double a0, double j)
Definition: CtrlUtil.h:33
httplib::ContentReceiverWithProgress
std::function< bool(const char *data, size_t data_length, uint64_t offset, uint64_t total_length)> ContentReceiverWithProgress
Definition: httplib.h:578
httplib::detail::case_ignore::hash::operator()
size_t operator()(const std::string &key) const
Definition: httplib.h:384
armarx
This file offers overloads of toIce() and fromIce() functions for STL container types.
Definition: ArmarXTimeserver.cpp:27
httplib::detail::serialize_multipart_formdata_get_content_type
std::string serialize_multipart_formdata_get_content_type(const std::string &boundary)
Definition: httplib.h:5110
httplib::Server::set_default_headers
Server & set_default_headers(Headers headers)
Definition: httplib.h:6266
httplib::Server::idle_interval_usec_
time_t idle_interval_usec_
Definition: httplib.h:1032
httplib::Request::content_length_
size_t content_length_
Definition: httplib.h:660
httplib::detail::scope_exit::scope_exit
scope_exit(std::function< void(void)> &&f)
Definition: httplib.h:405
armarx::status::success
@ success
httplib::detail::scope_exit::scope_exit
scope_exit(scope_exit &&rhs) noexcept
Definition: httplib.h:408
httplib::Request
Definition: httplib.h:612
httplib::Request::local_port
int local_port
Definition: httplib.h:622
httplib::Response::set_redirect
void set_redirect(const std::string &url, int status=StatusCode::Found_302)
Definition: httplib.h:5762
httplib::detail::divide
void divide(const std::string &str, char d, std::function< void(const char *, std::size_t, const char *, std::size_t)> fn)
Definition: httplib.h:2825
httplib::Ranges
std::vector< Range > Ranges
Definition: httplib.h:610
httplib::ContentReader::reader_
Reader reader_
Definition: httplib.h:605
httplib::Stream::get_remote_ip_and_port
virtual void get_remote_ip_and_port(std::string &ip, int &port) const =0
httplib::Error::Canceled
@ Canceled
httplib::ContentReader::operator()
bool operator()(MultipartContentHeader header, ContentReceiver receiver) const
Definition: httplib.h:596
httplib::detail::write_content
bool write_content(Stream &strm, const ContentProvider &content_provider, size_t offset, size_t length, const T &is_shutting_down)
Definition: httplib.h:4493
httplib::Response
Definition: httplib.h:666
httplib::Result::Result
Result()=default
httplib::detail::is_hex
bool is_hex(char c, int &v)
Definition: httplib.h:2519
httplib::Request::params
Params params
Definition: httplib.h:615
httplib::detail::FileStat::FileStat
FileStat(const std::string &path)
Definition: httplib.h:2664
CPPHTTPLIB_MULTIPART_FORM_DATA_FILE_MAX_COUNT
#define CPPHTTPLIB_MULTIPART_FORM_DATA_FILE_MAX_COUNT
Definition: httplib.h:94
httplib::detail::get_ip_and_port
bool get_ip_and_port(const struct sockaddr_storage &addr, socklen_t addr_len, std::string &ip, int &port)
Definition: httplib.h:3709
httplib::Error::Success
@ Success
httplib::Response::file_content_content_type_
std::string file_content_content_type_
Definition: httplib.h:721
httplib::Request::redirect_count_
size_t redirect_count_
Definition: httplib.h:659
httplib::Server
Definition: httplib.h:917
httplib::detail::MatcherBase::~MatcherBase
virtual ~MatcherBase()=default
httplib::detail::set_nonblocking
void set_nonblocking(socket_t sock, bool nonblocking)
Definition: httplib.h:3539
httplib::ClientImpl::default_headers_
Headers default_headers_
Definition: httplib.h:1515
httplib::detail::select_write
ssize_t select_write(socket_t sock, time_t sec, time_t usec)
Definition: httplib.h:3133
httplib::EarlyHints_103
@ EarlyHints_103
Definition: httplib.h:436
httplib::detail::EncodingType::None
@ None
httplib::detail::serialize_multipart_formdata_item_end
std::string serialize_multipart_formdata_item_end()
Definition: httplib.h:5102
httplib::Response::content_length_
size_t content_length_
Definition: httplib.h:715
httplib::ClientImpl::set_read_timeout
void set_read_timeout(time_t sec, time_t usec=0)
Definition: httplib.h:8722
httplib::detail::BufferStream::~BufferStream
~BufferStream() override=default
httplib::Request::version
std::string version
Definition: httplib.h:625
httplib::Server::set_file_extension_and_mimetype_mapping
Server & set_file_extension_and_mimetype_mapping(const std::string &ext, const std::string &mime)
Definition: httplib.h:6189
httplib::Client::set_url_encode
void set_url_encode(bool on)
Definition: httplib.h:10172
CPPHTTPLIB_KEEPALIVE_TIMEOUT_CHECK_INTERVAL_USECOND
#define CPPHTTPLIB_KEEPALIVE_TIMEOUT_CHECK_INTERVAL_USECOND
Definition: httplib.h:22