From 5b446d702a6c669c8b5fd2ae6e75caa437da7b57 Mon Sep 17 00:00:00 2001 From: Stenzek Date: Sat, 23 May 2026 16:29:07 +1000 Subject: [PATCH] HTTPDownloader: Add owner tracking to requests Allow finer-grained cancellation. --- src/core/achievements.cpp | 10 +-- src/core/game_list.cpp | 8 +- src/duckstation-qt/autoupdaterdialog.cpp | 32 ++++---- src/duckstation-qt/autoupdaterdialog.h | 6 +- src/duckstation-qt/qthost.cpp | 9 +-- src/util/http_cache.cpp | 34 +++++++-- src/util/http_cache.h | 14 +++- src/util/http_downloader.cpp | 93 ++++++++++++++++++++---- src/util/http_downloader.h | 22 ++++-- src/util/http_downloader_curl.cpp | 13 ++-- src/util/http_downloader_winhttp.cpp | 19 ++--- 11 files changed, 183 insertions(+), 77 deletions(-) diff --git a/src/core/achievements.cpp b/src/core/achievements.cpp index 1a97c9b9e..bf948148f 100644 --- a/src/core/achievements.cpp +++ b/src/core/achievements.cpp @@ -882,9 +882,9 @@ uint32_t Achievements::ClientReadMemory(uint32_t address, uint8_t* buffer, uint3 void Achievements::ClientServerCall(const rc_api_request_t* request, rc_client_server_callback_t callback, void* callback_data, rc_client_t* client) { - HTTPDownloader::Request::Callback hd_callback = [callback, callback_data](s32 status_code, const Error& error, - const std::string& content_type, - HTTPDownloader::Request::Data data) { + HTTPDownloader::Request::Callback hd_callback = [callback, callback_data](s32 status_code, Error& error, + std::string& content_type, + HTTPDownloader::Request::Data& data) { if (status_code != HTTPDownloader::HTTP_STATUS_OK) ERROR_LOG("Server call failed: {}", error.GetDescription()); @@ -904,12 +904,12 @@ void Achievements::ClientServerCall(const rc_api_request_t* request, rc_client_s { // const auto pd = std::string_view(request->post_data); // Log_DevFmt("Server POST: {}", pd.substr(0, std::min(pd.length(), 10))); - downloader->CreatePostRequest(request->url, request->post_data, std::move(hd_callback), nullptr, headers, + downloader->CreatePostRequest(request->url, request->post_data, &s_state, std::move(hd_callback), nullptr, headers, SERVER_CALL_TIMEOUT); } else { - downloader->CreateRequest(request->url, std::move(hd_callback), nullptr, headers, SERVER_CALL_TIMEOUT); + downloader->CreateRequest(request->url, &s_state, std::move(hd_callback), nullptr, headers, SERVER_CALL_TIMEOUT); } } diff --git a/src/core/game_list.cpp b/src/core/game_list.cpp index d66a78772..9747e9c08 100644 --- a/src/core/game_list.cpp +++ b/src/core/game_list.cpp @@ -1855,10 +1855,10 @@ bool GameList::DownloadCovers(const std::vector& url_templates, boo std::string filename = Path::URLDecode(url); if (HTTPDownloader* const downloader = HTTPCache::GetDownloader(error)) { - downloader->CreateRequest(std::move(url), [use_serial, &save_callback, entry_path = std::move(entry_path), - filename = std::move(filename)](s32 status_code, const Error& error, - const std::string& content_type, - HTTPDownloader::Request::Data data) { + downloader->CreateRequest( + std::move(url), &s_state, + [use_serial, &save_callback, entry_path = std::move(entry_path), filename = std::move(filename)]( + s32 status_code, Error& error, std::string& content_type, HTTPDownloader::Request::Data& data) { if (status_code != HTTPDownloader::HTTP_STATUS_OK || data.empty()) { ERROR_LOG("Download for {} failed: {}", Path::GetFileName(filename), error.GetDescription()); diff --git a/src/duckstation-qt/autoupdaterdialog.cpp b/src/duckstation-qt/autoupdaterdialog.cpp index 63a0685ec..90d100056 100644 --- a/src/duckstation-qt/autoupdaterdialog.cpp +++ b/src/duckstation-qt/autoupdaterdialog.cpp @@ -11,8 +11,8 @@ #include "core/core.h" -#include "util/http_downloader.h" #include "util/http_cache.h" +#include "util/http_downloader.h" #include "util/translation.h" #include "common/assert.h" @@ -359,22 +359,23 @@ void AutoUpdaterDialog::queueUpdateCheck(bool display_errors, bool ignore_skippe } ensureHttpPollingActive(); - m_http->CreateRequest(LATEST_TAG_URL, - [this, display_errors](s32 status_code, const Error& error, const std::string& content_type, - std::vector response) { - getLatestTagComplete(status_code, error, std::move(response), display_errors); - }); + m_http->CreateRequest( + LATEST_TAG_URL, this, + [this, display_errors](s32 status_code, Error& error, std::string& content_type, std::vector& response) { + getLatestTagComplete(status_code, error, response, display_errors); + }); } void AutoUpdaterDialog::queueGetLatestRelease() { ensureHttpPollingActive(); std::string url = fmt::format(LATEST_RELEASE_URL, getCurrentUpdateTag()); - m_http->CreateRequest(std::move(url), std::bind(&AutoUpdaterDialog::getLatestReleaseComplete, this, - std::placeholders::_1, std::placeholders::_2, std::placeholders::_4)); + m_http->CreateRequest(std::move(url), this, + std::bind(&AutoUpdaterDialog::getLatestReleaseComplete, this, std::placeholders::_1, + std::placeholders::_2, std::placeholders::_4)); } -void AutoUpdaterDialog::getLatestTagComplete(s32 status_code, const Error& error, std::vector response, +void AutoUpdaterDialog::getLatestTagComplete(s32 status_code, Error& error, std::vector& response, bool display_errors) { if (handleCancelledRequest(status_code)) @@ -441,7 +442,7 @@ void AutoUpdaterDialog::getLatestTagComplete(s32 status_code, const Error& error emit updateCheckCompleted(false); } -void AutoUpdaterDialog::getLatestReleaseComplete(s32 status_code, const Error& error, std::vector response) +void AutoUpdaterDialog::getLatestReleaseComplete(s32 status_code, Error& error, std::vector& response) { if (handleCancelledRequest(status_code)) return; @@ -521,11 +522,12 @@ void AutoUpdaterDialog::queueGetChanges() { ensureHttpPollingActive(); std::string url = fmt::format(CHANGES_URL, g_scm_hash_str, getCurrentUpdateTag()); - m_http->CreateRequest(std::move(url), std::bind(&AutoUpdaterDialog::getChangesComplete, this, std::placeholders::_1, - std::placeholders::_2, std::placeholders::_4)); + m_http->CreateRequest(std::move(url), this, + std::bind(&AutoUpdaterDialog::getChangesComplete, this, std::placeholders::_1, + std::placeholders::_2, std::placeholders::_4)); } -void AutoUpdaterDialog::getChangesComplete(s32 status_code, const Error& error, std::vector response) +void AutoUpdaterDialog::getChangesComplete(s32 status_code, Error& error, std::vector& response) { std::string_view error_message; @@ -607,8 +609,8 @@ void AutoUpdaterDialog::downloadUpdateClicked() ensureHttpPollingActive(); m_http->CreateRequest( - m_download_url.toStdString(), - [this](s32 status_code, const Error& error, const std::string&, std::vector response) { + m_download_url.toStdString(), this, + [this](s32 status_code, Error& error, std::string&, std::vector& response) { m_download_progress_callback->SetStatusText(TRANSLATE_SV("AutoUpdaterWindow", "Processing Update...")); m_download_progress_callback->SetProgressRange(1); m_download_progress_callback->SetProgressValue(1); diff --git a/src/duckstation-qt/autoupdaterdialog.h b/src/duckstation-qt/autoupdaterdialog.h index 4b915519f..678938160 100644 --- a/src/duckstation-qt/autoupdaterdialog.h +++ b/src/duckstation-qt/autoupdaterdialog.h @@ -71,11 +71,11 @@ private: bool updateNeeded() const; - void getLatestTagComplete(s32 status_code, const Error& error, std::vector response, bool display_errors); - void getLatestReleaseComplete(s32 status_code, const Error& error, std::vector response); + void getLatestTagComplete(s32 status_code, Error& error, std::vector& response, bool display_errors); + void getLatestReleaseComplete(s32 status_code, Error& error, std::vector& response); void queueGetChanges(); - void getChangesComplete(s32 status_code, const Error& error, std::vector response); + void getChangesComplete(s32 status_code, Error& error, std::vector& response); bool processUpdate(const std::vector& update_data); diff --git a/src/duckstation-qt/qthost.cpp b/src/duckstation-qt/qthost.cpp index 0760f600a..727736b0d 100644 --- a/src/duckstation-qt/qthost.cpp +++ b/src/duckstation-qt/qthost.cpp @@ -738,7 +738,7 @@ void QtHost::DownloadFile(QWidget* parent, std::string url, std::string path, QtAsyncTaskWithProgressDialog::create( parent, TRANSLATE_SV("QtHost", "File Download"), status_text, false, true, 0, 0, 0.0f, true, - [url = std::move(url), path = std::move(path), + [parent, url = std::move(url), path = std::move(path), completion_callback = std::move(completion_callback)](ProgressCallback* const progress) mutable { Error error; bool result = false; @@ -746,9 +746,8 @@ void QtHost::DownloadFile(QWidget* parent, std::string url, std::string path, { result = true; downloader->CreateRequest( - std::move(url), - [&result, &error, &path](s32 status_code, const Error& http_error, const std::string&, - std::vector hdata) { + std::move(url), parent, + [&result, &error, &path](s32 status_code, Error& http_error, std::string&, std::vector& hdata) { if (status_code != HTTPDownloader::HTTP_STATUS_OK) { error.SetString(http_error.GetDescription()); @@ -766,7 +765,7 @@ void QtHost::DownloadFile(QWidget* parent, std::string url, std::string path, } // Block until completion. - HTTPCache::WaitForAllRequests(); + HTTPCache::WaitForAllRequestsFromOwner(parent); QtAsyncTaskWithProgressDialog::CompletionCallback ret; if (completion_callback) diff --git a/src/util/http_cache.cpp b/src/util/http_cache.cpp index 6eb3f70e5..28687c553 100644 --- a/src/util/http_cache.cpp +++ b/src/util/http_cache.cpp @@ -135,12 +135,36 @@ void HTTPCache::WaitForAllRequests() s_locals.downloader->WaitForAllRequests(); } +void HTTPCache::WaitForAllRequestsFromOwner(const void* owner) +{ + if (s_locals.downloader) + s_locals.downloader->WaitForAllRequestsFromOwner(owner); +} + void HTTPCache::WaitForAllRequestsWithYield(std::function before_sleep_cb, std::function after_sleep_cb) { if (s_locals.downloader) s_locals.downloader->WaitForAllRequestsWithYield(std::move(before_sleep_cb), std::move(after_sleep_cb)); } +void HTTPCache::WaitForAllRequestsFromOwnerWithYield(const void* owner, std::function before_sleep_cb, + std::function after_sleep_cb) +{ + if (s_locals.downloader) + { + s_locals.downloader->WaitForAllRequestsFromOwnerWithYield(owner, std::move(before_sleep_cb), + std::move(after_sleep_cb)); + } +} + +void HTTPCache::CancelRequestsForOwner(const void* owner) +{ + if (!s_locals.downloader) + return; + + s_locals.downloader->CancelRequestsForOwner(owner); +} + HTTPDownloader* HTTPCache::GetDownloader(Error* create_error) { if (s_locals.downloader) [[likely]] @@ -261,11 +285,11 @@ bool HTTPCache::QueueDownload(std::string_view url, FetchCallback callback, Erro DEV_LOG("Cache miss for URL '{}', downloading...", url); - downloader->CreateRequest(std::string(url), [url = std::string(url)](s32 status_code, const Error& error, - const std::string& content_type, - HTTPDownloader::Request::Data data) { - DownloadCallback(url, status_code, error, content_type, std::move(data)); - }); + downloader->CreateRequest(std::string(url), &s_locals, + [url = std::string(url)](s32 status_code, Error& error, std::string& content_type, + HTTPDownloader::Request::Data& data) { + DownloadCallback(url, status_code, error, content_type, std::move(data)); + }); return true; } diff --git a/src/util/http_cache.h b/src/util/http_cache.h index 745ca30a9..ec98121b8 100644 --- a/src/util/http_cache.h +++ b/src/util/http_cache.h @@ -53,6 +53,11 @@ std::string GetUserAgent(); /// Shuts down the HTTP cache, releasing the downloader and cache archive. void Shutdown(); +/// Returns a pointer to the shared HTTP downloader, creating it on first use. +/// If @p create_error is non-null, creation details are written there on failure; if null, creation +/// is skipped after the first failed attempt. +HTTPDownloader* GetDownloader(Error* create_error = nullptr); + /// Returns true if idle updates are necessary (e.g. outstanding requests). bool IsDownloaderActive(); @@ -61,14 +66,15 @@ void PollRequests(); /// Waits for all requests to finish. void WaitForAllRequests(); +void WaitForAllRequestsFromOwner(const void* owner); /// Waits for all requests to finish, periodically yielding to allow other tasks to run. void WaitForAllRequestsWithYield(std::function before_sleep_cb, std::function after_sleep_cb); +void WaitForAllRequestsFromOwnerWithYield(const void* owner, std::function before_sleep_cb, + std::function after_sleep_cb); -/// Returns a locked pointer to the shared HTTP downloader, creating it on first use. -/// If @p create_error is non-null, creation details are written there on failure; if null, creation -/// is skipped after the first failed attempt. -HTTPDownloader* GetDownloader(Error* create_error = nullptr); +/// Cancels all outstanding requests for the specified owner. +void CancelRequestsForOwner(const void* owner); /// Returns a locked pointer to the shared cache archive, opening it on first use. CacheArchivePtr GetCacheArchive(); diff --git a/src/util/http_downloader.cpp b/src/util/http_downloader.cpp index 0ee65dbdd..d6f216ea9 100644 --- a/src/util/http_downloader.cpp +++ b/src/util/http_downloader.cpp @@ -24,9 +24,10 @@ HTTPDownloader::HTTPDownloader() HTTPDownloader::~HTTPDownloader() = default; -HTTPDownloader::Request::Request(HTTPDownloader* parent, Type type, std::string url, std::string post_data, - Callback callback, ProgressCallback* progress, u16 timeout_seconds) - : parent(parent), callback(std::move(callback)), progress(progress), url(std::move(url)), +HTTPDownloader::Request::Request(HTTPDownloader* parent, const void* owner, Type type, std::string url, + std::string post_data, Callback callback, ProgressCallback* progress, + u16 timeout_seconds) + : parent(parent), owner(owner), callback(std::move(callback)), progress(progress), url(std::move(url)), post_data(std::move(post_data)), type(type), timeout_seconds(timeout_seconds) { // set progress state to indeterminate until we know the size @@ -47,23 +48,24 @@ void HTTPDownloader::SetMaxActiveRequests(u32 max_active_requests) m_max_active_requests = max_active_requests; } -void HTTPDownloader::CreateRequest(std::string url, Request::Callback callback, +void HTTPDownloader::CreateRequest(std::string url, const void* owner, Request::Callback callback, ProgressCallback* progress /* = nullptr */, HeaderList additional_headers /* = */, std::optional timeout_seconds /* = */) { - Request* req = InternalCreateRequest(Request::Type::Get, std::move(url), {}, std::move(callback), progress, + Request* req = InternalCreateRequest(Request::Type::Get, std::move(url), {}, owner, std::move(callback), progress, timeout_seconds.value_or(m_default_timeout), additional_headers); DebugAssert(req); StartOrAddRequest(req); } -void HTTPDownloader::CreatePostRequest(std::string url, std::string post_data, Request::Callback callback, - ProgressCallback* progress /* = nullptr */, +void HTTPDownloader::CreatePostRequest(std::string url, std::string post_data, const void* owner, + Request::Callback callback, ProgressCallback* progress /* = nullptr */, HeaderList additional_headers /* = */, std::optional timeout_seconds /* = */) { - Request* req = InternalCreateRequest(Request::Type::Post, std::move(url), std::move(post_data), std::move(callback), - progress, timeout_seconds.value_or(m_default_timeout), additional_headers); + Request* req = + InternalCreateRequest(Request::Type::Post, std::move(url), std::move(post_data), owner, std::move(callback), + progress, timeout_seconds.value_or(m_default_timeout), additional_headers); DebugAssert(req); StartOrAddRequest(req); } @@ -112,7 +114,7 @@ void HTTPDownloader::LockedPollRequests(std::unique_lock& lock) lock.unlock(); req->error.SetStringFmt("Request timed out after {} seconds.", req->timeout_seconds); - req->callback(HTTP_STATUS_TIMEOUT, req->error, std::string(), Request::Data()); + req->callback(HTTP_STATUS_TIMEOUT, req->error, req->content_type, req->data); CloseRequest(req); @@ -130,7 +132,7 @@ void HTTPDownloader::LockedPollRequests(std::unique_lock& lock) lock.unlock(); req->error.SetStringView("Request was cancelled."); - req->callback(HTTP_STATUS_CANCELLED, req->error, std::string(), Request::Data()); + req->callback(HTTP_STATUS_CANCELLED, req->error, req->content_type, req->data); CloseRequest(req); @@ -168,7 +170,7 @@ void HTTPDownloader::LockedPollRequests(std::unique_lock& lock) else if (req->status_code < 0) DEV_LOG("Request failed with error {}", req->error.GetDescription()); - req->callback(req->status_code, req->error, req->content_type, std::move(req->data)); + req->callback(req->status_code, req->error, req->content_type, req->data); CloseRequest(req); lock.lock(); } @@ -240,6 +242,51 @@ void HTTPDownloader::WaitForAllRequestsWithYield(std::function before_sl } } +void HTTPDownloader::WaitForAllRequestsFromOwner(const void* owner) +{ + if (!owner) + { + WaitForAllRequests(); + return; + } + + std::unique_lock lock(m_pending_http_request_lock); + while (std::ranges::any_of(m_pending_http_requests, [owner](const Request* req) { return req->owner == owner; })) + { + // Don't burn too much CPU. + Timer::NanoSleep(WAIT_FOR_ALL_REQUESTS_POLL_INTERVAL_NS); + LockedPollRequests(lock); + } +} + +void HTTPDownloader::WaitForAllRequestsFromOwnerWithYield(const void* owner, std::function before_sleep_cb, + std::function after_sleep_cb) +{ + if (!owner) + { + WaitForAllRequestsWithYield(std::move(before_sleep_cb), std::move(after_sleep_cb)); + return; + } + + std::unique_lock lock(m_pending_http_request_lock); + while (std::ranges::any_of(m_pending_http_requests, [owner](const Request* req) { return req->owner == owner; })) + { + // Don't burn too much CPU. + if (before_sleep_cb) + { + lock.unlock(); + before_sleep_cb(); + } + Timer::NanoSleep(WAIT_FOR_ALL_REQUESTS_POLL_INTERVAL_NS); + if (after_sleep_cb) + { + after_sleep_cb(); + lock.lock(); + } + LockedPollRequests(lock); + } +} + void HTTPDownloader::LockedAddRequest(Request* request) { m_pending_http_requests.push_back(request); @@ -263,7 +310,21 @@ bool HTTPDownloader::HasAnyRequests() return !m_pending_http_requests.empty(); } +bool HTTPDownloader::HasAnyRequestsFromOwner(const void* owner) +{ + if (!owner) + return HasAnyRequests(); + + std::unique_lock lock(m_pending_http_request_lock); + return std::ranges::any_of(m_pending_http_requests, [owner](const Request* req) { return req->owner == owner; }); +} + void HTTPDownloader::CancelAllRequests() +{ + CancelRequestsForOwner(nullptr); +} + +void HTTPDownloader::CancelRequestsForOwner(const void* owner) { std::unique_lock lock(m_pending_http_request_lock); @@ -277,6 +338,12 @@ void HTTPDownloader::CancelAllRequests() for (size_t index = 0; index < m_pending_http_requests.size();) { Request* req = m_pending_http_requests[index]; + if (owner && req->owner != owner) + { + index++; + continue; + } + const Request::State req_state = req->state.load(std::memory_order_acquire); // can't cancel a request in pending stage @@ -296,7 +363,7 @@ void HTTPDownloader::CancelAllRequests() lock.unlock(); req->error.SetStringView("Request was cancelled."); - req->callback(HTTP_STATUS_CANCELLED, req->error, std::string(), Request::Data()); + req->callback(HTTP_STATUS_CANCELLED, req->error, req->content_type, req->data); CloseRequest(req); diff --git a/src/util/http_downloader.h b/src/util/http_downloader.h index e3e242410..04d73b123 100644 --- a/src/util/http_downloader.h +++ b/src/util/http_downloader.h @@ -36,8 +36,7 @@ public: struct Request { using Data = std::vector; - using Callback = - std::function; + using Callback = std::function; enum class Type : u8 { @@ -54,11 +53,12 @@ public: Complete, }; - Request(HTTPDownloader* parent, Type type, std::string url, std::string post_data, Callback callback, - ProgressCallback* progress, u16 timeout_seconds); + Request(HTTPDownloader* parent, const void* owner, Type type, std::string url, std::string post_data, + Callback callback, ProgressCallback* progress, u16 timeout_seconds); virtual ~Request(); HTTPDownloader* parent; + const void* owner; Callback callback; ProgressCallback* progress; std::string url; @@ -85,19 +85,25 @@ public: void SetDefaultTimeout(u16 timeout_seconds); void SetMaxActiveRequests(u32 max_active_requests); - void CreateRequest(std::string url, Request::Callback callback, ProgressCallback* progress = nullptr, - HeaderList additional_headers = {}, std::optional timeout_seconds = {}); - void CreatePostRequest(std::string url, std::string post_data, Request::Callback callback, + void CreateRequest(std::string url, const void* owner, Request::Callback callback, + ProgressCallback* progress = nullptr, HeaderList additional_headers = {}, + std::optional timeout_seconds = {}); + void CreatePostRequest(std::string url, std::string post_data, const void* owner, Request::Callback callback, ProgressCallback* progress = nullptr, HeaderList additional_headers = {}, std::optional timeout_seconds = {}); bool PollRequests(); void WaitForAllRequests(); void WaitForAllRequestsWithYield(std::function before_sleep_cb, std::function after_sleep_cb); + void WaitForAllRequestsFromOwner(const void* owner); + void WaitForAllRequestsFromOwnerWithYield(const void* owner, std::function before_sleep_cb, + std::function after_sleep_cb); bool HasAnyRequests(); + bool HasAnyRequestsFromOwner(const void* owner); void CancelAllRequests(); + void CancelRequestsForOwner(const void* owner); protected: - virtual Request* InternalCreateRequest(Request::Type type, std::string url, std::string post_data, + virtual Request* InternalCreateRequest(Request::Type type, std::string url, std::string post_data, const void* owner, Request::Callback callback, ProgressCallback* progress, u16 timeout_seconds, HeaderList additional_headers) = 0; diff --git a/src/util/http_downloader_curl.cpp b/src/util/http_downloader_curl.cpp index 425808a7f..0829ccdf7 100644 --- a/src/util/http_downloader_curl.cpp +++ b/src/util/http_downloader_curl.cpp @@ -30,8 +30,8 @@ public: bool Initialize(std::string user_agent, Error* error); protected: - Request* InternalCreateRequest(Request::Type type, std::string url, std::string post_data, Request::Callback callback, - ProgressCallback* progress, u16 timeout_seconds, + Request* InternalCreateRequest(Request::Type type, std::string url, std::string post_data, const void* owner, + Request::Callback callback, ProgressCallback* progress, u16 timeout_seconds, HeaderList additional_headers) override; bool StartRequest(HTTPDownloader::Request* request) override; void CloseRequest(HTTPDownloader::Request* request) override; @@ -171,12 +171,13 @@ HTTPDownloaderCurl::Request::~Request() } HTTPDownloader::Request* HTTPDownloaderCurl::InternalCreateRequest(Request::Type type, std::string url, - std::string post_data, Request::Callback callback, + std::string post_data, const void* owner, + Request::Callback callback, ProgressCallback* progress, u16 timeout_seconds, HeaderList additional_headers) { - Request* req = - new Request(this, type, std::move(url), std::move(post_data), std::move(callback), progress, timeout_seconds); + Request* req = new Request(this, owner, type, std::move(url), std::move(post_data), std::move(callback), progress, + timeout_seconds); for (const char* header : additional_headers) req->header_list = curl_slist_append(req->header_list, header); @@ -303,7 +304,7 @@ bool HTTPDownloaderCurl::StartRequest(HTTPDownloader::Request* request) { ERROR_LOG("curl_easy_init() failed"); req->error.SetStringView("curl_easy_init() failed"); - req->callback(HTTP_STATUS_ERROR, req->error, std::string(), req->data); + req->callback(HTTP_STATUS_ERROR, req->error, req->content_type, req->data); delete req; return false; } diff --git a/src/util/http_downloader_winhttp.cpp b/src/util/http_downloader_winhttp.cpp index 535b55cbb..5b612bd79 100644 --- a/src/util/http_downloader_winhttp.cpp +++ b/src/util/http_downloader_winhttp.cpp @@ -24,8 +24,8 @@ public: bool Initialize(std::string user_agent, Error* error); protected: - Request* InternalCreateRequest(Request::Type type, std::string url, std::string post_data, Request::Callback callback, - ProgressCallback* progress, u16 timeout_seconds, + Request* InternalCreateRequest(Request::Type type, std::string url, std::string post_data, const void* owner, + Request::Callback callback, ProgressCallback* progress, u16 timeout_seconds, HeaderList additional_headers) override; bool StartRequest(HTTPDownloader::Request* request) override; void CloseRequest(HTTPDownloader::Request* request) override; @@ -261,12 +261,13 @@ void CALLBACK HTTPDownloaderWinHttp::HTTPStatusCallback(HINTERNET hRequest, DWOR } HTTPDownloader::Request* HTTPDownloaderWinHttp::InternalCreateRequest(Request::Type type, std::string url, - std::string post_data, Request::Callback callback, + std::string post_data, const void* owner, + Request::Callback callback, ProgressCallback* progress, u16 timeout_seconds, HeaderList additional_headers) { - Request* req = - new Request(this, type, std::move(url), std::move(post_data), std::move(callback), progress, timeout_seconds); + Request* req = new Request(this, owner, type, std::move(url), std::move(post_data), std::move(callback), progress, + timeout_seconds); if (!additional_headers.empty()) { @@ -307,7 +308,7 @@ bool HTTPDownloaderWinHttp::StartRequest(HTTPDownloader::Request* request) const DWORD err = GetLastError(); ERROR_LOG("WinHttpCrackUrl() failed: {}", err); req->error.SetWin32("WinHttpCrackUrl() failed: ", err); - req->callback(HTTP_STATUS_ERROR, req->error, std::string(), req->data); + req->callback(HTTP_STATUS_ERROR, req->error, req->content_type, req->data); delete req; return false; } @@ -321,7 +322,7 @@ bool HTTPDownloaderWinHttp::StartRequest(HTTPDownloader::Request* request) const DWORD err = GetLastError(); ERROR_LOG("Failed to start HTTP request for '{}': {}", req->url, err); req->error.SetWin32("WinHttpConnect() failed: ", err); - req->callback(HTTP_STATUS_ERROR, req->error, std::string(), req->data); + req->callback(HTTP_STATUS_ERROR, req->error, req->content_type, req->data); delete req; return false; } @@ -335,7 +336,7 @@ bool HTTPDownloaderWinHttp::StartRequest(HTTPDownloader::Request* request) const DWORD err = GetLastError(); ERROR_LOG("WinHttpOpenRequest() failed: {}", err); req->error.SetWin32("WinHttpOpenRequest() failed: ", err); - req->callback(HTTP_STATUS_ERROR, req->error, std::string(), req->data); + req->callback(HTTP_STATUS_ERROR, req->error, req->content_type, req->data); WinHttpCloseHandle(req->hConnection); delete req; return false; @@ -349,7 +350,7 @@ bool HTTPDownloaderWinHttp::StartRequest(HTTPDownloader::Request* request) const DWORD err = GetLastError(); ERROR_LOG("WinHttpAddRequestHeaders() failed: {}", err); req->error.SetWin32("WinHttpAddRequestHeaders() failed: ", err); - req->callback(HTTP_STATUS_ERROR, req->error, std::string(), req->data); + req->callback(HTTP_STATUS_ERROR, req->error, req->content_type, req->data); WinHttpCloseHandle(req->hRequest); WinHttpCloseHandle(req->hConnection); delete req;