]> git.ipfire.org Git - thirdparty/ccache.git/commitdiff
Use cpp-httplib 0.9.2 (#905)
authorGregor Jasny <gregor.jasny@logmein.com>
Sun, 25 Jul 2021 05:08:32 +0000 (07:08 +0200)
committerGitHub <noreply@github.com>
Sun, 25 Jul 2021 05:08:32 +0000 (07:08 +0200)
LICENSE.adoc
src/storage/secondary/HttpStorage.cpp
src/third_party/httplib.h

index 1116ff8722d54d224fa9c2e4c1eb6fe0bb5a205b..e7f75bc720fd1ed85c2807d2799e622e2405cd5b 100644 (file)
@@ -678,7 +678,7 @@ src/third_party/httplib.h
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 cpp-httplib - A C++11 single-file header-only cross platform HTTP/HTTPS library.
-Copied from https://github.com/yhirose/cpp-httplib[cpp-httplib] v0.9.1.
+Copied from https://github.com/yhirose/cpp-httplib[cpp-httplib] v0.9.2.
 The library has the following license text:
 
 -------------------------------------------------------------------------------
index 7d54687f8e92abec5ccc8c38222c1b303ce2c9a2..1e1a58df0bfe1f0e086b68d247acca33429ab6c0 100644 (file)
@@ -56,43 +56,6 @@ private:
   std::string get_entry_path(const Digest& key) const;
 };
 
-nonstd::string_view
-to_string(const httplib::Error error)
-{
-  using httplib::Error;
-
-  switch (error) {
-  case Error::Success:
-    return "Success";
-  case Error::Connection:
-    return "Connection";
-  case Error::BindIPAddress:
-    return "BindIPAddress";
-  case Error::Read:
-    return "Read";
-  case Error::Write:
-    return "Write";
-  case Error::ExceedRedirectCount:
-    return "ExceedRedirectCount";
-  case Error::Canceled:
-    return "Canceled";
-  case Error::SSLConnection:
-    return "SSLConnection";
-  case Error::SSLLoadingCerts:
-    return "SSLLoadingCerts";
-  case Error::SSLServerVerification:
-    return "SSLServerVerification";
-  case Error::UnsupportedMultipartBoundaryChars:
-    return "UnsupportedMultipartBoundaryChars";
-  case Error::Compression:
-    return "Compression";
-  case Error::Unknown:
-    break;
-  }
-
-  return "Unknown";
-}
-
 std::string
 get_url_path(const Url& url)
 {
@@ -107,6 +70,7 @@ Url
 get_partial_url(const Url& from_url)
 {
   Url url;
+  url.scheme(from_url.scheme());
   url.host(from_url.host(), from_url.ip_version());
   if (!from_url.port().empty()) {
     url.port(from_url.port());
@@ -114,24 +78,6 @@ get_partial_url(const Url& from_url)
   return url;
 }
 
-std::string
-get_host_header_value(const Url& url)
-{
-  // We need to construct an HTTP Host header that follows the same IPv6
-  // escaping rules like a URL.
-  const auto rendered_value = get_partial_url(url).str();
-
-  // The rendered_value now contains a string like "//[::1]:8080". The leading
-  // slashes must be stripped.
-  const auto prefix = nonstd::string_view{"//"};
-  if (!util::starts_with(rendered_value, prefix)) {
-    throw core::Fatal(R"(Expected partial URL "{}" to start with "{}")",
-                      rendered_value,
-                      prefix);
-  }
-  return rendered_value.substr(prefix.size());
-}
-
 std::string
 get_url(const Url& url)
 {
@@ -141,12 +87,12 @@ get_url(const Url& url)
   }
 
   // httplib requires a partial URL with just scheme, host and port.
-  return get_partial_url(url).scheme(url.scheme()).str();
+  return get_partial_url(url).str();
 }
 
 HttpStorageBackend::HttpStorageBackend(const Params& params)
   : m_url_path(get_url_path(params.url)),
-    m_http_client(get_url(params.url).c_str())
+    m_http_client(get_url(params.url))
 {
   if (!params.url.user_info().empty()) {
     const auto pair = util::split_once(params.url.user_info(), ':');
@@ -159,9 +105,6 @@ HttpStorageBackend::HttpStorageBackend(const Params& params)
   }
 
   m_http_client.set_default_headers({
-    // Explicit setting of the Host header is required due to IPv6 address
-    // handling issues in httplib.
-    {"Host", get_host_header_value(params.url)},
     {"User-Agent", FMT("{}/{}", CCACHE_NAME, CCACHE_VERSION)},
   });
   m_http_client.set_keep_alive(true);
index ee9a947f47fee11afb2c9d53d69532335670152d..108f91f933016f2f2b70af7d6fc74972c86e57fd 100644 (file)
@@ -624,35 +624,22 @@ public:
 
   virtual bool is_valid() const;
 
-  Server &Get(const char *pattern, Handler handler);
-  Server &Get(const char *pattern, size_t pattern_len, Handler handler);
-  Server &Post(const char *pattern, Handler handler);
-  Server &Post(const char *pattern, size_t pattern_len, Handler handler);
-  Server &Post(const char *pattern, HandlerWithContentReader handler);
-  Server &Post(const char *pattern, size_t pattern_len,
-               HandlerWithContentReader handler);
-  Server &Put(const char *pattern, Handler handler);
-  Server &Put(const char *pattern, size_t pattern_len, Handler handler);
-  Server &Put(const char *pattern, HandlerWithContentReader handler);
-  Server &Put(const char *pattern, size_t pattern_len,
-              HandlerWithContentReader handler);
-  Server &Patch(const char *pattern, Handler handler);
-  Server &Patch(const char *pattern, size_t pattern_len, Handler handler);
-  Server &Patch(const char *pattern, HandlerWithContentReader handler);
-  Server &Patch(const char *pattern, size_t pattern_len,
-                HandlerWithContentReader handler);
-  Server &Delete(const char *pattern, Handler handler);
-  Server &Delete(const char *pattern, size_t pattern_len, Handler handler);
-  Server &Delete(const char *pattern, HandlerWithContentReader handler);
-  Server &Delete(const char *pattern, size_t pattern_len,
-                 HandlerWithContentReader handler);
-  Server &Options(const char *pattern, Handler handler);
-  Server &Options(const char *pattern, size_t pattern_len, Handler handler);
-
-  bool set_base_dir(const char *dir, const char *mount_point = nullptr);
-  bool set_mount_point(const char *mount_point, const char *dir,
+  Server &Get(const std::string &pattern, Handler handler);
+  Server &Post(const std::string &pattern, Handler handler);
+  Server &Post(const std::string &pattern, HandlerWithContentReader handler);
+  Server &Put(const std::string &pattern, Handler handler);
+  Server &Put(const std::string &pattern, HandlerWithContentReader handler);
+  Server &Patch(const std::string &pattern, Handler handler);
+  Server &Patch(const std::string &pattern, HandlerWithContentReader handler);
+  Server &Delete(const std::string &pattern, Handler handler);
+  Server &Delete(const std::string &pattern, HandlerWithContentReader handler);
+  Server &Options(const std::string &pattern, Handler handler);
+
+  bool set_base_dir(const std::string &dir,
+                    const std::string &mount_point = nullptr);
+  bool set_mount_point(const std::string &mount_point, const std::string &dir,
                        Headers headers = Headers());
-  bool remove_mount_point(const char *mount_point);
+  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_request_handler(Handler handler);
@@ -811,8 +798,31 @@ enum class Error {
   Compression,
 };
 
+inline std::string to_string(const Error error) {
+  switch (error) {
+  case Error::Success: return "Success";
+  case Error::Connection: return "Connection";
+  case Error::BindIPAddress: return "BindIPAddress";
+  case Error::Read: return "Read";
+  case Error::Write: return "Write";
+  case Error::ExceedRedirectCount: return "ExceedRedirectCount";
+  case Error::Canceled: return "Canceled";
+  case Error::SSLConnection: return "SSLConnection";
+  case Error::SSLLoadingCerts: return "SSLLoadingCerts";
+  case Error::SSLServerVerification: return "SSLServerVerification";
+  case Error::UnsupportedMultipartBoundaryChars:
+    return "UnsupportedMultipartBoundaryChars";
+  case Error::Compression: return "Compression";
+  case Error::Unknown: return "Unknown";
+  default: break;
+  }
+
+  return "Invalid";
+}
+
 inline std::ostream &operator<<(std::ostream &os, const Error &obj) {
-  os << static_cast<std::underlying_type<Error>::type>(obj);
+  os << to_string(obj);
+  os << " (" << static_cast<std::underlying_type<Error>::type>(obj) << ')';
   return os;
 }
 
@@ -1026,6 +1036,12 @@ public:
   void set_proxy_digest_auth(const char *username, const char *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_store(X509_STORE *ca_cert_store);
+#endif
+
 #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
   void enable_server_certificate_verification(bool enabled);
 #endif
@@ -1127,6 +1143,13 @@ protected:
   std::string proxy_digest_auth_password_;
 #endif
 
+#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+  std::string ca_cert_file_path_;
+  std::string ca_cert_dir_path_;
+
+  X509_STORE *ca_cert_store_ = nullptr;
+#endif
+
 #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
   bool server_certificate_verification_ = true;
 #endif
@@ -1153,6 +1176,8 @@ private:
       ContentProviderWithoutLength content_provider_without_length,
       const char *content_type);
 
+  std::string adjust_host_string(const std::string &host) const;
+
   virtual bool process_socket(const Socket &socket,
                               std::function<bool(Stream &strm)> callback);
   virtual bool is_ssl() const;
@@ -1161,9 +1186,9 @@ private:
 class Client {
 public:
   // Universal interface
-  explicit Client(const char *scheme_host_port);
+  explicit Client(const std::string &scheme_host_port);
 
-  explicit Client(const char *scheme_host_port,
+  explicit Client(const std::string &scheme_host_port,
                   const std::string &client_cert_path,
                   const std::string &client_key_path);
 
@@ -1403,9 +1428,6 @@ public:
 
   bool is_valid() const override;
 
-  void set_ca_cert_path(const char *ca_cert_file_path,
-                        const char *ca_cert_dir_path = nullptr);
-
   void set_ca_cert_store(X509_STORE *ca_cert_store);
 
   long get_openssl_verify_result() const;
@@ -1438,8 +1460,6 @@ private:
 
   std::vector<std::string> host_components_;
 
-  std::string ca_cert_file_path_;
-  std::string ca_cert_dir_path_;
   long verify_result_ = 0;
 
   friend class ClientImpl;
@@ -2558,28 +2578,40 @@ public:
                 Callback callback) override {
     assert(is_valid_);
 
-    auto flush = last ? Z_FINISH : Z_NO_FLUSH;
+    do {
+      constexpr size_t max_avail_in =
+          std::numeric_limits<decltype(strm_.avail_in)>::max();
+
+      strm_.avail_in = static_cast<decltype(strm_.avail_in)>(
+          std::min(data_length, max_avail_in));
+      strm_.next_in =
+          const_cast<Bytef *>(reinterpret_cast<const Bytef *>(data));
 
-    strm_.avail_in = static_cast<decltype(strm_.avail_in)>(data_length);
-    strm_.next_in = const_cast<Bytef *>(reinterpret_cast<const Bytef *>(data));
+      data_length -= strm_.avail_in;
+      data += strm_.avail_in;
 
-    int ret = Z_OK;
+      auto flush = (last && data_length == 0) ? Z_FINISH : Z_NO_FLUSH;
+      int ret = Z_OK;
 
-    std::array<char, CPPHTTPLIB_COMPRESSION_BUFSIZ> buff{};
-    do {
-      strm_.avail_out = static_cast<uInt>(buff.size());
-      strm_.next_out = reinterpret_cast<Bytef *>(buff.data());
+      std::array<char, CPPHTTPLIB_COMPRESSION_BUFSIZ> buff{};
+      do {
+        strm_.avail_out = static_cast<uInt>(buff.size());
+        strm_.next_out = reinterpret_cast<Bytef *>(buff.data());
 
-      ret = deflate(&strm_, flush);
-      if (ret == Z_STREAM_ERROR) { return false; }
+        ret = deflate(&strm_, flush);
+        if (ret == Z_STREAM_ERROR) { return false; }
 
-      if (!callback(buff.data(), buff.size() - strm_.avail_out)) {
-        return false;
-      }
-    } while (strm_.avail_out == 0);
+        if (!callback(buff.data(), buff.size() - strm_.avail_out)) {
+          return false;
+        }
+      } while (strm_.avail_out == 0);
+
+      assert((flush == Z_FINISH && ret == Z_STREAM_END) ||
+             (flush == Z_NO_FLUSH && ret == Z_OK));
+      assert(strm_.avail_in == 0);
+
+    } while (data_length > 0);
 
-    assert((last && ret == Z_STREAM_END) || (!last && ret == Z_OK));
-    assert(strm_.avail_in == 0);
     return true;
   }
 
@@ -2613,28 +2645,41 @@ public:
 
     int ret = Z_OK;
 
-    strm_.avail_in = static_cast<decltype(strm_.avail_in)>(data_length);
-    strm_.next_in = const_cast<Bytef *>(reinterpret_cast<const Bytef *>(data));
+    do {
+      constexpr size_t max_avail_in =
+          std::numeric_limits<decltype(strm_.avail_in)>::max();
+
+      strm_.avail_in = static_cast<decltype(strm_.avail_in)>(
+          std::min(data_length, max_avail_in));
+      strm_.next_in =
+          const_cast<Bytef *>(reinterpret_cast<const Bytef *>(data));
+
+      data_length -= strm_.avail_in;
+      data += strm_.avail_in;
+
+      std::array<char, CPPHTTPLIB_COMPRESSION_BUFSIZ> buff{};
+      while (strm_.avail_in > 0) {
+        strm_.avail_out = static_cast<uInt>(buff.size());
+        strm_.next_out = reinterpret_cast<Bytef *>(buff.data());
+
+        ret = inflate(&strm_, Z_NO_FLUSH);
+        assert(ret != Z_STREAM_ERROR);
+        switch (ret) {
+        case Z_NEED_DICT:
+        case Z_DATA_ERROR:
+        case Z_MEM_ERROR: inflateEnd(&strm_); return false;
+        }
 
-    std::array<char, CPPHTTPLIB_COMPRESSION_BUFSIZ> buff{};
-    while (strm_.avail_in > 0) {
-      strm_.avail_out = static_cast<uInt>(buff.size());
-      strm_.next_out = reinterpret_cast<Bytef *>(buff.data());
-
-      ret = inflate(&strm_, Z_NO_FLUSH);
-      assert(ret != Z_STREAM_ERROR);
-      switch (ret) {
-      case Z_NEED_DICT:
-      case Z_DATA_ERROR:
-      case Z_MEM_ERROR: inflateEnd(&strm_); return false;
+        if (!callback(buff.data(), buff.size() - strm_.avail_out)) {
+          return false;
+        }
       }
 
-      if (!callback(buff.data(), buff.size() - strm_.avail_out)) {
-        return false;
-      }
-    }
+      if (ret != Z_OK && ret != Z_STREAM_END) return false;
 
-    return ret == Z_OK || ret == Z_STREAM_END;
+    } while (data_length > 0);
+
+    return true;
   }
 
 private:
@@ -4225,128 +4270,79 @@ inline Server::Server()
 
 inline Server::~Server() {}
 
-inline Server &Server::Get(const char *pattern, Handler handler) {
-  return Get(pattern, strlen(pattern), handler);
-}
-
-inline Server &Server::Get(const char *pattern, size_t pattern_len,
-                           Handler handler) {
+inline Server &Server::Get(const std::string &pattern, Handler handler) {
   get_handlers_.push_back(
-      std::make_pair(std::regex(pattern, pattern_len), std::move(handler)));
+      std::make_pair(std::regex(pattern), std::move(handler)));
   return *this;
 }
 
-inline Server &Server::Post(const char *pattern, Handler handler) {
-  return Post(pattern, strlen(pattern), handler);
-}
-
-inline Server &Server::Post(const char *pattern, size_t pattern_len,
-                            Handler handler) {
+inline Server &Server::Post(const std::string &pattern, Handler handler) {
   post_handlers_.push_back(
-      std::make_pair(std::regex(pattern, pattern_len), std::move(handler)));
+      std::make_pair(std::regex(pattern), std::move(handler)));
   return *this;
 }
 
-inline Server &Server::Post(const char *pattern,
-                            HandlerWithContentReader handler) {
-  return Post(pattern, strlen(pattern), handler);
-}
-
-inline Server &Server::Post(const char *pattern, size_t pattern_len,
+inline Server &Server::Post(const std::string &pattern,
                             HandlerWithContentReader handler) {
   post_handlers_for_content_reader_.push_back(
-      std::make_pair(std::regex(pattern, pattern_len), std::move(handler)));
+      std::make_pair(std::regex(pattern), std::move(handler)));
   return *this;
 }
 
-inline Server &Server::Put(const char *pattern, Handler handler) {
-  return Put(pattern, strlen(pattern), handler);
-}
-
-inline Server &Server::Put(const char *pattern, size_t pattern_len,
-                           Handler handler) {
+inline Server &Server::Put(const std::string &pattern, Handler handler) {
   put_handlers_.push_back(
-      std::make_pair(std::regex(pattern, pattern_len), std::move(handler)));
+      std::make_pair(std::regex(pattern), std::move(handler)));
   return *this;
 }
 
-inline Server &Server::Put(const char *pattern,
-                           HandlerWithContentReader handler) {
-  return Put(pattern, strlen(pattern), handler);
-}
-
-inline Server &Server::Put(const char *pattern, size_t pattern_len,
+inline Server &Server::Put(const std::string &pattern,
                            HandlerWithContentReader handler) {
   put_handlers_for_content_reader_.push_back(
-      std::make_pair(std::regex(pattern, pattern_len), std::move(handler)));
+      std::make_pair(std::regex(pattern), std::move(handler)));
   return *this;
 }
 
-inline Server &Server::Patch(const char *pattern, Handler handler) {
-  return Patch(pattern, strlen(pattern), handler);
-}
-
-inline Server &Server::Patch(const char *pattern, size_t pattern_len,
-                             Handler handler) {
+inline Server &Server::Patch(const std::string &pattern, Handler handler) {
   patch_handlers_.push_back(
-      std::make_pair(std::regex(pattern, pattern_len), std::move(handler)));
+      std::make_pair(std::regex(pattern), std::move(handler)));
   return *this;
 }
 
-inline Server &Server::Patch(const char *pattern,
-                             HandlerWithContentReader handler) {
-  return Patch(pattern, strlen(pattern), handler);
-}
-
-inline Server &Server::Patch(const char *pattern, size_t pattern_len,
+inline Server &Server::Patch(const std::string &pattern,
                              HandlerWithContentReader handler) {
   patch_handlers_for_content_reader_.push_back(
-      std::make_pair(std::regex(pattern, pattern_len), std::move(handler)));
+      std::make_pair(std::regex(pattern), std::move(handler)));
   return *this;
 }
 
-inline Server &Server::Delete(const char *pattern, Handler handler) {
-  return Delete(pattern, strlen(pattern), handler);
-}
-
-inline Server &Server::Delete(const char *pattern, size_t pattern_len,
-                              Handler handler) {
+inline Server &Server::Delete(const std::string &pattern, Handler handler) {
   delete_handlers_.push_back(
-      std::make_pair(std::regex(pattern, pattern_len), std::move(handler)));
+      std::make_pair(std::regex(pattern), std::move(handler)));
   return *this;
 }
 
-inline Server &Server::Delete(const char *pattern,
-                              HandlerWithContentReader handler) {
-  return Delete(pattern, strlen(pattern), handler);
-}
-
-inline Server &Server::Delete(const char *pattern, size_t pattern_len,
+inline Server &Server::Delete(const std::string &pattern,
                               HandlerWithContentReader handler) {
   delete_handlers_for_content_reader_.push_back(
-      std::make_pair(std::regex(pattern, pattern_len), std::move(handler)));
+      std::make_pair(std::regex(pattern), std::move(handler)));
   return *this;
 }
 
-inline Server &Server::Options(const char *pattern, Handler handler) {
-  return Options(pattern, strlen(pattern), handler);
-}
-
-inline Server &Server::Options(const char *pattern, size_t pattern_len,
-                               Handler handler) {
+inline Server &Server::Options(const std::string &pattern, Handler handler) {
   options_handlers_.push_back(
-      std::make_pair(std::regex(pattern, pattern_len), std::move(handler)));
+      std::make_pair(std::regex(pattern), std::move(handler)));
   return *this;
 }
 
-inline bool Server::set_base_dir(const char *dir, const char *mount_point) {
+inline bool Server::set_base_dir(const std::string &dir,
+                                 const std::string &mount_point) {
   return set_mount_point(mount_point, dir);
 }
 
-inline bool Server::set_mount_point(const char *mount_point, const char *dir,
-                                    Headers headers) {
+inline bool Server::set_mount_point(const std::string &mount_point,
+                                    const std::string &dir, Headers headers) {
   if (detail::is_dir(dir)) {
-    std::string mnt = mount_point ? mount_point : "/";
+    std::string mnt = !mount_point.empty() ? mount_point : "/";
     if (!mnt.empty() && mnt[0] == '/') {
       base_dirs_.push_back({mnt, dir, std::move(headers)});
       return true;
@@ -4355,7 +4351,7 @@ inline bool Server::set_mount_point(const char *mount_point, const char *dir,
   return false;
 }
 
-inline bool Server::remove_mount_point(const char *mount_point) {
+inline bool Server::remove_mount_point(const std::string &mount_point) {
   for (auto it = base_dirs_.begin(); it != base_dirs_.end(); ++it) {
     if (it->mount_point == mount_point) {
       base_dirs_.erase(it);
@@ -5301,9 +5297,8 @@ inline ClientImpl::ClientImpl(const std::string &host, int port)
 inline ClientImpl::ClientImpl(const std::string &host, int port,
                               const std::string &client_cert_path,
                               const std::string &client_key_path)
-    // : (Error::Success), host_(host), port_(port),
     : host_(host), port_(port),
-      host_and_port_(host_ + ":" + std::to_string(port_)),
+      host_and_port_(adjust_host_string(host) + ":" + std::to_string(port)),
       client_cert_path_(client_cert_path), client_key_path_(client_key_path) {}
 
 inline ClientImpl::~ClientImpl() {
@@ -5347,6 +5342,11 @@ inline void ClientImpl::copy_settings(const ClientImpl &rhs) {
   proxy_digest_auth_username_ = rhs.proxy_digest_auth_username_;
   proxy_digest_auth_password_ = rhs.proxy_digest_auth_password_;
 #endif
+#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+  ca_cert_file_path_ = rhs.ca_cert_file_path_;
+  ca_cert_dir_path_ = rhs.ca_cert_dir_path_;
+  ca_cert_store_ = rhs.ca_cert_store_;
+#endif
 #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
   server_certificate_verification_ = rhs.server_certificate_verification_;
 #endif
@@ -5642,6 +5642,9 @@ inline bool ClientImpl::redirect(Request &req, Response &res, Error &error) {
 #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
       SSLClient cli(next_host.c_str(), next_port);
       cli.copy_settings(*this);
+      if (ca_cert_store_) {
+        cli.set_ca_cert_store(ca_cert_store_);
+      }
       return detail::redirect(cli, req, res, next_path, location, error);
 #else
       return false;
@@ -5898,6 +5901,12 @@ inline Result ClientImpl::send_with_content_provider(
   return Result{std::move(res), error, std::move(req.headers)};
 }
 
+inline std::string
+ClientImpl::adjust_host_string(const std::string &host) const {
+  if (host.find(':') != std::string::npos) { return "[" + host + "]"; }
+  return host;
+}
+
 inline bool ClientImpl::process_request(Stream &strm, Request &req,
                                         Response &res, bool close_connection,
                                         Error &error) {
@@ -6543,6 +6552,20 @@ inline void ClientImpl::set_proxy_digest_auth(const char *username,
 }
 #endif
 
+#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+inline 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; }
+}
+
+inline void ClientImpl::set_ca_cert_store(X509_STORE *ca_cert_store) {
+  if (ca_cert_store && ca_cert_store != ca_cert_store_) {
+    ca_cert_store_ = ca_cert_store;
+  }
+}
+#endif
+
 #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
 inline void ClientImpl::enable_server_certificate_verification(bool enabled) {
   server_certificate_verification_ = enabled;
@@ -6933,12 +6956,6 @@ inline SSLClient::~SSLClient() {
 
 inline bool SSLClient::is_valid() const { return ctx_; }
 
-inline void SSLClient::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; }
-}
-
 inline void SSLClient::set_ca_cert_store(X509_STORE *ca_cert_store) {
   if (ca_cert_store) {
     if (ctx_) {
@@ -7261,16 +7278,16 @@ inline bool SSLClient::check_host_name(const char *pattern,
 #endif
 
 // Universal client implementation
-inline Client::Client(const char *scheme_host_port)
+inline Client::Client(const std::string &scheme_host_port)
     : Client(scheme_host_port, std::string(), std::string()) {}
 
-inline Client::Client(const char *scheme_host_port,
+inline Client::Client(const std::string &scheme_host_port,
                       const std::string &client_cert_path,
                       const std::string &client_key_path) {
   const static std::regex re(
       R"((?:([a-z]+):\/\/)?(?:\[([\d:]+)\]|([^:/?#]+))(?::(\d+))?)");
 
-  std::cmatch m;
+  std::smatch m;
   if (std::regex_match(scheme_host_port, m, re)) {
     auto scheme = m[1].str();
 
@@ -7681,15 +7698,14 @@ inline void Client::set_logger(Logger logger) { cli_->set_logger(logger); }
 #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
 inline void Client::set_ca_cert_path(const char *ca_cert_file_path,
                                      const char *ca_cert_dir_path) {
-  if (is_ssl_) {
-    static_cast<SSLClient &>(*cli_).set_ca_cert_path(ca_cert_file_path,
-                                                     ca_cert_dir_path);
-  }
+  cli_->set_ca_cert_path(ca_cert_file_path, ca_cert_dir_path);
 }
 
 inline void Client::set_ca_cert_store(X509_STORE *ca_cert_store) {
   if (is_ssl_) {
     static_cast<SSLClient &>(*cli_).set_ca_cert_store(ca_cert_store);
+  } else {
+    cli_->set_ca_cert_store(ca_cert_store);
   }
 }