ladybird/Libraries/LibRequests/RequestClient.cpp
Timothy Flynn 3a413d988b LibRequests+RequestServer: Store websocket IDs as u64
The bug fixed here is that in RequestServer's ConnectionFromClient, we
stored the websocket ID as i32, despite it being i64 everywhere else.
Let's make it unsigned while we are here to be consistent with how all
other RS-related IDs will be soon.
2025-12-12 10:54:33 -05:00

189 lines
6.6 KiB
C++

/*
* Copyright (c) 2018-2020, Andreas Kling <andreas@ladybird.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibCore/Promise.h>
#include <LibCore/System.h>
#include <LibRequests/Request.h>
#include <LibRequests/RequestClient.h>
namespace Requests {
RequestClient::RequestClient(NonnullOwnPtr<IPC::Transport> transport)
: IPC::ConnectionToServer<RequestClientEndpoint, RequestServerEndpoint>(*this, move(transport))
{
}
RequestClient::~RequestClient() = default;
void RequestClient::die()
{
for (auto& [id, request] : m_requests) {
if (request)
request->did_finish({}, {}, {}, NetworkError::RequestServerDied);
}
for (auto& [id, promise] : m_pending_cache_size_estimations)
promise->reject(Error::from_string_literal("RequestServer process died"));
m_requests.clear();
m_pending_cache_size_estimations.clear();
}
void RequestClient::ensure_connection(URL::URL const& url, ::RequestServer::CacheLevel cache_level)
{
async_ensure_connection(url, cache_level);
}
RefPtr<Request> RequestClient::start_request(ByteString const& method, URL::URL const& url, Optional<HTTP::HeaderList const&> request_headers, ReadonlyBytes request_body, Core::ProxyData const& proxy_data)
{
auto body_result_or_error = ByteBuffer::copy(request_body);
if (body_result_or_error.is_error())
return nullptr;
static i32 s_next_request_id = 0;
auto request_id = s_next_request_id++;
auto headers = request_headers.map([](auto const& headers) { return headers.headers().span(); }).value_or({});
auto body_result = body_result_or_error.release_value();
IPCProxy::async_start_request(request_id, method, url, headers, body_result, proxy_data);
auto request = Request::create_from_id({}, *this, request_id);
m_requests.set(request_id, request);
return request;
}
void RequestClient::request_started(i32 request_id, IPC::File response_file)
{
auto request = m_requests.get(request_id);
if (!request.has_value()) {
warnln("Received response for non-existent request {}", request_id);
return;
}
auto response_fd = response_file.take_fd();
request.value()->set_request_fd({}, response_fd);
}
bool RequestClient::stop_request(Badge<Request>, Request& request)
{
if (!m_requests.contains(request.id()))
return false;
return IPCProxy::stop_request(request.id());
}
bool RequestClient::set_certificate(Badge<Request>, Request& request, ByteString certificate, ByteString key)
{
if (!m_requests.contains(request.id()))
return false;
return IPCProxy::set_certificate(request.id(), move(certificate), move(key));
}
NonnullRefPtr<Core::Promise<CacheSizes>> RequestClient::estimate_cache_size_accessed_since(UnixDateTime since)
{
auto promise = Core::Promise<CacheSizes>::construct();
auto cache_size_estimation_id = m_next_cache_size_estimation_id++;
m_pending_cache_size_estimations.set(cache_size_estimation_id, promise);
async_estimate_cache_size_accessed_since(cache_size_estimation_id, since);
return promise;
}
void RequestClient::estimated_cache_size(u64 cache_size_estimation_id, CacheSizes sizes)
{
if (auto promise = m_pending_cache_size_estimations.take(cache_size_estimation_id); promise.has_value())
(*promise)->resolve(sizes);
}
void RequestClient::request_finished(i32 request_id, u64 total_size, RequestTimingInfo timing_info, Optional<NetworkError> network_error)
{
RefPtr<Request> request;
if ((request = m_requests.get(request_id).value_or(nullptr))) {
request->did_finish({}, total_size, timing_info, network_error);
}
m_requests.remove(request_id);
}
void RequestClient::headers_became_available(i32 request_id, Vector<HTTP::Header> response_headers, Optional<u32> status_code, Optional<String> reason_phrase)
{
auto request = const_cast<Request*>(m_requests.get(request_id).value_or(nullptr));
if (!request) {
warnln("Received headers for non-existent request {}", request_id);
return;
}
request->did_receive_headers({}, HTTP::HeaderList::create(move(response_headers)), status_code, reason_phrase);
}
void RequestClient::certificate_requested(i32 request_id)
{
if (auto request = const_cast<Request*>(m_requests.get(request_id).value_or(nullptr))) {
request->did_request_certificates({});
}
}
RefPtr<WebSocket> RequestClient::websocket_connect(URL::URL const& url, ByteString const& origin, Vector<ByteString> const& protocols, Vector<ByteString> const& extensions, HTTP::HeaderList const& request_headers)
{
auto websocket_id = m_next_websocket_id++;
IPCProxy::async_websocket_connect(websocket_id, url, origin, protocols, extensions, request_headers.headers());
auto connection = WebSocket::create_from_id({}, *this, websocket_id);
m_websockets.set(websocket_id, connection);
return connection;
}
void RequestClient::websocket_connected(u64 websocket_id)
{
auto maybe_connection = m_websockets.get(websocket_id);
if (maybe_connection.has_value())
maybe_connection.value()->did_open({});
}
void RequestClient::websocket_received(u64 websocket_id, bool is_text, ByteBuffer data)
{
auto maybe_connection = m_websockets.get(websocket_id);
if (maybe_connection.has_value())
maybe_connection.value()->did_receive({}, move(data), is_text);
}
void RequestClient::websocket_errored(u64 websocket_id, i32 message)
{
auto maybe_connection = m_websockets.get(websocket_id);
if (maybe_connection.has_value())
maybe_connection.value()->did_error({}, message);
}
void RequestClient::websocket_closed(u64 websocket_id, u16 code, ByteString reason, bool clean)
{
auto maybe_connection = m_websockets.get(websocket_id);
if (maybe_connection.has_value())
maybe_connection.value()->did_close({}, code, move(reason), clean);
}
void RequestClient::websocket_ready_state_changed(u64 websocket_id, u32 ready_state)
{
auto maybe_connection = m_websockets.get(websocket_id);
if (maybe_connection.has_value()) {
VERIFY(ready_state <= static_cast<u32>(WebSocket::ReadyState::Closed));
maybe_connection.value()->set_ready_state(static_cast<WebSocket::ReadyState>(ready_state));
}
}
void RequestClient::websocket_subprotocol(u64 websocket_id, ByteString subprotocol)
{
auto maybe_connection = m_websockets.get(websocket_id);
if (maybe_connection.has_value()) {
maybe_connection.value()->set_subprotocol_in_use(move(subprotocol));
}
}
void RequestClient::websocket_certificate_requested(u64 websocket_id)
{
auto maybe_connection = m_websockets.get(websocket_id);
if (maybe_connection.has_value())
maybe_connection.value()->did_request_certificates({});
}
}