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