LibRequests: Fail websockets when RequestServer dies
Detach live websocket wrappers from a dead RequestServer connection, notify them with error and close events, and defer the on_request_server_died callback out of RequestClient::die(). Without this, a dead RequestServer could leave existing websocket objects stuck forever and future websocket construction could keep using a stale RequestClient with no terminal events.
This commit is contained in:
parent
48a0e9fef7
commit
c880a34541
3 changed files with 33 additions and 1 deletions
|
|
@ -4,6 +4,7 @@
|
|||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <LibCore/EventLoop.h>
|
||||
#include <LibCore/Promise.h>
|
||||
#include <LibCore/System.h>
|
||||
#include <LibRequests/Request.h>
|
||||
|
|
@ -28,8 +29,29 @@ void RequestClient::die()
|
|||
for (auto& [id, promise] : m_pending_cache_size_estimations)
|
||||
promise->reject(Error::from_string_literal("RequestServer process died"));
|
||||
|
||||
auto websockets = move(m_websockets);
|
||||
|
||||
m_requests.clear();
|
||||
m_pending_cache_size_estimations.clear();
|
||||
m_websockets.clear();
|
||||
|
||||
for (auto& [id, websocket] : websockets) {
|
||||
auto ready_state = websocket->ready_state();
|
||||
websocket->detach_from_client({});
|
||||
websocket->set_ready_state(WebSocket::ReadyState::Closed);
|
||||
|
||||
auto error = ready_state == WebSocket::ReadyState::Connecting
|
||||
? WebSocket::Error::CouldNotEstablishConnection
|
||||
: WebSocket::Error::ServerClosedSocket;
|
||||
websocket->did_error({}, to_underlying(error));
|
||||
websocket->did_close({}, to_underlying(::WebSocket::CloseStatusCode::AbnormalClosure), {}, false);
|
||||
}
|
||||
|
||||
if (auto request_server_died_callback = move(on_request_server_died)) {
|
||||
Core::deferred_invoke([request_server_died_callback = move(request_server_died_callback)]() mutable {
|
||||
request_server_died_callback();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
RefPtr<Request> RequestClient::start_request(ByteString const& method, URL::URL const& url, Optional<HTTP::HeaderList const&> request_headers, ReadonlyBytes request_body, HTTP::CacheMode cache_mode, HTTP::Cookie::IncludeCredentials include_credentials, Core::ProxyData const& proxy_data)
|
||||
|
|
|
|||
|
|
@ -37,6 +37,8 @@ void WebSocket::set_subprotocol_in_use(ByteString subprotocol)
|
|||
|
||||
void WebSocket::send(ReadonlyBytes binary_or_text_message, bool is_text)
|
||||
{
|
||||
if (!m_client)
|
||||
return;
|
||||
m_client->async_websocket_send(m_websocket_id, is_text, binary_or_text_message);
|
||||
}
|
||||
|
||||
|
|
@ -47,6 +49,8 @@ void WebSocket::send(StringView text_message)
|
|||
|
||||
void WebSocket::close(u16 code, ByteString reason)
|
||||
{
|
||||
if (!m_client)
|
||||
return;
|
||||
m_client->async_websocket_close(m_websocket_id, code, move(reason));
|
||||
}
|
||||
|
||||
|
|
@ -78,9 +82,14 @@ void WebSocket::did_request_certificates(Badge<RequestClient>)
|
|||
{
|
||||
if (on_certificate_requested) {
|
||||
auto result = on_certificate_requested();
|
||||
if (!m_client->websocket_set_certificate(m_websocket_id, result.certificate, result.key))
|
||||
if (!m_client || !m_client->websocket_set_certificate(m_websocket_id, result.certificate, result.key))
|
||||
dbgln("WebSocket: set_certificate failed");
|
||||
}
|
||||
}
|
||||
|
||||
void WebSocket::detach_from_client(Badge<RequestClient>)
|
||||
{
|
||||
m_client = nullptr;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -70,6 +70,7 @@ public:
|
|||
void did_error(Badge<RequestClient>, i32);
|
||||
void did_close(Badge<RequestClient>, u16, ByteString, bool);
|
||||
void did_request_certificates(Badge<RequestClient>);
|
||||
void detach_from_client(Badge<RequestClient>);
|
||||
|
||||
private:
|
||||
WebSocket(RequestClient&, u64 websocket_id);
|
||||
|
|
|
|||
Loading…
Reference in a new issue