From f724f542edfe29a9563fef133cf9b05b2b1859d1 Mon Sep 17 00:00:00 2001 From: Idan Horowitz Date: Wed, 6 Aug 2025 12:04:18 +0300 Subject: [PATCH] LibWeb: Implement CookieStore::set(options) --- Libraries/LibWeb/CookieStore/CookieStore.cpp | 44 ++++++++++++++++++++ Libraries/LibWeb/CookieStore/CookieStore.h | 13 ++++++ Libraries/LibWeb/CookieStore/CookieStore.idl | 11 +++++ 3 files changed, 68 insertions(+) diff --git a/Libraries/LibWeb/CookieStore/CookieStore.cpp b/Libraries/LibWeb/CookieStore/CookieStore.cpp index 0188e393555..8f1f942673d 100644 --- a/Libraries/LibWeb/CookieStore/CookieStore.cpp +++ b/Libraries/LibWeb/CookieStore/CookieStore.cpp @@ -522,4 +522,48 @@ GC::Ref CookieStore::set(String name, String value) return promise; } +// https://cookiestore.spec.whatwg.org/#dom-cookiestore-set-options +GC::Ref CookieStore::set(CookieInit const& options) +{ + auto& realm = this->realm(); + + // 1. Let settings be this’s relevant settings object. + auto const& settings = HTML::relevant_settings_object(*this); + + // 2. Let origin be settings’s origin. + auto const& origin = settings.origin(); + + // 3. If origin is an opaque origin, then return a promise rejected with a "SecurityError" DOMException. + if (origin.is_opaque()) + return WebIDL::create_rejected_promise(realm, WebIDL::SecurityError::create(realm, "Document origin is opaque"_string)); + + // 4. Let url be settings’s creation URL. + auto url = settings.creation_url; + + // 5. Let p be a new promise. + auto promise = WebIDL::create_promise(realm); + + // 6. Run the following steps in parallel: + Platform::EventLoopPlugin::the().deferred_invoke(GC::create_function(realm.heap(), [&realm, client = m_client, promise, url = move(url), options = options]() { + // 1. Let r be the result of running set a cookie with url, options["name"], options["value"], options["expires"], + // options["domain"], options["path"], options["sameSite"], and options["partitioned"]. + auto result = set_a_cookie(client, url, options.name, options.value, options.expires, options.domain, options.path, options.same_site, options.partitioned); + + // AD-HOC: Queue a global task to perform the next steps + // Spec issue: https://github.com/whatwg/cookiestore/issues/239 + queue_global_task(HTML::Task::Source::Unspecified, realm.global_object(), GC::create_function(realm.heap(), [&realm, promise, result]() { + HTML::TemporaryExecutionContext execution_context { realm }; + // 2. If r is failure, then reject p with a TypeError and abort these steps. + if (!result) + return WebIDL::reject_promise(realm, promise, JS::TypeError::create(realm, "Name, value, domain or path are malformed"sv)); + + // 3. Resolve p with undefined. + WebIDL::resolve_promise(realm, promise); + })); + })); + + // 7. Return p. + return promise; +} + } diff --git a/Libraries/LibWeb/CookieStore/CookieStore.h b/Libraries/LibWeb/CookieStore/CookieStore.h index e0e47c3042f..2c0da9f930c 100644 --- a/Libraries/LibWeb/CookieStore/CookieStore.h +++ b/Libraries/LibWeb/CookieStore/CookieStore.h @@ -10,6 +10,7 @@ #include #include #include +#include namespace Web::CookieStore { @@ -25,6 +26,17 @@ struct CookieStoreGetOptions { Optional url; }; +// https://cookiestore.spec.whatwg.org/#dictdef-cookieinit +struct CookieInit { + String name; + String value; + Optional expires; + Optional domain; + String path; + Bindings::CookieSameSite same_site; + bool partitioned { false }; +}; + // https://cookiestore.spec.whatwg.org/#cookiestore class CookieStore final : public DOM::EventTarget { WEB_PLATFORM_OBJECT(CookieStore, DOM::EventTarget); @@ -38,6 +50,7 @@ public: GC::Ref get_all(CookieStoreGetOptions const&); GC::Ref set(String name, String value); + GC::Ref set(CookieInit const&); private: CookieStore(JS::Realm&, PageClient&); diff --git a/Libraries/LibWeb/CookieStore/CookieStore.idl b/Libraries/LibWeb/CookieStore/CookieStore.idl index c0c59cdd301..56c72fcb416 100644 --- a/Libraries/LibWeb/CookieStore/CookieStore.idl +++ b/Libraries/LibWeb/CookieStore/CookieStore.idl @@ -22,6 +22,16 @@ enum CookieSameSite { "none" }; +dictionary CookieInit { + required USVString name; + required USVString value; + DOMHighResTimeStamp? expires = null; + USVString? domain = null; + USVString path = "/"; + CookieSameSite sameSite = "strict"; + boolean partitioned = false; +}; + // https://cookiestore.spec.whatwg.org/#cookiestore [Exposed=(ServiceWorker,Window), SecureContext] interface CookieStore : EventTarget { @@ -32,6 +42,7 @@ interface CookieStore : EventTarget { Promise getAll(optional CookieStoreGetOptions options = {}); Promise set(USVString name, USVString value); + Promise set(CookieInit options); }; // https://cookiestore.spec.whatwg.org/#Window