diff --git a/scripts/sync_vendor.py b/scripts/sync_vendor.py index 75d4a5ff61..1a87d73563 100755 --- a/scripts/sync_vendor.py +++ b/scripts/sync_vendor.py @@ -5,7 +5,7 @@ import os import sys import subprocess -HTTPLIB_VERSION = "refs/tags/v0.37.1" +HTTPLIB_VERSION = "refs/tags/v0.37.2" vendor = { "https://github.com/nlohmann/json/releases/latest/download/json.hpp": "vendor/nlohmann/json.hpp", diff --git a/vendor/cpp-httplib/httplib.cpp b/vendor/cpp-httplib/httplib.cpp index 71a5f00567..41e7a361c0 100644 --- a/vendor/cpp-httplib/httplib.cpp +++ b/vendor/cpp-httplib/httplib.cpp @@ -1995,9 +1995,9 @@ int getaddrinfo_with_timeout(const char *node, const char *service, memcpy((*current)->ai_addr, sockaddr_ptr, sockaddr_len); // Set port if service is specified - if (service && strlen(service) > 0) { - int port = atoi(service); - if (port > 0) { + if (service && *service) { + int port = 0; + if (parse_port(service, strlen(service), port)) { if (sockaddr_ptr->sa_family == AF_INET) { reinterpret_cast((*current)->ai_addr) ->sin_port = htons(static_cast(port)); @@ -3016,6 +3016,16 @@ bool read_headers(Stream &strm, Headers &headers) { header_count++; } + // RFC 9110 Section 8.6: Reject requests with multiple Content-Length + // headers that have different values to prevent request smuggling. + auto cl_range = headers.equal_range("Content-Length"); + if (cl_range.first != cl_range.second) { + const auto &first_val = cl_range.first->second; + for (auto it = std::next(cl_range.first); it != cl_range.second; ++it) { + if (it->second != first_val) { return false; } + } + } + return true; } @@ -7522,6 +7532,10 @@ bool Server::listen_internal() { detail::set_socket_opt_time(sock, SOL_SOCKET, SO_SNDTIMEO, write_timeout_sec_, write_timeout_usec_); + if (tcp_nodelay_) { + detail::set_socket_opt(sock, IPPROTO_TCP, TCP_NODELAY, 1); + } + if (!task_queue->enqueue( [this, sock]() { process_and_close_socket(sock); })) { output_error_log(Error::ResourceExhaustion, nullptr); @@ -8911,7 +8925,7 @@ bool ClientImpl::redirect(Request &req, Response &res, Error &error) { auto next_port = port_; if (!port_str.empty()) { - next_port = std::stoi(port_str); + if (!detail::parse_port(port_str, next_port)) { return false; } } else if (!next_scheme.empty()) { next_port = next_scheme == "https" ? 443 : 80; } @@ -8962,18 +8976,10 @@ bool ClientImpl::create_redirect_client( // Setup basic client configuration first setup_redirect_client(redirect_client); - // SSL-specific configuration for proxy environments - if (!proxy_host_.empty() && proxy_port_ != -1) { - // Critical: Disable SSL verification for proxy environments - redirect_client.enable_server_certificate_verification(false); - redirect_client.enable_server_hostname_verification(false); - } else { - // For direct SSL connections, copy SSL verification settings - redirect_client.enable_server_certificate_verification( - server_certificate_verification_); - redirect_client.enable_server_hostname_verification( - server_hostname_verification_); - } + redirect_client.enable_server_certificate_verification( + server_certificate_verification_); + redirect_client.enable_server_hostname_verification( + server_hostname_verification_); // Transfer CA certificate to redirect client if (!ca_cert_pem_.empty()) { @@ -10690,7 +10696,8 @@ Client::Client(const std::string &scheme_host_port, if (host.empty()) { host = m[3].str(); } auto port_str = m[4].str(); - auto port = !port_str.empty() ? std::stoi(port_str) : (is_ssl ? 443 : 80); + auto port = is_ssl ? 443 : 80; + if (!port_str.empty() && !detail::parse_port(port_str, port)) { return; } if (is_ssl) { #ifdef CPPHTTPLIB_SSL_ENABLED @@ -16103,7 +16110,8 @@ WebSocketClient::WebSocketClient( if (host_.empty()) { host_ = m[3].str(); } auto port_str = m[4].str(); - port_ = !port_str.empty() ? std::stoi(port_str) : (is_ssl ? 443 : 80); + port_ = is_ssl ? 443 : 80; + if (!port_str.empty() && !detail::parse_port(port_str, port_)) { return; } path_ = m[5].str(); diff --git a/vendor/cpp-httplib/httplib.h b/vendor/cpp-httplib/httplib.h index e01b3550ba..cdde8014d9 100644 --- a/vendor/cpp-httplib/httplib.h +++ b/vendor/cpp-httplib/httplib.h @@ -8,8 +8,8 @@ #ifndef CPPHTTPLIB_HTTPLIB_H #define CPPHTTPLIB_HTTPLIB_H -#define CPPHTTPLIB_VERSION "0.37.1" -#define CPPHTTPLIB_VERSION_NUM "0x002501" +#define CPPHTTPLIB_VERSION "0.37.2" +#define CPPHTTPLIB_VERSION_NUM "0x002502" #ifdef _WIN32 #if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0A00 @@ -689,6 +689,18 @@ inline from_chars_result from_chars(const char *first, const char *last, return {first + (endptr - s.c_str()), std::errc{}}; } +inline bool parse_port(const char *s, size_t len, int &port) { + int val = 0; + auto r = from_chars(s, s + len, val); + if (r.ec != std::errc{} || val < 1 || val > 65535) { return false; } + port = val; + return true; +} + +inline bool parse_port(const std::string &s, int &port) { + return parse_port(s.data(), s.size(), port); +} + } // namespace detail enum SSLVerifierResponse {