From f700fcae2e3026f0ffb3e68595715fcd5a721841 Mon Sep 17 00:00:00 2001 From: spycrab Date: Wed, 28 Mar 2018 00:28:26 +0200 Subject: [PATCH] HttpRequest: Add callback option --- Source/Core/Common/HttpRequest.cpp | 35 ++++++++++++++++++++++++------ Source/Core/Common/HttpRequest.h | 8 ++++++- 2 files changed, 35 insertions(+), 8 deletions(-) diff --git a/Source/Core/Common/HttpRequest.cpp b/Source/Core/Common/HttpRequest.cpp index da489ef18d..edb3286b19 100644 --- a/Source/Core/Common/HttpRequest.cpp +++ b/Source/Core/Common/HttpRequest.cpp @@ -6,9 +6,10 @@ #include #include -#include #include +#include + #include "Common/Logging/Log.h" #include "Common/ScopeGuard.h" #include "Common/StringUtil.h" @@ -24,23 +25,27 @@ public: POST, }; - explicit Impl(std::chrono::milliseconds timeout_ms); + explicit Impl(std::chrono::milliseconds timeout_ms, ProgressCallback callback); bool IsValid() const; Response Fetch(const std::string& url, Method method, const Headers& headers, const u8* payload, size_t size); + static int CurlProgressCallback(Impl* impl, double dlnow, double dltotal, double ulnow, + double ultotal); + private: static std::mutex s_curl_was_inited_mutex; static bool s_curl_was_inited; + ProgressCallback m_callback; std::unique_ptr m_curl{nullptr, curl_easy_cleanup}; }; std::mutex HttpRequest::Impl::s_curl_was_inited_mutex; bool HttpRequest::Impl::s_curl_was_inited = false; -HttpRequest::HttpRequest(std::chrono::milliseconds timeout_ms) - : m_impl(std::make_unique(timeout_ms)) +HttpRequest::HttpRequest(std::chrono::milliseconds timeout_ms, ProgressCallback callback) + : m_impl(std::make_unique(timeout_ms, callback)) { } @@ -69,7 +74,15 @@ HttpRequest::Response HttpRequest::Post(const std::string& url, const std::strin reinterpret_cast(payload.data()), payload.size()); } -HttpRequest::Impl::Impl(std::chrono::milliseconds timeout_ms) +int HttpRequest::Impl::CurlProgressCallback(Impl* impl, double dlnow, double dltotal, double ulnow, + double ultotal) +{ + // Abort if callback isn't true + return !impl->m_callback(dlnow, dltotal, ulnow, ultotal); +} + +HttpRequest::Impl::Impl(std::chrono::milliseconds timeout_ms, ProgressCallback callback) + : m_callback(callback) { { std::lock_guard lk(s_curl_was_inited_mutex); @@ -84,6 +97,14 @@ HttpRequest::Impl::Impl(std::chrono::milliseconds timeout_ms) if (!m_curl) return; + curl_easy_setopt(m_curl.get(), CURLOPT_NOPROGRESS, m_callback == nullptr); + + if (m_callback) + { + curl_easy_setopt(m_curl.get(), CURLOPT_PROGRESSDATA, this); + curl_easy_setopt(m_curl.get(), CURLOPT_PROGRESSFUNCTION, CurlProgressCallback); + } + // libcurl may not have been built with async DNS support, so we disable // signal handlers to avoid a possible and likely crash if a resolve times out. curl_easy_setopt(m_curl.get(), CURLOPT_NOSIGNAL, true); @@ -99,7 +120,7 @@ bool HttpRequest::Impl::IsValid() const return m_curl != nullptr; } -static size_t CurlCallback(char* data, size_t size, size_t nmemb, void* userdata) +static size_t CurlWriteCallback(char* data, size_t size, size_t nmemb, void* userdata) { auto* buffer = static_cast*>(userdata); const size_t actual_size = size * nmemb; @@ -133,7 +154,7 @@ HttpRequest::Response HttpRequest::Impl::Fetch(const std::string& url, Method me curl_easy_setopt(m_curl.get(), CURLOPT_HTTPHEADER, list); std::vector buffer; - curl_easy_setopt(m_curl.get(), CURLOPT_WRITEFUNCTION, CurlCallback); + curl_easy_setopt(m_curl.get(), CURLOPT_WRITEFUNCTION, CurlWriteCallback); curl_easy_setopt(m_curl.get(), CURLOPT_WRITEDATA, &buffer); const char* type = method == Method::POST ? "POST" : "GET"; diff --git a/Source/Core/Common/HttpRequest.h b/Source/Core/Common/HttpRequest.h index 2a6590c1ca..92bae2307e 100644 --- a/Source/Core/Common/HttpRequest.h +++ b/Source/Core/Common/HttpRequest.h @@ -5,6 +5,7 @@ #pragma once #include +#include #include #include #include @@ -18,7 +19,12 @@ namespace Common class HttpRequest final { public: - explicit HttpRequest(std::chrono::milliseconds timeout_ms = std::chrono::milliseconds{3000}); + // Return false to abort the request + using ProgressCallback = + std::function; + + explicit HttpRequest(std::chrono::milliseconds timeout_ms = std::chrono::milliseconds{3000}, + ProgressCallback callback = nullptr); ~HttpRequest(); bool IsValid() const;