From 37e1d6ece10eae8d2a8f7addb41131895d4c92f6 Mon Sep 17 00:00:00 2001 From: Feng Yu Date: Thu, 2 Jan 2025 17:18:49 -0800 Subject: [PATCH] LibWeb: Implement `nagivator.serviceWorker.getRegistration()` --- .../LibWeb/HTML/Scripting/Environments.cpp | 63 ++++++++++++++++++ .../LibWeb/HTML/Scripting/Environments.h | 17 +++++ .../LibWeb/ServiceWorker/Registration.cpp | 66 ++++++++++++++----- Libraries/LibWeb/ServiceWorker/Registration.h | 25 +++++++ .../LibWeb/ServiceWorker/ServiceWorker.cpp | 17 +++-- .../LibWeb/ServiceWorker/ServiceWorker.h | 10 +-- .../ServiceWorker/ServiceWorkerContainer.cpp | 59 +++++++++++++++++ .../ServiceWorker/ServiceWorkerContainer.h | 2 + .../ServiceWorker/ServiceWorkerContainer.idl | 2 +- .../ServiceWorkerRegistration.cpp | 16 ++++- .../ServiceWorker/ServiceWorkerRegistration.h | 29 +++++++- .../ServiceWorkerRegistration.idl | 10 +-- 12 files changed, 280 insertions(+), 36 deletions(-) diff --git a/Libraries/LibWeb/HTML/Scripting/Environments.cpp b/Libraries/LibWeb/HTML/Scripting/Environments.cpp index 55e154688cc..c077ece2e3a 100644 --- a/Libraries/LibWeb/HTML/Scripting/Environments.cpp +++ b/Libraries/LibWeb/HTML/Scripting/Environments.cpp @@ -21,6 +21,8 @@ #include #include #include +#include +#include #include namespace Web::HTML { @@ -61,6 +63,8 @@ void EnvironmentSettingsObject::visit_edges(Cell::Visitor& visitor) m_realm_execution_context->visit_edges(visitor); visitor.visit(m_fetch_group); visitor.visit(m_storage_manager); + visitor.visit(m_service_worker_registration_object_map); + visitor.visit(m_service_worker_object_map); } JS::ExecutionContext& EnvironmentSettingsObject::realm_execution_context() @@ -574,4 +578,63 @@ GC::Ref EnvironmentSettingsObject::storage_manager() return *m_storage_manager; } +// https://w3c.github.io/ServiceWorker/#get-the-service-worker-registration-object +GC::Ref EnvironmentSettingsObject::get_service_worker_registration_object(ServiceWorker::Registration const& registration) +{ + // 1. Let objectMap be environment’s service worker registration object map. + auto& object_map = this->m_service_worker_registration_object_map; + + // FIXME: File spec issue asking if this should be keyed on the registration's scope url only or on the url and the storage key + auto const key = ServiceWorker::RegistrationKey { registration.storage_key(), registration.scope_url().serialize(URL::ExcludeFragment::Yes).to_byte_string() }; + + // 2. If objectMap[registration] does not exist, then: + if (!object_map.contains(key)) { + // 1. Let registrationObject be a new ServiceWorkerRegistration in environment’s Realm. + // 2. Set registrationObject’s service worker registration to registration. + // 3. Set registrationObject’s installing attribute to null. + // 4. Set registrationObject’s waiting attribute to null. + // 5. Set registrationObject’s active attribute to null. + auto registration_object = ServiceWorker::ServiceWorkerRegistration::create(realm(), registration); + + // 6. If registration’s installing worker is not null, then set registrationObject’s installing attribute to the result of getting the service worker object that represents registration’s installing worker in environment. + if (registration.installing_worker()) + registration_object->set_installing(get_service_worker_object(registration.installing_worker())); + + // 7. If registration’s waiting worker is not null, then set registrationObject’s waiting attribute to the result of getting the service worker object that represents registration’s waiting worker in environment. + if (registration.waiting_worker()) + registration_object->set_waiting(get_service_worker_object(registration.waiting_worker())); + + // 8. If registration’s active worker is not null, then set registrationObject’s active attribute to the result of getting the service worker object that represents registration’s active worker in environment. + if (registration.active_worker()) + registration_object->set_active(get_service_worker_object(registration.active_worker())); + + // 9. Set objectMap[registration] to registrationObject. + object_map.set(key, registration_object); + } + + // 3. Return objectMap[registration]. + return *object_map.get(key); +} + +GC::Ref EnvironmentSettingsObject::get_service_worker_object(ServiceWorker::ServiceWorkerRecord* service_worker) +{ + // 1. Let objectMap be environment’s service worker object map. + auto& object_map = this->m_service_worker_object_map; + + // 2. If objectMap[serviceWorker] does not exist, then: + if (!object_map.contains(service_worker)) { + // 1. Let serviceWorkerObj be a new ServiceWorker in environment’s Realm, and associate it with serviceWorker. + auto service_worker_obj = ServiceWorker::ServiceWorker::create(realm(), service_worker); + + // 2. Set serviceWorkerObj’s state to serviceWorker’s state. + service_worker_obj->set_service_worker_state(service_worker->state); + + // 3. Set objectMap[serviceWorker] to serviceWorkerObj. + object_map.set(service_worker, service_worker_obj); + } + + // 3. Return objectMap[serviceWorker]. + return *object_map.get(service_worker); +} + } diff --git a/Libraries/LibWeb/HTML/Scripting/Environments.h b/Libraries/LibWeb/HTML/Scripting/Environments.h index 4757942f33a..ad9d5e08ea2 100644 --- a/Libraries/LibWeb/HTML/Scripting/Environments.h +++ b/Libraries/LibWeb/HTML/Scripting/Environments.h @@ -15,6 +15,7 @@ #include #include #include +#include namespace Web::HTML { @@ -105,6 +106,12 @@ public: GC::Ref storage_manager(); + // https://w3c.github.io/ServiceWorker/#get-the-service-worker-registration-object + GC::Ref get_service_worker_registration_object(ServiceWorker::Registration const&); + + // https://w3c.github.io/ServiceWorker/#get-the-service-worker-object + GC::Ref get_service_worker_object(ServiceWorker::ServiceWorkerRecord*); + [[nodiscard]] bool discarded() const { return m_discarded; } void set_discarded(bool b) { m_discarded = b; } @@ -127,6 +134,16 @@ private: // Each environment settings object has an associated StorageManager object. GC::Ptr m_storage_manager; + // https://w3c.github.io/ServiceWorker/#environment-settings-object-service-worker-registration-object-map + // An environment settings object has a service worker registration object map, + // a map where the keys are service worker registrations and the values are ServiceWorkerRegistration objects. + HashMap> m_service_worker_registration_object_map; + + // https://w3c.github.io/ServiceWorker/#environment-settings-object-service-worker-object-map + // An environment settings object has a service worker object map, + // a map where the keys are service workers and the values are ServiceWorker objects. + HashMap> m_service_worker_object_map; + // https://w3c.github.io/ServiceWorker/#service-worker-client-discarded-flag // A service worker client has an associated discarded flag. It is initially unset. bool m_discarded { false }; diff --git a/Libraries/LibWeb/ServiceWorker/Registration.cpp b/Libraries/LibWeb/ServiceWorker/Registration.cpp index 07838b34f33..eb9ad90f26f 100644 --- a/Libraries/LibWeb/ServiceWorker/Registration.cpp +++ b/Libraries/LibWeb/ServiceWorker/Registration.cpp @@ -5,17 +5,12 @@ */ #include +#include +#include #include namespace Web::ServiceWorker { -struct RegistrationKey { - StorageAPI::StorageKey key; - ByteString serialized_scope_url; - - bool operator==(RegistrationKey const&) const = default; -}; - // FIXME: Surely this needs hooks to be cleared and manipulated at the UA level // Does this need to be serialized to disk as well? static HashMap s_registrations; @@ -84,6 +79,53 @@ Registration& Registration::set(StorageAPI::StorageKey const& storage_key, URL:: return s_registrations.get(key).value(); } +// https://w3c.github.io/ServiceWorker/#scope-match-algorithm +Optional Registration::match(StorageAPI::StorageKey const& storage_key, URL::URL const& client_url) +{ + // FIXME: 1. Run the following steps atomically. + + // 2. Let clientURLString be serialized clientURL. + auto client_url_string = client_url.serialize(); + + // 3. Let matchingScopeString be the empty string. + ByteString matching_scope_string; + + // 4. Let scopeStringSet be an empty list. + Vector scope_string_set; + + // 5. For each (entry storage key, entry scope) of registration map's keys: + for (auto& [entry_storage_key, entry_scope] : s_registrations.keys()) { + // 1. If storage key equals entry storage key, then append entry scope to the end of scopeStringSet. + if (entry_storage_key == storage_key) + scope_string_set.append(entry_scope); + } + + // 6. Set matchingScopeString to the longest value in scopeStringSet which the value of clientURLString starts with, if it exists. + // NOTE: The URL string matching in this step is prefix-based rather than path-structural. E.g. a client + // URL string with "https://example.com/prefix-of/resource.html" will match a registration for a + // scope with "https://example.com/prefix". The URL string comparison is safe for the same-origin + // security as HTTP(S) URLs are always serialized with a trailing slash at the end of the origin + // part of the URLs. + for (auto& scope_string : scope_string_set) { + if (client_url_string.starts_with_bytes(scope_string) && scope_string.length() > matching_scope_string.length()) + matching_scope_string = scope_string; + } + + // 7. Let matchingScope be null. + Optional matching_scope; + + // 8. If matchingScopeString is not the empty string, then: + if (!matching_scope_string.is_empty()) { + // 1. Let matchingScope be the result of parsing matchingScopeString. + matching_scope = DOMURL::parse(matching_scope_string); + // 2. Assert: matchingScope’s origin and clientURL’s origin are same origin. + VERIFY(matching_scope.value().origin().is_same_origin(client_url.origin())); + } + + // 9. Return the result of running Get Registration given storage key and matchingScope. + return get(storage_key, matching_scope); +} + void Registration::remove(StorageAPI::StorageKey const& key, URL::URL const& scope) { (void)s_registrations.remove({ key, scope.serialize(URL::ExcludeFragment::Yes).to_byte_string() }); @@ -104,13 +146,3 @@ ServiceWorkerRecord* Registration::newest_worker() const } } - -namespace AK { -template<> -struct Traits : public DefaultTraits { - static unsigned hash(Web::ServiceWorker::RegistrationKey const& key) - { - return pair_int_hash(Traits::hash(key.key), Traits::hash(key.serialized_scope_url)); - } -}; -} diff --git a/Libraries/LibWeb/ServiceWorker/Registration.h b/Libraries/LibWeb/ServiceWorker/Registration.h index 1b013fbe9c0..55305e35095 100644 --- a/Libraries/LibWeb/ServiceWorker/Registration.h +++ b/Libraries/LibWeb/ServiceWorker/Registration.h @@ -31,6 +31,9 @@ public: // https://w3c.github.io/ServiceWorker/#set-registration-algorithm static Registration& set(StorageAPI::StorageKey const&, URL::URL const&, Bindings::ServiceWorkerUpdateViaCache); + // https://w3c.github.io/ServiceWorker/#scope-match-algorithm + static Optional match(StorageAPI::StorageKey const&, URL::URL const&); + static void remove(StorageAPI::StorageKey const&, URL::URL const&); bool is_unregistered(); @@ -42,6 +45,10 @@ public: void set_last_update_check_time(MonotonicTime time) { m_last_update_check_time = time; } ServiceWorkerRecord* newest_worker() const; + ServiceWorkerRecord* installing_worker() const { return m_installing_worker; } + ServiceWorkerRecord* waiting_worker() const { return m_waiting_worker; } + ServiceWorkerRecord* active_worker() const { return m_active_worker; } + bool is_stale() const; private: @@ -65,4 +72,22 @@ private: ByteString m_navigation_preload_header_value; // https://w3c.github.io/ServiceWorker/#service-worker-registration-navigation-preload-header-value }; +struct RegistrationKey { + StorageAPI::StorageKey key; + ByteString serialized_scope_url; + + bool operator==(RegistrationKey const&) const = default; +}; + +} + +namespace AK { +template<> +struct Traits : public DefaultTraits { + static unsigned hash(Web::ServiceWorker::RegistrationKey const& key) + { + return pair_int_hash(Traits::hash(key.key), Traits::hash(key.serialized_scope_url)); + } +}; + } diff --git a/Libraries/LibWeb/ServiceWorker/ServiceWorker.cpp b/Libraries/LibWeb/ServiceWorker/ServiceWorker.cpp index 6ccf9d8a2ba..a9e0ef8c8e8 100644 --- a/Libraries/LibWeb/ServiceWorker/ServiceWorker.cpp +++ b/Libraries/LibWeb/ServiceWorker/ServiceWorker.cpp @@ -12,17 +12,17 @@ namespace Web::ServiceWorker { -ServiceWorker::ServiceWorker(JS::Realm& realm, String script_url) +ServiceWorker::ServiceWorker(JS::Realm& realm, ServiceWorkerRecord* service_worker_record) : DOM::EventTarget(realm) - , m_script_url(move(script_url)) + , m_service_worker_record(service_worker_record) { } ServiceWorker::~ServiceWorker() = default; -GC::Ref ServiceWorker::create(JS::Realm& realm) +GC::Ref ServiceWorker::create(JS::Realm& realm, ServiceWorkerRecord* service_worker_record) { - return realm.create(realm, ""_string); + return realm.create(realm, service_worker_record); } void ServiceWorker::initialize(JS::Realm& realm) @@ -31,6 +31,15 @@ void ServiceWorker::initialize(JS::Realm& realm) WEB_SET_PROTOTYPE_FOR_INTERFACE(ServiceWorker); } +// https://w3c.github.io/ServiceWorker/#dom-serviceworker-scripturl +String ServiceWorker::script_url() const +{ + if (!m_service_worker_record) + return {}; + + return m_service_worker_record->script_url.serialize(); +} + #undef __ENUMERATE #define __ENUMERATE(attribute_name, event_name) \ void ServiceWorker::set_##attribute_name(WebIDL::CallbackType* value) \ diff --git a/Libraries/LibWeb/ServiceWorker/ServiceWorker.h b/Libraries/LibWeb/ServiceWorker/ServiceWorker.h index 39531f97594..1e27daaaed4 100644 --- a/Libraries/LibWeb/ServiceWorker/ServiceWorker.h +++ b/Libraries/LibWeb/ServiceWorker/ServiceWorker.h @@ -15,16 +15,18 @@ namespace Web::ServiceWorker { +// https://w3c.github.io/ServiceWorker/#serviceworker-interface class ServiceWorker : public DOM::EventTarget { WEB_PLATFORM_OBJECT(ServiceWorker, DOM::EventTarget); public: - [[nodiscard]] static GC::Ref create(JS::Realm& realm); + [[nodiscard]] static GC::Ref create(JS::Realm& realm, ServiceWorkerRecord*); virtual ~ServiceWorker() override; - String script_url() const { return m_script_url; } + String script_url() const; Bindings::ServiceWorkerState service_worker_state() const { return m_state; } + void set_service_worker_state(Bindings::ServiceWorkerState state) { m_state = state; } #undef __ENUMERATE #define __ENUMERATE(attribute_name, event_name) \ @@ -34,12 +36,12 @@ public: #undef __ENUMERATE private: - ServiceWorker(JS::Realm&, String script_url); + ServiceWorker(JS::Realm&, ServiceWorkerRecord*); virtual void initialize(JS::Realm&) override; - String m_script_url; Bindings::ServiceWorkerState m_state { Bindings::ServiceWorkerState::Parsed }; + ServiceWorkerRecord* m_service_worker_record; }; } diff --git a/Libraries/LibWeb/ServiceWorker/ServiceWorkerContainer.cpp b/Libraries/LibWeb/ServiceWorker/ServiceWorkerContainer.cpp index fa087bb1287..4550ab3483b 100644 --- a/Libraries/LibWeb/ServiceWorker/ServiceWorkerContainer.cpp +++ b/Libraries/LibWeb/ServiceWorker/ServiceWorkerContainer.cpp @@ -10,9 +10,13 @@ #include #include #include +#include +#include #include +#include #include #include +#include #include namespace Web::ServiceWorker { @@ -80,6 +84,61 @@ GC::Ref ServiceWorkerContainer::register_(String script_url, Re return p; } +// https://w3c.github.io/ServiceWorker/#navigator-service-worker-getRegistration +GC::Ref ServiceWorkerContainer::get_registration(String const& client_url) +{ + auto& realm = this->realm(); + + // 1. Let client be this's service worker client. + auto client = m_service_worker_client; + + // 2. Let storage key be the result of running obtain a storage key given client. + auto storage_key = StorageAPI::obtain_a_storage_key(client); + + // FIXME: Ad-Hoc. Spec should handle this failure. + if (!storage_key.has_value()) + return WebIDL::create_rejected_promise(realm, JS::TypeError::create(realm, "Failed to obtain a storage key"sv)); + + // 3. Let clientURL be the result of parsing clientURL with this's relevant settings object’s API base URL. + auto base_url = HTML::relevant_settings_object(*this).api_base_url(); + auto parsed_client_url = DOMURL::parse(client_url, base_url); + + // 4. If clientURL is failure, return a promise rejected with a TypeError. + if (!parsed_client_url.has_value()) + return WebIDL::create_rejected_promise(realm, JS::TypeError::create(realm, "clientURL is not a valid URL"sv)); + + // 5. Set clientURL’s fragment to null. + parsed_client_url->set_fragment({}); + + // 6. If the origin of clientURL is not client’s origin, return a promise rejected with a "SecurityError" DOMException. + if (!parsed_client_url->origin().is_same_origin(client->origin())) + return WebIDL::create_rejected_promise(realm, WebIDL::SecurityError::create(realm, "clientURL is not the same origin as the client's origin"_string)); + + // 7. Let promise be a new promise. + auto promise = WebIDL::create_promise(realm); + + // 8. Run the following substeps in parallel: + Platform::EventLoopPlugin::the().deferred_invoke(GC::create_function(realm.heap(), [promise, storage_key, parsed_client_url = *parsed_client_url]() { + auto& realm = HTML::relevant_realm(promise->promise()); + HTML::TemporaryExecutionContext const execution_context { realm, HTML::TemporaryExecutionContext::CallbacksEnabled::Yes }; + + // 1. Let registration be the result of running Match Service Worker Registration given storage key and clientURL. + auto maybe_registration = Registration::match(storage_key.value(), parsed_client_url); + + // 2. If registration is null, resolve promise with undefined and abort these steps. + if (!maybe_registration.has_value()) { + WebIDL::resolve_promise(realm, promise, JS::js_undefined()); + return; + } + + // 3. Resolve promise with the result of getting the service worker registration object that represents registration in promise’s relevant settings object. + auto registration_object = HTML::relevant_settings_object(promise->promise()).get_service_worker_registration_object(maybe_registration.value()); + WebIDL::resolve_promise(realm, promise, registration_object); + })); + + return promise; +} + // https://w3c.github.io/ServiceWorker/#start-register-algorithm void ServiceWorkerContainer::start_register(Optional scope_url, Optional script_url, GC::Ref promise, HTML::EnvironmentSettingsObject& client, URL::URL referrer, Bindings::WorkerType worker_type, Bindings::ServiceWorkerUpdateViaCache update_via_cache) { diff --git a/Libraries/LibWeb/ServiceWorker/ServiceWorkerContainer.h b/Libraries/LibWeb/ServiceWorker/ServiceWorkerContainer.h index 39dac835c58..ff204b2bee9 100644 --- a/Libraries/LibWeb/ServiceWorker/ServiceWorkerContainer.h +++ b/Libraries/LibWeb/ServiceWorker/ServiceWorkerContainer.h @@ -36,6 +36,8 @@ public: GC::Ref register_(String script_url, RegistrationOptions const& options); + GC::Ref get_registration(String const& client_url); + #undef __ENUMERATE #define __ENUMERATE(attribute_name, event_name) \ void set_##attribute_name(WebIDL::CallbackType*); \ diff --git a/Libraries/LibWeb/ServiceWorker/ServiceWorkerContainer.idl b/Libraries/LibWeb/ServiceWorker/ServiceWorkerContainer.idl index 9047dbb5c32..cb14114aa01 100644 --- a/Libraries/LibWeb/ServiceWorker/ServiceWorkerContainer.idl +++ b/Libraries/LibWeb/ServiceWorker/ServiceWorkerContainer.idl @@ -12,7 +12,7 @@ interface ServiceWorkerContainer : EventTarget { // FIXME: [NewObject] Promise register((TrustedScriptURL or USVString) scriptURL, optional RegistrationOptions options = {}); [NewObject, ImplementedAs=register_] Promise register(USVString scriptURL, optional RegistrationOptions options = {}); - [FIXME, NewObject] Promise<(ServiceWorkerRegistration or undefined)> getRegistration(optional USVString clientURL = ""); + [NewObject] Promise<(ServiceWorkerRegistration or undefined)> getRegistration(optional USVString clientURL = ""); [FIXME, NewObject] Promise> getRegistrations(); [FIXME] undefined startMessages(); diff --git a/Libraries/LibWeb/ServiceWorker/ServiceWorkerRegistration.cpp b/Libraries/LibWeb/ServiceWorker/ServiceWorkerRegistration.cpp index 607e05f9ceb..a761d076fe3 100644 --- a/Libraries/LibWeb/ServiceWorker/ServiceWorkerRegistration.cpp +++ b/Libraries/LibWeb/ServiceWorker/ServiceWorkerRegistration.cpp @@ -7,14 +7,16 @@ #include #include #include +#include #include namespace Web::ServiceWorker { GC_DEFINE_ALLOCATOR(ServiceWorkerRegistration); -ServiceWorkerRegistration::ServiceWorkerRegistration(JS::Realm& realm) +ServiceWorkerRegistration::ServiceWorkerRegistration(JS::Realm& realm, Registration const& registration) : DOM::EventTarget(realm) + , m_registration(registration) { } @@ -24,8 +26,16 @@ void ServiceWorkerRegistration::initialize(JS::Realm& realm) WEB_SET_PROTOTYPE_FOR_INTERFACE(ServiceWorkerRegistration); } -GC::Ref ServiceWorkerRegistration::create(JS::Realm& realm) +void ServiceWorkerRegistration::visit_edges(Cell::Visitor& visitor) { - return realm.create(realm); + Base::visit_edges(visitor); + visitor.visit(m_installing); + visitor.visit(m_waiting); + visitor.visit(m_active); +} + +GC::Ref ServiceWorkerRegistration::create(JS::Realm& realm, Registration const& registration) +{ + return realm.create(realm, registration); } } diff --git a/Libraries/LibWeb/ServiceWorker/ServiceWorkerRegistration.h b/Libraries/LibWeb/ServiceWorker/ServiceWorkerRegistration.h index e2b405126f4..0d79b833f68 100644 --- a/Libraries/LibWeb/ServiceWorker/ServiceWorkerRegistration.h +++ b/Libraries/LibWeb/ServiceWorker/ServiceWorkerRegistration.h @@ -10,17 +10,42 @@ namespace Web::ServiceWorker { +// https://w3c.github.io/ServiceWorker/#serviceworkerregistration-interface class ServiceWorkerRegistration : public DOM::EventTarget { WEB_PLATFORM_OBJECT(ServiceWorkerRegistration, DOM::EventTarget); GC_DECLARE_ALLOCATOR(ServiceWorkerRegistration); public: - [[nodiscard]] static GC::Ref create(JS::Realm& realm); + [[nodiscard]] static GC::Ref create(JS::Realm& realm, Registration const& registration); - explicit ServiceWorkerRegistration(JS::Realm&); + Registration const& registration() { return m_registration; } + + GC::Ptr installing() const { return m_installing; } + void set_installing(GC::Ptr installing) { m_installing = installing; } + + GC::Ptr waiting() const { return m_waiting; } + void set_waiting(GC::Ptr waiting) { m_waiting = waiting; } + + GC::Ptr active() const { return m_active; } + void set_active(GC::Ptr active) { m_active = active; } + + // https://w3c.github.io/ServiceWorker/#dom-serviceworkerregistration-scope + String scope() const { return m_registration.scope_url().serialize(); } + + // https://w3c.github.io/ServiceWorker/#dom-serviceworkerregistration-updateviacache + Bindings::ServiceWorkerUpdateViaCache update_via_cache() const { return m_registration.update_via_cache(); } + + explicit ServiceWorkerRegistration(JS::Realm&, Registration const&); virtual ~ServiceWorkerRegistration() override = default; +private: virtual void initialize(JS::Realm&) override; + virtual void visit_edges(JS::Cell::Visitor&) override; + + Registration const& m_registration; + GC::Ptr m_installing; + GC::Ptr m_waiting; + GC::Ptr m_active; }; } diff --git a/Libraries/LibWeb/ServiceWorker/ServiceWorkerRegistration.idl b/Libraries/LibWeb/ServiceWorker/ServiceWorkerRegistration.idl index 9c7785305c3..eec52d8d057 100644 --- a/Libraries/LibWeb/ServiceWorker/ServiceWorkerRegistration.idl +++ b/Libraries/LibWeb/ServiceWorker/ServiceWorkerRegistration.idl @@ -5,13 +5,13 @@ // https://w3c.github.io/ServiceWorker/#serviceworkerregistration-interface [SecureContext, Exposed=(Window,Worker)] interface ServiceWorkerRegistration : EventTarget { - [FIXME] readonly attribute ServiceWorker? installing; - [FIXME] readonly attribute ServiceWorker? waiting; - [FIXME] readonly attribute ServiceWorker? active; + readonly attribute ServiceWorker? installing; + readonly attribute ServiceWorker? waiting; + readonly attribute ServiceWorker? active; [FIXME, SameObject] readonly attribute NavigationPreloadManager navigationPreload; - [FIXME] readonly attribute USVString scope; - [FIXME] readonly attribute ServiceWorkerUpdateViaCache updateViaCache; + readonly attribute USVString scope; + readonly attribute ServiceWorkerUpdateViaCache updateViaCache; [FIXME, NewObject] Promise update(); [FIXME, NewObject] Promise unregister();