mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-25 00:50:22 +00:00
LibWeb: Add WebSocket task source
The WebSocket spec tells us to queue tasks instead of firing events synchronously at WebSockets, so this commit does exactly that. The way we've implemented web sockets means that the work is spread across multiple libraries and even processes, which is why it doesn't look like the spec verbatim.
This commit is contained in:
parent
7c2601f315
commit
87fc7028d7
Notes:
github-actions[bot]
2024-11-15 22:19:08 +00:00
Author: https://github.com/awesomekling Commit: https://github.com/LadybirdBrowser/ladybird/commit/87fc7028d7c Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/2369
2 changed files with 53 additions and 37 deletions
|
@ -68,6 +68,9 @@ public:
|
|||
// https://w3c.github.io/IndexedDB/#database-access-task-source
|
||||
DatabaseAccess,
|
||||
|
||||
// https://websockets.spec.whatwg.org/#websocket-task-source
|
||||
WebSocket,
|
||||
|
||||
// !!! IMPORTANT: Keep this field last!
|
||||
// This serves as the base value of all unique task sources.
|
||||
// Some elements, such as the HTMLMediaElement, must have a unique task source per instance.
|
||||
|
|
|
@ -247,28 +247,37 @@ WebIDL::ExceptionOr<void> WebSocket::send(Variant<GC::Root<WebIDL::BufferSource>
|
|||
// https://websockets.spec.whatwg.org/#feedback-from-the-protocol
|
||||
void WebSocket::on_open()
|
||||
{
|
||||
// 1. Change the readyState attribute's value to OPEN (1).
|
||||
// 2. Change the extensions attribute's value to the extensions in use, if it is not the null value. [WSP]
|
||||
// 3. Change the protocol attribute's value to the subprotocol in use, if it is not the null value. [WSP]
|
||||
dispatch_event(DOM::Event::create(realm(), HTML::EventNames::open));
|
||||
// When the WebSocket connection is established, the user agent must queue a task to run these steps:
|
||||
HTML::queue_a_task(HTML::Task::Source::WebSocket, nullptr, nullptr, GC::create_function(heap(), [this] {
|
||||
// 1. Change the readyState attribute's value to OPEN (1).
|
||||
// 2. Change the extensions attribute's value to the extensions in use, if it is not the null value. [WSP]
|
||||
// 3. Change the protocol attribute's value to the subprotocol in use, if it is not the null value. [WSP]
|
||||
dispatch_event(DOM::Event::create(realm(), HTML::EventNames::open));
|
||||
}));
|
||||
}
|
||||
|
||||
// https://websockets.spec.whatwg.org/#feedback-from-the-protocol
|
||||
void WebSocket::on_error()
|
||||
{
|
||||
dispatch_event(DOM::Event::create(realm(), HTML::EventNames::error));
|
||||
// When the WebSocket connection is closed, possibly cleanly, the user agent must queue a task to run the following substeps:
|
||||
HTML::queue_a_task(HTML::Task::Source::WebSocket, nullptr, nullptr, GC::create_function(heap(), [this] {
|
||||
dispatch_event(DOM::Event::create(realm(), HTML::EventNames::error));
|
||||
}));
|
||||
}
|
||||
|
||||
// https://websockets.spec.whatwg.org/#feedback-from-the-protocol
|
||||
void WebSocket::on_close(u16 code, String reason, bool was_clean)
|
||||
{
|
||||
// 1. Change the readyState attribute's value to CLOSED. This is handled by the Protocol's WebSocket
|
||||
// 2. If [needed], fire an event named error at the WebSocket object. This is handled by the Protocol's WebSocket
|
||||
HTML::CloseEventInit event_init {};
|
||||
event_init.was_clean = was_clean;
|
||||
event_init.code = code;
|
||||
event_init.reason = reason;
|
||||
dispatch_event(HTML::CloseEvent::create(realm(), HTML::EventNames::close, event_init));
|
||||
// When the WebSocket connection is closed, possibly cleanly, the user agent must queue a task to run the following substeps:
|
||||
HTML::queue_a_task(HTML::Task::Source::WebSocket, nullptr, nullptr, GC::create_function(heap(), [this, code, reason = move(reason), was_clean] {
|
||||
// 1. Change the readyState attribute's value to CLOSED. This is handled by the Protocol's WebSocket
|
||||
// 2. If [needed], fire an event named error at the WebSocket object. This is handled by the Protocol's WebSocket
|
||||
HTML::CloseEventInit event_init {};
|
||||
event_init.was_clean = was_clean;
|
||||
event_init.code = code;
|
||||
event_init.reason = reason;
|
||||
dispatch_event(HTML::CloseEvent::create(realm(), HTML::EventNames::close, event_init));
|
||||
}));
|
||||
}
|
||||
|
||||
// https://websockets.spec.whatwg.org/#feedback-from-the-protocol
|
||||
|
@ -276,33 +285,37 @@ void WebSocket::on_message(ByteBuffer message, bool is_text)
|
|||
{
|
||||
if (m_websocket->ready_state() != Requests::WebSocket::ReadyState::Open)
|
||||
return;
|
||||
if (is_text) {
|
||||
auto text_message = ByteString(ReadonlyBytes(message));
|
||||
HTML::MessageEventInit event_init;
|
||||
event_init.data = JS::PrimitiveString::create(vm(), text_message);
|
||||
event_init.origin = url().release_value_but_fixme_should_propagate_errors();
|
||||
dispatch_event(HTML::MessageEvent::create(realm(), HTML::EventNames::message, event_init));
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_binary_type == "blob") {
|
||||
// type indicates that the data is Binary and binaryType is "blob"
|
||||
HTML::MessageEventInit event_init;
|
||||
event_init.data = FileAPI::Blob::create(realm(), message, "text/plain;charset=utf-8"_string);
|
||||
event_init.origin = url().release_value_but_fixme_should_propagate_errors();
|
||||
dispatch_event(HTML::MessageEvent::create(realm(), HTML::EventNames::message, event_init));
|
||||
return;
|
||||
} else if (m_binary_type == "arraybuffer") {
|
||||
// type indicates that the data is Binary and binaryType is "arraybuffer"
|
||||
HTML::MessageEventInit event_init;
|
||||
event_init.data = JS::ArrayBuffer::create(realm(), message);
|
||||
event_init.origin = url().release_value_but_fixme_should_propagate_errors();
|
||||
dispatch_event(HTML::MessageEvent::create(realm(), HTML::EventNames::message, event_init));
|
||||
return;
|
||||
}
|
||||
// When a WebSocket message has been received with type type and data data, the user agent must queue a task to follow these steps:
|
||||
HTML::queue_a_task(HTML::Task::Source::WebSocket, nullptr, nullptr, GC::create_function(heap(), [this, message = move(message), is_text] {
|
||||
if (is_text) {
|
||||
auto text_message = ByteString(ReadonlyBytes(message));
|
||||
HTML::MessageEventInit event_init;
|
||||
event_init.data = JS::PrimitiveString::create(vm(), text_message);
|
||||
event_init.origin = url().release_value_but_fixme_should_propagate_errors();
|
||||
dispatch_event(HTML::MessageEvent::create(realm(), HTML::EventNames::message, event_init));
|
||||
return;
|
||||
}
|
||||
|
||||
dbgln("Unsupported WebSocket message type {}", m_binary_type);
|
||||
TODO();
|
||||
if (m_binary_type == "blob") {
|
||||
// type indicates that the data is Binary and binaryType is "blob"
|
||||
HTML::MessageEventInit event_init;
|
||||
event_init.data = FileAPI::Blob::create(realm(), message, "text/plain;charset=utf-8"_string);
|
||||
event_init.origin = url().release_value_but_fixme_should_propagate_errors();
|
||||
dispatch_event(HTML::MessageEvent::create(realm(), HTML::EventNames::message, event_init));
|
||||
return;
|
||||
} else if (m_binary_type == "arraybuffer") {
|
||||
// type indicates that the data is Binary and binaryType is "arraybuffer"
|
||||
HTML::MessageEventInit event_init;
|
||||
event_init.data = JS::ArrayBuffer::create(realm(), message);
|
||||
event_init.origin = url().release_value_but_fixme_should_propagate_errors();
|
||||
dispatch_event(HTML::MessageEvent::create(realm(), HTML::EventNames::message, event_init));
|
||||
return;
|
||||
}
|
||||
|
||||
dbgln("Unsupported WebSocket message type {}", m_binary_type);
|
||||
TODO();
|
||||
}));
|
||||
}
|
||||
|
||||
#undef __ENUMERATE
|
||||
|
|
Loading…
Reference in a new issue