]> git.ipfire.org Git - thirdparty/ccache.git/commitdiff
bump: Upgrade to cpp-httplib 0.11.1
authorJoel Rosdahl <joel@rosdahl.net>
Wed, 3 Aug 2022 19:38:51 +0000 (21:38 +0200)
committerJoel Rosdahl <joel@rosdahl.net>
Thu, 4 Aug 2022 18:53:47 +0000 (20:53 +0200)
LICENSE.adoc
src/storage/secondary/HttpStorage.cpp
src/third_party/httplib.cpp
src/third_party/httplib.h

index 05e30c0dc6ab5d59d1794b386eebbbbeaec2b70f..3f536b119a9f8f33b36f4220952462993dc34bd7 100644 (file)
@@ -516,7 +516,7 @@ SUCH DAMAGE.
 === src/third_party/httplib.*
 
 cpp-httplib - A C++11 cross-platform HTTP/HTTPS library. Copied from cpp-httplib
-v0.10.8 downloaded from https://github.com/yhirose/cpp-httplib[cpp-httplib]. The
+v0.11.1 downloaded from https://github.com/yhirose/cpp-httplib[cpp-httplib]. The
 library has the following license:
 
 ----
index 2276ce49a68ee1b6c72c136c8675763ba991ea53..b73fe356d1cb8b2d23c5e320466c10ee106feeaa 100644 (file)
@@ -103,8 +103,7 @@ HttpStorageBackend::HttpStorageBackend(const Params& params)
       throw core::Fatal("Expected username:password in URL but got \"{}\"",
                         params.url.user_info());
     }
-    m_http_client.set_basic_auth(std::string(user).c_str(),
-                                 std::string(*password).c_str());
+    m_http_client.set_basic_auth(std::string(user), std::string(*password));
   }
 
   m_http_client.set_default_headers({
@@ -117,7 +116,7 @@ HttpStorageBackend::HttpStorageBackend(const Params& params)
 
   for (const auto& attr : params.attributes) {
     if (attr.key == "bearer-token") {
-      m_http_client.set_bearer_token_auth(attr.value.c_str());
+      m_http_client.set_bearer_token_auth(attr.value);
     } else if (attr.key == "connect-timeout") {
       connect_timeout = parse_timeout_attribute(attr.value);
     } else if (attr.key == "keep-alive") {
@@ -148,7 +147,7 @@ nonstd::expected<std::optional<std::string>, SecondaryStorage::Backend::Failure>
 HttpStorageBackend::get(const Digest& key)
 {
   const auto url_path = get_entry_path(key);
-  const auto result = m_http_client.Get(url_path.c_str());
+  const auto result = m_http_client.Get(url_path);
 
   if (result.error() != httplib::Error::Success || !result) {
     LOG("Failed to get {} from http storage: {} ({})",
@@ -174,7 +173,7 @@ HttpStorageBackend::put(const Digest& key,
   const auto url_path = get_entry_path(key);
 
   if (only_if_missing) {
-    const auto result = m_http_client.Head(url_path.c_str());
+    const auto result = m_http_client.Head(url_path);
 
     if (result.error() != httplib::Error::Success || !result) {
       LOG("Failed to check for {} in http storage: {} ({})",
@@ -193,8 +192,8 @@ HttpStorageBackend::put(const Digest& key,
   }
 
   static const auto content_type = "application/octet-stream";
-  const auto result = m_http_client.Put(
-    url_path.c_str(), value.data(), value.size(), content_type);
+  const auto result =
+    m_http_client.Put(url_path, value.data(), value.size(), content_type);
 
   if (result.error() != httplib::Error::Success || !result) {
     LOG("Failed to put {} to http storage: {} ({})",
@@ -218,7 +217,7 @@ nonstd::expected<bool, SecondaryStorage::Backend::Failure>
 HttpStorageBackend::remove(const Digest& key)
 {
   const auto url_path = get_entry_path(key);
-  const auto result = m_http_client.Delete(url_path.c_str());
+  const auto result = m_http_client.Delete(url_path);
 
   if (result.error() != httplib::Error::Success || !result) {
     LOG("Failed to delete {} from http storage: {} ({})",
index 03c0806227874258da483b52b6d60cd886f1fad0..a7ebdd56b0464cd19f850f33f40609097e31f2c4 100644 (file)
@@ -662,7 +662,7 @@ int shutdown_socket(socket_t sock) {
 }
 
 template <typename BindOrConnect>
-socket_t create_socket(const char *host, const char *ip, int port,
+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) {
@@ -675,17 +675,41 @@ socket_t create_socket(const char *host, const char *ip, int port,
   hints.ai_socktype = SOCK_STREAM;
   hints.ai_protocol = 0;
 
-  if (ip[0] != '\0') {
-    node = ip;
+  if (!ip.empty()) {
+    node = ip.c_str();
     // Ask getaddrinfo to convert IP in c-string to address
     hints.ai_family = AF_UNSPEC;
     hints.ai_flags = AI_NUMERICHOST;
   } else {
-    node = host;
+    if (!host.empty()) { node = host.c_str(); }
     hints.ai_family = address_family;
     hints.ai_flags = socket_flags;
   }
 
+#ifndef _WIN32
+  if (hints.ai_family == AF_UNIX) {
+    const auto addrlen = host.length();
+    if (addrlen > sizeof(sockaddr_un::sun_path)) return INVALID_SOCKET;
+
+    auto sock = socket(hints.ai_family, hints.ai_socktype, hints.ai_protocol);
+    if (sock != INVALID_SOCKET) {
+      sockaddr_un addr;
+      addr.sun_family = AF_UNIX;
+      std::copy(host.begin(), host.end(), addr.sun_path);
+
+      hints.ai_addr = reinterpret_cast<sockaddr*>(&addr);
+      hints.ai_addrlen = static_cast<socklen_t>(
+          sizeof(addr) - sizeof(addr.sun_path) + addrlen);
+
+      if (!bind_or_connect(sock, hints)) {
+        close_socket(sock);
+        sock = INVALID_SOCKET;
+      }
+    }
+    return sock;
+  }
+#endif
+
   auto service = std::to_string(port);
 
   if (getaddrinfo(node, service.c_str(), &hints, &result)) {
@@ -773,7 +797,7 @@ bool is_connection_error() {
 #endif
 }
 
-bool bind_ip_address(socket_t sock, const char *host) {
+bool bind_ip_address(socket_t sock, const std::string &host) {
   struct addrinfo hints;
   struct addrinfo *result;
 
@@ -782,7 +806,7 @@ bool bind_ip_address(socket_t sock, const char *host) {
   hints.ai_socktype = SOCK_STREAM;
   hints.ai_protocol = 0;
 
-  if (getaddrinfo(host, "0", &hints, &result)) { return false; }
+  if (getaddrinfo(host.c_str(), "0", &hints, &result)) { return false; }
 
   auto ret = false;
   for (auto rp = result; rp; rp = rp->ai_next) {
@@ -841,8 +865,8 @@ std::string if2ip(int address_family, const std::string &ifn) {
 #endif
 
 socket_t create_client_socket(
-    const char *host, const char *ip, int port, int address_family,
-    bool tcp_nodelay, SocketOptions socket_options,
+    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) {
@@ -1354,12 +1378,13 @@ bool brotli_decompressor::decompress(const char *data,
 }
 #endif
 
-bool has_header(const Headers &headers, const char *key) {
+bool has_header(const Headers &headers, const std::string &key) {
   return headers.find(key) != headers.end();
 }
 
-const char *get_header_value(const Headers &headers, const char *key,
-                                    size_t id, const char *def) {
+const char *get_header_value(const Headers &headers,
+                                    const std::string &key, size_t id,
+                                    const char *def) {
   auto rng = headers.equal_range(key);
   auto it = rng.first;
   std::advance(it, static_cast<ssize_t>(id));
@@ -1916,7 +1941,11 @@ class MultipartFormDataParser {
 public:
   MultipartFormDataParser() = default;
 
-  void set_boundary(std::string &&boundary) { boundary_ = boundary; }
+  void set_boundary(std::string &&boundary) {
+    boundary_ = boundary;
+    dash_boundary_crlf_ = dash_ + boundary_ + crlf_;
+    crlf_dash_boundary_ = crlf_ + dash_ + boundary_;
+  }
 
   bool is_valid() const { return is_valid_; }
 
@@ -1928,18 +1957,15 @@ public:
         R"~(^Content-Disposition:\s*form-data;\s*name="(.*?)"(?:;\s*filename="(.*?)")?(?:;\s*filename\*=\S+)?\s*$)~",
         std::regex_constants::icase);
 
-    static const std::string dash_ = "--";
-    static const std::string crlf_ = "\r\n";
-
     buf_append(buf, n);
 
     while (buf_size() > 0) {
       switch (state_) {
       case 0: { // Initial boundary
-        auto pattern = dash_ + boundary_ + crlf_;
-        if (pattern.size() > buf_size()) { return true; }
-        if (!buf_start_with(pattern)) { return false; }
-        buf_erase(pattern.size());
+        buf_erase(buf_find(dash_boundary_crlf_));
+        if (dash_boundary_crlf_.size() > buf_size()) { return true; }
+        if (!buf_start_with(dash_boundary_crlf_)) { return false; }
+        buf_erase(dash_boundary_crlf_.size());
         state_ = 1;
         break;
       }
@@ -1974,7 +2000,6 @@ public:
               file_.filename = m[2];
             }
           }
-
           buf_erase(pos + crlf_.size());
           pos = buf_find(crlf_);
         }
@@ -1982,40 +2007,25 @@ public:
         break;
       }
       case 3: { // Body
-        {
-          auto pattern = crlf_ + dash_;
-          if (pattern.size() > buf_size()) { return true; }
-
-          auto pos = buf_find(pattern);
-
+        if (crlf_dash_boundary_.size() > buf_size()) { return true; }
+        auto pos = buf_find(crlf_dash_boundary_);
+        if (pos < buf_size()) {
           if (!content_callback(buf_data(), pos)) {
             is_valid_ = false;
             return false;
           }
-
-          buf_erase(pos);
-        }
-        {
-          auto pattern = crlf_ + dash_ + boundary_;
-          if (pattern.size() > buf_size()) { return true; }
-
-          auto pos = buf_find(pattern);
-          if (pos < buf_size()) {
-            if (!content_callback(buf_data(), pos)) {
-              is_valid_ = false;
-              return false;
-            }
-
-            buf_erase(pos + pattern.size());
-            state_ = 4;
-          } else {
-            if (!content_callback(buf_data(), pattern.size())) {
+          buf_erase(pos + crlf_dash_boundary_.size());
+          state_ = 4;
+        } else {
+          auto len = buf_size() - crlf_dash_boundary_.size();
+          if (len > 0) {
+            if (!content_callback(buf_data(), len)) {
               is_valid_ = false;
               return false;
             }
-
-            buf_erase(pattern.size());
+            buf_erase(len);
           }
+          return true;
         }
         break;
       }
@@ -2025,22 +2035,17 @@ public:
           buf_erase(crlf_.size());
           state_ = 1;
         } else {
-          auto pattern = dash_ + crlf_;
-          if (pattern.size() > buf_size()) { return true; }
-          if (buf_start_with(pattern)) {
-            buf_erase(pattern.size());
+          if (dash_crlf_.size() > buf_size()) { return true; }
+          if (buf_start_with(dash_crlf_)) {
+            buf_erase(dash_crlf_.size());
             is_valid_ = true;
-            state_ = 5;
+            buf_erase(buf_size()); // Remove epilogue
           } else {
             return true;
           }
         }
         break;
       }
-      case 5: { // Done
-        is_valid_ = false;
-        return false;
-      }
       }
     }
 
@@ -2063,7 +2068,12 @@ private:
     return true;
   }
 
+  const std::string dash_ = "--";
+  const std::string crlf_ = "\r\n";
+  const std::string dash_crlf_ = "--\r\n";
   std::string boundary_;
+  std::string dash_boundary_crlf_;
+  std::string crlf_dash_boundary_;
 
   size_t state_ = 0;
   bool is_valid_ = false;
@@ -2242,7 +2252,7 @@ bool make_multipart_ranges_data(const Request &req, Response &res,
   return process_multipart_ranges_data(
       req, res, boundary, content_type,
       [&](const std::string &token) { data += token; },
-      [&](const char *token) { data += token; },
+      [&](const std::string &token) { data += token; },
       [&](size_t offset, size_t length) {
         if (offset < res.body.size()) {
           data += res.body.substr(offset, length);
@@ -2261,7 +2271,7 @@ get_multipart_ranges_data_length(const Request &req, Response &res,
   process_multipart_ranges_data(
       req, res, boundary, content_type,
       [&](const std::string &token) { data_length += token.size(); },
-      [&](const char *token) { data_length += strlen(token); },
+      [&](const std::string &token) { data_length += token.size(); },
       [&](size_t /*offset*/, size_t length) {
         data_length += length;
         return true;
@@ -2279,7 +2289,7 @@ bool write_multipart_ranges_data(Stream &strm, const Request &req,
   return process_multipart_ranges_data(
       req, res, boundary, content_type,
       [&](const std::string &token) { strm.write(token); },
-      [&](const char *token) { strm.write(token); },
+      [&](const std::string &token) { strm.write(token); },
       [&](size_t offset, size_t length) {
         return write_content(strm, res.content_provider_, offset, length,
                              is_shutting_down);
@@ -2307,8 +2317,8 @@ bool expect_content(const Request &req) {
   return false;
 }
 
-bool has_crlf(const char *s) {
-  auto p = s;
+bool has_crlf(const std::string &s) {
+  auto p = s.c_str();
   while (*p) {
     if (*p == '\r' || *p == '\n') { return true; }
     p++;
@@ -2521,14 +2531,15 @@ private:
 
 } // namespace detail
 
-std::string hosted_at(const char *hostname) {
+std::string hosted_at(const std::string &hostname) {
   std::vector<std::string> addrs;
   hosted_at(hostname, addrs);
   if (addrs.empty()) { return std::string(); }
   return addrs[0];
 }
 
-void hosted_at(const char *hostname, std::vector<std::string> &addrs) {
+void hosted_at(const std::string &hostname,
+                      std::vector<std::string> &addrs) {
   struct addrinfo hints;
   struct addrinfo *result;
 
@@ -2537,7 +2548,7 @@ void hosted_at(const char *hostname, std::vector<std::string> &addrs) {
   hints.ai_socktype = SOCK_STREAM;
   hints.ai_protocol = 0;
 
-  if (getaddrinfo(hostname, nullptr, &hints, &result)) {
+  if (getaddrinfo(hostname.c_str(), nullptr, &hints, &result)) {
 #if defined __linux__ && !defined __ANDROID__
     res_init();
 #endif
@@ -2558,7 +2569,8 @@ void hosted_at(const char *hostname, std::vector<std::string> &addrs) {
   freeaddrinfo(result);
 }
 
-std::string append_query_params(const char *path, const Params &params) {
+std::string append_query_params(const std::string &path,
+                                       const Params &params) {
   std::string path_with_query = path;
   const static std::regex re("[^?]+\\?.*");
   auto delm = std::regex_match(path, re) ? '&' : '?';
@@ -2597,36 +2609,33 @@ make_bearer_token_authentication_header(const std::string &token,
 }
 
 // Request implementation
-bool Request::has_header(const char *key) const {
+bool Request::has_header(const std::string &key) const {
   return detail::has_header(headers, key);
 }
 
-std::string Request::get_header_value(const char *key, size_t id) const {
+std::string Request::get_header_value(const std::string &key,
+                                             size_t id) const {
   return detail::get_header_value(headers, key, id, "");
 }
 
-size_t Request::get_header_value_count(const char *key) const {
+size_t Request::get_header_value_count(const std::string &key) const {
   auto r = headers.equal_range(key);
   return static_cast<size_t>(std::distance(r.first, r.second));
 }
 
-void Request::set_header(const char *key, const char *val) {
+void Request::set_header(const std::string &key,
+                                const std::string &val) {
   if (!detail::has_crlf(key) && !detail::has_crlf(val)) {
     headers.emplace(key, val);
   }
 }
 
-void Request::set_header(const char *key, const std::string &val) {
-  if (!detail::has_crlf(key) && !detail::has_crlf(val.c_str())) {
-    headers.emplace(key, val);
-  }
-}
-
-bool Request::has_param(const char *key) const {
+bool Request::has_param(const std::string &key) const {
   return params.find(key) != params.end();
 }
 
-std::string Request::get_param_value(const char *key, size_t id) const {
+std::string Request::get_param_value(const std::string &key,
+                                            size_t id) const {
   auto rng = params.equal_range(key);
   auto it = rng.first;
   std::advance(it, static_cast<ssize_t>(id));
@@ -2634,7 +2643,7 @@ std::string Request::get_param_value(const char *key, size_t id) const {
   return std::string();
 }
 
-size_t Request::get_param_value_count(const char *key) const {
+size_t Request::get_param_value_count(const std::string &key) const {
   auto r = params.equal_range(key);
   return static_cast<size_t>(std::distance(r.first, r.second));
 }
@@ -2644,44 +2653,39 @@ bool Request::is_multipart_form_data() const {
   return !content_type.rfind("multipart/form-data", 0);
 }
 
-bool Request::has_file(const char *key) const {
+bool Request::has_file(const std::string &key) const {
   return files.find(key) != files.end();
 }
 
-MultipartFormData Request::get_file_value(const char *key) const {
+MultipartFormData Request::get_file_value(const std::string &key) const {
   auto it = files.find(key);
   if (it != files.end()) { return it->second; }
   return MultipartFormData();
 }
 
 // Response implementation
-bool Response::has_header(const char *key) const {
+bool Response::has_header(const std::string &key) const {
   return headers.find(key) != headers.end();
 }
 
-std::string Response::get_header_value(const char *key,
+std::string Response::get_header_value(const std::string &key,
                                               size_t id) const {
   return detail::get_header_value(headers, key, id, "");
 }
 
-size_t Response::get_header_value_count(const char *key) const {
+size_t Response::get_header_value_count(const std::string &key) const {
   auto r = headers.equal_range(key);
   return static_cast<size_t>(std::distance(r.first, r.second));
 }
 
-void Response::set_header(const char *key, const char *val) {
+void Response::set_header(const std::string &key,
+                                 const std::string &val) {
   if (!detail::has_crlf(key) && !detail::has_crlf(val)) {
     headers.emplace(key, val);
   }
 }
 
-void Response::set_header(const char *key, const std::string &val) {
-  if (!detail::has_crlf(key) && !detail::has_crlf(val.c_str())) {
-    headers.emplace(key, val);
-  }
-}
-
-void Response::set_redirect(const char *url, int stat) {
+void Response::set_redirect(const std::string &url, int stat) {
   if (!detail::has_crlf(url)) {
     set_header("Location", url);
     if (300 <= stat && stat < 400) {
@@ -2692,12 +2696,8 @@ void Response::set_redirect(const char *url, int stat) {
   }
 }
 
-void Response::set_redirect(const std::string &url, int stat) {
-  set_redirect(url.c_str(), stat);
-}
-
 void Response::set_content(const char *s, size_t n,
-                                  const char *content_type) {
+                                  const std::string &content_type) {
   body.assign(s, n);
 
   auto rng = headers.equal_range("Content-Type");
@@ -2706,12 +2706,12 @@ void Response::set_content(const char *s, size_t n,
 }
 
 void Response::set_content(const std::string &s,
-                                  const char *content_type) {
+                                  const std::string &content_type) {
   set_content(s.data(), s.size(), content_type);
 }
 
 void Response::set_content_provider(
-    size_t in_length, const char *content_type, ContentProvider provider,
+    size_t in_length, const std::string &content_type, ContentProvider provider,
     ContentProviderResourceReleaser resource_releaser) {
   assert(in_length > 0);
   set_header("Content-Type", content_type);
@@ -2722,7 +2722,7 @@ void Response::set_content_provider(
 }
 
 void Response::set_content_provider(
-    const char *content_type, ContentProviderWithoutLength provider,
+    const std::string &content_type, ContentProviderWithoutLength provider,
     ContentProviderResourceReleaser resource_releaser) {
   set_header("Content-Type", content_type);
   content_length_ = 0;
@@ -2732,7 +2732,7 @@ void Response::set_content_provider(
 }
 
 void Response::set_chunked_content_provider(
-    const char *content_type, ContentProviderWithoutLength provider,
+    const std::string &content_type, ContentProviderWithoutLength provider,
     ContentProviderResourceReleaser resource_releaser) {
   set_header("Content-Type", content_type);
   content_length_ = 0;
@@ -2742,16 +2742,17 @@ void Response::set_chunked_content_provider(
 }
 
 // Result implementation
-bool Result::has_request_header(const char *key) const {
+bool Result::has_request_header(const std::string &key) const {
   return request_headers_.find(key) != request_headers_.end();
 }
 
-std::string Result::get_request_header_value(const char *key,
+std::string Result::get_request_header_value(const std::string &key,
                                                     size_t id) const {
   return detail::get_header_value(request_headers_, key, id, "");
 }
 
-size_t Result::get_request_header_value_count(const char *key) const {
+size_t
+Result::get_request_header_value_count(const std::string &key) const {
   auto r = request_headers_.equal_range(key);
   return static_cast<size_t>(std::distance(r.first, r.second));
 }
@@ -2857,7 +2858,7 @@ bool BufferStream::is_readable() const { return true; }
 bool BufferStream::is_writable() const { return true; }
 
 ssize_t BufferStream::read(char *ptr, size_t size) {
-#if defined(_MSC_VER) && _MSC_VER <= 1900
+#if defined(_MSC_VER) && _MSC_VER < 1910
   auto len_read = buffer._Copy_s(ptr, size, size, position);
 #else
   auto len_read = buffer.copy(ptr, size, position);
@@ -2984,8 +2985,8 @@ bool Server::remove_mount_point(const std::string &mount_point) {
 }
 
 Server &
-Server::set_file_extension_and_mimetype_mapping(const char *ext,
-                                                const char *mime) {
+Server::set_file_extension_and_mimetype_mapping(const std::string &ext,
+                                                const std::string &mime) {
   file_extension_and_mimetype_map_[ext] = mime;
   return *this;
 }
@@ -3088,17 +3089,19 @@ Server &Server::set_payload_max_length(size_t length) {
   return *this;
 }
 
-bool Server::bind_to_port(const char *host, int port, int socket_flags) {
+bool Server::bind_to_port(const std::string &host, int port,
+                                 int socket_flags) {
   if (bind_internal(host, port, socket_flags) < 0) return false;
   return true;
 }
-int Server::bind_to_any_port(const char *host, int socket_flags) {
+int Server::bind_to_any_port(const std::string &host, int socket_flags) {
   return bind_internal(host, 0, socket_flags);
 }
 
 bool Server::listen_after_bind() { return listen_internal(); }
 
-bool Server::listen(const char *host, int port, int socket_flags) {
+bool Server::listen(const std::string &host, int port,
+                           int socket_flags) {
   return bind_to_port(host, port, socket_flags) && listen_internal();
 }
 
@@ -3241,14 +3244,16 @@ bool Server::write_response_core(Stream &strm, bool close_connection,
 
     // Flush buffer
     auto &data = bstrm.get_buffer();
-    strm.write(data.data(), data.size());
+    detail::write_data(strm, data.data(), data.size());
   }
 
   // Body
   auto ret = true;
   if (req.method != "HEAD") {
     if (!res.body.empty()) {
-      if (!strm.write(res.body)) { ret = false; }
+      if (!detail::write_data(strm, res.body.data(), res.body.size())) {
+        ret = false;
+      }
     } else if (res.content_provider_) {
       if (write_content_with_provider(strm, req, res, boundary, content_type)) {
         res.content_provider_success_ = true;
@@ -3444,10 +3449,11 @@ bool Server::handle_file_request(const Request &req, Response &res,
 }
 
 socket_t
-Server::create_server_socket(const char *host, int port, int socket_flags,
+Server::create_server_socket(const std::string &host, int port,
+                             int socket_flags,
                              SocketOptions socket_options) const {
   return detail::create_socket(
-      host, "", port, address_family_, socket_flags, tcp_nodelay_,
+      host, std::string(), port, address_family_, socket_flags, tcp_nodelay_,
       std::move(socket_options),
       [](socket_t sock, struct addrinfo &ai) -> bool {
         if (::bind(sock, ai.ai_addr, static_cast<socklen_t>(ai.ai_addrlen))) {
@@ -3458,7 +3464,8 @@ Server::create_server_socket(const char *host, int port, int socket_flags,
       });
 }
 
-int Server::bind_internal(const char *host, int port, int socket_flags) {
+int Server::bind_internal(const std::string &host, int port,
+                                 int socket_flags) {
   if (!is_valid()) { return -1; }
 
   svr_sock_ = create_server_socket(host, port, socket_flags, socket_options_);
@@ -3877,15 +3884,22 @@ Server::process_request(Stream &strm, bool close_connection,
     routed = routing(req, res, strm);
   } catch (std::exception &e) {
     if (exception_handler_) {
-      exception_handler_(req, res, e);
+      auto ep = std::current_exception();
+      exception_handler_(req, res, ep);
       routed = true;
     } else {
       res.status = 500;
       res.set_header("EXCEPTION_WHAT", e.what());
     }
   } catch (...) {
-    res.status = 500;
-    res.set_header("EXCEPTION_WHAT", "UNKNOWN");
+    if (exception_handler_) {
+      auto ep = std::current_exception();
+      exception_handler_(req, res, ep);
+      routed = true;
+    } else {
+      res.status = 500;
+      res.set_header("EXCEPTION_WHAT", "UNKNOWN");
+    }
   }
 #endif
 
@@ -3984,7 +3998,7 @@ void ClientImpl::copy_settings(const ClientImpl &rhs) {
 socket_t ClientImpl::create_client_socket(Error &error) const {
   if (!proxy_host_.empty() && proxy_port_ != -1) {
     return detail::create_client_socket(
-        proxy_host_.c_str(), "", proxy_port_, address_family_, tcp_nodelay_,
+        proxy_host_, std::string(), proxy_port_, address_family_, tcp_nodelay_,
         socket_options_, connection_timeout_sec_, connection_timeout_usec_,
         read_timeout_sec_, read_timeout_usec_, write_timeout_sec_,
         write_timeout_usec_, interface_, error);
@@ -3996,10 +4010,10 @@ socket_t ClientImpl::create_client_socket(Error &error) const {
   if (it != addr_map_.end()) ip = it->second;
 
   return detail::create_client_socket(
-      host_.c_str(), ip.c_str(), port_, address_family_, tcp_nodelay_,
-      socket_options_, connection_timeout_sec_, connection_timeout_usec_,
-      read_timeout_sec_, read_timeout_usec_, write_timeout_sec_,
-      write_timeout_usec_, interface_, error);
+      host_, ip, port_, address_family_, tcp_nodelay_, socket_options_,
+      connection_timeout_sec_, connection_timeout_usec_, read_timeout_sec_,
+      read_timeout_usec_, write_timeout_sec_, write_timeout_usec_, interface_,
+      error);
 }
 
 bool ClientImpl::create_and_connect_socket(Socket &socket,
@@ -4438,13 +4452,13 @@ bool ClientImpl::write_request(Stream &strm, Request &req,
 }
 
 std::unique_ptr<Response> ClientImpl::send_with_content_provider(
-    Request &req,
-    // const char *method, const char *path, const Headers &headers,
-    const char *body, size_t content_length, ContentProvider content_provider,
+    Request &req, const char *body, size_t content_length,
+    ContentProvider content_provider,
     ContentProviderWithoutLength content_provider_without_length,
-    const char *content_type, Error &error) {
-
-  if (content_type) { req.headers.emplace("Content-Type", content_type); }
+    const std::string &content_type, Error &error) {
+  if (!content_type.empty()) {
+    req.headers.emplace("Content-Type", content_type);
+  }
 
 #ifdef CPPHTTPLIB_ZLIB_SUPPORT
   if (compress_) { req.headers.emplace("Content-Encoding", "gzip"); }
@@ -4465,7 +4479,8 @@ std::unique_ptr<Response> ClientImpl::send_with_content_provider(
           auto last = offset + data_len == content_length;
 
           auto ret = compressor.compress(
-              data, data_len, last, [&](const char *compressed_data, size_t compressed_data_len) {
+              data, data_len, last,
+              [&](const char *compressed_data, size_t compressed_data_len) {
                 req.body.append(compressed_data, compressed_data_len);
                 return true;
               });
@@ -4521,10 +4536,10 @@ std::unique_ptr<Response> ClientImpl::send_with_content_provider(
 }
 
 Result ClientImpl::send_with_content_provider(
-    const char *method, const char *path, const Headers &headers,
+    const std::string &method, const std::string &path, const Headers &headers,
     const char *body, size_t content_length, ContentProvider content_provider,
     ContentProviderWithoutLength content_provider_without_length,
-    const char *content_type) {
+    const std::string &content_type) {
   Request req;
   req.method = method;
   req.headers = headers;
@@ -4533,9 +4548,7 @@ Result ClientImpl::send_with_content_provider(
   auto error = Error::Success;
 
   auto res = send_with_content_provider(
-      req,
-      // method, path, headers,
-      body, content_length, std::move(content_provider),
+      req, body, content_length, std::move(content_provider),
       std::move(content_provider_without_length), content_type, error);
 
   return Result{std::move(res), error, std::move(req.headers)};
@@ -4640,19 +4653,19 @@ ClientImpl::process_socket(const Socket &socket,
 
 bool ClientImpl::is_ssl() const { return false; }
 
-Result ClientImpl::Get(const char *path) {
+Result ClientImpl::Get(const std::string &path) {
   return Get(path, Headers(), Progress());
 }
 
-Result ClientImpl::Get(const char *path, Progress progress) {
+Result ClientImpl::Get(const std::string &path, Progress progress) {
   return Get(path, Headers(), std::move(progress));
 }
 
-Result ClientImpl::Get(const char *path, const Headers &headers) {
+Result ClientImpl::Get(const std::string &path, const Headers &headers) {
   return Get(path, headers, Progress());
 }
 
-Result ClientImpl::Get(const char *path, const Headers &headers,
+Result ClientImpl::Get(const std::string &path, const Headers &headers,
                               Progress progress) {
   Request req;
   req.method = "GET";
@@ -4663,45 +4676,45 @@ Result ClientImpl::Get(const char *path, const Headers &headers,
   return send_(std::move(req));
 }
 
-Result ClientImpl::Get(const char *path,
+Result ClientImpl::Get(const std::string &path,
                               ContentReceiver content_receiver) {
   return Get(path, Headers(), nullptr, std::move(content_receiver), nullptr);
 }
 
-Result ClientImpl::Get(const char *path,
+Result ClientImpl::Get(const std::string &path,
                               ContentReceiver content_receiver,
                               Progress progress) {
   return Get(path, Headers(), nullptr, std::move(content_receiver),
              std::move(progress));
 }
 
-Result ClientImpl::Get(const char *path, const Headers &headers,
+Result ClientImpl::Get(const std::string &path, const Headers &headers,
                               ContentReceiver content_receiver) {
   return Get(path, headers, nullptr, std::move(content_receiver), nullptr);
 }
 
-Result ClientImpl::Get(const char *path, const Headers &headers,
+Result ClientImpl::Get(const std::string &path, const Headers &headers,
                               ContentReceiver content_receiver,
                               Progress progress) {
   return Get(path, headers, nullptr, std::move(content_receiver),
              std::move(progress));
 }
 
-Result ClientImpl::Get(const char *path,
+Result ClientImpl::Get(const std::string &path,
                               ResponseHandler response_handler,
                               ContentReceiver content_receiver) {
   return Get(path, Headers(), std::move(response_handler),
              std::move(content_receiver), nullptr);
 }
 
-Result ClientImpl::Get(const char *path, const Headers &headers,
+Result ClientImpl::Get(const std::string &path, const Headers &headers,
                               ResponseHandler response_handler,
                               ContentReceiver content_receiver) {
   return Get(path, headers, std::move(response_handler),
              std::move(content_receiver), nullptr);
 }
 
-Result ClientImpl::Get(const char *path,
+Result ClientImpl::Get(const std::string &path,
                               ResponseHandler response_handler,
                               ContentReceiver content_receiver,
                               Progress progress) {
@@ -4709,7 +4722,7 @@ Result ClientImpl::Get(const char *path,
              std::move(content_receiver), std::move(progress));
 }
 
-Result ClientImpl::Get(const char *path, const Headers &headers,
+Result ClientImpl::Get(const std::string &path, const Headers &headers,
                               ResponseHandler response_handler,
                               ContentReceiver content_receiver,
                               Progress progress) {
@@ -4728,7 +4741,7 @@ Result ClientImpl::Get(const char *path, const Headers &headers,
   return send_(std::move(req));
 }
 
-Result ClientImpl::Get(const char *path, const Params &params,
+Result ClientImpl::Get(const std::string &path, const Params &params,
                               const Headers &headers, Progress progress) {
   if (params.empty()) { return Get(path, headers); }
 
@@ -4736,14 +4749,14 @@ Result ClientImpl::Get(const char *path, const Params &params,
   return Get(path_with_query.c_str(), headers, progress);
 }
 
-Result ClientImpl::Get(const char *path, const Params &params,
+Result ClientImpl::Get(const std::string &path, const Params &params,
                               const Headers &headers,
                               ContentReceiver content_receiver,
                               Progress progress) {
   return Get(path, params, headers, nullptr, content_receiver, progress);
 }
 
-Result ClientImpl::Get(const char *path, const Params &params,
+Result ClientImpl::Get(const std::string &path, const Params &params,
                               const Headers &headers,
                               ResponseHandler response_handler,
                               ContentReceiver content_receiver,
@@ -4757,11 +4770,12 @@ Result ClientImpl::Get(const char *path, const Params &params,
              content_receiver, progress);
 }
 
-Result ClientImpl::Head(const char *path) {
+Result ClientImpl::Head(const std::string &path) {
   return Head(path, Headers());
 }
 
-Result ClientImpl::Head(const char *path, const Headers &headers) {
+Result ClientImpl::Head(const std::string &path,
+                               const Headers &headers) {
   Request req;
   req.method = "HEAD";
   req.headers = headers;
@@ -4770,85 +4784,85 @@ Result ClientImpl::Head(const char *path, const Headers &headers) {
   return send_(std::move(req));
 }
 
-Result ClientImpl::Post(const char *path) {
-  return Post(path, std::string(), nullptr);
+Result ClientImpl::Post(const std::string &path) {
+  return Post(path, std::string(), std::string());
 }
 
-Result ClientImpl::Post(const char *path, const char *body,
+Result ClientImpl::Post(const std::string &path, const char *body,
                                size_t content_length,
-                               const char *content_type) {
+                               const std::string &content_type) {
   return Post(path, Headers(), body, content_length, content_type);
 }
 
-Result ClientImpl::Post(const char *path, const Headers &headers,
+Result ClientImpl::Post(const std::string &path, const Headers &headers,
                                const char *body, size_t content_length,
-                               const char *content_type) {
+                               const std::string &content_type) {
   return send_with_content_provider("POST", path, headers, body, content_length,
                                     nullptr, nullptr, content_type);
 }
 
-Result ClientImpl::Post(const char *path, const std::string &body,
-                               const char *content_type) {
+Result ClientImpl::Post(const std::string &path, const std::string &body,
+                               const std::string &content_type) {
   return Post(path, Headers(), body, content_type);
 }
 
-Result ClientImpl::Post(const char *path, const Headers &headers,
+Result ClientImpl::Post(const std::string &path, const Headers &headers,
                                const std::string &body,
-                               const char *content_type) {
+                               const std::string &content_type) {
   return send_with_content_provider("POST", path, headers, body.data(),
                                     body.size(), nullptr, nullptr,
                                     content_type);
 }
 
-Result ClientImpl::Post(const char *path, const Params &params) {
+Result ClientImpl::Post(const std::string &path, const Params &params) {
   return Post(path, Headers(), params);
 }
 
-Result ClientImpl::Post(const char *path, size_t content_length,
+Result ClientImpl::Post(const std::string &path, size_t content_length,
                                ContentProvider content_provider,
-                               const char *content_type) {
+                               const std::string &content_type) {
   return Post(path, Headers(), content_length, std::move(content_provider),
               content_type);
 }
 
-Result ClientImpl::Post(const char *path,
+Result ClientImpl::Post(const std::string &path,
                                ContentProviderWithoutLength content_provider,
-                               const char *content_type) {
+                               const std::string &content_type) {
   return Post(path, Headers(), std::move(content_provider), content_type);
 }
 
-Result ClientImpl::Post(const char *path, const Headers &headers,
+Result ClientImpl::Post(const std::string &path, const Headers &headers,
                                size_t content_length,
                                ContentProvider content_provider,
-                               const char *content_type) {
+                               const std::string &content_type) {
   return send_with_content_provider("POST", path, headers, nullptr,
                                     content_length, std::move(content_provider),
                                     nullptr, content_type);
 }
 
-Result ClientImpl::Post(const char *path, const Headers &headers,
+Result ClientImpl::Post(const std::string &path, const Headers &headers,
                                ContentProviderWithoutLength content_provider,
-                               const char *content_type) {
+                               const std::string &content_type) {
   return send_with_content_provider("POST", path, headers, nullptr, 0, nullptr,
                                     std::move(content_provider), content_type);
 }
 
-Result ClientImpl::Post(const char *path, const Headers &headers,
+Result ClientImpl::Post(const std::string &path, const Headers &headers,
                                const Params &params) {
   auto query = detail::params_to_query_str(params);
   return Post(path, headers, query, "application/x-www-form-urlencoded");
 }
 
-Result ClientImpl::Post(const char *path,
+Result ClientImpl::Post(const std::string &path,
                                const MultipartFormDataItems &items) {
   return Post(path, Headers(), items);
 }
 
-Result ClientImpl::Post(const char *path, const Headers &headers,
+Result ClientImpl::Post(const std::string &path, const Headers &headers,
                                const MultipartFormDataItems &items) {
   return Post(path, headers, items, detail::make_multipart_data_boundary());
 }
-Result ClientImpl::Post(const char *path, const Headers &headers,
+Result ClientImpl::Post(const std::string &path, const Headers &headers,
                                const MultipartFormDataItems &items,
                                const std::string &boundary) {
   for (size_t i = 0; i < boundary.size(); i++) {
@@ -4880,178 +4894,187 @@ Result ClientImpl::Post(const char *path, const Headers &headers,
   return Post(path, headers, body, content_type.c_str());
 }
 
-Result ClientImpl::Put(const char *path) {
-  return Put(path, std::string(), nullptr);
+Result ClientImpl::Put(const std::string &path) {
+  return Put(path, std::string(), std::string());
 }
 
-Result ClientImpl::Put(const char *path, const char *body,
-                              size_t content_length, const char *content_type) {
+Result ClientImpl::Put(const std::string &path, const char *body,
+                              size_t content_length,
+                              const std::string &content_type) {
   return Put(path, Headers(), body, content_length, content_type);
 }
 
-Result ClientImpl::Put(const char *path, const Headers &headers,
+Result ClientImpl::Put(const std::string &path, const Headers &headers,
                               const char *body, size_t content_length,
-                              const char *content_type) {
+                              const std::string &content_type) {
   return send_with_content_provider("PUT", path, headers, body, content_length,
                                     nullptr, nullptr, content_type);
 }
 
-Result ClientImpl::Put(const char *path, const std::string &body,
-                              const char *content_type) {
+Result ClientImpl::Put(const std::string &path, const std::string &body,
+                              const std::string &content_type) {
   return Put(path, Headers(), body, content_type);
 }
 
-Result ClientImpl::Put(const char *path, const Headers &headers,
+Result ClientImpl::Put(const std::string &path, const Headers &headers,
                               const std::string &body,
-                              const char *content_type) {
+                              const std::string &content_type) {
   return send_with_content_provider("PUT", path, headers, body.data(),
                                     body.size(), nullptr, nullptr,
                                     content_type);
 }
 
-Result ClientImpl::Put(const char *path, size_t content_length,
+Result ClientImpl::Put(const std::string &path, size_t content_length,
                               ContentProvider content_provider,
-                              const char *content_type) {
+                              const std::string &content_type) {
   return Put(path, Headers(), content_length, std::move(content_provider),
              content_type);
 }
 
-Result ClientImpl::Put(const char *path,
+Result ClientImpl::Put(const std::string &path,
                               ContentProviderWithoutLength content_provider,
-                              const char *content_type) {
+                              const std::string &content_type) {
   return Put(path, Headers(), std::move(content_provider), content_type);
 }
 
-Result ClientImpl::Put(const char *path, const Headers &headers,
+Result ClientImpl::Put(const std::string &path, const Headers &headers,
                               size_t content_length,
                               ContentProvider content_provider,
-                              const char *content_type) {
+                              const std::string &content_type) {
   return send_with_content_provider("PUT", path, headers, nullptr,
                                     content_length, std::move(content_provider),
                                     nullptr, content_type);
 }
 
-Result ClientImpl::Put(const char *path, const Headers &headers,
+Result ClientImpl::Put(const std::string &path, const Headers &headers,
                               ContentProviderWithoutLength content_provider,
-                              const char *content_type) {
+                              const std::string &content_type) {
   return send_with_content_provider("PUT", path, headers, nullptr, 0, nullptr,
                                     std::move(content_provider), content_type);
 }
 
-Result ClientImpl::Put(const char *path, const Params &params) {
+Result ClientImpl::Put(const std::string &path, const Params &params) {
   return Put(path, Headers(), params);
 }
 
-Result ClientImpl::Put(const char *path, const Headers &headers,
+Result ClientImpl::Put(const std::string &path, const Headers &headers,
                               const Params &params) {
   auto query = detail::params_to_query_str(params);
   return Put(path, headers, query, "application/x-www-form-urlencoded");
 }
 
-Result ClientImpl::Patch(const char *path) {
-  return Patch(path, std::string(), nullptr);
+Result ClientImpl::Patch(const std::string &path) {
+  return Patch(path, std::string(), std::string());
 }
 
-Result ClientImpl::Patch(const char *path, const char *body,
+Result ClientImpl::Patch(const std::string &path, const char *body,
                                 size_t content_length,
-                                const char *content_type) {
+                                const std::string &content_type) {
   return Patch(path, Headers(), body, content_length, content_type);
 }
 
-Result ClientImpl::Patch(const char *path, const Headers &headers,
+Result ClientImpl::Patch(const std::string &path, const Headers &headers,
                                 const char *body, size_t content_length,
-                                const char *content_type) {
+                                const std::string &content_type) {
   return send_with_content_provider("PATCH", path, headers, body,
                                     content_length, nullptr, nullptr,
                                     content_type);
 }
 
-Result ClientImpl::Patch(const char *path, const std::string &body,
-                                const char *content_type) {
+Result ClientImpl::Patch(const std::string &path,
+                                const std::string &body,
+                                const std::string &content_type) {
   return Patch(path, Headers(), body, content_type);
 }
 
-Result ClientImpl::Patch(const char *path, const Headers &headers,
+Result ClientImpl::Patch(const std::string &path, const Headers &headers,
                                 const std::string &body,
-                                const char *content_type) {
+                                const std::string &content_type) {
   return send_with_content_provider("PATCH", path, headers, body.data(),
                                     body.size(), nullptr, nullptr,
                                     content_type);
 }
 
-Result ClientImpl::Patch(const char *path, size_t content_length,
+Result ClientImpl::Patch(const std::string &path, size_t content_length,
                                 ContentProvider content_provider,
-                                const char *content_type) {
+                                const std::string &content_type) {
   return Patch(path, Headers(), content_length, std::move(content_provider),
                content_type);
 }
 
-Result ClientImpl::Patch(const char *path,
+Result ClientImpl::Patch(const std::string &path,
                                 ContentProviderWithoutLength content_provider,
-                                const char *content_type) {
+                                const std::string &content_type) {
   return Patch(path, Headers(), std::move(content_provider), content_type);
 }
 
-Result ClientImpl::Patch(const char *path, const Headers &headers,
+Result ClientImpl::Patch(const std::string &path, const Headers &headers,
                                 size_t content_length,
                                 ContentProvider content_provider,
-                                const char *content_type) {
+                                const std::string &content_type) {
   return send_with_content_provider("PATCH", path, headers, nullptr,
                                     content_length, std::move(content_provider),
                                     nullptr, content_type);
 }
 
-Result ClientImpl::Patch(const char *path, const Headers &headers,
+Result ClientImpl::Patch(const std::string &path, const Headers &headers,
                                 ContentProviderWithoutLength content_provider,
-                                const char *content_type) {
+                                const std::string &content_type) {
   return send_with_content_provider("PATCH", path, headers, nullptr, 0, nullptr,
                                     std::move(content_provider), content_type);
 }
 
-Result ClientImpl::Delete(const char *path) {
-  return Delete(path, Headers(), std::string(), nullptr);
+Result ClientImpl::Delete(const std::string &path) {
+  return Delete(path, Headers(), std::string(), std::string());
 }
 
-Result ClientImpl::Delete(const char *path, const Headers &headers) {
-  return Delete(path, headers, std::string(), nullptr);
+Result ClientImpl::Delete(const std::string &path,
+                                 const Headers &headers) {
+  return Delete(path, headers, std::string(), std::string());
 }
 
-Result ClientImpl::Delete(const char *path, const char *body,
+Result ClientImpl::Delete(const std::string &path, const char *body,
                                  size_t content_length,
-                                 const char *content_type) {
+                                 const std::string &content_type) {
   return Delete(path, Headers(), body, content_length, content_type);
 }
 
-Result ClientImpl::Delete(const char *path, const Headers &headers,
-                                 const char *body, size_t content_length,
-                                 const char *content_type) {
+Result ClientImpl::Delete(const std::string &path,
+                                 const Headers &headers, const char *body,
+                                 size_t content_length,
+                                 const std::string &content_type) {
   Request req;
   req.method = "DELETE";
   req.headers = headers;
   req.path = path;
 
-  if (content_type) { req.headers.emplace("Content-Type", content_type); }
+  if (!content_type.empty()) {
+    req.headers.emplace("Content-Type", content_type);
+  }
   req.body.assign(body, content_length);
 
   return send_(std::move(req));
 }
 
-Result ClientImpl::Delete(const char *path, const std::string &body,
-                                 const char *content_type) {
+Result ClientImpl::Delete(const std::string &path,
+                                 const std::string &body,
+                                 const std::string &content_type) {
   return Delete(path, Headers(), body.data(), body.size(), content_type);
 }
 
-Result ClientImpl::Delete(const char *path, const Headers &headers,
+Result ClientImpl::Delete(const std::string &path,
+                                 const Headers &headers,
                                  const std::string &body,
-                                 const char *content_type) {
+                                 const std::string &content_type) {
   return Delete(path, headers, body.data(), body.size(), content_type);
 }
 
-Result ClientImpl::Options(const char *path) {
+Result ClientImpl::Options(const std::string &path) {
   return Options(path, Headers());
 }
 
-Result ClientImpl::Options(const char *path, const Headers &headers) {
+Result ClientImpl::Options(const std::string &path,
+                                  const Headers &headers) {
   Request req;
   req.method = "OPTIONS";
   req.headers = headers;
@@ -5065,6 +5088,10 @@ size_t ClientImpl::is_socket_open() const {
   return socket_.is_open();
 }
 
+socket_t ClientImpl::socket() const {
+  return socket_.sock;
+}
+
 void ClientImpl::stop() {
   std::lock_guard<std::mutex> guard(socket_mutex_);
 
@@ -5103,19 +5130,19 @@ void ClientImpl::set_write_timeout(time_t sec, time_t usec) {
   write_timeout_usec_ = usec;
 }
 
-void ClientImpl::set_basic_auth(const char *username,
-                                       const char *password) {
+void ClientImpl::set_basic_auth(const std::string &username,
+                                       const std::string &password) {
   basic_auth_username_ = username;
   basic_auth_password_ = password;
 }
 
-void ClientImpl::set_bearer_token_auth(const char *token) {
+void ClientImpl::set_bearer_token_auth(const std::string &token) {
   bearer_token_auth_token_ = token;
 }
 
 #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
-void ClientImpl::set_digest_auth(const char *username,
-                                        const char *password) {
+void ClientImpl::set_digest_auth(const std::string &username,
+                                        const std::string &password) {
   digest_auth_username_ = username;
   digest_auth_password_ = password;
 }
@@ -5150,36 +5177,38 @@ void ClientImpl::set_compress(bool on) { compress_ = on; }
 
 void ClientImpl::set_decompress(bool on) { decompress_ = on; }
 
-void ClientImpl::set_interface(const char *intf) { interface_ = intf; }
+void ClientImpl::set_interface(const std::string &intf) {
+  interface_ = intf;
+}
 
-void ClientImpl::set_proxy(const char *host, int port) {
+void ClientImpl::set_proxy(const std::string &host, int port) {
   proxy_host_ = host;
   proxy_port_ = port;
 }
 
-void ClientImpl::set_proxy_basic_auth(const char *username,
-                                             const char *password) {
+void ClientImpl::set_proxy_basic_auth(const std::string &username,
+                                             const std::string &password) {
   proxy_basic_auth_username_ = username;
   proxy_basic_auth_password_ = password;
 }
 
-void ClientImpl::set_proxy_bearer_token_auth(const char *token) {
+void ClientImpl::set_proxy_bearer_token_auth(const std::string &token) {
   proxy_bearer_token_auth_token_ = token;
 }
 
 #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
-void ClientImpl::set_proxy_digest_auth(const char *username,
-                                              const char *password) {
+void ClientImpl::set_proxy_digest_auth(const std::string &username,
+                                              const std::string &password) {
   proxy_digest_auth_username_ = username;
   proxy_digest_auth_password_ = password;
 }
 #endif
 
 #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
-void ClientImpl::set_ca_cert_path(const char *ca_cert_file_path,
-                                         const char *ca_cert_dir_path) {
-  if (ca_cert_file_path) { ca_cert_file_path_ = ca_cert_file_path; }
-  if (ca_cert_dir_path) { ca_cert_dir_path_ = ca_cert_dir_path; }
+void ClientImpl::set_ca_cert_path(const std::string &ca_cert_file_path,
+                                         const std::string &ca_cert_dir_path) {
+  ca_cert_file_path_ = ca_cert_file_path;
+  ca_cert_dir_path_ = ca_cert_dir_path;
 }
 
 void ClientImpl::set_ca_cert_store(X509_STORE *ca_cert_store) {
@@ -5371,63 +5400,65 @@ bool SSLSocketStream::is_writable() const {
 }
 
 ssize_t SSLSocketStream::read(char *ptr, size_t size) {
-  size_t readbytes = 0;
   if (SSL_pending(ssl_) > 0) {
-    auto ret = SSL_read_ex(ssl_, ptr, size, &readbytes);
-    if (ret == 1) { return static_cast<ssize_t>(readbytes); }
-    if (SSL_get_error(ssl_, ret) == SSL_ERROR_ZERO_RETURN) { return 0; }
-    return -1;
-  }
-  if (!is_readable()) { return -1; }
-
-  auto ret = SSL_read_ex(ssl_, ptr, size, &readbytes);
-  if (ret == 1) { return static_cast<ssize_t>(readbytes); }
-  auto err = SSL_get_error(ssl_, ret);
-  int n = 1000;
+    return SSL_read(ssl_, ptr, static_cast<int>(size));
+  } else if (is_readable()) {
+    auto ret = SSL_read(ssl_, ptr, static_cast<int>(size));
+    if (ret < 0) {
+      auto err = SSL_get_error(ssl_, ret);
+      int n = 1000;
 #ifdef _WIN32
-  while (--n >= 0 &&
-         (err == SSL_ERROR_WANT_READ ||
-          (err == SSL_ERROR_SYSCALL && WSAGetLastError() == WSAETIMEDOUT))) {
+      while (--n >= 0 && (err == SSL_ERROR_WANT_READ ||
+                          (err == SSL_ERROR_SYSCALL &&
+                           WSAGetLastError() == WSAETIMEDOUT))) {
 #else
-  while (--n >= 0 && err == SSL_ERROR_WANT_READ) {
+      while (--n >= 0 && err == SSL_ERROR_WANT_READ) {
 #endif
-    if (SSL_pending(ssl_) > 0) {
-      ret = SSL_read_ex(ssl_, ptr, size, &readbytes);
-      if (ret == 1) { return static_cast<ssize_t>(readbytes); }
-      if (SSL_get_error(ssl_, ret) == SSL_ERROR_ZERO_RETURN) { return 0; }
-      return -1;
+        if (SSL_pending(ssl_) > 0) {
+          return SSL_read(ssl_, ptr, static_cast<int>(size));
+        } else if (is_readable()) {
+          std::this_thread::sleep_for(std::chrono::milliseconds(1));
+          ret = SSL_read(ssl_, ptr, static_cast<int>(size));
+          if (ret >= 0) { return ret; }
+          err = SSL_get_error(ssl_, ret);
+        } else {
+          return -1;
+        }
+      }
     }
-    if (!is_readable()) { return -1; }
-    std::this_thread::sleep_for(std::chrono::milliseconds(1));
-    ret = SSL_read_ex(ssl_, ptr, size, &readbytes);
-    if (ret == 1) { return static_cast<ssize_t>(readbytes); }
-    err = SSL_get_error(ssl_, ret);
+    return ret;
   }
-  if (err == SSL_ERROR_ZERO_RETURN) { return 0; }
   return -1;
 }
 
 ssize_t SSLSocketStream::write(const char *ptr, size_t size) {
-  if (!is_writable()) { return -1; }
-  size_t written = 0;
-  auto ret = SSL_write_ex(ssl_, ptr, size, &written);
-  if (ret == 1) { return static_cast<ssize_t>(written); }
-  auto err = SSL_get_error(ssl_, ret);
-  int n = 1000;
+  if (is_writable()) {
+    auto handle_size = static_cast<int>(
+        std::min<size_t>(size, (std::numeric_limits<int>::max)()));
+
+    auto ret = SSL_write(ssl_, ptr, static_cast<int>(handle_size));
+    if (ret < 0) {
+      auto err = SSL_get_error(ssl_, ret);
+      int n = 1000;
 #ifdef _WIN32
-  while (--n >= 0 &&
-         (err == SSL_ERROR_WANT_WRITE ||
-          (err == SSL_ERROR_SYSCALL && WSAGetLastError() == WSAETIMEDOUT))) {
+      while (--n >= 0 && (err == SSL_ERROR_WANT_WRITE ||
+                          (err == SSL_ERROR_SYSCALL &&
+                           WSAGetLastError() == WSAETIMEDOUT))) {
 #else
-  while (--n >= 0 && err == SSL_ERROR_WANT_WRITE) {
+      while (--n >= 0 && err == SSL_ERROR_WANT_WRITE) {
 #endif
-    if (!is_writable()) { return -1; }
-    std::this_thread::sleep_for(std::chrono::milliseconds(1));
-    ret = SSL_write_ex(ssl_, ptr, size, &written);
-    if (ret == 1) { return static_cast<ssize_t>(written); }
-    err = SSL_get_error(ssl_, ret);
+        if (is_writable()) {
+          std::this_thread::sleep_for(std::chrono::milliseconds(1));
+          ret = SSL_write(ssl_, ptr, static_cast<int>(handle_size));
+          if (ret >= 0) { return ret; }
+          err = SSL_get_error(ssl_, ret);
+        } else {
+          return -1;
+        }
+      }
+    }
+    return ret;
   }
-  if (err == SSL_ERROR_ZERO_RETURN) { return 0; }
   return -1;
 }
 
@@ -5967,12 +5998,12 @@ Client::Client(const std::string &scheme_host_port,
 
     if (is_ssl) {
 #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
-      cli_ = detail::make_unique<SSLClient>(host.c_str(), port,
+      cli_ = detail::make_unique<SSLClient>(host, port,
                                             client_cert_path, client_key_path);
       is_ssl_ = is_ssl;
 #endif
     } else {
-      cli_ = detail::make_unique<ClientImpl>(host.c_str(), port,
+      cli_ = detail::make_unique<ClientImpl>(host, port,
                                              client_cert_path, client_key_path);
     }
   } else {
@@ -5996,65 +6027,68 @@ bool Client::is_valid() const {
   return cli_ != nullptr && cli_->is_valid();
 }
 
-Result Client::Get(const char *path) { return cli_->Get(path); }
-Result Client::Get(const char *path, const Headers &headers) {
+Result Client::Get(const std::string &path) { return cli_->Get(path); }
+Result Client::Get(const std::string &path, const Headers &headers) {
   return cli_->Get(path, headers);
 }
-Result Client::Get(const char *path, Progress progress) {
+Result Client::Get(const std::string &path, Progress progress) {
   return cli_->Get(path, std::move(progress));
 }
-Result Client::Get(const char *path, const Headers &headers,
+Result Client::Get(const std::string &path, const Headers &headers,
                           Progress progress) {
   return cli_->Get(path, headers, std::move(progress));
 }
-Result Client::Get(const char *path, ContentReceiver content_receiver) {
+Result Client::Get(const std::string &path,
+                          ContentReceiver content_receiver) {
   return cli_->Get(path, std::move(content_receiver));
 }
-Result Client::Get(const char *path, const Headers &headers,
+Result Client::Get(const std::string &path, const Headers &headers,
                           ContentReceiver content_receiver) {
   return cli_->Get(path, headers, std::move(content_receiver));
 }
-Result Client::Get(const char *path, ContentReceiver content_receiver,
-                          Progress progress) {
+Result Client::Get(const std::string &path,
+                          ContentReceiver content_receiver, Progress progress) {
   return cli_->Get(path, std::move(content_receiver), std::move(progress));
 }
-Result Client::Get(const char *path, const Headers &headers,
+Result Client::Get(const std::string &path, const Headers &headers,
                           ContentReceiver content_receiver, Progress progress) {
   return cli_->Get(path, headers, std::move(content_receiver),
                    std::move(progress));
 }
-Result Client::Get(const char *path, ResponseHandler response_handler,
+Result Client::Get(const std::string &path,
+                          ResponseHandler response_handler,
                           ContentReceiver content_receiver) {
   return cli_->Get(path, std::move(response_handler),
                    std::move(content_receiver));
 }
-Result Client::Get(const char *path, const Headers &headers,
+Result Client::Get(const std::string &path, const Headers &headers,
                           ResponseHandler response_handler,
                           ContentReceiver content_receiver) {
   return cli_->Get(path, headers, std::move(response_handler),
                    std::move(content_receiver));
 }
-Result Client::Get(const char *path, ResponseHandler response_handler,
+Result Client::Get(const std::string &path,
+                          ResponseHandler response_handler,
                           ContentReceiver content_receiver, Progress progress) {
   return cli_->Get(path, std::move(response_handler),
                    std::move(content_receiver), std::move(progress));
 }
-Result Client::Get(const char *path, const Headers &headers,
+Result Client::Get(const std::string &path, const Headers &headers,
                           ResponseHandler response_handler,
                           ContentReceiver content_receiver, Progress progress) {
   return cli_->Get(path, headers, std::move(response_handler),
                    std::move(content_receiver), std::move(progress));
 }
-Result Client::Get(const char *path, const Params &params,
+Result Client::Get(const std::string &path, const Params &params,
                           const Headers &headers, Progress progress) {
   return cli_->Get(path, params, headers, progress);
 }
-Result Client::Get(const char *path, const Params &params,
+Result Client::Get(const std::string &path, const Params &params,
                           const Headers &headers,
                           ContentReceiver content_receiver, Progress progress) {
   return cli_->Get(path, params, headers, content_receiver, progress);
 }
-Result Client::Get(const char *path, const Params &params,
+Result Client::Get(const std::string &path, const Params &params,
                           const Headers &headers,
                           ResponseHandler response_handler,
                           ContentReceiver content_receiver, Progress progress) {
@@ -6062,185 +6096,198 @@ Result Client::Get(const char *path, const Params &params,
                    progress);
 }
 
-Result Client::Head(const char *path) { return cli_->Head(path); }
-Result Client::Head(const char *path, const Headers &headers) {
+Result Client::Head(const std::string &path) { return cli_->Head(path); }
+Result Client::Head(const std::string &path, const Headers &headers) {
   return cli_->Head(path, headers);
 }
 
-Result Client::Post(const char *path) { return cli_->Post(path); }
-Result Client::Post(const char *path, const char *body,
-                           size_t content_length, const char *content_type) {
+Result Client::Post(const std::string &path) { return cli_->Post(path); }
+Result Client::Post(const std::string &path, const char *body,
+                           size_t content_length,
+                           const std::string &content_type) {
   return cli_->Post(path, body, content_length, content_type);
 }
-Result Client::Post(const char *path, const Headers &headers,
+Result Client::Post(const std::string &path, const Headers &headers,
                            const char *body, size_t content_length,
-                           const char *content_type) {
+                           const std::string &content_type) {
   return cli_->Post(path, headers, body, content_length, content_type);
 }
-Result Client::Post(const char *path, const std::string &body,
-                           const char *content_type) {
+Result Client::Post(const std::string &path, const std::string &body,
+                           const std::string &content_type) {
   return cli_->Post(path, body, content_type);
 }
-Result Client::Post(const char *path, const Headers &headers,
-                           const std::string &body, const char *content_type) {
+Result Client::Post(const std::string &path, const Headers &headers,
+                           const std::string &body,
+                           const std::string &content_type) {
   return cli_->Post(path, headers, body, content_type);
 }
-Result Client::Post(const char *path, size_t content_length,
+Result Client::Post(const std::string &path, size_t content_length,
                            ContentProvider content_provider,
-                           const char *content_type) {
+                           const std::string &content_type) {
   return cli_->Post(path, content_length, std::move(content_provider),
                     content_type);
 }
-Result Client::Post(const char *path,
+Result Client::Post(const std::string &path,
                            ContentProviderWithoutLength content_provider,
-                           const char *content_type) {
+                           const std::string &content_type) {
   return cli_->Post(path, std::move(content_provider), content_type);
 }
-Result Client::Post(const char *path, const Headers &headers,
+Result Client::Post(const std::string &path, const Headers &headers,
                            size_t content_length,
                            ContentProvider content_provider,
-                           const char *content_type) {
+                           const std::string &content_type) {
   return cli_->Post(path, headers, content_length, std::move(content_provider),
                     content_type);
 }
-Result Client::Post(const char *path, const Headers &headers,
+Result Client::Post(const std::string &path, const Headers &headers,
                            ContentProviderWithoutLength content_provider,
-                           const char *content_type) {
+                           const std::string &content_type) {
   return cli_->Post(path, headers, std::move(content_provider), content_type);
 }
-Result Client::Post(const char *path, const Params &params) {
+Result Client::Post(const std::string &path, const Params &params) {
   return cli_->Post(path, params);
 }
-Result Client::Post(const char *path, const Headers &headers,
+Result Client::Post(const std::string &path, const Headers &headers,
                            const Params &params) {
   return cli_->Post(path, headers, params);
 }
-Result Client::Post(const char *path,
+Result Client::Post(const std::string &path,
                            const MultipartFormDataItems &items) {
   return cli_->Post(path, items);
 }
-Result Client::Post(const char *path, const Headers &headers,
+Result Client::Post(const std::string &path, const Headers &headers,
                            const MultipartFormDataItems &items) {
   return cli_->Post(path, headers, items);
 }
-Result Client::Post(const char *path, const Headers &headers,
+Result Client::Post(const std::string &path, const Headers &headers,
                            const MultipartFormDataItems &items,
                            const std::string &boundary) {
   return cli_->Post(path, headers, items, boundary);
 }
-Result Client::Put(const char *path) { return cli_->Put(path); }
-Result Client::Put(const char *path, const char *body,
-                          size_t content_length, const char *content_type) {
+Result Client::Put(const std::string &path) { return cli_->Put(path); }
+Result Client::Put(const std::string &path, const char *body,
+                          size_t content_length,
+                          const std::string &content_type) {
   return cli_->Put(path, body, content_length, content_type);
 }
-Result Client::Put(const char *path, const Headers &headers,
+Result Client::Put(const std::string &path, const Headers &headers,
                           const char *body, size_t content_length,
-                          const char *content_type) {
+                          const std::string &content_type) {
   return cli_->Put(path, headers, body, content_length, content_type);
 }
-Result Client::Put(const char *path, const std::string &body,
-                          const char *content_type) {
+Result Client::Put(const std::string &path, const std::string &body,
+                          const std::string &content_type) {
   return cli_->Put(path, body, content_type);
 }
-Result Client::Put(const char *path, const Headers &headers,
-                          const std::string &body, const char *content_type) {
+Result Client::Put(const std::string &path, const Headers &headers,
+                          const std::string &body,
+                          const std::string &content_type) {
   return cli_->Put(path, headers, body, content_type);
 }
-Result Client::Put(const char *path, size_t content_length,
+Result Client::Put(const std::string &path, size_t content_length,
                           ContentProvider content_provider,
-                          const char *content_type) {
+                          const std::string &content_type) {
   return cli_->Put(path, content_length, std::move(content_provider),
                    content_type);
 }
-Result Client::Put(const char *path,
+Result Client::Put(const std::string &path,
                           ContentProviderWithoutLength content_provider,
-                          const char *content_type) {
+                          const std::string &content_type) {
   return cli_->Put(path, std::move(content_provider), content_type);
 }
-Result Client::Put(const char *path, const Headers &headers,
+Result Client::Put(const std::string &path, const Headers &headers,
                           size_t content_length,
                           ContentProvider content_provider,
-                          const char *content_type) {
+                          const std::string &content_type) {
   return cli_->Put(path, headers, content_length, std::move(content_provider),
                    content_type);
 }
-Result Client::Put(const char *path, const Headers &headers,
+Result Client::Put(const std::string &path, const Headers &headers,
                           ContentProviderWithoutLength content_provider,
-                          const char *content_type) {
+                          const std::string &content_type) {
   return cli_->Put(path, headers, std::move(content_provider), content_type);
 }
-Result Client::Put(const char *path, const Params &params) {
+Result Client::Put(const std::string &path, const Params &params) {
   return cli_->Put(path, params);
 }
-Result Client::Put(const char *path, const Headers &headers,
+Result Client::Put(const std::string &path, const Headers &headers,
                           const Params &params) {
   return cli_->Put(path, headers, params);
 }
-Result Client::Patch(const char *path) { return cli_->Patch(path); }
-Result Client::Patch(const char *path, const char *body,
-                            size_t content_length, const char *content_type) {
+Result Client::Patch(const std::string &path) {
+  return cli_->Patch(path);
+}
+Result Client::Patch(const std::string &path, const char *body,
+                            size_t content_length,
+                            const std::string &content_type) {
   return cli_->Patch(path, body, content_length, content_type);
 }
-Result Client::Patch(const char *path, const Headers &headers,
+Result Client::Patch(const std::string &path, const Headers &headers,
                             const char *body, size_t content_length,
-                            const char *content_type) {
+                            const std::string &content_type) {
   return cli_->Patch(path, headers, body, content_length, content_type);
 }
-Result Client::Patch(const char *path, const std::string &body,
-                            const char *content_type) {
+Result Client::Patch(const std::string &path, const std::string &body,
+                            const std::string &content_type) {
   return cli_->Patch(path, body, content_type);
 }
-Result Client::Patch(const char *path, const Headers &headers,
-                            const std::string &body, const char *content_type) {
+Result Client::Patch(const std::string &path, const Headers &headers,
+                            const std::string &body,
+                            const std::string &content_type) {
   return cli_->Patch(path, headers, body, content_type);
 }
-Result Client::Patch(const char *path, size_t content_length,
+Result Client::Patch(const std::string &path, size_t content_length,
                             ContentProvider content_provider,
-                            const char *content_type) {
+                            const std::string &content_type) {
   return cli_->Patch(path, content_length, std::move(content_provider),
                      content_type);
 }
-Result Client::Patch(const char *path,
+Result Client::Patch(const std::string &path,
                             ContentProviderWithoutLength content_provider,
-                            const char *content_type) {
+                            const std::string &content_type) {
   return cli_->Patch(path, std::move(content_provider), content_type);
 }
-Result Client::Patch(const char *path, const Headers &headers,
+Result Client::Patch(const std::string &path, const Headers &headers,
                             size_t content_length,
                             ContentProvider content_provider,
-                            const char *content_type) {
+                            const std::string &content_type) {
   return cli_->Patch(path, headers, content_length, std::move(content_provider),
                      content_type);
 }
-Result Client::Patch(const char *path, const Headers &headers,
+Result Client::Patch(const std::string &path, const Headers &headers,
                             ContentProviderWithoutLength content_provider,
-                            const char *content_type) {
+                            const std::string &content_type) {
   return cli_->Patch(path, headers, std::move(content_provider), content_type);
 }
-Result Client::Delete(const char *path) { return cli_->Delete(path); }
-Result Client::Delete(const char *path, const Headers &headers) {
+Result Client::Delete(const std::string &path) {
+  return cli_->Delete(path);
+}
+Result Client::Delete(const std::string &path, const Headers &headers) {
   return cli_->Delete(path, headers);
 }
-Result Client::Delete(const char *path, const char *body,
-                             size_t content_length, const char *content_type) {
+Result Client::Delete(const std::string &path, const char *body,
+                             size_t content_length,
+                             const std::string &content_type) {
   return cli_->Delete(path, body, content_length, content_type);
 }
-Result Client::Delete(const char *path, const Headers &headers,
+Result Client::Delete(const std::string &path, const Headers &headers,
                              const char *body, size_t content_length,
-                             const char *content_type) {
+                             const std::string &content_type) {
   return cli_->Delete(path, headers, body, content_length, content_type);
 }
-Result Client::Delete(const char *path, const std::string &body,
-                             const char *content_type) {
+Result Client::Delete(const std::string &path, const std::string &body,
+                             const std::string &content_type) {
   return cli_->Delete(path, body, content_type);
 }
-Result Client::Delete(const char *path, const Headers &headers,
+Result Client::Delete(const std::string &path, const Headers &headers,
                              const std::string &body,
-                             const char *content_type) {
+                             const std::string &content_type) {
   return cli_->Delete(path, headers, body, content_type);
 }
-Result Client::Options(const char *path) { return cli_->Options(path); }
-Result Client::Options(const char *path, const Headers &headers) {
+Result Client::Options(const std::string &path) {
+  return cli_->Options(path);
+}
+Result Client::Options(const std::string &path, const Headers &headers) {
   return cli_->Options(path, headers);
 }
 
@@ -6252,6 +6299,8 @@ Result Client::send(const Request &req) { return cli_->send(req); }
 
 size_t Client::is_socket_open() const { return cli_->is_socket_open(); }
 
+socket_t Client::socket() const { return cli_->socket(); }
+
 void Client::stop() { cli_->stop(); }
 
 void
@@ -6285,15 +6334,16 @@ void Client::set_write_timeout(time_t sec, time_t usec) {
   cli_->set_write_timeout(sec, usec);
 }
 
-void Client::set_basic_auth(const char *username, const char *password) {
+void Client::set_basic_auth(const std::string &username,
+                                   const std::string &password) {
   cli_->set_basic_auth(username, password);
 }
-void Client::set_bearer_token_auth(const char *token) {
+void Client::set_bearer_token_auth(const std::string &token) {
   cli_->set_bearer_token_auth(token);
 }
 #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
-void Client::set_digest_auth(const char *username,
-                                    const char *password) {
+void Client::set_digest_auth(const std::string &username,
+                                    const std::string &password) {
   cli_->set_digest_auth(username, password);
 }
 #endif
@@ -6309,23 +6359,23 @@ void Client::set_compress(bool on) { cli_->set_compress(on); }
 
 void Client::set_decompress(bool on) { cli_->set_decompress(on); }
 
-void Client::set_interface(const char *intf) {
+void Client::set_interface(const std::string &intf) {
   cli_->set_interface(intf);
 }
 
-void Client::set_proxy(const char *host, int port) {
+void Client::set_proxy(const std::string &host, int port) {
   cli_->set_proxy(host, port);
 }
-void Client::set_proxy_basic_auth(const char *username,
-                                         const char *password) {
+void Client::set_proxy_basic_auth(const std::string &username,
+                                         const std::string &password) {
   cli_->set_proxy_basic_auth(username, password);
 }
-void Client::set_proxy_bearer_token_auth(const char *token) {
+void Client::set_proxy_bearer_token_auth(const std::string &token) {
   cli_->set_proxy_bearer_token_auth(token);
 }
 #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
-void Client::set_proxy_digest_auth(const char *username,
-                                          const char *password) {
+void Client::set_proxy_digest_auth(const std::string &username,
+                                          const std::string &password) {
   cli_->set_proxy_digest_auth(username, password);
 }
 #endif
@@ -6339,8 +6389,8 @@ void Client::enable_server_certificate_verification(bool enabled) {
 void Client::set_logger(Logger logger) { cli_->set_logger(logger); }
 
 #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
-void Client::set_ca_cert_path(const char *ca_cert_file_path,
-                                     const char *ca_cert_dir_path) {
+void Client::set_ca_cert_path(const std::string &ca_cert_file_path,
+                                     const std::string &ca_cert_dir_path) {
   cli_->set_ca_cert_path(ca_cert_file_path, ca_cert_dir_path);
 }
 
index ed165bcd4b70f7c352bac4368a213d6f5c227bf5..ce146e73397beec9c61ead6bd6966e599df9ad8d 100644 (file)
@@ -8,7 +8,7 @@
 #ifndef CPPHTTPLIB_HTTPLIB_H
 #define CPPHTTPLIB_HTTPLIB_H
 
-#define CPPHTTPLIB_VERSION "0.10.7"
+#define CPPHTTPLIB_VERSION "0.11.1"
 
 /*
  * Configuration
 #endif //_CRT_NONSTDC_NO_DEPRECATE
 
 #if defined(_MSC_VER)
+#if _MSC_VER < 1900
+#error Sorry, Visual Studio versions prior to 2015 are not supported
+#endif
+
+#pragma comment(lib, "ws2_32.lib")
+
 #ifdef _WIN64
 using ssize_t = __int64;
 #else
-using ssize_t = int;
-#endif
-
-#if _MSC_VER < 1900
-#define snprintf _snprintf_s
+using ssize_t = long;
 #endif
 #endif // _MSC_VER
 
@@ -154,10 +156,6 @@ using ssize_t = int;
 #define WSA_FLAG_NO_HANDLE_INHERIT 0x80
 #endif
 
-#ifdef _MSC_VER
-#pragma comment(lib, "ws2_32.lib")
-#endif
-
 #ifndef strcasecmp
 #define strcasecmp _stricmp
 #endif // strcasecmp
@@ -185,6 +183,7 @@ using socket_t = SOCKET;
 #include <pthread.h>
 #include <sys/select.h>
 #include <sys/socket.h>
+#include <sys/un.h>
 #include <unistd.h>
 
 using socket_t = int;
@@ -193,7 +192,6 @@ using socket_t = int;
 #endif
 #endif //_WIN32
 
-#include <cstring>
 #include <algorithm>
 #include <array>
 #include <atomic>
@@ -201,6 +199,7 @@ using socket_t = int;
 #include <cctype>
 #include <climits>
 #include <condition_variable>
+#include <cstring>
 #include <errno.h>
 #include <fcntl.h>
 #include <fstream>
@@ -429,22 +428,21 @@ struct Request {
   const SSL *ssl = nullptr;
 #endif
 
-  bool has_header(const char *key) const;
-  std::string get_header_value(const char *key, size_t id = 0) const;
+  bool has_header(const std::string &key) const;
+  std::string get_header_value(const std::string &key, size_t id = 0) const;
   template <typename T>
-  T get_header_value(const char *key, size_t id = 0) const;
-  size_t get_header_value_count(const char *key) const;
-  void set_header(const char *key, const char *val);
-  void set_header(const char *key, const std::string &val);
+  T get_header_value(const std::string &key, size_t id = 0) const;
+  size_t get_header_value_count(const std::string &key) const;
+  void set_header(const std::string &key, const std::string &val);
 
-  bool has_param(const char *key) const;
-  std::string get_param_value(const char *key, size_t id = 0) const;
-  size_t get_param_value_count(const char *key) const;
+  bool has_param(const std::string &key) const;
+  std::string get_param_value(const std::string &key, size_t id = 0) const;
+  size_t get_param_value_count(const std::string &key) const;
 
   bool is_multipart_form_data() const;
 
-  bool has_file(const char *key) const;
-  MultipartFormData get_file_value(const char *key) const;
+  bool has_file(const std::string &key) const;
+  MultipartFormData get_file_value(const std::string &key) const;
 
   // private members...
   size_t redirect_count_ = CPPHTTPLIB_REDIRECT_MAX_COUNT;
@@ -462,29 +460,27 @@ struct Response {
   std::string body;
   std::string location; // Redirect location
 
-  bool has_header(const char *key) const;
-  std::string get_header_value(const char *key, size_t id = 0) const;
+  bool has_header(const std::string &key) const;
+  std::string get_header_value(const std::string &key, size_t id = 0) const;
   template <typename T>
-  T get_header_value(const char *key, size_t id = 0) const;
-  size_t get_header_value_count(const char *key) const;
-  void set_header(const char *key, const char *val);
-  void set_header(const char *key, const std::string &val);
+  T get_header_value(const std::string &key, size_t id = 0) const;
+  size_t get_header_value_count(const std::string &key) const;
+  void set_header(const std::string &key, const std::string &val);
 
-  void set_redirect(const char *url, int status = 302);
   void set_redirect(const std::string &url, int status = 302);
-  void set_content(const char *s, size_t n, const char *content_type);
-  void set_content(const std::string &s, const char *content_type);
+  void set_content(const char *s, size_t n, const std::string &content_type);
+  void set_content(const std::string &s, const std::string &content_type);
 
   void set_content_provider(
-      size_t length, const char *content_type, ContentProvider provider,
+      size_t length, const std::string &content_type, ContentProvider provider,
       ContentProviderResourceReleaser resource_releaser = nullptr);
 
   void set_content_provider(
-      const char *content_type, ContentProviderWithoutLength provider,
+      const std::string &content_type, ContentProviderWithoutLength provider,
       ContentProviderResourceReleaser resource_releaser = nullptr);
 
   void set_chunked_content_provider(
-      const char *content_type, ContentProviderWithoutLength provider,
+      const std::string &content_type, ContentProviderWithoutLength provider,
       ContentProviderResourceReleaser resource_releaser = nullptr);
 
   Response() = default;
@@ -616,7 +612,7 @@ public:
   using Handler = std::function<void(const Request &, Response &)>;
 
   using ExceptionHandler =
-      std::function<void(const Request &, Response &, std::exception &e)>;
+      std::function<void(const Request &, Response &, std::exception_ptr ep)>;
 
   enum class HandlerResponse {
     Handled,
@@ -653,8 +649,8 @@ public:
   bool set_mount_point(const std::string &mount_point, const std::string &dir,
                        Headers headers = Headers());
   bool remove_mount_point(const std::string &mount_point);
-  Server &set_file_extension_and_mimetype_mapping(const char *ext,
-                                                  const char *mime);
+  Server &set_file_extension_and_mimetype_mapping(const std::string &ext,
+                                                  const std::string &mime);
   Server &set_file_request_handler(Handler handler);
 
   Server &set_error_handler(HandlerWithResponse handler);
@@ -689,11 +685,11 @@ public:
 
   Server &set_payload_max_length(size_t length);
 
-  bool bind_to_port(const char *host, int port, int socket_flags = 0);
-  int bind_to_any_port(const char *host, int socket_flags = 0);
+  bool bind_to_port(const std::string &host, int port, int socket_flags = 0);
+  int bind_to_any_port(const std::string &host, int socket_flags = 0);
   bool listen_after_bind();
 
-  bool listen(const char *host, int port, int socket_flags = 0);
+  bool listen(const std::string &host, int port, int socket_flags = 0);
 
   bool is_running() const;
   void stop();
@@ -721,9 +717,10 @@ private:
   using HandlersForContentReader =
       std::vector<std::pair<std::regex, HandlerWithContentReader>>;
 
-  socket_t create_server_socket(const char *host, int port, int socket_flags,
+  socket_t create_server_socket(const std::string &host, int port,
+                                int socket_flags,
                                 SocketOptions socket_options) const;
-  int bind_internal(const char *host, int port, int socket_flags);
+  int bind_internal(const std::string &host, int port, int socket_flags);
   bool listen_internal();
 
   bool routing(Request &req, Response &res, Stream &strm);
@@ -837,11 +834,12 @@ public:
   Error error() const { return err_; }
 
   // Request Headers
-  bool has_request_header(const char *key) const;
-  std::string get_request_header_value(const char *key, size_t id = 0) const;
+  bool has_request_header(const std::string &key) const;
+  std::string get_request_header_value(const std::string &key,
+                                       size_t id = 0) const;
   template <typename T>
-  T get_request_header_value(const char *key, size_t id = 0) const;
-  size_t get_request_header_value_count(const char *key) const;
+  T get_request_header_value(const std::string &key, size_t id = 0) const;
+  size_t get_request_header_value_count(const std::string &key) const;
 
 private:
   std::unique_ptr<Response> res_;
@@ -863,124 +861,140 @@ public:
 
   virtual bool is_valid() const;
 
-  Result Get(const char *path);
-  Result Get(const char *path, const Headers &headers);
-  Result Get(const char *path, Progress progress);
-  Result Get(const char *path, const Headers &headers, Progress progress);
-  Result Get(const char *path, ContentReceiver content_receiver);
-  Result Get(const char *path, const Headers &headers,
+  Result Get(const std::string &path);
+  Result Get(const std::string &path, const Headers &headers);
+  Result Get(const std::string &path, Progress progress);
+  Result Get(const std::string &path, const Headers &headers,
+             Progress progress);
+  Result Get(const std::string &path, ContentReceiver content_receiver);
+  Result Get(const std::string &path, const Headers &headers,
              ContentReceiver content_receiver);
-  Result Get(const char *path, ContentReceiver content_receiver,
+  Result Get(const std::string &path, ContentReceiver content_receiver,
              Progress progress);
-  Result Get(const char *path, const Headers &headers,
+  Result Get(const std::string &path, const Headers &headers,
              ContentReceiver content_receiver, Progress progress);
-  Result Get(const char *path, ResponseHandler response_handler,
+  Result Get(const std::string &path, ResponseHandler response_handler,
              ContentReceiver content_receiver);
-  Result Get(const char *path, const Headers &headers,
+  Result Get(const std::string &path, const Headers &headers,
              ResponseHandler response_handler,
              ContentReceiver content_receiver);
-  Result Get(const char *path, ResponseHandler response_handler,
+  Result Get(const std::string &path, ResponseHandler response_handler,
              ContentReceiver content_receiver, Progress progress);
-  Result Get(const char *path, const Headers &headers,
+  Result Get(const std::string &path, const Headers &headers,
              ResponseHandler response_handler, ContentReceiver content_receiver,
              Progress progress);
 
-  Result Get(const char *path, const Params &params, const Headers &headers,
+  Result Get(const std::string &path, const Params &params,
+             const Headers &headers, Progress progress = nullptr);
+  Result Get(const std::string &path, const Params &params,
+             const Headers &headers, ContentReceiver content_receiver,
              Progress progress = nullptr);
-  Result Get(const char *path, const Params &params, const Headers &headers,
+  Result Get(const std::string &path, const Params &params,
+             const Headers &headers, ResponseHandler response_handler,
              ContentReceiver content_receiver, Progress progress = nullptr);
-  Result Get(const char *path, const Params &params, const Headers &headers,
-             ResponseHandler response_handler, ContentReceiver content_receiver,
-             Progress progress = nullptr);
 
-  Result Head(const char *path);
-  Result Head(const char *path, const Headers &headers);
-
-  Result Post(const char *path);
-  Result Post(const char *path, const char *body, size_t content_length,
-              const char *content_type);
-  Result Post(const char *path, const Headers &headers, const char *body,
-              size_t content_length, const char *content_type);
-  Result Post(const char *path, const std::string &body,
-              const char *content_type);
-  Result Post(const char *path, const Headers &headers, const std::string &body,
-              const char *content_type);
-  Result Post(const char *path, size_t content_length,
-              ContentProvider content_provider, const char *content_type);
-  Result Post(const char *path, ContentProviderWithoutLength content_provider,
-              const char *content_type);
-  Result Post(const char *path, const Headers &headers, size_t content_length,
-              ContentProvider content_provider, const char *content_type);
-  Result Post(const char *path, const Headers &headers,
+  Result Head(const std::string &path);
+  Result Head(const std::string &path, const Headers &headers);
+
+  Result Post(const std::string &path);
+  Result Post(const std::string &path, const char *body, size_t content_length,
+              const std::string &content_type);
+  Result Post(const std::string &path, const Headers &headers, const char *body,
+              size_t content_length, const std::string &content_type);
+  Result Post(const std::string &path, const std::string &body,
+              const std::string &content_type);
+  Result Post(const std::string &path, const Headers &headers,
+              const std::string &body, const std::string &content_type);
+  Result Post(const std::string &path, size_t content_length,
+              ContentProvider content_provider,
+              const std::string &content_type);
+  Result Post(const std::string &path,
+              ContentProviderWithoutLength content_provider,
+              const std::string &content_type);
+  Result Post(const std::string &path, const Headers &headers,
+              size_t content_length, ContentProvider content_provider,
+              const std::string &content_type);
+  Result Post(const std::string &path, const Headers &headers,
               ContentProviderWithoutLength content_provider,
-              const char *content_type);
-  Result Post(const char *path, const Params &params);
-  Result Post(const char *path, const Headers &headers, const Params &params);
-  Result Post(const char *path, const MultipartFormDataItems &items);
-  Result Post(const char *path, const Headers &headers,
+              const std::string &content_type);
+  Result Post(const std::string &path, const Params &params);
+  Result Post(const std::string &path, const Headers &headers,
+              const Params &params);
+  Result Post(const std::string &path, const MultipartFormDataItems &items);
+  Result Post(const std::string &path, const Headers &headers,
               const MultipartFormDataItems &items);
-  Result Post(const char *path, const Headers &headers,
+  Result Post(const std::string &path, const Headers &headers,
               const MultipartFormDataItems &items, const std::string &boundary);
 
-  Result Put(const char *path);
-  Result Put(const char *path, const char *body, size_t content_length,
-             const char *content_type);
-  Result Put(const char *path, const Headers &headers, const char *body,
-             size_t content_length, const char *content_type);
-  Result Put(const char *path, const std::string &body,
-             const char *content_type);
-  Result Put(const char *path, const Headers &headers, const std::string &body,
-             const char *content_type);
-  Result Put(const char *path, size_t content_length,
-             ContentProvider content_provider, const char *content_type);
-  Result Put(const char *path, ContentProviderWithoutLength content_provider,
-             const char *content_type);
-  Result Put(const char *path, const Headers &headers, size_t content_length,
-             ContentProvider content_provider, const char *content_type);
-  Result Put(const char *path, const Headers &headers,
+  Result Put(const std::string &path);
+  Result Put(const std::string &path, const char *body, size_t content_length,
+             const std::string &content_type);
+  Result Put(const std::string &path, const Headers &headers, const char *body,
+             size_t content_length, const std::string &content_type);
+  Result Put(const std::string &path, const std::string &body,
+             const std::string &content_type);
+  Result Put(const std::string &path, const Headers &headers,
+             const std::string &body, const std::string &content_type);
+  Result Put(const std::string &path, size_t content_length,
+             ContentProvider content_provider, const std::string &content_type);
+  Result Put(const std::string &path,
              ContentProviderWithoutLength content_provider,
-             const char *content_type);
-  Result Put(const char *path, const Params &params);
-  Result Put(const char *path, const Headers &headers, const Params &params);
-
-  Result Patch(const char *path);
-  Result Patch(const char *path, const char *body, size_t content_length,
-               const char *content_type);
-  Result Patch(const char *path, const Headers &headers, const char *body,
-               size_t content_length, const char *content_type);
-  Result Patch(const char *path, const std::string &body,
-               const char *content_type);
-  Result Patch(const char *path, const Headers &headers,
-               const std::string &body, const char *content_type);
-  Result Patch(const char *path, size_t content_length,
-               ContentProvider content_provider, const char *content_type);
-  Result Patch(const char *path, ContentProviderWithoutLength content_provider,
-               const char *content_type);
-  Result Patch(const char *path, const Headers &headers, size_t content_length,
-               ContentProvider content_provider, const char *content_type);
-  Result Patch(const char *path, const Headers &headers,
+             const std::string &content_type);
+  Result Put(const std::string &path, const Headers &headers,
+             size_t content_length, ContentProvider content_provider,
+             const std::string &content_type);
+  Result Put(const std::string &path, const Headers &headers,
+             ContentProviderWithoutLength content_provider,
+             const std::string &content_type);
+  Result Put(const std::string &path, const Params &params);
+  Result Put(const std::string &path, const Headers &headers,
+             const Params &params);
+
+  Result Patch(const std::string &path);
+  Result Patch(const std::string &path, const char *body, size_t content_length,
+               const std::string &content_type);
+  Result Patch(const std::string &path, const Headers &headers,
+               const char *body, size_t content_length,
+               const std::string &content_type);
+  Result Patch(const std::string &path, const std::string &body,
+               const std::string &content_type);
+  Result Patch(const std::string &path, const Headers &headers,
+               const std::string &body, const std::string &content_type);
+  Result Patch(const std::string &path, size_t content_length,
+               ContentProvider content_provider,
+               const std::string &content_type);
+  Result Patch(const std::string &path,
+               ContentProviderWithoutLength content_provider,
+               const std::string &content_type);
+  Result Patch(const std::string &path, const Headers &headers,
+               size_t content_length, ContentProvider content_provider,
+               const std::string &content_type);
+  Result Patch(const std::string &path, const Headers &headers,
                ContentProviderWithoutLength content_provider,
-               const char *content_type);
-
-  Result Delete(const char *path);
-  Result Delete(const char *path, const Headers &headers);
-  Result Delete(const char *path, const char *body, size_t content_length,
-                const char *content_type);
-  Result Delete(const char *path, const Headers &headers, const char *body,
-                size_t content_length, const char *content_type);
-  Result Delete(const char *path, const std::string &body,
-                const char *content_type);
-  Result Delete(const char *path, const Headers &headers,
-                const std::string &body, const char *content_type);
-
-  Result Options(const char *path);
-  Result Options(const char *path, const Headers &headers);
+               const std::string &content_type);
+
+  Result Delete(const std::string &path);
+  Result Delete(const std::string &path, const Headers &headers);
+  Result Delete(const std::string &path, const char *body,
+                size_t content_length, const std::string &content_type);
+  Result Delete(const std::string &path, const Headers &headers,
+                const char *body, size_t content_length,
+                const std::string &content_type);
+  Result Delete(const std::string &path, const std::string &body,
+                const std::string &content_type);
+  Result Delete(const std::string &path, const Headers &headers,
+                const std::string &body, const std::string &content_type);
+
+  Result Options(const std::string &path);
+  Result Options(const std::string &path, const Headers &headers);
 
   bool send(Request &req, Response &res, Error &error);
   Result send(const Request &req);
 
   size_t is_socket_open() const;
 
+  socket_t socket() const;
+
   void stop();
 
   void set_hostname_addr_map(std::map<std::string, std::string> addr_map);
@@ -1004,10 +1018,11 @@ public:
   template <class Rep, class Period>
   void set_write_timeout(const std::chrono::duration<Rep, Period> &duration);
 
-  void set_basic_auth(const char *username, const char *password);
-  void set_bearer_token_auth(const char *token);
+  void set_basic_auth(const std::string &username, const std::string &password);
+  void set_bearer_token_auth(const std::string &token);
 #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
-  void set_digest_auth(const char *username, const char *password);
+  void set_digest_auth(const std::string &username,
+                       const std::string &password);
 #endif
 
   void set_keep_alive(bool on);
@@ -1019,18 +1034,20 @@ public:
 
   void set_decompress(bool on);
 
-  void set_interface(const char *intf);
+  void set_interface(const std::string &intf);
 
-  void set_proxy(const char *host, int port);
-  void set_proxy_basic_auth(const char *username, const char *password);
-  void set_proxy_bearer_token_auth(const char *token);
+  void set_proxy(const std::string &host, int port);
+  void set_proxy_basic_auth(const std::string &username,
+                            const std::string &password);
+  void set_proxy_bearer_token_auth(const std::string &token);
 #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
-  void set_proxy_digest_auth(const char *username, const char *password);
+  void set_proxy_digest_auth(const std::string &username,
+                             const std::string &password);
 #endif
 
 #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
-  void set_ca_cert_path(const char *ca_cert_file_path,
-                        const char *ca_cert_dir_path = nullptr);
+  void set_ca_cert_path(const std::string &ca_cert_file_path,
+                        const std::string &ca_cert_dir_path = std::string());
   void set_ca_cert_store(X509_STORE *ca_cert_store);
 #endif
 
@@ -1160,16 +1177,16 @@ private:
   bool handle_request(Stream &strm, Request &req, Response &res,
                       bool close_connection, Error &error);
   std::unique_ptr<Response> send_with_content_provider(
-      Request &req,
-      // const char *method, const char *path, const Headers &headers,
-      const char *body, size_t content_length, ContentProvider content_provider,
+      Request &req, const char *body, size_t content_length,
+      ContentProvider content_provider,
       ContentProviderWithoutLength content_provider_without_length,
-      const char *content_type, Error &error);
+      const std::string &content_type, Error &error);
   Result send_with_content_provider(
-      const char *method, const char *path, const Headers &headers,
-      const char *body, size_t content_length, ContentProvider content_provider,
+      const std::string &method, const std::string &path,
+      const Headers &headers, const char *body, size_t content_length,
+      ContentProvider content_provider,
       ContentProviderWithoutLength content_provider_without_length,
-      const char *content_type);
+      const std::string &content_type);
 
   std::string adjust_host_string(const std::string &host) const;
 
@@ -1200,122 +1217,138 @@ public:
 
   bool is_valid() const;
 
-  Result Get(const char *path);
-  Result Get(const char *path, const Headers &headers);
-  Result Get(const char *path, Progress progress);
-  Result Get(const char *path, const Headers &headers, Progress progress);
-  Result Get(const char *path, ContentReceiver content_receiver);
-  Result Get(const char *path, const Headers &headers,
+  Result Get(const std::string &path);
+  Result Get(const std::string &path, const Headers &headers);
+  Result Get(const std::string &path, Progress progress);
+  Result Get(const std::string &path, const Headers &headers,
+             Progress progress);
+  Result Get(const std::string &path, ContentReceiver content_receiver);
+  Result Get(const std::string &path, const Headers &headers,
              ContentReceiver content_receiver);
-  Result Get(const char *path, ContentReceiver content_receiver,
+  Result Get(const std::string &path, ContentReceiver content_receiver,
              Progress progress);
-  Result Get(const char *path, const Headers &headers,
+  Result Get(const std::string &path, const Headers &headers,
              ContentReceiver content_receiver, Progress progress);
-  Result Get(const char *path, ResponseHandler response_handler,
+  Result Get(const std::string &path, ResponseHandler response_handler,
              ContentReceiver content_receiver);
-  Result Get(const char *path, const Headers &headers,
+  Result Get(const std::string &path, const Headers &headers,
              ResponseHandler response_handler,
              ContentReceiver content_receiver);
-  Result Get(const char *path, const Headers &headers,
+  Result Get(const std::string &path, const Headers &headers,
              ResponseHandler response_handler, ContentReceiver content_receiver,
              Progress progress);
-  Result Get(const char *path, ResponseHandler response_handler,
+  Result Get(const std::string &path, ResponseHandler response_handler,
              ContentReceiver content_receiver, Progress progress);
 
-  Result Get(const char *path, const Params &params, const Headers &headers,
+  Result Get(const std::string &path, const Params &params,
+             const Headers &headers, Progress progress = nullptr);
+  Result Get(const std::string &path, const Params &params,
+             const Headers &headers, ContentReceiver content_receiver,
              Progress progress = nullptr);
-  Result Get(const char *path, const Params &params, const Headers &headers,
+  Result Get(const std::string &path, const Params &params,
+             const Headers &headers, ResponseHandler response_handler,
              ContentReceiver content_receiver, Progress progress = nullptr);
-  Result Get(const char *path, const Params &params, const Headers &headers,
-             ResponseHandler response_handler, ContentReceiver content_receiver,
-             Progress progress = nullptr);
 
-  Result Head(const char *path);
-  Result Head(const char *path, const Headers &headers);
-
-  Result Post(const char *path);
-  Result Post(const char *path, const char *body, size_t content_length,
-              const char *content_type);
-  Result Post(const char *path, const Headers &headers, const char *body,
-              size_t content_length, const char *content_type);
-  Result Post(const char *path, const std::string &body,
-              const char *content_type);
-  Result Post(const char *path, const Headers &headers, const std::string &body,
-              const char *content_type);
-  Result Post(const char *path, size_t content_length,
-              ContentProvider content_provider, const char *content_type);
-  Result Post(const char *path, ContentProviderWithoutLength content_provider,
-              const char *content_type);
-  Result Post(const char *path, const Headers &headers, size_t content_length,
-              ContentProvider content_provider, const char *content_type);
-  Result Post(const char *path, const Headers &headers,
+  Result Head(const std::string &path);
+  Result Head(const std::string &path, const Headers &headers);
+
+  Result Post(const std::string &path);
+  Result Post(const std::string &path, const char *body, size_t content_length,
+              const std::string &content_type);
+  Result Post(const std::string &path, const Headers &headers, const char *body,
+              size_t content_length, const std::string &content_type);
+  Result Post(const std::string &path, const std::string &body,
+              const std::string &content_type);
+  Result Post(const std::string &path, const Headers &headers,
+              const std::string &body, const std::string &content_type);
+  Result Post(const std::string &path, size_t content_length,
+              ContentProvider content_provider,
+              const std::string &content_type);
+  Result Post(const std::string &path,
               ContentProviderWithoutLength content_provider,
-              const char *content_type);
-  Result Post(const char *path, const Params &params);
-  Result Post(const char *path, const Headers &headers, const Params &params);
-  Result Post(const char *path, const MultipartFormDataItems &items);
-  Result Post(const char *path, const Headers &headers,
+              const std::string &content_type);
+  Result Post(const std::string &path, const Headers &headers,
+              size_t content_length, ContentProvider content_provider,
+              const std::string &content_type);
+  Result Post(const std::string &path, const Headers &headers,
+              ContentProviderWithoutLength content_provider,
+              const std::string &content_type);
+  Result Post(const std::string &path, const Params &params);
+  Result Post(const std::string &path, const Headers &headers,
+              const Params &params);
+  Result Post(const std::string &path, const MultipartFormDataItems &items);
+  Result Post(const std::string &path, const Headers &headers,
               const MultipartFormDataItems &items);
-  Result Post(const char *path, const Headers &headers,
+  Result Post(const std::string &path, const Headers &headers,
               const MultipartFormDataItems &items, const std::string &boundary);
-  Result Put(const char *path);
-  Result Put(const char *path, const char *body, size_t content_length,
-             const char *content_type);
-  Result Put(const char *path, const Headers &headers, const char *body,
-             size_t content_length, const char *content_type);
-  Result Put(const char *path, const std::string &body,
-             const char *content_type);
-  Result Put(const char *path, const Headers &headers, const std::string &body,
-             const char *content_type);
-  Result Put(const char *path, size_t content_length,
-             ContentProvider content_provider, const char *content_type);
-  Result Put(const char *path, ContentProviderWithoutLength content_provider,
-             const char *content_type);
-  Result Put(const char *path, const Headers &headers, size_t content_length,
-             ContentProvider content_provider, const char *content_type);
-  Result Put(const char *path, const Headers &headers,
+  Result Put(const std::string &path);
+  Result Put(const std::string &path, const char *body, size_t content_length,
+             const std::string &content_type);
+  Result Put(const std::string &path, const Headers &headers, const char *body,
+             size_t content_length, const std::string &content_type);
+  Result Put(const std::string &path, const std::string &body,
+             const std::string &content_type);
+  Result Put(const std::string &path, const Headers &headers,
+             const std::string &body, const std::string &content_type);
+  Result Put(const std::string &path, size_t content_length,
+             ContentProvider content_provider, const std::string &content_type);
+  Result Put(const std::string &path,
+             ContentProviderWithoutLength content_provider,
+             const std::string &content_type);
+  Result Put(const std::string &path, const Headers &headers,
+             size_t content_length, ContentProvider content_provider,
+             const std::string &content_type);
+  Result Put(const std::string &path, const Headers &headers,
              ContentProviderWithoutLength content_provider,
-             const char *content_type);
-  Result Put(const char *path, const Params &params);
-  Result Put(const char *path, const Headers &headers, const Params &params);
-  Result Patch(const char *path);
-  Result Patch(const char *path, const char *body, size_t content_length,
-               const char *content_type);
-  Result Patch(const char *path, const Headers &headers, const char *body,
-               size_t content_length, const char *content_type);
-  Result Patch(const char *path, const std::string &body,
-               const char *content_type);
-  Result Patch(const char *path, const Headers &headers,
-               const std::string &body, const char *content_type);
-  Result Patch(const char *path, size_t content_length,
-               ContentProvider content_provider, const char *content_type);
-  Result Patch(const char *path, ContentProviderWithoutLength content_provider,
-               const char *content_type);
-  Result Patch(const char *path, const Headers &headers, size_t content_length,
-               ContentProvider content_provider, const char *content_type);
-  Result Patch(const char *path, const Headers &headers,
+             const std::string &content_type);
+  Result Put(const std::string &path, const Params &params);
+  Result Put(const std::string &path, const Headers &headers,
+             const Params &params);
+  Result Patch(const std::string &path);
+  Result Patch(const std::string &path, const char *body, size_t content_length,
+               const std::string &content_type);
+  Result Patch(const std::string &path, const Headers &headers,
+               const char *body, size_t content_length,
+               const std::string &content_type);
+  Result Patch(const std::string &path, const std::string &body,
+               const std::string &content_type);
+  Result Patch(const std::string &path, const Headers &headers,
+               const std::string &body, const std::string &content_type);
+  Result Patch(const std::string &path, size_t content_length,
+               ContentProvider content_provider,
+               const std::string &content_type);
+  Result Patch(const std::string &path,
                ContentProviderWithoutLength content_provider,
-               const char *content_type);
-
-  Result Delete(const char *path);
-  Result Delete(const char *path, const Headers &headers);
-  Result Delete(const char *path, const char *body, size_t content_length,
-                const char *content_type);
-  Result Delete(const char *path, const Headers &headers, const char *body,
-                size_t content_length, const char *content_type);
-  Result Delete(const char *path, const std::string &body,
-                const char *content_type);
-  Result Delete(const char *path, const Headers &headers,
-                const std::string &body, const char *content_type);
-
-  Result Options(const char *path);
-  Result Options(const char *path, const Headers &headers);
+               const std::string &content_type);
+  Result Patch(const std::string &path, const Headers &headers,
+               size_t content_length, ContentProvider content_provider,
+               const std::string &content_type);
+  Result Patch(const std::string &path, const Headers &headers,
+               ContentProviderWithoutLength content_provider,
+               const std::string &content_type);
+
+  Result Delete(const std::string &path);
+  Result Delete(const std::string &path, const Headers &headers);
+  Result Delete(const std::string &path, const char *body,
+                size_t content_length, const std::string &content_type);
+  Result Delete(const std::string &path, const Headers &headers,
+                const char *body, size_t content_length,
+                const std::string &content_type);
+  Result Delete(const std::string &path, const std::string &body,
+                const std::string &content_type);
+  Result Delete(const std::string &path, const Headers &headers,
+                const std::string &body, const std::string &content_type);
+
+  Result Options(const std::string &path);
+  Result Options(const std::string &path, const Headers &headers);
 
   bool send(Request &req, Response &res, Error &error);
   Result send(const Request &req);
 
   size_t is_socket_open() const;
 
+  socket_t socket() const;
+
   void stop();
 
   void set_hostname_addr_map(std::map<std::string, std::string> addr_map);
@@ -1339,10 +1372,11 @@ public:
   template <class Rep, class Period>
   void set_write_timeout(const std::chrono::duration<Rep, Period> &duration);
 
-  void set_basic_auth(const char *username, const char *password);
-  void set_bearer_token_auth(const char *token);
+  void set_basic_auth(const std::string &username, const std::string &password);
+  void set_bearer_token_auth(const std::string &token);
 #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
-  void set_digest_auth(const char *username, const char *password);
+  void set_digest_auth(const std::string &username,
+                       const std::string &password);
 #endif
 
   void set_keep_alive(bool on);
@@ -1354,13 +1388,15 @@ public:
 
   void set_decompress(bool on);
 
-  void set_interface(const char *intf);
+  void set_interface(const std::string &intf);
 
-  void set_proxy(const char *host, int port);
-  void set_proxy_basic_auth(const char *username, const char *password);
-  void set_proxy_bearer_token_auth(const char *token);
+  void set_proxy(const std::string &host, int port);
+  void set_proxy_basic_auth(const std::string &username,
+                            const std::string &password);
+  void set_proxy_bearer_token_auth(const std::string &token);
 #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
-  void set_proxy_digest_auth(const char *username, const char *password);
+  void set_proxy_digest_auth(const std::string &username,
+                             const std::string &password);
 #endif
 
 #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
@@ -1371,8 +1407,8 @@ public:
 
   // SSL
 #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
-  void set_ca_cert_path(const char *ca_cert_file_path,
-                        const char *ca_cert_dir_path = nullptr);
+  void set_ca_cert_path(const std::string &ca_cert_file_path,
+                        const std::string &ca_cert_dir_path = std::string());
 
   void set_ca_cert_store(X509_STORE *ca_cert_store);
 
@@ -1487,12 +1523,13 @@ inline void duration_to_sec_and_usec(const T &duration, U callback) {
 }
 
 template <typename T>
-inline T get_header_value(const Headers & /*headers*/, const char * /*key*/,
-                          size_t /*id*/ = 0, uint64_t /*def*/ = 0) {}
+inline T get_header_value(const Headers & /*headers*/,
+                          const std::string & /*key*/, size_t /*id*/ = 0,
+                          uint64_t /*def*/ = 0) {}
 
 template <>
 inline uint64_t get_header_value<uint64_t>(const Headers &headers,
-                                           const char *key, size_t id,
+                                           const std::string &key, size_t id,
                                            uint64_t def) {
   auto rng = headers.equal_range(key);
   auto it = rng.first;
@@ -1506,12 +1543,12 @@ inline uint64_t get_header_value<uint64_t>(const Headers &headers,
 } // namespace detail
 
 template <typename T>
-inline T Request::get_header_value(const char *key, size_t id) const {
+inline T Request::get_header_value(const std::string &key, size_t id) const {
   return detail::get_header_value<T>(headers, key, id, 0);
 }
 
 template <typename T>
-inline T Response::get_header_value(const char *key, size_t id) const {
+inline T Response::get_header_value(const std::string &key, size_t id) const {
   return detail::get_header_value<T>(headers, key, id, 0);
 }
 
@@ -1520,11 +1557,7 @@ inline ssize_t Stream::write_format(const char *fmt, const Args &...args) {
   const auto bufsiz = 2048;
   std::array<char, bufsiz> buf{};
 
-#if defined(_MSC_VER) && _MSC_VER < 1900
-  auto sn = _snprintf_s(buf.data(), bufsiz, _TRUNCATE, fmt, args...);
-#else
   auto sn = snprintf(buf.data(), buf.size() - 1, fmt, args...);
-#endif
   if (sn <= 0) { return sn; }
 
   auto n = static_cast<size_t>(sn);
@@ -1534,14 +1567,8 @@ inline ssize_t Stream::write_format(const char *fmt, const Args &...args) {
 
     while (n >= glowable_buf.size() - 1) {
       glowable_buf.resize(glowable_buf.size() * 2);
-#if defined(_MSC_VER) && _MSC_VER < 1900
-      n = static_cast<size_t>(_snprintf_s(&glowable_buf[0], glowable_buf.size(),
-                                          glowable_buf.size() - 1, fmt,
-                                          args...));
-#else
       n = static_cast<size_t>(
           snprintf(&glowable_buf[0], glowable_buf.size() - 1, fmt, args...));
-#endif
     }
     return write(&glowable_buf[0], n);
   } else {
@@ -1621,7 +1648,8 @@ inline std::ostream &operator<<(std::ostream &os, const Error &obj) {
 }
 
 template <typename T>
-inline T Result::get_request_header_value(const char *key, size_t id) const {
+inline T Result::get_request_header_value(const std::string &key,
+                                          size_t id) const {
   return detail::get_header_value<T>(request_headers_, key, id, 0);
 }
 
@@ -1670,11 +1698,11 @@ Client::set_write_timeout(const std::chrono::duration<Rep, Period> &duration) {
  * .h + .cc.
  */
 
-std::string hosted_at(const char *hostname);
+std::string hosted_at(const std::string &hostname);
 
-void hosted_at(const char *hostname, std::vector<std::string> &addrs);
+void hosted_at(const std::string &hostname, std::vector<std::string> &addrs);
 
-std::string append_query_params(const char *path, const Params &params);
+std::string append_query_params(const std::string &path, const Params &params);
 
 std::pair<std::string, std::string> make_range_header(Ranges ranges);
 
@@ -1702,13 +1730,13 @@ bool process_client_socket(socket_t sock, time_t read_timeout_sec,
                            std::function<bool(Stream &)> callback);
 
 socket_t create_client_socket(
-    const char *host, const char *ip, int port, int address_family,
-    bool tcp_nodelay, SocketOptions socket_options,
+    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);
 
-const char *get_header_value(const Headers &headers, const char *key,
+const char *get_header_value(const Headers &headers, const std::string &key,
                              size_t id = 0, const char *def = nullptr);
 
 std::string params_to_query_str(const Params &params);