mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-06-09 17:44:56 +09:00
LibWeb: Close WebSockets when document is unloaded
Previously, they would stay open for the entire WebContent lifetime, or until the server closed the connection. This was particularly noticeable on collaborative websites/games such as https://jigsawpuzzles.io/, where the user using Ladybird would stick around even after they had navigated away.
This commit is contained in:
parent
3224f8acb5
commit
12a07b4fad
Notes:
github-actions[bot]
2025-02-26 10:48:29 +00:00
Author: https://github.com/Lubrsi
Commit: 12a07b4fad
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/3694
5 changed files with 66 additions and 3 deletions
|
@ -3905,8 +3905,11 @@ void Document::run_unloading_cleanup_steps()
|
||||||
// 1. Let window be document's relevant global object.
|
// 1. Let window be document's relevant global object.
|
||||||
auto& window = as<HTML::WindowOrWorkerGlobalScopeMixin>(HTML::relevant_global_object(*this));
|
auto& window = as<HTML::WindowOrWorkerGlobalScopeMixin>(HTML::relevant_global_object(*this));
|
||||||
|
|
||||||
// FIXME: 2. For each WebSocket object webSocket whose relevant global object is window, make disappear webSocket.
|
// 2. For each WebSocket object webSocket whose relevant global object is window, make disappear webSocket.
|
||||||
// If this affected any WebSocket objects, then set document's salvageable state to false.
|
// If this affected any WebSocket objects, then set document's salvageable state to false.
|
||||||
|
auto affected_any_web_sockets = window.make_disappear_all_web_sockets();
|
||||||
|
if (affected_any_web_sockets == HTML::WindowOrWorkerGlobalScopeMixin::AffectedAnyWebSockets::Yes)
|
||||||
|
m_salvageable = false;
|
||||||
|
|
||||||
// FIXME: 3. For each WebTransport object transport whose relevant global object is window, run the context cleanup steps given transport.
|
// FIXME: 3. For each WebTransport object transport whose relevant global object is window, run the context cleanup steps given transport.
|
||||||
|
|
||||||
|
|
|
@ -44,6 +44,7 @@
|
||||||
#include <LibWeb/WebIDL/DOMException.h>
|
#include <LibWeb/WebIDL/DOMException.h>
|
||||||
#include <LibWeb/WebIDL/ExceptionOr.h>
|
#include <LibWeb/WebIDL/ExceptionOr.h>
|
||||||
#include <LibWeb/WebIDL/Types.h>
|
#include <LibWeb/WebIDL/Types.h>
|
||||||
|
#include <LibWeb/WebSockets/WebSocket.h>
|
||||||
|
|
||||||
namespace Web::HTML {
|
namespace Web::HTML {
|
||||||
|
|
||||||
|
@ -638,6 +639,28 @@ void WindowOrWorkerGlobalScopeMixin::forcibly_close_all_event_sources()
|
||||||
event_source->forcibly_close();
|
event_source->forcibly_close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WindowOrWorkerGlobalScopeMixin::register_web_socket(Badge<WebSockets::WebSocket>, GC::Ref<WebSockets::WebSocket> web_socket)
|
||||||
|
{
|
||||||
|
m_registered_web_sockets.append(web_socket);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WindowOrWorkerGlobalScopeMixin::unregister_web_socket(Badge<WebSockets::WebSocket>, GC::Ref<WebSockets::WebSocket> web_socket)
|
||||||
|
{
|
||||||
|
m_registered_web_sockets.remove(web_socket);
|
||||||
|
}
|
||||||
|
|
||||||
|
WindowOrWorkerGlobalScopeMixin::AffectedAnyWebSockets WindowOrWorkerGlobalScopeMixin::make_disappear_all_web_sockets()
|
||||||
|
{
|
||||||
|
auto affected_any_web_sockets = AffectedAnyWebSockets::No;
|
||||||
|
|
||||||
|
for (auto& web_socket : m_registered_web_sockets) {
|
||||||
|
web_socket.make_disappear();
|
||||||
|
affected_any_web_sockets = AffectedAnyWebSockets::Yes;
|
||||||
|
}
|
||||||
|
|
||||||
|
return affected_any_web_sockets;
|
||||||
|
}
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/timers-and-user-prompts.html#run-steps-after-a-timeout
|
// https://html.spec.whatwg.org/multipage/timers-and-user-prompts.html#run-steps-after-a-timeout
|
||||||
void WindowOrWorkerGlobalScopeMixin::run_steps_after_a_timeout(i32 timeout, Function<void()> completion_step)
|
void WindowOrWorkerGlobalScopeMixin::run_steps_after_a_timeout(i32 timeout, Function<void()> completion_step)
|
||||||
{
|
{
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#include <LibWeb/HTML/ImageBitmap.h>
|
#include <LibWeb/HTML/ImageBitmap.h>
|
||||||
#include <LibWeb/PerformanceTimeline/PerformanceEntry.h>
|
#include <LibWeb/PerformanceTimeline/PerformanceEntry.h>
|
||||||
#include <LibWeb/PerformanceTimeline/PerformanceEntryTuple.h>
|
#include <LibWeb/PerformanceTimeline/PerformanceEntryTuple.h>
|
||||||
|
#include <LibWeb/WebSockets/WebSocket.h>
|
||||||
|
|
||||||
namespace Web::HTML {
|
namespace Web::HTML {
|
||||||
|
|
||||||
|
@ -63,6 +64,15 @@ public:
|
||||||
void unregister_event_source(Badge<EventSource>, GC::Ref<EventSource>);
|
void unregister_event_source(Badge<EventSource>, GC::Ref<EventSource>);
|
||||||
void forcibly_close_all_event_sources();
|
void forcibly_close_all_event_sources();
|
||||||
|
|
||||||
|
void register_web_socket(Badge<WebSockets::WebSocket>, GC::Ref<WebSockets::WebSocket>);
|
||||||
|
void unregister_web_socket(Badge<WebSockets::WebSocket>, GC::Ref<WebSockets::WebSocket>);
|
||||||
|
|
||||||
|
enum class AffectedAnyWebSockets {
|
||||||
|
No,
|
||||||
|
Yes,
|
||||||
|
};
|
||||||
|
AffectedAnyWebSockets make_disappear_all_web_sockets();
|
||||||
|
|
||||||
void run_steps_after_a_timeout(i32 timeout, Function<void()> completion_step);
|
void run_steps_after_a_timeout(i32 timeout, Function<void()> completion_step);
|
||||||
|
|
||||||
[[nodiscard]] GC::Ref<HighResolutionTime::Performance> performance();
|
[[nodiscard]] GC::Ref<HighResolutionTime::Performance> performance();
|
||||||
|
@ -123,6 +133,8 @@ private:
|
||||||
GC::Ptr<Crypto::Crypto> m_crypto;
|
GC::Ptr<Crypto::Crypto> m_crypto;
|
||||||
|
|
||||||
bool m_error_reporting_mode { false };
|
bool m_error_reporting_mode { false };
|
||||||
|
|
||||||
|
WebSockets::WebSocket::List m_registered_web_sockets;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -121,6 +121,9 @@ void WebSocket::initialize(JS::Realm& realm)
|
||||||
{
|
{
|
||||||
Base::initialize(realm);
|
Base::initialize(realm);
|
||||||
WEB_SET_PROTOTYPE_FOR_INTERFACE(WebSocket);
|
WEB_SET_PROTOTYPE_FOR_INTERFACE(WebSocket);
|
||||||
|
|
||||||
|
auto& relevant_global = as<HTML::WindowOrWorkerGlobalScopeMixin>(HTML::relevant_global_object(*this));
|
||||||
|
relevant_global.register_web_socket({}, *this);
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/server-sent-events.html#garbage-collection
|
// https://html.spec.whatwg.org/multipage/server-sent-events.html#garbage-collection
|
||||||
|
@ -134,6 +137,9 @@ void WebSocket::finalize()
|
||||||
// FIXME: LibProtocol does not yet support sending empty Close messages, so we use default values for now
|
// FIXME: LibProtocol does not yet support sending empty Close messages, so we use default values for now
|
||||||
m_websocket->close(1000);
|
m_websocket->close(1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto& relevant_global = as<HTML::WindowOrWorkerGlobalScopeMixin>(HTML::relevant_global_object(*this));
|
||||||
|
relevant_global.unregister_web_socket({}, *this);
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/server-sent-events.html#garbage-collection
|
// https://html.spec.whatwg.org/multipage/server-sent-events.html#garbage-collection
|
||||||
|
@ -395,6 +401,19 @@ void WebSocket::on_message(ByteBuffer message, bool is_text)
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// https://websockets.spec.whatwg.org/#make-disappear
|
||||||
|
void WebSocket::make_disappear()
|
||||||
|
{
|
||||||
|
// -> If the WebSocket connection is not yet established [WSP]
|
||||||
|
// - Fail the WebSocket connection. [WSP]
|
||||||
|
// -> If the WebSocket closing handshake has not yet been started [WSP]
|
||||||
|
// - Start the WebSocket closing handshake, with the status code to use in the WebSocket Close message being 1001. [WSP]
|
||||||
|
// -> Otherwise
|
||||||
|
// - Do nothing.
|
||||||
|
// NOTE: All of these are handled by the WebSocket Protocol when calling close()
|
||||||
|
m_websocket->close(1001);
|
||||||
|
}
|
||||||
|
|
||||||
#undef __ENUMERATE
|
#undef __ENUMERATE
|
||||||
#define __ENUMERATE(attribute_name, event_name) \
|
#define __ENUMERATE(attribute_name, event_name) \
|
||||||
void WebSocket::set_##attribute_name(WebIDL::CallbackType* value) \
|
void WebSocket::set_##attribute_name(WebIDL::CallbackType* value) \
|
||||||
|
|
|
@ -15,7 +15,6 @@
|
||||||
#include <LibWeb/Bindings/PlatformObject.h>
|
#include <LibWeb/Bindings/PlatformObject.h>
|
||||||
#include <LibWeb/DOM/EventTarget.h>
|
#include <LibWeb/DOM/EventTarget.h>
|
||||||
#include <LibWeb/Forward.h>
|
#include <LibWeb/Forward.h>
|
||||||
#include <LibWeb/HTML/Window.h>
|
|
||||||
#include <LibWeb/WebIDL/ExceptionOr.h>
|
#include <LibWeb/WebIDL/ExceptionOr.h>
|
||||||
|
|
||||||
#define ENUMERATE_WEBSOCKET_EVENT_HANDLERS(E) \
|
#define ENUMERATE_WEBSOCKET_EVENT_HANDLERS(E) \
|
||||||
|
@ -55,6 +54,8 @@ public:
|
||||||
WebIDL::ExceptionOr<void> close(Optional<u16> code, Optional<String> reason);
|
WebIDL::ExceptionOr<void> close(Optional<u16> code, Optional<String> reason);
|
||||||
WebIDL::ExceptionOr<void> send(Variant<GC::Root<WebIDL::BufferSource>, GC::Root<FileAPI::Blob>, String> const& data);
|
WebIDL::ExceptionOr<void> send(Variant<GC::Root<WebIDL::BufferSource>, GC::Root<FileAPI::Blob>, String> const& data);
|
||||||
|
|
||||||
|
void make_disappear();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void on_open();
|
void on_open();
|
||||||
void on_message(ByteBuffer message, bool is_text);
|
void on_message(ByteBuffer message, bool is_text);
|
||||||
|
@ -72,6 +73,11 @@ private:
|
||||||
URL::URL m_url;
|
URL::URL m_url;
|
||||||
String m_binary_type { "blob"_string };
|
String m_binary_type { "blob"_string };
|
||||||
RefPtr<Requests::WebSocket> m_websocket;
|
RefPtr<Requests::WebSocket> m_websocket;
|
||||||
|
|
||||||
|
IntrusiveListNode<WebSocket> m_list_node;
|
||||||
|
|
||||||
|
public:
|
||||||
|
using List = IntrusiveList<&WebSocket::m_list_node>;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue