diff options
author | Joel Rosdahl <joel@rosdahl.net> | 2021-11-03 21:38:50 +0100 |
---|---|---|
committer | Joel Rosdahl <joel@rosdahl.net> | 2021-11-06 14:30:56 +0100 |
commit | 56de5b763f841b0be741d0e933f7e579c9432bc3 (patch) | |
tree | 0731499c0532a0709e84046d03032e95e4cb471e | |
parent | e09f9c439e6c2de1ba7003ebedb9f1ba436c58c9 (diff) | |
download | ccache-56de5b763f841b0be741d0e933f7e579c9432bc3.tar.gz |
bump: Upgrade to cpp-httplib 0.9.7
-rw-r--r-- | LICENSE.adoc | 2 | ||||
-rw-r--r-- | src/third_party/httplib.cpp | 214 | ||||
-rw-r--r-- | src/third_party/httplib.h | 17 |
3 files changed, 180 insertions, 53 deletions
diff --git a/LICENSE.adoc b/LICENSE.adoc index 0ff2ca97..2bf092a8 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.4 downloaded from https://github.com/yhirose/cpp-httplib[cpp-httplib]. The +v0.9.7 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 6be2bc04..902aeeee 100644 --- a/src/third_party/httplib.cpp +++ b/src/third_party/httplib.cpp @@ -384,6 +384,34 @@ template <typename T> ssize_t handle_EINTR(T fn) { return res; } +ssize_t read_socket(socket_t sock, void *ptr, size_t size, int flags) { + return handle_EINTR([&]() { + return recv(sock, +#ifdef _WIN32 + static_cast<char *>(ptr), + static_cast<int>(size), +#else + ptr, + size, +#endif + 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<const char *>(ptr), + static_cast<int>(size), +#else + ptr, + size, +#endif + flags); + }); +} + ssize_t select_read(socket_t sock, time_t sec, time_t usec) { #ifdef CPPHTTPLIB_USE_POLL struct pollfd pfd_read; @@ -508,6 +536,12 @@ private: time_t read_timeout_usec_; time_t write_timeout_sec_; time_t write_timeout_usec_; + + std::vector<char> read_buff_; + size_t read_buff_off_ = 0; + size_t read_buff_content_size_ = 0; + + static const size_t read_buff_size_ = 1024 * 4; }; #ifdef CPPHTTPLIB_OPENSSL_SUPPORT @@ -1055,10 +1089,10 @@ bool gzip_compressor::compress(const char *data, size_t data_length, do { constexpr size_t max_avail_in = - std::numeric_limits<decltype(strm_.avail_in)>::max(); + (std::numeric_limits<decltype(strm_.avail_in)>::max)(); strm_.avail_in = static_cast<decltype(strm_.avail_in)>( - std::min(data_length, max_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; @@ -1114,10 +1148,10 @@ bool gzip_decompressor::decompress(const char *data, size_t data_length, do { constexpr size_t max_avail_in = - std::numeric_limits<decltype(strm_.avail_in)>::max(); + (std::numeric_limits<decltype(strm_.avail_in)>::max)(); strm_.avail_in = static_cast<decltype(strm_.avail_in)>( - std::min(data_length, max_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; @@ -1128,7 +1162,14 @@ bool gzip_decompressor::decompress(const char *data, size_t data_length, strm_.avail_out = static_cast<uInt>(buff.size()); strm_.next_out = reinterpret_cast<Bytef *>(buff.data()); + auto prev_avail_in = strm_.avail_in; + ret = inflate(&strm_, Z_NO_FLUSH); + + if (prev_avail_in - strm_.avail_in == 0) { + return false; + } + assert(ret != Z_STREAM_ERROR); switch (ret) { case Z_NEED_DICT: @@ -2152,17 +2193,15 @@ template <typename CTX, typename Init, typename Update, typename Final> std::string message_digest(const std::string &s, Init init, Update update, Final final, size_t digest_length) { - using namespace std; - std::vector<unsigned char> md(digest_length, 0); CTX ctx; init(&ctx); update(&ctx, s.data(), s.size()); final(md.data(), &ctx); - stringstream ss; + std::stringstream ss; for (auto c : md) { - ss << setfill('0') << setw(2) << hex << (unsigned int)c; + ss << std::setfill('0') << std::setw(2) << std::hex << (unsigned int)c; } return ss.str(); } @@ -2230,45 +2269,55 @@ std::pair<std::string, std::string> make_digest_authentication_header( const Request &req, const std::map<std::string, std::string> &auth, size_t cnonce_count, const std::string &cnonce, const std::string &username, const std::string &password, bool is_proxy = false) { - using namespace std; - - string nc; + std::string nc; { - stringstream ss; - ss << setfill('0') << setw(8) << hex << cnonce_count; + std::stringstream ss; + ss << std::setfill('0') << std::setw(8) << std::hex << cnonce_count; nc = ss.str(); } - auto qop = auth.at("qop"); - if (qop.find("auth-int") != std::string::npos) { - qop = "auth-int"; - } else { - qop = "auth"; + std::string qop; + if (auth.find("qop") != auth.end()) { + qop = auth.at("qop"); + if (qop.find("auth-int") != std::string::npos) { + qop = "auth-int"; + } else if (qop.find("auth") != std::string::npos) { + qop = "auth"; + } else { + qop.clear(); + } } std::string algo = "MD5"; if (auth.find("algorithm") != auth.end()) { algo = auth.at("algorithm"); } - string response; + std::string response; { - auto H = algo == "SHA-256" - ? detail::SHA_256 - : algo == "SHA-512" ? detail::SHA_512 : detail::MD5; + auto H = algo == "SHA-256" ? detail::SHA_256 + : algo == "SHA-512" ? detail::SHA_512 + : detail::MD5; auto A1 = username + ":" + auth.at("realm") + ":" + password; auto A2 = req.method + ":" + req.path; if (qop == "auth-int") { A2 += ":" + H(req.body); } - response = H(H(A1) + ":" + auth.at("nonce") + ":" + nc + ":" + cnonce + - ":" + qop + ":" + H(A2)); + if (qop.empty()) { + response = H(H(A1) + ":" + auth.at("nonce") + ":" + H(A2)); + } else { + response = H(H(A1) + ":" + auth.at("nonce") + ":" + nc + ":" + cnonce + + ":" + qop + ":" + H(A2)); + } } - auto field = "Digest username=\"" + username + "\", realm=\"" + - auth.at("realm") + "\", nonce=\"" + auth.at("nonce") + - "\", uri=\"" + req.path + "\", algorithm=" + algo + - ", qop=" + qop + ", nc=\"" + nc + "\", cnonce=\"" + cnonce + - "\", response=\"" + response + "\""; + 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 key = is_proxy ? "Proxy-Authorization" : "Authorization"; return std::make_pair(key, field); @@ -2555,7 +2604,8 @@ 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) {} + write_timeout_usec_(write_timeout_usec), + read_buff_(read_buff_size_, 0) {} SocketStream::~SocketStream() {} @@ -2568,31 +2618,56 @@ bool SocketStream::is_writable() const { } ssize_t SocketStream::read(char *ptr, size_t size) { - if (!is_readable()) { return -1; } - #ifdef _WIN32 - if (size > static_cast<size_t>((std::numeric_limits<int>::max)())) { - return -1; - } - return recv(sock_, ptr, static_cast<int>(size), CPPHTTPLIB_RECV_FLAGS); + size = (std::min)(size, static_cast<size_t>((std::numeric_limits<int>::max)())); #else - return handle_EINTR( - [&]() { return recv(sock_, ptr, size, CPPHTTPLIB_RECV_FLAGS); }); + size = (std::min)(size, static_cast<size_t>((std::numeric_limits<ssize_t>::max)())); #endif + + if (read_buff_off_ < read_buff_content_size_) { + auto remaining_size = read_buff_content_size_ - read_buff_off_; + if (size <= remaining_size) { + memcpy(ptr, read_buff_.data() + read_buff_off_, size); + read_buff_off_ += size; + return static_cast<ssize_t>(size); + } else { + memcpy(ptr, read_buff_.data() + read_buff_off_, remaining_size); + read_buff_off_ += remaining_size; + return static_cast<ssize_t>(remaining_size); + } + } + + if (!is_readable()) { return -1; } + + read_buff_off_ = 0; + read_buff_content_size_ = 0; + + if (size < read_buff_size_) { + auto n = read_socket(sock_, read_buff_.data(), read_buff_size_, CPPHTTPLIB_RECV_FLAGS); + if (n <= 0) { + return n; + } else if (n <= static_cast<ssize_t>(size)) { + memcpy(ptr, read_buff_.data(), static_cast<size_t>(n)); + return n; + } else { + memcpy(ptr, read_buff_.data(), size); + read_buff_off_ = size; + read_buff_content_size_ = static_cast<size_t>(n); + return static_cast<ssize_t>(size); + } + } else { + return read_socket(sock_, ptr, size, CPPHTTPLIB_RECV_FLAGS); + } } ssize_t SocketStream::write(const char *ptr, size_t size) { if (!is_writable()) { return -1; } #ifdef _WIN32 - if (size > static_cast<size_t>((std::numeric_limits<int>::max)())) { - return -1; - } - return send(sock_, ptr, static_cast<int>(size), CPPHTTPLIB_SEND_FLAGS); -#else - return handle_EINTR( - [&]() { return send(sock_, ptr, size, CPPHTTPLIB_SEND_FLAGS); }); + size = (std::min)(size, static_cast<size_t>((std::numeric_limits<int>::max)())); #endif + + return send_socket(sock_, ptr, size, CPPHTTPLIB_SEND_FLAGS); } void SocketStream::get_remote_ip_and_port(std::string &ip, @@ -3081,6 +3156,10 @@ bool Server::read_content(Stream &strm, Request &req, Response &res) { })) { const auto &content_type = req.get_header_value("Content-Type"); if (!content_type.find("application/x-www-form-urlencoded")) { + if (req.body.size() > CPPHTTPLIB_REQUEST_URI_MAX_LENGTH) { + res.status = 413; // NOTE: should be 414? + return false; + } detail::parse_query_text(req.body, req.params); } return true; @@ -3117,7 +3196,7 @@ bool Server::read_content_core(Stream &strm, Request &req, Response &res, /* For debug size_t pos = 0; while (pos < n) { - auto read_size = std::min<size_t>(1, n - pos); + auto read_size = (std::min)<size_t>(1, n - pos); auto ret = multipart_form_data_parser.parse( buf + pos, read_size, multipart_receiver, mulitpart_header); if (!ret) { return false; } @@ -4136,7 +4215,12 @@ bool ClientImpl::write_request(Stream &strm, Request &req, return write_content_with_provider(strm, req, error); } - return detail::write_data(strm, req.body.data(), req.body.size()); + if (!detail::write_data(strm, req.body.data(), req.body.size())) { + error = Error::Write; + return false; + } + + return true; } std::unique_ptr<Response> ClientImpl::send_with_content_provider( @@ -5106,7 +5190,30 @@ ssize_t SSLSocketStream::read(char *ptr, size_t size) { } ssize_t SSLSocketStream::write(const char *ptr, size_t size) { - if (is_writable()) { return SSL_write(ssl_, ptr, static_cast<int>(size)); } + if (is_writable()) { + auto ret = SSL_write(ssl_, ptr, static_cast<int>(size)); + if (ret < 0) { + 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)) { +#else + while (--n >= 0 && err == SSL_ERROR_WANT_WRITE) { +#endif + if (is_writable()) { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + ret = SSL_write(ssl_, ptr, static_cast<int>(size)); + if (ret >= 0) { return ret; } + err = SSL_get_error(ssl_, ret); + } else { + return -1; + } + } + } + return ret; + } return -1; } @@ -5187,6 +5294,17 @@ SSLServer::SSLServer(X509 *cert, EVP_PKEY *private_key, } } +SSLServer::SSLServer( + const std::function<bool(SSL_CTX &ssl_ctx)> &setup_ssl_ctx_callback) { + ctx_ = SSL_CTX_new(TLS_method()); + if (ctx_) { + if (!setup_ssl_ctx_callback(*ctx_)) { + SSL_CTX_free(ctx_); + ctx_ = nullptr; + } + } +} + SSLServer::~SSLServer() { if (ctx_) { SSL_CTX_free(ctx_); } } diff --git a/src/third_party/httplib.h b/src/third_party/httplib.h index 543ee9af..6d69d084 100644 --- a/src/third_party/httplib.h +++ b/src/third_party/httplib.h @@ -259,7 +259,7 @@ namespace detail { template <class T, class... Args> typename std::enable_if<!std::is_array<T>::value, std::unique_ptr<T>>::type -make_unique(Args &&... args) { +make_unique(Args &&...args) { return std::unique_ptr<T>(new T(std::forward<Args>(args)...)); } @@ -492,7 +492,7 @@ public: virtual socket_t socket() const = 0; template <typename... Args> - ssize_t write_format(const char *fmt, const Args &... args); + ssize_t write_format(const char *fmt, const Args &...args); ssize_t write(const char *ptr); ssize_t write(const std::string &s); }; @@ -622,7 +622,7 @@ public: Server &Options(const std::string &pattern, Handler handler); bool set_base_dir(const std::string &dir, - const std::string &mount_point = nullptr); + const std::string &mount_point = std::string()); bool set_mount_point(const std::string &mount_point, const std::string &dir, Headers headers = Headers()); bool remove_mount_point(const std::string &mount_point); @@ -1161,6 +1161,8 @@ public: const std::string &client_cert_path, const std::string &client_key_path); + Client(Client &&) = default; + ~Client(); bool is_valid() const; @@ -1362,6 +1364,9 @@ public: SSLServer(X509 *cert, EVP_PKEY *private_key, X509_STORE *client_ca_cert_store = nullptr); + SSLServer( + const std::function<bool(SSL_CTX &ssl_ctx)> &setup_ssl_ctx_callback); + ~SSLServer() override; bool is_valid() const override; @@ -1473,7 +1478,7 @@ inline T Response::get_header_value(const char *key, size_t id) const { } template <typename... Args> -inline ssize_t Stream::write_format(const char *fmt, const Args &... args) { +inline ssize_t Stream::write_format(const char *fmt, const Args &...args) { const auto bufsiz = 2048; std::array<char, bufsiz> buf; @@ -1671,6 +1676,10 @@ bool parse_range_header(const std::string &s, Ranges &ranges); int close_socket(socket_t sock); +ssize_t send_socket(socket_t sock, const void *ptr, size_t size, int flags); + +ssize_t read_socket(socket_t sock, void *ptr, size_t size, int flags); + enum class EncodingType { None = 0, Gzip, Brotli }; EncodingType encoding_type(const Request &req, const Response &res); |