Added HTTPClient type.

This commit is contained in:
2024-08-20 00:28:12 +02:00
parent 99f5987f4b
commit 03f255a7d0
3 changed files with 148 additions and 17 deletions

View File

@@ -1,6 +1,8 @@
#include "./http.hpp"
#include <format>
#include "../util/iterators.hpp"
#include "../util/string.hpp"
@@ -69,23 +71,14 @@ Task<StreamError> HTTPStream::c_writeRequest(const mijin::HTTPRequest& request)
}
}
MIJIN_HTTP_WRITE(request.method);
MIJIN_HTTP_WRITE(" ");
MIJIN_HTTP_WRITE(request.address);
MIJIN_HTTP_WRITE(" HTTP/1.0\n");
MIJIN_HTTP_WRITE(std::format("{} {} HTTP/{}.{}\n", request.method, request.address, request.version.major, request.version.minor));
for (const auto& [key, value] : moreHeaders)
{
MIJIN_HTTP_WRITE(key);
MIJIN_HTTP_WRITE(": ");
MIJIN_HTTP_WRITE(value);
MIJIN_HTTP_WRITE("\n");
MIJIN_HTTP_WRITE(std::format("{}: {}\n", key, value));
}
for (const auto& [key, value] : request.headers)
{
MIJIN_HTTP_WRITE(key);
MIJIN_HTTP_WRITE(": ");
MIJIN_HTTP_WRITE(value);
MIJIN_HTTP_WRITE("\n");
MIJIN_HTTP_WRITE(std::format("{}: {}\n", key, value));
}
MIJIN_HTTP_WRITE("\n");
@@ -163,7 +156,106 @@ Task<StreamResult<HTTPResponse>> HTTPStream::c_readResponse() noexcept
co_return response;
}
Task<StreamResult<HTTPResponse>> HTTPClient::c_request(ip_address_t address, std::uint16_t port, bool https,
HTTPRequest request) noexcept
{
if (const StreamError error = createSocket(address, port, https); error != StreamError::SUCCESS)
{
co_return error;
}
if (!request.headers.contains("connection"))
{
request.headers.emplace("connection", "keep-alive");
}
StreamResult<HTTPResponse> response = co_await stream_->c_request(request);
if (response.isError())
{
disconnect();
if (const StreamError error = createSocket(address, port, https); error != StreamError::SUCCESS)
{
co_return error;
}
response = co_await stream_->c_request(request);
}
co_return response;
}
Task<StreamResult<HTTPResponse>> HTTPClient::c_request(const URL& url, HTTPRequest request) noexcept
{
if (url.getHost().empty())
{
co_return StreamError::UNKNOWN_ERROR;
}
std::uint16_t port = url.getPort();
bool https = false;
if (equalsIgnoreCase(url.getScheme(), "http"))
{
port = (port != 0) ? port : 80;
}
else if (equalsIgnoreCase(url.getScheme(), "https"))
{
port = (port != 0) ? port : 443;
https = true;
}
else
{
co_return StreamError::UNKNOWN_ERROR;
}
Optional<ip_address_t> ipAddress = ipAddressFromString(url.getHost());
// TODO: lookup host
if (ipAddress.empty())
{
co_return StreamError::UNKNOWN_ERROR;
}
if (!request.headers.contains("host"))
{
request.headers.emplace("host", url.getHost());
}
request.address = url.getPathQueryFragment();
if (request.address.empty())
{
request.address = "/";
}
co_return co_await c_request(*ipAddress, port, https, std::move(request));
}
void HTTPClient::disconnect() noexcept
{
if (socket_ == nullptr)
{
return;
}
stream_.destroy();
socket_ = nullptr;
}
StreamError HTTPClient::createSocket(ip_address_t address, std::uint16_t port, bool https) noexcept
{
if (socket_ != nullptr && address == lastIP_ && port == lastPort_ && https == lastWasHttps_)
{
return StreamError::SUCCESS;
}
disconnect();
MIJIN_ASSERT(!https, "HTTPS not supported yet.");
std::unique_ptr<TCPSocket> newSocket = std::make_unique<TCPSocket>();
if (const StreamError error = newSocket->open(address, port); error != StreamError::SUCCESS)
{
return error;
}
lastIP_ = address;
lastPort_ = port;
lastWasHttps_ = https;
socket_ = std::move(newSocket);
stream_.construct(socket_->getStream());
return StreamError::SUCCESS;
}
}
#undef MIJIN_HTTP_WRITE
#undef MIJIN_HTTP_READLINE
#undef MIJIN_HTTP_CHECKREAD
#undef MIJIN_HTTP_READLINE