diff --git a/include/powerloader/context.hpp b/include/powerloader/context.hpp index 2fef8c7e..77f9ba3d 100644 --- a/include/powerloader/context.hpp +++ b/include/powerloader/context.hpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include diff --git a/include/powerloader/curl.hpp b/include/powerloader/curl.hpp index 3cbfb853..e9a4496e 100644 --- a/include/powerloader/curl.hpp +++ b/include/powerloader/curl.hpp @@ -1,15 +1,9 @@ #ifndef POWERLOADER_CURL_HPP #define POWERLOADER_CURL_HPP -#include -#include #include -#include -#include -#include #include -#include #include #include @@ -18,15 +12,9 @@ extern "C" #include } -#include -#include -#include - namespace powerloader { - class Context; class CURLHandle; - using proxy_map_type = std::map; enum class ssl_backend_t { @@ -46,22 +34,11 @@ namespace powerloader rustls = CURLSSLBACKEND_RUSTLS, }; - class POWERLOADER_API curl_error : public std::runtime_error - { - public: - curl_error(const std::string& what = "download error", bool serious = false); - bool is_serious() const; - - private: - bool m_serious; - }; - + // This is supposed to be used outside powerloader struct POWERLOADER_API Response { std::map headers; - curl_off_t average_speed = -1; - curl_off_t downloaded_size = -1; long http_status = 0; std::string effective_url; @@ -75,89 +52,12 @@ namespace powerloader // `h.perform() method) std::optional content; nlohmann::json json() const; - }; - - // TODO: rename this, try to not expose it - POWERLOADER_API CURL* get_handle(const Context& ctx); - - class POWERLOADER_API CURLHandle - { - public: - using end_callback_type = std::function; - explicit CURLHandle(const Context& ctx); - CURLHandle(const Context& ctx, const std::string& url); - ~CURLHandle(); - - CURLHandle& url(const std::string& url, const proxy_map_type& proxies); - CURLHandle& accept_encoding(); - CURLHandle& user_agent(const std::string& user_agent); - - Response perform(); - void finalize_transfer(); - // TODO: should be private? - void finalize_transfer(Response& response); - - template - tl::expected getinfo(CURLINFO option); - - // TODO: why do we need to expose these three methods - CURL* handle(); - operator CURL*(); // TODO: consider making this `explicit` or remove it - CURL* ptr() const; - - CURLHandle& add_header(const std::string& header); - CURLHandle& add_headers(const std::vector& headers); - CURLHandle& reset_headers(); - - template - CURLHandle& setopt(CURLoption opt, const T& val); - - void set_default_callbacks(); - CURLHandle& set_end_callback(end_callback_type func); - - CURLHandle& upload(std::ifstream& stream); - CURLHandle& upload(std::istringstream& stream); - - CURLHandle(CURLHandle&& rhs); - CURLHandle& operator=(CURLHandle&& rhs); private: - void init_handle(const Context& ctx); - - CURL* m_handle; - curl_slist* p_headers = nullptr; - char errorbuffer[CURL_ERROR_SIZE]; - - std::unique_ptr response; - end_callback_type end_callback; + curl_off_t average_speed = -1; + curl_off_t downloaded_size = -1; }; - // TODO: restrict the possible implementations in the cpp file - template - CURLHandle& CURLHandle::setopt(CURLoption opt, const T& val) - { - CURLcode ok; - if constexpr (std::is_same()) - { - ok = curl_easy_setopt(m_handle, opt, val.c_str()); - } - else if constexpr (std::is_same()) - { - ok = curl_easy_setopt(m_handle, opt, val ? 1L : 0L); - } - else - { - ok = curl_easy_setopt(m_handle, opt, val); - } - if (ok != CURLE_OK) - { - throw curl_error( - fmt::format("curl: curl_easy_setopt failed {}", curl_easy_strerror(ok))); - } - return *this; - } - - std::optional proxy_match(const proxy_map_type& ctx, const std::string& url); } #endif diff --git a/include/powerloader/download_target.hpp b/include/powerloader/download_target.hpp index 50042eac..e20ec284 100644 --- a/include/powerloader/download_target.hpp +++ b/include/powerloader/download_target.hpp @@ -6,14 +6,12 @@ #include #include #include -#include #include #include #include namespace powerloader { - struct zck_target; struct POWERLOADER_API CacheControl @@ -80,8 +78,8 @@ namespace powerloader m_error = std::move(err); } - /// Returns a DownloadError if there was a falure at download or none if no error was set so - /// far. + /// Returns a DownloadError if there was a failure at download or none if no error was set + /// so far. std::optional get_error() const noexcept { return m_error; diff --git a/include/powerloader/downloader.hpp b/include/powerloader/downloader.hpp index 0cd2f1a2..31a5efcb 100644 --- a/include/powerloader/downloader.hpp +++ b/include/powerloader/downloader.hpp @@ -21,7 +21,6 @@ extern "C" #include #include -#include #include #include #include diff --git a/include/powerloader/mirror.hpp b/include/powerloader/mirror.hpp index 1679ef18..3fc1accf 100644 --- a/include/powerloader/mirror.hpp +++ b/include/powerloader/mirror.hpp @@ -7,7 +7,6 @@ #include #include -#include #include #include #include @@ -16,6 +15,7 @@ namespace powerloader { class Target; class Context; + class CURLHandle; enum class MirrorState { diff --git a/include/powerloader/mirrors/oci.hpp b/include/powerloader/mirrors/oci.hpp index 5f801fd9..e4265b6c 100644 --- a/include/powerloader/mirrors/oci.hpp +++ b/include/powerloader/mirrors/oci.hpp @@ -3,6 +3,7 @@ #include #include +#include #include #include diff --git a/include/powerloader/mirrors/s3.hpp b/include/powerloader/mirrors/s3.hpp index e6887c67..97349468 100644 --- a/include/powerloader/mirrors/s3.hpp +++ b/include/powerloader/mirrors/s3.hpp @@ -9,7 +9,6 @@ namespace powerloader { - class Target; struct POWERLOADER_API S3CanonicalRequest diff --git a/include/powerloader/url.hpp b/include/powerloader/url.hpp index f78a6fc7..56f7ef5c 100644 --- a/include/powerloader/url.hpp +++ b/include/powerloader/url.hpp @@ -19,27 +19,6 @@ extern "C" #include -// typedef enum { -// CURLUE_OK, -// CURLUE_BAD_HANDLE, /* 1 */ -// CURLUE_BAD_PARTPOINTER, /* 2 */ -// CURLUE_MALFORMED_INPUT, /* 3 */ -// CURLUE_BAD_PORT_NUMBER, /* 4 */ -// CURLUE_UNSUPPORTED_SCHEME, /* 5 */ -// CURLUE_URLDECODE, /* 6 */ -// CURLUE_OUT_OF_MEMORY, /* 7 */ -// CURLUE_USER_NOT_ALLOWED, /* 8 */ -// CURLUE_UNKNOWN_PART, /* 9 */ -// CURLUE_NO_SCHEME, /* 10 */ -// CURLUE_NO_USER, /* 11 */ -// CURLUE_NO_PASSWORD, /* 12 */ -// CURLUE_NO_OPTIONS, /* 13 */ -// CURLUE_NO_HOST, /* 14 */ -// CURLUE_NO_PORT, /* 15 */ -// CURLUE_NO_QUERY, /* 16 */ -// CURLUE_NO_FRAGMENT /* 17 */ -// } CURLUcode; - namespace powerloader { POWERLOADER_API bool has_scheme(const std::string& url); @@ -135,11 +114,6 @@ namespace powerloader } } // namespace detail - inline std::string join_url() - { - return ""; - } - template inline std::string join_url(const S& s, const Args&... args) { diff --git a/src/curl.cpp b/src/curl.cpp index 2002b9b7..a1e05c25 100644 --- a/src/curl.cpp +++ b/src/curl.cpp @@ -3,7 +3,6 @@ #include #include -#include #include #include #include @@ -230,16 +229,6 @@ namespace powerloader return m_handle; } - CURLHandle::operator CURL*() - { - return handle(); - } - - CURL* CURLHandle::ptr() const - { - return m_handle; - } - CURLHandle& CURLHandle::add_header(const std::string& header) { p_headers = curl_slist_append(p_headers, header.c_str()); diff --git a/src/curl_internal.hpp b/src/curl_internal.hpp index a15a9af9..5950c9f0 100644 --- a/src/curl_internal.hpp +++ b/src/curl_internal.hpp @@ -1,10 +1,110 @@ #ifndef POWERLOADER_SRC_CURL_INTERNAL_HPP #define POWERLOADER_SRC_CURL_INTERNAL_HPP -#include +#include +#include +#include +#include + +#include +#include +#include #include +namespace powerloader +{ + class Context; + using proxy_map_type = std::map; + + // If needed, this can be moved to curl.hpp + class POWERLOADER_API curl_error : public std::runtime_error + { + public: + curl_error(const std::string& what = "download error", bool serious = false); + bool is_serious() const; + + private: + bool m_serious; + }; + + class POWERLOADER_API CURLHandle + { + public: + using end_callback_type = std::function; + explicit CURLHandle(const Context& ctx); + CURLHandle(const Context& ctx, const std::string& url); + ~CURLHandle(); + + CURLHandle& url(const std::string& url, const proxy_map_type& proxies); + CURLHandle& accept_encoding(); + CURLHandle& user_agent(const std::string& user_agent); + + Response perform(); + void finalize_transfer(); + + template + tl::expected getinfo(CURLINFO option); + + // This is made public because it is used internally in quite some files + CURL* handle(); + + CURLHandle& add_header(const std::string& header); + CURLHandle& add_headers(const std::vector& headers); + CURLHandle& reset_headers(); + + template + CURLHandle& setopt(CURLoption opt, const T& val); + + void set_default_callbacks(); + CURLHandle& set_end_callback(end_callback_type func); + + CURLHandle& upload(std::ifstream& stream); + CURLHandle& upload(std::istringstream& stream); + + CURLHandle(CURLHandle&& rhs); + CURLHandle& operator=(CURLHandle&& rhs); + + private: + void init_handle(const Context& ctx); + void finalize_transfer(Response& response); + + CURL* m_handle; + curl_slist* p_headers = nullptr; + char errorbuffer[CURL_ERROR_SIZE]; + + std::unique_ptr response; + end_callback_type end_callback; + }; + + // TODO: restrict the possible implementations in the cpp file + template + CURLHandle& CURLHandle::setopt(CURLoption opt, const T& val) + { + CURLcode ok; + if constexpr (std::is_same()) + { + ok = curl_easy_setopt(m_handle, opt, val.c_str()); + } + else if constexpr (std::is_same()) + { + ok = curl_easy_setopt(m_handle, opt, val ? 1L : 0L); + } + else + { + ok = curl_easy_setopt(m_handle, opt, val); + } + if (ok != CURLE_OK) + { + throw curl_error( + fmt::format("curl: curl_easy_setopt failed {}", curl_easy_strerror(ok))); + } + return *this; + } + + std::optional proxy_match(const proxy_map_type& ctx, const std::string& url); +} + namespace powerloader::details { // Scoped initialization and termination of CURL. diff --git a/src/download_target.cpp b/src/download_target.cpp index 9aad6561..3db34969 100644 --- a/src/download_target.cpp +++ b/src/download_target.cpp @@ -1,6 +1,9 @@ #include "powerloader/context.hpp" #include +#include "curl_internal.hpp" + + #ifdef WITH_ZCHUNK #include "zck.hpp" #endif diff --git a/src/downloader.cpp b/src/downloader.cpp index 1a181543..b7db4ff6 100644 --- a/src/downloader.cpp +++ b/src/downloader.cpp @@ -16,13 +16,14 @@ namespace fs = std::filesystem; #include -#include +// #include #include #include #include #include #include #include "target.hpp" + #ifdef WITH_ZCHUNK #include "zck.hpp" #endif diff --git a/src/fastest_mirror.cpp b/src/fastest_mirror.cpp index 6a3555dd..47a1ad4c 100644 --- a/src/fastest_mirror.cpp +++ b/src/fastest_mirror.cpp @@ -3,9 +3,10 @@ #include #include -#include #include +#include "curl_internal.hpp" + namespace powerloader { namespace detail @@ -54,9 +55,9 @@ namespace powerloader std::size_t handles_added = 0; for (auto& el : mirrors) { - if (el.handle) + if (el.handle.handle()) { - curl_multi_add_handle(multihandle, el.handle); + curl_multi_add_handle(multihandle, el.handle.handle()); handles_added++; spdlog::info("Checking URL: {}", el.url); } @@ -156,7 +157,7 @@ namespace powerloader for (auto& el : mirrors) { // Remove handle - curl_multi_remove_handle(multihandle, el.handle); + curl_multi_remove_handle(multihandle, el.handle.handle()); // Calculate plain_connect_time auto effective_url = el.handle.getinfo(CURLINFO_EFFECTIVE_URL); diff --git a/src/mirror.cpp b/src/mirror.cpp index db60e933..0c3df4fb 100644 --- a/src/mirror.cpp +++ b/src/mirror.cpp @@ -8,6 +8,7 @@ #include "powerloader/mirrorid.hpp" #include "target.hpp" +#include "curl_internal.hpp" namespace powerloader { diff --git a/src/target.cpp b/src/target.cpp index 08b98ccd..d2aefcc8 100644 --- a/src/target.cpp +++ b/src/target.cpp @@ -169,9 +169,7 @@ namespace powerloader std::size_t zckheadercb(char* buffer, std::size_t size, std::size_t nitems, Target* self) { assert(self && self->m_target); - long code = -1; - curl_easy_getinfo(self->m_curl_handle->ptr(), CURLINFO_RESPONSE_CODE, &code); - if (code == 200) + if (self->m_curl_handle->getinfo(CURLINFO_RESPONSE_CODE) == 200) { spdlog::info("Too many ranges were attempted in one download"); self->m_range_fail = 1; @@ -548,7 +546,7 @@ namespace powerloader m_mirror->prepare(m_target->path(), h); m_state = DownloadState::kPREPARATION; - CURLMcode cm_rc = curl_multi_add_handle(multi_handle, h); + CURLMcode cm_rc = curl_multi_add_handle(multi_handle, h.handle()); if (cm_rc != CURLM_OK) { spdlog::error("curl_multi_add_handle() failed: {}", curl_multi_strerror(cm_rc)); @@ -698,7 +696,7 @@ namespace powerloader } // Add the new handle to the curl multi handle - CURLMcode cm_rc = curl_multi_add_handle(multi_handle, h); + CURLMcode cm_rc = curl_multi_add_handle(multi_handle, h.handle()); if (cm_rc != CURLM_OK) { spdlog::error("curl_multi_add_handle() failed: {}", curl_multi_strerror(cm_rc)); diff --git a/src/target.hpp b/src/target.hpp index b11db41e..20f1cfb7 100644 --- a/src/target.hpp +++ b/src/target.hpp @@ -7,7 +7,6 @@ #include #include -#include #include #include #include @@ -15,6 +14,8 @@ #include "compression.hpp" +#include "curl_internal.hpp" + namespace powerloader { namespace fs = std::filesystem; diff --git a/src/uploader/multipart_upload.cpp b/src/uploader/multipart_upload.cpp index 3174b8d2..34357fd0 100644 --- a/src/uploader/multipart_upload.cpp +++ b/src/uploader/multipart_upload.cpp @@ -1,4 +1,4 @@ -#include +#include void add_multipart_upload(CURLHandle& target, diff --git a/src/uploader/oci_upload.cpp b/src/uploader/oci_upload.cpp index 73575f1f..294108aa 100644 --- a/src/uploader/oci_upload.cpp +++ b/src/uploader/oci_upload.cpp @@ -5,6 +5,7 @@ #include #include +#include "curl_internal.hpp" namespace powerloader { diff --git a/src/uploader/s3_upload.cpp b/src/uploader/s3_upload.cpp index 21bcd0cb..87b68e46 100644 --- a/src/uploader/s3_upload.cpp +++ b/src/uploader/s3_upload.cpp @@ -3,6 +3,8 @@ #include +#include "curl_internal.hpp" + namespace powerloader { Response s3_upload(const Context& ctx, diff --git a/src/url.cpp b/src/url.cpp index a0de2221..0b76aa13 100644 --- a/src/url.cpp +++ b/src/url.cpp @@ -15,6 +15,28 @@ namespace fs = std::filesystem; +/** AS A REFERENCE */ +// typedef enum { +// CURLUE_OK, +// CURLUE_BAD_HANDLE, /* 1 */ +// CURLUE_BAD_PARTPOINTER, /* 2 */ +// CURLUE_MALFORMED_INPUT, /* 3 */ +// CURLUE_BAD_PORT_NUMBER, /* 4 */ +// CURLUE_UNSUPPORTED_SCHEME, /* 5 */ +// CURLUE_URLDECODE, /* 6 */ +// CURLUE_OUT_OF_MEMORY, /* 7 */ +// CURLUE_USER_NOT_ALLOWED, /* 8 */ +// CURLUE_UNKNOWN_PART, /* 9 */ +// CURLUE_NO_SCHEME, /* 10 */ +// CURLUE_NO_USER, /* 11 */ +// CURLUE_NO_PASSWORD, /* 12 */ +// CURLUE_NO_OPTIONS, /* 13 */ +// CURLUE_NO_HOST, /* 14 */ +// CURLUE_NO_PORT, /* 15 */ +// CURLUE_NO_QUERY, /* 16 */ +// CURLUE_NO_FRAGMENT /* 17 */ +// } CURLUcode; + namespace powerloader { bool has_scheme(const std::string& url)