diff --git a/Libraries/LibWeb/CookieStore/CookieStore.cpp b/Libraries/LibWeb/CookieStore/CookieStore.cpp index 8f1f942673d..a0fc078fcf6 100644 --- a/Libraries/LibWeb/CookieStore/CookieStore.cpp +++ b/Libraries/LibWeb/CookieStore/CookieStore.cpp @@ -566,4 +566,65 @@ GC::Ref CookieStore::set(CookieInit const& options) return promise; } +// https://cookiestore.spec.whatwg.org/#delete-a-cookie +static bool delete_a_cookie(PageClient& client, URL::URL const& url, String name, Optional domain, Optional path, bool partitioned) +{ + // 1. Let expires be the earliest representable date represented as a timestamp. + // NOTE: The exact value of expires is not important for the purposes of this algorithm, as long as it is in the past. + HighResolutionTime::DOMHighResTimeStamp expires = UnixDateTime::earliest().milliseconds_since_epoch(); + + // 2. Let value be the empty string. + String value; + + // 3. If name’s length is 0, then set value to any non-empty implementation-defined string. + if (name.is_empty()) + value = "ladybird"_string; + + // 4. Return the results of running set a cookie with url, name, value, expires, domain, path, "strict", and partitioned. + return set_a_cookie(client, url, move(name), move(value), expires, move(domain), move(path), Bindings::CookieSameSite::Strict, partitioned); +} + +// https://cookiestore.spec.whatwg.org/#dom-cookiestore-delete +GC::Ref CookieStore::delete_(String name) +{ + 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), name = move(name)]() { + // 1. Let r be the result of running delete a cookie with url, name, null, "/", and true. + auto result = delete_a_cookie(client, url, move(name), {}, "/"_string, true); + + // 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 is 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 2c0da9f930c..67417cc4850 100644 --- a/Libraries/LibWeb/CookieStore/CookieStore.h +++ b/Libraries/LibWeb/CookieStore/CookieStore.h @@ -52,6 +52,8 @@ public: GC::Ref set(String name, String value); GC::Ref set(CookieInit const&); + GC::Ref delete_(String name); + private: CookieStore(JS::Realm&, PageClient&); diff --git a/Libraries/LibWeb/CookieStore/CookieStore.idl b/Libraries/LibWeb/CookieStore/CookieStore.idl index 56c72fcb416..4042e6a4810 100644 --- a/Libraries/LibWeb/CookieStore/CookieStore.idl +++ b/Libraries/LibWeb/CookieStore/CookieStore.idl @@ -43,6 +43,8 @@ interface CookieStore : EventTarget { Promise set(USVString name, USVString value); Promise set(CookieInit options); + + Promise delete(USVString name); }; // https://cookiestore.spec.whatwg.org/#Window