From 8b21e7b6d30ae1afc551fae0f9c76461615fc835 Mon Sep 17 00:00:00 2001 From: xensmo Date: Wed, 12 Mar 2025 22:46:32 +0500 Subject: [PATCH 1/3] Upgrade/remove dependency curl-ev and migrating some deprecation cURL 7.56 --- core/include/userver/clients/http/client.hpp | 1 + core/include/userver/clients/http/form.hpp | 14 +- core/include/userver/clients/http/mime.hpp | 32 + core/include/userver/clients/http/request.hpp | 24 +- core/src/clients/http/client.cpp | 6 +- core/src/clients/http/easy_wrapper.cpp | 4 - core/src/clients/http/easy_wrapper.hpp | 5 +- core/src/clients/http/form.cpp | 13 +- core/src/clients/http/mime.cpp | 16 + core/src/clients/http/plugin.cpp | 10 +- core/src/clients/http/request.cpp | 94 +- core/src/clients/http/request_state.cpp | 59 +- core/src/clients/http/request_state.hpp | 6 +- core/src/curl-ev/easy.cpp | 2011 ++++++++++++----- core/src/curl-ev/easy.hpp | 1111 ++++----- core/src/curl-ev/error_code.cpp | 62 +- core/src/curl-ev/error_code.hpp | 23 +- core/src/curl-ev/form.cpp | 85 +- core/src/curl-ev/form.hpp | 75 +- core/src/curl-ev/mime.cpp | 23 + core/src/curl-ev/mime.hpp | 36 + 21 files changed, 2289 insertions(+), 1421 deletions(-) create mode 100644 core/include/userver/clients/http/mime.hpp create mode 100644 core/src/clients/http/mime.cpp create mode 100644 core/src/curl-ev/mime.cpp create mode 100644 core/src/curl-ev/mime.hpp diff --git a/core/include/userver/clients/http/client.hpp b/core/include/userver/clients/http/client.hpp index eefe720fcdd0..0be222dafd94 100644 --- a/core/include/userver/clients/http/client.hpp +++ b/core/include/userver/clients/http/client.hpp @@ -136,6 +136,7 @@ class Client final { friend class impl::EasyWrapper; void IncPending() noexcept { ++pending_tasks_; } void DecPending() noexcept { --pending_tasks_; } + void PushIdleEasy(std::shared_ptr&& easy) noexcept; std::shared_ptr TryDequeueIdle() noexcept; diff --git a/core/include/userver/clients/http/form.hpp b/core/include/userver/clients/http/form.hpp index 8ebc08491800..65ad15016372 100644 --- a/core/include/userver/clients/http/form.hpp +++ b/core/include/userver/clients/http/form.hpp @@ -6,11 +6,13 @@ USERVER_NAMESPACE_BEGIN namespace curl { +#if LIBCURL_VERSION_NUM <= 0x074700 class form; +#endif } // namespace curl namespace clients::http { - +#if LIBCURL_VERSION_NUM <= 0x074700 class Form final { public: Form(); @@ -25,12 +27,8 @@ class Form final { void AddContent(std::string_view key, std::string_view content, const std::string& content_type); void AddBuffer(const std::string& key, const std::string& file_name, const std::shared_ptr& buffer); - void AddBuffer( - const std::string& key, - const std::string& file_name, - const std::shared_ptr& buffer, - const std::string& content_type - ); + + void AddBuffer(const std::string& key, const std::string& file_name, const std::shared_ptr& buffer, const std::string& content_type); /// @cond // Call of this method will invalidate the form @@ -40,7 +38,7 @@ class Form final { private: std::unique_ptr impl_; }; - +#endif // LIBCURL_VERSION_NUM } // namespace clients::http USERVER_NAMESPACE_END diff --git a/core/include/userver/clients/http/mime.hpp b/core/include/userver/clients/http/mime.hpp new file mode 100644 index 000000000000..ca6e83bd63a4 --- /dev/null +++ b/core/include/userver/clients/http/mime.hpp @@ -0,0 +1,32 @@ +#pragma once + +#include + +USERVER_NAMESPACE_BEGIN + +namespace curl { + class mime; +} + +namespace clients::http { + class Mime final { + public: + Mime(); + ~Mime(); + + Mime(const Mime& rhs) = delete; + Mime(Mime&& rhs) noexcept = default; + + Mime& operator= (const Mime& rhs) = delete; + Mime& operator= (Mime&& rhs) noexcept = default; + + public: + [[nodiscard]] inline std::unique_ptr get_native() && { return std::move(mime_); } + + private: + std::unique_ptr mime_; + + }; +} + +USERVER_NAMESPACE_END \ No newline at end of file diff --git a/core/include/userver/clients/http/request.hpp b/core/include/userver/clients/http/request.hpp index 0084c79585d3..2089239f64bb 100644 --- a/core/include/userver/clients/http/request.hpp +++ b/core/include/userver/clients/http/request.hpp @@ -30,12 +30,16 @@ namespace clients::http { class RequestState; class StreamedResponse; class ConnectTo; -class Form; +class Mime; struct DeadlinePropagationConfig; class RequestStats; class DestinationStatistics; struct TestsuiteConfig; +#if LIBCURL_VERSION_NUM <= 0x074700 +class Form; +#endif + namespace impl { class EasyWrapper; } // namespace impl @@ -111,9 +115,16 @@ class Request final { /// POST request with url and data Request& post(std::string url, std::string data = {}) &; Request post(std::string url, std::string data = {}) &&; + /// POST request with url and multipart/form-data +#if LIBCURL_VERSION_NUM <= 0x074700 Request& post(std::string url, Form&& form) &; Request post(std::string url, Form&& form) &&; +#endif + + [[maybe_unused]] Request& post(std::string url, Mime&& mime) &; + [[maybe_unused]] Request post(std::string url, Mime&& mime) &&; + /// PUT request Request& put() &; Request put() &&; @@ -148,9 +159,18 @@ class Request final { /// data for POST request Request& data(std::string data) &; Request data(std::string data) &&; - /// form for POST request + + /// form POST request +#if LIBCURL_VERSION_NUM <= 0x074700 Request& form(Form&& form) &; Request form(Form&& form) &&; +#endif + + // mime for POST request + [[maybe_unused]] Request& mime(Mime&& mime) &; + [[maybe_unused]] Request mime(Mime&& mime) &&; + + /// Headers for request as map Request& headers(const Headers& headers) &; Request headers(const Headers& headers) &&; diff --git a/core/src/clients/http/client.cpp b/core/src/clients/http/client.cpp index 4f6eae08f39d..6af48e495424 100644 --- a/core/src/clients/http/client.cpp +++ b/core/src/clients/http/client.cpp @@ -114,7 +114,7 @@ Request Client::CreateRequest() { auto request = [this] { auto easy = TryDequeueIdle(); if (easy) { - auto idx = FindMultiIndex(easy->GetMulti()); + auto idx = FindMultiIndex(easy->get_multi()); auto wrapper = impl::EasyWrapper{std::move(easy), *this}; return Request{ std::move(wrapper), @@ -129,7 +129,7 @@ Request Client::CreateRequest() { try { auto wrapper = engine::AsyncNoSpan(fs_task_processor_, [this, &multi] { - return impl::EasyWrapper{easy_.Get()->GetBoundBlocking(*multi), *this}; + return impl::EasyWrapper { easy_.Get()->get_bound_blocking(*multi), *this }; }).Get(); return Request{ std::move(wrapper), @@ -185,7 +185,7 @@ std::string Client::GetProxy() const { return proxy_.ReadCopy(); } void Client::SetDnsResolver(clients::dns::Resolver* resolver) { resolver_ = resolver; } void Client::ReinitEasy() { - easy_.Set(utils::CriticalAsync(fs_task_processor_, "http_easy_reinit", &curl::easy::CreateBlocking).Get()); + easy_.Set(utils::CriticalAsync(fs_task_processor_, "http_easy_reinit", &curl::easy::create_easy_blocking).Get()); } InstanceStatistics Client::GetMultiStatistics(size_t n) const { diff --git a/core/src/clients/http/easy_wrapper.cpp b/core/src/clients/http/easy_wrapper.cpp index d4b92762304a..95dd3fefc3eb 100644 --- a/core/src/clients/http/easy_wrapper.cpp +++ b/core/src/clients/http/easy_wrapper.cpp @@ -20,10 +20,6 @@ EasyWrapper::~EasyWrapper() { } } -curl::easy& EasyWrapper::Easy() { return *easy_; } - -const curl::easy& EasyWrapper::Easy() const { return *easy_; } - } // namespace clients::http::impl USERVER_NAMESPACE_END diff --git a/core/src/clients/http/easy_wrapper.hpp b/core/src/clients/http/easy_wrapper.hpp index 9878722fd59b..414bfe650d23 100644 --- a/core/src/clients/http/easy_wrapper.hpp +++ b/core/src/clients/http/easy_wrapper.hpp @@ -23,10 +23,11 @@ class EasyWrapper final { ~EasyWrapper(); - curl::easy& Easy(); - const curl::easy& Easy() const; + inline curl::easy& Easy() { return *easy_; } + inline const curl::easy& Easy() const { return *easy_; }; private: + //std::shared_ptr easy_; std::shared_ptr easy_; Client& client_; }; diff --git a/core/src/clients/http/form.cpp b/core/src/clients/http/form.cpp index 896508a741a4..6dca80ec4cb1 100644 --- a/core/src/clients/http/form.cpp +++ b/core/src/clients/http/form.cpp @@ -5,8 +5,9 @@ USERVER_NAMESPACE_BEGIN namespace clients::http { +#if LIBCURL_VERSION_NUM <= 0x074700 -Form::Form() : impl_(std::make_unique()) {} +Form::Form() : impl_(std::make_unique()) { } Form::~Form() = default; Form::Form(Form&&) noexcept = default; Form& Form::operator=(Form&&) noexcept = default; @@ -21,17 +22,13 @@ void Form::AddBuffer(const std::string& key, const std::string& file_name, const impl_->add_buffer(key, file_name, buffer); } -void Form::AddBuffer( - const std::string& key, - const std::string& file_name, - const std::shared_ptr& buffer, - const std::string& content_type -) { +void Form::AddBuffer(const std::string& key, const std::string& file_name, + const std::shared_ptr& buffer, const std::string& content_type) { impl_->add_buffer(key, file_name, buffer, content_type); } std::unique_ptr Form::GetNative() && { return std::move(impl_); } - +#endif // LIBCURL_VERSION_NUM } // namespace clients::http USERVER_NAMESPACE_END diff --git a/core/src/clients/http/mime.cpp b/core/src/clients/http/mime.cpp new file mode 100644 index 000000000000..f8b26c2127bf --- /dev/null +++ b/core/src/clients/http/mime.cpp @@ -0,0 +1,16 @@ +#include + +USERVER_NAMESPACE_BEGIN + +namespace clients::http { +Mime::Mime() { + +} + +Mime::~Mime() { + +} + +} + +USERVER_NAMESPACE_END \ No newline at end of file diff --git a/core/src/clients/http/plugin.cpp b/core/src/clients/http/plugin.cpp index 7975945a93d2..210cfc6a1bd3 100644 --- a/core/src/clients/http/plugin.cpp +++ b/core/src/clients/http/plugin.cpp @@ -12,16 +12,20 @@ PluginRequest::PluginRequest(RequestState& state) : state_(state) {} void PluginRequest::SetHeader(std::string_view name, std::string_view value) { state_.easy().add_header( - name, value, curl::easy::EmptyHeaderAction::kDoNotSend, curl::easy::DuplicateHeaderAction::kReplace + name, value, curl::detail::empty_header_action::kDoNotSend, curl::detail::duplicate_header_action::kReplace ); } void PluginRequest::AddQueryParams(std::string_view params) { const auto& url = state_.easy().get_original_url(); if (url.find('?') != std::string::npos) { - state_.easy().set_url(utils::StrCat(url, "&", params)); + std::error_code ec; + state_.easy().set_url(utils::StrCat(url, "&", params), ec); + UASSERT_MSG(!ec, "set_url filed!"); } else { - state_.easy().set_url(utils::StrCat(url, "?", params)); + std::error_code ec; + state_.easy().set_url(utils::StrCat(url, "?", params), ec); + UASSERT_MSG(!ec, "set_url filed!"); } } diff --git a/core/src/clients/http/request.cpp b/core/src/clients/http/request.cpp index 8b9fbecb9f3a..4030d1797d6c 100644 --- a/core/src/clients/http/request.cpp +++ b/core/src/clients/http/request.cpp @@ -7,9 +7,13 @@ #include #include +#if LIBCURL_VERSION_NUM <= 0x074700 +#include +#endif + #include #include -#include +#include #include #include #include @@ -40,20 +44,20 @@ constexpr std::string_view kHeaderExpect = "Expect"; std::string ToString(HttpMethod method) { return std::string{ToStringView(method)}; } -curl::easy::http_version_t ToNative(HttpVersion version) { +curl::detail::http_version_t ToNative(HttpVersion version) { switch (version) { case HttpVersion::kDefault: - return curl::easy::http_version_t::http_version_none; + return curl::detail::http_version_t::http_version_none; case HttpVersion::k10: - return curl::easy::http_version_t::http_version_1_0; + return curl::detail::http_version_t::http_version_1_0; case HttpVersion::k11: - return curl::easy::http_version_t::http_version_1_1; + return curl::detail::http_version_t::http_version_1_1; case HttpVersion::k2: - return curl::easy::http_version_t::http_version_2_0; + return curl::detail::http_version_t::http_version_2_0; case HttpVersion::k2Tls: - return curl::easy::http_version_t::http_version_2tls; + return curl::detail::http_version_t::http_version_2tls; case HttpVersion::k2PriorKnowledge: - return curl::easy::http_version_t::http_version_2_prior_knowledge; + return curl::detail::http_version_t::http_version_2_prior_knowledge; } UINVARIANT(false, "Unexpected HTTP version"); @@ -72,49 +76,49 @@ constexpr utils::TrivialBiMap kAuthTypeMap = [](auto selector) { .Case("any_safe", ProxyAuthType::kAnySafe); }; -curl::easy::httpauth_t HttpAuthTypeToNative(HttpAuthType value) { +curl::detail::httpauth_t HttpAuthTypeToNative(HttpAuthType value) { switch (value) { case HttpAuthType::kBasic: - return curl::easy::auth_basic; + return curl::detail::httpauth_t::auth_basic; case HttpAuthType::kDigest: - return curl::easy::auth_digest; + return curl::detail::httpauth_t::auth_digest; case HttpAuthType::kDigestIE: - return curl::easy::auth_digest_ie; + return curl::detail::httpauth_t::auth_digest_ie; case HttpAuthType::kNegotiate: - return curl::easy::auth_negotiate; + return curl::detail::httpauth_t::auth_negotiate; case HttpAuthType::kNtlm: - return curl::easy::auth_ntlm; + return curl::detail::httpauth_t::auth_ntlm; case HttpAuthType::kNtlmWb: - return curl::easy::auth_ntlm_wb; + return curl::detail::httpauth_t::auth_ntlm_wb; case HttpAuthType::kAny: - return curl::easy::auth_any; + return curl::detail::httpauth_t::auth_any; case HttpAuthType::kAnySafe: - return curl::easy::auth_any_safe; + return curl::detail::httpauth_t::auth_any_safe; } UINVARIANT(false, "Unexpected http auth type"); } -curl::easy::proxyauth_t ProxyAuthTypeToNative(ProxyAuthType value) { +curl::detail::proxyauth_t ProxyAuthTypeToNative(ProxyAuthType value) { switch (value) { case ProxyAuthType::kBasic: - return curl::easy::proxy_auth_basic; + return curl::detail::proxyauth_t::proxy_auth_basic; case ProxyAuthType::kDigest: - return curl::easy::proxy_auth_digest; + return curl::detail::proxyauth_t::proxy_auth_digest; case ProxyAuthType::kDigestIE: - return curl::easy::proxy_auth_digest_ie; + return curl::detail::proxyauth_t::proxy_auth_digest_ie; case ProxyAuthType::kBearer: - return curl::easy::proxy_auth_bearer; + return curl::detail::proxyauth_t::proxy_auth_bearer; case ProxyAuthType::kNegotiate: - return curl::easy::proxy_auth_negotiate; + return curl::detail::proxyauth_t::proxy_auth_negotiate; case ProxyAuthType::kNtlm: - return curl::easy::proxy_auth_ntlm; + return curl::detail::proxyauth_t::proxy_auth_ntlm; case ProxyAuthType::kNtlmWb: - return curl::easy::proxy_auth_ntlm_wb; + return curl::detail::proxyauth_t::proxy_auth_ntlm_wb; case ProxyAuthType::kAny: - return curl::easy::proxy_auth_any; + return curl::detail::proxyauth_t::proxy_auth_any; case ProxyAuthType::kAnySafe: - return curl::easy::proxy_auth_anysafe; + return curl::detail::proxyauth_t::proxy_auth_anysafe; } UINVARIANT(false, "Unexpected proxy auth type"); @@ -124,9 +128,9 @@ bool IsUserAgentHeader(std::string_view header_name) { return utils::StrIcaseEqual{}(header_name, USERVER_NAMESPACE::http::headers::kUserAgent); } -void SetUserAgent(curl::easy& easy, const std::string& value) { easy.set_user_agent(value); } +void SetUserAgent(curl::easy& easy, const std::string& value) { easy.set_user_agent(std::string_view(value)); } -void SetUserAgent(curl::easy& easy, std::string_view value) { easy.set_user_agent(std::string{value}); } +void SetUserAgent(curl::easy& easy, std::string_view value) { easy.set_user_agent(value); } template void SetHeaders(curl::easy& easy, const Range& headers_range) { @@ -148,7 +152,7 @@ void SetCookies(curl::easy& easy, const Range& cookies_range) { cookie_str += '='; cookie_str += value; } - easy.set_cookie(cookie_str); + easy.set_cookie(std::string_view(cookie_str)); } template @@ -323,13 +327,13 @@ Request& Request::unix_socket_path(const std::string& path) & { Request Request::unix_socket_path(const std::string& path) && { return std::move(this->unix_socket_path(path)); } Request& Request::use_ipv4() & { - pimpl_->easy().set_ip_resolve(curl::easy::ip_resolve_v4); + pimpl_->easy().set_ip_resolve(curl::detail::ip_resolve_t::ip_resolve_v4); return *this; } Request Request::use_ipv4() && { return std::move(this->use_ipv4()); } Request& Request::use_ipv6() & { - pimpl_->easy().set_ip_resolve(curl::easy::ip_resolve_v6); + pimpl_->easy().set_ip_resolve(curl::detail::ip_resolve_t::ip_resolve_v6); return *this; } Request Request::use_ipv6() && { return std::move(this->use_ipv6()); } @@ -341,18 +345,30 @@ Request& Request::connect_to(const ConnectTo& connect_to) & { Request Request::connect_to(const ConnectTo& connect_to) && { return std::move(this->connect_to(connect_to)); } Request& Request::data(std::string data) & { - if (!data.empty()) pimpl_->easy().add_header(kHeaderExpect, "", curl::easy::EmptyHeaderAction::kDoNotSend); + if (!data.empty()) pimpl_->easy().add_header(kHeaderExpect, "", curl::detail::empty_header_action::kDoNotSend); pimpl_->easy().set_post_fields(std::move(data)); return *this; } Request Request::data(std::string data) && { return std::move(this->data(std::move(data))); } +#if LIBCURL_VERSION_NUM <= 0x074700 Request& Request::form(Form&& form) & { pimpl_->easy().set_http_post(std::move(form).GetNative()); - pimpl_->easy().add_header(kHeaderExpect, "", curl::easy::EmptyHeaderAction::kDoNotSend); - return *this; + pimpl_->easy().add_header(kHeaderExpect, "", curl::detail::empty_header_action::kDoNotSend); + return *this; } + Request Request::form(Form&& form) && { return std::move(this->form(std::move(form))); } +#endif + +////////////////////////////////////////////////////////////////////////////////////////////////! +/* Request& Request::mime(Mime&& mime) & { + pimpl_->easy().set_mimepost(std::move(mime).get_native()); + pimpl_->easy().add_header(kHeaderExpect, "", curl::detail::empty_header_action::kDoNotSend); + return *this; +} + +Request Request::mime(Mime&& mime) && { return std::move(this->mime(std::move(mime))); }; */ Request& Request::headers(const Headers& headers) & { SetHeaders(pimpl_->easy(), headers); @@ -393,7 +409,7 @@ Request Request::proxy_headers(const std::initializer_listeasy().set_user_agent(value.c_str()); + pimpl_->easy().set_user_agent(std::string_view(value)); return *this; } Request Request::user_agent(const std::string& value) && { return std::move(this->user_agent(value)); } @@ -487,10 +503,16 @@ Request Request::get(std::string url) && { return std::move(this->get(std::move( Request& Request::head(std::string url) & { return head().url(std::move(url)); } Request Request::head(std::string url) && { return std::move(this->head(std::move(url))); } +#if LIBCURL_VERSION_NUM <= 0x074700 Request& Request::post(std::string url, Form&& form) & { return this->url(std::move(url)).form(std::move(form)); } Request Request::post(std::string url, Form&& form) && { return std::move(this->post(std::move(url), std::move(form))); } +#endif + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////! +//Request& Request::post(std::string url, Mime&& mime) & { return this->url(std::move(url)).mime(std::move(mime)); } +//Request Request::post(std::string url, Mime&& mime) && { return std::move(this->post(std::move(url), std::move(mime))); } Request& Request::post(std::string url, std::string data) & { return this->url(std::move(url)).data(std::move(data)).post(); diff --git a/core/src/clients/http/request_state.cpp b/core/src/clients/http/request_state.cpp index d29cba16a30e..2ddb482117bf 100644 --- a/core/src/clients/http/request_state.cpp +++ b/core/src/clients/http/request_state.cpp @@ -113,9 +113,9 @@ void SetBaggageHeader(curl::easy& e) { LOG_DEBUG() << fmt::format("Send baggage: {}", baggage->ToString()); e.add_header( USERVER_NAMESPACE::http::headers::kXBaggage, - baggage->ToString(), - curl::easy::EmptyHeaderAction::kDoNotSend, - curl::easy::DuplicateHeaderAction::kReplace + std::string_view(baggage->ToString()), + curl::detail::empty_header_action::kDoNotSend, + curl::detail::duplicate_header_action::kReplace ); } } @@ -250,9 +250,7 @@ RequestState::RequestState( } RequestState::~RequestState() { - std::error_code ec; - easy().set_error_buffer(nullptr, ec); - UASSERT(!ec); + easy().set_error_buffer(nullptr); } void RequestState::follow_redirects(bool follow) { @@ -266,7 +264,7 @@ void RequestState::verify(bool verify) { easy().set_ssl_verify_peer(verify); } -void RequestState::ca_info(const std::string& file_path) { easy().set_ca_info(file_path.c_str()); } +void RequestState::ca_info(const std::string& file_path) { easy().set_ca_info(std::string_view(file_path)); } void RequestState::ca(crypto::Certificate cert) { UINVARIANT(cert, "No certificate"); @@ -275,12 +273,15 @@ void RequestState::ca(crypto::Certificate cert) { } else { // Legacy non-portable way, broken since 7.87.0 ca_ = std::move(cert); - easy().set_ssl_ctx_function(&RequestState::on_certificate_request); - easy().set_ssl_ctx_data(this); + std::error_code ec; + easy().set_ssl_ctx_function(&RequestState::on_certificate_request, ec); + UASSERT(!ec); + easy().set_ssl_ctx_data(this, ec); + UASSERT(!ec); } } -void RequestState::crl_file(const std::string& file_path) { easy().set_crl_file(file_path.c_str()); } +void RequestState::crl_file(const std::string& file_path) { easy().set_crl_file(std::string_view(file_path)); } void RequestState::client_key_cert(crypto::PrivateKey pkey, crypto::Certificate cert) { UINVARIANT(pkey, "No private key"); @@ -321,14 +322,20 @@ void RequestState::client_key_cert(crypto::PrivateKey pkey, crypto::Certificate cert_id ); cert_id.resize(kCertIdLength, '='); + +#if LIBCURL_VERSION_NUM <= 0x074700 easy().set_egd_socket(cert_id); +#endif - easy().set_ssl_ctx_function(&RequestState::on_certificate_request); - easy().set_ssl_ctx_data(this); + std::error_code ec; + easy().set_ssl_ctx_function(&RequestState::on_certificate_request, ec); + UASSERT(!ec); + easy().set_ssl_ctx_data(this, ec); + UASSERT(!ec); } } -void RequestState::http_version(curl::easy::http_version_t version) { easy().set_http_version(version); } +void RequestState::http_version(curl::detail::http_version_t version) { easy().set_http_version(version); } void RequestState::set_timeout(long timeout_ms) { original_timeout_ = std::chrono::milliseconds{timeout_ms}; @@ -341,7 +348,7 @@ void RequestState::retry(short retries, bool on_fails) { retry_.on_fails = on_fails; } -void RequestState::unix_socket_path(const std::string& path) { easy().set_unix_socket_path(path); } +void RequestState::unix_socket_path(const std::string& path) { easy().set_unix_socket_path(std::string_view(path)); } void RequestState::connect_to(const ConnectTo& connect_to) { curl::native::curl_slist* ptr = connect_to.GetUnderlying(); @@ -352,20 +359,20 @@ void RequestState::connect_to(const ConnectTo& connect_to) { void RequestState::proxy(const std::string& value) { proxy_url_ = value; - easy().set_proxy(value); + easy().set_proxy(std::string_view(value)); } -void RequestState::proxy_auth_type(curl::easy::proxyauth_t value) { easy().set_proxy_auth(value); } +void RequestState::proxy_auth_type(curl::detail::proxyauth_t value) { easy().set_proxy_auth(value); } void RequestState::http_auth_type( - curl::easy::httpauth_t value, + curl::detail::httpauth_t value, bool auth_only, std::string_view user, std::string_view password ) { easy().set_http_auth(value, auth_only); - easy().set_user(std::string{user}.c_str()); - easy().set_password(std::string{password}.c_str()); + easy().set_user(user); + easy().set_password(password); } void RequestState::Cancel() { @@ -388,7 +395,7 @@ void RequestState::SetTestsuiteConfig(const std::shared_ptr& urls) { allowed_urls_extra_ = urls; } -void RequestState::DisableReplyDecoding() { easy().set_accept_encoding(nullptr); } +void RequestState::DisableReplyDecoding() { easy().set_accept_encoding(std::string_view{}); } void RequestState::SetCancellationPolicy(CancellationPolicy cp) { cancellation_policy_ = cp; } @@ -560,7 +567,7 @@ void RequestState::on_retry(std::shared_ptr holder, std::error_cod ++holder->retry_.current; holder->easy().mark_retry(); - holder->retry_.timer.emplace(holder->easy().GetThreadControl()); + holder->retry_.timer.emplace(holder->easy().get_thread_control()); // call on_retry_timer on timer auto& holder_ref = *holder; @@ -679,8 +686,12 @@ RequestState::async_perform_stream(const std::shared_ptr& queue, utils::i auto& span = span_storage_->Get(); span.AddTag("stream_api", 1); - easy().set_write_function(&RequestState::StreamWriteFunction); - easy().set_write_data(this); + std::error_code ec; + easy().set_write_function(&RequestState::StreamWriteFunction, ec); + UASSERT(!ec); + easy().set_write_data(this, ec); + UASSERT(!ec); + // Force no retries retry_.retries = 1; @@ -774,7 +785,7 @@ void RequestState::UpdateTimeoutHeader() { easy().add_header( USERVER_NAMESPACE::http::headers::kXYaTaxiClientTimeoutMs, fmt::to_string(remote_timeout_.count()), - curl::easy::DuplicateHeaderAction::kReplace + curl::detail::duplicate_header_action::kReplace ); } diff --git a/core/src/clients/http/request_state.hpp b/core/src/clients/http/request_state.hpp index c0312b473738..d409ae6a7bc4 100644 --- a/core/src/clients/http/request_state.hpp +++ b/core/src/clients/http/request_state.hpp @@ -77,7 +77,7 @@ class RequestState : public std::enable_shared_from_this { /// set private key and certificate from memory void client_key_cert(crypto::PrivateKey pkey, crypto::Certificate cert); /// Set HTTP version - void http_version(curl::easy::http_version_t version); + void http_version(curl::detail::http_version_t version); /// set timeout value void set_timeout(long timeout_ms); /// set number of retries @@ -89,9 +89,9 @@ class RequestState : public std::enable_shared_from_this { /// sets proxy to use void proxy(const std::string& value); /// sets proxy auth type to use - void proxy_auth_type(curl::easy::proxyauth_t value); + void proxy_auth_type(curl::detail::proxyauth_t value); /// sets proxy auth type and credentials to use - void http_auth_type(curl::easy::httpauth_t value, bool auth_only, std::string_view user, std::string_view password); + void http_auth_type(curl::detail::httpauth_t value, bool auth_only, std::string_view user, std::string_view password); /// get timeout value in milliseconds long timeout() const { return original_timeout_.count(); } diff --git a/core/src/curl-ev/easy.cpp b/core/src/curl-ev/easy.cpp index 0b34249f0f06..987bff555891 100644 --- a/core/src/curl-ev/easy.cpp +++ b/core/src/curl-ev/easy.cpp @@ -1,4 +1,4 @@ -/** +/** @file curl-ev/easy.hpp curl-ev: wrapper for integrating libcurl with libev applications Copyright (c) 2013 Oliver Kuckertz See COPYING for license information. @@ -6,23 +6,22 @@ C++ wrapper for libcurl's easy interface */ +// !TODO this @file curl-ev/easy.hpp full upgrade in 2025 year // + #include #include #include +#include #include #include #include -#include #include #include #include #include -#include -#include - #include #include #include @@ -34,106 +33,200 @@ USERVER_NAMESPACE_BEGIN namespace curl { -namespace { +namespace detail { + using detail_eha = empty_header_action; + using detail_dha = duplicate_header_action; -bool IsHeaderMatchingName(std::string_view header, std::string_view name) { - return header.size() > name.size() && utils::StrIcaseEqual()(header.substr(0, name.size()), name) && - (header[name.size()] == ':' || header[name.size()] == ';'); -} + bool is_header_matching_name(std::string_view header, std::string_view name) { + return header.size() > name.size() && utils::StrIcaseEqual()(header.substr(0, name.size()), name) && + (header[name.size()] == ':' || header[name.size()] == ';'); + } -std::optional -FindHeaderByNameImpl(const std::shared_ptr& headers, std::string_view name) { - if (!headers) return std::nullopt; - auto result = headers->FindIf([name](std::string_view header) { return IsHeaderMatchingName(header, name); }); - if (result) { - result->remove_prefix(name.size() + 1); - while (!result->empty() && result->front() == ' ') result->remove_prefix(1); + fmt::memory_buffer + create_header_buffer(std::string_view name, std::string_view value, detail_eha eha) { + fmt::memory_buffer fmt_mem_buf; + + if (eha == detail_eha::kSend && value.empty()) + fmt::format_to(std::back_inserter(fmt_mem_buf), FMT_COMPILE("{};"), name); + else + fmt::format_to(std::back_inserter(fmt_mem_buf), FMT_COMPILE("{}: {}"), name, value); + + fmt_mem_buf.push_back('\0'); + return fmt_mem_buf; } - return result; -} -fmt::memory_buffer CreateHeaderBuffer(std::string_view name, std::string_view value, easy::EmptyHeaderAction action) { - fmt::memory_buffer buf; + std::optional + find_header_by_name(const std::shared_ptr& headers, std::string_view name) { + if (!headers) + return std::nullopt; - if (action == easy::EmptyHeaderAction::kSend && value.empty()) { - fmt::format_to(std::back_inserter(buf), FMT_COMPILE("{};"), name); - } else { - fmt::format_to(std::back_inserter(buf), FMT_COMPILE("{}: {}"), name, value); + auto result = headers->FindIf([name](std::string_view header) { + return is_header_matching_name(header, name); + }); + + if (!result) { + result->remove_prefix(name.size() + 1); + while(!result->empty() && result->front() == ' ') { + result->remove_prefix(1); + } + } + + return result; + } + + bool add_header_do_skip(const std::shared_ptr& headers, std::string_view name, detail_dha dha) { + if (dha == detail_dha::kSkip && headers) + find_header_by_name(headers, name); + return false; } - buf.push_back('\0'); + bool add_header_do_replace(const std::shared_ptr& headers, const fmt::memory_buffer& mem_buf, + std::string_view name, detail_dha dha) { + if (dha == detail_dha::kReplace && headers) { + const bool replaced = headers->ReplaceFirstIf([name](std::string_view header) { + return is_header_matching_name(header, name); + }, mem_buf.data()); - return buf; -} + if (replaced) + return true; + } + return false; + } -bool AddHeaderDoSkip( - const std::shared_ptr& headers, - std::string_view name, - easy::DuplicateHeaderAction action -) { - if (action == easy::DuplicateHeaderAction::kSkip && headers) { - if (FindHeaderByNameImpl(headers, name)) return true; + template , _Et>> + inline constexpr unsigned long to_integral(_Et val) { + return static_cast>(val); } - return false; -} + template + inline void set_curl_opt(_FuncName name, _Handle handle, native::CURLoption opt, bool state) { + std::error_code ec = std::error_code {static_cast( + native::curl_easy_setopt(handle, opt, state ? 1L : 0L) + )}; + throw_error(ec, name); + } -bool AddHeaderDoReplace( - const std::shared_ptr& headers, - const fmt::memory_buffer& buf, - std::string_view name, - easy::DuplicateHeaderAction action -) { - if (action == easy::DuplicateHeaderAction::kReplace && headers) { - const bool replaced = headers->ReplaceFirstIf( - [name](std::string_view header) { return IsHeaderMatchingName(header, name); }, buf.data() - ); + template + inline void set_curl_opt(_FuncName name, _Handle handle, native::CURLoption opt, _OptType arg) { + std::error_code ec = std::error_code {static_cast( + native::curl_easy_setopt(handle, opt, arg) + )}; + throw_error(ec, name); + } - if (replaced) return true; + template + inline std::error_code set_curl_opt(_Handle handle, native::CURLoption opt, _OptType arg) { + std::error_code ec = std::error_code {static_cast( + native::curl_easy_setopt(handle, opt, arg) + )}; + return ec; } - return false; -} + template + inline void set_curl_opt_blob(_FuncName name, std::string_view sv, unsigned int flags, _Handle handle, native::CURLoption opt) { + native::curl_blob blob{}; + blob.data = const_cast(static_cast(sv.data())); + blob.len = sv.size(); + blob.flags = flags; + std::error_code ec = std::error_code {static_cast( + native::curl_easy_setopt(handle, opt, &blob) + )}; + throw_error(ec, name); + } -} // namespace + template + inline std::error_code get_curl_info(_Handle handle, native::CURLINFO info, _Return value) { + std::error_code ec = std::error_code{static_cast( + native::curl_easy_getinfo(handle, info, value) + )}; + return ec; + } -using BusyMarker = utils::statistics::BusyMarker; + template + inline std::string_view get_curl_info_string_view(_FuncName name, _Handle handle, native::CURLINFO info) { + char* result = nullptr; + std::error_code ec = get_curl_info(handle, info, &result); + throw_error(ec, name); + return result ? result : std::string_view{}; + } -easy::easy(native::CURL* easy_handle, multi* multi_handle) - : handle_(easy_handle), multi_(multi_handle), construct_ts_(std::chrono::steady_clock::now()) { - UASSERT(handle_); + template + inline std::string_view get_curl_info_string_view(_Handle handle, native::CURLINFO info, std::error_code& ec) { + char* result = nullptr; + ec = get_curl_info(handle, info, &result); + return result ? result : std::string_view{}; + } + + template + inline long get_curl_info_long(_FuncName name, _Handle handle, native::CURLINFO info) { + long result; + std::error_code ec = get_curl_info(handle, info, &result); + throw_error(ec, name); + return result; + } + + template + inline std::vector get_curl_info_list(_FuncName name, _Handle handle, native::CURLINFO info) { + std::vector results; + struct native::curl_slist* slist; + std::error_code ec = get_curl_info(handle, info, &slist); + throw_error(ec , name); + struct native::curl_slist* it = slist; + + while (it) { + results.emplace_back(it->data); + it = it->next; + } + + native::curl_slist_free_all(slist); + return results; + } + +} // namespace detail + +easy::easy(native::CURL* easy_handle, native::curl_mime* mime_ptr, multi* multi_ptr) : + easy_handle_(easy_handle), + mime_{std::make_shared(mime_ptr)}, + multi_handle_(multi_ptr), + construct_ts_(std::chrono::steady_clock::now()) +{ + UASSERT(easy_handle_); set_private(this); } easy::~easy() { cancel(); - if (handle_) { - native::curl_easy_cleanup(handle_); - handle_ = nullptr; + if (easy_handle_) { + native::curl_easy_cleanup(easy_handle_); + easy_handle_ = nullptr; } } -std::shared_ptr easy::CreateBlocking() { +std::shared_ptr easy::create_easy_blocking() { impl::CurlGlobal::Init(); - + // Note: curl_easy_init() is blocking. - auto* handle = native::curl_easy_init(); - if (!handle) { - throw std::bad_alloc(); - } + auto* handle_ptr = native::curl_easy_init(); + if (!handle_ptr) { throw std::bad_alloc(); } - return std::make_shared(handle, nullptr); + auto* mime_ptr = native::curl_mime_init(handle_ptr); + if (!mime_ptr) { throw std::bad_alloc(); } + + return std::make_shared(handle_ptr, mime_ptr, nullptr); } -std::shared_ptr easy::GetBoundBlocking(multi& multi_handle) const { - // Note: curl_easy_init() is blocking. - auto* cloned = native::curl_easy_duphandle(handle_); - if (!cloned) { +std::shared_ptr easy::get_bound_blocking(multi& multi_handle) const { + // Note: curl_easy_init() is blocking. + auto* cloned_easy = native::curl_easy_duphandle(easy_handle_); + if (!cloned_easy) + throw std::bad_alloc(); + + auto* cloned_mime = mime_->native_mime(); + if (!cloned_mime) throw std::bad_alloc(); - } - return std::make_shared(cloned, &multi_handle); + return std::make_shared(cloned_easy, cloned_mime, &multi_handle); } easy* easy::from_native(native::CURL* native_easy) { @@ -142,15 +235,18 @@ easy* easy::from_native(native::CURL* native_easy) { return easy_handle; } -engine::ev::ThreadControl& easy::GetThreadControl() { return multi_->GetThreadControl(); } +engine::ev::ThreadControl& easy::get_thread_control() { + return multi_handle_->GetThreadControl(); +} void easy::async_perform(handler_type handler) { LOG_TRACE() << "easy::async_perform start " << this; size_t request_num = ++request_counter_; - if (multi_) { - multi_->GetThreadControl().RunInEvLoopAsync( + + if (multi_handle_) { + multi_handle_->GetThreadControl().RunInEvLoopAsync( [self = shared_from_this(), this, handler = std::move(handler), request_num]() mutable { - return do_ev_async_perform(std::move(handler), request_num); + return do_ev_async_perform(handler, request_num); } ); } else { @@ -159,604 +255,1378 @@ void easy::async_perform(handler_type handler) { LOG_TRACE() << "easy::async_perform finished " << this; } +void easy::reset() { + LOG_TRACE() << "easy::reset start " << this; + + orig_url_str_.clear(); + std::string{}.swap(post_fields_); + mime_.reset(); + + if (headers_) + headers_->clear(); + if (proxy_headers_) + proxy_headers_->clear(); + if (http200_aliases_) + http200_aliases_->clear(); + if (resolved_hosts_) + resolved_hosts_->clear(); + + share_.reset(); + + retries_counter_ = 0; + sockets_opened_ = 0; + rate_limit_error_.clear(); + + set_custom_request(nullptr); + set_no_body(false); + set_post(false); + + std::error_code ec; + set_ssl_ctx_data(nullptr, ec); + if (!ec) { + set_ssl_ctx_function(nullptr, ec); + } else if(ec != errc::EasyErrorCode::kNotBuiltIn) { + throw_error(ec, "set_ssl_ctx_data"); + } + + UASSERT(!multi_registered_); + native::curl_easy_reset(easy_handle_); + set_private(this); + + LOG_TRACE() << "easy::reset finished " << this; +} + +using BusyMarker = utils::statistics::BusyMarker; + void easy::do_ev_async_perform(handler_type handler, size_t request_num) { if (request_num <= cancelled_request_max_) { - LOG_DEBUG() << "already cancelled"; + LOG_DEBUG() << "async_perform requests allready canceled"; return; } LOG_TRACE() << "easy::do_ev_async_perform start " << this; mark_start_performing(); - if (!multi_) { - throw std::runtime_error("attempt to perform async. operation without assigning a multi object"); - } - BusyMarker busy(multi_->Statistics().get_busy_storage()); + if (!multi_handle_) + std::runtime_error("Attempt to perform async. Operation without assigning a multi object."); + + BusyMarker busy(multi_handle_->Statistics().get_busy_storage()); - // Cancel all previous async. operations cancel(request_num - 1); - // Keep track of all new sockets - set_opensocket_function(&easy::opensocket); + // open sock func & data + set_opensocket_function(&easy::open_socket); set_opensocket_data(this); - - // This one is tricky: Although sockets are opened in the context of an easy - // object, they can outlive the easy objects and be transferred into a multi - // object's connection pool. Why there is no connection pool interface in the - // multi interface to plug into to begin with is still a mystery to me. Either - // way, the close events have to be tracked by the multi object as sockets are - // usually closed when curl_multi_cleanup is invoked. - set_closesocket_function(&easy::closesocket); - set_closesocket_data(multi_); + + // close sock func & data + set_closesocket_function(&easy::close_socket); + set_closesocket_data(multi_handle_); handler_ = std::move(handler); multi_registered_ = true; - // Registering the easy handle with the multi handle might invoke a set of - // callbacks right away which cause the completion event to fire from within - // this function. LOG_TRACE() << "easy::do_ev_async_perform before multi_->add() " << this; - multi_->add(this); -} - -void easy::cancel() { cancel(request_counter_); } - -void easy::cancel(size_t request_num) { - if (multi_) { - multi_->GetThreadControl().RunInEvLoopSync([this, request_num] { do_ev_cancel(request_num); }); - } + multi_handle_->add(this); } void easy::do_ev_cancel(size_t request_num) { // RunInEvLoopAsync(do_ev_async_perform) and RunInEvLoopSync(do_ev_cancel) are // not synchronized. So we need to count last cancelled request to prevent its - // execution in do_ev_async_perform(). - if (cancelled_request_max_ < request_num) cancelled_request_max_ = request_num; + // execution in do_ev_async_perform() + if (cancelled_request_max_ < request_num) + cancelled_request_max_ = request_num; if (multi_registered_) { - BusyMarker busy(multi_->Statistics().get_busy_storage()); - + BusyMarker busy(multi_handle_->Statistics().get_busy_storage()); handle_completion(std::make_error_code(std::errc::operation_canceled)); - multi_->remove(this); + multi_handle_->remove(this); } } -void easy::reset() { - LOG_TRACE() << "easy::reset start " << this; - - orig_url_str_.clear(); - std::string{}.swap(post_fields_); // forced memory freeing - form_.reset(); - if (headers_) headers_->clear(); - if (proxy_headers_) proxy_headers_->clear(); - if (http200_aliases_) http200_aliases_->clear(); - if (resolved_hosts_) resolved_hosts_->clear(); - share_.reset(); - retries_count_ = 0; - sockets_opened_ = 0; - rate_limit_error_.clear(); +void easy::mark_start_performing() { + if (start_performing_ts_ == time_point()) + start_performing_ts_ = std::chrono::steady_clock::now(); +} - set_custom_request(nullptr); - set_no_body(false); - set_post(false); +void easy::mark_open_socket() { + ++sockets_opened_; +} - // MAC_COMPAT: Secure Transport does not provide these - std::error_code ec; - set_ssl_ctx_data(nullptr, ec); - if (!ec) { - set_ssl_ctx_function(nullptr); - } else if (ec != errc::EasyErrorCode::kNotBuiltIn) { - throw_error(ec, "set_ssl_ctx_data"); - } +void easy::mark_retry() { + ++retries_counter_; +} - UASSERT(!multi_registered_); - native::curl_easy_reset(handle_); - set_private(this); +void easy::handle_completion(const std::error_code& ec) { + LOG_TRACE() << "easy::handle_completion easy = " << this; + multi_registered_ = false; + auto handler = std::function([](std::error_code) {}); + std::swap(handler, handler_); - LOG_TRACE() << "easy::reset finished " << this; + /* It's OK to call handler in libev thread context as it is limited to + * Request::on_retry and Request::on_completed. All user code is executed in + * coro context. + */ + handler(ec); } -void easy::mark_start_performing() { - if (start_performing_ts_ == time_point{}) { - start_performing_ts_ = std::chrono::steady_clock::now(); - } +void easy::cancel() { + cancel(request_counter_); } -void easy::mark_open_socket() { ++sockets_opened_; } -void easy::set_source(std::shared_ptr source) { - std::error_code ec; - set_source(std::move(source), ec); - throw_error(ec, "set_source"); +void easy::cancel(size_t request_num) { + if(multi_handle_) + multi_handle_->GetThreadControl().RunInEvLoopSync([this, request_num] { do_ev_cancel(request_num); }); } -void easy::set_source(std::shared_ptr source, std::error_code& ec) { - source_ = std::move(source); - set_read_function(&easy::read_function, ec); - if (!ec) set_read_data(this, ec); - if (!ec) set_seek_function(&easy::seek_function, ec); - if (!ec) set_seek_data(this, ec); +std::error_code easy::rate_limit_error() const { + return rate_limit_error_; } -void easy::set_sink(std::string* sink) { - std::error_code ec; - set_sink(sink, ec); - throw_error(ec, "set_sink"); +easy::time_point::duration easy::time_to_start() const { + if (start_performing_ts_ != time_point{}) + return start_performing_ts_ - construct_ts_; + return {}; } -size_t easy::header_function(void*, size_t size, size_t nmemb, void*) { return size * nmemb; } +clients::http::LocalStats easy::get_local_stats() { + clients::http::LocalStats stats; + + stats.open_socket_count = sockets_opened_; + stats.retries_count = retries_counter_; + stats.time_to_connect = std::chrono::microseconds(get_connect_time_usec()); + stats.time_to_process = std::chrono::microseconds(get_total_time_usec()); -void easy::set_sink(std::string* sink, std::error_code& ec) { - sink_ = sink; - set_write_function(&easy::write_function); - if (!ec) set_write_data(this); + return stats; } -void easy::unset_progress_callback() { - set_no_progress(true); - set_xferinfo_function(nullptr); - set_xferinfo_data(nullptr); +const std::string& easy::get_post_data() const { + return post_fields_; } -void easy::set_progress_callback(progress_callback_t progress_callback) { - progress_callback_ = std::move(progress_callback); - set_no_progress(false); - set_xferinfo_function(&easy::xferinfo_function); - set_xferinfo_data(this); +std::string easy::extract_post_data() { + auto result = std::move(post_fields_); + set_post_fields({}); + return result; } -void easy::set_url(std::string url_str) { - std::error_code ec; - set_url(std::move(url_str), ec); - throw_error(ec, "set_url"); +bool easy::has_post_data() const { + return !post_fields_.empty() || mime_; } -void easy::set_url(std::string&& url_str, std::error_code& ec) { - url_.SetAbsoluteUrl(url_str.c_str(), ec); - if (!ec) { - ec = static_cast( - native::curl_easy_setopt(handle_, native::CURLOPT_CURLU, url_.native_handle()) - ); - UASSERT(!ec); - } - - if (!ec) { - orig_url_str_ = std::move(url_str); - } else { - orig_url_str_.clear(); - } +void easy::add_header(std::string_view name, std::string_view value, detail_eha eha, detail_dha dha) { + if (detail::add_header_do_skip(headers_, name, dha)) { return; } + auto buffer = detail::create_header_buffer(name, value, eha); + if (detail::add_header_do_replace(headers_, buffer, name, dha)) { return; } + add_header(buffer.data()); } -const std::string& easy::get_original_url() const { return orig_url_str_; } - -const url& easy::get_easy_url() const { return url_; } - -void easy::set_post_fields(std::string&& post_fields) { - std::error_code ec; - set_post_fields(std::move(post_fields), ec); - throw_error(ec, "set_post_fields"); +void easy::add_header(std::string_view name, std::string_view value, detail_dha dha) { + add_header(name, value, detail_eha::kSend, dha); } -void easy::set_post_fields(std::string&& post_fields, std::error_code& ec) { - post_fields_ = std::move(post_fields); - ec = std::error_code{static_cast( - native::curl_easy_setopt(handle_, native::CURLOPT_POSTFIELDS, post_fields_.c_str()) - )}; +void easy::add_header(const char* header) { + if (!headers_) + headers_ = std::make_shared(); + + headers_->add(header); + std::error_code ec = detail::set_curl_opt( + easy_handle_, native::CURLOPT_HTTPHEADER, headers_->native_handle()); + throw_error(ec, "add_header"); +} - if (!ec) set_post_field_size_large(static_cast(post_fields_.length()), ec); +void easy::add_header(const std::string& header) { + add_header(header.c_str()); } -void easy::set_http_post(std::unique_ptr
form) { - std::error_code ec; - set_http_post(std::move(form), ec); - throw_error(ec, "set_http_post"); +void easy::add_proxy_header(std::string_view name, std::string_view value, detail_eha eha, detail_dha dha) { + if (detail::add_header_do_skip(proxy_headers_, name, dha)) { return; } + auto buffer = detail::create_header_buffer(name, value, eha); + if (detail::add_header_do_replace(proxy_headers_, buffer, name, dha)) { return; } + add_proxy_header(buffer.data()); } -void easy::set_http_post(std::unique_ptr form, std::error_code& ec) { - form_ = std::move(form); +void easy::add_proxy_header(const char* header) { + if (!proxy_headers_) + proxy_headers_ = std::make_shared(); - if (form_) { - ec = std::error_code{static_cast( - native::curl_easy_setopt(handle_, native::CURLOPT_HTTPPOST, form_->native_handle()) - )}; - } else { - ec = std::error_code{ - static_cast(native::curl_easy_setopt(handle_, native::CURLOPT_HTTPPOST, NULL))}; - } + proxy_headers_->add(header); + std::error_code ec = detail::set_curl_opt( + easy_handle_, native::CURLOPT_PROXYHEADER, proxy_headers_->native_handle()); + throw_error(ec, "add_proxy_header"); } -void easy::add_header( - std::string_view name, - std::string_view value, - EmptyHeaderAction empty_header_action, - DuplicateHeaderAction duplicate_header_action -) { - std::error_code ec; - add_header(name, value, ec, empty_header_action, duplicate_header_action); - throw_error(ec, "add_header"); +void easy::add_proxy_header(const std::string& header) { + add_proxy_header(header.c_str()); } -void easy::add_header( - std::string_view name, - std::string_view value, - std::error_code& ec, - EmptyHeaderAction empty_header_action, - DuplicateHeaderAction duplicate_header_action -) { - if (AddHeaderDoSkip(headers_, name, duplicate_header_action)) { - return; - } +void easy::add_resolve(const std::string& host, const std::string& port, const std::string& addr) { + if (!resolved_hosts_) + resolved_hosts_ = std::make_shared(); - auto buf = CreateHeaderBuffer(name, value, empty_header_action); + auto host_port_addr = utils::StrCat(host, ":", port, ":", addr); + const std::string_view host_port_view {host_port_addr.data(), host_port_addr.size() - addr.size()}; - if (AddHeaderDoReplace(headers_, buf, name, duplicate_header_action)) { - return; + if (!resolved_hosts_->ReplaceFirstIf( + [host_port_view](const auto& entry) { + // host_port_addr, of which we hold a string_view, might be moved in + // ReplaceFirstIf, but it's guaranteed that this + // lambda is not called after that. + return std::string_view{entry}.substr(host_port_view.size()) == host_port_view; + }, + std::move(host_port_addr) + )) { + UASSERT_MSG(!host_port_addr.empty(), "ReplaceFirstIf moved the string out, when it shouldn't have done so."); + resolved_hosts_->add(std::move(host_port_addr)); } - add_header(buf.data(), ec); + set_resolves(resolved_hosts_); + + std::error_code ec = detail::set_curl_opt( + easy_handle_, native::CURLOPT_RESOLVE, resolved_hosts_->native_handle()); + + throw_error(ec, "add_resolve"); } -void easy::add_header(std::string_view name, std::string_view value, DuplicateHeaderAction duplicate_header_action) { - std::error_code ec; - add_header(name, value, ec, duplicate_header_action); - throw_error(ec, "add_header"); +void easy::add_http200_alias(const std::string& http200_alias) { + if (!http200_aliases_) + http200_aliases_ = std::make_shared(); + + http200_aliases_->add(http200_alias); + std::error_code ec = detail::set_curl_opt( + easy_handle_, native::CURLOPT_HTTP200ALIASES, http200_aliases_->native_handle()); + throw_error(ec, "add_http200_alias"); } -void easy::add_header( - std::string_view name, - std::string_view value, - std::error_code& ec, - DuplicateHeaderAction duplicate_header_action -) { - add_header(name, value, ec, EmptyHeaderAction::kSend, duplicate_header_action); +std::optional easy::find_header_by_name(std::string_view name) const { + return detail::find_header_by_name(headers_, name); } -std::optional easy::FindHeaderByName(std::string_view name) const { - return FindHeaderByNameImpl(headers_, name); +// setters + +void easy::set_share(std::shared_ptr share) { + share_ = std::move(share); + + if (share) { + std::error_code ec = detail::set_curl_opt( + easy_handle_, native::CURLOPT_SHARE, share->native_handle()); + throw_error(ec, "set_share native_handle failed!"); + } else { + std::error_code ec = detail::set_curl_opt( + easy_handle_, native::CURLOPT_SHARE, nullptr); + throw_error(ec, "set_share nullptr failed!"); + } } -void easy::add_header(const char* header) { - std::error_code ec; - add_header(header, ec); - throw_error(ec, "add_header"); +// cURL Opt setters +void easy::set_verbose(bool state) { + detail::set_curl_opt( + "set_verbose", easy_handle_, native::CURLOPT_VERBOSE, state); } -void easy::add_header(const char* header, std::error_code& ec) { - if (!headers_) { - headers_ = std::make_shared(); - } +void easy::set_header(bool state) { + detail::set_curl_opt( + "set_header", easy_handle_, native::CURLOPT_HEADER, state); +} - headers_->add(header); - ec = std::error_code{static_cast( - native::curl_easy_setopt(handle_, native::CURLOPT_HTTPHEADER, headers_->native_handle()) - )}; +void easy::set_no_progress(bool state) { + detail::set_curl_opt( + "set_no_progress", easy_handle_, native::CURLOPT_NOPROGRESS, state); } -void easy::add_header(const std::string& header) { add_header(header.c_str()); } +void easy::set_no_signal(bool state) { + detail::set_curl_opt( + "set_no_signal", easy_handle_, native::CURLOPT_NOSIGNAL, state); +} -void easy::add_header(const std::string& header, std::error_code& ec) { add_header(header.c_str(), ec); } +void easy::set_wildcard_match(bool state) { + detail::set_curl_opt( + "set_wildcard_match", easy_handle_, native::CURLOPT_WILDCARDMATCH, state); +} -void easy::set_headers(std::shared_ptr headers) { - std::error_code ec; - set_headers(std::move(headers), ec); - throw_error(ec, "set_headers"); +void easy::set_post(bool state) { + detail::set_curl_opt( + "set_post", easy_handle_, native::CURLOPT_POST, state); } -void easy::set_headers(std::shared_ptr headers, std::error_code& ec) { - headers_ = std::move(headers); +void easy::set_source(std::shared_ptr source) { + std::error_code ec; + source_ = std::move(source); + set_read_function(&easy::read_runction, ec); + if (!ec) + set_read_data(this, ec); + if (!ec) + set_seek_function(&easy::seek_function, ec); + if (!ec) + set_seek_data(this, ec); - if (headers_) { - ec = std::error_code{static_cast( - native::curl_easy_setopt(handle_, native::CURLOPT_HTTPHEADER, headers_->native_handle()) - )}; - } else { - ec = std::error_code{ - static_cast(native::curl_easy_setopt(handle_, native::CURLOPT_HTTPHEADER, NULL))}; - } + throw_error(ec, "set_source"); } -void easy::add_proxy_header( - std::string_view name, - std::string_view value, - EmptyHeaderAction empty_header_action, - DuplicateHeaderAction duplicate_header_action -) { +void easy::set_sink(std::string* sink) { std::error_code ec; - add_proxy_header(name, value, ec, empty_header_action, duplicate_header_action); - throw_error(ec, "add_proxy_header"); + sink_ = sink; + set_write_function(&easy::write_function, ec); + if (!ec) + set_write_data(this, ec); + throw_error(ec, "set_sink"); } -void easy::add_proxy_header( - std::string_view name, - std::string_view value, - std::error_code& ec, - EmptyHeaderAction empty_header_action, - DuplicateHeaderAction duplicate_header_action -) { - if (AddHeaderDoSkip(proxy_headers_, name, duplicate_header_action)) { - return; - } +void easy::set_private(void* ptr) { + detail::set_curl_opt( + "set_private", easy_handle_, native::CURLOPT_PRIVATE, ptr); +} - auto buf = CreateHeaderBuffer(name, value, empty_header_action); +void easy::set_custom_request(const std::string& str) { + detail::set_curl_opt( + "set_custom_request", easy_handle_, native::CURLOPT_CUSTOMREQUEST, str.c_str()); +} - if (AddHeaderDoReplace(proxy_headers_, buf, name, duplicate_header_action)) { - return; - } +void easy::set_new_directory_perms(long perms) { + detail::set_curl_opt( + "set_new_directory_perms", easy_handle_, native::CURLOPT_NEW_DIRECTORY_PERMS, perms); +} - add_proxy_header(buf.data(), ec); +void easy::set_new_file_perms(long perms) { + detail::set_curl_opt( + "set_new_file_perms", easy_handle_, native::CURLOPT_NEW_FILE_PERMS, perms); } -void easy::add_proxy_header(const char* header, std::error_code& ec) { - if (!proxy_headers_) { - proxy_headers_ = std::make_shared(); +void easy::set_url(std::string&& url_str, std::error_code& ec) { + url_.SetAbsoluteUrl(url_str.c_str(), ec); + if (!ec) { + detail::set_curl_opt( + "set_url", easy_handle_, native::CURLOPT_URL, url_.native_handle()); + throw_error(ec, "set_url native_handle failed!"); } - proxy_headers_->add(header); - ec = std::error_code{static_cast( - native::curl_easy_setopt(handle_, native::CURLOPT_PROXYHEADER, proxy_headers_->native_handle()) - )}; + if (!ec) + orig_url_str_ = std::move(url_str); + else + orig_url_str_.clear(); } -void easy::add_http200_alias(const std::string& http200_alias) { - std::error_code ec; - add_http200_alias(http200_alias, ec); - throw_error(ec, "add_http200_alias"); +void easy::set_progress_data(void* ptr) { + detail::set_curl_opt( + "set_progress_data", easy_handle_, native::CURLOPT_XFERINFODATA, ptr); // CURLOPT_PROGRESSDATA } -void easy::add_http200_alias(const std::string& http200_alias, std::error_code& ec) { - if (!http200_aliases_) { - http200_aliases_ = std::make_shared(); - } - - http200_aliases_->add(http200_alias); - ec = std::error_code{static_cast( - native::curl_easy_setopt(handle_, native::CURLOPT_HTTP200ALIASES, http200_aliases_->native_handle()) - )}; +void easy::set_error_buffer(char* buffer) { + detail::set_curl_opt( + "set_error_buffer", easy_handle_, native::CURLOPT_ERRORBUFFER, buffer); } -void easy::set_http200_aliases(std::shared_ptr http200_aliases) { - std::error_code ec; - set_http200_aliases(std::move(http200_aliases), ec); - throw_error(ec, "set_http200_aliases"); +void easy::set_stderr(FILE* file) { + detail::set_curl_opt( + "set_stderr", easy_handle_, native::CURLOPT_STDERR, file); } -void easy::set_http200_aliases(std::shared_ptr http200_aliases, std::error_code& ec) { - http200_aliases_ = std::move(http200_aliases); +void easy::set_fail_on_error(bool state) { + detail::set_curl_opt( + "set_fail_on_error", easy_handle_, native::CURLOPT_FAILONERROR, state); +} - if (http200_aliases) { - ec = std::error_code{static_cast( - native::curl_easy_setopt(handle_, native::CURLOPT_HTTP200ALIASES, http200_aliases_->native_handle()) - )}; +void easy::set_mimepost(std::unique_ptr mime_ptr) { + mime_ = std::move(mime_ptr); + if (mime_) { + std::error_code ec = detail::set_curl_opt( + easy_handle_, native::CURLOPT_MIMEPOST, mime_->native_mime()); + throw_error(ec, "set_mimepost native_mime failed!"); } else { - ec = std::error_code{ - static_cast(native::curl_easy_setopt(handle_, native::CURLOPT_HTTP200ALIASES, nullptr) - )}; + std::error_code ec = detail::set_curl_opt( + easy_handle_, native::CURLOPT_MIMEPOST, nullptr); + throw_error(ec, "set_mimepost nullptr failed!"); } } -void easy::add_resolve(const std::string& host, const std::string& port, const std::string& addr) { - std::error_code ec; - add_resolve(host, port, addr, ec); - throw_error(ec, "add_resolve"); +void easy::set_http_proxy_tunnel(bool state) { + detail::set_curl_opt( + "set_http_proxy_tunnel", easy_handle_, native::CURLOPT_HTTPPROXYTUNNEL, state); +} + +void easy::set_socks5_gsapi_nec(bool state) { + detail::set_curl_opt( + "set_socks5_gsapi_nec", easy_handle_, native::CURLOPT_SOCKS5_GSSAPI_NEC, state); +} + +void easy::set_tcp_no_delay(bool state) { + detail::set_curl_opt( + "set_tcp_no_delay", easy_handle_, native::CURLOPT_TCP_NODELAY, state); +} + +void easy::set_tcp_keep_alive(bool state) { + detail::set_curl_opt( + "set_tcp_keep_alive", easy_handle_, native::CURLOPT_TCP_KEEPALIVE, state); +} + +void easy::set_auto_referrer(bool state) { + detail::set_curl_opt( + "set_auto_referrer", easy_handle_, native::CURLOPT_AUTOREFERER, state); +} + +void easy::set_follow_location(bool state) { + detail::set_curl_opt( + "set_follow_location", easy_handle_, native::CURLOPT_FOLLOWLOCATION, state); +} + +void easy::set_unrestricted_auth(bool state) { + detail::set_curl_opt( + "set_unrestricted_auth", easy_handle_, native::CURLOPT_UNRESTRICTED_AUTH, state); +} + +void easy::set_max_redirs(long value) { + detail::set_curl_opt( + "set_max_redirs", easy_handle_, native::CURLOPT_MAXREDIRS, value); +} +void easy::set_post_redir(long value) { + detail::set_curl_opt( + "set_post_redir", easy_handle_, native::CURLOPT_POSTREDIR, value); +} + +void easy::set_post_field_size(long value) { + detail::set_curl_opt( + "set_post_field_size", easy_handle_, native::CURLOPT_POSTFIELDSIZE, value); +} + +void easy::set_proxy_port(long value) { + detail::set_curl_opt( + "set_proxy_port", easy_handle_, native::CURLOPT_PROXYPORT, value); +} + +void easy::set_proxy_type(long value) { + detail::set_curl_opt( + "set_proxy_port", easy_handle_, native::CURLOPT_PROXYTYPE, value); +} + +void easy::set_local_port(long value) { + detail::set_curl_opt( + "set_local_port", easy_handle_, native::CURLOPT_LOCALPORT, value); +} + +void easy::set_local_port_range(long value) { + detail::set_curl_opt( + "set_local_port_range", easy_handle_, native::CURLOPT_LOCALPORTRANGE, value); +} + +void easy::set_dns_cache_timeout(long value) { + detail::set_curl_opt( + "set_dns_cache_timeout", easy_handle_, native::CURLOPT_DNS_CACHE_TIMEOUT, value); +} + +void easy::set_buffer_size(long value) { + detail::set_curl_opt( + "set_buffer_size", easy_handle_, native::CURLOPT_BUFFERSIZE, value); +} + +void easy::set_port(long value) { + detail::set_curl_opt( + "set_port", easy_handle_, native::CURLOPT_PORT, value); +} + +void easy::set_address_scope(long value) { + detail::set_curl_opt( + "set_address_scope", easy_handle_, native::CURLOPT_ADDRESS_SCOPE, value); +} + +void easy::set_tcp_keep_idle(long value) { + detail::set_curl_opt( + "set_tcp_keep_idle", easy_handle_, native::CURLOPT_TCP_KEEPIDLE, value); +} + +void easy::set_tcp_keep_intvl(long value) { + detail::set_curl_opt( + "set_tcp_keep_intvl", easy_handle_, native::CURLOPT_TCP_KEEPINTVL, value); +} + +void easy::set_connect_to(native::curl_slist* slist) { + detail::set_curl_opt( + "set_connect_to", easy_handle_, native::CURLOPT_CONNECT_TO, slist); +} + +void easy::set_post_field_size_large(native::curl_off_t value) { + detail::set_curl_opt( + "set_post_field_size_large", easy_handle_, native::CURLOPT_POSTFIELDSIZE_LARGE, value); +} + +void easy::set_post_fields(void* ptr) { + detail::set_curl_opt( + "set_post_fields", easy_handle_, native::CURLOPT_POSTFIELDS, ptr); +} + +void easy::set_post_fields(std::string&& post_fields) { + post_fields_ = std::move(post_fields); + std::error_code ec; + if (!post_fields_.empty()) + ec = detail::set_curl_opt(easy_handle_, native::CURLOPT_POSTFIELDS, post_fields_.data()); + + if (!ec) + set_post_field_size_large(static_cast(post_fields_.size())); + + throw_error(ec, "set_post_fields"); +} + +void easy::set_proxy(std::string_view sv) { + detail::set_curl_opt( + "set_proxy", easy_handle_, native::CURLOPT_PROXY, sv.data()); +} + +void easy::set_no_proxy(std::string_view sv) { + detail::set_curl_opt( + "set_no_proxy", easy_handle_, native::CURLOPT_NOPROXY, sv.data()); +} + +void easy::set_interface(std::string_view sv) { + detail::set_curl_opt( + "set_interface", easy_handle_, native::CURLOPT_INTERFACE, sv.data()); +} + +void easy::set_unix_socket_path(std::string_view sv) { + detail::set_curl_opt( + "set_unix_socket_path", easy_handle_, native::CURLOPT_UNIX_SOCKET_PATH, sv.data()); +} + +void easy::set_accept_encoding(std::string_view sv) { + detail::set_curl_opt( + "set_accept_encoding", easy_handle_, native::CURLOPT_ACCEPT_ENCODING, sv.data()); +} + +void easy::set_transfer_encoding(std::string_view sv) { + detail::set_curl_opt( + "set_transfer_encoding", easy_handle_, native::CURLOPT_TRANSFER_ENCODING, sv.data()); +} + +void easy::set_referer(std::string_view sv) { + detail::set_curl_opt( + "set_referer", easy_handle_, native::CURLOPT_REFERER, sv.data()); +} + +void easy::set_user_agent(std::string_view sv) { + detail::set_curl_opt( + "set_user_agent", easy_handle_, native::CURLOPT_USERAGENT, sv.data()); +} + +void easy::set_protocols_str(std::string_view sv) { + detail::set_curl_opt( + "set_protocols", easy_handle_, native::CURLOPT_PROTOCOLS_STR, sv.data()); +} + +void easy::set_redir_protocols_str(std::string_view sv) { + detail::set_curl_opt( + "set_redir_protocols_str", easy_handle_, native::CURLOPT_REDIR_PROTOCOLS_STR, sv.data()); +} + +void easy::set_headers(std::shared_ptr headers) { + headers_ = std::move(headers); + + if (headers_) { + std::error_code ec = detail::set_curl_opt( + easy_handle_, native::CURLOPT_HTTPHEADER, headers_->native_handle()); + throw_error(ec, "set_headers native_handle failed!"); + } else { + std::error_code ec = detail::set_curl_opt( + easy_handle_, native::CURLOPT_HTTPHEADER, nullptr); + throw_error(ec, "set_headers nullptr failed!"); + } +} + +void easy::set_http200_aliases(std::shared_ptr http200_aliases) { + http200_aliases_ = std::move(http200_aliases); + + if (http200_aliases_) { + std::error_code ec = detail::set_curl_opt( + easy_handle_, native::CURLOPT_HTTP200ALIASES, http200_aliases_->native_handle()); + throw_error(ec, "set_http200_aliases native_handle failed!"); + } else { + std::error_code ec = detail::set_curl_opt( + easy_handle_, native::CURLOPT_HTTP200ALIASES, nullptr); + throw_error(ec, "set_http200_aliases nullptr failed!"); + } +} + +void easy::set_tls_auth_type(long value) { + detail::set_curl_opt( + "set_tls_auth_type", easy_handle_, native::CURLOPT_TLSAUTH_TYPE, value); +} + +void easy::set_tls_auth_user(std::string_view sv) { + detail::set_curl_opt( + "set_tls_auth_user", easy_handle_, native::CURLOPT_TLSAUTH_USERNAME, sv.data()); +} + +void easy::set_tls_auth_password(std::string_view sv) { + detail::set_curl_opt( + "set_tls_auth_password", easy_handle_, native::CURLOPT_TLSAUTH_PASSWORD, sv.data()); +} + +void easy::set_netrc_file(std::string_view sv) { + detail::set_curl_opt( + "set_netrc_file", easy_handle_, native::CURLOPT_NETRC_FILE, sv.data()); +} + +void easy::set_user(std::string_view sv) { + detail::set_curl_opt( + "set_user", easy_handle_, native::CURLOPT_USERNAME, sv.data()); +} + +void easy::set_password(std::string_view sv) { + detail::set_curl_opt( + "set_password", easy_handle_, native::CURLOPT_PASSWORD, sv.data()); +} + +void easy::set_proxy_user(std::string_view sv) { + detail::set_curl_opt( + "set_proxy_user", easy_handle_, native::CURLOPT_PROXYUSERNAME, sv.data()); +} + +void easy::set_proxy_password(std::string_view sv) { + detail::set_curl_opt( + "set_proxy_password", easy_handle_, native::CURLOPT_PROXYPASSWORD, sv.data()); +} + +void easy::set_netrc(detail::netrc_t netrc) { + detail::set_curl_opt( + "set_netrc", easy_handle_, native::CURLOPT_NETRC, detail::to_integral(netrc)); +} + +void easy::set_http_auth(detail::httpauth_t httpauth, bool auth_only) { + auto result = detail::to_integral(httpauth) | (auth_only ? CURLAUTH_ONLY : 0UL); + detail::set_curl_opt( + "set_http_auth", easy_handle_, native::CURLOPT_HTTPAUTH, result); +} + +void easy::set_proxy_auth(detail::proxyauth_t proxyauth) { + detail::set_curl_opt( + "set_proxy_auth", easy_handle_, native::CURLOPT_PROXYAUTH, detail::to_integral(proxyauth)); +} + +void easy::set_transfer_text(bool state) { + detail::set_curl_opt( + "set_transfer_text", easy_handle_, native::CURLOPT_TRANSFERTEXT, state); +} + +void easy::set_transfer_mode(bool state) { + detail::set_curl_opt( + "set_transfer_mode", easy_handle_, native::CURLOPT_PROXY_TRANSFER_MODE, state); +} + +void easy::set_crlf(bool state) { + detail::set_curl_opt( + "set_crlf", easy_handle_, native::CURLOPT_CRLF, state); +} + +void easy::set_file_time(bool state) { + detail::set_curl_opt( + "set_file_time", easy_handle_, native::CURLOPT_FILETIME, state); +} + +void easy::set_upload(bool state) { + detail::set_curl_opt( + "set_upload", easy_handle_, native::CURLOPT_UPLOAD, state); +} + +void easy::set_no_body(bool state) { + detail::set_curl_opt( + "set_no_body", easy_handle_, native::CURLOPT_NOBODY, state); +} + +void easy::set_ignore_content_length(bool state) { + detail::set_curl_opt( + "set_ignore_content_length", easy_handle_, native::CURLOPT_IGNORE_CONTENT_LENGTH, state); +} + +void easy::set_http_content_decoding(bool state) { + detail::set_curl_opt( + "set_http_content_decoding", easy_handle_, native::CURLOPT_HTTP_CONTENT_DECODING, state); +} + +void easy::set_http_transfer_decoding(bool state) { + detail::set_curl_opt( + "set_http_transfer_decoding", easy_handle_, native::CURLOPT_HTTP_TRANSFER_DECODING, state); +} + +void easy::set_http_get(bool state) { + detail::set_curl_opt( + "set_http_get", easy_handle_, native::CURLOPT_HTTPGET, state); +} + +void easy::set_cookie_session(bool state) { + detail::set_curl_opt( + "set_cookie_session", easy_handle_, native::CURLOPT_COOKIESESSION, state); +} + +void easy::set_resume_from(long value) { + detail::set_curl_opt( + "set_resume_from", easy_handle_, native::CURLOPT_RESUME_FROM, value); +} + +void easy::set_in_file_size(long value) { + detail::set_curl_opt( + "set_in_file_size", easy_handle_, native::CURLOPT_INFILESIZE, value); +} + +void easy::set_max_file_size(long value) { + detail::set_curl_opt( + "set_max_file_size", easy_handle_, native::CURLOPT_MAXFILESIZE, value); +} + +void easy::set_time_value(long value) { + detail::set_curl_opt( + "set_time_value", easy_handle_, native::CURLOPT_TIMEVALUE, value); +} + +void easy::set_resume_from_large(native::curl_off_t value) { + detail::set_curl_opt( + "set_resume_from_large", easy_handle_, native::CURLOPT_RESUME_FROM_LARGE, value); +} + +void easy::set_in_file_size_large(native::curl_off_t value) { + detail::set_curl_opt( + "set_in_file_size_large", easy_handle_, native::CURLOPT_INFILESIZE_LARGE, value); +} + +void easy::set_max_file_size_large(native::curl_off_t value) { + detail::set_curl_opt( + "set_max_file_size_large", easy_handle_, native::CURLOPT_MAXFILESIZE_LARGE, value); +} + +void easy::set_range(std::string_view sv) { + detail::set_curl_opt( + "set_range", easy_handle_, native::CURLOPT_RANGE, sv.data()); +} + +void easy::set_cookie_list(std::string_view sv) { + detail::set_curl_opt( + "set_cookie_list", easy_handle_, native::CURLOPT_COOKIELIST, sv.data()); +} + +void easy::set_cookie(std::string_view sv) { + detail::set_curl_opt( + "set_cookie", easy_handle_, native::CURLOPT_COOKIE, sv.data()); +} + +void easy::set_cookie_file(std::string_view sv) { + detail::set_curl_opt( + "set_cookie_file", easy_handle_, native::CURLOPT_COOKIEFILE, sv.data()); +} + +void easy::set_cookie_jar(std::string_view sv) { + detail::set_curl_opt( + "set_cookie_jar", easy_handle_, native::CURLOPT_COOKIEJAR, sv.data()); +} + +void easy::set_http_version(detail::http_version_t version) { + detail::set_curl_opt( + "set_http_version", easy_handle_, native::CURLOPT_HTTP_VERSION, detail::to_integral(version)); +} + +void easy::set_time_condition(detail::time_condition_t condition) { + detail::set_curl_opt( + "set_time_condition", easy_handle_, native::CURLOPT_TIMECONDITION, detail::to_integral(condition)); +} + +void easy::set_fresh_connect(bool state) { + detail::set_curl_opt( + "set_fresh_connect", easy_handle_, native::CURLOPT_FRESH_CONNECT, state); +} + +void easy::set_forbit_reuse(bool state) { + detail::set_curl_opt( + "set_forbit_reuse", easy_handle_, native::CURLOPT_FORBID_REUSE, state); +} + +void easy::set_connect_only(bool state) { + detail::set_curl_opt( + "set_connect_only", easy_handle_, native::CURLOPT_CONNECT_ONLY, state); +} + +void easy::set_timeout(long timeout) { + detail::set_curl_opt( + "set_timeout", easy_handle_, native::CURLOPT_TIMEOUT, timeout); +} + +void easy::set_timeout_ms(long timeout) { + detail::set_curl_opt( + "set_timeout_ms", easy_handle_, native::CURLOPT_TIMEOUT_MS, timeout); +} + +void easy::set_low_speed_limit(long limit) { + detail::set_curl_opt( + "set_low_speed", easy_handle_, native::CURLOPT_LOW_SPEED_LIMIT, limit); +} + +void easy::set_low_speed_time(long time) { + detail::set_curl_opt( + "set_low_speed_time", easy_handle_, native::CURLOPT_LOW_SPEED_TIME, time); +} + +void easy::set_max_connects(long connects) { + detail::set_curl_opt( + "set_max_connects", easy_handle_, native::CURLOPT_MAXCONNECTS, connects); +} + +void easy::set_connect_timeout(long timeout) { + detail::set_curl_opt( + "set_connect_timeout", easy_handle_, native::CURLOPT_CONNECTTIMEOUT, timeout); +} + +void easy::set_connect_timeout_ms(long timeout) { + detail::set_curl_opt( + "set_connect_timeout_ms", easy_handle_, native::CURLOPT_CONNECTTIMEOUT_MS, timeout); +} + +void easy::set_accept_timeout_ms(long timeout) { + detail::set_curl_opt( + "set_accept_timeout_ms", easy_handle_, native::CURLOPT_ACCEPTTIMEOUT_MS, timeout); +} + +void easy::set_max_send_speed_large(native::curl_off_t large) { + detail::set_curl_opt( + "set_max_send_speed_large", easy_handle_, native::CURLOPT_MAX_SEND_SPEED_LARGE, large); +} + +void easy::set_max_recv_speed_large(native::curl_off_t large) { + detail::set_curl_opt( + "set_max_recv_speed_large", easy_handle_, native::CURLOPT_MAX_RECV_SPEED_LARGE, large); +} + +void easy::set_dns_servers(std::string_view sv) { + detail::set_curl_opt( + "set_dns_servers", easy_handle_, native::CURLOPT_DNS_SERVERS, sv.data()); +} + +void easy::set_ip_resolve(detail::ip_resolve_t resolve) { + detail::set_curl_opt( + "set_ip_resolve", easy_handle_, native::CURLOPT_IPRESOLVE, detail::to_integral(resolve)); +} + +void easy::set_resolves(std::shared_ptr resolved_hosts) { + resolved_hosts_ = std::move(resolved_hosts); + if (resolved_hosts_) { + std::error_code ec = detail::set_curl_opt( + easy_handle_, native::CURLOPT_RESOLVE, resolved_hosts_->native_handle()); + throw_error(ec, "set_resolves native_handle failed!"); + } else { + std::error_code ec = detail::set_curl_opt( + easy_handle_, native::CURLOPT_RESOLVE, nullptr); + throw_error(ec, "set_resolves nullptr failed!"); + } +} + +void easy::set_ssh_auth_types(long types) { + detail::set_curl_opt( + "set_ssh_auth_types", easy_handle_, native::CURLOPT_SSH_AUTH_TYPES, types); +} + +void easy::set_ssh_host_public_key_md5(std::string_view sv) { + detail::set_curl_opt( + "set_ssh_host_public_key_md5", easy_handle_, native::CURLOPT_SSH_HOST_PUBLIC_KEY_MD5, sv.data()); +} + +void easy::set_ssh_public_key_file(std::string_view sv) { + detail::set_curl_opt( + "set_ssh_public_key_file", easy_handle_, native::CURLOPT_SSH_PUBLIC_KEYFILE, sv.data()); +} + +void easy::set_ssh_private_key_file(std::string_view sv) { + detail::set_curl_opt( + "set_ssh_private_key_file", easy_handle_, native::CURLOPT_SSH_PRIVATE_KEYFILE, sv.data()); +} + +void easy::set_ssh_known_hosts(std::string_view sv) { + detail::set_curl_opt( + "set_ssh_known_hosts", easy_handle_, native::CURLOPT_SSH_KNOWNHOSTS, sv.data()); +} + +void easy::set_ssh_key_function(void* ptr) { + detail::set_curl_opt( + "set_ssh_key_function", easy_handle_, native::CURLOPT_SSH_KEYFUNCTION, ptr); +} + +void easy::set_ssh_key_data(void* ptr) { + detail::set_curl_opt( + "set_ssh_key_data", easy_handle_, native::CURLOPT_SSH_KEYDATA, ptr); +} + +void easy::set_ssl_cert(std::string_view sv) { + detail::set_curl_opt( + "set_ssl_cert", easy_handle_, native::CURLOPT_SSLCERT, sv.data()); +} + +void easy::set_ssl_cert_type(std::string_view sv) { + detail::set_curl_opt( + "set_ssl_cert_type", easy_handle_, native::CURLOPT_SSLCERTTYPE, sv.data()); +} + +void easy::set_ssl_key(std::string_view sv) { + detail::set_curl_opt( + "set_ssl_key", easy_handle_, native::CURLOPT_SSLKEY, sv.data()); +} + +void easy::set_ssl_key_type(std::string_view sv) { + detail::set_curl_opt( + "set_ssl_key_type", easy_handle_, native::CURLOPT_SSLKEYTYPE, sv.data()); +} + +void easy::set_ssl_key_passwd(std::string_view sv) { + detail::set_curl_opt( + "set_ssl_key_passwd", easy_handle_, native::CURLOPT_KEYPASSWD, sv.data()); +} + +void easy::set_ssl_engine(std::string_view sv) { + detail::set_curl_opt( + "set_ssl_engine", easy_handle_, native::CURLOPT_SSLENGINE, sv.data()); +} + +void easy::set_ssl_engine_default(std::string_view sv) { + detail::set_curl_opt( + "set_ssl_engine_default", easy_handle_, native::CURLOPT_SSLENGINE_DEFAULT, sv.data()); +} + +void easy::set_ca_info(std::string_view sv) { + detail::set_curl_opt( + "set_ca_info", easy_handle_, native::CURLOPT_CAINFO, sv.data()); +} + +void easy::set_ca_file(std::string_view sv) { + detail::set_curl_opt( + "set_ca_file", easy_handle_, native::CURLOPT_CAPATH, sv.data()); +} + +void easy::set_crl_file(std::string_view sv) { + detail::set_curl_opt( + "set_crl_file", easy_handle_, native::CURLOPT_CRLFILE, sv.data()); +} + +void easy::set_issuer_cert(std::string_view sv) { + detail::set_curl_opt( + "set_issuer_cert", easy_handle_, native::CURLOPT_ISSUERCERT, sv.data()); +} + +void easy::set_ssl_cipher_list(std::string_view sv) { + detail::set_curl_opt( + "set_ssl_cipher_list", easy_handle_, native::CURLOPT_SSL_CIPHER_LIST, sv.data()); +} + +void easy::set_krb_level(std::string_view sv) { + detail::set_curl_opt( + "set_krb_level", easy_handle_, native::CURLOPT_KRBLEVEL, sv.data()); +} + +void easy::set_ssl_options(long options) { + detail::set_curl_opt( + "set_ssl_options", easy_handle_, native::CURLOPT_SSL_OPTIONS, options); +} + +void easy::set_gssapi_delegation(long arg) { + detail::set_curl_opt( + "set_gssapi_delegation", easy_handle_, native::CURLOPT_GSSAPI_DELEGATION, arg); +} + +void easy::set_cert_info(bool state) { + detail::set_curl_opt( + "set_cert_info", easy_handle_, native::CURLOPT_CERTINFO, state); +} + +void easy::set_ssl_session_id_cache(bool state) { + detail::set_curl_opt( + "set_ssl_session_id_cache", easy_handle_, native::CURLOPT_SSL_SESSIONID_CACHE, state); +} + +void easy::set_ssl_verify_peer(bool state) { + detail::set_curl_opt("set_ssl_verify_peer", easy_handle_, native::CURLOPT_SSL_VERIFYPEER, state); +} + +void easy::set_ssl_verify_host(bool state) { + std::error_code ec = detail::set_curl_opt(easy_handle_, native::CURLOPT_SSL_VERIFYHOST, state ? 2L : 0L); + throw_error(ec, "set_ssl_verify_host"); +} + +void easy::set_ssl_version(detail::ssl_version_t version) { + detail::set_curl_opt( + "set_ssl_version", easy_handle_, native::CURLOPT_SSLVERSION, detail::to_integral(version)); +} + +void easy::set_use_ssl(detail::use_ssl_t ssl) { + detail::set_curl_opt( + "set_use_ssl", easy_handle_, native::CURLOPT_USE_SSL, detail::to_integral(ssl)); +} + +void easy::set_ssl_cert_blob_copy(std::string_view sv) { + detail::set_curl_opt_blob( + "set_ssl_cert_blob_copy", sv, CURL_BLOB_COPY, easy_handle_, native::CURLOPT_SSLCERT_BLOB); +} + +void easy::set_ssl_cert_blob_no_copy(std::string_view sv) { + detail::set_curl_opt_blob( + "set_ssl_cert_blob_no_copy", sv, CURL_BLOB_NOCOPY, easy_handle_, native::CURLOPT_SSLCERT_BLOB); +} + +void easy::set_ssl_key_blob_copy(std::string_view sv) { + detail::set_curl_opt_blob( + "set_ssl_key_blob_copy", sv, CURL_BLOB_COPY, easy_handle_, native::CURLOPT_SSLKEY_BLOB); +} + +void easy::set_ssl_key_blob_no_copy(std::string_view sv) { + detail::set_curl_opt_blob( + "set_ssl_key_blob_no_copy", sv, CURL_BLOB_NOCOPY, easy_handle_, native::CURLOPT_SSLKEY_BLOB); +} + +void easy::set_ca_info_blob_copy(std::string_view sv) { + detail::set_curl_opt_blob( + "set_ca_info_blob_copy", sv, CURL_BLOB_COPY, easy_handle_, native::CURLOPT_CAINFO_BLOB); +} + +void easy::set_ca_info_blob_no_copy(std::string_view sv) { + detail::set_curl_opt_blob( + "set_ca_info_blob_no_copy", sv, CURL_BLOB_NOCOPY, easy_handle_, native::CURLOPT_CAINFO_BLOB); +} + +// * puplic callback function @fn set_* @return none +void easy::set_progress_callback(progress_function_t func) { + progress_function_ = std::move(func); + set_no_progress(false); + set_xferinfo_function(&easy::xfer_function); + set_xferinfo_data(this); +} + +void easy::unset_progress_callback() { + set_no_progress(true); + set_xferinfo_function(nullptr); + set_xferinfo_data(nullptr); } -void easy::add_resolve(const std::string& host, const std::string& port, const std::string& addr, std::error_code& ec) { - if (!resolved_hosts_) { - resolved_hosts_ = std::make_shared(); - } - auto host_port_addr = utils::StrCat(host, ":", port, ":", addr); - const std::string_view host_port_view{host_port_addr.data(), host_port_addr.size() - addr.size()}; +void easy::set_header_function(header_function_t func) { + detail::set_curl_opt( + "set_header_function", easy_handle_, native::CURLOPT_HEADERFUNCTION, func); +} - if (!resolved_hosts_->ReplaceFirstIf( - [host_port_view](const auto& entry) { - // host_port_addr, of which we hold a string_view, might be moved in - // ReplaceFirstIf, but it's guaranteed that this - // lambda is not called after that. - return std::string_view{entry}.substr(host_port_view.size()) == host_port_view; - }, - std::move(host_port_addr) - )) { - UASSERT_MSG(!host_port_addr.empty(), "ReplaceFirstIf moved the string out, when it shouldn't have done so."); - resolved_hosts_->add(std::move(host_port_addr)); - } +void easy::set_header_data(void* ptr) { + detail::set_curl_opt( + "set_header_data", easy_handle_, native::CURLOPT_HEADERDATA, ptr); +} - ec = std::error_code{static_cast( - native::curl_easy_setopt(handle_, native::CURLOPT_RESOLVE, resolved_hosts_->native_handle()) - )}; +void easy::set_debug_function(debug_function_t func) { + detail::set_curl_opt( + "set_debug_function", easy_handle_, native::CURLOPT_DEBUGFUNCTION, func); } -void easy::set_resolves(std::shared_ptr resolved_hosts) { - std::error_code ec; - set_resolves(std::move(resolved_hosts), ec); - throw_error(ec, "set_resolves"); +void easy::set_debug_data(void* ptr) { + detail::set_curl_opt( + "set_debug_data", easy_handle_, native::CURLOPT_DEBUGDATA, ptr); } -void easy::set_resolves(std::shared_ptr resolved_hosts, std::error_code& ec) { - resolved_hosts_ = std::move(resolved_hosts); +void easy::set_interleave_function(interleave_function_t func) { + detail::set_curl_opt( + "set_interleave_function", easy_handle_, native::CURLOPT_INTERLEAVEFUNCTION, func); +} - if (resolved_hosts_) { - ec = std::error_code{static_cast( - native::curl_easy_setopt(handle_, native::CURLOPT_RESOLVE, resolved_hosts_->native_handle()) - )}; - } else { - ec = std::error_code{ - static_cast(native::curl_easy_setopt(handle_, native::CURLOPT_RESOLVE, NULL))}; - } +void easy::set_interleave_data(void* ptr) { + detail::set_curl_opt( + "set_interleave_data", easy_handle_, native::CURLOPT_INTERLEAVEDATA, ptr); } -void easy::set_share(std::shared_ptr share) { - std::error_code ec; - set_share(std::move(share), ec); - throw_error(ec, "set_share"); +void easy::set_write_function(write_function_t func, std::error_code& ec) { + ec = detail::set_curl_opt(easy_handle_, native::CURLOPT_WRITEFUNCTION, func); } -void easy::set_share(std::shared_ptr share, std::error_code& ec) { - share_ = std::move(share); +void easy::set_write_data(void* ptr, std::error_code& ec) { + ec = detail::set_curl_opt(easy_handle_, native::CURLOPT_WRITEDATA, ptr); +} - if (share) { - ec = std::error_code{static_cast( - native::curl_easy_setopt(handle_, native::CURLOPT_SHARE, share_->native_handle()) - )}; - } else { - ec = std::error_code{ - static_cast(native::curl_easy_setopt(handle_, native::CURLOPT_SHARE, NULL))}; - } +void easy::set_read_function(read_function_t func, std::error_code& ec) { + ec = detail::set_curl_opt(easy_handle_, native::CURLOPT_READFUNCTION, func); } -bool easy::has_post_data() const { return !post_fields_.empty() || form_; } +void easy::set_read_data(void* ptr, std::error_code& ec) { + ec = detail::set_curl_opt(easy_handle_, native::CURLOPT_READDATA, ptr); +} -const std::string& easy::get_post_data() const { return post_fields_; } +void easy::set_seek_function(seek_function_t func, std::error_code& ec) { + ec = detail::set_curl_opt(easy_handle_, native::CURLOPT_SEEKFUNCTION, func); +} -std::string easy::extract_post_data() { - auto data = std::move(post_fields_); - set_post_fields({}); - return data; +void easy::set_seek_data(void* ptr, std::error_code& ec) { + ec = detail::set_curl_opt(easy_handle_, native::CURLOPT_SEEKDATA, ptr); } -void easy::handle_completion(const std::error_code& err) { - LOG_TRACE() << "easy::handle_completion easy=" << this; +void easy::set_sockopt_function(sockopt_function_t func) { + detail::set_curl_opt( + "set_sockopt_function", easy_handle_, native::CURLOPT_SOCKOPTFUNCTION, func); +} - multi_registered_ = false; +void easy::set_sockopt_data(void* ptr) { + detail::set_curl_opt( + "set_sockopt_data", easy_handle_, native::CURLOPT_SOCKOPTDATA, ptr); +} - auto handler = std::function([](std::error_code) {}); - swap(handler, handler_); +void easy::set_xferinfo_function(xfer_function_t func) { + detail::set_curl_opt( + "set_xferinfo_function", easy_handle_, native::CURLOPT_XFERINFOFUNCTION, func); +} - /* It's OK to call handler in libev thread context as it is limited to - * Request::on_retry and Request::on_completed. All user code is executed in - * coro context. - */ - handler(err); +void easy::set_xferinfo_data(void* ptr) { + detail::set_curl_opt( + "set_xferinfo_data", easy_handle_, native::CURLOPT_XFERINFODATA, ptr); } -void easy::mark_retry() { ++retries_count_; } +void easy::set_opensocket_function(opensocket_function_t func) { + detail::set_curl_opt( + "set_opensocket_function", easy_handle_, native::CURLOPT_OPENSOCKETFUNCTION, func); +} -clients::http::LocalStats easy::get_local_stats() { - clients::http::LocalStats stats; +void easy::set_opensocket_data(void* ptr) { + detail::set_curl_opt( + "set_opensocket_data", easy_handle_, native::CURLOPT_OPENSOCKETDATA, ptr); +} - stats.open_socket_count = sockets_opened_; - stats.retries_count = retries_count_; - stats.time_to_connect = std::chrono::microseconds(get_connect_time_usec()); - stats.time_to_process = std::chrono::microseconds(get_total_time_usec()); +void easy::set_closesocket_function(closesocket_function_t func) { + detail::set_curl_opt( + "set_closesocket_function", easy_handle_, native::CURLOPT_CLOSESOCKETFUNCTION, func); +} - return stats; +void easy::set_closesocket_data(void* ptr) { + detail::set_curl_opt( + "set_closesocket_data", easy_handle_, native::CURLOPT_CLOSESOCKETDATA, ptr); } -std::error_code easy::rate_limit_error() const { return rate_limit_error_; } +void easy::set_ssl_ctx_function(ssl_ctx_function_t func, std::error_code& ec) { + ec = detail::set_curl_opt(easy_handle_, native::CURLOPT_SSL_CTX_FUNCTION, func); +} -easy::time_point::duration easy::time_to_start() const { - if (start_performing_ts_ != time_point{}) { - return start_performing_ts_ - construct_ts_; - } - return {}; +void easy::set_ssl_ctx_data(void* ptr, std::error_code& ec) { + ec = detail::set_curl_opt(easy_handle_, native::CURLOPT_SSL_CTX_DATA, ptr); } -native::curl_socket_t easy::open_tcp_socket(native::curl_sockaddr* address) { +// public getters +std::string_view easy::get_effective_url() { std::error_code ec; + std::string_view sv = get_effective_url(ec); + throw_error(ec, "get_effective_url"); + return sv; +} +std::string_view easy::get_effective_url(std::error_code& ec) { + return detail::get_curl_info_string_view(easy_handle_, native::CURLINFO_EFFECTIVE_URL, ec); +} - LOG_TRACE() << "open_tcp_socket family=" << address->family; +std::vector easy::get_ssl_engines() { + return detail::get_curl_info_list( + "get_ssl_engines", easy_handle_, native::CURLINFO_SSL_ENGINES); +} - int fd = socket(address->family, address->socktype, address->protocol); - if (fd == -1) { - const auto old_errno = errno; - LOG_ERROR() << "socket(2) failed with error: " << utils::strerror(old_errno); - return CURL_SOCKET_BAD; - } - if (multi_) multi_->BindEasySocket(*this, fd); - return fd; +std::vector easy::get_cookielist() { + return detail::get_curl_info_list( + "get_cookielist", easy_handle_, native::CURLINFO_COOKIELIST); } -size_t easy::write_function(char* ptr, size_t size, size_t nmemb, void* userdata) noexcept { - easy* self = static_cast(userdata); - size_t actual_size = size * nmemb; +std::string_view easy::get_scheme() { + return detail::get_curl_info_string_view( + "get_scheme", easy_handle_, native::CURLINFO_SCHEME); +} - if (!actual_size) { - return 0; - } +std::string_view easy::get_local_ip() { + return detail::get_curl_info_string_view( + "get_local_ip", easy_handle_, native::CURLINFO_LOCAL_IP); +} - try { - self->sink_->append(ptr, actual_size); - } catch (const std::exception&) { - // out of memory - return 0; - } +std::string_view easy::get_rtsp_session_id() { + return detail::get_curl_info_string_view( + "get_rtsp_session_id", easy_handle_, native::CURLINFO_RTSP_SESSION_ID); +} - return actual_size; +std::string_view easy::get_primary_ip() { + return detail::get_curl_info_string_view( + "get_primary_ip", easy_handle_, native::CURLINFO_PRIMARY_IP); } -size_t easy::read_function(void* ptr, size_t size, size_t nmemb, void* userdata) noexcept { - // FIXME readsome doesn't work with TFTP (see cURL docs) +std::string_view easy::get_redirect_url() { + return detail::get_curl_info_string_view( + "get_redirect_url", easy_handle_, native::CURLINFO_REDIRECT_URL); +} - easy* self = static_cast(userdata); - size_t actual_size = size * nmemb; +std::string_view easy::get_ftp_entry_path() { + return detail::get_curl_info_string_view( + "get_ftp_entry_path", easy_handle_, native::CURLINFO_FTP_ENTRY_PATH); +} - if (!self->source_) return CURL_READFUNC_ABORT; +std::string_view easy::get_content_type() { + return detail::get_curl_info_string_view( + "get_content_type", easy_handle_, native::CURLINFO_CONTENT_TYPE); +} - if (self->source_->eof()) { - return 0; - } +long easy::get_http_version() { + return detail::get_curl_info_long( + "get_http_version", easy_handle_, native::CURLINFO_HTTP_VERSION); +} - std::streamsize chars_stored = self->source_->readsome(static_cast(ptr), actual_size); +long easy::get_proxy_ssl_verifyresult() { + return detail::get_curl_info_long( + "get_proxy_ssl_verifyresult", easy_handle_, native::CURLINFO_PROXY_SSL_VERIFYRESULT); +} - if (!*self->source_) { - return CURL_READFUNC_ABORT; - } else { - return static_cast(chars_stored); - } +long easy::get_local_port() { + return detail::get_curl_info_long( + "get_local_port", easy_handle_, native::CURLINFO_LOCAL_PORT); } -int easy::seek_function(void* instream, native::curl_off_t offset, int origin) noexcept { - // TODO we could allow the user to define an offset which this library - // should consider as position zero for uploading chunks of the file - // alternatively do tellg() on the source stream when it is first passed to - // use_source() and use that as origin +long easy::get_primary_port() { + return detail::get_curl_info_long( + "get_primary_port", easy_handle_, native::CURLINFO_PRIMARY_PORT); +} - easy* self = static_cast(instream); +long easy::get_rtsp_cseq_recv() { + return detail::get_curl_info_long( + "get_rtsp_cseq_recv", easy_handle_, native::CURLINFO_RTSP_CSEQ_RECV); +} - std::ios::seekdir dir = std::ios::beg; +long easy::get_rtsp_server_cseq() { + return detail::get_curl_info_long( + "get_rtsp_server_cseq", easy_handle_, native::CURLINFO_RTSP_SERVER_CSEQ); +} - switch (origin) { - case SEEK_SET: - dir = std::ios::beg; - break; +long easy::get_rtsp_client_cseq() { + return detail::get_curl_info_long( + "get_rtsp_client_cseq", easy_handle_, native::CURLINFO_RTSP_CLIENT_CSEQ); +} - case SEEK_CUR: - dir = std::ios::cur; - break; +long easy::get_condition_unmet() { + return detail::get_curl_info_long( + "get_condition_unmet", easy_handle_, native::CURLINFO_CONDITION_UNMET); +} - case SEEK_END: - dir = std::ios::end; - break; +long easy::get_num_connects() { + return detail::get_curl_info_long( + "get_num_connects", easy_handle_, native::CURLINFO_NUM_CONNECTS); +} - default: - return CURL_SEEKFUNC_FAIL; - } +long easy::get_os_errno() { + return detail::get_curl_info_long( + "get_os_errno", easy_handle_, native::CURLINFO_OS_ERRNO); +} - if (!self->source_->seekg(offset, dir)) { - return CURL_SEEKFUNC_FAIL; - } else { - return CURL_SEEKFUNC_OK; - } +long easy::get_proxyauth_avail() { + return detail::get_curl_info_long( + "get_proxyauth_avail", easy_handle_, native::CURLINFO_PROXYAUTH_AVAIL); } -int easy::xferinfo_function( - void* clientp, - native::curl_off_t dltotal, - native::curl_off_t dlnow, - native::curl_off_t ultotal, - native::curl_off_t ulnow -) noexcept { - easy* self = static_cast(clientp); - try { - return self->progress_callback_(dltotal, dlnow, ultotal, ulnow) ? 0 : 1; - } catch (const std::exception& ex) { - LOG_LIMITED_WARNING() << "Progress callback failed: " << ex; - return 1; - } +long easy::get_httpauth_avail() { + return detail::get_curl_info_long( + "get_httpauth_avail", easy_handle_, native::CURLINFO_HTTPAUTH_AVAIL); +} + +long easy::get_http_connectcode() { + return detail::get_curl_info_long( + "get_http_connectcode", easy_handle_, native::CURLINFO_HTTP_CONNECTCODE); +} + +long easy::get_redirect_count() { + return detail::get_curl_info_long( + "get_redirect_count", easy_handle_, native::CURLINFO_REDIRECT_COUNT); +} + +long easy::get_redirect_time() { + return detail::get_curl_info_long( + "get_redirect_time", easy_handle_, native::CURLINFO_REDIRECT_TIME); +} + +long easy::get_header_size() { + return detail::get_curl_info_long( + "get_header_size", easy_handle_, native::CURLINFO_HEADER_SIZE); +} + +long easy::get_request_size() { + return detail::get_curl_info_long( + "get_request_size", easy_handle_, native::CURLINFO_REQUEST_SIZE); +} + +long easy::get_ssl_verifyresult() { + return detail::get_curl_info_long( + "get_ssl_verifyresult", easy_handle_, native::CURLINFO_SSL_VERIFYRESULT); +} + +long easy::get_response_code() { + return detail::get_curl_info_long( + "get_response_code", easy_handle_, native::CURLINFO_RESPONSE_CODE); +} + +long easy::get_content_length_upload() { + return detail::get_curl_info_long( + "get_content_length_upload", easy_handle_, native::CURLINFO_CONTENT_LENGTH_UPLOAD_T); +} + +long easy::get_content_length_download() { + return detail::get_curl_info_long( + "get_content_length_download", easy_handle_, native::CURLINFO_CONTENT_LENGTH_DOWNLOAD_T); +} + +long easy::get_filetime_sec() { + return detail::get_curl_info_long( + "get_filetime_sec", easy_handle_, native::CURLINFO_FILETIME_T); +} + +long easy::get_speed_upload_bps() { + return detail::get_curl_info_long( + "get_speed_upload_bps", easy_handle_, native::CURLINFO_SPEED_UPLOAD_T); +} + +long easy::get_speed_download_bps() { + return detail::get_curl_info_long( + "get_speed_dowload_bps", easy_handle_, native::CURLINFO_SPEED_DOWNLOAD_T); +} + +long easy::get_size_download() { + return detail::get_curl_info_long( + "get_size_download", easy_handle_, native::CURLINFO_SIZE_DOWNLOAD_T); +} + +long easy::get_size_upload() { + return detail::get_curl_info_long( + "get_size_upload", easy_handle_, native::CURLINFO_SIZE_UPLOAD_T); +} + +// stats getters +long easy::get_total_time_usec() { + return detail::get_curl_info_long( + "get_total_time_usec", easy_handle_, native::CURLINFO_TOTAL_TIME_T); +} + +long easy::get_namelookup_time_usec() { + return detail::get_curl_info_long( + "get_namelookup_time_usec", easy_handle_, native::CURLINFO_NAMELOOKUP_TIME_T); +} + +long easy::get_connect_time_usec() { + return detail::get_curl_info_long( + "get_connect_time_usec", easy_handle_, native::CURLINFO_CONNECT_TIME_T); +} + +long easy::get_pretransfer_time_usec() { + return detail::get_curl_info_long( + "get_pretransfer_time_usec", easy_handle_, native::CURLINFO_PRETRANSFER_TIME_T); +} + +long easy::get_starttransfer_time_usec() { + return detail::get_curl_info_long( + "get_starttransfer_time_usec", easy_handle_, native::CURLINFO_STARTTRANSFER_TIME_T); +} + +long easy::get_redirect_time_usec() { + return detail::get_curl_info_long( + "get_redirect_time_usec", easy_handle_, native::CURLINFO_REDIRECT_TIME_T); +} + +long easy::get_appconnect_time_usec() { + return detail::get_curl_info_long( + "get_appconnect_time_usec", easy_handle_, native::CURLINFO_APPCONNECT_TIME_T); +} + +long easy::get_retry_after_sec() { + return detail::get_curl_info_long("get_retry_after_sec", easy_handle_, native::CURLINFO_RETRY_AFTER); } -native::curl_socket_t -easy::opensocket(void* clientp, native::curlsocktype purpose, struct native::curl_sockaddr* address) noexcept { +// private static +native::curl_socket_t easy::open_socket(void* clientp, native::curlsocktype purpose, struct native::curl_sockaddr* address) noexcept { easy* self = static_cast(clientp); - multi* multi_handle = self->multi_; - native::curl_socket_t s = -1; + multi* multi_handle = self->multi_handle_; + + native::curl_socket_t socket = -1; if (multi_handle) { std::error_code ec; @@ -772,31 +1642,30 @@ easy::opensocket(void* clientp, native::curlsocktype purpose, struct native::cur return CURL_SOCKET_BAD; } else { LOG_TRACE() << "not throttled"; - } + } } else { LOG_TRACE() << "skip throttle check"; } if (purpose == native::CURLSOCKTYPE_IPCXN && address->socktype == SOCK_STREAM) { // Note to self: Why is address->protocol always set to zero? - s = self->open_tcp_socket(address); - if (s != -1 && multi_handle) { + socket = self->open_tcp_socket(address); + if (socket != -1 && multi_handle) { multi_handle->Statistics().mark_open_socket(); self->mark_open_socket(); } - return s; + return socket; } - // unknown or invalid socket type return CURL_SOCKET_BAD; } -int easy::closesocket(void* clientp, native::curl_socket_t item) noexcept { +int easy::close_socket(void* clientp, native::curl_socket_t item) noexcept { auto* multi_handle = static_cast(clientp); multi_handle->UnbindEasySocket(item); - int ret = close(item); - if (ret == -1) { + int result = close(item); + if (result == -1) { const auto old_errno = errno; LOG_ERROR() << "close(2) failed with error: " << utils::strerror(old_errno); } @@ -805,6 +1674,128 @@ int easy::closesocket(void* clientp, native::curl_socket_t item) noexcept { return 0; } -} // namespace curl +int easy::seek_function(void* instream, native::curl_off_t offset, int origin) noexcept { + // TODO we could allow the user to define an offset which this library + // should consider as position zero for uploading chunks of the file + // alternatively do tellg() on the source stream when it is first passed to + // use_source() and use that as origin + easy* self = static_cast(instream); + + std::ios::seekdir dir = std::ios::beg; + + switch (origin) { + case SEEK_SET: + dir = std::ios::beg; + break; + case SEEK_CUR: + dir = std::ios::cur; + break; + case SEEK_END: + dir = std::ios::end; + break; + default: + return CURL_SEEKFUNC_FAIL; + } + + if (!self->source_->seekg(offset, dir)) + return CURL_SEEKFUNC_FAIL; + + return CURL_SEEKFUNC_OK; +} + +size_t easy::header_function(void*, size_t size, size_t nmemb, void*) { + return size * nmemb; +} + +size_t easy::read_runction(void* ptr, size_t size, size_t nmemb, void* userdata) noexcept { + // FIXME readsome doesn't work with TFTP (see cURL docs) + easy* self = static_cast(userdata); + std::streamsize actual_size = static_cast(size * nmemb); + + if (!self->source_) + return CURL_READFUNC_ABORT; + + if (!self->source_->eof()) + return 0; + + std::streamsize result = self->source_->readsome(static_cast(ptr), actual_size); + + if (!*self->source_) + return CURL_READFUNC_ABORT; + + return static_cast(result); +} + +size_t easy::write_function(char* ptr, size_t size, size_t nmemb, void* userdata) noexcept { + easy* self = static_cast(userdata); + size_t actual_size = size * nmemb; + + if(!actual_size) + return 0; + + try { + self->sink_->append(ptr, actual_size); + } catch (const std::exception& ex) { + LOG_LIMITED_WARNING() << "write function failed: " << ex; + return 0; + } + + return actual_size; +} + +int easy::xfer_function(void* clinetp, native::curl_off_t dltotal, native::curl_off_t dlnow, + native::curl_off_t ultotal, native::curl_off_t ulnow) noexcept { + easy* self = static_cast(clinetp); + try { + return self->progress_function_(dltotal, dlnow, ultotal, ulnow) ? 0 : 1; + } catch (const std::exception& ex) { + LOG_LIMITED_WARNING() << "progress callback failed: " << ex; + return 1; + } +} + +native::curl_socket_t easy::open_tcp_socket(struct native::curl_sockaddr* address) noexcept { + std::error_code ec; + + LOG_TRACE() << "easy::open_tcp_socket family = " << address->family; + int fd = socket(address->family, address->socktype, address->protocol); + if (fd == -1) { + const auto old_errno = errno; + LOG_ERROR() << "socket(2) failed with error: " << utils::strerror(old_errno); + return CURL_SOCKET_BAD; + } + + if (multi_handle_) + multi_handle_->BindEasySocket(*this, fd); + + return fd; +} + +#if LIBCURL_VERSION_NUM <= 0x074700 + void easy::set_http_post(std::unique_ptr form_ptr>) { + form_ = std::move(form); + if (form_) { + std::error_code ec = detail::set_curl_opt( + easy_handle_, native::CURLOPT_HTTPPOST, form_->native_handle()); + throw_error(ec, "set_http_post native_handle failed!"); + } else { + std::error_code ec = detail::set_curl_opt( + easy_handle_, native::CURLOPT_HTTPPOST, nullptr); + throw_error(ec, "set_http_post nullptr failed!"); + } + } + + void easy::set_egd_socket(std::string_view sv) { + detail::set_curl_opt("set_egd_socket", easy_handle_, native::CURLOPT_EGDSOCKET, sv.data()); + } + + long easy::get_protocol() { + return detail::get_curl_info_long( + "get_protocol", easy_handle_, native::CURLINFO_PROTOCOL); + } + +#endif + +} // namespace curl -USERVER_NAMESPACE_END +USERVER_NAMESPACE_END \ No newline at end of file diff --git a/core/src/curl-ev/easy.hpp b/core/src/curl-ev/easy.hpp index f7a02a78a5b8..8fccd7421af8 100644 --- a/core/src/curl-ev/easy.hpp +++ b/core/src/curl-ev/easy.hpp @@ -1,3 +1,5 @@ +#pragma once + /** @file curl-ev/easy.hpp curl-ev: wrapper for integrating libcurl with libev applications Copyright (c) 2013 Oliver Kuckertz @@ -6,7 +8,7 @@ C++ wrapper for libcurl's easy interface */ -#pragma once +// !TODO this @file curl-ev/easy.hpp full upgrade in 2025 year // #include #include @@ -16,686 +18,486 @@ #include #include #include +#include -#include -#include +#include #include #include +#include +#include + #include USERVER_NAMESPACE_BEGIN namespace engine::ev { - -class ThreadControl; - + class ThreadControl; } // namespace engine::ev -// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) -#define IMPLEMENT_CURL_OPTION(FUNCTION_NAME, OPTION_NAME, OPTION_TYPE) \ - inline void FUNCTION_NAME(OPTION_TYPE arg) { \ - std::error_code ec; \ - FUNCTION_NAME(arg, ec); \ - throw_error(ec, PP_STRINGIZE(FUNCTION_NAME)); \ - } \ - inline void FUNCTION_NAME(OPTION_TYPE arg, std::error_code& ec) { \ - ec = std::error_code(static_cast(native::curl_easy_setopt(handle_, OPTION_NAME, arg))); \ - } - -// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) -#define IMPLEMENT_CURL_OPTION_BOOLEAN(FUNCTION_NAME, OPTION_NAME) \ - inline void FUNCTION_NAME(bool enabled) { \ - std::error_code ec; \ - FUNCTION_NAME(enabled, ec); \ - throw_error(ec, PP_STRINGIZE(FUNCTION_NAME)); \ - } \ - inline void FUNCTION_NAME(bool enabled, std::error_code& ec) { \ - ec = std::error_code( \ - static_cast(native::curl_easy_setopt(handle_, OPTION_NAME, enabled ? 1L : 0L)) \ - ); \ - } - -// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) -#define IMPLEMENT_CURL_OPTION_ENUM(FUNCTION_NAME, OPTION_NAME, ENUM_TYPE, OPTION_TYPE) \ - inline void FUNCTION_NAME(ENUM_TYPE arg) { \ - std::error_code ec; \ - FUNCTION_NAME(arg, ec); \ - throw_error(ec, PP_STRINGIZE(FUNCTION_NAME)); \ - } \ - inline void FUNCTION_NAME(ENUM_TYPE arg, std::error_code& ec) { \ - ec = std::error_code(static_cast( \ - native::curl_easy_setopt(handle_, OPTION_NAME, static_cast(arg)) \ - )); \ - } - -// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) -#define IMPLEMENT_CURL_OPTION_STRING(FUNCTION_NAME, OPTION_NAME) \ - inline void FUNCTION_NAME(const char* str) { \ - std::error_code ec; \ - FUNCTION_NAME(str, ec); \ - throw_error(ec, PP_STRINGIZE(FUNCTION_NAME)); \ - } \ - inline void FUNCTION_NAME(const char* str, std::error_code& ec) { \ - ec = std::error_code(static_cast(native::curl_easy_setopt(handle_, OPTION_NAME, str))); \ - } \ - inline void FUNCTION_NAME(const std::string& str) { \ - std::error_code ec; \ - FUNCTION_NAME(str, ec); \ - throw_error(ec, PP_STRINGIZE(FUNCTION_NAME)); \ - } \ - inline void FUNCTION_NAME(const std::string& str, std::error_code& ec) { \ - ec = std::error_code( \ - static_cast(native::curl_easy_setopt(handle_, OPTION_NAME, str.c_str())) \ - ); \ - } - -// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) -#define IMPLEMENT_CURL_OPTION_BLOB(FUNCTION_NAME, OPTION_NAME) \ -private: \ - inline void FUNCTION_NAME##_impl(std::string_view sv, unsigned int flags, std::error_code& ec) { \ - native::curl_blob blob{}; \ - /* NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast) */ \ - blob.data = const_cast(static_cast(sv.data())); \ - blob.len = sv.size(); \ - blob.flags = flags; \ - ec = std::error_code(static_cast(native::curl_easy_setopt(handle_, OPTION_NAME, &blob))); \ - } \ - \ -public: \ - static constexpr bool is_##FUNCTION_NAME##_available = true; \ - inline void FUNCTION_NAME##_copy(std::string_view sv) { \ - std::error_code ec; \ - FUNCTION_NAME##_copy(sv, ec); \ - throw_error(ec, PP_STRINGIZE(FUNCTION_NAME##_copy)); \ - } \ - inline void FUNCTION_NAME##_no_copy(std::string_view sv) { \ - std::error_code ec; \ - FUNCTION_NAME##_no_copy(sv, ec); \ - throw_error(ec, PP_STRINGIZE(FUNCTION_NAME##_no_copy)); \ - } \ - inline void FUNCTION_NAME##_copy(std::string_view sv, std::error_code& ec) { \ - FUNCTION_NAME##_impl(sv, CURL_BLOB_COPY, ec); \ - } \ - inline void FUNCTION_NAME##_no_copy(std::string_view sv, std::error_code& ec) { \ - FUNCTION_NAME##_impl(sv, CURL_BLOB_NOCOPY, ec); \ - } - -// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) -#define DELETE_CURL_OPTION_BLOB(FUNCTION_NAME) \ - static constexpr bool is_##FUNCTION_NAME##_available = false; \ - inline void FUNCTION_NAME##_copy(std::string_view) = delete; \ - inline void FUNCTION_NAME##_no_copy(std::string_view) = delete; \ - inline void FUNCTION_NAME##_copy(std::string_view, std::error_code&) = delete; \ - inline void FUNCTION_NAME##_no_copy(std::string_view, std::error_code&) = delete - -// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) -#define IMPLEMENT_CURL_OPTION_GET_STRING_VIEW(FUNCTION_NAME, OPTION_NAME) \ - inline std::string_view FUNCTION_NAME() { \ - std::error_code ec; \ - auto info = FUNCTION_NAME(ec); \ - throw_error(ec, PP_STRINGIZE(FUNCTION_NAME)); \ - return info; \ - } \ - inline std::string_view FUNCTION_NAME(std::error_code& ec) { \ - char* info = nullptr; \ - ec = \ - std::error_code(static_cast(native::curl_easy_getinfo(handle_, OPTION_NAME, &info))); \ - return info ? info : std::string_view{}; \ - } - -// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) -#define IMPLEMENT_CURL_OPTION_GET_LONG(FUNCTION_NAME, OPTION_NAME) \ - inline long FUNCTION_NAME() { \ - long info; \ - std::error_code ec = \ - std::error_code(static_cast(native::curl_easy_getinfo(handle_, OPTION_NAME, &info))); \ - throw_error(ec, PP_STRINGIZE(FUNCTION_NAME)); \ - return info; \ - } - -// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) -#define IMPLEMENT_CURL_OPTION_GET_CURL_OFF_T(FUNCTION_NAME, OPTION_NAME) \ - inline long FUNCTION_NAME() { \ - native::curl_off_t info; \ - std::error_code ec = \ - std::error_code(static_cast(native::curl_easy_getinfo(handle_, OPTION_NAME, &info))); \ - throw_error(ec, PP_STRINGIZE(FUNCTION_NAME)); \ - return info; \ - } - -// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) -#define IMPLEMENT_CURL_OPTION_GET_LIST(FUNCTION_NAME, OPTION_NAME) \ - inline std::vector FUNCTION_NAME() { \ - struct native::curl_slist* info; \ - std::vector results; \ - std::error_code ec = \ - std::error_code(static_cast(native::curl_easy_getinfo(handle_, OPTION_NAME, &info))); \ - throw_error(ec, PP_STRINGIZE(FUNCTION_NAME)); \ - struct native::curl_slist* it = info; \ - while (it) { \ - results.emplace_back(it->data); \ - it = it->next; \ - } \ - native::curl_slist_free_all(info); \ - return results; \ - } - -#ifdef CURL_SSLVERSION_DEFAULT -// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) -#define CURL_SSLVERSION_NAMESPACE -#else -// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) -#define CURL_SSLVERSION_NAMESPACE native:: -#endif - namespace curl { -// class form; class multi; class share; class string_list; +namespace detail { + enum class empty_header_action { kSend, kDoNotSend }; + enum class duplicate_header_action { kAdd, kSkip, kReplace }; + enum class http_version_t : unsigned long { + http_version_none = native::CURL_HTTP_VERSION_NONE, + http_version_1_0 = native::CURL_HTTP_VERSION_1_0, + http_version_1_1 = native::CURL_HTTP_VERSION_1_1, + http_version_2_0 = native::CURL_HTTP_VERSION_2_0, + http_version_2tls = native::CURL_HTTP_VERSION_2TLS, + http_version_2_prior_knowledge = native::CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE, + http_version_3_0 = native::CURL_HTTP_VERSION_3, + http_version_3_0_only = native::CURL_HTTP_VERSION_3ONLY + }; + enum class ssl_version_t : unsigned long { + ssl_version_default = native::CURL_SSLVERSION_DEFAULT, + ssl_version_tls_v1 = native::CURL_SSLVERSION_TLSv1, + ssl_version_ssl_v2 = native::CURL_SSLVERSION_SSLv2, + ssl_version_ssl_v3 = native::CURL_SSLVERSION_SSLv3 + }; + enum class use_ssl_t : unsigned long { + use_ssl_none = native::CURLUSESSL_NONE, + use_ssl_try = native::CURLUSESSL_TRY, + use_ssl_control = native::CURLUSESSL_CONTROL, + use_ssl_all = native::CURLUSESSL_ALL + }; + enum class ip_resolve_t : unsigned long { + ip_resolve_whatever = CURL_IPRESOLVE_WHATEVER, + ip_resolve_v4 = CURL_IPRESOLVE_V4, + ip_resolve_v6 = CURL_IPRESOLVE_V6 + }; + enum class time_condition_t : unsigned long { + if_modified_since = native::CURL_TIMECOND_IFMODSINCE, + if_unmodified_since = native::CURL_TIMECOND_IFUNMODSINCE + }; + enum class netrc_t : unsigned long { + netrc_optional = native::CURL_NETRC_OPTIONAL, + netrc_ignored = native::CURL_NETRC_IGNORED, + netrc_required = native::CURL_NETRC_REQUIRED + }; + enum class httpauth_t : unsigned long { + auth_basic = CURLAUTH_BASIC, + auth_digest = CURLAUTH_DIGEST, + auth_digest_ie = CURLAUTH_DIGEST_IE, + auth_negotiate = CURLAUTH_NEGOTIATE, + auth_ntlm = CURLAUTH_NTLM, + auth_ntlm_wb = CURLAUTH_NTLM_WB, + auth_any = CURLAUTH_ANY, + auth_any_safe = CURLAUTH_ANYSAFE + }; + enum class proxyauth_t : unsigned long { + proxy_auth_basic = CURLAUTH_BASIC, + proxy_auth_digest = CURLAUTH_DIGEST, + proxy_auth_digest_ie = CURLAUTH_DIGEST_IE, + proxy_auth_bearer = CURLAUTH_BEARER, + proxy_auth_negotiate = CURLAUTH_NEGOTIATE, + proxy_auth_ntlm = CURLAUTH_NTLM, + proxy_auth_ntlm_wb = CURLAUTH_NTLM_WB, + proxy_auth_any = CURLAUTH_ANY, + proxy_auth_anysafe = CURLAUTH_ANYSAFE + }; +} // namespace detail + +/************************************************************* + * * cURL easy wrapper class + * * @class easy + * TODO: @brief curl-ev wrapper shared class for libcurl + ************************************************************/ class easy final : public std::enable_shared_from_this { public: - using handler_type = std::function; - using time_point = std::chrono::steady_clock::time_point; + explicit easy(native::CURL* easy_handle, native::curl_mime* mime_ptr, multi* multi_ptr); - static easy* from_native(native::CURL* native_easy); + easy(const easy& rhs) = delete; + easy(easy&& rhs) noexcept = default; - // Creates an initialized but unbound easy, use GetBound() for usable - // instances. May block on resolver initialization. - static std::shared_ptr CreateBlocking(); + easy& operator= (const easy& rhs) noexcept = default; + easy& operator= (easy&& rhs) noexcept = default; - easy(native::CURL*, multi*); - easy(const easy&) = delete; ~easy(); - // Makes a clone of an initialized easy, hopefully non-blocking (skips full - // resolver initialization). - std::shared_ptr GetBoundBlocking(multi&) const; - - const multi* GetMulti() const { return multi_; } - - inline native::CURL* native_handle() { return handle_; } - engine::ev::ThreadControl& GetThreadControl(); +public: + using time_point = std::chrono::steady_clock::time_point; + using handler_type = std::function; + + // * this function unused, use async_perform() + [[maybe_unused]] void perform(){} - void perform(); - void perform(std::error_code& ec); void async_perform(handler_type handler); void cancel(); void reset(); - void set_source(std::shared_ptr source); - void set_source(std::shared_ptr source, std::error_code& ec); - void set_sink(std::string* sink); - void set_sink(std::string* sink, std::error_code& ec); + void mark_retry(); - using progress_callback_t = std::function; - void unset_progress_callback(); - void set_progress_callback(progress_callback_t progress_callback); +// public sys + void handle_completion(const std::error_code& ec); - // behavior options + void set_share(std::shared_ptr share); - IMPLEMENT_CURL_OPTION_BOOLEAN(set_verbose, native::CURLOPT_VERBOSE); - IMPLEMENT_CURL_OPTION_BOOLEAN(set_header, native::CURLOPT_HEADER); - IMPLEMENT_CURL_OPTION_BOOLEAN(set_no_progress, native::CURLOPT_NOPROGRESS); - IMPLEMENT_CURL_OPTION_BOOLEAN(set_no_signal, native::CURLOPT_NOSIGNAL); - IMPLEMENT_CURL_OPTION_BOOLEAN(set_wildcard_match, native::CURLOPT_WILDCARDMATCH); +// public static + static easy* from_native(native::CURL* native_easy); + static std::shared_ptr create_easy_blocking(); - // callback options +// public + std::error_code rate_limit_error() const; + time_point::duration time_to_start() const; + clients::http::LocalStats get_local_stats(); + const std::string& get_post_data() const; - using write_function_t = size_t (*)(char* ptr, size_t size, size_t nmemb, void* userdata); - IMPLEMENT_CURL_OPTION(set_write_function, native::CURLOPT_WRITEFUNCTION, write_function_t); - IMPLEMENT_CURL_OPTION(set_write_data, native::CURLOPT_WRITEDATA, void*); - using read_function_t = size_t (*)(void* ptr, size_t size, size_t nmemb, void* userdata); - IMPLEMENT_CURL_OPTION(set_read_function, native::CURLOPT_READFUNCTION, read_function_t); - IMPLEMENT_CURL_OPTION(set_read_data, native::CURLOPT_READDATA, void*); - using seek_function_t = int (*)(void* instream, native::curl_off_t offset, int origin); - IMPLEMENT_CURL_OPTION(set_seek_function, native::CURLOPT_SEEKFUNCTION, seek_function_t); - IMPLEMENT_CURL_OPTION(set_seek_data, native::CURLOPT_SEEKDATA, void*); - using sockopt_function_t = int (*)(void* clientp, native::curl_socket_t curlfd, native::curlsocktype purpose); - IMPLEMENT_CURL_OPTION(set_sockopt_function, native::CURLOPT_SOCKOPTFUNCTION, sockopt_function_t); - IMPLEMENT_CURL_OPTION(set_sockopt_data, native::CURLOPT_SOCKOPTDATA, void*); - using opensocket_function_t = - native::curl_socket_t (*)(void* clientp, native::curlsocktype purpose, struct native::curl_sockaddr* address); - IMPLEMENT_CURL_OPTION(set_opensocket_function, native::CURLOPT_OPENSOCKETFUNCTION, opensocket_function_t); - IMPLEMENT_CURL_OPTION(set_opensocket_data, native::CURLOPT_OPENSOCKETDATA, void*); - using closesocket_function_t = int (*)(void* clientp, native::curl_socket_t item); - IMPLEMENT_CURL_OPTION(set_closesocket_function, native::CURLOPT_CLOSESOCKETFUNCTION, closesocket_function_t); - IMPLEMENT_CURL_OPTION(set_closesocket_data, native::CURLOPT_CLOSESOCKETDATA, void*); - IMPLEMENT_CURL_OPTION(set_progress_data, native::CURLOPT_PROGRESSDATA, void*); - using xferinfo_function_t = int (*)( - void* clientp, - native::curl_off_t dltotal, - native::curl_off_t dlnow, - native::curl_off_t ultotal, - native::curl_off_t ulnow - ); - IMPLEMENT_CURL_OPTION(set_xferinfo_function, native::CURLOPT_XFERINFOFUNCTION, xferinfo_function_t); - IMPLEMENT_CURL_OPTION(set_xferinfo_data, native::CURLOPT_XFERINFODATA, void*); - using header_function_t = size_t (*)(void* ptr, size_t size, size_t nmemb, void* userdata); - IMPLEMENT_CURL_OPTION(set_header_function, native::CURLOPT_HEADERFUNCTION, header_function_t); - IMPLEMENT_CURL_OPTION(set_header_data, native::CURLOPT_HEADERDATA, void*); - using debug_callback_t = int (*)(native::CURL*, native::curl_infotype, char*, size_t, void*); - IMPLEMENT_CURL_OPTION(set_debug_callback, native::CURLOPT_DEBUGFUNCTION, debug_callback_t); - IMPLEMENT_CURL_OPTION(set_debug_data, native::CURLOPT_DEBUGDATA, void*); - using ssl_ctx_function_t = native::CURLcode (*)(native::CURL* curl, void* sslctx, void* parm); - IMPLEMENT_CURL_OPTION(set_ssl_ctx_function, native::CURLOPT_SSL_CTX_FUNCTION, ssl_ctx_function_t); - IMPLEMENT_CURL_OPTION(set_ssl_ctx_data, native::CURLOPT_SSL_CTX_DATA, void*); - using interleave_function_t = size_t (*)(void* ptr, size_t size, size_t nmemb, void* userdata); - IMPLEMENT_CURL_OPTION(set_interleave_function, native::CURLOPT_INTERLEAVEFUNCTION, interleave_function_t); - IMPLEMENT_CURL_OPTION(set_interleave_data, native::CURLOPT_INTERLEAVEDATA, void*); + std::string extract_post_data(); - // error options + bool has_post_data() const; - IMPLEMENT_CURL_OPTION(set_error_buffer, native::CURLOPT_ERRORBUFFER, char*); - IMPLEMENT_CURL_OPTION(set_stderr, native::CURLOPT_STDERR, FILE*); - IMPLEMENT_CURL_OPTION_BOOLEAN(set_fail_on_error, native::CURLOPT_FAILONERROR); +// public inline + inline native::CURL* native_handle() { return easy_handle_; } + inline const multi* get_multi() const { return multi_handle_; } - // network options + inline bool operator<(const easy& other) const { return (this < &other); } - void set_url(std::string url_str); +public: + using detail_eha = detail::empty_header_action; + using detail_dha = detail::duplicate_header_action; + + void add_header(std::string_view name, std::string_view value, + detail_eha eha = detail_eha::kSend, detail_dha dha = detail_dha::kAdd); + void add_header(std::string_view name, std::string_view value, detail_dha dha); + void add_header(const char* header); + void add_header(const std::string& header); + void add_proxy_header(std::string_view name, std::string_view value, + detail_eha = detail_eha::kSend, detail_dha = detail_dha::kAdd); + void add_proxy_header(const char* header); + void add_proxy_header(const std::string& header); + void add_resolve(const std::string& host, const std::string& port, const std::string& addr); + void add_http200_alias(const std::string& http200_alias); - /// @overload `set_url` - /// @note Doesn't perform a move from `url_str`, if error occurs. - void set_url(std::string&& url_str, std::error_code& ec); + std::optional find_header_by_name(std::string_view name) const; - const std::string& get_original_url() const; - const url& get_easy_url() const; - - IMPLEMENT_CURL_OPTION(set_protocols, native::CURLOPT_PROTOCOLS, long); - IMPLEMENT_CURL_OPTION(set_redir_protocols, native::CURLOPT_REDIR_PROTOCOLS, long); - IMPLEMENT_CURL_OPTION_STRING(set_proxy, native::CURLOPT_PROXY); - IMPLEMENT_CURL_OPTION(set_proxy_port, native::CURLOPT_PROXYPORT, long); - IMPLEMENT_CURL_OPTION(set_proxy_type, native::CURLOPT_PROXYTYPE, long); - IMPLEMENT_CURL_OPTION_STRING(set_no_proxy, native::CURLOPT_NOPROXY); - IMPLEMENT_CURL_OPTION_BOOLEAN(set_http_proxy_tunnel, native::CURLOPT_HTTPPROXYTUNNEL); - IMPLEMENT_CURL_OPTION_BOOLEAN(set_socks5_gsapi_nec, native::CURLOPT_SOCKS5_GSSAPI_NEC); - IMPLEMENT_CURL_OPTION_STRING(set_interface, native::CURLOPT_INTERFACE); - IMPLEMENT_CURL_OPTION(set_local_port, native::CURLOPT_LOCALPORT, long); - IMPLEMENT_CURL_OPTION(set_local_port_range, native::CURLOPT_LOCALPORTRANGE, long); - IMPLEMENT_CURL_OPTION(set_dns_cache_timeout, native::CURLOPT_DNS_CACHE_TIMEOUT, long); - IMPLEMENT_CURL_OPTION(set_buffer_size, native::CURLOPT_BUFFERSIZE, long); - IMPLEMENT_CURL_OPTION(set_port, native::CURLOPT_PORT, long); - IMPLEMENT_CURL_OPTION_BOOLEAN(set_tcp_no_delay, native::CURLOPT_TCP_NODELAY); - IMPLEMENT_CURL_OPTION(set_address_scope, native::CURLOPT_ADDRESS_SCOPE, long); - IMPLEMENT_CURL_OPTION_BOOLEAN(set_tcp_keep_alive, native::CURLOPT_TCP_KEEPALIVE); - IMPLEMENT_CURL_OPTION(set_tcp_keep_idle, native::CURLOPT_TCP_KEEPIDLE, long); - IMPLEMENT_CURL_OPTION(set_tcp_keep_intvl, native::CURLOPT_TCP_KEEPINTVL, long); - IMPLEMENT_CURL_OPTION_STRING(set_unix_socket_path, native::CURLOPT_UNIX_SOCKET_PATH); - IMPLEMENT_CURL_OPTION(set_connect_to, native::CURLOPT_CONNECT_TO, native::curl_slist*); - // authentication options - - enum netrc_t { - netrc_optional = native::CURL_NETRC_OPTIONAL, - netrc_ignored = native::CURL_NETRC_IGNORED, - netrc_required = native::CURL_NETRC_REQUIRED - }; - IMPLEMENT_CURL_OPTION_ENUM(set_netrc, native::CURLOPT_NETRC, netrc_t, long); - IMPLEMENT_CURL_OPTION_STRING(set_netrc_file, native::CURLOPT_NETRC_FILE); - IMPLEMENT_CURL_OPTION_STRING(set_user, native::CURLOPT_USERNAME); - IMPLEMENT_CURL_OPTION_STRING(set_password, native::CURLOPT_PASSWORD); - IMPLEMENT_CURL_OPTION_STRING(set_proxy_user, native::CURLOPT_PROXYUSERNAME); - IMPLEMENT_CURL_OPTION_STRING(set_proxy_password, native::CURLOPT_PROXYPASSWORD); - enum httpauth_t { - auth_basic = CURLAUTH_BASIC, - auth_digest = CURLAUTH_DIGEST, - auth_digest_ie = CURLAUTH_DIGEST_IE, - auth_negotiate = CURLAUTH_NEGOTIATE, - auth_ntlm = CURLAUTH_NTLM, - auth_ntlm_wb = CURLAUTH_NTLM_WB, - auth_any = CURLAUTH_ANY, - auth_any_safe = CURLAUTH_ANYSAFE - }; - inline void set_http_auth(httpauth_t auth, bool auth_only) { - std::error_code ec; - set_http_auth(auth, auth_only, ec); - throw_error(ec, "set_http_auth failed"); - } - inline void set_http_auth(httpauth_t auth, bool auth_only, std::error_code& ec) { - auto l = static_cast(auth | (auth_only ? CURLAUTH_ONLY : 0UL)); - ec = std::error_code( - static_cast(native::curl_easy_setopt(handle_, native::CURLOPT_HTTPAUTH, l)) - ); - } - IMPLEMENT_CURL_OPTION(set_tls_auth_type, native::CURLOPT_TLSAUTH_TYPE, long); - IMPLEMENT_CURL_OPTION_STRING(set_tls_auth_user, native::CURLOPT_TLSAUTH_USERNAME); - IMPLEMENT_CURL_OPTION_STRING(set_tls_auth_password, native::CURLOPT_TLSAUTH_PASSWORD); - enum proxyauth_t { - proxy_auth_basic = CURLAUTH_BASIC, - proxy_auth_digest = CURLAUTH_DIGEST, - proxy_auth_digest_ie = CURLAUTH_DIGEST_IE, - proxy_auth_bearer = CURLAUTH_BEARER, - proxy_auth_negotiate = CURLAUTH_NEGOTIATE, - proxy_auth_ntlm = CURLAUTH_NTLM, - proxy_auth_ntlm_wb = CURLAUTH_NTLM_WB, - proxy_auth_any = CURLAUTH_ANY, - proxy_auth_anysafe = CURLAUTH_ANYSAFE - }; - IMPLEMENT_CURL_OPTION(set_proxy_auth, native::CURLOPT_PROXYAUTH, long); - - // HTTP options - - IMPLEMENT_CURL_OPTION_BOOLEAN(set_auto_referrer, native::CURLOPT_AUTOREFERER); - IMPLEMENT_CURL_OPTION_STRING(set_accept_encoding, native::CURLOPT_ACCEPT_ENCODING); - IMPLEMENT_CURL_OPTION_STRING(set_transfer_encoding, native::CURLOPT_TRANSFER_ENCODING); - IMPLEMENT_CURL_OPTION_BOOLEAN(set_follow_location, native::CURLOPT_FOLLOWLOCATION); - IMPLEMENT_CURL_OPTION_BOOLEAN(set_unrestricted_auth, native::CURLOPT_UNRESTRICTED_AUTH); - IMPLEMENT_CURL_OPTION(set_max_redirs, native::CURLOPT_MAXREDIRS, long); - IMPLEMENT_CURL_OPTION(set_post_redir, native::CURLOPT_POSTREDIR, long); - IMPLEMENT_CURL_OPTION_BOOLEAN(set_post, native::CURLOPT_POST); +public: +/// cURL Opt setters + void set_verbose(bool state); + void set_header(bool state); + void set_no_progress(bool state); + void set_no_signal(bool state); + void set_wildcard_match(bool state); + void set_post(bool state); + + void set_source(std::shared_ptr source); + void set_sink(std::string* sink); + void set_private(void* ptr); + void set_custom_request(const std::string& str); + void set_new_directory_perms(long perms); + void set_new_file_perms(long perms); + + void set_url(std::string&& url_str, std::error_code& ec); + void set_progress_data(void* ptr); + + void set_error_buffer(char* buffer); + void set_stderr(FILE* file); + void set_fail_on_error(bool state); + + void set_mimepost(std::unique_ptr mime_ptr); + +// * puplic http setters @fn set_* @return none + void set_http_proxy_tunnel(bool state); + void set_socks5_gsapi_nec(bool state); + void set_tcp_no_delay(bool state); + void set_tcp_keep_alive(bool state); + void set_auto_referrer(bool state); + void set_follow_location(bool state); + void set_unrestricted_auth(bool state); + void set_max_redirs(long value); + void set_post_redir(long value); + void set_post_field_size(long value); + void set_proxy_port(long value); + void set_proxy_type(long value); + void set_local_port(long value); + void set_local_port_range(long value); + void set_dns_cache_timeout(long value); + void set_buffer_size(long value); + void set_port(long value); + void set_address_scope(long value); + void set_tcp_keep_idle(long value); + void set_tcp_keep_intvl(long value); + void set_connect_to(native::curl_slist* slist); + void set_post_field_size_large(native::curl_off_t value); + void set_post_fields(void* ptr); void set_post_fields(std::string&& post_fields); - void set_post_fields(std::string&& post_fields, std::error_code& ec); - IMPLEMENT_CURL_OPTION(set_post_fields, native::CURLOPT_POSTFIELDS, void*); - IMPLEMENT_CURL_OPTION(set_post_field_size, native::CURLOPT_POSTFIELDSIZE, long); - IMPLEMENT_CURL_OPTION(set_post_field_size_large, native::CURLOPT_POSTFIELDSIZE_LARGE, native::curl_off_t); - - void set_http_post(std::unique_ptr form); - void set_http_post(std::unique_ptr form, std::error_code& ec); - - IMPLEMENT_CURL_OPTION_STRING(set_referer, native::CURLOPT_REFERER); - IMPLEMENT_CURL_OPTION_STRING(set_user_agent, native::CURLOPT_USERAGENT); - enum class EmptyHeaderAction { kSend, kDoNotSend }; - enum class DuplicateHeaderAction { kAdd, kSkip, kReplace }; - void add_header( - std::string_view name, - std::string_view value, - EmptyHeaderAction empty_header_action = EmptyHeaderAction::kSend, - DuplicateHeaderAction duplicate_header_action = DuplicateHeaderAction::kAdd - ); - void add_header( - std::string_view name, - std::string_view value, - std::error_code& ec, - EmptyHeaderAction empty_header_action = EmptyHeaderAction::kSend, - DuplicateHeaderAction duplicate_header_action = DuplicateHeaderAction::kAdd - ); - void add_header(std::string_view name, std::string_view value, DuplicateHeaderAction duplicate_header_action); - void add_header( - std::string_view name, - std::string_view value, - std::error_code& ec, - DuplicateHeaderAction duplicate_header_action - ); - void add_header(const char* header); - void add_header(const char* header, std::error_code& ec); - void add_header(const std::string& header); - void add_header(const std::string& header, std::error_code& ec); + void set_proxy(std::string_view sv); + void set_interface(std::string_view sv); + void set_unix_socket_path(std::string_view sv); + void set_no_proxy(std::string_view sv); + void set_accept_encoding(std::string_view sv); + void set_transfer_encoding(std::string_view sv); + void set_referer(std::string_view sv); + void set_user_agent(std::string_view sv); + void set_protocols_str(std::string_view sv); + void set_redir_protocols_str(std::string_view sv); void set_headers(std::shared_ptr headers); - void set_headers(std::shared_ptr headers, std::error_code& ec); - std::optional FindHeaderByName(std::string_view name) const; - void add_proxy_header( - std::string_view name, - std::string_view value, - EmptyHeaderAction empty_header_action = EmptyHeaderAction::kSend, - DuplicateHeaderAction duplicate_header_action = DuplicateHeaderAction::kAdd - ); - void add_proxy_header( - std::string_view name, - std::string_view value, - std::error_code& ec, - EmptyHeaderAction empty_header_action = EmptyHeaderAction::kSend, - DuplicateHeaderAction duplicate_header_action = DuplicateHeaderAction::kAdd - ); - void add_proxy_header(const char* header, std::error_code& ec); - void add_http200_alias(const std::string& http200_alias); - void add_http200_alias(const std::string& http200_alias, std::error_code& ec); void set_http200_aliases(std::shared_ptr http200_aliases); - void set_http200_aliases(std::shared_ptr http200_aliases, std::error_code& ec); - IMPLEMENT_CURL_OPTION_STRING(set_cookie, native::CURLOPT_COOKIE); - IMPLEMENT_CURL_OPTION_STRING(set_cookie_file, native::CURLOPT_COOKIEFILE); - IMPLEMENT_CURL_OPTION_STRING(set_cookie_jar, native::CURLOPT_COOKIEJAR); - IMPLEMENT_CURL_OPTION_BOOLEAN(set_cookie_session, native::CURLOPT_COOKIESESSION); - IMPLEMENT_CURL_OPTION_STRING(set_cookie_list, native::CURLOPT_COOKIELIST); - IMPLEMENT_CURL_OPTION_BOOLEAN(set_http_get, native::CURLOPT_HTTPGET); - enum http_version_t { - http_version_none = native::CURL_HTTP_VERSION_NONE, - http_version_1_0 = native::CURL_HTTP_VERSION_1_0, - http_version_1_1 = native::CURL_HTTP_VERSION_1_1, - http_version_2_0 = native::CURL_HTTP_VERSION_2_0, - http_version_2tls = native::CURL_HTTP_VERSION_2TLS, - http_version_2_prior_knowledge = native::CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE, - }; - IMPLEMENT_CURL_OPTION_ENUM(set_http_version, native::CURLOPT_HTTP_VERSION, http_version_t, long); - IMPLEMENT_CURL_OPTION_BOOLEAN(set_ignore_content_length, native::CURLOPT_IGNORE_CONTENT_LENGTH); - IMPLEMENT_CURL_OPTION_BOOLEAN(set_http_content_decoding, native::CURLOPT_HTTP_CONTENT_DECODING); - IMPLEMENT_CURL_OPTION_BOOLEAN(set_http_transfer_decoding, native::CURLOPT_HTTP_TRANSFER_DECODING); - - // protocol options - - IMPLEMENT_CURL_OPTION_BOOLEAN(set_transfer_text, native::CURLOPT_TRANSFERTEXT); - IMPLEMENT_CURL_OPTION_BOOLEAN(set_transfer_mode, native::CURLOPT_PROXY_TRANSFER_MODE); - IMPLEMENT_CURL_OPTION_BOOLEAN(set_crlf, native::CURLOPT_CRLF); - IMPLEMENT_CURL_OPTION_STRING(set_range, native::CURLOPT_RANGE); - IMPLEMENT_CURL_OPTION(set_resume_from, native::CURLOPT_RESUME_FROM, long); - IMPLEMENT_CURL_OPTION(set_resume_from_large, native::CURLOPT_RESUME_FROM_LARGE, native::curl_off_t); - IMPLEMENT_CURL_OPTION_STRING(set_custom_request, native::CURLOPT_CUSTOMREQUEST); - IMPLEMENT_CURL_OPTION_BOOLEAN(set_file_time, native::CURLOPT_FILETIME); - IMPLEMENT_CURL_OPTION_BOOLEAN(set_no_body, native::CURLOPT_NOBODY); - IMPLEMENT_CURL_OPTION(set_in_file_size, native::CURLOPT_INFILESIZE, long); - IMPLEMENT_CURL_OPTION(set_in_file_size_large, native::CURLOPT_INFILESIZE_LARGE, native::curl_off_t); - IMPLEMENT_CURL_OPTION_BOOLEAN(set_upload, native::CURLOPT_UPLOAD); - IMPLEMENT_CURL_OPTION(set_max_file_size, native::CURLOPT_MAXFILESIZE, long); - IMPLEMENT_CURL_OPTION(set_max_file_size_large, native::CURLOPT_MAXFILESIZE_LARGE, native::curl_off_t); - enum time_condition_t { - if_modified_since = native::CURL_TIMECOND_IFMODSINCE, - if_unmodified_since = native::CURL_TIMECOND_IFUNMODSINCE - }; - IMPLEMENT_CURL_OPTION_ENUM(set_time_condition, native::CURLOPT_TIMECONDITION, time_condition_t, long); - IMPLEMENT_CURL_OPTION(set_time_value, native::CURLOPT_TIMEVALUE, long); - - // connection options - - IMPLEMENT_CURL_OPTION(set_timeout, native::CURLOPT_TIMEOUT, long); - IMPLEMENT_CURL_OPTION(set_timeout_ms, native::CURLOPT_TIMEOUT_MS, long); - IMPLEMENT_CURL_OPTION(set_low_speed_limit, native::CURLOPT_LOW_SPEED_LIMIT, long); - IMPLEMENT_CURL_OPTION(set_low_speed_time, native::CURLOPT_LOW_SPEED_TIME, long); - IMPLEMENT_CURL_OPTION(set_max_send_speed_large, native::CURLOPT_MAX_SEND_SPEED_LARGE, native::curl_off_t); - IMPLEMENT_CURL_OPTION(set_max_recv_speed_large, native::CURLOPT_MAX_RECV_SPEED_LARGE, native::curl_off_t); - IMPLEMENT_CURL_OPTION(set_max_connects, native::CURLOPT_MAXCONNECTS, long); - IMPLEMENT_CURL_OPTION_BOOLEAN(set_fresh_connect, native::CURLOPT_FRESH_CONNECT); - IMPLEMENT_CURL_OPTION_BOOLEAN(set_forbot_reuse, native::CURLOPT_FORBID_REUSE); - IMPLEMENT_CURL_OPTION(set_connect_timeout, native::CURLOPT_CONNECTTIMEOUT, long); - IMPLEMENT_CURL_OPTION(set_connect_timeout_ms, native::CURLOPT_CONNECTTIMEOUT_MS, long); - enum ip_resolve_t { - ip_resolve_whatever = CURL_IPRESOLVE_WHATEVER, - ip_resolve_v4 = CURL_IPRESOLVE_V4, - ip_resolve_v6 = CURL_IPRESOLVE_V6 - }; - IMPLEMENT_CURL_OPTION_ENUM(set_ip_resolve, native::CURLOPT_IPRESOLVE, ip_resolve_t, long); - IMPLEMENT_CURL_OPTION_BOOLEAN(set_connect_only, native::CURLOPT_CONNECT_ONLY); - enum use_ssl_t { - use_ssl_none = native::CURLUSESSL_NONE, - use_ssl_try = native::CURLUSESSL_TRY, - use_ssl_control = native::CURLUSESSL_CONTROL, - use_ssl_all = native::CURLUSESSL_ALL - }; - IMPLEMENT_CURL_OPTION_ENUM(set_use_ssl, native::CURLOPT_USE_SSL, use_ssl_t, long); - void add_resolve(const std::string& host, const std::string& port, const std::string& addr); - void add_resolve(const std::string& host, const std::string& port, const std::string& addr, std::error_code& ec); + +// * puplic auth setters @fn set_* @return none + void set_tls_auth_type(long value); + void set_tls_auth_user(std::string_view sv); + void set_tls_auth_password(std::string_view sv); + void set_netrc_file(std::string_view sv); + void set_user(std::string_view sv); + void set_password(std::string_view sv); + void set_proxy_user(std::string_view sv); + void set_proxy_password(std::string_view sv); + void set_netrc(detail::netrc_t netrc); + void set_http_auth(detail::httpauth_t httpauth, bool auth_only); + void set_proxy_auth(detail::proxyauth_t proxyauth); + +// * puplic protocol setters @fn set_* @return none + void set_transfer_text(bool state); + void set_transfer_mode(bool state); + void set_crlf(bool state); + void set_file_time(bool state); + void set_upload(bool state); + void set_no_body(bool state); + void set_ignore_content_length(bool state); + void set_http_content_decoding(bool state); + void set_http_transfer_decoding(bool state); + void set_http_get(bool state); + void set_cookie_session(bool state); + void set_resume_from(long value); + void set_in_file_size(long value); + void set_max_file_size(long value); + void set_time_value(long value); + void set_resume_from_large(native::curl_off_t value); + void set_in_file_size_large(native::curl_off_t value); + void set_max_file_size_large(native::curl_off_t value); + void set_range(std::string_view sv); + void set_cookie_list(std::string_view sv); + void set_cookie(std::string_view sv); + void set_cookie_file(std::string_view sv); + void set_cookie_jar(std::string_view sv); + void set_http_version(detail::http_version_t version); + void set_time_condition(detail::time_condition_t condition); + +// * puplic connection setters @fn set_* @return none + void set_fresh_connect(bool state); + void set_forbit_reuse(bool state); + void set_connect_only(bool state); + void set_timeout(long timeout); + void set_timeout_ms(long timeout); + void set_low_speed_limit(long limit); + void set_low_speed_time(long time); + void set_max_connects(long connects); + void set_connect_timeout(long timeout); + void set_connect_timeout_ms(long timeout); + void set_accept_timeout_ms(long timeout); + void set_max_send_speed_large(native::curl_off_t large); + void set_max_recv_speed_large(native::curl_off_t large); + void set_dns_servers(std::string_view sv); + void set_ip_resolve(detail::ip_resolve_t resolve); void set_resolves(std::shared_ptr resolved_hosts); - void set_resolves(std::shared_ptr resolved_hosts, std::error_code& ec); - IMPLEMENT_CURL_OPTION_STRING(set_dns_servers, native::CURLOPT_DNS_SERVERS); - IMPLEMENT_CURL_OPTION(set_accept_timeout_ms, native::CURLOPT_ACCEPTTIMEOUT_MS, long); - - // SSL and security options - - IMPLEMENT_CURL_OPTION_STRING(set_ssl_cert, native::CURLOPT_SSLCERT); - IMPLEMENT_CURL_OPTION_STRING(set_ssl_cert_type, native::CURLOPT_SSLCERTTYPE); - IMPLEMENT_CURL_OPTION_STRING(set_ssl_key, native::CURLOPT_SSLKEY); - IMPLEMENT_CURL_OPTION_STRING(set_ssl_key_type, native::CURLOPT_SSLKEYTYPE); - IMPLEMENT_CURL_OPTION_STRING(set_ssl_key_passwd, native::CURLOPT_KEYPASSWD); - IMPLEMENT_CURL_OPTION_STRING(set_ssl_engine, native::CURLOPT_SSLENGINE); - IMPLEMENT_CURL_OPTION_STRING(set_ssl_engine_default, native::CURLOPT_SSLENGINE_DEFAULT); -#if LIBCURL_VERSION_NUM >= 0x074700 - IMPLEMENT_CURL_OPTION_BLOB(set_ssl_cert_blob, native::CURLOPT_SSLCERT_BLOB); - IMPLEMENT_CURL_OPTION_BLOB(set_ssl_key_blob, native::CURLOPT_SSLKEY_BLOB); -#else - DELETE_CURL_OPTION_BLOB(set_ssl_cert_blob); - DELETE_CURL_OPTION_BLOB(set_ssl_key_blob); + +// * puplic ssh setters @fn set_* @return none + void set_ssh_auth_types(long types); + void set_ssh_host_public_key_md5(std::string_view sv); + void set_ssh_public_key_file(std::string_view sv); + void set_ssh_private_key_file(std::string_view sv); + void set_ssh_known_hosts(std::string_view sv); + void set_ssh_key_function(void* ptr); // !TODO ssh key callback ? + void set_ssh_key_data(void* ptr); + +// * ssl and security setters @fn set_* @return none + void set_ssl_cert(std::string_view sv); + void set_ssl_cert_type(std::string_view sv); + void set_ssl_key(std::string_view sv); + void set_ssl_key_type(std::string_view sv); + void set_ssl_key_passwd(std::string_view sv); + void set_ssl_engine(std::string_view sv); + void set_ssl_engine_default(std::string_view sv); + void set_ca_info(std::string_view sv); + void set_ca_file(std::string_view sv); + void set_crl_file(std::string_view sv); + void set_issuer_cert(std::string_view sv); + void set_ssl_cipher_list(std::string_view sv); + void set_krb_level(std::string_view sv); + void set_ssl_options(long options); + void set_gssapi_delegation(long arg); + void set_cert_info(bool state); + void set_ssl_session_id_cache(bool state); + void set_ssl_verify_peer(bool state); + void set_ssl_verify_host(bool state); + void set_ssl_version(detail::ssl_version_t version); + void set_use_ssl(detail::use_ssl_t ssl); + +#if LIBCURL_VERSION_NUM >= 0x074700 + void set_ssl_cert_blob_copy(std::string_view sv); + void set_ssl_cert_blob_no_copy(std::string_view sv); + void set_ssl_key_blob_copy(std::string_view sv); + void set_ssl_key_blob_no_copy(std::string_view sv); + + static constexpr bool is_set_ssl_cert_blob_available = true; + static constexpr bool is_set_ssl_key_blob_available = true; #endif - enum ssl_version_t { - ssl_version_default = CURL_SSLVERSION_NAMESPACE CURL_SSLVERSION_DEFAULT, - ssl_version_tls_v1 = CURL_SSLVERSION_NAMESPACE CURL_SSLVERSION_TLSv1, - ssl_version_ssl_v2 = CURL_SSLVERSION_NAMESPACE CURL_SSLVERSION_SSLv2, - ssl_version_ssl_v3 = CURL_SSLVERSION_NAMESPACE CURL_SSLVERSION_SSLv3, - }; - IMPLEMENT_CURL_OPTION_ENUM(set_ssl_version, native::CURLOPT_SSLVERSION, ssl_version_t, long); - IMPLEMENT_CURL_OPTION_BOOLEAN(set_ssl_verify_peer, native::CURLOPT_SSL_VERIFYPEER); - IMPLEMENT_CURL_OPTION_STRING(set_ca_info, native::CURLOPT_CAINFO); + #if LIBCURL_VERSION_NUM >= 0x074D00 - IMPLEMENT_CURL_OPTION_BLOB(set_ca_info_blob, native::CURLOPT_CAINFO_BLOB); -#else - DELETE_CURL_OPTION_BLOB(set_ca_info_blob); + void set_ca_info_blob_copy(std::string_view sv); + void set_ca_info_blob_no_copy(std::string_view sv); + + static constexpr bool is_set_ca_info_blob_available = true; #endif - IMPLEMENT_CURL_OPTION_STRING(set_issuer_cert, native::CURLOPT_ISSUERCERT); - IMPLEMENT_CURL_OPTION_STRING(set_ca_file, native::CURLOPT_CAPATH); - IMPLEMENT_CURL_OPTION_STRING(set_crl_file, native::CURLOPT_CRLFILE); - inline void set_ssl_verify_host(bool verify_host) { - std::error_code ec; - set_ssl_verify_host(verify_host, ec); - throw_error(ec, "set_ssl_verify_host failed"); - } - inline void set_ssl_verify_host(bool verify_host, std::error_code& ec) { - ec = std::error_code{static_cast( - native::curl_easy_setopt(handle_, native::CURLOPT_SSL_VERIFYHOST, verify_host ? 2L : 0L) - )}; - } - IMPLEMENT_CURL_OPTION_BOOLEAN(set_cert_info, native::CURLOPT_CERTINFO); - IMPLEMENT_CURL_OPTION_STRING(set_random_file, native::CURLOPT_RANDOM_FILE); - IMPLEMENT_CURL_OPTION_STRING(set_egd_socket, native::CURLOPT_EGDSOCKET); - IMPLEMENT_CURL_OPTION_STRING(set_ssl_cipher_list, native::CURLOPT_SSL_CIPHER_LIST); - IMPLEMENT_CURL_OPTION_BOOLEAN(set_ssl_session_id_cache, native::CURLOPT_SSL_SESSIONID_CACHE); - IMPLEMENT_CURL_OPTION(set_ssl_options, native::CURLOPT_SSL_OPTIONS, long); - IMPLEMENT_CURL_OPTION_STRING(set_krb_level, native::CURLOPT_KRBLEVEL); - IMPLEMENT_CURL_OPTION(set_gssapi_delegation, native::CURLOPT_GSSAPI_DELEGATION, long); - - // SSH options - - IMPLEMENT_CURL_OPTION(set_ssh_auth_types, native::CURLOPT_SSH_AUTH_TYPES, long); - IMPLEMENT_CURL_OPTION_STRING(set_ssh_host_public_key_md5, native::CURLOPT_SSH_HOST_PUBLIC_KEY_MD5); - IMPLEMENT_CURL_OPTION_STRING(set_ssh_public_key_file, native::CURLOPT_SSH_PUBLIC_KEYFILE); - IMPLEMENT_CURL_OPTION_STRING(set_ssh_private_key_file, native::CURLOPT_SSH_PRIVATE_KEYFILE); - IMPLEMENT_CURL_OPTION_STRING(set_ssh_known_hosts, native::CURLOPT_SSH_KNOWNHOSTS); - IMPLEMENT_CURL_OPTION(set_ssh_key_function, native::CURLOPT_SSH_KEYFUNCTION, - void*); // TODO curl_sshkeycallback? - IMPLEMENT_CURL_OPTION(set_ssh_key_data, native::CURLOPT_SSH_KEYDATA, void*); - - // other options - - IMPLEMENT_CURL_OPTION(set_private, native::CURLOPT_PRIVATE, void*); - void set_share(std::shared_ptr share); - void set_share(std::shared_ptr share, std::error_code& ec); - IMPLEMENT_CURL_OPTION(set_new_file_perms, native::CURLOPT_NEW_FILE_PERMS, long); - IMPLEMENT_CURL_OPTION(set_new_directory_perms, native::CURLOPT_NEW_DIRECTORY_PERMS, long); - - // getters - - IMPLEMENT_CURL_OPTION_GET_STRING_VIEW(get_effective_url, native::CURLINFO_EFFECTIVE_URL); - IMPLEMENT_CURL_OPTION_GET_LONG(get_response_code, native::CURLINFO_RESPONSE_CODE); - // CURLINFO_TOTAL_TIME - // CURLINFO_NAMELOOKUP_TIME - // CURLINFO_CONNECT_TIME - // CURLINFO_PRETRANSFER_TIME - // CURLINFO_SIZE_UPLOAD - IMPLEMENT_CURL_OPTION_GET_CURL_OFF_T(get_size_upload, native::CURLINFO_SIZE_UPLOAD_T); - // CURLINFO_SIZE_DOWNLOAD - IMPLEMENT_CURL_OPTION_GET_CURL_OFF_T(get_size_download, native::CURLINFO_SIZE_DOWNLOAD_T); - // CURLINFO_SPEED_DOWNLOAD - IMPLEMENT_CURL_OPTION_GET_CURL_OFF_T(get_speed_download_bps, native::CURLINFO_SPEED_DOWNLOAD_T); - // CURLINFO_SPEED_UPLOAD - IMPLEMENT_CURL_OPTION_GET_CURL_OFF_T(get_speed_upload_bps, native::CURLINFO_SPEED_UPLOAD_T); - IMPLEMENT_CURL_OPTION_GET_LONG(get_header_size, native::CURLINFO_HEADER_SIZE); - IMPLEMENT_CURL_OPTION_GET_LONG(get_request_size, native::CURLINFO_REQUEST_SIZE); - IMPLEMENT_CURL_OPTION_GET_LONG(get_ssl_verifyresult, native::CURLINFO_SSL_VERIFYRESULT); - // CURLINFO_FILETIME - IMPLEMENT_CURL_OPTION_GET_CURL_OFF_T(get_filetime_sec, native::CURLINFO_FILETIME_T); - // CURLINFO_CONTENT_LENGTH_DOWNLOAD - IMPLEMENT_CURL_OPTION_GET_CURL_OFF_T(get_content_length_download, native::CURLINFO_CONTENT_LENGTH_DOWNLOAD_T); - // CURLINFO_CONTENT_LENGTH_UPLOAD - IMPLEMENT_CURL_OPTION_GET_CURL_OFF_T(get_content_length_upload, native::CURLINFO_CONTENT_LENGTH_UPLOAD_T); - // CURLINFO_STARTTRANSFER_TIME - IMPLEMENT_CURL_OPTION_GET_STRING_VIEW(get_content_type, native::CURLINFO_CONTENT_TYPE); - // CURLINFO_REDIRECT_TIME - IMPLEMENT_CURL_OPTION_GET_LONG(get_redirect_count, native::CURLINFO_REDIRECT_COUNT); - // CURLINFO_PRIVATE - IMPLEMENT_CURL_OPTION_GET_LONG(get_http_connectcode, native::CURLINFO_HTTP_CONNECTCODE); - IMPLEMENT_CURL_OPTION_GET_LONG(get_httpauth_avail, native::CURLINFO_HTTPAUTH_AVAIL); - IMPLEMENT_CURL_OPTION_GET_LONG(get_proxyauth_avail, native::CURLINFO_PROXYAUTH_AVAIL); - IMPLEMENT_CURL_OPTION_GET_LONG(get_os_errno, native::CURLINFO_OS_ERRNO); - IMPLEMENT_CURL_OPTION_GET_LONG(get_num_connects, native::CURLINFO_NUM_CONNECTS); - IMPLEMENT_CURL_OPTION_GET_LIST(get_ssl_engines, native::CURLINFO_SSL_ENGINES); - IMPLEMENT_CURL_OPTION_GET_LIST(get_cookielist, native::CURLINFO_COOKIELIST); - IMPLEMENT_CURL_OPTION_GET_STRING_VIEW(get_ftp_entry_path, native::CURLINFO_FTP_ENTRY_PATH); - IMPLEMENT_CURL_OPTION_GET_STRING_VIEW(get_redirect_url, native::CURLINFO_REDIRECT_URL); - IMPLEMENT_CURL_OPTION_GET_STRING_VIEW(get_primary_ip, native::CURLINFO_PRIMARY_IP); - // CURLINFO_APPCONNECT_TIME - // CURLINFO_CERTINFO - IMPLEMENT_CURL_OPTION_GET_LONG(get_condition_unmet, native::CURLINFO_CONDITION_UNMET); - IMPLEMENT_CURL_OPTION_GET_STRING_VIEW(get_rtsp_session_id, native::CURLINFO_RTSP_SESSION_ID); - IMPLEMENT_CURL_OPTION_GET_LONG(get_rtsp_client_cseq, native::CURLINFO_RTSP_CLIENT_CSEQ); - IMPLEMENT_CURL_OPTION_GET_LONG(get_rtsp_server_cseq, native::CURLINFO_RTSP_SERVER_CSEQ); - IMPLEMENT_CURL_OPTION_GET_LONG(get_rtsp_cseq_recv, native::CURLINFO_RTSP_CSEQ_RECV); - IMPLEMENT_CURL_OPTION_GET_LONG(get_primary_port, native::CURLINFO_PRIMARY_PORT); - IMPLEMENT_CURL_OPTION_GET_STRING_VIEW(get_local_ip, native::CURLINFO_LOCAL_IP); - IMPLEMENT_CURL_OPTION_GET_LONG(get_local_port, native::CURLINFO_LOCAL_PORT); - // CURLINFO_TLS_SESSION - // CURLINFO_ACTIVESOCKET - // CURLINFO_TLS_SSL_PTR - IMPLEMENT_CURL_OPTION_GET_LONG(get_http_version, native::CURLINFO_HTTP_VERSION); - IMPLEMENT_CURL_OPTION_GET_LONG(get_proxy_ssl_verifyresult, native::CURLINFO_PROXY_SSL_VERIFYRESULT); - IMPLEMENT_CURL_OPTION_GET_LONG(get_protocol, native::CURLINFO_PROTOCOL); - IMPLEMENT_CURL_OPTION_GET_STRING_VIEW(get_scheme, native::CURLINFO_SCHEME); - IMPLEMENT_CURL_OPTION_GET_CURL_OFF_T(get_total_time_usec, native::CURLINFO_TOTAL_TIME_T); - IMPLEMENT_CURL_OPTION_GET_CURL_OFF_T(get_namelookup_time_usec, native::CURLINFO_NAMELOOKUP_TIME_T); - IMPLEMENT_CURL_OPTION_GET_CURL_OFF_T(get_connect_time_usec, native::CURLINFO_CONNECT_TIME_T); - IMPLEMENT_CURL_OPTION_GET_CURL_OFF_T(get_pretransfer_time_usec, native::CURLINFO_PRETRANSFER_TIME_T); - IMPLEMENT_CURL_OPTION_GET_CURL_OFF_T(get_starttransfer_time_usec, native::CURLINFO_STARTTRANSFER_TIME_T); - IMPLEMENT_CURL_OPTION_GET_CURL_OFF_T(get_redirect_time_usec, native::CURLINFO_REDIRECT_TIME_T); - IMPLEMENT_CURL_OPTION_GET_CURL_OFF_T(get_appconnect_time_usec, native::CURLINFO_APPCONNECT_TIME_T); - IMPLEMENT_CURL_OPTION_GET_CURL_OFF_T(get_retry_after_sec, native::CURLINFO_RETRY_AFTER); - bool has_post_data() const; +// * puplic callback function @fn set_* @return none + using progress_function_t = std::function; + void set_progress_callback(progress_function_t func); + void unset_progress_callback(); - const std::string& get_post_data() const; + using header_function_t = size_t (*)(void* ptr, size_t size, size_t nmemb, void* userdata); + void set_header_function(header_function_t func); + void set_header_data(void* ptr); - std::string extract_post_data(); + using debug_function_t = int (*)(native::CURL*, native::curl_infotype, char*, size_t, void*); + void set_debug_function(debug_function_t func); + void set_debug_data(void* ptr); - inline bool operator<(const easy& other) const { return (this < &other); } + using interleave_function_t = size_t (*)(void* ptr, size_t size, size_t nmemb, void* userdata); + void set_interleave_function(interleave_function_t func); + void set_interleave_data(void* ptr); + + using write_function_t = size_t (*)(char* ptr, size_t size, size_t nmemb, void* userdata); + void set_write_function(write_function_t func, std::error_code& ec); + void set_write_data(void* ptr, std::error_code& ec); - void handle_completion(const std::error_code& err); + using read_function_t = std::size_t (*)(void* ptr, size_t size, size_t nmemb, void* userdata); + void set_read_function(read_function_t func, std::error_code& ec); + void set_read_data(void* ptr, std::error_code& ec); - void mark_retry(); + using seek_function_t = int (*)(void* instream, native::curl_off_t offset, int origin); + void set_seek_function(seek_function_t func, std::error_code& ec); + void set_seek_data(void* ptr, std::error_code& ec); - clients::http::LocalStats get_local_stats(); + using sockopt_function_t = int (*)(void* clientp, native::curl_socket_t curlfd, native::curlsocktype purpose); + void set_sockopt_function(sockopt_function_t func); + void set_sockopt_data(void* ptr); - std::error_code rate_limit_error() const; + using xfer_function_t = int (*)(void* clinetp, native::curl_off_t dltotal, native::curl_off_t dlnow, + native::curl_off_t ultotal, native::curl_off_t ulnow); + void set_xferinfo_function(xfer_function_t func); + void set_xferinfo_data(void* ptr); - time_point::duration time_to_start() const; + using opensocket_function_t = native::curl_socket_t (*)(void* clientp, + native::curlsocktype purpose, struct native::curl_sockaddr* address); + void set_opensocket_function(opensocket_function_t func); + void set_opensocket_data(void* ptr); -private: - static size_t header_function(void* ptr, size_t size, size_t nmemb, void* userdata); + using closesocket_function_t = int (*)(void* clientp, native::curl_socket_t item); + void set_closesocket_function(closesocket_function_t func); + void set_closesocket_data(void* ptr); + + using ssl_ctx_function_t = native::CURLcode (*)(native::CURL* curl, void* sslctx, void* parm); + void set_ssl_ctx_function(ssl_ctx_function_t func, std::error_code& ec); + void set_ssl_ctx_data(void* ptr, std::error_code& ec); + +// * getters @fn get_* @return std::shared_ptr + [[nodiscard]] std::shared_ptr get_bound_blocking(multi& multi_handle) const; + [[nodiscard]] inline const std::string& get_original_url() const { return orig_url_str_; } + [[nodiscard]] inline const url& get_easy_url() const { return url_; } + +// * getters @fn get_* @return std::vector + [[nodiscard]] std::vector get_ssl_engines(); + [[nodiscard]] std::vector get_cookielist(); + +// * getters @fn get_* @return std::string_view + [[nodiscard]] std::string_view get_effective_url(); + [[nodiscard]] std::string_view get_effective_url(std::error_code& ec); + [[nodiscard]] std::string_view get_scheme(); + [[nodiscard]] std::string_view get_local_ip(); + [[nodiscard]] std::string_view get_rtsp_session_id(); + [[nodiscard]] std::string_view get_primary_ip(); + [[nodiscard]] std::string_view get_redirect_url(); + [[nodiscard]] std::string_view get_ftp_entry_path(); + [[nodiscard]] std::string_view get_content_type(); + +// * getters @fn get_* @return long + [[nodiscard]] long get_http_version(); + [[nodiscard]] long get_proxy_ssl_verifyresult(); + [[nodiscard]] long get_local_port(); + [[nodiscard]] long get_primary_port(); + [[nodiscard]] long get_rtsp_cseq_recv(); + [[nodiscard]] long get_rtsp_server_cseq(); + [[nodiscard]] long get_rtsp_client_cseq(); + [[nodiscard]] long get_condition_unmet(); + [[nodiscard]] long get_num_connects(); + [[nodiscard]] long get_os_errno(); + [[nodiscard]] long get_proxyauth_avail(); + [[nodiscard]] long get_httpauth_avail(); + [[nodiscard]] long get_http_connectcode(); + [[nodiscard]] long get_redirect_count(); + [[nodiscard]] long get_redirect_time(); + [[nodiscard]] long get_header_size(); + [[nodiscard]] long get_request_size(); + [[nodiscard]] long get_ssl_verifyresult(); + [[nodiscard]] long get_response_code(); + +// * getters stats @fn get_* @return long + [[nodiscard]] long get_content_length_upload(); // return native::curl_off_t ? + [[nodiscard]] long get_content_length_download(); // return native::curl_off_t ? + [[nodiscard]] long get_filetime_sec(); // return native::curl_off_t ? + [[nodiscard]] long get_speed_upload_bps(); // return native::curl_off_t ? + [[nodiscard]] long get_speed_download_bps(); // return native::curl_off_t ? + [[nodiscard]] long get_size_download(); // return native::curl_off_t ? + [[nodiscard]] long get_size_upload(); // return native::curl_off_t ? + +// * getters stats @fn get_* @return long + [[nodiscard]] long get_total_time_usec(); // return native::curl_off_t ? + [[nodiscard]] long get_namelookup_time_usec(); // return native::curl_off_t ? + [[nodiscard]] long get_connect_time_usec(); // return native::curl_off_t ? + [[nodiscard]] long get_pretransfer_time_usec(); // return native::curl_off_t ? + [[nodiscard]] long get_starttransfer_time_usec(); // return native::curl_off_t ? + [[nodiscard]] long get_redirect_time_usec(); // return native::curl_off_t ? + [[nodiscard]] long get_appconnect_time_usec(); // return native::curl_off_t ? + [[nodiscard]] long get_retry_after_sec(); // return native::curl_off_t ? + + engine::ev::ThreadControl& get_thread_control(); + + // this deprecated function use set_mimepost() + [[deprecated("Use set_mimepost())")]] [[noreturn]] + void set_http_post(void*); + // this deprecated function + [[deprecated("Serves no purpose anymore")]] [[noreturn]] + void set_random_file(std::string_view); // CURLOPT_RANDOM_FILE + // this deprecated function + [[deprecated("Serves no purpose anymore")]] [[noreturn]] + void set_egd_socket(std::string_view); // CURLOPT_EGDSOCKET + // this deprecated function + [[deprecated("Use set_redir_protocols_str()")]] [[noreturn]] + void set_redir_protocols(long); // CURLOPT_REDIR_PROTOCOLS + [[deprecated("Use set_protocols_str()")]] [[noreturn]] + void set_protocols(long); // CURLOPT_PROTOCOLS + // this deprecated function + [[deprecated("Use get_scheme()")]] [[noreturn]] + void get_protocol(); // CURLINFO_PROTOCOL + +#if LIBCURL_VERSION_NUM <= 0x074700 + #include + std::shared_ptr form_; - native::curl_socket_t open_tcp_socket(native::curl_sockaddr* address); - void cancel(size_t request_num); + void set_http_post(std::unique_ptr form_ptr>); + void set_egd_socket(std::string_view); - static size_t write_function(char* ptr, size_t size, size_t nmemb, void* userdata) noexcept; - static size_t read_function(void* ptr, size_t size, size_t nmemb, void* userdata) noexcept; + long get_protocol(); +#endif + +private: +// private static + static native::curl_socket_t open_socket(void* clientp, native::curlsocktype purpose, struct native::curl_sockaddr* address) noexcept; + static int close_socket(void* clientp, native::curl_socket_t item) noexcept; static int seek_function(void* instream, native::curl_off_t offset, int origin) noexcept; - static int xferinfo_function( - void* clientp, - native::curl_off_t dltotal, - native::curl_off_t dlnow, - native::curl_off_t ultotal, - native::curl_off_t ulnow - ) noexcept; - static native::curl_socket_t - opensocket(void* clientp, native::curlsocktype purpose, struct native::curl_sockaddr* address) noexcept; - static int closesocket(void* clientp, native::curl_socket_t item) noexcept; + static size_t header_function(void* ptr, size_t size, size_t nmemb, void* userdata); + static size_t read_runction(void* ptr, size_t size, size_t nmemb, void* userdata) noexcept; + static size_t write_function(char* ptr, size_t size, size_t nmemb, void* userdata) noexcept; + static int xfer_function(void* clinetp, native::curl_off_t dltotal, native::curl_off_t dlnow, + native::curl_off_t ultotal, native::curl_off_t ulnow) noexcept; + + native::curl_socket_t open_tcp_socket(struct native::curl_sockaddr* address) noexcept; // do_ev_* methods run in libev thread void do_ev_async_perform(handler_type handler, size_t request_num); @@ -704,39 +506,40 @@ class easy final : public std::enable_shared_from_this { void mark_start_performing(); void mark_open_socket(); - native::CURL* handle_{nullptr}; - multi* multi_; - size_t request_counter_{0}; - size_t cancelled_request_max_{0}; - bool multi_registered_{false}; - std::string orig_url_str_; - url url_; - handler_type handler_; - std::shared_ptr source_; - std::string* sink_{nullptr}; - std::string post_fields_; - std::shared_ptr form_; - std::shared_ptr headers_; - std::shared_ptr proxy_headers_; - std::shared_ptr http200_aliases_; - std::shared_ptr resolved_hosts_; - std::shared_ptr share_; - progress_callback_t progress_callback_; - std::size_t retries_count_{0}; - std::size_t sockets_opened_{0}; - std::error_code rate_limit_error_; + void cancel(size_t request_num); + +protected: + native::CURL* easy_handle_; + std::shared_ptr mime_; + multi* multi_handle_; + url url_; + + size_t request_counter_ { 0 }; + size_t retries_counter_ { 0 }; + size_t cancelled_request_max_ { 0 }; + size_t sockets_opened_ { 0 }; + + bool multi_registered_ { false }; + + std::string* sink_ { nullptr }; + std::string orig_url_str_ {}; + std::string post_fields_ {}; + + std::shared_ptr share_ { nullptr }; + std::shared_ptr source_ { nullptr }; + std::shared_ptr headers_ { nullptr }; + std::shared_ptr proxy_headers_ { nullptr }; + std::shared_ptr http200_aliases_ { nullptr }; + std::shared_ptr resolved_hosts_ { nullptr }; + + handler_type handler_ {}; + progress_function_t progress_function_ {}; + + std::error_code rate_limit_error_ {}; time_point start_performing_ts_{}; const time_point construct_ts_; }; -} // namespace curl - -#undef IMPLEMENT_CURL_OPTION -#undef IMPLEMENT_CURL_OPTION_BOOLEAN -#undef IMPLEMENT_CURL_OPTION_ENUM -#undef IMPLEMENT_CURL_OPTION_STRING -#undef IMPLEMENT_CURL_OPTION_GET_STRING_VIEW -#undef IMPLEMENT_CURL_OPTION_GET_LONG -#undef IMPLEMENT_CURL_OPTION_GET_LIST +} // namespace curl -USERVER_NAMESPACE_END +USERVER_NAMESPACE_END \ No newline at end of file diff --git a/core/src/curl-ev/error_code.cpp b/core/src/curl-ev/error_code.cpp index c22dfd493daf..3f077b86bdfb 100644 --- a/core/src/curl-ev/error_code.cpp +++ b/core/src/curl-ev/error_code.cpp @@ -7,6 +7,8 @@ error_code class */ +// !TODO this header file upgrade in 2025 year // + #include USERVER_NAMESPACE_BEGIN @@ -18,6 +20,31 @@ class EasyErrorCategory final : public std::error_category { public: using std::error_category::error_category; +#if LIBCURL_VERSION_NUM <= 0x074700 + [[nodiscard]] std::string message(int cond) const override { + switch (static_cast(cond)) { + case FormErrorCode::kSuccess: + return "no error"; + case FormErrorCode::kMemory: + return "memory allocation error"; + case FormErrorCode::kOptionTwice: + return "one option is given twice"; + case FormErrorCode::kNull: + return "a null pointer was given for a char"; + case FormErrorCode::kUnknownOption: + return "an unknown option was used"; + case FormErrorCode::kIncomplete: + return "some FormInfo is not complete (or error)"; + case FormErrorCode::kIllegalArray: + return "an illegal option is used in an array"; + case FormErrorCode::kDisabled: + return "form support was disabled"; + default: + return "unknown CURLFORMcode"; + } + } +#endif + [[nodiscard]] const char* name() const noexcept override { return "curl-easy"; } [[nodiscard]] std::string message(int cond) const override { @@ -52,29 +79,6 @@ class FormErrorCategory final : public std::error_category { using std::error_category::error_category; [[nodiscard]] const char* name() const noexcept override { return "curl-form"; } - - [[nodiscard]] std::string message(int cond) const override { - switch (static_cast(cond)) { - case FormErrorCode::kSuccess: - return "no error"; - case FormErrorCode::kMemory: - return "memory allocation error"; - case FormErrorCode::kOptionTwice: - return "one option is given twice"; - case FormErrorCode::kNull: - return "a null pointer was given for a char"; - case FormErrorCode::kUnknownOption: - return "an unknown option was used"; - case FormErrorCode::kIncomplete: - return "some FormInfo is not complete (or error)"; - case FormErrorCode::kIllegalArray: - return "an illegal option is used in an array"; - case FormErrorCode::kDisabled: - return "form support was disabled"; - default: - return "unknown CURLFORMcode"; - } - } }; class UrlErrorCategory final : public std::error_category { @@ -164,11 +168,6 @@ const std::error_category& GetShareCategory() noexcept { return kShareCategory; } -const std::error_category& GetFormCategory() noexcept { - static const FormErrorCategory kFormCategory; - return kFormCategory; -} - const std::error_category& GetUrlCategory() noexcept { static const UrlErrorCategory kUrlCategory; return kUrlCategory; @@ -179,6 +178,13 @@ const std::error_category& GetRateLimitCategory() noexcept { return kRateLimitCategory; } +#if LIBCURL_VERSION_NUM <= 0x074700 +const std::error_category& GetFormCategory() noexcept { + static const FormErrorCategory kFormCategory; + return kFormCategory; +} +#endif + } // namespace curl::errc USERVER_NAMESPACE_END diff --git a/core/src/curl-ev/error_code.hpp b/core/src/curl-ev/error_code.hpp index 65660baa69de..ec7657d49c8e 100644 --- a/core/src/curl-ev/error_code.hpp +++ b/core/src/curl-ev/error_code.hpp @@ -7,6 +7,8 @@ error_code class */ +// !TODO this header file upgrade in 2025 year // + #pragma once #include @@ -128,6 +130,7 @@ enum class ShareErrorCode { kNotBuiltIn = native::CURLSHE_NOT_BUILT_IN }; +#if LIBCURL_VERSION_NUM <= 0x074700 enum class FormErrorCode { kSuccess = native::CURL_FORMADD_OK, kMemory = native::CURL_FORMADD_MEMORY, @@ -138,6 +141,7 @@ enum class FormErrorCode { kIllegalArray = native::CURL_FORMADD_ILLEGAL_ARRAY, kDisabled = native::CURL_FORMADD_DISABLED }; +#endif enum class UrlErrorCode { kSuccess = native::CURLUE_OK, @@ -169,10 +173,13 @@ enum class RateLimitErrorCode { const std::error_category& GetEasyCategory() noexcept; const std::error_category& GetMultiCategory() noexcept; const std::error_category& GetShareCategory() noexcept; -const std::error_category& GetFormCategory() noexcept; const std::error_category& GetUrlCategory() noexcept; const std::error_category& GetRateLimitCategory() noexcept; +#if LIBCURL_VERSION_NUM <= 0x074700 +const std::error_category& GetFormCategory() noexcept; +#endif + } // namespace curl::errc USERVER_NAMESPACE_END @@ -188,15 +195,17 @@ struct is_error_code_enum : std:: template <> struct is_error_code_enum : std::true_type {}; -template <> -struct is_error_code_enum : std::true_type {}; - template <> struct is_error_code_enum : std::true_type {}; template <> struct is_error_code_enum : std::true_type {}; +#if LIBCURL_VERSION_NUM <= 0x074700 +template <> +struct is_error_code_enum : std::true_type {}; +#endif + } // namespace std USERVER_NAMESPACE_BEGIN @@ -209,12 +218,14 @@ inline std::error_code make_error_code(MultiErrorCode e) { return {static_cast(e), GetShareCategory()}; } -inline std::error_code make_error_code(FormErrorCode e) { return {static_cast(e), GetFormCategory()}; } - inline std::error_code make_error_code(UrlErrorCode e) { return {static_cast(e), GetUrlCategory()}; } inline std::error_code make_error_code(RateLimitErrorCode e) { return {static_cast(e), GetRateLimitCategory()}; } +#if LIBCURL_VERSION_NUM <= 0x074700 +inline std::error_code make_error_code(FormErrorCode e) { return {static_cast(e), GetFormCategory()}; } +#endif + } // namespace curl::errc USERVER_NAMESPACE_END diff --git a/core/src/curl-ev/form.cpp b/core/src/curl-ev/form.cpp index a6cbb6894643..9a322e871300 100644 --- a/core/src/curl-ev/form.cpp +++ b/core/src/curl-ev/form.cpp @@ -14,6 +14,7 @@ USERVER_NAMESPACE_BEGIN namespace curl { +#if LIBCURL_VERSION_NUM <= 0x074700 form::form() { impl::CurlGlobal::Init(); } @@ -52,12 +53,7 @@ void form::add_content(std::string_view key, std::string_view content, const std throw_error(ec, "add_content"); } -void form::add_content( - std::string_view key, - std::string_view content, - const std::string& content_type, - std::error_code& ec -) { +void form::add_content(std::string_view key, std::string_view content, const std::string& content_type, std::error_code& ec) { ec = std::error_code{static_cast(native::curl_formadd( &post_, &last_, @@ -75,13 +71,7 @@ void form::add_content( ))}; } -void form::add_buffer( - const std::string& key, - const std::string& file_name, - const char* buffer, - size_t buffer_len, - std::error_code& ec -) { +void form::add_buffer(const std::string& key, const std::string& file_name, const char* buffer, size_t buffer_len, std::error_code& ec) { ec = std::error_code{static_cast(native::curl_formadd( &post_, &last_, @@ -99,44 +89,24 @@ void form::add_buffer( ))}; } -void form::add_buffer( - const std::string& key, - const std::string& file_name, - const std::shared_ptr& buffer -) { +void form::add_buffer(const std::string& key, const std::string& file_name, const std::shared_ptr& buffer) { std::error_code ec; add_buffer(key, file_name, buffer, ec); throw_error(ec, "add_buffer"); } -void form::add_buffer( - const std::string& key, - const std::string& file_name, - const std::shared_ptr& buffer, - std::error_code& ec -) { +void form::add_buffer(const std::string& key, const std::string& file_name, const std::shared_ptr& buffer, std::error_code& ec) { buffers_.push_back(buffer); add_buffer(key, file_name, buffers_.back()->c_str(), buffers_.back()->size(), ec); } -void form::add_buffer( - const std::string& key, - const std::string& file_name, - const std::shared_ptr& buffer, - const std::string& content_type -) { +void form::add_buffer(const std::string& key, const std::string& file_name, const std::shared_ptr& buffer, const std::string& content_type) { std::error_code ec; add_buffer(key, file_name, buffer, content_type, ec); throw_error(ec, "add_buffer"); } -void form::add_buffer( - const std::string& key, - const std::string& file_name, - const std::shared_ptr& buffer, - const std::string& content_type, - std::error_code& ec -) { +void form::add_buffer(const std::string& key, const std::string& file_name, const std::shared_ptr& buffer, const std::string& content_type, std::error_code& ec) { buffers_.push_back(buffer); ec = std::error_code{static_cast(native::curl_formadd( &post_, @@ -163,7 +133,7 @@ void form::add_file(const std::string& key, const std::string& file_path) { throw_error(ec, "add_file"); } -void form::add_file(const std::string& key, const std::string& file_path, std::error_code& ec) { +void form::add_file([[maybe_unused]] const std::string& key, [[maybe_unused]] const std::string& file_path, [[maybe_unused]] std::error_code& ec) { ec = std::error_code{static_cast(native::curl_formadd( &post_, &last_, @@ -183,12 +153,7 @@ void form::add_file(const std::string& key, const std::string& file_path, const throw_error(ec, "add_file"); } -void form::add_file( - const std::string& key, - const std::string& file_path, - const std::string& content_type, - std::error_code& ec -) { +void form::add_file(const std::string& key, const std::string& file_path, const std::string& content_type, std::error_code& ec) { ec = std::error_code{static_cast(native::curl_formadd( &post_, &last_, @@ -210,12 +175,7 @@ void form::add_file_using_name(const std::string& key, const std::string& file_p throw_error(ec, "add_file_using_name"); } -void form::add_file_using_name( - const std::string& key, - const std::string& file_path, - const std::string& file_name, - std::error_code& ec -) { +void form::add_file_using_name(const std::string& key, const std::string& file_path, const std::string& file_name, std::error_code& ec) { ec = std::error_code{static_cast(native::curl_formadd( &post_, &last_, @@ -231,24 +191,13 @@ void form::add_file_using_name( ))}; } -void form::add_file_using_name( - const std::string& key, - const std::string& file_path, - const std::string& file_name, - const std::string& content_type -) { +void form::add_file_using_name(const std::string& key, const std::string& file_path, const std::string& file_name, const std::string& content_type) { std::error_code ec; add_file_using_name(key, file_path, file_name, content_type, ec); throw_error(ec, "add_file_using_name"); } -void form::add_file_using_name( - const std::string& key, - const std::string& file_path, - const std::string& file_name, - const std::string& content_type, - std::error_code& ec -) { +void form::add_file_using_name(const std::string& key, const std::string& file_path, const std::string& file_name, const std::string& content_type, std::error_code& ec) { ec = std::error_code{static_cast(native::curl_formadd( &post_, &last_, @@ -272,7 +221,7 @@ void form::add_file_content(const std::string& key, const std::string& file_path throw_error(ec, "add_file_content"); } -void form::add_file_content(const std::string& key, const std::string& file_path, std::error_code& ec) { +void form::add_file_content([[maybe_unused]] const std::string& key, [[maybe_unused]] const std::string& file_path, [[maybe_unused]] std::error_code& ec) { ec = std::error_code{static_cast(native::curl_formadd( &post_, &last_, @@ -292,12 +241,7 @@ void form::add_file_content(const std::string& key, const std::string& file_path throw_error(ec, "add_file_content"); } -void form::add_file_content( - const std::string& key, - const std::string& file_path, - const std::string& content_type, - std::error_code& ec -) { +void form::add_file_content(const std::string& key, const std::string& file_path, const std::string& content_type, std::error_code& ec) { ec = std::error_code{static_cast(native::curl_formadd( &post_, &last_, @@ -313,6 +257,7 @@ void form::add_file_content( ))}; } +#endif // LIBCURL_VERSION_NUM } // namespace curl USERVER_NAMESPACE_END diff --git a/core/src/curl-ev/form.hpp b/core/src/curl-ev/form.hpp index fcacae37c98c..893539a1f07e 100644 --- a/core/src/curl-ev/form.hpp +++ b/core/src/curl-ev/form.hpp @@ -18,6 +18,7 @@ USERVER_NAMESPACE_BEGIN namespace curl { +#if LIBCURL_VERSION_NUM <= 0x074700 class form { public: form(); @@ -32,82 +33,36 @@ class form { void add_content(std::string_view key, std::string_view content); void add_content(std::string_view key, std::string_view content, std::error_code& ec); void add_content(std::string_view key, std::string_view content, const std::string& content_type); - void - add_content(std::string_view key, std::string_view content, const std::string& content_type, std::error_code& ec); + void add_content(std::string_view key, std::string_view content, const std::string& content_type, std::error_code& ec); void add_buffer(const std::string& key, const std::string& file_name, const std::shared_ptr& buffer); - void add_buffer( - const std::string& key, - const std::string& file_name, - const std::shared_ptr& buffer, - std::error_code& ec - ); - void add_buffer( - const std::string& key, - const std::string& file_name, - const std::shared_ptr& buffer, - const std::string& content_type - ); - void add_buffer( - const std::string& key, - const std::string& file_name, - const std::shared_ptr& buffer, - const std::string& content_type, - std::error_code& ec - ); + void add_buffer(const std::string& key, const std::string& file_name, const std::shared_ptr& buffer, std::error_code& ec); + void add_buffer(const std::string& key, const std::string& file_name, const std::shared_ptr& buffer, const std::string& content_type); + void add_buffer(const std::string& key, const std::string& file_name, const std::shared_ptr& buffer, const std::string& content_type, std::error_code& ec); private: void add_file(const std::string& key, const std::string& file_path); void add_file(const std::string& key, const std::string& file_path, std::error_code& ec); void add_file(const std::string& key, const std::string& file_path, const std::string& content_type); - void add_file( - const std::string& key, - const std::string& file_path, - const std::string& content_type, - std::error_code& ec - ); + void add_file(const std::string& key, const std::string& file_path, const std::string& content_type, std::error_code& ec); + void add_file_using_name(const std::string& key, const std::string& file_path, const std::string& file_name); - void add_file_using_name( - const std::string& key, - const std::string& file_path, - const std::string& file_name, - std::error_code& ec - ); - void add_file_using_name( - const std::string& key, - const std::string& file_path, - const std::string& file_name, - const std::string& content_type - ); - void add_file_using_name( - const std::string& key, - const std::string& file_path, - const std::string& file_name, - const std::string& content_type, - std::error_code& ec - ); + void add_file_using_name(const std::string& key, const std::string& file_path, const std::string& file_name, std::error_code& ec); + void add_file_using_name(const std::string& key, const std::string& file_path, const std::string& file_name, const std::string& content_type); + void add_file_using_name(const std::string& key, const std::string& file_path, const std::string& file_name, const std::string& content_type, std::error_code& ec); + void add_file_content(const std::string& key, const std::string& file_path); void add_file_content(const std::string& key, const std::string& file_path, std::error_code& ec); void add_file_content(const std::string& key, const std::string& file_path, const std::string& content_type); - void add_file_content( - const std::string& key, - const std::string& file_path, - const std::string& content_type, - std::error_code& ec - ); - - void add_buffer( - const std::string& key, - const std::string& file_name, - const char* buffer, - size_t buffer_len, - std::error_code& ec - ); + void add_file_content(const std::string& key, const std::string& file_path, const std::string& content_type, std::error_code& ec); + + void add_buffer(const std::string& key, const std::string& file_name, const char* buffer, size_t buffer_len, std::error_code& ec); native::curl_httppost* post_{nullptr}; native::curl_httppost* last_{nullptr}; std::vector> buffers_; }; +#endif // LIBCURL_VERSION_NUM } // namespace curl diff --git a/core/src/curl-ev/mime.cpp b/core/src/curl-ev/mime.cpp new file mode 100644 index 000000000000..9ef8ef8cea76 --- /dev/null +++ b/core/src/curl-ev/mime.cpp @@ -0,0 +1,23 @@ +// !TODO this @file curl-ev/mime.cpp create in 2025 year // + +#include +#include +#include + +USERVER_NAMESPACE_BEGIN +namespace curl { + +mime::mime(native::curl_mime* mime_ptr) : + mime_(mime_ptr) { + +} + +mime::~mime() { + if (mime_) { + native::curl_mime_free(mime_); + mime_ = nullptr; + } +} + +} // curl namespace +USERVER_NAMESPACE_END \ No newline at end of file diff --git a/core/src/curl-ev/mime.hpp b/core/src/curl-ev/mime.hpp new file mode 100644 index 000000000000..9e05addd5282 --- /dev/null +++ b/core/src/curl-ev/mime.hpp @@ -0,0 +1,36 @@ +#pragma once + +// !TODO this @file curl-ev/mime.cpp create in 2025 year // + +#include +#include +#include + +#include + +USERVER_NAMESPACE_BEGIN + +namespace curl { + +class mime final { +public: + mime(native::curl_mime* mime_ptr); + ~mime(); + + mime(const mime& rhs) = delete; + mime(mime&& rhs) noexcept = default; + + mime& operator= (const mime& rhs) = delete; + mime& operator= (mime&& rhs) noexcept = default; + + inline native::curl_mime* native_mime() { return mime_; } + inline native::curl_mimepart* native_part() { return part_; } + +private: + native::curl_mime* mime_ { nullptr }; + native::curl_mimepart* part_ { nullptr }; +}; + +} // namespace curl + +USERVER_NAMESPACE_END \ No newline at end of file From 64cca454e676ca4203d6aa511e91e2d1838c3dc2 Mon Sep 17 00:00:00 2001 From: xensmo Date: Thu, 13 Mar 2025 22:10:29 +0500 Subject: [PATCH 2/3] Edit and removal comments curl-ev and migrating some deprecation cURL --- build.txt | 17 ++ core/include/userver/clients/http/form.hpp | 5 +- core/include/userver/clients/http/mime.hpp | 17 +- core/include/userver/clients/http/request.hpp | 25 +- core/src/clients/http/client.cpp | 6 +- core/src/clients/http/form.cpp | 3 +- core/src/clients/http/mime.cpp | 21 ++ core/src/clients/http/plugin.cpp | 2 +- core/src/clients/http/request.cpp | 83 +++--- core/src/clients/http/request_state.cpp | 14 +- core/src/clients/http/request_state.hpp | 6 +- core/src/curl-ev/easy.cpp | 88 +++--- core/src/curl-ev/easy.hpp | 279 +++++++++--------- core/src/curl-ev/error_code.cpp | 62 ++-- core/src/curl-ev/error_code.hpp | 23 +- core/src/curl-ev/form.cpp | 4 +- core/src/curl-ev/form.hpp | 2 - core/src/curl-ev/mime.cpp | 99 ++++++- core/src/curl-ev/mime.hpp | 13 +- 19 files changed, 424 insertions(+), 345 deletions(-) create mode 100644 build.txt diff --git a/build.txt b/build.txt new file mode 100644 index 000000000000..9a3299d7daf5 --- /dev/null +++ b/build.txt @@ -0,0 +1,17 @@ +[1/10] Building CXX object core/CMakeFiles/userver-core.dir/src/clients/http/easy_wrapper.cpp.o +[2/10] Building CXX object core/CMakeFiles/userver-core.dir/src/clients/http/plugin.cpp.o +[3/10] Building CXX object core/CMakeFiles/userver-core.dir/src/clients/http/response_future.cpp.o +[4/10] Building CXX object core/CMakeFiles/userver-core.dir/src/clients/http/streamed_response.cpp.o +[5/10] Building CXX object core/CMakeFiles/userver-core.dir/src/clients/http/request.cpp.o +/home/xensmo/userver/core/src/clients/http/request.cpp:352:20: warning: 'set_http_post' is deprecated: Use set_mimepost()) [-Wdeprecated-declarations] + 352 | pimpl_->easy().set_http_post(std::move(form).GetNative()); + | ^ +/home/xensmo/userver/core/src/curl-ev/easy.hpp:456:7: note: 'set_http_post' has been explicitly marked deprecated here + 456 | [[deprecated("Use set_mimepost())")]] + | ^ +1 warning generated. +[6/10] Building CXX object core/CMakeFiles/userver-core.dir/src/curl-ev/multi.cpp.o +[7/10] Building CXX object core/CMakeFiles/userver-core.dir/src/clients/http/client.cpp.o +[8/10] Building CXX object core/CMakeFiles/userver-core.dir/src/curl-ev/easy.cpp.o +[9/10] Building CXX object core/CMakeFiles/userver-core.dir/src/clients/http/request_state.cpp.o +[10/10] Linking CXX static library core/libuserver-core.a diff --git a/core/include/userver/clients/http/form.hpp b/core/include/userver/clients/http/form.hpp index 65ad15016372..453d0d66b7da 100644 --- a/core/include/userver/clients/http/form.hpp +++ b/core/include/userver/clients/http/form.hpp @@ -6,13 +6,11 @@ USERVER_NAMESPACE_BEGIN namespace curl { -#if LIBCURL_VERSION_NUM <= 0x074700 class form; -#endif } // namespace curl namespace clients::http { -#if LIBCURL_VERSION_NUM <= 0x074700 + class Form final { public: Form(); @@ -38,7 +36,6 @@ class Form final { private: std::unique_ptr impl_; }; -#endif // LIBCURL_VERSION_NUM } // namespace clients::http USERVER_NAMESPACE_END diff --git a/core/include/userver/clients/http/mime.hpp b/core/include/userver/clients/http/mime.hpp index ca6e83bd63a4..a2a6abd6208e 100644 --- a/core/include/userver/clients/http/mime.hpp +++ b/core/include/userver/clients/http/mime.hpp @@ -14,14 +14,21 @@ namespace clients::http { Mime(); ~Mime(); - Mime(const Mime& rhs) = delete; - Mime(Mime&& rhs) noexcept = default; + Mime(const Mime&) = delete; + Mime(Mime&&) noexcept; - Mime& operator= (const Mime& rhs) = delete; - Mime& operator= (Mime&& rhs) noexcept = default; + Mime& operator= (const Mime&) = delete; + Mime& operator= (Mime&&) noexcept; public: - [[nodiscard]] inline std::unique_ptr get_native() && { return std::move(mime_); } + void AddContent(std::string_view key, std::string_view content); + void AddContent(std::string_view key, std::string_view content, std::string_view content_type); + + void AddBuffer(std::string_view key, std::string_view name, const std::shared_ptr& buffer); + void AddBuffer(std::string_view key, std::string_view name, std::string_view content_type, const std::shared_ptr& buffer); + + public: + std::unique_ptr GetNative() &&; private: std::unique_ptr mime_; diff --git a/core/include/userver/clients/http/request.hpp b/core/include/userver/clients/http/request.hpp index 2089239f64bb..95db4cf3f82d 100644 --- a/core/include/userver/clients/http/request.hpp +++ b/core/include/userver/clients/http/request.hpp @@ -30,16 +30,13 @@ namespace clients::http { class RequestState; class StreamedResponse; class ConnectTo; +class Form; class Mime; struct DeadlinePropagationConfig; class RequestStats; class DestinationStatistics; struct TestsuiteConfig; -#if LIBCURL_VERSION_NUM <= 0x074700 -class Form; -#endif - namespace impl { class EasyWrapper; } // namespace impl @@ -115,16 +112,12 @@ class Request final { /// POST request with url and data Request& post(std::string url, std::string data = {}) &; Request post(std::string url, std::string data = {}) &&; - /// POST request with url and multipart/form-data -#if LIBCURL_VERSION_NUM <= 0x074700 Request& post(std::string url, Form&& form) &; Request post(std::string url, Form&& form) &&; -#endif - - [[maybe_unused]] Request& post(std::string url, Mime&& mime) &; - [[maybe_unused]] Request post(std::string url, Mime&& mime) &&; - + /// POST request with url and mime + Request& post(std::string url, Mime&& mime) &; + Request post(std::string url, Mime&& mime) &&; /// PUT request Request& put() &; Request put() &&; @@ -159,18 +152,12 @@ class Request final { /// data for POST request Request& data(std::string data) &; Request data(std::string data) &&; - /// form POST request -#if LIBCURL_VERSION_NUM <= 0x074700 Request& form(Form&& form) &; Request form(Form&& form) &&; -#endif - // mime for POST request - [[maybe_unused]] Request& mime(Mime&& mime) &; - [[maybe_unused]] Request mime(Mime&& mime) &&; - - + Request& mime(Mime&& mime) &; + Request mime(Mime&& mime) &&; /// Headers for request as map Request& headers(const Headers& headers) &; Request headers(const Headers& headers) &&; diff --git a/core/src/clients/http/client.cpp b/core/src/clients/http/client.cpp index 6af48e495424..65d836347c1b 100644 --- a/core/src/clients/http/client.cpp +++ b/core/src/clients/http/client.cpp @@ -114,7 +114,7 @@ Request Client::CreateRequest() { auto request = [this] { auto easy = TryDequeueIdle(); if (easy) { - auto idx = FindMultiIndex(easy->get_multi()); + auto idx = FindMultiIndex(easy->GetMulti()); auto wrapper = impl::EasyWrapper{std::move(easy), *this}; return Request{ std::move(wrapper), @@ -129,7 +129,7 @@ Request Client::CreateRequest() { try { auto wrapper = engine::AsyncNoSpan(fs_task_processor_, [this, &multi] { - return impl::EasyWrapper { easy_.Get()->get_bound_blocking(*multi), *this }; + return impl::EasyWrapper { easy_.Get()->GetBoundBlocking(*multi), *this }; }).Get(); return Request{ std::move(wrapper), @@ -185,7 +185,7 @@ std::string Client::GetProxy() const { return proxy_.ReadCopy(); } void Client::SetDnsResolver(clients::dns::Resolver* resolver) { resolver_ = resolver; } void Client::ReinitEasy() { - easy_.Set(utils::CriticalAsync(fs_task_processor_, "http_easy_reinit", &curl::easy::create_easy_blocking).Get()); + easy_.Set(utils::CriticalAsync(fs_task_processor_, "http_easy_reinit", &curl::easy::CreateBlocking).Get()); } InstanceStatistics Client::GetMultiStatistics(size_t n) const { diff --git a/core/src/clients/http/form.cpp b/core/src/clients/http/form.cpp index 6dca80ec4cb1..c48fa2d8ae8c 100644 --- a/core/src/clients/http/form.cpp +++ b/core/src/clients/http/form.cpp @@ -5,7 +5,6 @@ USERVER_NAMESPACE_BEGIN namespace clients::http { -#if LIBCURL_VERSION_NUM <= 0x074700 Form::Form() : impl_(std::make_unique()) { } Form::~Form() = default; @@ -28,7 +27,7 @@ void Form::AddBuffer(const std::string& key, const std::string& file_name, } std::unique_ptr Form::GetNative() && { return std::move(impl_); } -#endif // LIBCURL_VERSION_NUM + } // namespace clients::http USERVER_NAMESPACE_END diff --git a/core/src/clients/http/mime.cpp b/core/src/clients/http/mime.cpp index f8b26c2127bf..a72c69ef5a26 100644 --- a/core/src/clients/http/mime.cpp +++ b/core/src/clients/http/mime.cpp @@ -11,6 +11,27 @@ Mime::~Mime() { } +Mime::Mime(Mime&&) noexcept = default; +Mime& Mime::operator= (Mime&&) noexcept = default; + +std::unique_ptr Mime::GetNative() && { return std::move(mime_); } + +void Mime::AddContent(std::string_view key, std::string_view content) { + mime_->add_content(key, content); } +void Mime::AddContent(std::string_view key, std::string_view content, std::string_view content_type) { + mime_->add_content(key, content, content_type); +} + +void Mime::AddBuffer(std::string_view key, std::string_view name, const std::shared_ptr& buffer) { + mime_->add_buffer(key, name, buffer); +} + +void Mime::AddBuffer(std::string_view key, std::string_view name, std::string_view content_type, const std::shared_ptr& buffer) { + mime_->add_buffer(key, name, content_type, buffer); +} + +} // namespace clients::http + USERVER_NAMESPACE_END \ No newline at end of file diff --git a/core/src/clients/http/plugin.cpp b/core/src/clients/http/plugin.cpp index 210cfc6a1bd3..f4d937e019fb 100644 --- a/core/src/clients/http/plugin.cpp +++ b/core/src/clients/http/plugin.cpp @@ -12,7 +12,7 @@ PluginRequest::PluginRequest(RequestState& state) : state_(state) {} void PluginRequest::SetHeader(std::string_view name, std::string_view value) { state_.easy().add_header( - name, value, curl::detail::empty_header_action::kDoNotSend, curl::detail::duplicate_header_action::kReplace + name, value, curl::easy::EmptyHeaderAction::kDoNotSend, curl::easy::DuplicateHeaderAction::kReplace ); } diff --git a/core/src/clients/http/request.cpp b/core/src/clients/http/request.cpp index 4030d1797d6c..4cf0d82b3677 100644 --- a/core/src/clients/http/request.cpp +++ b/core/src/clients/http/request.cpp @@ -7,12 +7,9 @@ #include #include -#if LIBCURL_VERSION_NUM <= 0x074700 -#include -#endif - #include #include +#include #include #include #include @@ -44,20 +41,20 @@ constexpr std::string_view kHeaderExpect = "Expect"; std::string ToString(HttpMethod method) { return std::string{ToStringView(method)}; } -curl::detail::http_version_t ToNative(HttpVersion version) { +curl::easy::http_version_t ToNative(HttpVersion version) { switch (version) { case HttpVersion::kDefault: - return curl::detail::http_version_t::http_version_none; + return curl::easy::http_version_t::http_version_none; case HttpVersion::k10: - return curl::detail::http_version_t::http_version_1_0; + return curl::easy::http_version_t::http_version_1_0; case HttpVersion::k11: - return curl::detail::http_version_t::http_version_1_1; + return curl::easy::http_version_t::http_version_1_1; case HttpVersion::k2: - return curl::detail::http_version_t::http_version_2_0; + return curl::easy::http_version_t::http_version_2_0; case HttpVersion::k2Tls: - return curl::detail::http_version_t::http_version_2tls; + return curl::easy::http_version_t::http_version_2tls; case HttpVersion::k2PriorKnowledge: - return curl::detail::http_version_t::http_version_2_prior_knowledge; + return curl::easy::http_version_t::http_version_2_prior_knowledge; } UINVARIANT(false, "Unexpected HTTP version"); @@ -76,49 +73,49 @@ constexpr utils::TrivialBiMap kAuthTypeMap = [](auto selector) { .Case("any_safe", ProxyAuthType::kAnySafe); }; -curl::detail::httpauth_t HttpAuthTypeToNative(HttpAuthType value) { +curl::easy::httpauth_t HttpAuthTypeToNative(HttpAuthType value) { switch (value) { case HttpAuthType::kBasic: - return curl::detail::httpauth_t::auth_basic; + return curl::easy::httpauth_t::auth_basic; case HttpAuthType::kDigest: - return curl::detail::httpauth_t::auth_digest; + return curl::easy::httpauth_t::auth_digest; case HttpAuthType::kDigestIE: - return curl::detail::httpauth_t::auth_digest_ie; + return curl::easy::httpauth_t::auth_digest_ie; case HttpAuthType::kNegotiate: - return curl::detail::httpauth_t::auth_negotiate; + return curl::easy::httpauth_t::auth_negotiate; case HttpAuthType::kNtlm: - return curl::detail::httpauth_t::auth_ntlm; + return curl::easy::httpauth_t::auth_ntlm; case HttpAuthType::kNtlmWb: - return curl::detail::httpauth_t::auth_ntlm_wb; + return curl::easy::httpauth_t::auth_ntlm_wb; case HttpAuthType::kAny: - return curl::detail::httpauth_t::auth_any; + return curl::easy::httpauth_t::auth_any; case HttpAuthType::kAnySafe: - return curl::detail::httpauth_t::auth_any_safe; + return curl::easy::httpauth_t::auth_any_safe; } UINVARIANT(false, "Unexpected http auth type"); } -curl::detail::proxyauth_t ProxyAuthTypeToNative(ProxyAuthType value) { +curl::easy::proxyauth_t ProxyAuthTypeToNative(ProxyAuthType value) { switch (value) { case ProxyAuthType::kBasic: - return curl::detail::proxyauth_t::proxy_auth_basic; + return curl::easy::proxyauth_t::proxy_auth_basic; case ProxyAuthType::kDigest: - return curl::detail::proxyauth_t::proxy_auth_digest; + return curl::easy::proxyauth_t::proxy_auth_digest; case ProxyAuthType::kDigestIE: - return curl::detail::proxyauth_t::proxy_auth_digest_ie; + return curl::easy::proxyauth_t::proxy_auth_digest_ie; case ProxyAuthType::kBearer: - return curl::detail::proxyauth_t::proxy_auth_bearer; + return curl::easy::proxyauth_t::proxy_auth_bearer; case ProxyAuthType::kNegotiate: - return curl::detail::proxyauth_t::proxy_auth_negotiate; + return curl::easy::proxyauth_t::proxy_auth_negotiate; case ProxyAuthType::kNtlm: - return curl::detail::proxyauth_t::proxy_auth_ntlm; + return curl::easy::proxyauth_t::proxy_auth_ntlm; case ProxyAuthType::kNtlmWb: - return curl::detail::proxyauth_t::proxy_auth_ntlm_wb; + return curl::easy::proxyauth_t::proxy_auth_ntlm_wb; case ProxyAuthType::kAny: - return curl::detail::proxyauth_t::proxy_auth_any; + return curl::easy::proxyauth_t::proxy_auth_any; case ProxyAuthType::kAnySafe: - return curl::detail::proxyauth_t::proxy_auth_anysafe; + return curl::easy::proxyauth_t::proxy_auth_anysafe; } UINVARIANT(false, "Unexpected proxy auth type"); @@ -327,13 +324,13 @@ Request& Request::unix_socket_path(const std::string& path) & { Request Request::unix_socket_path(const std::string& path) && { return std::move(this->unix_socket_path(path)); } Request& Request::use_ipv4() & { - pimpl_->easy().set_ip_resolve(curl::detail::ip_resolve_t::ip_resolve_v4); + pimpl_->easy().set_ip_resolve(curl::easy::ip_resolve_t::ip_resolve_v4); return *this; } Request Request::use_ipv4() && { return std::move(this->use_ipv4()); } Request& Request::use_ipv6() & { - pimpl_->easy().set_ip_resolve(curl::detail::ip_resolve_t::ip_resolve_v6); + pimpl_->easy().set_ip_resolve(curl::easy::ip_resolve_t::ip_resolve_v6); return *this; } Request Request::use_ipv6() && { return std::move(this->use_ipv6()); } @@ -345,30 +342,27 @@ Request& Request::connect_to(const ConnectTo& connect_to) & { Request Request::connect_to(const ConnectTo& connect_to) && { return std::move(this->connect_to(connect_to)); } Request& Request::data(std::string data) & { - if (!data.empty()) pimpl_->easy().add_header(kHeaderExpect, "", curl::detail::empty_header_action::kDoNotSend); + if (!data.empty()) pimpl_->easy().add_header(kHeaderExpect, "", curl::easy::EmptyHeaderAction::kDoNotSend); pimpl_->easy().set_post_fields(std::move(data)); return *this; } Request Request::data(std::string data) && { return std::move(this->data(std::move(data))); } -#if LIBCURL_VERSION_NUM <= 0x074700 Request& Request::form(Form&& form) & { pimpl_->easy().set_http_post(std::move(form).GetNative()); - pimpl_->easy().add_header(kHeaderExpect, "", curl::detail::empty_header_action::kDoNotSend); + pimpl_->easy().add_header(kHeaderExpect, "", curl::easy::EmptyHeaderAction::kDoNotSend); return *this; } Request Request::form(Form&& form) && { return std::move(this->form(std::move(form))); } -#endif -////////////////////////////////////////////////////////////////////////////////////////////////! -/* Request& Request::mime(Mime&& mime) & { - pimpl_->easy().set_mimepost(std::move(mime).get_native()); - pimpl_->easy().add_header(kHeaderExpect, "", curl::detail::empty_header_action::kDoNotSend); +Request& Request::mime(Mime&& mime) & { + pimpl_->easy().set_mimepost(std::move(mime).GetNative()); + pimpl_->easy().add_header(kHeaderExpect, "", curl::easy::EmptyHeaderAction::kDoNotSend); return *this; } -Request Request::mime(Mime&& mime) && { return std::move(this->mime(std::move(mime))); }; */ +Request Request::mime(Mime&& mime) && { return std::move(this->mime(std::move(mime))); }; Request& Request::headers(const Headers& headers) & { SetHeaders(pimpl_->easy(), headers); @@ -503,16 +497,13 @@ Request Request::get(std::string url) && { return std::move(this->get(std::move( Request& Request::head(std::string url) & { return head().url(std::move(url)); } Request Request::head(std::string url) && { return std::move(this->head(std::move(url))); } -#if LIBCURL_VERSION_NUM <= 0x074700 Request& Request::post(std::string url, Form&& form) & { return this->url(std::move(url)).form(std::move(form)); } Request Request::post(std::string url, Form&& form) && { return std::move(this->post(std::move(url), std::move(form))); } -#endif -////////////////////////////////////////////////////////////////////////////////////////////////////////////////! -//Request& Request::post(std::string url, Mime&& mime) & { return this->url(std::move(url)).mime(std::move(mime)); } -//Request Request::post(std::string url, Mime&& mime) && { return std::move(this->post(std::move(url), std::move(mime))); } +Request& Request::post(std::string url, Mime&& mime) & { return this->url(std::move(url)).mime(std::move(mime)); } +Request Request::post(std::string url, Mime&& mime) && { return std::move(this->post(std::move(url), std::move(mime))); } Request& Request::post(std::string url, std::string data) & { return this->url(std::move(url)).data(std::move(data)).post(); diff --git a/core/src/clients/http/request_state.cpp b/core/src/clients/http/request_state.cpp index 2ddb482117bf..347bb185bb0b 100644 --- a/core/src/clients/http/request_state.cpp +++ b/core/src/clients/http/request_state.cpp @@ -114,8 +114,8 @@ void SetBaggageHeader(curl::easy& e) { e.add_header( USERVER_NAMESPACE::http::headers::kXBaggage, std::string_view(baggage->ToString()), - curl::detail::empty_header_action::kDoNotSend, - curl::detail::duplicate_header_action::kReplace + curl::easy::EmptyHeaderAction::kDoNotSend, + curl::easy::DuplicateHeaderAction::kReplace ); } } @@ -335,7 +335,7 @@ void RequestState::client_key_cert(crypto::PrivateKey pkey, crypto::Certificate } } -void RequestState::http_version(curl::detail::http_version_t version) { easy().set_http_version(version); } +void RequestState::http_version(curl::easy::http_version_t version) { easy().set_http_version(version); } void RequestState::set_timeout(long timeout_ms) { original_timeout_ = std::chrono::milliseconds{timeout_ms}; @@ -362,10 +362,10 @@ void RequestState::proxy(const std::string& value) { easy().set_proxy(std::string_view(value)); } -void RequestState::proxy_auth_type(curl::detail::proxyauth_t value) { easy().set_proxy_auth(value); } +void RequestState::proxy_auth_type(curl::easy::proxyauth_t value) { easy().set_proxy_auth(value); } void RequestState::http_auth_type( - curl::detail::httpauth_t value, + curl::easy::httpauth_t value, bool auth_only, std::string_view user, std::string_view password @@ -567,7 +567,7 @@ void RequestState::on_retry(std::shared_ptr holder, std::error_cod ++holder->retry_.current; holder->easy().mark_retry(); - holder->retry_.timer.emplace(holder->easy().get_thread_control()); + holder->retry_.timer.emplace(holder->easy().GetThreadControl()); // call on_retry_timer on timer auto& holder_ref = *holder; @@ -785,7 +785,7 @@ void RequestState::UpdateTimeoutHeader() { easy().add_header( USERVER_NAMESPACE::http::headers::kXYaTaxiClientTimeoutMs, fmt::to_string(remote_timeout_.count()), - curl::detail::duplicate_header_action::kReplace + curl::easy::DuplicateHeaderAction::kReplace ); } diff --git a/core/src/clients/http/request_state.hpp b/core/src/clients/http/request_state.hpp index d409ae6a7bc4..c0312b473738 100644 --- a/core/src/clients/http/request_state.hpp +++ b/core/src/clients/http/request_state.hpp @@ -77,7 +77,7 @@ class RequestState : public std::enable_shared_from_this { /// set private key and certificate from memory void client_key_cert(crypto::PrivateKey pkey, crypto::Certificate cert); /// Set HTTP version - void http_version(curl::detail::http_version_t version); + void http_version(curl::easy::http_version_t version); /// set timeout value void set_timeout(long timeout_ms); /// set number of retries @@ -89,9 +89,9 @@ class RequestState : public std::enable_shared_from_this { /// sets proxy to use void proxy(const std::string& value); /// sets proxy auth type to use - void proxy_auth_type(curl::detail::proxyauth_t value); + void proxy_auth_type(curl::easy::proxyauth_t value); /// sets proxy auth type and credentials to use - void http_auth_type(curl::detail::httpauth_t value, bool auth_only, std::string_view user, std::string_view password); + void http_auth_type(curl::easy::httpauth_t value, bool auth_only, std::string_view user, std::string_view password); /// get timeout value in milliseconds long timeout() const { return original_timeout_.count(); } diff --git a/core/src/curl-ev/easy.cpp b/core/src/curl-ev/easy.cpp index 987bff555891..d279859d7a1b 100644 --- a/core/src/curl-ev/easy.cpp +++ b/core/src/curl-ev/easy.cpp @@ -6,8 +6,6 @@ C++ wrapper for libcurl's easy interface */ -// !TODO this @file curl-ev/easy.hpp full upgrade in 2025 year // - #include #include @@ -34,19 +32,16 @@ USERVER_NAMESPACE_BEGIN namespace curl { namespace detail { - using detail_eha = empty_header_action; - using detail_dha = duplicate_header_action; - bool is_header_matching_name(std::string_view header, std::string_view name) { return header.size() > name.size() && utils::StrIcaseEqual()(header.substr(0, name.size()), name) && (header[name.size()] == ':' || header[name.size()] == ';'); } fmt::memory_buffer - create_header_buffer(std::string_view name, std::string_view value, detail_eha eha) { + create_header_buffer(std::string_view name, std::string_view value, easy::EmptyHeaderAction eha) { fmt::memory_buffer fmt_mem_buf; - if (eha == detail_eha::kSend && value.empty()) + if (eha == easy::EmptyHeaderAction::kSend && value.empty()) fmt::format_to(std::back_inserter(fmt_mem_buf), FMT_COMPILE("{};"), name); else fmt::format_to(std::back_inserter(fmt_mem_buf), FMT_COMPILE("{}: {}"), name, value); @@ -74,15 +69,15 @@ namespace detail { return result; } - bool add_header_do_skip(const std::shared_ptr& headers, std::string_view name, detail_dha dha) { - if (dha == detail_dha::kSkip && headers) + bool add_header_do_skip(const std::shared_ptr& headers, std::string_view name, easy::DuplicateHeaderAction dha) { + if (dha == easy::DuplicateHeaderAction::kSkip && headers) find_header_by_name(headers, name); return false; } bool add_header_do_replace(const std::shared_ptr& headers, const fmt::memory_buffer& mem_buf, - std::string_view name, detail_dha dha) { - if (dha == detail_dha::kReplace && headers) { + std::string_view name, easy::DuplicateHeaderAction dha) { + if (dha == easy::DuplicateHeaderAction::kReplace && headers) { const bool replaced = headers->ReplaceFirstIf([name](std::string_view header) { return is_header_matching_name(header, name); }, mem_buf.data()); @@ -203,7 +198,7 @@ easy::~easy() { } } -std::shared_ptr easy::create_easy_blocking() { +std::shared_ptr easy::CreateBlocking() { impl::CurlGlobal::Init(); // Note: curl_easy_init() is blocking. @@ -216,7 +211,7 @@ std::shared_ptr easy::create_easy_blocking() { return std::make_shared(handle_ptr, mime_ptr, nullptr); } -std::shared_ptr easy::get_bound_blocking(multi& multi_handle) const { +std::shared_ptr easy::GetBoundBlocking(multi& multi_handle) const { // Note: curl_easy_init() is blocking. auto* cloned_easy = native::curl_easy_duphandle(easy_handle_); if (!cloned_easy) @@ -235,7 +230,7 @@ easy* easy::from_native(native::CURL* native_easy) { return easy_handle; } -engine::ev::ThreadControl& easy::get_thread_control() { +engine::ev::ThreadControl& easy::GetThreadControl() { return multi_handle_->GetThreadControl(); } @@ -412,15 +407,15 @@ bool easy::has_post_data() const { return !post_fields_.empty() || mime_; } -void easy::add_header(std::string_view name, std::string_view value, detail_eha eha, detail_dha dha) { +void easy::add_header(std::string_view name, std::string_view value, EmptyHeaderAction eha, DuplicateHeaderAction dha) { if (detail::add_header_do_skip(headers_, name, dha)) { return; } auto buffer = detail::create_header_buffer(name, value, eha); if (detail::add_header_do_replace(headers_, buffer, name, dha)) { return; } add_header(buffer.data()); } -void easy::add_header(std::string_view name, std::string_view value, detail_dha dha) { - add_header(name, value, detail_eha::kSend, dha); +void easy::add_header(std::string_view name, std::string_view value, DuplicateHeaderAction dha) { + add_header(name, value, EmptyHeaderAction::kSend, dha); } void easy::add_header(const char* header) { @@ -437,7 +432,7 @@ void easy::add_header(const std::string& header) { add_header(header.c_str()); } -void easy::add_proxy_header(std::string_view name, std::string_view value, detail_eha eha, detail_dha dha) { +void easy::add_proxy_header(std::string_view name, std::string_view value, EmptyHeaderAction eha, DuplicateHeaderAction dha) { if (detail::add_header_do_skip(proxy_headers_, name, dha)) { return; } auto buffer = detail::create_header_buffer(name, value, eha); if (detail::add_header_do_replace(proxy_headers_, buffer, name, dha)) { return; } @@ -496,7 +491,7 @@ void easy::add_http200_alias(const std::string& http200_alias) { throw_error(ec, "add_http200_alias"); } -std::optional easy::find_header_by_name(std::string_view name) const { +std::optional easy::FindHeaderByName(std::string_view name) const { return detail::find_header_by_name(headers_, name); } @@ -881,18 +876,18 @@ void easy::set_proxy_password(std::string_view sv) { "set_proxy_password", easy_handle_, native::CURLOPT_PROXYPASSWORD, sv.data()); } -void easy::set_netrc(detail::netrc_t netrc) { +void easy::set_netrc(netrc_t netrc) { detail::set_curl_opt( "set_netrc", easy_handle_, native::CURLOPT_NETRC, detail::to_integral(netrc)); } -void easy::set_http_auth(detail::httpauth_t httpauth, bool auth_only) { +void easy::set_http_auth(httpauth_t httpauth, bool auth_only) { auto result = detail::to_integral(httpauth) | (auth_only ? CURLAUTH_ONLY : 0UL); detail::set_curl_opt( "set_http_auth", easy_handle_, native::CURLOPT_HTTPAUTH, result); } -void easy::set_proxy_auth(detail::proxyauth_t proxyauth) { +void easy::set_proxy_auth(proxyauth_t proxyauth) { detail::set_curl_opt( "set_proxy_auth", easy_handle_, native::CURLOPT_PROXYAUTH, detail::to_integral(proxyauth)); } @@ -1012,12 +1007,12 @@ void easy::set_cookie_jar(std::string_view sv) { "set_cookie_jar", easy_handle_, native::CURLOPT_COOKIEJAR, sv.data()); } -void easy::set_http_version(detail::http_version_t version) { +void easy::set_http_version(http_version_t version) { detail::set_curl_opt( "set_http_version", easy_handle_, native::CURLOPT_HTTP_VERSION, detail::to_integral(version)); } -void easy::set_time_condition(detail::time_condition_t condition) { +void easy::set_time_condition(time_condition_t condition) { detail::set_curl_opt( "set_time_condition", easy_handle_, native::CURLOPT_TIMECONDITION, detail::to_integral(condition)); } @@ -1092,7 +1087,7 @@ void easy::set_dns_servers(std::string_view sv) { "set_dns_servers", easy_handle_, native::CURLOPT_DNS_SERVERS, sv.data()); } -void easy::set_ip_resolve(detail::ip_resolve_t resolve) { +void easy::set_ip_resolve(ip_resolve_t resolve) { detail::set_curl_opt( "set_ip_resolve", easy_handle_, native::CURLOPT_IPRESOLVE, detail::to_integral(resolve)); } @@ -1239,12 +1234,12 @@ void easy::set_ssl_verify_host(bool state) { throw_error(ec, "set_ssl_verify_host"); } -void easy::set_ssl_version(detail::ssl_version_t version) { +void easy::set_ssl_version(ssl_version_t version) { detail::set_curl_opt( "set_ssl_version", easy_handle_, native::CURLOPT_SSLVERSION, detail::to_integral(version)); } -void easy::set_use_ssl(detail::use_ssl_t ssl) { +void easy::set_use_ssl(use_ssl_t ssl) { detail::set_curl_opt( "set_use_ssl", easy_handle_, native::CURLOPT_USE_SSL, detail::to_integral(ssl)); } @@ -1771,30 +1766,27 @@ native::curl_socket_t easy::open_tcp_socket(struct native::curl_sockaddr* addres return fd; } -#if LIBCURL_VERSION_NUM <= 0x074700 - void easy::set_http_post(std::unique_ptr form_ptr>) { - form_ = std::move(form); - if (form_) { - std::error_code ec = detail::set_curl_opt( - easy_handle_, native::CURLOPT_HTTPPOST, form_->native_handle()); - throw_error(ec, "set_http_post native_handle failed!"); - } else { - std::error_code ec = detail::set_curl_opt( - easy_handle_, native::CURLOPT_HTTPPOST, nullptr); - throw_error(ec, "set_http_post nullptr failed!"); - } +void easy::set_http_post(std::unique_ptr form_ptr) { + form_ = std::move(form_ptr); + if (form_) { + std::error_code ec = detail::set_curl_opt( + easy_handle_, native::CURLOPT_HTTPPOST, form_->native_handle()); + throw_error(ec, "set_http_post native_handle failed!"); + } else { + std::error_code ec = detail::set_curl_opt( + easy_handle_, native::CURLOPT_HTTPPOST, nullptr); + throw_error(ec, "set_http_post nullptr failed!"); } +} - void easy::set_egd_socket(std::string_view sv) { - detail::set_curl_opt("set_egd_socket", easy_handle_, native::CURLOPT_EGDSOCKET, sv.data()); - } +void easy::set_egd_socket(std::string_view sv) { + detail::set_curl_opt("set_egd_socket", easy_handle_, native::CURLOPT_EGDSOCKET, sv.data()); +} - long easy::get_protocol() { - return detail::get_curl_info_long( - "get_protocol", easy_handle_, native::CURLINFO_PROTOCOL); - } - -#endif +long easy::get_protocol() { + return detail::get_curl_info_long( + "get_protocol", easy_handle_, native::CURLINFO_PROTOCOL); +} } // namespace curl diff --git a/core/src/curl-ev/easy.hpp b/core/src/curl-ev/easy.hpp index 8fccd7421af8..a792752da9cd 100644 --- a/core/src/curl-ev/easy.hpp +++ b/core/src/curl-ev/easy.hpp @@ -8,8 +8,6 @@ C++ wrapper for libcurl's easy interface */ -// !TODO this @file curl-ev/easy.hpp full upgrade in 2025 year // - #include #include #include @@ -20,6 +18,8 @@ #include #include +#include +#include #include #include #include @@ -35,23 +35,43 @@ namespace engine::ev { class ThreadControl; } // namespace engine::ev +#ifdef CURL_SSLVERSION_DEFAULT +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define CURL_SSLVERSION_NAMESPACE +#else +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define CURL_SSLVERSION_NAMESPACE native:: +#endif + namespace curl { class multi; class share; class string_list; -namespace detail { - enum class empty_header_action { kSend, kDoNotSend }; - enum class duplicate_header_action { kAdd, kSkip, kReplace }; +class easy final : public std::enable_shared_from_this { +public: + explicit easy(native::CURL* easy_handle, native::curl_mime* mime_ptr, multi* multi_ptr); + + easy(const easy& rhs) = delete; + easy(easy&& rhs) = delete; + + easy& operator= (const easy& rhs) = delete; + easy& operator= (easy&& rhs) = delete; + + ~easy(); + +public: + enum class EmptyHeaderAction { kSend, kDoNotSend }; + enum class DuplicateHeaderAction { kAdd, kSkip, kReplace }; enum class http_version_t : unsigned long { http_version_none = native::CURL_HTTP_VERSION_NONE, http_version_1_0 = native::CURL_HTTP_VERSION_1_0, http_version_1_1 = native::CURL_HTTP_VERSION_1_1, http_version_2_0 = native::CURL_HTTP_VERSION_2_0, http_version_2tls = native::CURL_HTTP_VERSION_2TLS, - http_version_2_prior_knowledge = native::CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE, - http_version_3_0 = native::CURL_HTTP_VERSION_3, - http_version_3_0_only = native::CURL_HTTP_VERSION_3ONLY + http_version_2_prior_knowledge = native::CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE + // !http_version_3_0 = native::CURL_HTTP_VERSION_3, // important, uncomments next feature + // !http_version_3_0_only = native::CURL_HTTP_VERSION_3ONLY // version userver supports HTTP/3 }; enum class ssl_version_t : unsigned long { ssl_version_default = native::CURL_SSLVERSION_DEFAULT, @@ -100,26 +120,7 @@ namespace detail { proxy_auth_any = CURLAUTH_ANY, proxy_auth_anysafe = CURLAUTH_ANYSAFE }; -} // namespace detail -/************************************************************* - * * cURL easy wrapper class - * * @class easy - * TODO: @brief curl-ev wrapper shared class for libcurl - ************************************************************/ -class easy final : public std::enable_shared_from_this { -public: - explicit easy(native::CURL* easy_handle, native::curl_mime* mime_ptr, multi* multi_ptr); - - easy(const easy& rhs) = delete; - easy(easy&& rhs) noexcept = default; - - easy& operator= (const easy& rhs) noexcept = default; - easy& operator= (easy&& rhs) noexcept = default; - - ~easy(); - -public: using time_point = std::chrono::steady_clock::time_point; using handler_type = std::function; @@ -131,16 +132,16 @@ class easy final : public std::enable_shared_from_this { void reset(); void mark_retry(); -// public sys void handle_completion(const std::error_code& ec); void set_share(std::shared_ptr share); -// public static static easy* from_native(native::CURL* native_easy); - static std::shared_ptr create_easy_blocking(); + [[nodiscard]] static std::shared_ptr CreateBlocking(); + + [[nodiscard]] std::shared_ptr GetBoundBlocking(multi& multi_handle) const; + engine::ev::ThreadControl& GetThreadControl(); -// public std::error_code rate_limit_error() const; time_point::duration time_to_start() const; clients::http::LocalStats get_local_stats(); @@ -150,29 +151,25 @@ class easy final : public std::enable_shared_from_this { bool has_post_data() const; -// public inline inline native::CURL* native_handle() { return easy_handle_; } - inline const multi* get_multi() const { return multi_handle_; } + inline const multi* GetMulti() const { return multi_handle_; } inline bool operator<(const easy& other) const { return (this < &other); } public: - using detail_eha = detail::empty_header_action; - using detail_dha = detail::duplicate_header_action; - void add_header(std::string_view name, std::string_view value, - detail_eha eha = detail_eha::kSend, detail_dha dha = detail_dha::kAdd); - void add_header(std::string_view name, std::string_view value, detail_dha dha); + EmptyHeaderAction eha = EmptyHeaderAction::kSend, DuplicateHeaderAction dha = DuplicateHeaderAction::kAdd); + void add_header(std::string_view name, std::string_view value, DuplicateHeaderAction dha); void add_header(const char* header); void add_header(const std::string& header); void add_proxy_header(std::string_view name, std::string_view value, - detail_eha = detail_eha::kSend, detail_dha = detail_dha::kAdd); + EmptyHeaderAction = EmptyHeaderAction::kSend, DuplicateHeaderAction = DuplicateHeaderAction::kAdd); void add_proxy_header(const char* header); void add_proxy_header(const std::string& header); void add_resolve(const std::string& host, const std::string& port, const std::string& addr); void add_http200_alias(const std::string& http200_alias); - std::optional find_header_by_name(std::string_view name) const; + std::optional FindHeaderByName(std::string_view name) const; public: /// cURL Opt setters @@ -180,18 +177,18 @@ class easy final : public std::enable_shared_from_this { void set_header(bool state); void set_no_progress(bool state); void set_no_signal(bool state); - void set_wildcard_match(bool state); + [[maybe_unused]] void set_wildcard_match(bool state); void set_post(bool state); - void set_source(std::shared_ptr source); + [[maybe_unused]] void set_source(std::shared_ptr source); void set_sink(std::string* sink); void set_private(void* ptr); void set_custom_request(const std::string& str); - void set_new_directory_perms(long perms); - void set_new_file_perms(long perms); + [[maybe_unused]] void set_new_directory_perms(long perms); + [[maybe_unused]] void set_new_file_perms(long perms); void set_url(std::string&& url_str, std::error_code& ec); - void set_progress_data(void* ptr); + [[maybe_unused]] void set_progress_data(void* ptr); void set_error_buffer(char* buffer); void set_stderr(FILE* file); @@ -200,109 +197,109 @@ class easy final : public std::enable_shared_from_this { void set_mimepost(std::unique_ptr mime_ptr); // * puplic http setters @fn set_* @return none - void set_http_proxy_tunnel(bool state); - void set_socks5_gsapi_nec(bool state); - void set_tcp_no_delay(bool state); - void set_tcp_keep_alive(bool state); - void set_auto_referrer(bool state); + [[maybe_unused]] void set_http_proxy_tunnel(bool state); + [[maybe_unused]] void set_socks5_gsapi_nec(bool state); + [[maybe_unused]] void set_tcp_no_delay(bool state); + [[maybe_unused]] void set_tcp_keep_alive(bool state); + [[maybe_unused]] void set_auto_referrer(bool state); void set_follow_location(bool state); - void set_unrestricted_auth(bool state); + [[maybe_unused]] void set_unrestricted_auth(bool state); void set_max_redirs(long value); void set_post_redir(long value); - void set_post_field_size(long value); - void set_proxy_port(long value); - void set_proxy_type(long value); - void set_local_port(long value); - void set_local_port_range(long value); - void set_dns_cache_timeout(long value); - void set_buffer_size(long value); - void set_port(long value); - void set_address_scope(long value); - void set_tcp_keep_idle(long value); - void set_tcp_keep_intvl(long value); + [[maybe_unused]] void set_post_field_size(long value); + [[maybe_unused]] void set_proxy_port(long value); + [[maybe_unused]] void set_proxy_type(long value); + [[maybe_unused]] void set_local_port(long value); + [[maybe_unused]] void set_local_port_range(long value); + [[maybe_unused]] void set_dns_cache_timeout(long value); + [[maybe_unused]] void set_buffer_size(long value); + [[maybe_unused]] void set_port(long value); + [[maybe_unused]] void set_address_scope(long value); + [[maybe_unused]] void set_tcp_keep_idle(long value); + [[maybe_unused]] void set_tcp_keep_intvl(long value); void set_connect_to(native::curl_slist* slist); void set_post_field_size_large(native::curl_off_t value); void set_post_fields(void* ptr); void set_post_fields(std::string&& post_fields); void set_proxy(std::string_view sv); - void set_interface(std::string_view sv); + [[maybe_unused]] void set_interface(std::string_view sv); void set_unix_socket_path(std::string_view sv); - void set_no_proxy(std::string_view sv); + [[maybe_unused]] void set_no_proxy(std::string_view sv); void set_accept_encoding(std::string_view sv); - void set_transfer_encoding(std::string_view sv); - void set_referer(std::string_view sv); + [[maybe_unused]] void set_transfer_encoding(std::string_view sv); + [[maybe_unused]] void set_referer(std::string_view sv); void set_user_agent(std::string_view sv); - void set_protocols_str(std::string_view sv); - void set_redir_protocols_str(std::string_view sv); - void set_headers(std::shared_ptr headers); - void set_http200_aliases(std::shared_ptr http200_aliases); + [[maybe_unused]] void set_protocols_str(std::string_view sv); + [[maybe_unused]] void set_redir_protocols_str(std::string_view sv); + [[maybe_unused]] void set_headers(std::shared_ptr headers); + [[maybe_unused]] void set_http200_aliases(std::shared_ptr http200_aliases); // * puplic auth setters @fn set_* @return none - void set_tls_auth_type(long value); - void set_tls_auth_user(std::string_view sv); - void set_tls_auth_password(std::string_view sv); - void set_netrc_file(std::string_view sv); + [[maybe_unused]] void set_tls_auth_type(long value); + [[maybe_unused]] void set_tls_auth_user(std::string_view sv); + [[maybe_unused]] void set_tls_auth_password(std::string_view sv); + [[maybe_unused]] void set_netrc_file(std::string_view sv); void set_user(std::string_view sv); void set_password(std::string_view sv); - void set_proxy_user(std::string_view sv); - void set_proxy_password(std::string_view sv); - void set_netrc(detail::netrc_t netrc); - void set_http_auth(detail::httpauth_t httpauth, bool auth_only); - void set_proxy_auth(detail::proxyauth_t proxyauth); + [[maybe_unused]] void set_proxy_user(std::string_view sv); + [[maybe_unused]] void set_proxy_password(std::string_view sv); + [[maybe_unused]] void set_netrc(netrc_t netrc); + void set_http_auth(httpauth_t httpauth, bool auth_only); + void set_proxy_auth(proxyauth_t proxyauth); // * puplic protocol setters @fn set_* @return none - void set_transfer_text(bool state); - void set_transfer_mode(bool state); - void set_crlf(bool state); - void set_file_time(bool state); - void set_upload(bool state); + [[maybe_unused]] void set_transfer_text(bool state); + [[maybe_unused]] void set_transfer_mode(bool state); + [[maybe_unused]] void set_crlf(bool state); + [[maybe_unused]] void set_file_time(bool state); + [[maybe_unused]] void set_upload(bool state); void set_no_body(bool state); - void set_ignore_content_length(bool state); - void set_http_content_decoding(bool state); - void set_http_transfer_decoding(bool state); + [[maybe_unused]] void set_ignore_content_length(bool state); + [[maybe_unused]] void set_http_content_decoding(bool state); + [[maybe_unused]] void set_http_transfer_decoding(bool state); void set_http_get(bool state); - void set_cookie_session(bool state); - void set_resume_from(long value); - void set_in_file_size(long value); - void set_max_file_size(long value); - void set_time_value(long value); - void set_resume_from_large(native::curl_off_t value); - void set_in_file_size_large(native::curl_off_t value); - void set_max_file_size_large(native::curl_off_t value); - void set_range(std::string_view sv); - void set_cookie_list(std::string_view sv); + [[maybe_unused]] void set_cookie_session(bool state); + [[maybe_unused]] void set_resume_from(long value); + [[maybe_unused]] void set_in_file_size(long value); + [[maybe_unused]] void set_max_file_size(long value); + [[maybe_unused]] void set_time_value(long value); + [[maybe_unused]] void set_resume_from_large(native::curl_off_t value); + [[maybe_unused]] void set_in_file_size_large(native::curl_off_t value); + [[maybe_unused]] void set_max_file_size_large(native::curl_off_t value); + [[maybe_unused]] void set_range(std::string_view sv); + [[maybe_unused]] void set_cookie_list(std::string_view sv); void set_cookie(std::string_view sv); - void set_cookie_file(std::string_view sv); - void set_cookie_jar(std::string_view sv); - void set_http_version(detail::http_version_t version); - void set_time_condition(detail::time_condition_t condition); + [[maybe_unused]] void set_cookie_file(std::string_view sv); + [[maybe_unused]] void set_cookie_jar(std::string_view sv); + void set_http_version(http_version_t version); + [[maybe_unused]] void set_time_condition(time_condition_t condition); // * puplic connection setters @fn set_* @return none - void set_fresh_connect(bool state); - void set_forbit_reuse(bool state); - void set_connect_only(bool state); - void set_timeout(long timeout); + [[maybe_unused]] void set_fresh_connect(bool state); + [[maybe_unused]] void set_forbit_reuse(bool state); + [[maybe_unused]] void set_connect_only(bool state); + [[maybe_unused]] void set_timeout(long timeout); void set_timeout_ms(long timeout); - void set_low_speed_limit(long limit); - void set_low_speed_time(long time); - void set_max_connects(long connects); - void set_connect_timeout(long timeout); + [[maybe_unused]] void set_low_speed_limit(long limit); + [[maybe_unused]] void set_low_speed_time(long time); + [[maybe_unused]] void set_max_connects(long connects); + [[maybe_unused]] void set_connect_timeout(long timeout); void set_connect_timeout_ms(long timeout); - void set_accept_timeout_ms(long timeout); - void set_max_send_speed_large(native::curl_off_t large); - void set_max_recv_speed_large(native::curl_off_t large); - void set_dns_servers(std::string_view sv); - void set_ip_resolve(detail::ip_resolve_t resolve); + [[maybe_unused]] void set_accept_timeout_ms(long timeout); + [[maybe_unused]] void set_max_send_speed_large(native::curl_off_t large); + [[maybe_unused]] void set_max_recv_speed_large(native::curl_off_t large); + [[maybe_unused]] void set_dns_servers(std::string_view sv); + void set_ip_resolve(ip_resolve_t resolve); void set_resolves(std::shared_ptr resolved_hosts); // * puplic ssh setters @fn set_* @return none - void set_ssh_auth_types(long types); - void set_ssh_host_public_key_md5(std::string_view sv); - void set_ssh_public_key_file(std::string_view sv); - void set_ssh_private_key_file(std::string_view sv); - void set_ssh_known_hosts(std::string_view sv); - void set_ssh_key_function(void* ptr); // !TODO ssh key callback ? - void set_ssh_key_data(void* ptr); + [[maybe_unused]] void set_ssh_auth_types(long types); + [[maybe_unused]] void set_ssh_host_public_key_md5(std::string_view sv); + [[maybe_unused]] void set_ssh_public_key_file(std::string_view sv); + [[maybe_unused]] void set_ssh_private_key_file(std::string_view sv); + [[maybe_unused]] void set_ssh_known_hosts(std::string_view sv); + [[maybe_unused]] void set_ssh_key_function(void* ptr); // !TODO ssh key callback ? + [[maybe_unused]] void set_ssh_key_data(void* ptr); // * ssl and security setters @fn set_* @return none void set_ssl_cert(std::string_view sv); @@ -324,8 +321,8 @@ class easy final : public std::enable_shared_from_this { void set_ssl_session_id_cache(bool state); void set_ssl_verify_peer(bool state); void set_ssl_verify_host(bool state); - void set_ssl_version(detail::ssl_version_t version); - void set_use_ssl(detail::use_ssl_t ssl); + void set_ssl_version(ssl_version_t version); + void set_use_ssl(use_ssl_t ssl); #if LIBCURL_VERSION_NUM >= 0x074700 void set_ssl_cert_blob_copy(std::string_view sv); @@ -359,8 +356,8 @@ class easy final : public std::enable_shared_from_this { void set_debug_data(void* ptr); using interleave_function_t = size_t (*)(void* ptr, size_t size, size_t nmemb, void* userdata); - void set_interleave_function(interleave_function_t func); - void set_interleave_data(void* ptr); + [[maybe_unused]] void set_interleave_function(interleave_function_t func); + [[maybe_unused]] void set_interleave_data(void* ptr); using write_function_t = size_t (*)(char* ptr, size_t size, size_t nmemb, void* userdata); void set_write_function(write_function_t func, std::error_code& ec); @@ -397,7 +394,6 @@ class easy final : public std::enable_shared_from_this { void set_ssl_ctx_data(void* ptr, std::error_code& ec); // * getters @fn get_* @return std::shared_ptr - [[nodiscard]] std::shared_ptr get_bound_blocking(multi& multi_handle) const; [[nodiscard]] inline const std::string& get_original_url() const { return orig_url_str_; } [[nodiscard]] inline const url& get_easy_url() const { return url_; } @@ -456,35 +452,23 @@ class easy final : public std::enable_shared_from_this { [[nodiscard]] long get_appconnect_time_usec(); // return native::curl_off_t ? [[nodiscard]] long get_retry_after_sec(); // return native::curl_off_t ? - engine::ev::ThreadControl& get_thread_control(); - // this deprecated function use set_mimepost() - [[deprecated("Use set_mimepost())")]] [[noreturn]] - void set_http_post(void*); + [[deprecated("Use set_mimepost())")]] + void set_http_post(std::unique_ptr form_ptr); // this deprecated function [[deprecated("Serves no purpose anymore")]] [[noreturn]] void set_random_file(std::string_view); // CURLOPT_RANDOM_FILE // this deprecated function - [[deprecated("Serves no purpose anymore")]] [[noreturn]] - void set_egd_socket(std::string_view); // CURLOPT_EGDSOCKET + [[deprecated("Serves no purpose anymore")]] + void set_egd_socket(std::string_view sv); // CURLOPT_EGDSOCKET // this deprecated function [[deprecated("Use set_redir_protocols_str()")]] [[noreturn]] void set_redir_protocols(long); // CURLOPT_REDIR_PROTOCOLS [[deprecated("Use set_protocols_str()")]] [[noreturn]] void set_protocols(long); // CURLOPT_PROTOCOLS // this deprecated function - [[deprecated("Use get_scheme()")]] [[noreturn]] - void get_protocol(); // CURLINFO_PROTOCOL - -#if LIBCURL_VERSION_NUM <= 0x074700 - #include - std::shared_ptr form_; - - void set_http_post(std::unique_ptr form_ptr>); - void set_egd_socket(std::string_view); - - long get_protocol(); -#endif + [[deprecated("Use get_scheme()")]] + long get_protocol(); // CURLINFO_PROTOCOL private: // private static @@ -506,13 +490,13 @@ class easy final : public std::enable_shared_from_this { void mark_start_performing(); void mark_open_socket(); - void cancel(size_t request_num); + void cancel(size_t request_num); protected: native::CURL* easy_handle_; std::shared_ptr mime_; multi* multi_handle_; - url url_; + url url_; size_t request_counter_ { 0 }; size_t retries_counter_ { 0 }; @@ -523,8 +507,9 @@ class easy final : public std::enable_shared_from_this { std::string* sink_ { nullptr }; std::string orig_url_str_ {}; - std::string post_fields_ {}; + std::string post_fields_ {}; + std::shared_ptr form_ { nullptr }; std::shared_ptr share_ { nullptr }; std::shared_ptr source_ { nullptr }; std::shared_ptr headers_ { nullptr }; diff --git a/core/src/curl-ev/error_code.cpp b/core/src/curl-ev/error_code.cpp index 3f077b86bdfb..163acfda9290 100644 --- a/core/src/curl-ev/error_code.cpp +++ b/core/src/curl-ev/error_code.cpp @@ -7,8 +7,6 @@ error_code class */ -// !TODO this header file upgrade in 2025 year // - #include USERVER_NAMESPACE_BEGIN @@ -20,31 +18,6 @@ class EasyErrorCategory final : public std::error_category { public: using std::error_category::error_category; -#if LIBCURL_VERSION_NUM <= 0x074700 - [[nodiscard]] std::string message(int cond) const override { - switch (static_cast(cond)) { - case FormErrorCode::kSuccess: - return "no error"; - case FormErrorCode::kMemory: - return "memory allocation error"; - case FormErrorCode::kOptionTwice: - return "one option is given twice"; - case FormErrorCode::kNull: - return "a null pointer was given for a char"; - case FormErrorCode::kUnknownOption: - return "an unknown option was used"; - case FormErrorCode::kIncomplete: - return "some FormInfo is not complete (or error)"; - case FormErrorCode::kIllegalArray: - return "an illegal option is used in an array"; - case FormErrorCode::kDisabled: - return "form support was disabled"; - default: - return "unknown CURLFORMcode"; - } - } -#endif - [[nodiscard]] const char* name() const noexcept override { return "curl-easy"; } [[nodiscard]] std::string message(int cond) const override { @@ -79,6 +52,29 @@ class FormErrorCategory final : public std::error_category { using std::error_category::error_category; [[nodiscard]] const char* name() const noexcept override { return "curl-form"; } + + [[nodiscard]] std::string message(int cond) const override { + switch (static_cast(cond)) { + case FormErrorCode::kSuccess: + return "no error"; + case FormErrorCode::kMemory: + return "memory allocation error"; + case FormErrorCode::kOptionTwice: + return "one option is given twice"; + case FormErrorCode::kNull: + return "a null pointer was given for a char"; + case FormErrorCode::kUnknownOption: + return "an unknown option was used"; + case FormErrorCode::kIncomplete: + return "some FormInfo is not complete (or error)"; + case FormErrorCode::kIllegalArray: + return "an illegal option is used in an array"; + case FormErrorCode::kDisabled: + return "form support was disabled"; + default: + return "unknown CURLFORMcode"; + } + } }; class UrlErrorCategory final : public std::error_category { @@ -168,6 +164,11 @@ const std::error_category& GetShareCategory() noexcept { return kShareCategory; } +const std::error_category& GetFormCategory() noexcept { + static const FormErrorCategory kFormCategory; + return kFormCategory; +} + const std::error_category& GetUrlCategory() noexcept { static const UrlErrorCategory kUrlCategory; return kUrlCategory; @@ -178,13 +179,6 @@ const std::error_category& GetRateLimitCategory() noexcept { return kRateLimitCategory; } -#if LIBCURL_VERSION_NUM <= 0x074700 -const std::error_category& GetFormCategory() noexcept { - static const FormErrorCategory kFormCategory; - return kFormCategory; -} -#endif - } // namespace curl::errc USERVER_NAMESPACE_END diff --git a/core/src/curl-ev/error_code.hpp b/core/src/curl-ev/error_code.hpp index ec7657d49c8e..65660baa69de 100644 --- a/core/src/curl-ev/error_code.hpp +++ b/core/src/curl-ev/error_code.hpp @@ -7,8 +7,6 @@ error_code class */ -// !TODO this header file upgrade in 2025 year // - #pragma once #include @@ -130,7 +128,6 @@ enum class ShareErrorCode { kNotBuiltIn = native::CURLSHE_NOT_BUILT_IN }; -#if LIBCURL_VERSION_NUM <= 0x074700 enum class FormErrorCode { kSuccess = native::CURL_FORMADD_OK, kMemory = native::CURL_FORMADD_MEMORY, @@ -141,7 +138,6 @@ enum class FormErrorCode { kIllegalArray = native::CURL_FORMADD_ILLEGAL_ARRAY, kDisabled = native::CURL_FORMADD_DISABLED }; -#endif enum class UrlErrorCode { kSuccess = native::CURLUE_OK, @@ -173,13 +169,10 @@ enum class RateLimitErrorCode { const std::error_category& GetEasyCategory() noexcept; const std::error_category& GetMultiCategory() noexcept; const std::error_category& GetShareCategory() noexcept; +const std::error_category& GetFormCategory() noexcept; const std::error_category& GetUrlCategory() noexcept; const std::error_category& GetRateLimitCategory() noexcept; -#if LIBCURL_VERSION_NUM <= 0x074700 -const std::error_category& GetFormCategory() noexcept; -#endif - } // namespace curl::errc USERVER_NAMESPACE_END @@ -196,15 +189,13 @@ template <> struct is_error_code_enum : std::true_type {}; template <> -struct is_error_code_enum : std::true_type {}; +struct is_error_code_enum : std::true_type {}; template <> -struct is_error_code_enum : std::true_type {}; +struct is_error_code_enum : std::true_type {}; -#if LIBCURL_VERSION_NUM <= 0x074700 template <> -struct is_error_code_enum : std::true_type {}; -#endif +struct is_error_code_enum : std::true_type {}; } // namespace std @@ -218,14 +209,12 @@ inline std::error_code make_error_code(MultiErrorCode e) { return {static_cast(e), GetShareCategory()}; } +inline std::error_code make_error_code(FormErrorCode e) { return {static_cast(e), GetFormCategory()}; } + inline std::error_code make_error_code(UrlErrorCode e) { return {static_cast(e), GetUrlCategory()}; } inline std::error_code make_error_code(RateLimitErrorCode e) { return {static_cast(e), GetRateLimitCategory()}; } -#if LIBCURL_VERSION_NUM <= 0x074700 -inline std::error_code make_error_code(FormErrorCode e) { return {static_cast(e), GetFormCategory()}; } -#endif - } // namespace curl::errc USERVER_NAMESPACE_END diff --git a/core/src/curl-ev/form.cpp b/core/src/curl-ev/form.cpp index 9a322e871300..2ba8ea7af2d7 100644 --- a/core/src/curl-ev/form.cpp +++ b/core/src/curl-ev/form.cpp @@ -14,7 +14,6 @@ USERVER_NAMESPACE_BEGIN namespace curl { -#if LIBCURL_VERSION_NUM <= 0x074700 form::form() { impl::CurlGlobal::Init(); } @@ -221,7 +220,7 @@ void form::add_file_content(const std::string& key, const std::string& file_path throw_error(ec, "add_file_content"); } -void form::add_file_content([[maybe_unused]] const std::string& key, [[maybe_unused]] const std::string& file_path, [[maybe_unused]] std::error_code& ec) { +void form::add_file_content(const std::string& key, const std::string& file_path, std::error_code& ec) { ec = std::error_code{static_cast(native::curl_formadd( &post_, &last_, @@ -257,7 +256,6 @@ void form::add_file_content(const std::string& key, const std::string& file_path ))}; } -#endif // LIBCURL_VERSION_NUM } // namespace curl USERVER_NAMESPACE_END diff --git a/core/src/curl-ev/form.hpp b/core/src/curl-ev/form.hpp index 893539a1f07e..00a93fd40599 100644 --- a/core/src/curl-ev/form.hpp +++ b/core/src/curl-ev/form.hpp @@ -18,7 +18,6 @@ USERVER_NAMESPACE_BEGIN namespace curl { -#if LIBCURL_VERSION_NUM <= 0x074700 class form { public: form(); @@ -62,7 +61,6 @@ class form { native::curl_httppost* last_{nullptr}; std::vector> buffers_; }; -#endif // LIBCURL_VERSION_NUM } // namespace curl diff --git a/core/src/curl-ev/mime.cpp b/core/src/curl-ev/mime.cpp index 9ef8ef8cea76..80497669d50e 100644 --- a/core/src/curl-ev/mime.cpp +++ b/core/src/curl-ev/mime.cpp @@ -1,9 +1,11 @@ -// !TODO this @file curl-ev/mime.cpp create in 2025 year // +/** @file curl-ev/mime.cpp */ #include #include #include +#include + USERVER_NAMESPACE_BEGIN namespace curl { @@ -19,5 +21,100 @@ mime::~mime() { } } +void mime::add_content(std::string_view key, std::string_view content) { + LOG_TRACE() << "mime::add_content start " << this; + + if(!mime_) { + LOG_ERROR() << "mime failed!"; + return; + } + // content part + part_ = native::curl_mime_addpart(mime_); + native::curl_mime_data(part_, content.data(), content.length()); + // key part + part_ = native::curl_mime_addpart(mime_); + native::curl_mime_data(part_, key.data(), key.length()); + native::curl_mime_name(part_, key.data()); + // + part_ = native::curl_mime_addpart(mime_); + native::curl_mime_subparts(part_, mime_); + native::curl_mime_type(part_, "multipart/form-data"); + + + LOG_TRACE() << "mime::add_content finished " << this; +} + +void mime::add_content(std::string_view key, std::string_view content, std::string_view content_type) { + LOG_TRACE() << "mime::add_content start " << this; + + if(!mime_) { + LOG_ERROR() << "mime failed!"; + return; + } + // content part + part_ = native::curl_mime_addpart(mime_); + native::curl_mime_data(part_, content.data(), content.length()); + native::curl_mime_type(part_, content_type.data()); + // key part + part_ = native::curl_mime_addpart(mime_); + native::curl_mime_data(part_, key.data(), key.length()); + native::curl_mime_name(part_, key.data()); + // + part_ = native::curl_mime_addpart(mime_); + native::curl_mime_subparts(part_, mime_); + native::curl_mime_type(part_, "multipart/from-data"); + + LOG_TRACE() << "mime::add_content finished " << this; +} + +void mime::add_buffer(std::string_view key, std::string_view name, const std::shared_ptr& buffer) { + LOG_TRACE() << "mime::add_buffer start " << this; + + if(!mime_) { + LOG_ERROR() << "mime failed!"; + return; + } + + buffers_.push_back(buffer); + + part_ = native::curl_mime_addpart(mime_); + native::curl_mime_data(part_, buffer->c_str(), buffer->length()); + + part_ = native::curl_mime_addpart(mime_); + native::curl_mime_data(part_, key.data(), key.length()); + native::curl_mime_name(part_, name.data()); + + part_ = native::curl_mime_addpart(mime_); + native::curl_mime_subparts(part_, mime_); + native::curl_mime_type(part_, "multipart/from-data"); + + LOG_TRACE() << "mime::add_buffer finished " << this; +} + +void mime::add_buffer(std::string_view key, std::string_view name, std::string_view content_type, const std::shared_ptr& buffer) { + LOG_TRACE() << "mime::add_buffer start " << this; + + if(!mime_) { + LOG_ERROR() << "mime failed!"; + return; + } + + buffers_.push_back(buffer); + + part_ = native::curl_mime_addpart(mime_); + native::curl_mime_data(part_, buffer->c_str(), buffer->length()); + native::curl_mime_type(part_, content_type.data()); + + part_ = native::curl_mime_addpart(mime_); + native::curl_mime_data(part_, key.data(), key.length()); + native::curl_mime_name(part_, name.data()); + + part_ = native::curl_mime_addpart(mime_); + native::curl_mime_subparts(part_, mime_); + native::curl_mime_type(part_, "multipart/from-data"); + + LOG_TRACE() << "mime::add_buffer finished " << this; +} + } // curl namespace USERVER_NAMESPACE_END \ No newline at end of file diff --git a/core/src/curl-ev/mime.hpp b/core/src/curl-ev/mime.hpp index 9e05addd5282..c925e0b9a5bb 100644 --- a/core/src/curl-ev/mime.hpp +++ b/core/src/curl-ev/mime.hpp @@ -1,6 +1,6 @@ #pragma once -// !TODO this @file curl-ev/mime.cpp create in 2025 year // +/** @file curl-ev/mime.cpp */ #include #include @@ -18,17 +18,24 @@ class mime final { ~mime(); mime(const mime& rhs) = delete; - mime(mime&& rhs) noexcept = default; + mime(mime&& rhs) = delete; mime& operator= (const mime& rhs) = delete; - mime& operator= (mime&& rhs) noexcept = default; + mime& operator= (mime&& rhs) = delete; inline native::curl_mime* native_mime() { return mime_; } inline native::curl_mimepart* native_part() { return part_; } +public: + void add_content(std::string_view key, std::string_view content); + void add_content(std::string_view key, std::string_view content, std::string_view content_type); + + void add_buffer(std::string_view key, std::string_view name, const std::shared_ptr& buffer); + void add_buffer(std::string_view key, std::string_view name, std::string_view content_type, const std::shared_ptr& buffer); private: native::curl_mime* mime_ { nullptr }; native::curl_mimepart* part_ { nullptr }; + std::vector> buffers_ { nullptr }; }; } // namespace curl From 550f9a28062957f4937b670213a56b5a45598865 Mon Sep 17 00:00:00 2001 From: Taras Litvinenko Date: Thu, 13 Mar 2025 22:14:44 +0500 Subject: [PATCH 3/3] Delete build.txt --- build.txt | 17 ----------------- 1 file changed, 17 deletions(-) delete mode 100644 build.txt diff --git a/build.txt b/build.txt deleted file mode 100644 index 9a3299d7daf5..000000000000 --- a/build.txt +++ /dev/null @@ -1,17 +0,0 @@ -[1/10] Building CXX object core/CMakeFiles/userver-core.dir/src/clients/http/easy_wrapper.cpp.o -[2/10] Building CXX object core/CMakeFiles/userver-core.dir/src/clients/http/plugin.cpp.o -[3/10] Building CXX object core/CMakeFiles/userver-core.dir/src/clients/http/response_future.cpp.o -[4/10] Building CXX object core/CMakeFiles/userver-core.dir/src/clients/http/streamed_response.cpp.o -[5/10] Building CXX object core/CMakeFiles/userver-core.dir/src/clients/http/request.cpp.o -/home/xensmo/userver/core/src/clients/http/request.cpp:352:20: warning: 'set_http_post' is deprecated: Use set_mimepost()) [-Wdeprecated-declarations] - 352 | pimpl_->easy().set_http_post(std::move(form).GetNative()); - | ^ -/home/xensmo/userver/core/src/curl-ev/easy.hpp:456:7: note: 'set_http_post' has been explicitly marked deprecated here - 456 | [[deprecated("Use set_mimepost())")]] - | ^ -1 warning generated. -[6/10] Building CXX object core/CMakeFiles/userver-core.dir/src/curl-ev/multi.cpp.o -[7/10] Building CXX object core/CMakeFiles/userver-core.dir/src/clients/http/client.cpp.o -[8/10] Building CXX object core/CMakeFiles/userver-core.dir/src/curl-ev/easy.cpp.o -[9/10] Building CXX object core/CMakeFiles/userver-core.dir/src/clients/http/request_state.cpp.o -[10/10] Linking CXX static library core/libuserver-core.a