From: Joel Rosdahl Date: Thu, 27 Jan 2022 19:15:29 +0000 (+0100) Subject: bump: Upgrade to cpp-httplib 0.10.2 X-Git-Tag: v4.6~28 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=041748d834a077c138fb5e6e70b7eb0598c6b75c;p=thirdparty%2Fccache.git bump: Upgrade to cpp-httplib 0.10.2 --- diff --git a/LICENSE.adoc b/LICENSE.adoc index 99f454cb6..e1df2e8ff 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.10.1 downloaded from https://github.com/yhirose/cpp-httplib[cpp-httplib]. The +v0.10.2 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 9f1cc31b8..70c86f1a6 100644 --- a/src/third_party/httplib.cpp +++ b/src/third_party/httplib.cpp @@ -111,8 +111,12 @@ std::string base64_encode(const std::string &in) { } bool is_file(const std::string &path) { +#ifdef _WIN32 + return _access_s(path.c_str(), 0) == 0; +#else struct stat st; return stat(path.c_str(), &st) >= 0 && S_ISREG(st.st_mode); +#endif } bool is_dir(const std::string &path) { @@ -465,7 +469,7 @@ ssize_t select_write(socket_t sock, time_t sec, time_t usec) { #endif } -bool wait_until_socket_is_ready(socket_t sock, time_t sec, time_t usec) { +Error wait_until_socket_is_ready(socket_t sock, time_t sec, time_t usec) { #ifdef CPPHTTPLIB_USE_POLL struct pollfd pfd_read; pfd_read.fd = sock; @@ -475,17 +479,23 @@ bool wait_until_socket_is_ready(socket_t sock, time_t sec, time_t usec) { auto poll_res = handle_EINTR([&]() { return poll(&pfd_read, 1, timeout); }); + if (poll_res == 0) { + return Error::ConnectionTimeout; + } + if (poll_res > 0 && pfd_read.revents & (POLLIN | POLLOUT)) { int error = 0; socklen_t len = sizeof(error); auto res = getsockopt(sock, SOL_SOCKET, SO_ERROR, reinterpret_cast(&error), &len); - return res >= 0 && !error; + auto successful = res >= 0 && !error; + return successful ? Error::Success : Error::Connection; } - return false; + + return Error::Connection; #else #ifndef _WIN32 - if (sock >= FD_SETSIZE) { return false; } + if (sock >= FD_SETSIZE) { return Error::Connection; } #endif fd_set fdsr; @@ -503,14 +513,19 @@ bool wait_until_socket_is_ready(socket_t sock, time_t sec, time_t usec) { return select(static_cast(sock + 1), &fdsr, &fdsw, &fdse, &tv); }); + if (ret == 0) { + return Error::ConnectionTimeout; + } + if (ret > 0 && (FD_ISSET(sock, &fdsr) || FD_ISSET(sock, &fdsw))) { int error = 0; socklen_t len = sizeof(error); - return getsockopt(sock, SOL_SOCKET, SO_ERROR, - reinterpret_cast(&error), &len) >= 0 && - !error; + auto res = getsockopt(sock, SOL_SOCKET, SO_ERROR, + reinterpret_cast(&error), &len); + auto successful = res >= 0 && !error; + return successful ? Error::Success : Error::Connection; } - return false; + return Error::Connection; #endif } @@ -655,25 +670,28 @@ socket_t create_socket(const char *host, const char *ip, int port, SocketOptions socket_options, BindOrConnect bind_or_connect) { // Get address info + const char *node = nullptr; struct addrinfo hints; struct addrinfo *result; memset(&hints, 0, sizeof(struct addrinfo)); - hints.ai_family = address_family; hints.ai_socktype = SOCK_STREAM; - hints.ai_flags = socket_flags; hints.ai_protocol = 0; - // Ask getaddrinfo to convert IP in c-string to address if (ip[0] != '\0') { + node = ip; + // Ask getaddrinfo to convert IP in c-string to address hints.ai_family = AF_UNSPEC; hints.ai_flags = AI_NUMERICHOST; + } else { + node = host; + hints.ai_family = address_family; + hints.ai_flags = socket_flags; } auto service = std::to_string(port); - if (ip[0] != '\0' ? getaddrinfo(ip, service.c_str(), &hints, &result) - : getaddrinfo(host, service.c_str(), &hints, &result)) { + if (getaddrinfo(node, service.c_str(), &hints, &result)) { #if defined __linux__ && !defined __ANDROID__ res_init(); #endif @@ -833,27 +851,45 @@ socket_t create_client_socket( ::connect(sock2, ai.ai_addr, static_cast(ai.ai_addrlen)); if (ret < 0) { - if (is_connection_error() || - !wait_until_socket_is_ready(sock2, connection_timeout_sec, - connection_timeout_usec)) { + if (is_connection_error()) { error = Error::Connection; return false; } + error = wait_until_socket_is_ready(sock2, connection_timeout_sec, + connection_timeout_usec); + if (error != Error::Success) { + return false; + } } set_nonblocking(sock2, false); { +#ifdef _WIN32 + auto timeout = static_cast(read_timeout_sec * 1000 + + read_timeout_usec / 1000); + setsockopt(sock2, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, + sizeof(timeout)); +#else timeval tv; tv.tv_sec = static_cast(read_timeout_sec); tv.tv_usec = static_cast(read_timeout_usec); setsockopt(sock2, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(tv)); +#endif } { + +#ifdef _WIN32 + auto timeout = static_cast(write_timeout_sec * 1000 + + write_timeout_usec / 1000); + setsockopt(sock2, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout, + sizeof(timeout)); +#else timeval tv; tv.tv_sec = static_cast(write_timeout_sec); tv.tv_usec = static_cast(write_timeout_usec); setsockopt(sock2, SOL_SOCKET, SO_SNDTIMEO, (char *)&tv, sizeof(tv)); +#endif } error = Error::Success; @@ -869,7 +905,7 @@ socket_t create_client_socket( return sock; } -void get_remote_ip_and_port(const struct sockaddr_storage &addr, +bool get_remote_ip_and_port(const struct sockaddr_storage &addr, socklen_t addr_len, std::string &ip, int &port) { if (addr.ss_family == AF_INET) { @@ -877,14 +913,19 @@ void get_remote_ip_and_port(const struct sockaddr_storage &addr, } else if (addr.ss_family == AF_INET6) { port = ntohs(reinterpret_cast(&addr)->sin6_port); + } else { + return false; } std::array ipstr{}; - if (!getnameinfo(reinterpret_cast(&addr), addr_len, - ipstr.data(), static_cast(ipstr.size()), nullptr, - 0, NI_NUMERICHOST)) { - ip = ipstr.data(); + if (getnameinfo(reinterpret_cast(&addr), addr_len, + ipstr.data(), static_cast(ipstr.size()), nullptr, + 0, NI_NUMERICHOST)) { + return false; } + + ip = ipstr.data(); + return true; } void get_remote_ip_and_port(socket_t sock, std::string &ip, int &port) { @@ -1346,17 +1387,26 @@ bool read_headers(Stream &strm, Headers &headers) { if (!line_reader.getline()) { return false; } // Check if the line ends with CRLF. + auto line_terminator_len = 2; if (line_reader.end_with_crlf()) { // Blank line indicates end of headers. if (line_reader.size() == 2) { break; } +#ifdef CPPHTTPLIB_ALLOW_LF_AS_LINE_TERMINATOR + } else { + // Blank line indicates end of headers. + if (line_reader.size() == 1) { break; } + line_terminator_len = 1; + } +#else } else { continue; // Skip invalid line. } +#endif if (line_reader.size() > CPPHTTPLIB_HEADER_MAX_LENGTH) { return false; } - // Exclude CRLF - auto end = line_reader.ptr() + line_reader.size() - 2; + // Exclude line terminator + auto end = line_reader.ptr() + line_reader.size() - line_terminator_len; parse_header(line_reader.ptr(), end, [&](std::string &&key, std::string &&val) { @@ -2085,6 +2135,7 @@ std::string make_multipart_data_boundary() { // platforms, but due to lack of support in the c++ standard library, // doing better requires either some ugly hacks or breaking portability. std::random_device seed_gen; + // Request 128 bits of entropy for initialization std::seed_seq seed_sequence{seed_gen(), seed_gen(), seed_gen(), seed_gen()}; std::mt19937 engine(seed_sequence); @@ -2367,14 +2418,16 @@ std::pair make_digest_authentication_header( } } - auto field = - "Digest username=\"" + username + "\", realm=\"" + auth.at("realm") + - "\", nonce=\"" + auth.at("nonce") + "\", uri=\"" + req.path + - "\", algorithm=" + algo + - (qop.empty() ? ", response=\"" - : ", qop=" + qop + ", nc=\"" + nc + "\", cnonce=\"" + - cnonce + "\", response=\"") + - response + "\""; + auto opaque = (auth.find("opaque") != auth.end()) ? auth.at("opaque") : ""; + + auto field = "Digest username=\"" + username + "\", realm=\"" + + auth.at("realm") + "\", nonce=\"" + auth.at("nonce") + + "\", uri=\"" + req.path + "\", algorithm=" + algo + + (qop.empty() ? ", response=\"" + : ", qop=" + qop + ", nc=" + nc + ", cnonce=\"" + + cnonce + "\", response=\"") + + response + "\"" + + (opaque.empty() ? "" : ", opaque=\"" + opaque + "\""); auto key = is_proxy ? "Proxy-Authorization" : "Authorization"; return std::make_pair(key, field); @@ -2444,6 +2497,41 @@ private: } // namespace detail +std::string hosted_at(const char *hostname) { + std::vector addrs; + hosted_at(hostname, addrs); + if (addrs.empty()) { return std::string(); } + return addrs[0]; +} + +void hosted_at(const char *hostname, std::vector &addrs) { + struct addrinfo hints; + struct addrinfo *result; + + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = 0; + + if (getaddrinfo(hostname, nullptr, &hints, &result)) { +#if defined __linux__ && !defined __ANDROID__ + res_init(); +#endif + return; + } + + for (auto rp = result; rp; rp = rp->ai_next) { + const auto &addr = + *reinterpret_cast(rp->ai_addr); + std::string ip; + int dummy = -1; + if (detail::get_remote_ip_and_port(addr, sizeof(struct sockaddr_storage), + ip, dummy)) { + addrs.push_back(ip); + } + } +} + std::string append_query_params(const char *path, const Params ¶ms) { std::string path_with_query = path; const static std::regex re("[^?]+\\?.*"); @@ -3400,16 +3488,31 @@ bool Server::listen_internal() { } { +#ifdef _WIN32 + auto timeout = static_cast(read_timeout_sec_ * 1000 + + read_timeout_usec_ / 1000); + setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, + sizeof(timeout)); +#else timeval tv; tv.tv_sec = static_cast(read_timeout_sec_); tv.tv_usec = static_cast(read_timeout_usec_); setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(tv)); +#endif } { + +#ifdef _WIN32 + auto timeout = static_cast(write_timeout_sec_ * 1000 + + write_timeout_usec_ / 1000); + setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout, + sizeof(timeout)); +#else timeval tv; tv.tv_sec = static_cast(write_timeout_sec_); tv.tv_usec = static_cast(write_timeout_usec_); setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (char *)&tv, sizeof(tv)); +#endif } #if __cplusplus > 201703L @@ -3852,6 +3955,7 @@ socket_t ClientImpl::create_client_socket(Error &error) const { 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_); @@ -3912,7 +4016,11 @@ bool ClientImpl::read_response_line(Stream &strm, const Request &req, if (!line_reader.getline()) { return false; } +#ifdef CPPHTTPLIB_ALLOW_LF_AS_LINE_TERMINATOR const static std::regex re("(HTTP/1\\.[01]) (\\d{3})(?: (.*?))?\r\n"); +#else + const static std::regex re("(HTTP/1\\.[01]) (\\d{3})(?: (.*?))?\r?\n"); +#endif std::cmatch m; if (!std::regex_match(line_reader.ptr(), m, re)) { @@ -4299,11 +4407,6 @@ std::unique_ptr ClientImpl::send_with_content_provider( ContentProviderWithoutLength content_provider_without_length, const char *content_type, Error &error) { - // Request req; - // req.method = method; - // req.headers = headers; - // req.path = path; - if (content_type) { req.headers.emplace("Content-Type", content_type); } #ifdef CPPHTTPLIB_ZLIB_SUPPORT diff --git a/src/third_party/httplib.h b/src/third_party/httplib.h index 656a1a752..014d21653 100644 --- a/src/third_party/httplib.h +++ b/src/third_party/httplib.h @@ -217,6 +217,15 @@ using socket_t = int; #include #ifdef CPPHTTPLIB_OPENSSL_SUPPORT +// these are defined in wincrypt.h and it breaks compilation if BoringSSL is +// used +#ifdef _WIN32 +#undef X509_NAME +#undef X509_CERT_PAIR +#undef X509_EXTENSIONS +#undef PKCS7_SIGNER_INFO +#endif + #include #include #include @@ -790,6 +799,7 @@ enum class Error { SSLServerVerification, UnsupportedMultipartBoundaryChars, Compression, + ConnectionTimeout, }; std::string to_string(const Error error); @@ -1585,6 +1595,7 @@ inline std::string to_string(const Error error) { case Error::UnsupportedMultipartBoundaryChars: return "UnsupportedMultipartBoundaryChars"; case Error::Compression: return "Compression"; + case Error::ConnectionTimeout: return "ConnectionTimeout"; case Error::Unknown: return "Unknown"; default: break; } @@ -1648,6 +1659,10 @@ Client::set_write_timeout(const std::chrono::duration &duration) { * .h + .cc. */ +std::string hosted_at(const char *hostname); + +void hosted_at(const char *hostname, std::vector &addrs); + std::string append_query_params(const char *path, const Params ¶ms); std::pair make_range_header(Ranges ranges); @@ -1661,6 +1676,8 @@ namespace detail { std::string encode_query_param(const std::string &value); +std::string decode_url(const std::string &s, bool convert_plus_to_space); + void read_file(const std::string &path, std::string &out); std::string trim_copy(const std::string &s);