From: Joel Rosdahl Date: Wed, 29 Dec 2021 15:21:32 +0000 (+0100) Subject: bump: Upgrade to cpp-httplib 0.10.1 X-Git-Tag: v4.6~54 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=e22e934dcaf164f0e3a64330d66e14b47b19ce01;p=thirdparty%2Fccache.git bump: Upgrade to cpp-httplib 0.10.1 --- diff --git a/LICENSE.adoc b/LICENSE.adoc index 431697aa8..1ff47bd0a 100644 --- a/LICENSE.adoc +++ b/LICENSE.adoc @@ -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.9.7 downloaded from https://github.com/yhirose/cpp-httplib[cpp-httplib]. The +v0.10.1 downloaded from https://github.com/yhirose/cpp-httplib[cpp-httplib]. The library has the following license: ---- diff --git a/src/third_party/httplib.cpp b/src/third_party/httplib.cpp index 902aeeeea..9f1cc31b8 100644 --- a/src/third_party/httplib.cpp +++ b/src/third_party/httplib.cpp @@ -388,25 +388,22 @@ ssize_t read_socket(socket_t sock, void *ptr, size_t size, int flags) { return handle_EINTR([&]() { return recv(sock, #ifdef _WIN32 - static_cast(ptr), - static_cast(size), + static_cast(ptr), static_cast(size), #else - ptr, - size, + ptr, size, #endif flags); }); } -ssize_t send_socket(socket_t sock, const void *ptr, size_t size, int flags) { +ssize_t send_socket(socket_t sock, const void *ptr, size_t size, + int flags) { return handle_EINTR([&]() { return send(sock, #ifdef _WIN32 - static_cast(ptr), - static_cast(size), + static_cast(ptr), static_cast(size), #else - ptr, - size, + ptr, size, #endif flags); }); @@ -517,6 +514,17 @@ bool wait_until_socket_is_ready(socket_t sock, time_t sec, time_t usec) { #endif } +bool is_socket_alive(socket_t sock) { + const auto val = detail::select_read(sock, 0, 0); + if (val == 0) { + return true; + } else if (val < 0 && errno == EBADF) { + return false; + } + char buf[1]; + return detail::read_socket(sock, &buf[0], sizeof(buf), MSG_PEEK) > 0; +} + class SocketStream : public Stream { public: SocketStream(socket_t sock, time_t read_timeout_sec, time_t read_timeout_usec, @@ -590,12 +598,14 @@ bool keep_alive(socket_t sock, time_t keep_alive_timeout_sec) { template bool -process_server_socket_core(socket_t sock, size_t keep_alive_max_count, +process_server_socket_core(const std::atomic &svr_sock, socket_t sock, + size_t keep_alive_max_count, time_t keep_alive_timeout_sec, T callback) { assert(keep_alive_max_count > 0); auto ret = false; auto count = keep_alive_max_count; - while (count > 0 && keep_alive(sock, keep_alive_timeout_sec)) { + while (svr_sock != INVALID_SOCKET && count > 0 && + keep_alive(sock, keep_alive_timeout_sec)) { auto close_connection = count == 1; auto connection_closed = false; ret = callback(close_connection, connection_closed); @@ -607,12 +617,13 @@ process_server_socket_core(socket_t sock, size_t keep_alive_max_count, template bool -process_server_socket(socket_t sock, size_t keep_alive_max_count, +process_server_socket(const std::atomic &svr_sock, socket_t sock, + size_t keep_alive_max_count, time_t keep_alive_timeout_sec, time_t read_timeout_sec, time_t read_timeout_usec, time_t write_timeout_sec, time_t write_timeout_usec, T callback) { return process_server_socket_core( - sock, keep_alive_max_count, keep_alive_timeout_sec, + svr_sock, sock, keep_alive_max_count, keep_alive_timeout_sec, [&](bool close_connection, bool &connection_closed) { SocketStream strm(sock, read_timeout_sec, read_timeout_usec, write_timeout_sec, write_timeout_usec); @@ -639,8 +650,8 @@ int shutdown_socket(socket_t sock) { } template -socket_t create_socket(const char *host, int port, int address_family, - int socket_flags, bool tcp_nodelay, +socket_t create_socket(const char *host, const char *ip, int port, + int address_family, int socket_flags, bool tcp_nodelay, SocketOptions socket_options, BindOrConnect bind_or_connect) { // Get address info @@ -653,9 +664,16 @@ socket_t create_socket(const char *host, int port, int address_family, hints.ai_flags = socket_flags; hints.ai_protocol = 0; + // Ask getaddrinfo to convert IP in c-string to address + if (ip[0] != '\0') { + hints.ai_family = AF_UNSPEC; + hints.ai_flags = AI_NUMERICHOST; + } + auto service = std::to_string(port); - if (getaddrinfo(host, service.c_str(), &hints, &result)) { + if (ip[0] != '\0' ? getaddrinfo(ip, service.c_str(), &hints, &result) + : getaddrinfo(host, service.c_str(), &hints, &result)) { #if defined __linux__ && !defined __ANDROID__ res_init(); #endif @@ -790,13 +808,13 @@ std::string if2ip(const std::string &ifn) { #endif socket_t create_client_socket( - const char *host, 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, + const char *host, const char *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) { auto sock = create_socket( - host, port, address_family, 0, tcp_nodelay, std::move(socket_options), + host, ip, port, address_family, 0, tcp_nodelay, std::move(socket_options), [&](socket_t sock2, struct addrinfo &ai) -> bool { if (!intf.empty()) { #ifdef USE_IF2IP @@ -1033,11 +1051,13 @@ const char *status_message(int status) { } bool can_compress_content_type(const std::string &content_type) { - return (!content_type.find("text/") && content_type != "text/event-stream") || + return (!content_type.rfind("text/", 0) && + content_type != "text/event-stream") || content_type == "image/svg+xml" || content_type == "application/javascript" || content_type == "application/json" || content_type == "application/xml" || + content_type == "application/protobuf" || content_type == "application/xhtml+xml"; } @@ -1166,9 +1186,7 @@ bool gzip_decompressor::decompress(const char *data, size_t data_length, ret = inflate(&strm_, Z_NO_FLUSH); - if (prev_avail_in - strm_.avail_in == 0) { - return false; - } + if (prev_avail_in - strm_.avail_in == 0) { return false; } assert(ret != Z_STREAM_ERROR); switch (ret) { @@ -1335,6 +1353,8 @@ bool read_headers(Stream &strm, Headers &headers) { continue; // Skip invalid line. } + if (line_reader.size() > CPPHTTPLIB_HEADER_MAX_LENGTH) { return false; } + // Exclude CRLF auto end = line_reader.ptr() + line_reader.size() - 2; @@ -1781,7 +1801,11 @@ bool parse_multipart_boundary(const std::string &content_type, return !boundary.empty(); } +#ifdef CPPHTTPLIB_NO_EXCEPTIONS +bool parse_range_header(const std::string &s, Ranges &ranges) { +#else bool parse_range_header(const std::string &s, Ranges &ranges) try { +#endif static auto re_first_range = std::regex(R"(bytes=(\d*-\d*(?:,\s*\d*-\d*)*))"); std::smatch m; if (std::regex_match(s, m, re_first_range)) { @@ -1813,7 +1837,11 @@ bool parse_range_header(const std::string &s, Ranges &ranges) try { return all_valid_ranges; } return false; +#ifdef CPPHTTPLIB_NO_EXCEPTIONS +} +#else } catch (...) { return false; } +#endif class MultipartFormDataParser { public: @@ -1833,17 +1861,15 @@ public: static const std::string dash_ = "--"; static const std::string crlf_ = "\r\n"; - buf_.append(buf, n); // TODO: performance improvement + buf_append(buf, n); - while (!buf_.empty()) { + while (buf_size() > 0) { switch (state_) { case 0: { // Initial boundary auto pattern = dash_ + boundary_ + crlf_; - if (pattern.size() > buf_.size()) { return true; } - auto pos = buf_.find(pattern); - if (pos != 0) { return false; } - buf_.erase(0, pattern.size()); - off_ += pattern.size(); + if (pattern.size() > buf_size()) { return true; } + if (!buf_start_with(pattern)) { return false; } + buf_erase(pattern.size()); state_ = 1; break; } @@ -1853,22 +1879,22 @@ public: break; } case 2: { // Headers - auto pos = buf_.find(crlf_); - while (pos != std::string::npos) { + auto pos = buf_find(crlf_); + if (pos > CPPHTTPLIB_HEADER_MAX_LENGTH) { return false; } + while (pos < buf_size()) { // Empty line if (pos == 0) { if (!header_callback(file_)) { is_valid_ = false; return false; } - buf_.erase(0, crlf_.size()); - off_ += crlf_.size(); + buf_erase(crlf_.size()); state_ = 3; break; } static const std::string header_name = "content-type:"; - const auto header = buf_.substr(0, pos); + const auto header = buf_head(pos); if (start_with_case_ignore(header, header_name)) { file_.content_type = trim_copy(header.substr(header_name.size())); } else { @@ -1879,9 +1905,8 @@ public: } } - buf_.erase(0, pos + crlf_.size()); - off_ += pos + crlf_.size(); - pos = buf_.find(crlf_); + buf_erase(pos + crlf_.size()); + pos = buf_find(crlf_); } if (state_ != 3) { return true; } break; @@ -1889,56 +1914,51 @@ public: case 3: { // Body { auto pattern = crlf_ + dash_; - if (pattern.size() > buf_.size()) { return true; } + if (pattern.size() > buf_size()) { return true; } - auto pos = find_string(buf_, pattern); + auto pos = buf_find(pattern); - if (!content_callback(buf_.data(), pos)) { + if (!content_callback(buf_data(), pos)) { is_valid_ = false; return false; } - off_ += pos; - buf_.erase(0, pos); + buf_erase(pos); } { auto pattern = crlf_ + dash_ + boundary_; - if (pattern.size() > buf_.size()) { return true; } + if (pattern.size() > buf_size()) { return true; } - auto pos = buf_.find(pattern); - if (pos != std::string::npos) { - if (!content_callback(buf_.data(), pos)) { + auto pos = buf_find(pattern); + if (pos < buf_size()) { + if (!content_callback(buf_data(), pos)) { is_valid_ = false; return false; } - off_ += pos + pattern.size(); - buf_.erase(0, pos + pattern.size()); + buf_erase(pos + pattern.size()); state_ = 4; } else { - if (!content_callback(buf_.data(), pattern.size())) { + if (!content_callback(buf_data(), pattern.size())) { is_valid_ = false; return false; } - off_ += pattern.size(); - buf_.erase(0, pattern.size()); + buf_erase(pattern.size()); } } break; } case 4: { // Boundary - if (crlf_.size() > buf_.size()) { return true; } - if (buf_.compare(0, crlf_.size(), crlf_) == 0) { - buf_.erase(0, crlf_.size()); - off_ += crlf_.size(); + if (crlf_.size() > buf_size()) { return true; } + if (buf_start_with(crlf_)) { + buf_erase(crlf_.size()); state_ = 1; } else { auto pattern = dash_ + crlf_; - if (pattern.size() > buf_.size()) { return true; } - if (buf_.compare(0, pattern.size(), pattern) == 0) { - buf_.erase(0, pattern.size()); - off_ += pattern.size(); + if (pattern.size() > buf_size()) { return true; } + if (buf_start_with(pattern)) { + buf_erase(pattern.size()); is_valid_ = true; state_ = 5; } else { @@ -1973,41 +1993,78 @@ private: return true; } - bool start_with(const std::string &a, size_t off, + std::string boundary_; + + size_t state_ = 0; + bool is_valid_ = false; + MultipartFormData file_; + + // Buffer + bool start_with(const std::string &a, size_t spos, size_t epos, const std::string &b) const { - if (a.size() - off < b.size()) { return false; } + if (epos - spos < b.size()) { return false; } for (size_t i = 0; i < b.size(); i++) { - if (a[i + off] != b[i]) { return false; } + if (a[i + spos] != b[i]) { return false; } } return true; } - size_t find_string(const std::string &s, const std::string &pattern) const { - auto c = pattern.front(); + size_t buf_size() const { return buf_epos_ - buf_spos_; } + + const char *buf_data() const { return &buf_[buf_spos_]; } + + std::string buf_head(size_t l) const { return buf_.substr(buf_spos_, l); } + + bool buf_start_with(const std::string &s) const { + return start_with(buf_, buf_spos_, buf_epos_, s); + } + + size_t buf_find(const std::string &s) const { + auto c = s.front(); - size_t off = 0; - while (off < s.size()) { - auto pos = s.find(c, off); - if (pos == std::string::npos) { return s.size(); } + size_t off = buf_spos_; + while (off < buf_epos_) { + auto pos = off; + while (true) { + if (pos == buf_epos_) { return buf_size(); } + if (buf_[pos] == c) { break; } + pos++; + } - auto rem = s.size() - pos; - if (pattern.size() > rem) { return pos; } + auto remaining_size = buf_epos_ - pos; + if (s.size() > remaining_size) { return buf_size(); } - if (start_with(s, pos, pattern)) { return pos; } + if (start_with(buf_, pos, buf_epos_, s)) { return pos - buf_spos_; } off = pos + 1; } - return s.size(); + return buf_size(); } - std::string boundary_; + void buf_append(const char *data, size_t n) { + auto remaining_size = buf_size(); + if (remaining_size > 0 && buf_spos_ > 0) { + for (size_t i = 0; i < remaining_size; i++) { + buf_[i] = buf_[buf_spos_ + i]; + } + } + buf_spos_ = 0; + buf_epos_ = remaining_size; + + if (remaining_size + n > buf_.size()) { buf_.resize(remaining_size + n); } + + for (size_t i = 0; i < n; i++) { + buf_[buf_epos_ + i] = data[i]; + } + buf_epos_ += n; + } + + void buf_erase(size_t size) { buf_spos_ += size; } std::string buf_; - size_t state_ = 0; - bool is_valid_ = false; - size_t off_ = 0; - MultipartFormData file_; + size_t buf_spos_ = 0; + size_t buf_epos_ = 0; }; std::string to_lower(const char *beg, const char *end) { @@ -2470,7 +2527,7 @@ size_t Request::get_param_value_count(const char *key) const { bool Request::is_multipart_form_data() const { const auto &content_type = get_header_value("Content-Type"); - return !content_type.find("multipart/form-data"); + return !content_type.rfind("multipart/form-data", 0); } bool Request::has_file(const char *key) const { @@ -2604,8 +2661,7 @@ SocketStream::SocketStream(socket_t sock, time_t read_timeout_sec, : sock_(sock), read_timeout_sec_(read_timeout_sec), read_timeout_usec_(read_timeout_usec), write_timeout_sec_(write_timeout_sec), - write_timeout_usec_(write_timeout_usec), - read_buff_(read_buff_size_, 0) {} + write_timeout_usec_(write_timeout_usec), read_buff_(read_buff_size_, 0) {} SocketStream::~SocketStream() {} @@ -2619,9 +2675,11 @@ bool SocketStream::is_writable() const { ssize_t SocketStream::read(char *ptr, size_t size) { #ifdef _WIN32 - size = (std::min)(size, static_cast((std::numeric_limits::max)())); + size = + (std::min)(size, static_cast((std::numeric_limits::max)())); #else - size = (std::min)(size, static_cast((std::numeric_limits::max)())); + size = (std::min)(size, + static_cast((std::numeric_limits::max)())); #endif if (read_buff_off_ < read_buff_content_size_) { @@ -2643,7 +2701,8 @@ ssize_t SocketStream::read(char *ptr, size_t size) { read_buff_content_size_ = 0; if (size < read_buff_size_) { - auto n = read_socket(sock_, read_buff_.data(), read_buff_size_, CPPHTTPLIB_RECV_FLAGS); + auto n = read_socket(sock_, read_buff_.data(), read_buff_size_, + CPPHTTPLIB_RECV_FLAGS); if (n <= 0) { return n; } else if (n <= static_cast(size)) { @@ -2664,7 +2723,8 @@ ssize_t SocketStream::write(const char *ptr, size_t size) { if (!is_writable()) { return -1; } #ifdef _WIN32 - size = (std::min)(size, static_cast((std::numeric_limits::max)())); + size = + (std::min)(size, static_cast((std::numeric_limits::max)())); #endif return send_socket(sock_, ptr, size, CPPHTTPLIB_SEND_FLAGS); @@ -3265,15 +3325,13 @@ socket_t Server::create_server_socket(const char *host, int port, int socket_flags, SocketOptions socket_options) const { return detail::create_socket( - host, port, address_family_, socket_flags, tcp_nodelay_, + host, "", 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(ai.ai_addrlen))) { return false; } - if (::listen(sock, 5)) { // Listen through 5 channels - return false; - } + if (::listen(sock, CPPHTTPLIB_LISTEN_BACKLOG)) { return false; } return true; }); } @@ -3675,6 +3733,9 @@ Server::process_request(Stream &strm, bool close_connection, // Rounting bool routed = false; +#ifdef CPPHTTPLIB_NO_EXCEPTIONS + routed = routing(req, res, strm); +#else try { routed = routing(req, res, strm); } catch (std::exception &e) { @@ -3689,6 +3750,7 @@ Server::process_request(Stream &strm, bool close_connection, res.status = 500; res.set_header("EXCEPTION_WHAT", "UNKNOWN"); } +#endif if (routed) { if (res.status == -1) { res.status = req.ranges.empty() ? 200 : 206; } @@ -3703,8 +3765,9 @@ bool Server::is_valid() const { return true; } bool Server::process_and_close_socket(socket_t sock) { auto ret = detail::process_server_socket( - sock, keep_alive_max_count_, keep_alive_timeout_sec_, read_timeout_sec_, - read_timeout_usec_, write_timeout_sec_, write_timeout_usec_, + svr_sock_, sock, keep_alive_max_count_, keep_alive_timeout_sec_, + read_timeout_sec_, read_timeout_usec_, write_timeout_sec_, + write_timeout_usec_, [this](Stream &strm, bool close_connection, bool &connection_closed) { return process_request(strm, close_connection, connection_closed, nullptr); @@ -3784,16 +3847,21 @@ 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_.c_str(), "", 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); } + // Check is custom IP specified for host_ + std::string ip; + auto it = addr_map_.find(host_); + if (it != addr_map_.end()) ip = it->second; + return detail::create_client_socket( - host_.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_.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); } bool ClientImpl::create_and_connect_socket(Socket &socket, @@ -3838,7 +3906,7 @@ void ClientImpl::close_socket(Socket &socket) { bool ClientImpl::read_response_line(Stream &strm, const Request &req, Response &res) { - std::array buf; + std::array buf{}; detail::stream_line_reader line_reader(strm, buf.data(), buf.size()); @@ -3873,13 +3941,14 @@ bool ClientImpl::send(Request &req, Response &res, Error &error) { { std::lock_guard guard(socket_mutex_); + // Set this to false immediately - if it ever gets set to true by the end of // the request, we know another thread instructed us to close the socket. socket_should_be_closed_when_request_is_done_ = false; auto is_alive = false; if (socket_.is_open()) { - is_alive = detail::select_write(socket_.sock, 0, 0) > 0; + is_alive = detail::is_socket_alive(socket_.sock); if (!is_alive) { // Attempt to avoid sigpipe by shutting down nongracefully if it seems // like the other side has already closed the connection Also, there @@ -4136,7 +4205,7 @@ bool ClientImpl::write_request(Stream &strm, Request &req, if (!req.has_header("Accept")) { req.headers.emplace("Accept", "*/*"); } if (!req.has_header("User-Agent")) { - req.headers.emplace("User-Agent", "cpp-httplib/0.9"); + req.headers.emplace("User-Agent", "cpp-httplib/0.10.1"); } if (req.body.empty()) { @@ -4918,6 +4987,11 @@ void ClientImpl::set_follow_location(bool on) { follow_location_ = on; } void ClientImpl::set_url_encode(bool on) { url_encode_ = on; } +void ClientImpl::set_hostname_addr_map( + const std::map addr_map) { + addr_map_ = std::move(addr_map); +} + void ClientImpl::set_default_headers(Headers headers) { default_headers_ = std::move(headers); } @@ -5057,14 +5131,13 @@ bool ssl_connect_or_accept_nonblocking(socket_t sock, SSL *ssl, } template -bool -process_server_socket_ssl(SSL *ssl, socket_t sock, size_t keep_alive_max_count, - time_t keep_alive_timeout_sec, - time_t read_timeout_sec, time_t read_timeout_usec, - time_t write_timeout_sec, time_t write_timeout_usec, - T callback) { +bool process_server_socket_ssl( + const std::atomic &svr_sock, SSL *ssl, socket_t sock, + size_t keep_alive_max_count, time_t keep_alive_timeout_sec, + time_t read_timeout_sec, time_t read_timeout_usec, time_t write_timeout_sec, + time_t write_timeout_usec, T callback) { return process_server_socket_core( - sock, keep_alive_max_count, keep_alive_timeout_sec, + svr_sock, sock, keep_alive_max_count, keep_alive_timeout_sec, [&](bool close_connection, bool &connection_closed) { SSLSocketStream strm(sock, ssl, read_timeout_sec, read_timeout_usec, write_timeout_sec, write_timeout_usec); @@ -5166,9 +5239,9 @@ ssize_t SSLSocketStream::read(char *ptr, size_t size) { 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) { #endif @@ -5196,9 +5269,9 @@ ssize_t SSLSocketStream::write(const char *ptr, size_t size) { 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) { #endif @@ -5232,17 +5305,14 @@ static SSLInit sslinit_; SSLServer::SSLServer(const char *cert_path, const char *private_key_path, const char *client_ca_cert_file_path, const char *client_ca_cert_dir_path) { - ctx_ = SSL_CTX_new(TLS_method()); + ctx_ = SSL_CTX_new(TLS_server_method()); if (ctx_) { SSL_CTX_set_options(ctx_, - SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | - SSL_OP_NO_COMPRESSION | + SSL_OP_NO_COMPRESSION | SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION); - // auto ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1); - // SSL_CTX_set_tmp_ecdh(ctx_, ecdh); - // EC_KEY_free(ecdh); + SSL_CTX_set_min_proto_version(ctx_, TLS1_1_VERSION); if (SSL_CTX_use_certificate_chain_file(ctx_, cert_path) != 1 || SSL_CTX_use_PrivateKey_file(ctx_, private_key_path, SSL_FILETYPE_PEM) != @@ -5250,46 +5320,35 @@ SSLServer::SSLServer(const char *cert_path, const char *private_key_path, SSL_CTX_free(ctx_); ctx_ = nullptr; } else if (client_ca_cert_file_path || client_ca_cert_dir_path) { - // if (client_ca_cert_file_path) { - // auto list = SSL_load_client_CA_file(client_ca_cert_file_path); - // SSL_CTX_set_client_CA_list(ctx_, list); - // } - SSL_CTX_load_verify_locations(ctx_, client_ca_cert_file_path, client_ca_cert_dir_path); SSL_CTX_set_verify( - ctx_, - SSL_VERIFY_PEER | - SSL_VERIFY_FAIL_IF_NO_PEER_CERT, // SSL_VERIFY_CLIENT_ONCE, - nullptr); + ctx_, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, nullptr); } } } SSLServer::SSLServer(X509 *cert, EVP_PKEY *private_key, X509_STORE *client_ca_cert_store) { - ctx_ = SSL_CTX_new(SSLv23_server_method()); + ctx_ = SSL_CTX_new(TLS_server_method()); if (ctx_) { SSL_CTX_set_options(ctx_, - SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | - SSL_OP_NO_COMPRESSION | + SSL_OP_NO_COMPRESSION | SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION); + SSL_CTX_set_min_proto_version(ctx_, TLS1_1_VERSION); + if (SSL_CTX_use_certificate(ctx_, cert) != 1 || SSL_CTX_use_PrivateKey(ctx_, private_key) != 1) { SSL_CTX_free(ctx_); ctx_ = nullptr; } else if (client_ca_cert_store) { - SSL_CTX_set_cert_store(ctx_, client_ca_cert_store); SSL_CTX_set_verify( - ctx_, - SSL_VERIFY_PEER | - SSL_VERIFY_FAIL_IF_NO_PEER_CERT, // SSL_VERIFY_CLIENT_ONCE, - nullptr); + ctx_, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, nullptr); } } } @@ -5311,6 +5370,8 @@ SSLServer::~SSLServer() { bool SSLServer::is_valid() const { return ctx_; } +SSL_CTX *SSLServer::ssl_context() const { return ctx_; } + bool SSLServer::process_and_close_socket(socket_t sock) { auto ssl = detail::ssl_new( sock, ctx_, ctx_mutex_, @@ -5323,7 +5384,7 @@ bool SSLServer::process_and_close_socket(socket_t sock) { bool ret = false; if (ssl) { ret = detail::process_server_socket_ssl( - ssl, sock, keep_alive_max_count_, keep_alive_timeout_sec_, + svr_sock_, ssl, sock, keep_alive_max_count_, keep_alive_timeout_sec_, read_timeout_sec_, read_timeout_usec_, write_timeout_sec_, write_timeout_usec_, [this, ssl](Stream &strm, bool close_connection, @@ -5354,12 +5415,13 @@ SSLClient::SSLClient(const std::string &host, int port, const std::string &client_cert_path, const std::string &client_key_path) : ClientImpl(host, port, client_cert_path, client_key_path) { - ctx_ = SSL_CTX_new(SSLv23_client_method()); + ctx_ = SSL_CTX_new(TLS_client_method()); detail::split(&host_[0], &host_[host_.size()], '.', [&](const char *b, const char *e) { host_components_.emplace_back(std::string(b, e)); }); + if (!client_cert_path.empty() && !client_key_path.empty()) { if (SSL_CTX_use_certificate_file(ctx_, client_cert_path.c_str(), SSL_FILETYPE_PEM) != 1 || @@ -5374,12 +5436,13 @@ SSLClient::SSLClient(const std::string &host, int port, SSLClient::SSLClient(const std::string &host, int port, X509 *client_cert, EVP_PKEY *client_key) : ClientImpl(host, port) { - ctx_ = SSL_CTX_new(SSLv23_client_method()); + ctx_ = SSL_CTX_new(TLS_client_method()); detail::split(&host_[0], &host_[host_.size()], '.', [&](const char *b, const char *e) { host_components_.emplace_back(std::string(b, e)); }); + if (client_cert != nullptr && client_key != nullptr) { if (SSL_CTX_use_certificate(ctx_, client_cert) != 1 || SSL_CTX_use_PrivateKey(ctx_, client_key) != 1) { @@ -5739,8 +5802,10 @@ Client::Client(const std::string &scheme_host_port, #else if (!scheme.empty() && scheme != "http") { #endif +#ifndef CPPHTTPLIB_NO_EXCEPTIONS std::string msg = "'" + scheme + "' scheme is not supported."; throw std::invalid_argument(msg); +#endif return; } @@ -6041,6 +6106,11 @@ size_t Client::is_socket_open() const { return cli_->is_socket_open(); } void Client::stop() { cli_->stop(); } +void Client::set_hostname_addr_map( + const std::map addr_map) { + cli_->set_hostname_addr_map(std::move(addr_map)); +} + void Client::set_default_headers(Headers headers) { cli_->set_default_headers(std::move(headers)); } diff --git a/src/third_party/httplib.h b/src/third_party/httplib.h index 6d69d084f..656a1a752 100644 --- a/src/third_party/httplib.h +++ b/src/third_party/httplib.h @@ -60,6 +60,10 @@ #define CPPHTTPLIB_REQUEST_URI_MAX_LENGTH 8192 #endif +#ifndef CPPHTTPLIB_HEADER_MAX_LENGTH +#define CPPHTTPLIB_HEADER_MAX_LENGTH 8192 +#endif + #ifndef CPPHTTPLIB_REDIRECT_MAX_COUNT #define CPPHTTPLIB_REDIRECT_MAX_COUNT 20 #endif @@ -95,6 +99,10 @@ #define CPPHTTPLIB_SEND_FLAGS 0 #endif +#ifndef CPPHTTPLIB_LISTEN_BACKLOG +#define CPPHTTPLIB_LISTEN_BACKLOG 5 +#endif + /* * Headers */ @@ -505,7 +513,7 @@ public: virtual void enqueue(std::function fn) = 0; virtual void shutdown() = 0; - virtual void on_idle(){}; + virtual void on_idle() {} }; class ThreadPool : public TaskQueue { @@ -955,6 +963,8 @@ public: void stop(); + void set_hostname_addr_map(const std::map addr_map); + void set_default_headers(Headers headers); void set_address_family(int family); @@ -1058,6 +1068,9 @@ protected: std::thread::id socket_requests_are_from_thread_ = std::thread::id(); bool socket_should_be_closed_when_request_is_done_ = false; + // Hostname-IP map + std::map addr_map_; + // Default headers Headers default_headers_; @@ -1285,6 +1298,8 @@ public: void stop(); + void set_hostname_addr_map(const std::map addr_map); + void set_default_headers(Headers headers); void set_address_family(int family); @@ -1371,6 +1386,8 @@ public: bool is_valid() const override; + SSL_CTX *ssl_context() const; + private: bool process_and_close_socket(socket_t sock) override; @@ -1480,10 +1497,10 @@ inline T Response::get_header_value(const char *key, size_t id) const { template inline ssize_t Stream::write_format(const char *fmt, const Args &...args) { const auto bufsiz = 2048; - std::array buf; + std::array buf{}; #if defined(_MSC_VER) && _MSC_VER < 1900 - auto sn = _snprintf_s(buf.data(), bufsiz - 1, buf.size() - 1, fmt, args...); + auto sn = _snprintf_s(buf.data(), bufsiz, _TRUNCATE, fmt, args...); #else auto sn = snprintf(buf.data(), buf.size() - 1, fmt, args...); #endif @@ -1656,14 +1673,12 @@ bool process_client_socket(socket_t sock, time_t read_timeout_sec, time_t write_timeout_usec, std::function callback); -socket_t create_client_socket(const char *host, 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); +socket_t create_client_socket( + const char *host, const char *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, size_t id = 0, const char *def = nullptr);