1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-26 08:47:34 +00:00

LibWeb: Migrate WebSockets::WebSocket to String

This commit is contained in:
Kenneth Myhra 2023-06-17 09:18:55 +02:00 committed by Andreas Kling
parent c03c0ec900
commit 57626c4f9a
3 changed files with 38 additions and 35 deletions

View file

@ -48,7 +48,7 @@ WebSocketClientSocket::~WebSocketClientSocket() = default;
WebSocketClientManager::WebSocketClientManager() = default; WebSocketClientManager::WebSocketClientManager() = default;
// https://websockets.spec.whatwg.org/#dom-websocket-websocket // https://websockets.spec.whatwg.org/#dom-websocket-websocket
WebIDL::ExceptionOr<JS::NonnullGCPtr<WebSocket>> WebSocket::construct_impl(JS::Realm& realm, DeprecatedString const& url, Optional<Variant<DeprecatedString, Vector<DeprecatedString>>> const& protocols) WebIDL::ExceptionOr<JS::NonnullGCPtr<WebSocket>> WebSocket::construct_impl(JS::Realm& realm, String const& url, Optional<Variant<String, Vector<String>>> const& protocols)
{ {
auto& window = verify_cast<HTML::Window>(realm.global_object()); auto& window = verify_cast<HTML::Window>(realm.global_object());
AK::URL url_record(url); AK::URL url_record(url);
@ -58,13 +58,13 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<WebSocket>> WebSocket::construct_impl(JS::R
return WebIDL::SyntaxError::create(realm, "Invalid protocol"); return WebIDL::SyntaxError::create(realm, "Invalid protocol");
if (!url_record.fragment().is_empty()) if (!url_record.fragment().is_empty())
return WebIDL::SyntaxError::create(realm, "Presence of URL fragment is invalid"); return WebIDL::SyntaxError::create(realm, "Presence of URL fragment is invalid");
Vector<DeprecatedString> protocols_sequence; Vector<String> protocols_sequence;
if (protocols.has_value()) { if (protocols.has_value()) {
// 5. If `protocols` is a string, set `protocols` to a sequence consisting of just that string // 5. If `protocols` is a string, set `protocols` to a sequence consisting of just that string
if (protocols.value().has<DeprecatedString>()) if (protocols.value().has<String>())
protocols_sequence = { protocols.value().get<DeprecatedString>() }; protocols_sequence = { protocols.value().get<String>() };
else else
protocols_sequence = protocols.value().get<Vector<DeprecatedString>>(); protocols_sequence = protocols.value().get<Vector<String>>();
// 6. If any of the values in `protocols` occur more than once or otherwise fail to match the requirements, throw SyntaxError // 6. If any of the values in `protocols` occur more than once or otherwise fail to match the requirements, throw SyntaxError
auto sorted_protocols = protocols_sequence; auto sorted_protocols = protocols_sequence;
quick_sort(sorted_protocols); quick_sort(sorted_protocols);
@ -75,7 +75,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<WebSocket>> WebSocket::construct_impl(JS::R
auto protocol = sorted_protocols[i]; auto protocol = sorted_protocols[i];
if (i < sorted_protocols.size() - 1 && protocol == sorted_protocols[i + 1]) if (i < sorted_protocols.size() - 1 && protocol == sorted_protocols[i + 1])
return WebIDL::SyntaxError::create(realm, "Found a duplicate protocol name in the specified list"); return WebIDL::SyntaxError::create(realm, "Found a duplicate protocol name in the specified list");
for (auto character : protocol) { for (auto character : protocol.code_points()) {
if (character < '\x21' || character > '\x7E') if (character < '\x21' || character > '\x7E')
return WebIDL::SyntaxError::create(realm, "Found invalid character in subprotocol name"); return WebIDL::SyntaxError::create(realm, "Found invalid character in subprotocol name");
} }
@ -84,13 +84,16 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<WebSocket>> WebSocket::construct_impl(JS::R
return MUST_OR_THROW_OOM(realm.heap().allocate<WebSocket>(realm, window, url_record, protocols_sequence)); return MUST_OR_THROW_OOM(realm.heap().allocate<WebSocket>(realm, window, url_record, protocols_sequence));
} }
WebSocket::WebSocket(HTML::Window& window, AK::URL& url, Vector<DeprecatedString> const& protocols) WebSocket::WebSocket(HTML::Window& window, AK::URL& url, Vector<String> const& protocols)
: EventTarget(window.realm()) : EventTarget(window.realm())
, m_window(window) , m_window(window)
{ {
// FIXME: Integrate properly with FETCH as per https://fetch.spec.whatwg.org/#websocket-opening-handshake // FIXME: Integrate properly with FETCH as per https://fetch.spec.whatwg.org/#websocket-opening-handshake
auto origin_string = m_window->associated_document().origin().serialize(); auto origin_string = m_window->associated_document().origin().serialize();
m_websocket = WebSocketClientManager::the().connect(url, origin_string, protocols); Vector<DeprecatedString> protcol_deprecated_strings;
for (auto protocol : protocols)
protcol_deprecated_strings.append(protocol.to_deprecated_string());
m_websocket = WebSocketClientManager::the().connect(url, origin_string, protcol_deprecated_strings);
m_websocket->on_open = [weak_this = make_weak_ptr<WebSocket>()] { m_websocket->on_open = [weak_this = make_weak_ptr<WebSocket>()] {
if (!weak_this) if (!weak_this)
return; return;
@ -107,7 +110,7 @@ WebSocket::WebSocket(HTML::Window& window, AK::URL& url, Vector<DeprecatedString
if (!weak_this) if (!weak_this)
return; return;
auto& websocket = const_cast<WebSocket&>(*weak_this); auto& websocket = const_cast<WebSocket&>(*weak_this);
websocket.on_close(code, reason, was_clean); websocket.on_close(code, String::from_deprecated_string(reason).release_value_but_fixme_should_propagate_errors(), was_clean);
}; };
m_websocket->on_error = [weak_this = make_weak_ptr<WebSocket>()](auto) { m_websocket->on_error = [weak_this = make_weak_ptr<WebSocket>()](auto) {
if (!weak_this) if (!weak_this)
@ -142,25 +145,25 @@ WebSocket::ReadyState WebSocket::ready_state() const
} }
// https://websockets.spec.whatwg.org/#dom-websocket-extensions // https://websockets.spec.whatwg.org/#dom-websocket-extensions
DeprecatedString WebSocket::extensions() const String WebSocket::extensions() const
{ {
if (!m_websocket) if (!m_websocket)
return DeprecatedString::empty(); return String {};
// https://websockets.spec.whatwg.org/#feedback-from-the-protocol // https://websockets.spec.whatwg.org/#feedback-from-the-protocol
// FIXME: Change the extensions attribute's value to the extensions in use, if it is not the null value. // FIXME: Change the extensions attribute's value to the extensions in use, if it is not the null value.
return DeprecatedString::empty(); return String {};
} }
// https://websockets.spec.whatwg.org/#dom-websocket-protocol // https://websockets.spec.whatwg.org/#dom-websocket-protocol
DeprecatedString WebSocket::protocol() const WebIDL::ExceptionOr<String> WebSocket::protocol() const
{ {
if (!m_websocket) if (!m_websocket)
return DeprecatedString::empty(); return String {};
return m_websocket->subprotocol_in_use(); return TRY_OR_THROW_OOM(vm(), String::from_deprecated_string(m_websocket->subprotocol_in_use()));
} }
// https://websockets.spec.whatwg.org/#dom-websocket-close // https://websockets.spec.whatwg.org/#dom-websocket-close
WebIDL::ExceptionOr<void> WebSocket::close(Optional<u16> code, Optional<DeprecatedString> reason) WebIDL::ExceptionOr<void> WebSocket::close(Optional<u16> code, Optional<String> reason)
{ {
// 1. If code is present, but is neither an integer equal to 1000 nor an integer in the range 3000 to 4999, inclusive, throw an "InvalidAccessError" DOMException. // 1. If code is present, but is neither an integer equal to 1000 nor an integer in the range 3000 to 4999, inclusive, throw an "InvalidAccessError" DOMException.
if (code.has_value() && *code != 1000 && (*code < 3000 || *code > 4099)) if (code.has_value() && *code != 1000 && (*code < 3000 || *code > 4099))
@ -182,12 +185,12 @@ WebIDL::ExceptionOr<void> WebSocket::close(Optional<u16> code, Optional<Deprecat
// -> Otherwise // -> Otherwise
// NOTE: All of these are handled by the WebSocket Protocol when calling close() // NOTE: All of these are handled by the WebSocket Protocol when calling close()
// 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(code.value_or(1000), reason.value_or(DeprecatedString::empty())); m_websocket->close(code.value_or(1000), reason.value_or(String {}).to_deprecated_string());
return {}; return {};
} }
// https://websockets.spec.whatwg.org/#dom-websocket-send // https://websockets.spec.whatwg.org/#dom-websocket-send
WebIDL::ExceptionOr<void> WebSocket::send(Variant<JS::Handle<JS::Object>, JS::Handle<FileAPI::Blob>, DeprecatedString> const& data) WebIDL::ExceptionOr<void> WebSocket::send(Variant<JS::Handle<JS::Object>, JS::Handle<FileAPI::Blob>, String> const& data)
{ {
auto state = ready_state(); auto state = ready_state();
if (state == WebSocket::ReadyState::Connecting) if (state == WebSocket::ReadyState::Connecting)
@ -195,7 +198,7 @@ WebIDL::ExceptionOr<void> WebSocket::send(Variant<JS::Handle<JS::Object>, JS::Ha
if (state == WebSocket::ReadyState::Open) { if (state == WebSocket::ReadyState::Open) {
TRY_OR_THROW_OOM(vm(), TRY_OR_THROW_OOM(vm(),
data.visit( data.visit(
[this](DeprecatedString const& string) -> ErrorOr<void> { [this](String const& string) -> ErrorOr<void> {
m_websocket->send(string); m_websocket->send(string);
return {}; return {};
}, },
@ -233,14 +236,14 @@ void WebSocket::on_error()
} }
// https://websockets.spec.whatwg.org/#feedback-from-the-protocol // https://websockets.spec.whatwg.org/#feedback-from-the-protocol
void WebSocket::on_close(u16 code, DeprecatedString reason, bool was_clean) 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 // 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 // 2. If [needed], fire an event named error at the WebSocket object. This is handled by the Protocol's WebSocket
HTML::CloseEventInit event_init {}; HTML::CloseEventInit event_init {};
event_init.was_clean = was_clean; event_init.was_clean = was_clean;
event_init.code = code; event_init.code = code;
event_init.reason = String::from_deprecated_string(reason).release_value_but_fixme_should_propagate_errors(); event_init.reason = reason;
dispatch_event(HTML::CloseEvent::create(realm(), HTML::EventNames::close, event_init).release_value_but_fixme_should_propagate_errors()); dispatch_event(HTML::CloseEvent::create(realm(), HTML::EventNames::close, event_init).release_value_but_fixme_should_propagate_errors());
} }
@ -253,7 +256,7 @@ void WebSocket::on_message(ByteBuffer message, bool is_text)
auto text_message = DeprecatedString(ReadonlyBytes(message)); auto text_message = DeprecatedString(ReadonlyBytes(message));
HTML::MessageEventInit event_init; HTML::MessageEventInit event_init;
event_init.data = JS::PrimitiveString::create(vm(), text_message); event_init.data = JS::PrimitiveString::create(vm(), text_message);
event_init.origin = String::from_deprecated_string(url()).release_value_but_fixme_should_propagate_errors(); event_init.origin = url().release_value_but_fixme_should_propagate_errors();
dispatch_event(HTML::MessageEvent::create(realm(), HTML::EventNames::message, event_init).release_value_but_fixme_should_propagate_errors()); dispatch_event(HTML::MessageEvent::create(realm(), HTML::EventNames::message, event_init).release_value_but_fixme_should_propagate_errors());
return; return;
} }
@ -265,7 +268,7 @@ void WebSocket::on_message(ByteBuffer message, bool is_text)
// type indicates that the data is Binary and binaryType is "arraybuffer" // type indicates that the data is Binary and binaryType is "arraybuffer"
HTML::MessageEventInit event_init; HTML::MessageEventInit event_init;
event_init.data = JS::ArrayBuffer::create(realm(), message); event_init.data = JS::ArrayBuffer::create(realm(), message);
event_init.origin = String::from_deprecated_string(url()).release_value_but_fixme_should_propagate_errors(); event_init.origin = url().release_value_but_fixme_should_propagate_errors();
dispatch_event(HTML::MessageEvent::create(realm(), HTML::EventNames::message, event_init).release_value_but_fixme_should_propagate_errors()); dispatch_event(HTML::MessageEvent::create(realm(), HTML::EventNames::message, event_init).release_value_but_fixme_should_propagate_errors());
return; return;
} }

View file

@ -37,11 +37,11 @@ public:
Closed = 3, Closed = 3,
}; };
static WebIDL::ExceptionOr<JS::NonnullGCPtr<WebSocket>> construct_impl(JS::Realm&, DeprecatedString const& url, Optional<Variant<DeprecatedString, Vector<DeprecatedString>>> const& protocols); static WebIDL::ExceptionOr<JS::NonnullGCPtr<WebSocket>> construct_impl(JS::Realm&, String const& url, Optional<Variant<String, Vector<String>>> const& protocols);
virtual ~WebSocket() override; virtual ~WebSocket() override;
DeprecatedString url() const { return m_url.to_deprecated_string(); } WebIDL::ExceptionOr<String> url() const { return TRY_OR_THROW_OOM(vm(), m_url.to_string()); }
#undef __ENUMERATE #undef __ENUMERATE
#define __ENUMERATE(attribute_name, event_name) \ #define __ENUMERATE(attribute_name, event_name) \
@ -51,22 +51,22 @@ public:
#undef __ENUMERATE #undef __ENUMERATE
ReadyState ready_state() const; ReadyState ready_state() const;
DeprecatedString extensions() const; String extensions() const;
DeprecatedString protocol() const; WebIDL::ExceptionOr<String> protocol() const;
DeprecatedString const& binary_type() { return m_binary_type; }; String const& binary_type() { return m_binary_type; };
void set_binary_type(DeprecatedString const& type) { m_binary_type = type; }; void set_binary_type(String const& type) { m_binary_type = type; };
WebIDL::ExceptionOr<void> close(Optional<u16> code, Optional<DeprecatedString> reason); WebIDL::ExceptionOr<void> close(Optional<u16> code, Optional<String> reason);
WebIDL::ExceptionOr<void> send(Variant<JS::Handle<JS::Object>, JS::Handle<FileAPI::Blob>, DeprecatedString> const& data); WebIDL::ExceptionOr<void> send(Variant<JS::Handle<JS::Object>, JS::Handle<FileAPI::Blob>, String> const& data);
private: private:
void on_open(); void on_open();
void on_message(ByteBuffer message, bool is_text); void on_message(ByteBuffer message, bool is_text);
void on_error(); void on_error();
void on_close(u16 code, DeprecatedString reason, bool was_clean); void on_close(u16 code, String reason, bool was_clean);
WebSocket(HTML::Window&, AK::URL&, Vector<DeprecatedString> const& protocols); WebSocket(HTML::Window&, AK::URL&, Vector<String> const& protocols);
virtual JS::ThrowCompletionOr<void> initialize(JS::Realm&) override; virtual JS::ThrowCompletionOr<void> initialize(JS::Realm&) override;
virtual void visit_edges(Cell::Visitor&) override; virtual void visit_edges(Cell::Visitor&) override;
@ -74,7 +74,7 @@ private:
JS::NonnullGCPtr<HTML::Window> m_window; JS::NonnullGCPtr<HTML::Window> m_window;
AK::URL m_url; AK::URL m_url;
DeprecatedString m_binary_type { "blob" }; String m_binary_type { "blob"_string.release_value_but_fixme_should_propagate_errors() };
RefPtr<WebSocketClientSocket> m_websocket; RefPtr<WebSocketClientSocket> m_websocket;
}; };

View file

@ -2,7 +2,7 @@
#import <DOM/EventHandler.idl> #import <DOM/EventHandler.idl>
// https://websockets.spec.whatwg.org/#websocket // https://websockets.spec.whatwg.org/#websocket
[Exposed=(Window,Worker)] [Exposed=(Window,Worker), UseNewAKString]
interface WebSocket : EventTarget { interface WebSocket : EventTarget {
constructor(USVString url, optional (DOMString or sequence<DOMString>) protocols); constructor(USVString url, optional (DOMString or sequence<DOMString>) protocols);