11#include "httplib.h"
22namespace httplib {
3- // httplib::any — type-erased value container (C++11 compatible)
4- // On C++17+ builds, thin wrappers around std::any are provided.
53
64/*
75 * Implementation that will be part of the .cc file if split into .h + .cc.
@@ -1877,7 +1875,7 @@ int getaddrinfo_with_timeout(const char *node, const char *service,
18771875 }
18781876
18791877 return ret;
1880- #elif TARGET_OS_MAC
1878+ #elif TARGET_OS_MAC && defined(__clang__)
18811879 if (!node) { return EAI_NONAME; }
18821880 // macOS implementation using CFHost API for asynchronous DNS resolution
18831881 CFStringRef hostname_ref = CFStringCreateWithCString(
@@ -5836,6 +5834,17 @@ std::string Request::get_param_value(const std::string &key,
58365834 return std::string();
58375835}
58385836
5837+ std::vector<std::string>
5838+ Request::get_param_values(const std::string &key) const {
5839+ auto rng = params.equal_range(key);
5840+ std::vector<std::string> values;
5841+ values.reserve(static_cast<size_t>(std::distance(rng.first, rng.second)));
5842+ for (auto it = rng.first; it != rng.second; ++it) {
5843+ values.push_back(it->second);
5844+ }
5845+ return values;
5846+ }
5847+
58395848size_t Request::get_param_value_count(const std::string &key) const {
58405849 auto r = params.equal_range(key);
58415850 return static_cast<size_t>(std::distance(r.first, r.second));
@@ -7013,6 +7022,15 @@ Server &Server::set_keep_alive_timeout(time_t sec) {
70137022 return *this;
70147023}
70157024
7025+ template <class Rep, class Period>
7026+ Server &Server::set_keep_alive_timeout(
7027+ const std::chrono::duration<Rep, Period> &duration) {
7028+ detail::duration_to_sec_and_usec(duration, [&](time_t sec, time_t /*usec*/) {
7029+ set_keep_alive_timeout(sec);
7030+ });
7031+ return *this;
7032+ }
7033+
70167034Server &Server::set_read_timeout(time_t sec, time_t usec) {
70177035 read_timeout_sec_ = sec;
70187036 read_timeout_usec_ = usec;
@@ -9119,20 +9137,21 @@ bool ClientImpl::redirect(Request &req, Response &res, Error &error) {
91199137 auto location = res.get_header_value("location");
91209138 if (location.empty()) { return false; }
91219139
9122- thread_local const std::regex re(
9123- R"((?:(https?):)?(?://(?:\[([a-fA-F\d:]+)\]|([^:/?#]+))(?::(\d+))?)?([^?#]*)(\?[^#]*)?(?:#.*)?)");
9140+ detail::UrlComponents uc;
9141+ if (!detail::parse_url(location, uc)) { return false; }
91249142
9125- std::smatch m;
9126- if (!std::regex_match(location, m, re)) { return false; }
9143+ // Only follow http/https redirects
9144+ if (!uc.scheme.empty() && uc.scheme != "http" && uc.scheme != "https") {
9145+ return false;
9146+ }
91279147
91289148 auto scheme = is_ssl() ? "https" : "http";
91299149
9130- auto next_scheme = m[1].str();
9131- auto next_host = m[2].str();
9132- if (next_host.empty()) { next_host = m[3].str(); }
9133- auto port_str = m[4].str();
9134- auto next_path = m[5].str();
9135- auto next_query = m[6].str();
9150+ auto next_scheme = std::move(uc.scheme);
9151+ auto next_host = std::move(uc.host);
9152+ auto port_str = std::move(uc.port);
9153+ auto next_path = std::move(uc.path);
9154+ auto next_query = std::move(uc.query);
91369155
91379156 auto next_port = port_;
91389157 if (!port_str.empty()) {
@@ -9145,7 +9164,7 @@ bool ClientImpl::redirect(Request &req, Response &res, Error &error) {
91459164 if (next_host.empty()) { next_host = host_; }
91469165 if (next_path.empty()) { next_path = "/"; }
91479166
9148- auto path = decode_query_component (next_path, true ) + next_query;
9167+ auto path = decode_path_component (next_path) + next_query;
91499168
91509169 // Same host redirect - use current client
91519170 if (next_scheme == scheme && next_host == host_ && next_port == port_) {
@@ -10869,12 +10888,9 @@ Client::Client(const std::string &scheme_host_port)
1086910888Client::Client(const std::string &scheme_host_port,
1087010889 const std::string &client_cert_path,
1087110890 const std::string &client_key_path) {
10872- const static std::regex re(
10873- R"((?:([a-z]+):\/\/)?(?:\[([a-fA-F\d:]+)\]|([^:/?#]+))(?::(\d+))?)");
10874-
10875- std::smatch m;
10876- if (std::regex_match(scheme_host_port, m, re)) {
10877- auto scheme = m[1].str();
10891+ detail::UrlComponents uc;
10892+ if (detail::parse_url(scheme_host_port, uc) && !uc.host.empty()) {
10893+ auto &scheme = uc.scheme;
1087810894
1087910895#ifdef CPPHTTPLIB_SSL_ENABLED
1088010896 if (!scheme.empty() && (scheme != "http" && scheme != "https")) {
@@ -10890,12 +10906,10 @@ Client::Client(const std::string &scheme_host_port,
1089010906
1089110907 auto is_ssl = scheme == "https";
1089210908
10893- auto host = m[2].str();
10894- if (host.empty()) { host = m[3].str(); }
10909+ auto host = std::move(uc.host);
1089510910
10896- auto port_str = m[4].str();
1089710911 auto port = is_ssl ? 443 : 80;
10898- if (!port_str. empty() && !detail::parse_port(port_str , port)) { return; }
10912+ if (!uc.port. empty() && !detail::parse_port(uc.port , port)) { return; }
1089910913
1090010914 if (is_ssl) {
1090110915#ifdef CPPHTTPLIB_SSL_ENABLED
@@ -12466,6 +12480,18 @@ std::string Request::sni() const {
1246612480 */
1246712481
1246812482#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
12483+ // These wrappers forward to deprecated APIs that will be removed by v1.0.0.
12484+ // Suppress C4996 / -Wdeprecated-declarations so that MSVC /sdl builds (which
12485+ // promote C4996 to an error) compile cleanly even though the wrappers
12486+ // themselves are also marked [[deprecated]].
12487+ #if defined(_MSC_VER)
12488+ #pragma warning(push)
12489+ #pragma warning(disable : 4996)
12490+ #elif defined(__GNUC__) || defined(__clang__)
12491+ #pragma GCC diagnostic push
12492+ #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
12493+ #endif
12494+
1246912495SSL_CTX *Client::ssl_context() const {
1247012496 if (is_ssl_) { return static_cast<SSLClient &>(*cli_).ssl_context(); }
1247112497 return nullptr;
@@ -12480,6 +12506,12 @@ long Client::get_verify_result() const {
1248012506 if (is_ssl_) { return static_cast<SSLClient &>(*cli_).get_verify_result(); }
1248112507 return -1; // NOTE: -1 doesn't match any of X509_V_ERR_???
1248212508}
12509+
12510+ #if defined(_MSC_VER)
12511+ #pragma warning(pop)
12512+ #elif defined(__GNUC__) || defined(__clang__)
12513+ #pragma GCC diagnostic pop
12514+ #endif
1248312515#endif // CPPHTTPLIB_OPENSSL_SUPPORT
1248412516
1248512517/*
@@ -16302,12 +16334,10 @@ bool WebSocket::is_open() const { return !closed_; }
1630216334WebSocketClient::WebSocketClient(
1630316335 const std::string &scheme_host_port_path, const Headers &headers)
1630416336 : headers_(headers) {
16305- const static std::regex re(
16306- R"(([a-z]+):\/\/(?:\[([a-fA-F\d:]+)\]|([^:/?#]+))(?::(\d+))?(\/.*))");
16307-
16308- std::smatch m;
16309- if (std::regex_match(scheme_host_port_path, m, re)) {
16310- auto scheme = m[1].str();
16337+ detail::UrlComponents uc;
16338+ if (detail::parse_url(scheme_host_port_path, uc) && !uc.scheme.empty() &&
16339+ !uc.host.empty() && !uc.path.empty()) {
16340+ auto &scheme = uc.scheme;
1631116341
1631216342#ifdef CPPHTTPLIB_SSL_ENABLED
1631316343 if (scheme != "ws" && scheme != "wss") {
@@ -16323,14 +16353,12 @@ WebSocketClient::WebSocketClient(
1632316353
1632416354 auto is_ssl = scheme == "wss";
1632516355
16326- host_ = m[2].str();
16327- if (host_.empty()) { host_ = m[3].str(); }
16356+ host_ = std::move(uc.host);
1632816357
16329- auto port_str = m[4].str();
1633016358 port_ = is_ssl ? 443 : 80;
16331- if (!port_str. empty() && !detail::parse_port(port_str , port_)) { return; }
16359+ if (!uc.port. empty() && !detail::parse_port(uc.port , port_)) { return; }
1633216360
16333- path_ = m[5].str( );
16361+ path_ = std::move(uc.path );
1633416362
1633516363#ifdef CPPHTTPLIB_SSL_ENABLED
1633616364 is_ssl_ = is_ssl;
0 commit comments