HTTPDownloader: Improve error reporting
Give something human-readable when an error occurs.
This commit is contained in:
parent
6d72a48708
commit
dac5dd562b
|
@ -141,6 +141,6 @@ private:
|
||||||
void AddPrefixFmtArgs(fmt::string_view fmt, fmt::format_args args);
|
void AddPrefixFmtArgs(fmt::string_view fmt, fmt::format_args args);
|
||||||
void AddSuffixFmtArgs(fmt::string_view fmt, fmt::format_args args);
|
void AddSuffixFmtArgs(fmt::string_view fmt, fmt::format_args args);
|
||||||
|
|
||||||
Type m_type = Type::None;
|
|
||||||
std::string m_description;
|
std::string m_description;
|
||||||
|
Type m_type = Type::None;
|
||||||
};
|
};
|
||||||
|
|
|
@ -354,10 +354,13 @@ std::string Achievements::GetLocalImagePath(const std::string_view image_name, i
|
||||||
|
|
||||||
void Achievements::DownloadImage(std::string url, std::string cache_filename)
|
void Achievements::DownloadImage(std::string url, std::string cache_filename)
|
||||||
{
|
{
|
||||||
auto callback = [cache_filename](s32 status_code, const std::string& content_type,
|
auto callback = [cache_filename](s32 status_code, const Error& error, const std::string& content_type,
|
||||||
HTTPDownloader::Request::Data data) {
|
HTTPDownloader::Request::Data data) {
|
||||||
if (status_code != HTTPDownloader::HTTP_STATUS_OK)
|
if (status_code != HTTPDownloader::HTTP_STATUS_OK)
|
||||||
|
{
|
||||||
|
ERROR_LOG("Failed to download badge '{}': {}", Path::GetFileName(cache_filename), error.GetDescription());
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!FileSystem::WriteBinaryFile(cache_filename.c_str(), data.data(), data.size()))
|
if (!FileSystem::WriteBinaryFile(cache_filename.c_str(), data.data(), data.size()))
|
||||||
{
|
{
|
||||||
|
@ -753,8 +756,12 @@ 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 Achievements::ClientServerCall(const rc_api_request_t* request, rc_client_server_callback_t callback,
|
||||||
void* callback_data, rc_client_t* client)
|
void* callback_data, rc_client_t* client)
|
||||||
{
|
{
|
||||||
HTTPDownloader::Request::Callback hd_callback =
|
HTTPDownloader::Request::Callback hd_callback = [callback, callback_data](s32 status_code, const Error& error,
|
||||||
[callback, callback_data](s32 status_code, const std::string& content_type, HTTPDownloader::Request::Data data) {
|
const std::string& content_type,
|
||||||
|
HTTPDownloader::Request::Data data) {
|
||||||
|
if (status_code != HTTPDownloader::HTTP_STATUS_OK)
|
||||||
|
ERROR_LOG("Server call failed: {}", error.GetDescription());
|
||||||
|
|
||||||
rc_api_server_response_t rr;
|
rc_api_server_response_t rr;
|
||||||
rr.http_status_code = (status_code <= 0) ? (status_code == HTTPDownloader::HTTP_STATUS_CANCELLED ?
|
rr.http_status_code = (status_code <= 0) ? (status_code == HTTPDownloader::HTTP_STATUS_CANCELLED ?
|
||||||
RC_API_SERVER_RESPONSE_CLIENT_ERROR :
|
RC_API_SERVER_RESPONSE_CLIENT_ERROR :
|
||||||
|
|
|
@ -1454,10 +1454,11 @@ bool GameList::DownloadCovers(const std::vector<std::string>& url_templates, boo
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<HTTPDownloader> downloader(HTTPDownloader::Create(Host::GetHTTPUserAgent()));
|
Error error;
|
||||||
|
std::unique_ptr<HTTPDownloader> downloader(HTTPDownloader::Create(Host::GetHTTPUserAgent(), &error));
|
||||||
if (!downloader)
|
if (!downloader)
|
||||||
{
|
{
|
||||||
progress->DisplayError("Failed to create HTTP downloader.");
|
progress->DisplayError(fmt::format("Failed to create HTTP downloader:\n{}", error.GetDescription()));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1484,11 +1485,15 @@ bool GameList::DownloadCovers(const std::vector<std::string>& url_templates, boo
|
||||||
|
|
||||||
// we could actually do a few in parallel here...
|
// we could actually do a few in parallel here...
|
||||||
std::string filename = Path::URLDecode(url);
|
std::string filename = Path::URLDecode(url);
|
||||||
downloader->CreateRequest(
|
downloader->CreateRequest(std::move(url), [use_serial, &save_callback, entry_path = std::move(entry_path),
|
||||||
std::move(url), [use_serial, &save_callback, entry_path = std::move(entry_path), filename = std::move(filename)](
|
filename = std::move(filename)](s32 status_code, const Error& error,
|
||||||
s32 status_code, const std::string& content_type, HTTPDownloader::Request::Data data) {
|
const std::string& content_type,
|
||||||
|
HTTPDownloader::Request::Data data) {
|
||||||
if (status_code != HTTPDownloader::HTTP_STATUS_OK || data.empty())
|
if (status_code != HTTPDownloader::HTTP_STATUS_OK || data.empty())
|
||||||
|
{
|
||||||
|
ERROR_LOG("Download for {} failed: {}", Path::GetFileName(filename), error.GetDescription());
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
std::unique_lock lock(s_mutex);
|
std::unique_lock lock(s_mutex);
|
||||||
const GameList::Entry* entry = GetEntryForPath(entry_path);
|
const GameList::Entry* entry = GetEntryForPath(entry_path);
|
||||||
|
|
|
@ -88,9 +88,10 @@ AutoUpdaterDialog::AutoUpdaterDialog(QWidget* parent /* = nullptr */) : QDialog(
|
||||||
connect(m_ui.skipThisUpdate, &QPushButton::clicked, this, &AutoUpdaterDialog::skipThisUpdateClicked);
|
connect(m_ui.skipThisUpdate, &QPushButton::clicked, this, &AutoUpdaterDialog::skipThisUpdateClicked);
|
||||||
connect(m_ui.remindMeLater, &QPushButton::clicked, this, &AutoUpdaterDialog::remindMeLaterClicked);
|
connect(m_ui.remindMeLater, &QPushButton::clicked, this, &AutoUpdaterDialog::remindMeLaterClicked);
|
||||||
|
|
||||||
m_http = HTTPDownloader::Create(Host::GetHTTPUserAgent());
|
Error error;
|
||||||
|
m_http = HTTPDownloader::Create(Host::GetHTTPUserAgent(), &error);
|
||||||
if (!m_http)
|
if (!m_http)
|
||||||
ERROR_LOG("Failed to create HTTP downloader, auto updater will not be available.");
|
ERROR_LOG("Failed to create HTTP downloader, auto updater will not be available:\n{}", error.GetDescription());
|
||||||
}
|
}
|
||||||
|
|
||||||
AutoUpdaterDialog::~AutoUpdaterDialog() = default;
|
AutoUpdaterDialog::~AutoUpdaterDialog() = default;
|
||||||
|
@ -277,7 +278,7 @@ void AutoUpdaterDialog::queueUpdateCheck(bool display_message)
|
||||||
}
|
}
|
||||||
|
|
||||||
m_http->CreateRequest(LATEST_TAG_URL, std::bind(&AutoUpdaterDialog::getLatestTagComplete, this, std::placeholders::_1,
|
m_http->CreateRequest(LATEST_TAG_URL, std::bind(&AutoUpdaterDialog::getLatestTagComplete, this, std::placeholders::_1,
|
||||||
std::placeholders::_3));
|
std::placeholders::_2, std::placeholders::_4));
|
||||||
#else
|
#else
|
||||||
emit updateCheckCompleted();
|
emit updateCheckCompleted();
|
||||||
#endif
|
#endif
|
||||||
|
@ -294,11 +295,11 @@ void AutoUpdaterDialog::queueGetLatestRelease()
|
||||||
|
|
||||||
std::string url = fmt::format(fmt::runtime(LATEST_RELEASE_URL), getCurrentUpdateTag());
|
std::string url = fmt::format(fmt::runtime(LATEST_RELEASE_URL), getCurrentUpdateTag());
|
||||||
m_http->CreateRequest(std::move(url), std::bind(&AutoUpdaterDialog::getLatestReleaseComplete, this,
|
m_http->CreateRequest(std::move(url), std::bind(&AutoUpdaterDialog::getLatestReleaseComplete, this,
|
||||||
std::placeholders::_1, std::placeholders::_3));
|
std::placeholders::_1, std::placeholders::_2, std::placeholders::_4));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void AutoUpdaterDialog::getLatestTagComplete(s32 status_code, std::vector<u8> response)
|
void AutoUpdaterDialog::getLatestTagComplete(s32 status_code, const Error& error, std::vector<u8> response)
|
||||||
{
|
{
|
||||||
#ifdef UPDATE_CHECKER_SUPPORTED
|
#ifdef UPDATE_CHECKER_SUPPORTED
|
||||||
const std::string selected_tag(getCurrentUpdateTag());
|
const std::string selected_tag(getCurrentUpdateTag());
|
||||||
|
@ -351,14 +352,14 @@ void AutoUpdaterDialog::getLatestTagComplete(s32 status_code, std::vector<u8> re
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (m_display_messages)
|
if (m_display_messages)
|
||||||
reportError(fmt::format("Failed to download latest tag info: HTTP {}", status_code));
|
reportError(fmt::format("Failed to download latest tag info: {}", error.GetDescription()));
|
||||||
}
|
}
|
||||||
|
|
||||||
emit updateCheckCompleted();
|
emit updateCheckCompleted();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void AutoUpdaterDialog::getLatestReleaseComplete(s32 status_code, std::vector<u8> response)
|
void AutoUpdaterDialog::getLatestReleaseComplete(s32 status_code, const Error& error, std::vector<u8> response)
|
||||||
{
|
{
|
||||||
#ifdef UPDATE_CHECKER_SUPPORTED
|
#ifdef UPDATE_CHECKER_SUPPORTED
|
||||||
if (status_code == HTTPDownloader::HTTP_STATUS_OK)
|
if (status_code == HTTPDownloader::HTTP_STATUS_OK)
|
||||||
|
@ -415,7 +416,7 @@ void AutoUpdaterDialog::getLatestReleaseComplete(s32 status_code, std::vector<u8
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
reportError(fmt::format("Failed to download latest release info: HTTP {}", status_code));
|
reportError(fmt::format("Failed to download latest release info: {}", error.GetDescription()));
|
||||||
}
|
}
|
||||||
|
|
||||||
emit updateCheckCompleted();
|
emit updateCheckCompleted();
|
||||||
|
@ -430,11 +431,11 @@ void AutoUpdaterDialog::queueGetChanges()
|
||||||
|
|
||||||
std::string url = fmt::format(fmt::runtime(CHANGES_URL), g_scm_hash_str, getCurrentUpdateTag());
|
std::string url = fmt::format(fmt::runtime(CHANGES_URL), g_scm_hash_str, getCurrentUpdateTag());
|
||||||
m_http->CreateRequest(std::move(url), std::bind(&AutoUpdaterDialog::getChangesComplete, this, std::placeholders::_1,
|
m_http->CreateRequest(std::move(url), std::bind(&AutoUpdaterDialog::getChangesComplete, this, std::placeholders::_1,
|
||||||
std::placeholders::_3));
|
std::placeholders::_2, std::placeholders::_4));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void AutoUpdaterDialog::getChangesComplete(s32 status_code, std::vector<u8> response)
|
void AutoUpdaterDialog::getChangesComplete(s32 status_code, const Error& error, std::vector<u8> response)
|
||||||
{
|
{
|
||||||
#ifdef UPDATE_CHECKER_SUPPORTED
|
#ifdef UPDATE_CHECKER_SUPPORTED
|
||||||
if (status_code == HTTPDownloader::HTTP_STATUS_OK)
|
if (status_code == HTTPDownloader::HTTP_STATUS_OK)
|
||||||
|
@ -503,7 +504,7 @@ void AutoUpdaterDialog::getChangesComplete(s32 status_code, std::vector<u8> resp
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
reportError(fmt::format("Failed to download change list: HTTP {}", status_code));
|
reportError(fmt::format("Failed to download change list: {}", error.GetDescription()));
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -527,13 +528,13 @@ void AutoUpdaterDialog::downloadUpdateClicked()
|
||||||
|
|
||||||
m_http->CreateRequest(
|
m_http->CreateRequest(
|
||||||
m_download_url.toStdString(),
|
m_download_url.toStdString(),
|
||||||
[this, &download_result](s32 status_code, const std::string&, std::vector<u8> response) {
|
[this, &download_result](s32 status_code, const Error& error, const std::string&, std::vector<u8> response) {
|
||||||
if (status_code == HTTPDownloader::HTTP_STATUS_CANCELLED)
|
if (status_code == HTTPDownloader::HTTP_STATUS_CANCELLED)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (status_code != HTTPDownloader::HTTP_STATUS_OK)
|
if (status_code != HTTPDownloader::HTTP_STATUS_OK)
|
||||||
{
|
{
|
||||||
reportError(fmt::format("Download failed: HTTP status code {}", status_code));
|
reportError(fmt::format("Download failed: {}", error.GetDescription()));
|
||||||
download_result = false;
|
download_result = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,11 +58,11 @@ private:
|
||||||
bool updateNeeded() const;
|
bool updateNeeded() const;
|
||||||
std::string getCurrentUpdateTag() const;
|
std::string getCurrentUpdateTag() const;
|
||||||
|
|
||||||
void getLatestTagComplete(s32 status_code, std::vector<u8> response);
|
void getLatestTagComplete(s32 status_code, const Error& error, std::vector<u8> response);
|
||||||
void getLatestReleaseComplete(s32 status_code, std::vector<u8> response);
|
void getLatestReleaseComplete(s32 status_code, const Error& error, std::vector<u8> response);
|
||||||
|
|
||||||
void queueGetChanges();
|
void queueGetChanges();
|
||||||
void getChangesComplete(s32 status_code, std::vector<u8> response);
|
void getChangesComplete(s32 status_code, const Error& error, std::vector<u8> response);
|
||||||
|
|
||||||
bool processUpdate(const std::vector<u8>& update_data);
|
bool processUpdate(const std::vector<u8>& update_data);
|
||||||
|
|
||||||
|
|
|
@ -261,11 +261,13 @@ std::optional<bool> QtHost::DownloadFile(QWidget* parent, const QString& title,
|
||||||
{
|
{
|
||||||
static constexpr u32 HTTP_POLL_INTERVAL = 10;
|
static constexpr u32 HTTP_POLL_INTERVAL = 10;
|
||||||
|
|
||||||
std::unique_ptr<HTTPDownloader> http = HTTPDownloader::Create(Host::GetHTTPUserAgent());
|
Error error;
|
||||||
|
std::unique_ptr<HTTPDownloader> http = HTTPDownloader::Create(Host::GetHTTPUserAgent(), &error);
|
||||||
if (!http)
|
if (!http)
|
||||||
{
|
{
|
||||||
QMessageBox::critical(parent, qApp->translate("QtHost", "Error"),
|
QMessageBox::critical(parent, qApp->translate("QtHost", "Error"),
|
||||||
qApp->translate("QtHost", "Failed to create HTTPDownloader."));
|
qApp->translate("QtHost", "Failed to create HTTPDownloader:\n%1")
|
||||||
|
.arg(QString::fromStdString(error.GetDescription())));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -281,14 +283,16 @@ std::optional<bool> QtHost::DownloadFile(QWidget* parent, const QString& title,
|
||||||
|
|
||||||
http->CreateRequest(
|
http->CreateRequest(
|
||||||
std::move(url),
|
std::move(url),
|
||||||
[parent, data, &download_result](s32 status_code, const std::string&, std::vector<u8> hdata) {
|
[parent, data, &download_result](s32 status_code, const Error& error, const std::string&, std::vector<u8> hdata) {
|
||||||
if (status_code == HTTPDownloader::HTTP_STATUS_CANCELLED)
|
if (status_code == HTTPDownloader::HTTP_STATUS_CANCELLED)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (status_code != HTTPDownloader::HTTP_STATUS_OK)
|
if (status_code != HTTPDownloader::HTTP_STATUS_OK)
|
||||||
{
|
{
|
||||||
QMessageBox::critical(parent, qApp->translate("QtHost", "Error"),
|
QMessageBox::critical(parent, qApp->translate("QtHost", "Error"),
|
||||||
qApp->translate("QtHost", "Download failed with HTTP status code %1.").arg(status_code));
|
qApp->translate("QtHost", "Download failed with HTTP status code %1:\n%2")
|
||||||
|
.arg(status_code)
|
||||||
|
.arg(QString::fromStdString(error.GetDescription())));
|
||||||
download_result = false;
|
download_result = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1913,11 +1917,13 @@ std::string Host::GetClipboardText()
|
||||||
{
|
{
|
||||||
// Hope this doesn't deadlock...
|
// Hope this doesn't deadlock...
|
||||||
std::string ret;
|
std::string ret;
|
||||||
QtHost::RunOnUIThread([&ret]() {
|
QtHost::RunOnUIThread(
|
||||||
|
[&ret]() {
|
||||||
QClipboard* clipboard = QGuiApplication::clipboard();
|
QClipboard* clipboard = QGuiApplication::clipboard();
|
||||||
if (clipboard)
|
if (clipboard)
|
||||||
ret = clipboard->text().toStdString();
|
ret = clipboard->text().toStdString();
|
||||||
}, true);
|
},
|
||||||
|
true);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -224,7 +224,6 @@ if(WIN32)
|
||||||
dinput_source.cpp
|
dinput_source.cpp
|
||||||
dinput_source.h
|
dinput_source.h
|
||||||
http_downloader_winhttp.cpp
|
http_downloader_winhttp.cpp
|
||||||
http_downloader_winhttp.h
|
|
||||||
platform_misc_win32.cpp
|
platform_misc_win32.cpp
|
||||||
win32_raw_input_source.cpp
|
win32_raw_input_source.cpp
|
||||||
win32_raw_input_source.h
|
win32_raw_input_source.h
|
||||||
|
@ -275,7 +274,6 @@ endif()
|
||||||
if(NOT WIN32 AND NOT ANDROID)
|
if(NOT WIN32 AND NOT ANDROID)
|
||||||
target_sources(util PRIVATE
|
target_sources(util PRIVATE
|
||||||
http_downloader_curl.cpp
|
http_downloader_curl.cpp
|
||||||
http_downloader_curl.h
|
|
||||||
)
|
)
|
||||||
target_link_libraries(util PRIVATE
|
target_link_libraries(util PRIVATE
|
||||||
CURL::libcurl
|
CURL::libcurl
|
||||||
|
|
|
@ -109,7 +109,8 @@ void HTTPDownloader::LockedPollRequests(std::unique_lock<std::mutex>& lock)
|
||||||
m_pending_http_requests.erase(m_pending_http_requests.begin() + index);
|
m_pending_http_requests.erase(m_pending_http_requests.begin() + index);
|
||||||
lock.unlock();
|
lock.unlock();
|
||||||
|
|
||||||
req->callback(HTTP_STATUS_TIMEOUT, std::string(), Request::Data());
|
req->error.SetStringFmt("Request timed out after {} seconds.", m_timeout);
|
||||||
|
req->callback(HTTP_STATUS_TIMEOUT, req->error, std::string(), Request::Data());
|
||||||
|
|
||||||
CloseRequest(req);
|
CloseRequest(req);
|
||||||
|
|
||||||
|
@ -126,7 +127,8 @@ void HTTPDownloader::LockedPollRequests(std::unique_lock<std::mutex>& lock)
|
||||||
m_pending_http_requests.erase(m_pending_http_requests.begin() + index);
|
m_pending_http_requests.erase(m_pending_http_requests.begin() + index);
|
||||||
lock.unlock();
|
lock.unlock();
|
||||||
|
|
||||||
req->callback(HTTP_STATUS_CANCELLED, std::string(), Request::Data());
|
req->error.SetStringView("Request was cancelled.");
|
||||||
|
req->callback(HTTP_STATUS_CANCELLED, req->error, std::string(), Request::Data());
|
||||||
|
|
||||||
CloseRequest(req);
|
CloseRequest(req);
|
||||||
|
|
||||||
|
@ -159,7 +161,9 @@ void HTTPDownloader::LockedPollRequests(std::unique_lock<std::mutex>& lock)
|
||||||
|
|
||||||
// run callback with lock unheld
|
// run callback with lock unheld
|
||||||
lock.unlock();
|
lock.unlock();
|
||||||
req->callback(req->status_code, req->content_type, std::move(req->data));
|
if (req->status_code != HTTP_STATUS_OK)
|
||||||
|
req->error.SetStringFmt("Request failed with HTTP status code {}", req->status_code);
|
||||||
|
req->callback(req->status_code, req->error, req->content_type, std::move(req->data));
|
||||||
CloseRequest(req);
|
CloseRequest(req);
|
||||||
lock.lock();
|
lock.lock();
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "common/error.h"
|
||||||
#include "common/types.h"
|
#include "common/types.h"
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
|
@ -29,7 +30,8 @@ public:
|
||||||
struct Request
|
struct Request
|
||||||
{
|
{
|
||||||
using Data = std::vector<u8>;
|
using Data = std::vector<u8>;
|
||||||
using Callback = std::function<void(s32 status_code, const std::string& content_type, Data data)>;
|
using Callback =
|
||||||
|
std::function<void(s32 status_code, const Error& error, const std::string& content_type, Data data)>;
|
||||||
|
|
||||||
enum class Type
|
enum class Type
|
||||||
{
|
{
|
||||||
|
@ -53,6 +55,7 @@ public:
|
||||||
std::string post_data;
|
std::string post_data;
|
||||||
std::string content_type;
|
std::string content_type;
|
||||||
Data data;
|
Data data;
|
||||||
|
Error error;
|
||||||
u64 start_time;
|
u64 start_time;
|
||||||
s32 status_code = 0;
|
s32 status_code = 0;
|
||||||
u32 content_length = 0;
|
u32 content_length = 0;
|
||||||
|
@ -64,7 +67,7 @@ public:
|
||||||
HTTPDownloader();
|
HTTPDownloader();
|
||||||
virtual ~HTTPDownloader();
|
virtual ~HTTPDownloader();
|
||||||
|
|
||||||
static std::unique_ptr<HTTPDownloader> Create(std::string user_agent = DEFAULT_USER_AGENT);
|
static std::unique_ptr<HTTPDownloader> Create(std::string user_agent = DEFAULT_USER_AGENT, Error* error = nullptr);
|
||||||
static std::string GetExtensionForContentType(const std::string& content_type);
|
static std::string GetExtensionForContentType(const std::string& content_type);
|
||||||
|
|
||||||
void SetTimeout(float timeout);
|
void SetTimeout(float timeout);
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
|
// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
|
||||||
// SPDX-License-Identifier: CC-BY-NC-ND-4.0
|
// SPDX-License-Identifier: CC-BY-NC-ND-4.0
|
||||||
|
|
||||||
#include "http_downloader_curl.h"
|
#include "http_downloader.h"
|
||||||
|
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "common/log.h"
|
#include "common/log.h"
|
||||||
|
@ -9,12 +9,41 @@
|
||||||
#include "common/timer.h"
|
#include "common/timer.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <curl/curl.h>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
|
||||||
LOG_CHANNEL(HTTPDownloader);
|
LOG_CHANNEL(HTTPDownloader);
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
class HTTPDownloaderCurl final : public HTTPDownloader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
HTTPDownloaderCurl();
|
||||||
|
~HTTPDownloaderCurl() override;
|
||||||
|
|
||||||
|
bool Initialize(std::string user_agent, Error* error);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Request* InternalCreateRequest() override;
|
||||||
|
void InternalPollRequests() override;
|
||||||
|
bool StartRequest(HTTPDownloader::Request* request) override;
|
||||||
|
void CloseRequest(HTTPDownloader::Request* request) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct Request : HTTPDownloader::Request
|
||||||
|
{
|
||||||
|
CURL* handle = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
static size_t WriteCallback(char* ptr, size_t size, size_t nmemb, void* userdata);
|
||||||
|
|
||||||
|
CURLM* m_multi_handle = nullptr;
|
||||||
|
std::string m_user_agent;
|
||||||
|
};
|
||||||
|
} // namespace
|
||||||
|
|
||||||
HTTPDownloaderCurl::HTTPDownloaderCurl() : HTTPDownloader()
|
HTTPDownloaderCurl::HTTPDownloaderCurl() : HTTPDownloader()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -25,11 +54,11 @@ HTTPDownloaderCurl::~HTTPDownloaderCurl()
|
||||||
curl_multi_cleanup(m_multi_handle);
|
curl_multi_cleanup(m_multi_handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<HTTPDownloader> HTTPDownloader::Create(std::string user_agent)
|
std::unique_ptr<HTTPDownloader> HTTPDownloader::Create(std::string user_agent, Error* error)
|
||||||
{
|
{
|
||||||
std::unique_ptr<HTTPDownloaderCurl> instance(std::make_unique<HTTPDownloaderCurl>());
|
std::unique_ptr<HTTPDownloaderCurl> instance = std::make_unique<HTTPDownloaderCurl>();
|
||||||
if (!instance->Initialize(std::move(user_agent)))
|
if (!instance->Initialize(std::move(user_agent), error))
|
||||||
return {};
|
instance.reset();
|
||||||
|
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
@ -37,7 +66,7 @@ std::unique_ptr<HTTPDownloader> HTTPDownloader::Create(std::string user_agent)
|
||||||
static bool s_curl_initialized = false;
|
static bool s_curl_initialized = false;
|
||||||
static std::once_flag s_curl_initialized_once_flag;
|
static std::once_flag s_curl_initialized_once_flag;
|
||||||
|
|
||||||
bool HTTPDownloaderCurl::Initialize(std::string user_agent)
|
bool HTTPDownloaderCurl::Initialize(std::string user_agent, Error* error)
|
||||||
{
|
{
|
||||||
if (!s_curl_initialized)
|
if (!s_curl_initialized)
|
||||||
{
|
{
|
||||||
|
@ -53,7 +82,7 @@ bool HTTPDownloaderCurl::Initialize(std::string user_agent)
|
||||||
});
|
});
|
||||||
if (!s_curl_initialized)
|
if (!s_curl_initialized)
|
||||||
{
|
{
|
||||||
ERROR_LOG("curl_global_init() failed");
|
Error::SetStringView(error, "curl_global_init() failed");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -61,7 +90,7 @@ bool HTTPDownloaderCurl::Initialize(std::string user_agent)
|
||||||
m_multi_handle = curl_multi_init();
|
m_multi_handle = curl_multi_init();
|
||||||
if (!m_multi_handle)
|
if (!m_multi_handle)
|
||||||
{
|
{
|
||||||
ERROR_LOG("curl_multi_init() failed");
|
Error::SetStringView(error, "curl_multi_init() failed");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -153,6 +182,7 @@ void HTTPDownloaderCurl::InternalPollRequests()
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ERROR_LOG("Request for '{}' returned error {}", req->url, static_cast<int>(msg->data.result));
|
ERROR_LOG("Request for '{}' returned error {}", req->url, static_cast<int>(msg->data.result));
|
||||||
|
req->error.SetStringFmt("Request failed: {}", curl_easy_strerror(msg->data.result));
|
||||||
}
|
}
|
||||||
|
|
||||||
req->state.store(Request::State::Complete, std::memory_order_release);
|
req->state.store(Request::State::Complete, std::memory_order_release);
|
||||||
|
@ -187,7 +217,8 @@ bool HTTPDownloaderCurl::StartRequest(HTTPDownloader::Request* request)
|
||||||
if (err != CURLM_OK)
|
if (err != CURLM_OK)
|
||||||
{
|
{
|
||||||
ERROR_LOG("curl_multi_add_handle() returned {}", static_cast<int>(err));
|
ERROR_LOG("curl_multi_add_handle() returned {}", static_cast<int>(err));
|
||||||
req->callback(HTTP_STATUS_ERROR, std::string(), req->data);
|
req->error.SetStringFmt("curl_multi_add_handle() failed: {}", curl_multi_strerror(err));
|
||||||
|
req->callback(HTTP_STATUS_ERROR, req->error, std::string(), req->data);
|
||||||
curl_easy_cleanup(req->handle);
|
curl_easy_cleanup(req->handle);
|
||||||
delete req;
|
delete req;
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -1,36 +0,0 @@
|
||||||
// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
|
|
||||||
// SPDX-License-Identifier: CC-BY-NC-ND-4.0
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include "http_downloader.h"
|
|
||||||
|
|
||||||
#include <atomic>
|
|
||||||
#include <curl/curl.h>
|
|
||||||
#include <memory>
|
|
||||||
#include <mutex>
|
|
||||||
|
|
||||||
class HTTPDownloaderCurl final : public HTTPDownloader
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
HTTPDownloaderCurl();
|
|
||||||
~HTTPDownloaderCurl() override;
|
|
||||||
|
|
||||||
bool Initialize(std::string user_agent);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
Request* InternalCreateRequest() override;
|
|
||||||
void InternalPollRequests() override;
|
|
||||||
bool StartRequest(HTTPDownloader::Request* request) override;
|
|
||||||
void CloseRequest(HTTPDownloader::Request* request) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
struct Request : HTTPDownloader::Request
|
|
||||||
{
|
|
||||||
CURL* handle = nullptr;
|
|
||||||
};
|
|
||||||
|
|
||||||
static size_t WriteCallback(char* ptr, size_t size, size_t nmemb, void* userdata);
|
|
||||||
|
|
||||||
CURLM* m_multi_handle = nullptr;
|
|
||||||
std::string m_user_agent;
|
|
||||||
};
|
|
|
@ -1,7 +1,7 @@
|
||||||
// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
|
// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
|
||||||
// SPDX-License-Identifier: CC-BY-NC-ND-4.0
|
// SPDX-License-Identifier: CC-BY-NC-ND-4.0
|
||||||
|
|
||||||
#include "http_downloader_winhttp.h"
|
#include "http_downloader.h"
|
||||||
|
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "common/log.h"
|
#include "common/log.h"
|
||||||
|
@ -10,6 +10,41 @@
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
|
#include "common/windows_headers.h"
|
||||||
|
|
||||||
|
#include <winhttp.h>
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
class HTTPDownloaderWinHttp final : public HTTPDownloader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
HTTPDownloaderWinHttp();
|
||||||
|
~HTTPDownloaderWinHttp() override;
|
||||||
|
|
||||||
|
bool Initialize(std::string user_agent, Error* error);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Request* InternalCreateRequest() override;
|
||||||
|
void InternalPollRequests() override;
|
||||||
|
bool StartRequest(HTTPDownloader::Request* request) override;
|
||||||
|
void CloseRequest(HTTPDownloader::Request* request) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct Request : HTTPDownloader::Request
|
||||||
|
{
|
||||||
|
std::wstring object_name;
|
||||||
|
HINTERNET hConnection = NULL;
|
||||||
|
HINTERNET hRequest = NULL;
|
||||||
|
u32 io_position = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void CALLBACK HTTPStatusCallback(HINTERNET hInternet, DWORD_PTR dwContext, DWORD dwInternetStatus,
|
||||||
|
LPVOID lpvStatusInformation, DWORD dwStatusInformationLength);
|
||||||
|
|
||||||
|
HINTERNET m_hSession = NULL;
|
||||||
|
};
|
||||||
|
} // namespace
|
||||||
|
|
||||||
LOG_CHANNEL(HTTPDownloader);
|
LOG_CHANNEL(HTTPDownloader);
|
||||||
|
|
||||||
HTTPDownloaderWinHttp::HTTPDownloaderWinHttp() : HTTPDownloader()
|
HTTPDownloaderWinHttp::HTTPDownloaderWinHttp() : HTTPDownloader()
|
||||||
|
@ -25,16 +60,16 @@ HTTPDownloaderWinHttp::~HTTPDownloaderWinHttp()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<HTTPDownloader> HTTPDownloader::Create(std::string user_agent)
|
std::unique_ptr<HTTPDownloader> HTTPDownloader::Create(std::string user_agent, Error* error)
|
||||||
{
|
{
|
||||||
std::unique_ptr<HTTPDownloaderWinHttp> instance(std::make_unique<HTTPDownloaderWinHttp>());
|
std::unique_ptr<HTTPDownloaderWinHttp> instance(std::make_unique<HTTPDownloaderWinHttp>());
|
||||||
if (!instance->Initialize(std::move(user_agent)))
|
if (!instance->Initialize(std::move(user_agent), error))
|
||||||
return {};
|
instance.reset();
|
||||||
|
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HTTPDownloaderWinHttp::Initialize(std::string user_agent)
|
bool HTTPDownloaderWinHttp::Initialize(std::string user_agent, Error* error)
|
||||||
{
|
{
|
||||||
static constexpr DWORD dwAccessType = WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY;
|
static constexpr DWORD dwAccessType = WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY;
|
||||||
|
|
||||||
|
@ -42,7 +77,7 @@ bool HTTPDownloaderWinHttp::Initialize(std::string user_agent)
|
||||||
WINHTTP_FLAG_ASYNC);
|
WINHTTP_FLAG_ASYNC);
|
||||||
if (m_hSession == NULL)
|
if (m_hSession == NULL)
|
||||||
{
|
{
|
||||||
ERROR_LOG("WinHttpOpen() failed: {}", GetLastError());
|
Error::SetWin32(error, "WinHttpOpen() failed: ", GetLastError());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,7 +86,7 @@ bool HTTPDownloaderWinHttp::Initialize(std::string user_agent)
|
||||||
if (WinHttpSetStatusCallback(m_hSession, HTTPStatusCallback, notification_flags, NULL) ==
|
if (WinHttpSetStatusCallback(m_hSession, HTTPStatusCallback, notification_flags, NULL) ==
|
||||||
WINHTTP_INVALID_STATUS_CALLBACK)
|
WINHTTP_INVALID_STATUS_CALLBACK)
|
||||||
{
|
{
|
||||||
ERROR_LOG("WinHttpSetStatusCallback() failed: {}", GetLastError());
|
Error::SetWin32(error, "WinHttpSetStatusCallback() failed: ", GetLastError());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,6 +126,7 @@ void CALLBACK HTTPDownloaderWinHttp::HTTPStatusCallback(HINTERNET hRequest, DWOR
|
||||||
const WINHTTP_ASYNC_RESULT* res = reinterpret_cast<const WINHTTP_ASYNC_RESULT*>(lpvStatusInformation);
|
const WINHTTP_ASYNC_RESULT* res = reinterpret_cast<const WINHTTP_ASYNC_RESULT*>(lpvStatusInformation);
|
||||||
ERROR_LOG("WinHttp async function {} returned error {}", res->dwResult, res->dwError);
|
ERROR_LOG("WinHttp async function {} returned error {}", res->dwResult, res->dwError);
|
||||||
req->status_code = HTTP_STATUS_ERROR;
|
req->status_code = HTTP_STATUS_ERROR;
|
||||||
|
req->error.SetStringFmt("WinHttp async function {} returned error {}", res->dwResult, res->dwError);
|
||||||
req->state.store(Request::State::Complete);
|
req->state.store(Request::State::Complete);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -99,8 +135,10 @@ void CALLBACK HTTPDownloaderWinHttp::HTTPStatusCallback(HINTERNET hRequest, DWOR
|
||||||
DEV_LOG("SendRequest complete");
|
DEV_LOG("SendRequest complete");
|
||||||
if (!WinHttpReceiveResponse(hRequest, nullptr))
|
if (!WinHttpReceiveResponse(hRequest, nullptr))
|
||||||
{
|
{
|
||||||
ERROR_LOG("WinHttpReceiveResponse() failed: {}", GetLastError());
|
const DWORD err = GetLastError();
|
||||||
|
ERROR_LOG("WinHttpReceiveResponse() failed: {}", err);
|
||||||
req->status_code = HTTP_STATUS_ERROR;
|
req->status_code = HTTP_STATUS_ERROR;
|
||||||
|
req->error.SetWin32("WinHttpReceiveResponse() failed: ", err);
|
||||||
req->state.store(Request::State::Complete);
|
req->state.store(Request::State::Complete);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,8 +152,10 @@ void CALLBACK HTTPDownloaderWinHttp::HTTPStatusCallback(HINTERNET hRequest, DWOR
|
||||||
if (!WinHttpQueryHeaders(hRequest, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER,
|
if (!WinHttpQueryHeaders(hRequest, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER,
|
||||||
WINHTTP_HEADER_NAME_BY_INDEX, &req->status_code, &buffer_size, WINHTTP_NO_HEADER_INDEX))
|
WINHTTP_HEADER_NAME_BY_INDEX, &req->status_code, &buffer_size, WINHTTP_NO_HEADER_INDEX))
|
||||||
{
|
{
|
||||||
ERROR_LOG("WinHttpQueryHeaders() for status code failed: {}", GetLastError());
|
const DWORD err = GetLastError();
|
||||||
|
ERROR_LOG("WinHttpQueryHeaders() for status code failed: {}", err);
|
||||||
req->status_code = HTTP_STATUS_ERROR;
|
req->status_code = HTTP_STATUS_ERROR;
|
||||||
|
req->error.SetWin32("WinHttpQueryHeaders() failed: ", err);
|
||||||
req->state.store(Request::State::Complete);
|
req->state.store(Request::State::Complete);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -125,8 +165,9 @@ void CALLBACK HTTPDownloaderWinHttp::HTTPStatusCallback(HINTERNET hRequest, DWOR
|
||||||
WINHTTP_HEADER_NAME_BY_INDEX, &req->content_length, &buffer_size,
|
WINHTTP_HEADER_NAME_BY_INDEX, &req->content_length, &buffer_size,
|
||||||
WINHTTP_NO_HEADER_INDEX))
|
WINHTTP_NO_HEADER_INDEX))
|
||||||
{
|
{
|
||||||
if (GetLastError() != ERROR_WINHTTP_HEADER_NOT_FOUND)
|
const DWORD err = GetLastError();
|
||||||
WARNING_LOG("WinHttpQueryHeaders() for content length failed: {}", GetLastError());
|
if (err != ERROR_WINHTTP_HEADER_NOT_FOUND)
|
||||||
|
WARNING_LOG("WinHttpQueryHeaders() for content length failed: {}", err);
|
||||||
|
|
||||||
req->content_length = 0;
|
req->content_length = 0;
|
||||||
}
|
}
|
||||||
|
@ -152,8 +193,10 @@ void CALLBACK HTTPDownloaderWinHttp::HTTPStatusCallback(HINTERNET hRequest, DWOR
|
||||||
// start reading
|
// start reading
|
||||||
if (!WinHttpQueryDataAvailable(hRequest, nullptr) && GetLastError() != ERROR_IO_PENDING)
|
if (!WinHttpQueryDataAvailable(hRequest, nullptr) && GetLastError() != ERROR_IO_PENDING)
|
||||||
{
|
{
|
||||||
ERROR_LOG("WinHttpQueryDataAvailable() failed: {}", GetLastError());
|
const DWORD err = GetLastError();
|
||||||
|
ERROR_LOG("WinHttpQueryDataAvailable() failed: {}", err);
|
||||||
req->status_code = HTTP_STATUS_ERROR;
|
req->status_code = HTTP_STATUS_ERROR;
|
||||||
|
req->error.SetWin32("WinHttpQueryDataAvailable() failed: ", err);
|
||||||
req->state.store(Request::State::Complete);
|
req->state.store(Request::State::Complete);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -178,8 +221,10 @@ void CALLBACK HTTPDownloaderWinHttp::HTTPStatusCallback(HINTERNET hRequest, DWOR
|
||||||
if (!WinHttpReadData(hRequest, req->data.data() + req->io_position, bytes_available, nullptr) &&
|
if (!WinHttpReadData(hRequest, req->data.data() + req->io_position, bytes_available, nullptr) &&
|
||||||
GetLastError() != ERROR_IO_PENDING)
|
GetLastError() != ERROR_IO_PENDING)
|
||||||
{
|
{
|
||||||
ERROR_LOG("WinHttpReadData() failed: {}", GetLastError());
|
const DWORD err = GetLastError();
|
||||||
|
ERROR_LOG("WinHttpReadData() failed: {}", err);
|
||||||
req->status_code = HTTP_STATUS_ERROR;
|
req->status_code = HTTP_STATUS_ERROR;
|
||||||
|
req->error.SetWin32("WinHttpReadData() failed: ", err);
|
||||||
req->state.store(Request::State::Complete);
|
req->state.store(Request::State::Complete);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -196,8 +241,10 @@ void CALLBACK HTTPDownloaderWinHttp::HTTPStatusCallback(HINTERNET hRequest, DWOR
|
||||||
|
|
||||||
if (!WinHttpQueryDataAvailable(hRequest, nullptr) && GetLastError() != ERROR_IO_PENDING)
|
if (!WinHttpQueryDataAvailable(hRequest, nullptr) && GetLastError() != ERROR_IO_PENDING)
|
||||||
{
|
{
|
||||||
ERROR_LOG("WinHttpQueryDataAvailable() failed: {}", GetLastError());
|
const DWORD err = GetLastError();
|
||||||
|
ERROR_LOG("WinHttpQueryDataAvailable() failed: {}", err);
|
||||||
req->status_code = HTTP_STATUS_ERROR;
|
req->status_code = HTTP_STATUS_ERROR;
|
||||||
|
req->error.SetWin32("WinHttpQueryDataAvailable() failed: ", err);
|
||||||
req->state.store(Request::State::Complete);
|
req->state.store(Request::State::Complete);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -238,8 +285,10 @@ bool HTTPDownloaderWinHttp::StartRequest(HTTPDownloader::Request* request)
|
||||||
const std::wstring url_wide(StringUtil::UTF8StringToWideString(req->url));
|
const std::wstring url_wide(StringUtil::UTF8StringToWideString(req->url));
|
||||||
if (!WinHttpCrackUrl(url_wide.c_str(), static_cast<DWORD>(url_wide.size()), 0, &uc))
|
if (!WinHttpCrackUrl(url_wide.c_str(), static_cast<DWORD>(url_wide.size()), 0, &uc))
|
||||||
{
|
{
|
||||||
ERROR_LOG("WinHttpCrackUrl() failed: {}", GetLastError());
|
const DWORD err = GetLastError();
|
||||||
req->callback(HTTP_STATUS_ERROR, std::string(), req->data);
|
ERROR_LOG("WinHttpCrackUrl() failed: {}", err);
|
||||||
|
req->error.SetWin32("WinHttpCrackUrl() failed: ", err);
|
||||||
|
req->callback(HTTP_STATUS_ERROR, req->error, std::string(), req->data);
|
||||||
delete req;
|
delete req;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -250,8 +299,10 @@ bool HTTPDownloaderWinHttp::StartRequest(HTTPDownloader::Request* request)
|
||||||
req->hConnection = WinHttpConnect(m_hSession, host_name.c_str(), uc.nPort, 0);
|
req->hConnection = WinHttpConnect(m_hSession, host_name.c_str(), uc.nPort, 0);
|
||||||
if (!req->hConnection)
|
if (!req->hConnection)
|
||||||
{
|
{
|
||||||
ERROR_LOG("Failed to start HTTP request for '{}': {}", req->url, GetLastError());
|
const DWORD err = GetLastError();
|
||||||
req->callback(HTTP_STATUS_ERROR, std::string(), req->data);
|
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);
|
||||||
delete req;
|
delete req;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -262,7 +313,9 @@ bool HTTPDownloaderWinHttp::StartRequest(HTTPDownloader::Request* request)
|
||||||
req->object_name.c_str(), NULL, NULL, NULL, request_flags);
|
req->object_name.c_str(), NULL, NULL, NULL, request_flags);
|
||||||
if (!req->hRequest)
|
if (!req->hRequest)
|
||||||
{
|
{
|
||||||
ERROR_LOG("WinHttpOpenRequest() failed: {}", GetLastError());
|
const DWORD err = GetLastError();
|
||||||
|
ERROR_LOG("WinHttpOpenRequest() failed: {}", err);
|
||||||
|
req->error.SetWin32("WinHttpSendRequest() failed: ", err);
|
||||||
WinHttpCloseHandle(req->hConnection);
|
WinHttpCloseHandle(req->hConnection);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -283,8 +336,10 @@ bool HTTPDownloaderWinHttp::StartRequest(HTTPDownloader::Request* request)
|
||||||
|
|
||||||
if (!result && GetLastError() != ERROR_IO_PENDING)
|
if (!result && GetLastError() != ERROR_IO_PENDING)
|
||||||
{
|
{
|
||||||
ERROR_LOG("WinHttpSendRequest() failed: {}", GetLastError());
|
const DWORD err = GetLastError();
|
||||||
|
ERROR_LOG("WinHttpSendRequest() failed: {}", err);
|
||||||
req->status_code = HTTP_STATUS_ERROR;
|
req->status_code = HTTP_STATUS_ERROR;
|
||||||
|
req->error.SetWin32("WinHttpSendRequest() failed: ", err);
|
||||||
req->state.store(Request::State::Complete);
|
req->state.store(Request::State::Complete);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,38 +0,0 @@
|
||||||
// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
|
|
||||||
// SPDX-License-Identifier: CC-BY-NC-ND-4.0
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include "http_downloader.h"
|
|
||||||
|
|
||||||
#include "common/windows_headers.h"
|
|
||||||
|
|
||||||
#include <winhttp.h>
|
|
||||||
|
|
||||||
class HTTPDownloaderWinHttp final : public HTTPDownloader
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
HTTPDownloaderWinHttp();
|
|
||||||
~HTTPDownloaderWinHttp() override;
|
|
||||||
|
|
||||||
bool Initialize(std::string user_agent);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
Request* InternalCreateRequest() override;
|
|
||||||
void InternalPollRequests() override;
|
|
||||||
bool StartRequest(HTTPDownloader::Request* request) override;
|
|
||||||
void CloseRequest(HTTPDownloader::Request* request) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
struct Request : HTTPDownloader::Request
|
|
||||||
{
|
|
||||||
std::wstring object_name;
|
|
||||||
HINTERNET hConnection = NULL;
|
|
||||||
HINTERNET hRequest = NULL;
|
|
||||||
u32 io_position = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
static void CALLBACK HTTPStatusCallback(HINTERNET hInternet, DWORD_PTR dwContext, DWORD dwInternetStatus,
|
|
||||||
LPVOID lpvStatusInformation, DWORD dwStatusInformationLength);
|
|
||||||
|
|
||||||
HINTERNET m_hSession = NULL;
|
|
||||||
};
|
|
|
@ -28,10 +28,6 @@
|
||||||
<ClInclude Include="gpu_texture.h" />
|
<ClInclude Include="gpu_texture.h" />
|
||||||
<ClInclude Include="host.h" />
|
<ClInclude Include="host.h" />
|
||||||
<ClInclude Include="http_downloader.h" />
|
<ClInclude Include="http_downloader.h" />
|
||||||
<ClInclude Include="http_downloader_curl.h">
|
|
||||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="http_downloader_winhttp.h" />
|
|
||||||
<ClInclude Include="imgui_fullscreen.h" />
|
<ClInclude Include="imgui_fullscreen.h" />
|
||||||
<ClInclude Include="imgui_manager.h" />
|
<ClInclude Include="imgui_manager.h" />
|
||||||
<ClInclude Include="ini_settings_interface.h" />
|
<ClInclude Include="ini_settings_interface.h" />
|
||||||
|
|
|
@ -57,8 +57,6 @@
|
||||||
<ClInclude Include="host.h" />
|
<ClInclude Include="host.h" />
|
||||||
<ClInclude Include="postprocessing_shader_fx.h" />
|
<ClInclude Include="postprocessing_shader_fx.h" />
|
||||||
<ClInclude Include="pch.h" />
|
<ClInclude Include="pch.h" />
|
||||||
<ClInclude Include="http_downloader_curl.h" />
|
|
||||||
<ClInclude Include="http_downloader_winhttp.h" />
|
|
||||||
<ClInclude Include="http_downloader.h" />
|
<ClInclude Include="http_downloader.h" />
|
||||||
<ClInclude Include="gpu_framebuffer_manager.h" />
|
<ClInclude Include="gpu_framebuffer_manager.h" />
|
||||||
<ClInclude Include="imgui_animated.h" />
|
<ClInclude Include="imgui_animated.h" />
|
||||||
|
|
Loading…
Reference in New Issue