NDDEM
Server.h
Go to the documentation of this file.
1 //
2 // httplib.h
3 //
4 // Copyright (c) 2019 Yuji Hirose. All rights reserved.
5 // MIT License
6 //
7 
8 #ifndef CPPHTTPLIB_HTTPLIB_H
9 #define CPPHTTPLIB_HTTPLIB_H
10 
11 #ifdef _WIN32
12 #ifndef _CRT_SECURE_NO_WARNINGS
13 #define _CRT_SECURE_NO_WARNINGS
14 #endif //_CRT_SECURE_NO_WARNINGS
15 
16 #ifndef _CRT_NONSTDC_NO_DEPRECATE
17 #define _CRT_NONSTDC_NO_DEPRECATE
18 #endif //_CRT_NONSTDC_NO_DEPRECATE
19 
20 #if defined(_MSC_VER) && _MSC_VER < 1900
21 #define snprintf _snprintf_s
22 #endif // _MSC_VER
23 
24 #ifndef S_ISREG
25 #define S_ISREG(m) (((m)&S_IFREG) == S_IFREG)
26 #endif // S_ISREG
27 
28 #ifndef S_ISDIR
29 #define S_ISDIR(m) (((m)&S_IFDIR) == S_IFDIR)
30 #endif // S_ISDIR
31 
32 #ifndef NOMINMAX
33 #define NOMINMAX
34 #endif // NOMINMAX
35 
36 #include <io.h>
37 #include <winsock2.h>
38 #include <ws2tcpip.h>
39 
40 #pragma comment(lib, "ws2_32.lib")
41 
42 #ifndef strcasecmp
43 #define strcasecmp _stricmp
44 #endif // strcasecmp
45 
46 typedef SOCKET socket_t;
47 #else
48 #include <arpa/inet.h>
49 #include <cstring>
50 #include <netdb.h>
51 #include <netinet/in.h>
52 #include <pthread.h>
53 #include <signal.h>
54 #include <sys/select.h>
55 #include <sys/socket.h>
56 #include <unistd.h>
57 
58 typedef int socket_t;
59 #define INVALID_SOCKET (-1)
60 #endif //_WIN32
61 
62 #include <assert.h>
63 #include <fcntl.h>
64 #include <fstream>
65 #include <functional>
66 #include <map>
67 #include <memory>
68 #include <mutex>
69 #include <regex>
70 #include <string>
71 #include <sys/stat.h>
72 #include <thread>
73 
74 #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
75 #include <openssl/err.h>
76 #include <openssl/ssl.h>
77 #include <openssl/x509v3.h>
78 #endif
79 
80 #ifdef CPPHTTPLIB_ZLIB_SUPPORT
81 #include <zlib.h>
82 #endif
83 
84 /*
85  * Configuration
86  */
87 #define CPPHTTPLIB_KEEPALIVE_TIMEOUT_SECOND 5
88 #define CPPHTTPLIB_KEEPALIVE_TIMEOUT_USECOND 0
89 #define CPPHTTPLIB_KEEPALIVE_MAX_COUNT 5
90 #define CPPHTTPLIB_REQUEST_URI_MAX_LENGTH 8192
91 #define CPPHTTPLIB_PAYLOAD_MAX_LENGTH std::numeric_limits<size_t>::max()
92 
93 namespace httplib {
94 
95 namespace detail {
96 
97 struct ci {
98  bool operator()(const std::string &s1, const std::string &s2) const {
99  return std::lexicographical_compare(
100  s1.begin(), s1.end(), s2.begin(), s2.end(),
101  [](char c1, char c2) { return ::tolower(c1) < ::tolower(c2); });
102  }
103 };
104 
105 } // namespace detail
106 
107 enum class HttpVersion { v1_0 = 0, v1_1 };
108 
109 typedef std::multimap<std::string, std::string, detail::ci> Headers;
110 
111 template <typename uint64_t, typename... Args>
112 std::pair<std::string, std::string> make_range_header(uint64_t value,
113  Args... args);
114 
115 typedef std::map<std::string, std::string> Params;
116 typedef std::smatch Match;
117 typedef std::function<bool(uint64_t current, uint64_t total)> Progress;
118 
119 struct MultipartFile {
120  std::string filename;
121  std::string content_type;
122  size_t offset = 0;
123  size_t length = 0;
124 };
125 typedef std::multimap<std::string, MultipartFile> MultipartFiles;
126 
127 struct Request {
128  std::string version;
129  std::string method;
130  std::string target;
131  std::string path;
132  Headers headers;
133  std::string body;
134  Params params;
135  MultipartFiles files;
136  Match matches;
137 
138  Progress progress;
139 
140  bool has_header(const char *key) const;
141  std::string get_header_value(const char *key, size_t id = 0) const;
142  size_t get_header_value_count(const char *key) const;
143  void set_header(const char *key, const char *val);
144 
145  bool has_param(const char *key) const;
146  std::string get_param_value(const char *key, size_t id = 0) const;
147  size_t get_param_value_count(const char *key) const;
148 
149  bool has_file(const char *key) const;
150  MultipartFile get_file_value(const char *key) const;
151 };
152 
153 struct Response {
154  std::string version;
155  int status;
156  Headers headers;
157  std::string body;
158  std::function<std::string(uint64_t offset)> streamcb;
159 
160  bool has_header(const char *key) const;
161  std::string get_header_value(const char *key, size_t id = 0) const;
162  size_t get_header_value_count(const char *key) const;
163  void set_header(const char *key, const char *val);
164 
165  void set_redirect(const char *uri);
166  void set_content(const char *s, size_t n, const char *content_type);
167  void set_content(const std::string &s, const char *content_type);
168 
169  Response() : status(-1) {}
170 };
171 
172 class Stream {
173 public:
174  virtual ~Stream() {}
175  virtual int read(char *ptr, size_t size) = 0;
176  virtual int write(const char *ptr, size_t size1) = 0;
177  virtual int write(const char *ptr) = 0;
178  virtual std::string get_remote_addr() const = 0;
179 
180  template <typename... Args>
181  void write_format(const char *fmt, const Args &... args);
182 };
183 
184 class SocketStream : public Stream {
185 public:
186  SocketStream(socket_t sock);
187  virtual ~SocketStream();
188 
189  virtual int read(char *ptr, size_t size);
190  virtual int write(const char *ptr, size_t size);
191  virtual int write(const char *ptr);
192  virtual std::string get_remote_addr() const;
193 
194 private:
195  socket_t sock_;
196 };
197 
198 class BufferStream : public Stream {
199 public:
200  BufferStream() {}
201  virtual ~BufferStream() {}
202 
203  virtual int read(char *ptr, size_t size);
204  virtual int write(const char *ptr, size_t size);
205  virtual int write(const char *ptr);
206  virtual std::string get_remote_addr() const;
207 
208  const std::string &get_buffer() const;
209 
210 private:
211  std::string buffer;
212 };
213 
214 class Server {
215 public:
216  typedef std::function<void(const Request &, Response &)> Handler;
217  typedef std::function<void(const Request &, const Response &)> Logger;
218 
219  Server();
220 
221  virtual ~Server();
222 
223  virtual bool is_valid() const;
224 
225  Server &Get(const char *pattern, Handler handler);
226  Server &Post(const char *pattern, Handler handler);
227 
228  Server &Put(const char *pattern, Handler handler);
229  Server &Patch(const char *pattern, Handler handler);
230  Server &Delete(const char *pattern, Handler handler);
231  Server &Options(const char *pattern, Handler handler);
232 
233  bool set_base_dir(const char *path);
234 
235  void set_error_handler(Handler handler);
236  void set_logger(Logger logger);
237 
238  void set_keep_alive_max_count(size_t count);
239  void set_payload_max_length(uint64_t length);
240 
241  int bind_to_any_port(const char *host, int socket_flags = 0);
242  bool listen_after_bind();
243 
244  bool listen(const char *host, int port, int socket_flags = 0);
245 
246  bool is_running() const;
247  void stop();
248 
249 protected:
250  bool process_request(Stream &strm, bool last_connection,
251  bool &connection_close);
252 
253  size_t keep_alive_max_count_;
254  size_t payload_max_length_;
255 
256 private:
257  typedef std::vector<std::pair<std::regex, Handler>> Handlers;
258 
259  socket_t create_server_socket(const char *host, int port,
260  int socket_flags) const;
261  int bind_internal(const char *host, int port, int socket_flags);
262  bool listen_internal();
263 
264  bool routing(Request &req, Response &res);
265  bool handle_file_request(Request &req, Response &res);
266  bool dispatch_request(Request &req, Response &res, Handlers &handlers);
267 
268  bool parse_request_line(const char *s, Request &req);
269  void write_response(Stream &strm, bool last_connection, const Request &req,
270  Response &res);
271 
272  virtual bool read_and_close_socket(socket_t sock);
273 
274  bool is_running_;
275  socket_t svr_sock_;
276  std::string base_dir_;
277  Handlers get_handlers_;
278  Handlers post_handlers_;
279  Handlers put_handlers_;
280  Handlers patch_handlers_;
281  Handlers delete_handlers_;
282  Handlers options_handlers_;
283  Handler error_handler_;
284  Logger logger_;
285 
286  // TODO: Use thread pool...
287  std::mutex running_threads_mutex_;
288  int running_threads_;
289 };
290 
291 class Client {
292 public:
293  Client(const char *host, int port = 80, time_t timeout_sec = 300);
294 
295  virtual ~Client();
296 
297  virtual bool is_valid() const;
298 
299  std::shared_ptr<Response> Get(const char *path, Progress progress = nullptr);
300  std::shared_ptr<Response> Get(const char *path, const Headers &headers,
301  Progress progress = nullptr);
302 
303  std::shared_ptr<Response> Head(const char *path);
304  std::shared_ptr<Response> Head(const char *path, const Headers &headers);
305 
306  std::shared_ptr<Response> Post(const char *path, const std::string &body,
307  const char *content_type);
308  std::shared_ptr<Response> Post(const char *path, const Headers &headers,
309  const std::string &body,
310  const char *content_type);
311 
312  std::shared_ptr<Response> Post(const char *path, const Params &params);
313  std::shared_ptr<Response> Post(const char *path, const Headers &headers,
314  const Params &params);
315 
316  std::shared_ptr<Response> Put(const char *path, const std::string &body,
317  const char *content_type);
318  std::shared_ptr<Response> Put(const char *path, const Headers &headers,
319  const std::string &body,
320  const char *content_type);
321 
322  std::shared_ptr<Response> Patch(const char *path, const std::string &body,
323  const char *content_type);
324  std::shared_ptr<Response> Patch(const char *path, const Headers &headers,
325  const std::string &body,
326  const char *content_type);
327 
328  std::shared_ptr<Response> Delete(const char *path,
329  const std::string &body = std::string(),
330  const char *content_type = nullptr);
331  std::shared_ptr<Response> Delete(const char *path, const Headers &headers,
332  const std::string &body = std::string(),
333  const char *content_type = nullptr);
334 
335  std::shared_ptr<Response> Options(const char *path);
336  std::shared_ptr<Response> Options(const char *path, const Headers &headers);
337 
338  bool send(Request &req, Response &res);
339 
340 protected:
341  bool process_request(Stream &strm, Request &req, Response &res,
342  bool &connection_close);
343 
344  const std::string host_;
345  const int port_;
346  time_t timeout_sec_;
347  const std::string host_and_port_;
348 
349 private:
350  socket_t create_client_socket() const;
351  bool read_response_line(Stream &strm, Response &res);
352  void write_request(Stream &strm, Request &req);
353 
354  virtual bool read_and_close_socket(socket_t sock, Request &req,
355  Response &res);
356  virtual bool is_ssl() const;
357 };
358 
359 #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
360 class SSLSocketStream : public Stream {
361 public:
362  SSLSocketStream(socket_t sock, SSL *ssl);
363  virtual ~SSLSocketStream();
364 
365  virtual int read(char *ptr, size_t size);
366  virtual int write(const char *ptr, size_t size);
367  virtual int write(const char *ptr);
368  virtual std::string get_remote_addr() const;
369 
370 private:
371  socket_t sock_;
372  SSL *ssl_;
373 };
374 
375 class SSLServer : public Server {
376 public:
377  SSLServer(const char *cert_path, const char *private_key_path);
378 
379  virtual ~SSLServer();
380 
381  virtual bool is_valid() const;
382 
383 private:
384  virtual bool read_and_close_socket(socket_t sock);
385 
386  SSL_CTX *ctx_;
387  std::mutex ctx_mutex_;
388 };
389 
390 class SSLClient : public Client {
391 public:
392  SSLClient(const char *host, int port = 443, time_t timeout_sec = 300);
393 
394  virtual ~SSLClient();
395 
396  virtual bool is_valid() const;
397 
398  void set_ca_cert_path(const char *ca_cert_path);
399  void enable_server_certificate_verification(bool enabled);
400 
401  long get_openssl_verify_result() const;
402 
403 private:
404  virtual bool read_and_close_socket(socket_t sock, Request &req,
405  Response &res);
406  virtual bool is_ssl() const;
407 
408  bool verify_host(X509 *server_cert) const;
409  bool verify_host_with_subject_alt_name(X509 *server_cert) const;
410  bool verify_host_with_common_name(X509 *server_cert) const;
411  bool check_host_name(const char *pattern, size_t pattern_len) const;
412 
413  SSL_CTX *ctx_;
414  std::mutex ctx_mutex_;
415  std::vector<std::string> host_components_;
416  std::string ca_cert_path_;
417  bool server_certificate_verification_ = false;
418  long verify_result_ = 0;
419 };
420 #endif
421 
422 /*
423  * Implementation
424  */
425 namespace detail {
426 
427 template <class Fn> void split(const char *b, const char *e, char d, Fn fn) {
428  int i = 0;
429  int beg = 0;
430 
431  while (e ? (b + i != e) : (b[i] != '\0')) {
432  if (b[i] == d) {
433  fn(&b[beg], &b[i]);
434  beg = i + 1;
435  }
436  i++;
437  }
438 
439  if (i) { fn(&b[beg], &b[i]); }
440 }
441 
442 // NOTE: until the read size reaches `fixed_buffer_size`, use `fixed_buffer`
443 // to store data. The call can set memory on stack for performance.
444 class stream_line_reader {
445 public:
446  stream_line_reader(Stream &strm, char *fixed_buffer, size_t fixed_buffer_size)
447  : strm_(strm), fixed_buffer_(fixed_buffer),
448  fixed_buffer_size_(fixed_buffer_size) {}
449 
450  const char *ptr() const {
451  if (glowable_buffer_.empty()) {
452  return fixed_buffer_;
453  } else {
454  return glowable_buffer_.data();
455  }
456  }
457 
458  size_t size() const {
459  if (glowable_buffer_.empty()) {
460  return fixed_buffer_used_size_;
461  } else {
462  return glowable_buffer_.size();
463  }
464  }
465 
466  bool getline() {
467  fixed_buffer_used_size_ = 0;
468  glowable_buffer_.clear();
469 
470  for (size_t i = 0;; i++) {
471  char byte;
472  auto n = strm_.read(&byte, 1);
473 
474  if (n < 0) {
475  return false;
476  } else if (n == 0) {
477  if (i == 0) {
478  return false;
479  } else {
480  break;
481  }
482  }
483 
484  append(byte);
485 
486  if (byte == '\n') { break; }
487  }
488 
489  return true;
490  }
491 
492 private:
493  void append(char c) {
494  if (fixed_buffer_used_size_ < fixed_buffer_size_ - 1) {
495  fixed_buffer_[fixed_buffer_used_size_++] = c;
496  fixed_buffer_[fixed_buffer_used_size_] = '\0';
497  } else {
498  if (glowable_buffer_.empty()) {
499  assert(fixed_buffer_[fixed_buffer_used_size_] == '\0');
500  glowable_buffer_.assign(fixed_buffer_, fixed_buffer_used_size_);
501  }
502  glowable_buffer_ += c;
503  }
504  }
505 
506  Stream &strm_;
507  char *fixed_buffer_;
508  const size_t fixed_buffer_size_;
509  size_t fixed_buffer_used_size_;
510  std::string glowable_buffer_;
511 };
512 
513 inline int close_socket(socket_t sock) {
514 #ifdef _WIN32
515  return closesocket(sock);
516 #else
517  return close(sock);
518 #endif
519 }
520 
521 inline int select_read(socket_t sock, time_t sec, time_t usec) {
522  fd_set fds;
523  FD_ZERO(&fds);
524  FD_SET(sock, &fds);
525 
526  timeval tv;
527  tv.tv_sec = static_cast<long>(sec);
528  tv.tv_usec = static_cast<long>(usec);
529 
530  return select(static_cast<int>(sock + 1), &fds, nullptr, nullptr, &tv);
531 }
532 
533 inline bool wait_until_socket_is_ready(socket_t sock, time_t sec, time_t usec) {
534  fd_set fdsr;
535  FD_ZERO(&fdsr);
536  FD_SET(sock, &fdsr);
537 
538  auto fdsw = fdsr;
539  auto fdse = fdsr;
540 
541  timeval tv;
542  tv.tv_sec = static_cast<long>(sec);
543  tv.tv_usec = static_cast<long>(usec);
544 
545  if (select(static_cast<int>(sock + 1), &fdsr, &fdsw, &fdse, &tv) < 0) {
546  return false;
547  } else if (FD_ISSET(sock, &fdsr) || FD_ISSET(sock, &fdsw)) {
548  int error = 0;
549  socklen_t len = sizeof(error);
550  if (getsockopt(sock, SOL_SOCKET, SO_ERROR, (char *)&error, &len) < 0 ||
551  error) {
552  return false;
553  }
554  } else {
555  return false;
556  }
557 
558  return true;
559 }
560 
561 template <typename T>
562 inline bool read_and_close_socket(socket_t sock, size_t keep_alive_max_count,
563  T callback) {
564  bool ret = false;
565 
566  if (keep_alive_max_count > 0) {
567  auto count = keep_alive_max_count;
568  while (count > 0 &&
569  detail::select_read(sock, CPPHTTPLIB_KEEPALIVE_TIMEOUT_SECOND,
571  SocketStream strm(sock);
572  auto last_connection = count == 1;
573  auto connection_close = false;
574 
575  ret = callback(strm, last_connection, connection_close);
576  if (!ret || connection_close) { break; }
577 
578  count--;
579  }
580  } else {
581  SocketStream strm(sock);
582  auto dummy_connection_close = false;
583  ret = callback(strm, true, dummy_connection_close);
584  }
585 
586  close_socket(sock);
587  return ret;
588 }
589 
590 inline int shutdown_socket(socket_t sock) {
591 #ifdef _WIN32
592  return shutdown(sock, SD_BOTH);
593 #else
594  return shutdown(sock, SHUT_RDWR);
595 #endif
596 }
597 
598 template <typename Fn>
599 socket_t create_socket(const char *host, int port, Fn fn,
600  int socket_flags = 0) {
601 #ifdef _WIN32
602 #define SO_SYNCHRONOUS_NONALERT 0x20
603 #define SO_OPENTYPE 0x7008
604 
605  int opt = SO_SYNCHRONOUS_NONALERT;
606  setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, (char *)&opt,
607  sizeof(opt));
608 #endif
609 
610  // Get address info
611  struct addrinfo hints;
612  struct addrinfo *result;
613 
614  memset(&hints, 0, sizeof(struct addrinfo));
615  hints.ai_family = AF_UNSPEC;
616  hints.ai_socktype = SOCK_STREAM;
617  hints.ai_flags = socket_flags;
618  hints.ai_protocol = 0;
619 
620  auto service = std::to_string(port);
621 
622  if (getaddrinfo(host, service.c_str(), &hints, &result)) {
623  return INVALID_SOCKET;
624  }
625 
626  for (auto rp = result; rp; rp = rp->ai_next) {
627  // Create a socket
628  auto sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
629  if (sock == INVALID_SOCKET) { continue; }
630 
631  // Make 'reuse address' option available
632  int yes = 1;
633  setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&yes, sizeof(yes));
634 
635  // bind or connect
636  if (fn(sock, *rp)) {
637  freeaddrinfo(result);
638  return sock;
639  }
640 
641  close_socket(sock);
642  }
643 
644  freeaddrinfo(result);
645  return INVALID_SOCKET;
646 }
647 
648 inline void set_nonblocking(socket_t sock, bool nonblocking) {
649 #ifdef _WIN32
650  auto flags = nonblocking ? 1UL : 0UL;
651  ioctlsocket(sock, FIONBIO, &flags);
652 #else
653  auto flags = fcntl(sock, F_GETFL, 0);
654  fcntl(sock, F_SETFL,
655  nonblocking ? (flags | O_NONBLOCK) : (flags & (~O_NONBLOCK)));
656 #endif
657 }
658 
659 inline bool is_connection_error() {
660 #ifdef _WIN32
661  return WSAGetLastError() != WSAEWOULDBLOCK;
662 #else
663  return errno != EINPROGRESS;
664 #endif
665 }
666 
667 inline std::string get_remote_addr(socket_t sock) {
668  struct sockaddr_storage addr;
669  socklen_t len = sizeof(addr);
670 
671  if (!getpeername(sock, (struct sockaddr *)&addr, &len)) {
672  char ipstr[NI_MAXHOST];
673 
674  if (!getnameinfo((struct sockaddr *)&addr, len, ipstr, sizeof(ipstr),
675  nullptr, 0, NI_NUMERICHOST)) {
676  return ipstr;
677  }
678  }
679 
680  return std::string();
681 }
682 
683 inline bool is_file(const std::string &path) {
684  struct stat st;
685  return stat(path.c_str(), &st) >= 0 && S_ISREG(st.st_mode);
686 }
687 
688 inline bool is_dir(const std::string &path) {
689  struct stat st;
690  return stat(path.c_str(), &st) >= 0 && S_ISDIR(st.st_mode);
691 }
692 
693 inline bool is_valid_path(const std::string &path) {
694  size_t level = 0;
695  size_t i = 0;
696 
697  // Skip slash
698  while (i < path.size() && path[i] == '/') {
699  i++;
700  }
701 
702  while (i < path.size()) {
703  // Read component
704  auto beg = i;
705  while (i < path.size() && path[i] != '/') {
706  i++;
707  }
708 
709  auto len = i - beg;
710  assert(len > 0);
711 
712  if (!path.compare(beg, len, ".")) {
713  ;
714  } else if (!path.compare(beg, len, "..")) {
715  if (level == 0) { return false; }
716  level--;
717  } else {
718  level++;
719  }
720 
721  // Skip slash
722  while (i < path.size() && path[i] == '/') {
723  i++;
724  }
725  }
726 
727  return true;
728 }
729 
730 inline void read_file(const std::string &path, std::string &out) {
731  std::ifstream fs(path, std::ios_base::binary);
732  fs.seekg(0, std::ios_base::end);
733  auto size = fs.tellg();
734  fs.seekg(0);
735  out.resize(static_cast<size_t>(size));
736  fs.read(&out[0], size);
737 }
738 
739 inline std::string file_extension(const std::string &path) {
740  std::smatch m;
741  auto pat = std::regex("\\.([a-zA-Z0-9]+)$");
742  if (std::regex_search(path, m, pat)) { return m[1].str(); }
743  return std::string();
744 }
745 
746 inline const char *find_content_type(const std::string &path) {
747  auto ext = file_extension(path);
748  if (ext == "txt") {
749  return "text/plain";
750  } else if (ext == "html") {
751  return "text/html";
752  } else if (ext == "css") {
753  return "text/css";
754  } else if (ext == "jpeg" || ext == "jpg") {
755  return "image/jpg";
756  } else if (ext == "png") {
757  return "image/png";
758  } else if (ext == "gif") {
759  return "image/gif";
760  } else if (ext == "svg") {
761  return "image/svg+xml";
762  } else if (ext == "ico") {
763  return "image/x-icon";
764  } else if (ext == "json") {
765  return "application/json";
766  } else if (ext == "pdf") {
767  return "application/pdf";
768  } else if (ext == "js") {
769  return "application/javascript";
770  } else if (ext == "xml") {
771  return "application/xml";
772  } else if (ext == "xhtml") {
773  return "application/xhtml+xml";
774  }
775  return nullptr;
776 }
777 
778 inline const char *status_message(int status) {
779  switch (status) {
780  case 200: return "OK";
781  case 301: return "Moved Permanently";
782  case 302: return "Found";
783  case 303: return "See Other";
784  case 304: return "Not Modified";
785  case 400: return "Bad Request";
786  case 403: return "Forbidden";
787  case 404: return "Not Found";
788  case 413: return "Payload Too Large";
789  case 414: return "Request-URI Too Long";
790  case 415: return "Unsupported Media Type";
791  default:
792  case 500: return "Internal Server Error";
793  }
794 }
795 
796 inline bool has_header(const Headers &headers, const char *key) {
797  return headers.find(key) != headers.end();
798 }
799 
800 inline const char *get_header_value(const Headers &headers, const char *key,
801  size_t id = 0, const char *def = nullptr) {
802  auto it = headers.find(key);
803  std::advance(it, id);
804  if (it != headers.end()) { return it->second.c_str(); }
805  return def;
806 }
807 
808 inline uint64_t get_header_value_uint64(const Headers &headers, const char *key,
809  int def = 0) {
810  auto it = headers.find(key);
811  if (it != headers.end()) {
812  return std::strtoull(it->second.data(), nullptr, 10);
813  }
814  return def;
815 }
816 
817 inline bool read_headers(Stream &strm, Headers &headers) {
818  static std::regex re(R"((.+?):\s*(.+?)\s*\r\n)");
819 
820  const auto bufsiz = 2048;
821  char buf[bufsiz];
822 
823  stream_line_reader reader(strm, buf, bufsiz);
824 
825  for (;;) {
826  if (!reader.getline()) { return false; }
827  if (!strcmp(reader.ptr(), "\r\n")) { break; }
828  std::cmatch m;
829  if (std::regex_match(reader.ptr(), m, re)) {
830  auto key = std::string(m[1]);
831  auto val = std::string(m[2]);
832  headers.emplace(key, val);
833  }
834  }
835 
836  return true;
837 }
838 
839 inline bool read_content_with_length(Stream &strm, std::string &out, size_t len,
840  Progress progress) {
841  out.assign(len, 0);
842  size_t r = 0;
843  while (r < len) {
844  auto n = strm.read(&out[r], len - r);
845  if (n <= 0) { return false; }
846 
847  r += n;
848 
849  if (progress) {
850  if (!progress(r, len)) { return false; }
851  }
852  }
853 
854  return true;
855 }
856 
857 inline void skip_content_with_length(Stream &strm, size_t len) {
858  char buf[BUFSIZ];
859  size_t r = 0;
860  while (r < len) {
861  auto n = strm.read(buf, BUFSIZ);
862  if (n <= 0) { return; }
863  r += n;
864  }
865 }
866 
867 inline bool read_content_without_length(Stream &strm, std::string &out) {
868  for (;;) {
869  char byte;
870  auto n = strm.read(&byte, 1);
871  if (n < 0) {
872  return false;
873  } else if (n == 0) {
874  return true;
875  }
876  out += byte;
877  }
878 
879  return true;
880 }
881 
882 inline bool read_content_chunked(Stream &strm, std::string &out) {
883  const auto bufsiz = 16;
884  char buf[bufsiz];
885 
886  stream_line_reader reader(strm, buf, bufsiz);
887 
888  if (!reader.getline()) { return false; }
889 
890  auto chunk_len = std::stoi(reader.ptr(), 0, 16);
891 
892  while (chunk_len > 0) {
893  std::string chunk;
894  if (!read_content_with_length(strm, chunk, chunk_len, nullptr)) {
895  return false;
896  }
897 
898  if (!reader.getline()) { return false; }
899 
900  if (strcmp(reader.ptr(), "\r\n")) { break; }
901 
902  out += chunk;
903 
904  if (!reader.getline()) { return false; }
905 
906  chunk_len = std::stoi(reader.ptr(), 0, 16);
907  }
908 
909  if (chunk_len == 0) {
910  // Reader terminator after chunks
911  if (!reader.getline() || strcmp(reader.ptr(), "\r\n")) return false;
912  }
913 
914  return true;
915 }
916 
917 template <typename T>
918 bool read_content(Stream &strm, T &x, uint64_t payload_max_length,
919  bool &exceed_payload_max_length,
920  Progress progress = Progress()) {
921  if (has_header(x.headers, "Content-Length")) {
922  auto len = get_header_value_uint64(x.headers, "Content-Length", 0);
923  if (len == 0) {
924  const auto &encoding =
925  get_header_value(x.headers, "Transfer-Encoding", 0, "");
926  if (!strcasecmp(encoding, "chunked")) {
927  return read_content_chunked(strm, x.body);
928  }
929  }
930 
931  if ((len > payload_max_length) ||
932  // For 32-bit platform
933  (sizeof(size_t) < sizeof(uint64_t) &&
934  len > std::numeric_limits<size_t>::max())) {
935  exceed_payload_max_length = true;
936  skip_content_with_length(strm, len);
937  return false;
938  }
939 
940  return read_content_with_length(strm, x.body, len, progress);
941  } else {
942  const auto &encoding =
943  get_header_value(x.headers, "Transfer-Encoding", 0, "");
944  if (!strcasecmp(encoding, "chunked")) {
945  return read_content_chunked(strm, x.body);
946  }
947  return read_content_without_length(strm, x.body);
948  }
949  return true;
950 }
951 
952 template <typename T> inline void write_headers(Stream &strm, const T &info) {
953  for (const auto &x : info.headers) {
954  strm.write_format("%s: %s\r\n", x.first.c_str(), x.second.c_str());
955  }
956  strm.write("\r\n");
957 }
958 
959 inline std::string encode_url(const std::string &s) {
960  std::string result;
961 
962  for (auto i = 0; s[i]; i++) {
963  switch (s[i]) {
964  case ' ': result += "%20"; break;
965  case '+': result += "%2B"; break;
966  case '\r': result += "%0D"; break;
967  case '\n': result += "%0A"; break;
968  case '\'': result += "%27"; break;
969  case ',': result += "%2C"; break;
970  case ':': result += "%3A"; break;
971  case ';': result += "%3B"; break;
972  default:
973  auto c = static_cast<uint8_t>(s[i]);
974  if (c >= 0x80) {
975  result += '%';
976  char hex[4];
977  size_t len = snprintf(hex, sizeof(hex) - 1, "%02X", c);
978  assert(len == 2);
979  result.append(hex, len);
980  } else {
981  result += s[i];
982  }
983  break;
984  }
985  }
986 
987  return result;
988 }
989 
990 inline bool is_hex(char c, int &v) {
991  if (0x20 <= c && isdigit(c)) {
992  v = c - '0';
993  return true;
994  } else if ('A' <= c && c <= 'F') {
995  v = c - 'A' + 10;
996  return true;
997  } else if ('a' <= c && c <= 'f') {
998  v = c - 'a' + 10;
999  return true;
1000  }
1001  return false;
1002 }
1003 
1004 inline bool from_hex_to_i(const std::string &s, size_t i, size_t cnt,
1005  int &val) {
1006  if (i >= s.size()) { return false; }
1007 
1008  val = 0;
1009  for (; cnt; i++, cnt--) {
1010  if (!s[i]) { return false; }
1011  int v = 0;
1012  if (is_hex(s[i], v)) {
1013  val = val * 16 + v;
1014  } else {
1015  return false;
1016  }
1017  }
1018  return true;
1019 }
1020 
1021 inline std::string from_i_to_hex(uint64_t n) {
1022  const char *charset = "0123456789abcdef";
1023  std::string ret;
1024  do {
1025  ret = charset[n & 15] + ret;
1026  n >>= 4;
1027  } while (n > 0);
1028  return ret;
1029 }
1030 
1031 inline size_t to_utf8(int code, char *buff) {
1032  if (code < 0x0080) {
1033  buff[0] = (code & 0x7F);
1034  return 1;
1035  } else if (code < 0x0800) {
1036  buff[0] = (0xC0 | ((code >> 6) & 0x1F));
1037  buff[1] = (0x80 | (code & 0x3F));
1038  return 2;
1039  } else if (code < 0xD800) {
1040  buff[0] = (0xE0 | ((code >> 12) & 0xF));
1041  buff[1] = (0x80 | ((code >> 6) & 0x3F));
1042  buff[2] = (0x80 | (code & 0x3F));
1043  return 3;
1044  } else if (code < 0xE000) { // D800 - DFFF is invalid...
1045  return 0;
1046  } else if (code < 0x10000) {
1047  buff[0] = (0xE0 | ((code >> 12) & 0xF));
1048  buff[1] = (0x80 | ((code >> 6) & 0x3F));
1049  buff[2] = (0x80 | (code & 0x3F));
1050  return 3;
1051  } else if (code < 0x110000) {
1052  buff[0] = (0xF0 | ((code >> 18) & 0x7));
1053  buff[1] = (0x80 | ((code >> 12) & 0x3F));
1054  buff[2] = (0x80 | ((code >> 6) & 0x3F));
1055  buff[3] = (0x80 | (code & 0x3F));
1056  return 4;
1057  }
1058 
1059  // NOTREACHED
1060  return 0;
1061 }
1062 
1063 inline std::string decode_url(const std::string &s) {
1064  std::string result;
1065 
1066  for (size_t i = 0; i < s.size(); i++) {
1067  if (s[i] == '%' && i + 1 < s.size()) {
1068  if (s[i + 1] == 'u') {
1069  int val = 0;
1070  if (from_hex_to_i(s, i + 2, 4, val)) {
1071  // 4 digits Unicode codes
1072  char buff[4];
1073  size_t len = to_utf8(val, buff);
1074  if (len > 0) { result.append(buff, len); }
1075  i += 5; // 'u0000'
1076  } else {
1077  result += s[i];
1078  }
1079  } else {
1080  int val = 0;
1081  if (from_hex_to_i(s, i + 1, 2, val)) {
1082  // 2 digits hex codes
1083  result += val;
1084  i += 2; // '00'
1085  } else {
1086  result += s[i];
1087  }
1088  }
1089  } else if (s[i] == '+') {
1090  result += ' ';
1091  } else {
1092  result += s[i];
1093  }
1094  }
1095 
1096  return result;
1097 }
1098 
1099 inline void parse_query_text(const std::string &s, Params &params) {
1100  split(&s[0], &s[s.size()], '&', [&](const char *b, const char *e) {
1101  std::string key;
1102  std::string val;
1103  split(b, e, '=', [&](const char *b, const char *e) {
1104  if (key.empty()) {
1105  key.assign(b, e);
1106  } else {
1107  val.assign(b, e);
1108  }
1109  });
1110  params.emplace(key, decode_url(val));
1111  });
1112 }
1113 
1114 inline bool parse_multipart_boundary(const std::string &content_type,
1115  std::string &boundary) {
1116  auto pos = content_type.find("boundary=");
1117  if (pos == std::string::npos) { return false; }
1118 
1119  boundary = content_type.substr(pos + 9);
1120  return true;
1121 }
1122 
1123 inline bool parse_multipart_formdata(const std::string &boundary,
1124  const std::string &body,
1125  MultipartFiles &files) {
1126  static std::string dash = "--";
1127  static std::string crlf = "\r\n";
1128 
1129  static std::regex re_content_type("Content-Type: (.*?)",
1130  std::regex_constants::icase);
1131 
1132  static std::regex re_content_disposition(
1133  "Content-Disposition: form-data; name=\"(.*?)\"(?:; filename=\"(.*?)\")?",
1134  std::regex_constants::icase);
1135 
1136  auto dash_boundary = dash + boundary;
1137 
1138  auto pos = body.find(dash_boundary);
1139  if (pos != 0) { return false; }
1140 
1141  pos += dash_boundary.size();
1142 
1143  auto next_pos = body.find(crlf, pos);
1144  if (next_pos == std::string::npos) { return false; }
1145 
1146  pos = next_pos + crlf.size();
1147 
1148  while (pos < body.size()) {
1149  next_pos = body.find(crlf, pos);
1150  if (next_pos == std::string::npos) { return false; }
1151 
1152  std::string name;
1153  MultipartFile file;
1154 
1155  auto header = body.substr(pos, (next_pos - pos));
1156 
1157  while (pos != next_pos) {
1158  std::smatch m;
1159  if (std::regex_match(header, m, re_content_type)) {
1160  file.content_type = m[1];
1161  } else if (std::regex_match(header, m, re_content_disposition)) {
1162  name = m[1];
1163  file.filename = m[2];
1164  }
1165 
1166  pos = next_pos + crlf.size();
1167 
1168  next_pos = body.find(crlf, pos);
1169  if (next_pos == std::string::npos) { return false; }
1170 
1171  header = body.substr(pos, (next_pos - pos));
1172  }
1173 
1174  pos = next_pos + crlf.size();
1175 
1176  next_pos = body.find(crlf + dash_boundary, pos);
1177 
1178  if (next_pos == std::string::npos) { return false; }
1179 
1180  file.offset = pos;
1181  file.length = next_pos - pos;
1182 
1183  pos = next_pos + crlf.size() + dash_boundary.size();
1184 
1185  next_pos = body.find(crlf, pos);
1186  if (next_pos == std::string::npos) { return false; }
1187 
1188  files.emplace(name, file);
1189 
1190  pos = next_pos + crlf.size();
1191  }
1192 
1193  return true;
1194 }
1195 
1196 inline std::string to_lower(const char *beg, const char *end) {
1197  std::string out;
1198  auto it = beg;
1199  while (it != end) {
1200  out += ::tolower(*it);
1201  it++;
1202  }
1203  return out;
1204 }
1205 
1206 inline void make_range_header_core(std::string &) {}
1207 
1208 template <typename uint64_t>
1209 inline void make_range_header_core(std::string &field, uint64_t value) {
1210  if (!field.empty()) { field += ", "; }
1211  field += std::to_string(value) + "-";
1212 }
1213 
1214 template <typename uint64_t, typename... Args>
1215 inline void make_range_header_core(std::string &field, uint64_t value1,
1216  uint64_t value2, Args... args) {
1217  if (!field.empty()) { field += ", "; }
1218  field += std::to_string(value1) + "-" + std::to_string(value2);
1219  make_range_header_core(field, args...);
1220 }
1221 
1222 #ifdef CPPHTTPLIB_ZLIB_SUPPORT
1223 inline bool can_compress(const std::string &content_type) {
1224  return !content_type.find("text/") || content_type == "image/svg+xml" ||
1225  content_type == "application/javascript" ||
1226  content_type == "application/json" ||
1227  content_type == "application/xml" ||
1228  content_type == "application/xhtml+xml";
1229 }
1230 
1231 inline void compress(std::string &content) {
1232  z_stream strm;
1233  strm.zalloc = Z_NULL;
1234  strm.zfree = Z_NULL;
1235  strm.opaque = Z_NULL;
1236 
1237  auto ret = deflateInit2(&strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 31, 8,
1239  if (ret != Z_OK) { return; }
1240 
1241  strm.avail_in = content.size();
1242  strm.next_in = (Bytef *)content.data();
1243 
1244  std::string compressed;
1245 
1246  const auto bufsiz = 16384;
1247  char buff[bufsiz];
1248  do {
1249  strm.avail_out = bufsiz;
1250  strm.next_out = (Bytef *)buff;
1251  deflate(&strm, Z_FINISH);
1252  compressed.append(buff, bufsiz - strm.avail_out);
1253  } while (strm.avail_out == 0);
1254 
1255  content.swap(compressed);
1256 
1257  deflateEnd(&strm);
1258 }
1259 
1260 inline void decompress(std::string &content) {
1261  z_stream strm;
1262  strm.zalloc = Z_NULL;
1263  strm.zfree = Z_NULL;
1264  strm.opaque = Z_NULL;
1265 
1266  // 15 is the value of wbits, which should be at the maximum possible value to
1267  // ensure that any gzip stream can be decoded. The offset of 16 specifies that
1268  // the stream to decompress will be formatted with a gzip wrapper.
1269  auto ret = inflateInit2(&strm, 16 + 15);
1270  if (ret != Z_OK) { return; }
1271 
1272  strm.avail_in = content.size();
1273  strm.next_in = (Bytef *)content.data();
1274 
1275  std::string decompressed;
1276 
1277  const auto bufsiz = 16384;
1278  char buff[bufsiz];
1279  do {
1280  strm.avail_out = bufsiz;
1281  strm.next_out = (Bytef *)buff;
1282  inflate(&strm, Z_NO_FLUSH);
1283  decompressed.append(buff, bufsiz - strm.avail_out);
1284  } while (strm.avail_out == 0);
1285 
1286  content.swap(decompressed);
1287 
1288  inflateEnd(&strm);
1289 }
1290 #endif
1291 
1292 #ifdef _WIN32
1293 class WSInit {
1294 public:
1295  WSInit() {
1296  WSADATA wsaData;
1297  WSAStartup(0x0002, &wsaData);
1298  }
1299 
1300  ~WSInit() { WSACleanup(); }
1301 };
1302 
1303 static WSInit wsinit_;
1304 #endif
1305 
1306 } // namespace detail
1307 
1308 // Header utilities
1309 template <typename uint64_t, typename... Args>
1310 inline std::pair<std::string, std::string> make_range_header(uint64_t value,
1311  Args... args) {
1312  std::string field;
1313  detail::make_range_header_core(field, value, args...);
1314  field.insert(0, "bytes=");
1315  return std::make_pair("Range", field);
1316 }
1317 
1318 // Request implementation
1319 inline bool Request::has_header(const char *key) const {
1320  return detail::has_header(headers, key);
1321 }
1322 
1323 inline std::string Request::get_header_value(const char *key, size_t id) const {
1324  return detail::get_header_value(headers, key, id, "");
1325 }
1326 
1327 inline size_t Request::get_header_value_count(const char *key) const {
1328  auto r = headers.equal_range(key);
1329  return std::distance(r.first, r.second);
1330 }
1331 
1332 inline void Request::set_header(const char *key, const char *val) {
1333  headers.emplace(key, val);
1334 }
1335 
1336 inline bool Request::has_param(const char *key) const {
1337  return params.find(key) != params.end();
1338 }
1339 
1340 inline std::string Request::get_param_value(const char *key, size_t id) const {
1341  auto it = params.find(key);
1342  std::advance(it, id);
1343  if (it != params.end()) { return it->second; }
1344  return std::string();
1345 }
1346 
1347 inline size_t Request::get_param_value_count(const char *key) const {
1348  auto r = params.equal_range(key);
1349  return std::distance(r.first, r.second);
1350 }
1351 
1352 inline bool Request::has_file(const char *key) const {
1353  return files.find(key) != files.end();
1354 }
1355 
1356 inline MultipartFile Request::get_file_value(const char *key) const {
1357  auto it = files.find(key);
1358  if (it != files.end()) { return it->second; }
1359  return MultipartFile();
1360 }
1361 
1362 // Response implementation
1363 inline bool Response::has_header(const char *key) const {
1364  return headers.find(key) != headers.end();
1365 }
1366 
1367 inline std::string Response::get_header_value(const char *key,
1368  size_t id) const {
1369  return detail::get_header_value(headers, key, id, "");
1370 }
1371 
1372 inline size_t Response::get_header_value_count(const char *key) const {
1373  auto r = headers.equal_range(key);
1374  return std::distance(r.first, r.second);
1375 }
1376 
1377 inline void Response::set_header(const char *key, const char *val) {
1378  headers.emplace(key, val);
1379 }
1380 
1381 inline void Response::set_redirect(const char *url) {
1382  set_header("Location", url);
1383  status = 302;
1384 }
1385 
1386 inline void Response::set_content(const char *s, size_t n,
1387  const char *content_type) {
1388  body.assign(s, n);
1389  set_header("Content-Type", content_type);
1390 }
1391 
1392 inline void Response::set_content(const std::string &s,
1393  const char *content_type) {
1394  body = s;
1395  set_header("Content-Type", content_type);
1396 }
1397 
1398 // Rstream implementation
1399 template <typename... Args>
1400 inline void Stream::write_format(const char *fmt, const Args &... args) {
1401  const auto bufsiz = 2048;
1402  char buf[bufsiz];
1403 
1404 #if defined(_MSC_VER) && _MSC_VER < 1900
1405  auto n = _snprintf_s(buf, bufsiz, bufsiz - 1, fmt, args...);
1406 #else
1407  auto n = snprintf(buf, bufsiz - 1, fmt, args...);
1408 #endif
1409  if (n > 0) {
1410  if (n >= bufsiz - 1) {
1411  std::vector<char> glowable_buf(bufsiz);
1412 
1413  while (n >= static_cast<int>(glowable_buf.size() - 1)) {
1414  glowable_buf.resize(glowable_buf.size() * 2);
1415 #if defined(_MSC_VER) && _MSC_VER < 1900
1416  n = _snprintf_s(&glowable_buf[0], glowable_buf.size(),
1417  glowable_buf.size() - 1, fmt, args...);
1418 #else
1419  n = snprintf(&glowable_buf[0], glowable_buf.size() - 1, fmt, args...);
1420 #endif
1421  }
1422  write(&glowable_buf[0], n);
1423  } else {
1424  write(buf, n);
1425  }
1426  }
1427 }
1428 
1429 // Socket stream implementation
1430 inline SocketStream::SocketStream(socket_t sock) : sock_(sock) {}
1431 
1432 inline SocketStream::~SocketStream() {}
1433 
1434 inline int SocketStream::read(char *ptr, size_t size) {
1435  return recv(sock_, ptr, static_cast<int>(size), 0);
1436 }
1437 
1438 inline int SocketStream::write(const char *ptr, size_t size) {
1439  return send(sock_, ptr, static_cast<int>(size), 0);
1440 }
1441 
1442 inline int SocketStream::write(const char *ptr) {
1443  return write(ptr, strlen(ptr));
1444 }
1445 
1446 inline std::string SocketStream::get_remote_addr() const {
1447  return detail::get_remote_addr(sock_);
1448 }
1449 
1450 // Buffer stream implementation
1451 inline int BufferStream::read(char *ptr, size_t size) {
1452 #if defined(_MSC_VER) && _MSC_VER < 1900
1453  return static_cast<int>(buffer._Copy_s(ptr, size, size));
1454 #else
1455  return static_cast<int>(buffer.copy(ptr, size));
1456 #endif
1457 }
1458 
1459 inline int BufferStream::write(const char *ptr, size_t size) {
1460  buffer.append(ptr, size);
1461  return static_cast<int>(size);
1462 }
1463 
1464 inline int BufferStream::write(const char *ptr) {
1465  size_t size = strlen(ptr);
1466  buffer.append(ptr, size);
1467  return static_cast<int>(size);
1468 }
1469 
1470 inline std::string BufferStream::get_remote_addr() const { return ""; }
1471 
1472 inline const std::string &BufferStream::get_buffer() const { return buffer; }
1473 
1474 // HTTP server implementation
1475 inline Server::Server()
1476  : keep_alive_max_count_(CPPHTTPLIB_KEEPALIVE_MAX_COUNT),
1477  payload_max_length_(CPPHTTPLIB_PAYLOAD_MAX_LENGTH), is_running_(false),
1478  svr_sock_(INVALID_SOCKET), running_threads_(0) {
1479 #ifndef _WIN32
1480  signal(SIGPIPE, SIG_IGN);
1481 #endif
1482 }
1483 
1484 inline Server::~Server() {}
1485 
1486 inline Server &Server::Get(const char *pattern, Handler handler) {
1487  get_handlers_.push_back(std::make_pair(std::regex(pattern), handler));
1488  return *this;
1489 }
1490 
1491 inline Server &Server::Post(const char *pattern, Handler handler) {
1492  post_handlers_.push_back(std::make_pair(std::regex(pattern), handler));
1493  return *this;
1494 }
1495 
1496 inline Server &Server::Put(const char *pattern, Handler handler) {
1497  put_handlers_.push_back(std::make_pair(std::regex(pattern), handler));
1498  return *this;
1499 }
1500 
1501 inline Server &Server::Patch(const char *pattern, Handler handler) {
1502  patch_handlers_.push_back(std::make_pair(std::regex(pattern), handler));
1503  return *this;
1504 }
1505 
1506 inline Server &Server::Delete(const char *pattern, Handler handler) {
1507  delete_handlers_.push_back(std::make_pair(std::regex(pattern), handler));
1508  return *this;
1509 }
1510 
1511 inline Server &Server::Options(const char *pattern, Handler handler) {
1512  options_handlers_.push_back(std::make_pair(std::regex(pattern), handler));
1513  return *this;
1514 }
1515 
1516 inline bool Server::set_base_dir(const char *path) {
1517  if (detail::is_dir(path)) {
1518  base_dir_ = path;
1519  return true;
1520  }
1521  return false;
1522 }
1523 
1524 inline void Server::set_error_handler(Handler handler) {
1525  error_handler_ = handler;
1526 }
1527 
1528 inline void Server::set_logger(Logger logger) { logger_ = logger; }
1529 
1530 inline void Server::set_keep_alive_max_count(size_t count) {
1531  keep_alive_max_count_ = count;
1532 }
1533 
1534 inline void Server::set_payload_max_length(uint64_t length) {
1535  payload_max_length_ = length;
1536 }
1537 
1538 inline int Server::bind_to_any_port(const char *host, int socket_flags) {
1539  return bind_internal(host, 0, socket_flags);
1540 }
1541 
1542 inline bool Server::listen_after_bind() { return listen_internal(); }
1543 
1544 inline bool Server::listen(const char *host, int port, int socket_flags) {
1545  if (bind_internal(host, port, socket_flags) < 0) return false;
1546  return listen_internal();
1547 }
1548 
1549 inline bool Server::is_running() const { return is_running_; }
1550 
1551 inline void Server::stop() {
1552  if (is_running_) {
1553  assert(svr_sock_ != INVALID_SOCKET);
1554  auto sock = svr_sock_;
1555  svr_sock_ = INVALID_SOCKET;
1556  detail::shutdown_socket(sock);
1557  detail::close_socket(sock);
1558  }
1559 }
1560 
1561 inline bool Server::parse_request_line(const char *s, Request &req) {
1562  static std::regex re("(GET|HEAD|POST|PUT|PATCH|DELETE|OPTIONS) "
1563  "(([^?]+)(?:\\?(.+?))?) (HTTP/1\\.[01])\r\n");
1564 
1565  std::cmatch m;
1566  if (std::regex_match(s, m, re)) {
1567  req.version = std::string(m[5]);
1568  req.method = std::string(m[1]);
1569  req.target = std::string(m[2]);
1570  req.path = detail::decode_url(m[3]);
1571 
1572  // Parse query text
1573  auto len = std::distance(m[4].first, m[4].second);
1574  if (len > 0) { detail::parse_query_text(m[4], req.params); }
1575 
1576  return true;
1577  }
1578 
1579  return false;
1580 }
1581 
1582 inline void Server::write_response(Stream &strm, bool last_connection,
1583  const Request &req, Response &res) {
1584  assert(res.status != -1);
1585 
1586  if (400 <= res.status && error_handler_) { error_handler_(req, res); }
1587 
1588  // Response line
1589  strm.write_format("HTTP/1.1 %d %s\r\n", res.status,
1590  detail::status_message(res.status));
1591 
1592  // Headers
1593  if (last_connection || req.get_header_value("Connection") == "close") {
1594  res.set_header("Connection", "close");
1595  }
1596 
1597  if (!last_connection && req.get_header_value("Connection") == "Keep-Alive") {
1598  res.set_header("Connection", "Keep-Alive");
1599  }
1600  res.set_header("Access-Control-Allow-Origin", "*") ;
1601  if (res.body.empty()) {
1602  if (!res.has_header("Content-Length")) {
1603  if (res.streamcb) {
1604  // Streamed response
1605  res.set_header("Transfer-Encoding", "chunked");
1606  } else {
1607  res.set_header("Content-Length", "0");
1608  }
1609  }
1610  } else {
1611 #ifdef CPPHTTPLIB_ZLIB_SUPPORT
1612  // TODO: 'Accpet-Encoding' has gzip, not gzip;q=0
1613  const auto &encodings = req.get_header_value("Accept-Encoding");
1614  if (encodings.find("gzip") != std::string::npos &&
1615  detail::can_compress(res.get_header_value("Content-Type"))) {
1616  detail::compress(res.body);
1617  res.set_header("Content-Encoding", "gzip");
1618  }
1619 #endif
1620 
1621  if (!res.has_header("Content-Type")) {
1622  res.set_header("Content-Type", "text/plain");
1623  }
1624 
1625  auto length = std::to_string(res.body.size());
1626  res.set_header("Content-Length", length.c_str());
1627  }
1628 
1629  detail::write_headers(strm, res);
1630 
1631  // Body
1632  if (req.method != "HEAD") {
1633  if (!res.body.empty()) {
1634  strm.write(res.body.c_str(), res.body.size());
1635  } else if (res.streamcb) {
1636  bool chunked_response = !res.has_header("Content-Length");
1637  uint64_t offset = 0;
1638  bool data_available = true;
1639  while (data_available) {
1640  std::string chunk = res.streamcb(offset);
1641  offset += chunk.size();
1642  data_available = !chunk.empty();
1643  // Emit chunked response header and footer for each chunk
1644  if (chunked_response)
1645  chunk = detail::from_i_to_hex(chunk.size()) + "\r\n" + chunk + "\r\n";
1646  if (strm.write(chunk.c_str(), chunk.size()) < 0) break; // Stop on error
1647  }
1648  }
1649  }
1650 
1651  // Log
1652  if (logger_) { logger_(req, res); }
1653 }
1654 
1655 inline bool Server::handle_file_request(Request &req, Response &res) {
1656  if (!base_dir_.empty() && detail::is_valid_path(req.path)) {
1657  std::string path = base_dir_ + req.path;
1658 
1659  if (!path.empty() && path.back() == '/') { path += "index.html"; }
1660 
1661  if (detail::is_file(path)) {
1662  detail::read_file(path, res.body);
1663  auto type = detail::find_content_type(path);
1664  if (type) { res.set_header("Content-Type", type); }
1665  res.status = 200;
1666  return true;
1667  }
1668  }
1669 
1670  return false;
1671 }
1672 
1673 inline socket_t Server::create_server_socket(const char *host, int port,
1674  int socket_flags) const {
1675  return detail::create_socket(
1676  host, port,
1677  [](socket_t sock, struct addrinfo &ai) -> bool {
1678  if (::bind(sock, ai.ai_addr, static_cast<int>(ai.ai_addrlen))) {
1679  return false;
1680  }
1681  if (::listen(sock, 5)) { // Listen through 5 channels
1682  return false;
1683  }
1684  return true;
1685  },
1686  socket_flags);
1687 }
1688 
1689 inline int Server::bind_internal(const char *host, int port, int socket_flags) {
1690  if (!is_valid()) { return -1; }
1691 
1692  svr_sock_ = create_server_socket(host, port, socket_flags);
1693  if (svr_sock_ == INVALID_SOCKET) { return -1; }
1694 
1695  if (port == 0) {
1696  struct sockaddr_storage address;
1697  socklen_t len = sizeof(address);
1698  if (getsockname(svr_sock_, reinterpret_cast<struct sockaddr *>(&address),
1699  &len) == -1) {
1700  return -1;
1701  }
1702  if (address.ss_family == AF_INET) {
1703  return ntohs(reinterpret_cast<struct sockaddr_in *>(&address)->sin_port);
1704  } else if (address.ss_family == AF_INET6) {
1705  return ntohs(
1706  reinterpret_cast<struct sockaddr_in6 *>(&address)->sin6_port);
1707  } else {
1708  return -1;
1709  }
1710  } else {
1711  return port;
1712  }
1713 }
1714 
1715 inline bool Server::listen_internal() {
1716  auto ret = true;
1717 
1718  is_running_ = true;
1719 
1720  for (;;) {
1721  auto val = detail::select_read(svr_sock_, 0, 100000);
1722 
1723  if (val == 0) { // Timeout
1724  if (svr_sock_ == INVALID_SOCKET) {
1725  // The server socket was closed by 'stop' method.
1726  break;
1727  }
1728  continue;
1729  }
1730 
1731  socket_t sock = accept(svr_sock_, nullptr, nullptr);
1732 
1733  if (sock == INVALID_SOCKET) {
1734  if (svr_sock_ != INVALID_SOCKET) {
1735  detail::close_socket(svr_sock_);
1736  ret = false;
1737  } else {
1738  ; // The server socket was closed by user.
1739  }
1740  break;
1741  }
1742 
1743  // TODO: Use thread pool...
1744  std::thread([=]() {
1745  {
1746  std::lock_guard<std::mutex> guard(running_threads_mutex_);
1747  running_threads_++;
1748  }
1749 
1750  read_and_close_socket(sock);
1751 
1752  {
1753  std::lock_guard<std::mutex> guard(running_threads_mutex_);
1754  running_threads_--;
1755  }
1756  }).detach();
1757  }
1758 
1759  // TODO: Use thread pool...
1760  for (;;) {
1761  std::this_thread::sleep_for(std::chrono::milliseconds(10));
1762  std::lock_guard<std::mutex> guard(running_threads_mutex_);
1763  if (!running_threads_) { break; }
1764  }
1765 
1766  is_running_ = false;
1767 
1768  return ret;
1769 }
1770 
1771 inline bool Server::routing(Request &req, Response &res) {
1772  if (req.method == "GET" && handle_file_request(req, res)) { return true; }
1773 
1774  if (req.method == "GET" || req.method == "HEAD") {
1775  return dispatch_request(req, res, get_handlers_);
1776  } else if (req.method == "POST") {
1777  return dispatch_request(req, res, post_handlers_);
1778  } else if (req.method == "PUT") {
1779  return dispatch_request(req, res, put_handlers_);
1780  } else if (req.method == "PATCH") {
1781  return dispatch_request(req, res, patch_handlers_);
1782  } else if (req.method == "DELETE") {
1783  return dispatch_request(req, res, delete_handlers_);
1784  } else if (req.method == "OPTIONS") {
1785  return dispatch_request(req, res, options_handlers_);
1786  }
1787  return false;
1788 }
1789 
1790 inline bool Server::dispatch_request(Request &req, Response &res,
1791  Handlers &handlers) {
1792  for (const auto &x : handlers) {
1793  const auto &pattern = x.first;
1794  const auto &handler = x.second;
1795 
1796  if (std::regex_match(req.path, req.matches, pattern)) {
1797  handler(req, res);
1798  return true;
1799  }
1800  }
1801  return false;
1802 }
1803 
1804 inline bool Server::process_request(Stream &strm, bool last_connection,
1805  bool &connection_close) {
1806  const auto bufsiz = 2048;
1807  char buf[bufsiz];
1808 
1809  detail::stream_line_reader reader(strm, buf, bufsiz);
1810 
1811  // Connection has been closed on client
1812  if (!reader.getline()) { return false; }
1813 
1814  Request req;
1815  Response res;
1816 
1817  res.version = "HTTP/1.1";
1818 
1819  // Check if the request URI doesn't exceed the limit
1820  if (reader.size() > CPPHTTPLIB_REQUEST_URI_MAX_LENGTH) {
1821  res.status = 414;
1822  write_response(strm, last_connection, req, res);
1823  return true;
1824  }
1825 
1826  // Request line and headers
1827  if (!parse_request_line(reader.ptr(), req) ||
1828  !detail::read_headers(strm, req.headers)) {
1829  res.status = 400;
1830  write_response(strm, last_connection, req, res);
1831  return true;
1832  }
1833 
1834  if (req.get_header_value("Connection") == "close") {
1835  connection_close = true;
1836  }
1837 
1838  req.set_header("REMOTE_ADDR", strm.get_remote_addr().c_str());
1839 
1840  // Body
1841  if (req.method == "POST" || req.method == "PUT" || req.method == "PATCH") {
1842  bool exceed_payload_max_length = false;
1843  if (!detail::read_content(strm, req, payload_max_length_,
1844  exceed_payload_max_length)) {
1845  res.status = exceed_payload_max_length ? 413 : 400;
1846  write_response(strm, last_connection, req, res);
1847  return !exceed_payload_max_length;
1848  }
1849 
1850  const auto &content_type = req.get_header_value("Content-Type");
1851 
1852  if (req.get_header_value("Content-Encoding") == "gzip") {
1853 #ifdef CPPHTTPLIB_ZLIB_SUPPORT
1854  detail::decompress(req.body);
1855 #else
1856  res.status = 415;
1857  write_response(strm, last_connection, req, res);
1858  return true;
1859 #endif
1860  }
1861 
1862  if (!content_type.find("application/x-www-form-urlencoded")) {
1863  detail::parse_query_text(req.body, req.params);
1864  } else if (!content_type.find("multipart/form-data")) {
1865  std::string boundary;
1866  if (!detail::parse_multipart_boundary(content_type, boundary) ||
1867  !detail::parse_multipart_formdata(boundary, req.body, req.files)) {
1868  res.status = 400;
1869  write_response(strm, last_connection, req, res);
1870  return true;
1871  }
1872  }
1873  }
1874 
1875  if (routing(req, res)) {
1876  if (res.status == -1) { res.status = 200; }
1877  } else {
1878  res.status = 404;
1879  }
1880 
1881  write_response(strm, last_connection, req, res);
1882  return true;
1883 }
1884 
1885 inline bool Server::is_valid() const { return true; }
1886 
1887 inline bool Server::read_and_close_socket(socket_t sock) {
1888  return detail::read_and_close_socket(
1889  sock, keep_alive_max_count_,
1890  [this](Stream &strm, bool last_connection, bool &connection_close) {
1891  return process_request(strm, last_connection, connection_close);
1892  });
1893 }
1894 
1895 // HTTP client implementation
1896 inline Client::Client(const char *host, int port, time_t timeout_sec)
1897  : host_(host), port_(port), timeout_sec_(timeout_sec),
1898  host_and_port_(host_ + ":" + std::to_string(port_)) {}
1899 
1900 inline Client::~Client() {}
1901 
1902 inline bool Client::is_valid() const { return true; }
1903 
1904 inline socket_t Client::create_client_socket() const {
1905  return detail::create_socket(
1906  host_.c_str(), port_, [=](socket_t sock, struct addrinfo &ai) -> bool {
1907  detail::set_nonblocking(sock, true);
1908 
1909  auto ret = connect(sock, ai.ai_addr, static_cast<int>(ai.ai_addrlen));
1910  if (ret < 0) {
1911  if (detail::is_connection_error() ||
1912  !detail::wait_until_socket_is_ready(sock, timeout_sec_, 0)) {
1913  detail::close_socket(sock);
1914  return false;
1915  }
1916  }
1917 
1918  detail::set_nonblocking(sock, false);
1919  return true;
1920  });
1921 }
1922 
1923 inline bool Client::read_response_line(Stream &strm, Response &res) {
1924  const auto bufsiz = 2048;
1925  char buf[bufsiz];
1926 
1927  detail::stream_line_reader reader(strm, buf, bufsiz);
1928 
1929  if (!reader.getline()) { return false; }
1930 
1931  const static std::regex re("(HTTP/1\\.[01]) (\\d+?) .*\r\n");
1932 
1933  std::cmatch m;
1934  if (std::regex_match(reader.ptr(), m, re)) {
1935  res.version = std::string(m[1]);
1936  res.status = std::stoi(std::string(m[2]));
1937  }
1938 
1939  return true;
1940 }
1941 
1942 inline bool Client::send(Request &req, Response &res) {
1943  if (req.path.empty()) { return false; }
1944 
1945  auto sock = create_client_socket();
1946  if (sock == INVALID_SOCKET) { return false; }
1947 
1948  return read_and_close_socket(sock, req, res);
1949 }
1950 
1951 inline void Client::write_request(Stream &strm, Request &req) {
1952  BufferStream bstrm;
1953 
1954  // Request line
1955  auto path = detail::encode_url(req.path);
1956 
1957  bstrm.write_format("%s %s HTTP/1.1\r\n", req.method.c_str(), path.c_str());
1958 
1959  // Headers
1960  if (!req.has_header("Host")) {
1961  if (is_ssl()) {
1962  if (port_ == 443) {
1963  req.set_header("Host", host_.c_str());
1964  } else {
1965  req.set_header("Host", host_and_port_.c_str());
1966  }
1967  } else {
1968  if (port_ == 80) {
1969  req.set_header("Host", host_.c_str());
1970  } else {
1971  req.set_header("Host", host_and_port_.c_str());
1972  }
1973  }
1974  }
1975 
1976  if (!req.has_header("Accept")) { req.set_header("Accept", "*/*"); }
1977 
1978  if (!req.has_header("User-Agent")) {
1979  req.set_header("User-Agent", "cpp-httplib/0.2");
1980  }
1981 
1982  // TODO: Support KeepAlive connection
1983  // if (!req.has_header("Connection")) {
1984  req.set_header("Connection", "close");
1985  // }
1986 
1987  if (req.body.empty()) {
1988  if (req.method == "POST" || req.method == "PUT" || req.method == "PATCH") {
1989  req.set_header("Content-Length", "0");
1990  }
1991  } else {
1992  if (!req.has_header("Content-Type")) {
1993  req.set_header("Content-Type", "text/plain");
1994  }
1995 
1996  if (!req.has_header("Content-Length")) {
1997  auto length = std::to_string(req.body.size());
1998  req.set_header("Content-Length", length.c_str());
1999  }
2000  }
2001 
2002  detail::write_headers(bstrm, req);
2003 
2004  // Body
2005  if (!req.body.empty()) { bstrm.write(req.body.c_str(), req.body.size()); }
2006 
2007  // Flush buffer
2008  auto &data = bstrm.get_buffer();
2009  strm.write(data.data(), data.size());
2010 }
2011 
2012 inline bool Client::process_request(Stream &strm, Request &req, Response &res,
2013  bool &connection_close) {
2014  // Send request
2015  write_request(strm, req);
2016 
2017  // Receive response and headers
2018  if (!read_response_line(strm, res) ||
2019  !detail::read_headers(strm, res.headers)) {
2020  return false;
2021  }
2022 
2023  if (res.get_header_value("Connection") == "close" ||
2024  res.version == "HTTP/1.0") {
2025  connection_close = true;
2026  }
2027 
2028  // Body
2029  if (req.method != "HEAD") {
2030  bool exceed_payload_max_length = false;
2031  if (!detail::read_content(strm, res, std::numeric_limits<uint64_t>::max(),
2032  exceed_payload_max_length, req.progress)) {
2033  return false;
2034  }
2035 
2036  if (res.get_header_value("Content-Encoding") == "gzip") {
2037 #ifdef CPPHTTPLIB_ZLIB_SUPPORT
2038  detail::decompress(res.body);
2039 #else
2040  return false;
2041 #endif
2042  }
2043  }
2044 
2045  return true;
2046 }
2047 
2048 inline bool Client::read_and_close_socket(socket_t sock, Request &req,
2049  Response &res) {
2050  return detail::read_and_close_socket(
2051  sock, 0,
2052  [&](Stream &strm, bool /*last_connection*/, bool &connection_close) {
2053  return process_request(strm, req, res, connection_close);
2054  });
2055 }
2056 
2057 inline bool Client::is_ssl() const { return false; }
2058 
2059 inline std::shared_ptr<Response> Client::Get(const char *path,
2060  Progress progress) {
2061  return Get(path, Headers(), progress);
2062 }
2063 
2064 inline std::shared_ptr<Response>
2065 Client::Get(const char *path, const Headers &headers, Progress progress) {
2066  Request req;
2067  req.method = "GET";
2068  req.path = path;
2069  req.headers = headers;
2070  req.progress = progress;
2071 
2072  auto res = std::make_shared<Response>();
2073 
2074  return send(req, *res) ? res : nullptr;
2075 }
2076 
2077 inline std::shared_ptr<Response> Client::Head(const char *path) {
2078  return Head(path, Headers());
2079 }
2080 
2081 inline std::shared_ptr<Response> Client::Head(const char *path,
2082  const Headers &headers) {
2083  Request req;
2084  req.method = "HEAD";
2085  req.headers = headers;
2086  req.path = path;
2087 
2088  auto res = std::make_shared<Response>();
2089 
2090  return send(req, *res) ? res : nullptr;
2091 }
2092 
2093 inline std::shared_ptr<Response> Client::Post(const char *path,
2094  const std::string &body,
2095  const char *content_type) {
2096  return Post(path, Headers(), body, content_type);
2097 }
2098 
2099 inline std::shared_ptr<Response> Client::Post(const char *path,
2100  const Headers &headers,
2101  const std::string &body,
2102  const char *content_type) {
2103  Request req;
2104  req.method = "POST";
2105  req.headers = headers;
2106  req.path = path;
2107 
2108  req.headers.emplace("Content-Type", content_type);
2109  req.body = body;
2110 
2111  auto res = std::make_shared<Response>();
2112 
2113  return send(req, *res) ? res : nullptr;
2114 }
2115 
2116 inline std::shared_ptr<Response> Client::Post(const char *path,
2117  const Params &params) {
2118  return Post(path, Headers(), params);
2119 }
2120 
2121 inline std::shared_ptr<Response>
2122 Client::Post(const char *path, const Headers &headers, const Params &params) {
2123  std::string query;
2124  for (auto it = params.begin(); it != params.end(); ++it) {
2125  if (it != params.begin()) { query += "&"; }
2126  query += it->first;
2127  query += "=";
2128  query += detail::encode_url(it->second);
2129  }
2130 
2131  return Post(path, headers, query, "application/x-www-form-urlencoded");
2132 }
2133 
2134 inline std::shared_ptr<Response> Client::Put(const char *path,
2135  const std::string &body,
2136  const char *content_type) {
2137  return Put(path, Headers(), body, content_type);
2138 }
2139 
2140 inline std::shared_ptr<Response> Client::Put(const char *path,
2141  const Headers &headers,
2142  const std::string &body,
2143  const char *content_type) {
2144  Request req;
2145  req.method = "PUT";
2146  req.headers = headers;
2147  req.path = path;
2148 
2149  req.headers.emplace("Content-Type", content_type);
2150  req.body = body;
2151 
2152  auto res = std::make_shared<Response>();
2153 
2154  return send(req, *res) ? res : nullptr;
2155 }
2156 
2157 inline std::shared_ptr<Response> Client::Patch(const char *path,
2158  const std::string &body,
2159  const char *content_type) {
2160  return Patch(path, Headers(), body, content_type);
2161 }
2162 
2163 inline std::shared_ptr<Response> Client::Patch(const char *path,
2164  const Headers &headers,
2165  const std::string &body,
2166  const char *content_type) {
2167  Request req;
2168  req.method = "PATCH";
2169  req.headers = headers;
2170  req.path = path;
2171 
2172  req.headers.emplace("Content-Type", content_type);
2173  req.body = body;
2174 
2175  auto res = std::make_shared<Response>();
2176 
2177  return send(req, *res) ? res : nullptr;
2178 }
2179 
2180 inline std::shared_ptr<Response> Client::Delete(const char *path,
2181  const std::string &body,
2182  const char *content_type) {
2183  return Delete(path, Headers(), body, content_type);
2184 }
2185 
2186 inline std::shared_ptr<Response> Client::Delete(const char *path,
2187  const Headers &headers,
2188  const std::string &body,
2189  const char *content_type) {
2190  Request req;
2191  req.method = "DELETE";
2192  req.headers = headers;
2193  req.path = path;
2194 
2195  if (content_type) { req.headers.emplace("Content-Type", content_type); }
2196  req.body = body;
2197 
2198  auto res = std::make_shared<Response>();
2199 
2200  return send(req, *res) ? res : nullptr;
2201 }
2202 
2203 inline std::shared_ptr<Response> Client::Options(const char *path) {
2204  return Options(path, Headers());
2205 }
2206 
2207 inline std::shared_ptr<Response> Client::Options(const char *path,
2208  const Headers &headers) {
2209  Request req;
2210  req.method = "OPTIONS";
2211  req.path = path;
2212  req.headers = headers;
2213 
2214  auto res = std::make_shared<Response>();
2215 
2216  return send(req, *res) ? res : nullptr;
2217 }
2218 
2219 /*
2220  * SSL Implementation
2221  */
2222 #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
2223 namespace detail {
2224 
2225 template <typename U, typename V, typename T>
2226 inline bool
2227 read_and_close_socket_ssl(socket_t sock, size_t keep_alive_max_count,
2228  // TODO: OpenSSL 1.0.2 occasionally crashes...
2229  // The upcoming 1.1.0 is going to be thread safe.
2230  SSL_CTX *ctx, std::mutex &ctx_mutex,
2231  U SSL_connect_or_accept, V setup, T callback) {
2232  SSL *ssl = nullptr;
2233  {
2234  std::lock_guard<std::mutex> guard(ctx_mutex);
2235 
2236  ssl = SSL_new(ctx);
2237  if (!ssl) { return false; }
2238  }
2239 
2240  auto bio = BIO_new_socket(sock, BIO_NOCLOSE);
2241  SSL_set_bio(ssl, bio, bio);
2242 
2243  if (!setup(ssl)) { return false; }
2244 
2245  bool ret = false;
2246 
2247  if (SSL_connect_or_accept(ssl) == 1) {
2248  if (keep_alive_max_count > 0) {
2249  auto count = keep_alive_max_count;
2250  while (count > 0 &&
2251  detail::select_read(sock, CPPHTTPLIB_KEEPALIVE_TIMEOUT_SECOND,
2253  SSLSocketStream strm(sock, ssl);
2254  auto last_connection = count == 1;
2255  auto connection_close = false;
2256 
2257  ret = callback(strm, last_connection, connection_close);
2258  if (!ret || connection_close) { break; }
2259 
2260  count--;
2261  }
2262  } else {
2263  SSLSocketStream strm(sock, ssl);
2264  auto dummy_connection_close = false;
2265  ret = callback(strm, true, dummy_connection_close);
2266  }
2267 
2268  SSL_shutdown(ssl);
2269 
2270  {
2271  std::lock_guard<std::mutex> guard(ctx_mutex);
2272  SSL_free(ssl);
2273  }
2274 
2275  close_socket(sock);
2276  }
2277 
2278  return ret;
2279 }
2280 
2281 class SSLInit {
2282 public:
2283  SSLInit() {
2284  SSL_load_error_strings();
2285  SSL_library_init();
2286  }
2287 
2288  ~SSLInit() { ERR_free_strings(); }
2289 };
2290 
2291 static SSLInit sslinit_;
2292 
2293 } // namespace detail
2294 
2295 // SSL socket stream implementation
2296 inline SSLSocketStream::SSLSocketStream(socket_t sock, SSL *ssl)
2297  : sock_(sock), ssl_(ssl) {}
2298 
2299 inline SSLSocketStream::~SSLSocketStream() {}
2300 
2301 inline int SSLSocketStream::read(char *ptr, size_t size) {
2302  return SSL_read(ssl_, ptr, size);
2303 }
2304 
2305 inline int SSLSocketStream::write(const char *ptr, size_t size) {
2306  return SSL_write(ssl_, ptr, size);
2307 }
2308 
2309 inline int SSLSocketStream::write(const char *ptr) {
2310  return write(ptr, strlen(ptr));
2311 }
2312 
2313 inline std::string SSLSocketStream::get_remote_addr() const {
2314  return detail::get_remote_addr(sock_);
2315 }
2316 
2317 // SSL HTTP server implementation
2318 inline SSLServer::SSLServer(const char *cert_path,
2319  const char *private_key_path) {
2320  ctx_ = SSL_CTX_new(SSLv23_server_method());
2321 
2322  if (ctx_) {
2323  SSL_CTX_set_options(ctx_,
2324  SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 |
2325  SSL_OP_NO_COMPRESSION |
2326  SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION);
2327 
2328  // auto ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
2329  // SSL_CTX_set_tmp_ecdh(ctx_, ecdh);
2330  // EC_KEY_free(ecdh);
2331 
2332  if (SSL_CTX_use_certificate_chain_file(ctx_, cert_path) != 1 ||
2333  SSL_CTX_use_PrivateKey_file(ctx_, private_key_path, SSL_FILETYPE_PEM) !=
2334  1) {
2335  SSL_CTX_free(ctx_);
2336  ctx_ = nullptr;
2337  }
2338  }
2339 }
2340 
2341 inline SSLServer::~SSLServer() {
2342  if (ctx_) { SSL_CTX_free(ctx_); }
2343 }
2344 
2345 inline bool SSLServer::is_valid() const { return ctx_; }
2346 
2347 inline bool SSLServer::read_and_close_socket(socket_t sock) {
2348  return detail::read_and_close_socket_ssl(
2349  sock, keep_alive_max_count_, ctx_, ctx_mutex_, SSL_accept,
2350  [](SSL * /*ssl*/) { return true; },
2351  [this](Stream &strm, bool last_connection, bool &connection_close) {
2352  return process_request(strm, last_connection, connection_close);
2353  });
2354 }
2355 
2356 // SSL HTTP client implementation
2357 inline SSLClient::SSLClient(const char *host, int port, time_t timeout_sec)
2358  : Client(host, port, timeout_sec) {
2359  ctx_ = SSL_CTX_new(SSLv23_client_method());
2360 
2361  detail::split(&host_[0], &host_[host_.size()], '.',
2362  [&](const char *b, const char *e) {
2363  host_components_.emplace_back(std::string(b, e));
2364  });
2365 }
2366 
2367 inline SSLClient::~SSLClient() {
2368  if (ctx_) { SSL_CTX_free(ctx_); }
2369 }
2370 
2371 inline bool SSLClient::is_valid() const { return ctx_; }
2372 
2373 inline void SSLClient::set_ca_cert_path(const char *ca_cert_path) {
2374  ca_cert_path_ = ca_cert_path;
2375 }
2376 
2377 inline void SSLClient::enable_server_certificate_verification(bool enabled) {
2378  server_certificate_verification_ = enabled;
2379 }
2380 
2381 inline long SSLClient::get_openssl_verify_result() const {
2382  return verify_result_;
2383 }
2384 
2385 inline bool SSLClient::read_and_close_socket(socket_t sock, Request &req,
2386  Response &res) {
2387 
2388  return is_valid() &&
2389  detail::read_and_close_socket_ssl(
2390  sock, 0, ctx_, ctx_mutex_,
2391  [&](SSL *ssl) {
2392  if (ca_cert_path_.empty()) {
2393  SSL_CTX_set_verify(ctx_, SSL_VERIFY_NONE, nullptr);
2394  } else {
2395  if (!SSL_CTX_load_verify_locations(ctx_, ca_cert_path_.c_str(),
2396  nullptr)) {
2397  return false;
2398  }
2399  SSL_CTX_set_verify(ctx_, SSL_VERIFY_PEER, nullptr);
2400  }
2401 
2402  if (SSL_connect(ssl) != 1) { return false; }
2403 
2404  if (server_certificate_verification_) {
2405  verify_result_ = SSL_get_verify_result(ssl);
2406 
2407  if (verify_result_ != X509_V_OK) { return false; }
2408 
2409  auto server_cert = SSL_get_peer_certificate(ssl);
2410 
2411  if (server_cert == nullptr) { return false; }
2412 
2413  if (!verify_host(server_cert)) { return false; }
2414  }
2415 
2416  return true;
2417  },
2418  [&](SSL *ssl) {
2419  SSL_set_tlsext_host_name(ssl, host_.c_str());
2420  return true;
2421  },
2422  [&](Stream &strm, bool /*last_connection*/,
2423  bool &connection_close) {
2424  return process_request(strm, req, res, connection_close);
2425  });
2426 }
2427 
2428 inline bool SSLClient::is_ssl() const { return true; }
2429 
2430 inline bool SSLClient::verify_host(X509 *server_cert) const {
2431  /* Quote from RFC2818 section 3.1 "Server Identity"
2432 
2433  If a subjectAltName extension of type dNSName is present, that MUST
2434  be used as the identity. Otherwise, the (most specific) Common Name
2435  field in the Subject field of the certificate MUST be used. Although
2436  the use of the Common Name is existing practice, it is deprecated and
2437  Certification Authorities are encouraged to use the dNSName instead.
2438 
2439  Matching is performed using the matching rules specified by
2440  [RFC2459]. If more than one identity of a given type is present in
2441  the certificate (e.g., more than one dNSName name, a match in any one
2442  of the set is considered acceptable.) Names may contain the wildcard
2443  character * which is considered to match any single domain name
2444  component or component fragment. E.g., *.a.com matches foo.a.com but
2445  not bar.foo.a.com. f*.com matches foo.com but not bar.com.
2446 
2447  In some cases, the URI is specified as an IP address rather than a
2448  hostname. In this case, the iPAddress subjectAltName must be present
2449  in the certificate and must exactly match the IP in the URI.
2450 
2451  */
2452  return verify_host_with_subject_alt_name(server_cert) ||
2453  verify_host_with_common_name(server_cert);
2454 }
2455 
2456 inline bool
2457 SSLClient::verify_host_with_subject_alt_name(X509 *server_cert) const {
2458  auto ret = false;
2459 
2460  auto type = GEN_DNS;
2461 
2462  struct in6_addr addr6;
2463  struct in_addr addr;
2464  size_t addr_len = 0;
2465 
2466  if (inet_pton(AF_INET6, host_.c_str(), &addr6)) {
2467  type = GEN_IPADD;
2468  addr_len = sizeof(struct in6_addr);
2469  } else if (inet_pton(AF_INET, host_.c_str(), &addr)) {
2470  type = GEN_IPADD;
2471  addr_len = sizeof(struct in_addr);
2472  }
2473 
2474  auto alt_names =
2475  X509_get_ext_d2i(server_cert, NID_subject_alt_name, nullptr, nullptr);
2476 
2477  if (alt_names) {
2478  auto dsn_matched = false;
2479  auto ip_mached = false;
2480 
2481  auto count = sk_GENERAL_NAME_num(alt_names);
2482 
2483  for (auto i = 0; i < count && !dsn_matched; i++) {
2484  auto val = sk_GENERAL_NAME_value(alt_names, i);
2485  if (val->type == type) {
2486  auto name = (const char *)ASN1_STRING_data(val->d.ia5);
2487  auto name_len = (size_t)ASN1_STRING_length(val->d.ia5);
2488 
2489  if (strlen(name) == name_len) {
2490  switch (type) {
2491  case GEN_DNS: dsn_matched = check_host_name(name, name_len); break;
2492 
2493  case GEN_IPADD:
2494  if (!memcmp(&addr6, name, addr_len) ||
2495  !memcmp(&addr, name, addr_len)) {
2496  ip_mached = true;
2497  }
2498  break;
2499  }
2500  }
2501  }
2502  }
2503 
2504  if (dsn_matched || ip_mached) { ret = true; }
2505  }
2506 
2507  GENERAL_NAMES_free((STACK_OF(GENERAL_NAME) *)alt_names);
2508 
2509  return ret;
2510 }
2511 
2512 inline bool SSLClient::verify_host_with_common_name(X509 *server_cert) const {
2513  const auto subject_name = X509_get_subject_name(server_cert);
2514 
2515  if (subject_name != nullptr) {
2516  char name[BUFSIZ];
2517  auto name_len = X509_NAME_get_text_by_NID(subject_name, NID_commonName,
2518  name, sizeof(name));
2519 
2520  if (name_len != -1) { return check_host_name(name, name_len); }
2521  }
2522 
2523  return false;
2524 }
2525 
2526 inline bool SSLClient::check_host_name(const char *pattern,
2527  size_t pattern_len) const {
2528  if (host_.size() == pattern_len && host_ == pattern) {
2529  return true;
2530  }
2531 
2532  // Wildcard match
2533  // https://bugs.launchpad.net/ubuntu/+source/firefox-3.0/+bug/376484
2534  std::vector<std::string> pattern_components;
2535  detail::split(&pattern[0], &pattern[pattern_len], '.',
2536  [&](const char *b, const char *e) {
2537  pattern_components.emplace_back(std::string(b, e));
2538  });
2539 
2540  if (host_components_.size() != pattern_components.size()) { return false; }
2541 
2542  auto itr = pattern_components.begin();
2543  for (const auto &h : host_components_) {
2544  auto &p = *itr;
2545  if (p != h && p != "*") {
2546  auto partial_match = (p.size() > 0 && p[p.size() - 1] == '*' &&
2547  !p.compare(0, p.size() - 1, h));
2548  if (!partial_match) { return false; }
2549  }
2550  ++itr;
2551  }
2552 
2553  return true;
2554 }
2555 #endif
2556 
2557 } // namespace httplib
2558 
2559 #endif // CPPHTTPLIB_HTTPLIB_H
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:25318
#define CPPHTTPLIB_KEEPALIVE_TIMEOUT_USECOND
Definition: Server.h:88
#define CPPHTTPLIB_PAYLOAD_MAX_LENGTH
Definition: Server.h:91
#define INVALID_SOCKET
Definition: Server.h:59
int socket_t
Definition: Server.h:58
#define CPPHTTPLIB_KEEPALIVE_MAX_COUNT
Definition: Server.h:89
#define CPPHTTPLIB_KEEPALIVE_TIMEOUT_SECOND
Definition: Server.h:87
#define CPPHTTPLIB_REQUEST_URI_MAX_LENGTH
Definition: Server.h:90
Concept for receiving events from GenericReader upon parsing. The functions return true if no error o...
Concept for reading and writing characters.
@ pos
Definition: Typedefs.h:19
uint d
type
The type the bitset is encoded with.
Definition: bitset.hpp:44
std::true_type yes
Definition: traits.hpp:49
detail namespace with internal helper functions
Definition: json.hpp:260
Definition: json.hpp:5678
void close(FILE *out)
Definition: Vtk.h:123
const GenericPointer< typename T::ValueType > T2 value
Definition: pointer.h:1282
unsigned char uint8_t
Definition: stdint.h:124
unsigned __int64 uint64_t
Definition: stdint.h:136
Definition: zlib.h:86
uInt avail_in
Definition: zlib.h:88
alloc_func zalloc
Definition: zlib.h:98
uInt avail_out
Definition: zlib.h:92
z_const Bytef * next_in
Definition: zlib.h:87
free_func zfree
Definition: zlib.h:99
voidpf opaque
Definition: zlib.h:100
Bytef * next_out
Definition: zlib.h:91
Byte FAR Bytef
Definition: zconf.h:406
#define Z_DEFLATED
Definition: zlib.h:209
#define Z_DEFAULT_STRATEGY
Definition: zlib.h:200
#define deflateInit2(strm, level, method, windowBits, memLevel, strategy)
Definition: zlib.h:1798
#define inflateInit2(strm, windowBits)
Definition: zlib.h:1801
#define Z_FINISH
Definition: zlib.h:172
#define Z_OK
Definition: zlib.h:177
#define Z_NO_FLUSH
Definition: zlib.h:168
#define Z_NULL
Definition: zlib.h:212
#define Z_DEFAULT_COMPRESSION
Definition: zlib.h:193