Apply suggestions

This commit is contained in:
PabloMK7 2023-10-05 14:48:02 +02:00
parent 13418013a4
commit b8c3f0648b
2 changed files with 77 additions and 65 deletions

View file

@ -65,13 +65,6 @@ const ResultCode ERROR_WRONG_CERT_HANDLE = // 0xD8A0A0C9
const ResultCode ERROR_CERT_ALREADY_SET = // 0xD8A0A03D const ResultCode ERROR_CERT_ALREADY_SET = // 0xD8A0A03D
ResultCode(61, ErrorModule::HTTP, ErrorSummary::InvalidState, ErrorLevel::Permanent); ResultCode(61, ErrorModule::HTTP, ErrorSummary::InvalidState, ErrorLevel::Permanent);
struct URLInfo {
bool is_https;
std::string host;
int port;
std::string path;
};
// Splits URL into its components. Example: https://citra-emu.org:443/index.html // Splits URL into its components. Example: https://citra-emu.org:443/index.html
// is_https: true; host: citra-emu.org; port: 443; path: /index.html // is_https: true; host: citra-emu.org; port: 443; path: /index.html
static URLInfo SplitUrl(const std::string& url) { static URLInfo SplitUrl(const std::string& url) {
@ -166,7 +159,6 @@ void Context::MakeRequest() {
URLInfo url_info = SplitUrl(url); URLInfo url_info = SplitUrl(url);
httplib::Request request; httplib::Request request;
httplib::Error error{-1};
std::vector<Context::RequestHeader> pending_headers; std::vector<Context::RequestHeader> pending_headers;
request.method = request_method_strings.at(method); request.method = request_method_strings.at(method);
request.path = url_info.path; request.path = url_info.path;
@ -178,11 +170,6 @@ void Context::MakeRequest() {
return true; return true;
}; };
auto header_writter = [&pending_headers](httplib::Stream& strm,
httplib::Headers& httplib_headers) {
return HandleHeaderWrite(pending_headers, strm, httplib_headers);
};
for (const auto& header : headers) { for (const auto& header : headers) {
pending_headers.push_back(header); pending_headers.push_back(header);
} }
@ -200,8 +187,36 @@ void Context::MakeRequest() {
state = RequestState::InProgress; state = RequestState::InProgress;
// Sadly, we have to duplicate code, the class hierarchy in httplib is not very useful...
if (url_info.is_https) { if (url_info.is_https) {
MakeRequestSSL(request, url_info, pending_headers);
} else {
MakeRequestNonSSL(request, url_info, pending_headers);
}
}
void Context::MakeRequestNonSSL(httplib::Request& request, const URLInfo& url_info,
std::vector<Context::RequestHeader>& pending_headers) {
httplib::Error error{-1};
std::unique_ptr<httplib::Client> client =
std::make_unique<httplib::Client>(url_info.host, url_info.port);
client->set_header_writer(
[&pending_headers](httplib::Stream& strm, httplib::Headers& httplib_headers) {
return HandleHeaderWrite(pending_headers, strm, httplib_headers);
});
if (!client->send(request, response, error)) {
LOG_ERROR(Service_HTTP, "Request failed: {}: {}", error, httplib::to_string(error));
state = RequestState::TimedOut;
} else {
LOG_DEBUG(Service_HTTP, "Request successful");
// TODO(B3N30): Verify this state on HW
state = RequestState::ReadyToDownloadContent;
}
}
void Context::MakeRequestSSL(httplib::Request& request, const URLInfo& url_info,
std::vector<Context::RequestHeader>& pending_headers) {
httplib::Error error{-1};
X509* cert = nullptr; X509* cert = nullptr;
EVP_PKEY* key = nullptr; EVP_PKEY* key = nullptr;
{ {
@ -212,16 +227,14 @@ void Context::MakeRequest() {
cert = d2i_X509(nullptr, &tmpCertPtr, (long)clcert_data->certificate.size()); cert = d2i_X509(nullptr, &tmpCertPtr, (long)clcert_data->certificate.size());
key = d2i_PrivateKey(EVP_PKEY_RSA, nullptr, &tmpKeyPtr, key = d2i_PrivateKey(EVP_PKEY_RSA, nullptr, &tmpKeyPtr,
(long)clcert_data->private_key.size()); (long)clcert_data->private_key.size());
client = client = std::make_unique<httplib::SSLClient>(url_info.host, url_info.port, cert, key);
std::make_unique<httplib::SSLClient>(url_info.host, url_info.port, cert, key);
} else if (auto client_cert = ssl_config.client_cert_ctx.lock()) { } else if (auto client_cert = ssl_config.client_cert_ctx.lock()) {
const unsigned char* tmpCertPtr = client_cert->certificate.data(); const unsigned char* tmpCertPtr = client_cert->certificate.data();
const unsigned char* tmpKeyPtr = client_cert->private_key.data(); const unsigned char* tmpKeyPtr = client_cert->private_key.data();
cert = d2i_X509(nullptr, &tmpCertPtr, (long)client_cert->certificate.size()); cert = d2i_X509(nullptr, &tmpCertPtr, (long)client_cert->certificate.size());
key = d2i_PrivateKey(EVP_PKEY_RSA, nullptr, &tmpKeyPtr, key = d2i_PrivateKey(EVP_PKEY_RSA, nullptr, &tmpKeyPtr,
(long)client_cert->private_key.size()); (long)client_cert->private_key.size());
client = client = std::make_unique<httplib::SSLClient>(url_info.host, url_info.port, cert, key);
std::make_unique<httplib::SSLClient>(url_info.host, url_info.port, cert, key);
} else { } else {
client = std::make_unique<httplib::SSLClient>(url_info.host, url_info.port); client = std::make_unique<httplib::SSLClient>(url_info.host, url_info.port);
} }
@ -231,7 +244,10 @@ void Context::MakeRequest() {
// Hack: Since for now RootCerts are not implemented we set the VerifyMode to None. // Hack: Since for now RootCerts are not implemented we set the VerifyMode to None.
client->enable_server_certificate_verification(false); client->enable_server_certificate_verification(false);
client->set_header_writer(header_writter); client->set_header_writer(
[&pending_headers](httplib::Stream& strm, httplib::Headers& httplib_headers) {
return HandleHeaderWrite(pending_headers, strm, httplib_headers);
});
if (!client->send(request, response, error)) { if (!client->send(request, response, error)) {
LOG_ERROR(Service_HTTP, "Request failed: {}: {}", error, httplib::to_string(error)); LOG_ERROR(Service_HTTP, "Request failed: {}: {}", error, httplib::to_string(error));
@ -248,21 +264,6 @@ void Context::MakeRequest() {
if (key) { if (key) {
EVP_PKEY_free(key); EVP_PKEY_free(key);
} }
} else {
std::unique_ptr<httplib::Client> client =
std::make_unique<httplib::Client>(url_info.host, url_info.port);
client->set_header_writer(header_writter);
if (!client->send(request, response, error)) {
LOG_ERROR(Service_HTTP, "Request failed: {}: {}", error, httplib::to_string(error));
state = RequestState::TimedOut;
} else {
LOG_DEBUG(Service_HTTP, "Request successful");
// TODO(B3N30): Verify this state on HW
state = RequestState::ReadyToDownloadContent;
}
}
} }
void HTTP_C::Initialize(Kernel::HLERequestContext& ctx) { void HTTP_C::Initialize(Kernel::HLERequestContext& ctx) {

View file

@ -61,6 +61,13 @@ enum class ClientCertID : u32 {
Default = 0x40, // Default client cert Default = 0x40, // Default client cert
}; };
struct URLInfo {
bool is_https;
std::string host;
int port;
std::string path;
};
/// Represents a client certificate along with its private key, stored as a byte array of DER data. /// Represents a client certificate along with its private key, stored as a byte array of DER data.
/// There can only be at most one client certificate context attached to an HTTP context at any /// There can only be at most one client certificate context attached to an HTTP context at any
/// given time. /// given time.
@ -134,8 +141,6 @@ public:
Context(const Context&) = delete; Context(const Context&) = delete;
Context& operator=(const Context&) = delete; Context& operator=(const Context&) = delete;
void MakeRequest();
struct Proxy { struct Proxy {
std::string url; std::string url;
std::string username; std::string username;
@ -215,6 +220,12 @@ public:
size_t current_copied_data; size_t current_copied_data;
bool uses_default_client_cert{}; bool uses_default_client_cert{};
httplib::Response response; httplib::Response response;
void MakeRequest();
void MakeRequestNonSSL(httplib::Request& request, const URLInfo& url_info,
std::vector<Context::RequestHeader>& pending_headers);
void MakeRequestSSL(httplib::Request& request, const URLInfo& url_info,
std::vector<Context::RequestHeader>& pending_headers);
}; };
struct SessionData : public Kernel::SessionRequestHandler::SessionDataBase { struct SessionData : public Kernel::SessionRequestHandler::SessionDataBase {