mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-10-22 16:09:23 +00:00
132 lines
4.8 KiB
C++
132 lines
4.8 KiB
C++
/*
|
||
* Copyright (c) 2025, Idan Horowitz <idan.horowitz@serenityos.org>
|
||
*
|
||
* SPDX-License-Identifier: BSD-2-Clause
|
||
*/
|
||
|
||
#include <LibWeb/Bindings/CookieStorePrototype.h>
|
||
#include <LibWeb/Bindings/Intrinsics.h>
|
||
#include <LibWeb/CookieStore/CookieStore.h>
|
||
#include <LibWeb/HTML/Scripting/Environments.h>
|
||
#include <LibWeb/HTML/Scripting/TemporaryExecutionContext.h>
|
||
#include <LibWeb/Page/Page.h>
|
||
#include <LibWeb/Platform/EventLoopPlugin.h>
|
||
#include <LibWeb/WebIDL/DOMException.h>
|
||
#include <LibWeb/WebIDL/Promise.h>
|
||
|
||
namespace Web::CookieStore {
|
||
|
||
GC_DEFINE_ALLOCATOR(CookieStore);
|
||
|
||
CookieStore::CookieStore(JS::Realm& realm, PageClient& client)
|
||
: DOM::EventTarget(realm)
|
||
, m_client(client)
|
||
{
|
||
}
|
||
|
||
void CookieStore::initialize(JS::Realm& realm)
|
||
{
|
||
WEB_SET_PROTOTYPE_FOR_INTERFACE(CookieStore);
|
||
Base::initialize(realm);
|
||
}
|
||
|
||
void CookieStore::visit_edges(Cell::Visitor& visitor)
|
||
{
|
||
Base::visit_edges(visitor);
|
||
|
||
visitor.visit(m_client);
|
||
}
|
||
|
||
// https://cookiestore.spec.whatwg.org/#create-a-cookielistitem
|
||
static CookieListItem create_a_cookie_list_item(Cookie::Cookie const& cookie)
|
||
{
|
||
// 1. Let name be the result of running UTF-8 decode without BOM on cookie’s name.
|
||
// 2. Let value be the result of running UTF-8 decode without BOM on cookie’s value.
|
||
// 3. Return «[ "name" → name, "value" → value ]»
|
||
return CookieListItem {
|
||
.name = cookie.name,
|
||
.value = cookie.value,
|
||
};
|
||
}
|
||
|
||
// https://cookiestore.spec.whatwg.org/#query-cookies
|
||
static Vector<CookieListItem> query_cookies(PageClient& client, URL::URL const& url, Optional<String> const& name)
|
||
{
|
||
// 1. Perform the steps defined in Cookies § Retrieval Model to compute the "cookie-string from a given cookie store"
|
||
// with url as request-uri. The cookie-string itself is ignored, but the intermediate cookie-list is used in subsequent steps.
|
||
// For the purposes of the steps, the cookie-string is being generated for a "non-HTTP" API.
|
||
auto cookie_list = client.page_did_request_all_cookies_cookiestore(url);
|
||
|
||
// 2. Let list be a new list.
|
||
Vector<CookieListItem> list;
|
||
|
||
// 3. For each cookie in cookie-list, run these steps:
|
||
for (auto const& cookie : cookie_list) {
|
||
// 1. Assert: cookie’s http-only-flag is false.
|
||
VERIFY(!cookie.http_only);
|
||
|
||
// 2. If name is given, then run these steps:
|
||
if (name.has_value()) {
|
||
// 1. Let cookieName be the result of running UTF-8 decode without BOM on cookie’s name.
|
||
// 2. If cookieName does not equal name, then continue.
|
||
if (cookie.name != name.value())
|
||
continue;
|
||
}
|
||
// 3. Let item be the result of running create a CookieListItem from cookie.
|
||
auto item = create_a_cookie_list_item(cookie);
|
||
|
||
// 4. Append item to list.
|
||
list.append(move(item));
|
||
}
|
||
|
||
// 4. Return list.
|
||
return list;
|
||
}
|
||
|
||
// https://cookiestore.spec.whatwg.org/#dom-cookiestore-get
|
||
GC::Ref<WebIDL::Promise> CookieStore::get(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 list be the results of running query cookies with url and name.
|
||
auto list = query_cookies(client, url, name);
|
||
|
||
// 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, list = move(list)]() {
|
||
HTML::TemporaryExecutionContext execution_context { realm };
|
||
// 2. If list is failure, then reject p with a TypeError and abort these steps.
|
||
|
||
// 3. If list is empty, then resolve p with null.
|
||
if (list.is_empty())
|
||
WebIDL::resolve_promise(realm, promise, JS::js_null());
|
||
|
||
// 4. Otherwise, resolve p with the first item of list.
|
||
else
|
||
WebIDL::resolve_promise(realm, promise, Bindings::cookie_list_item_to_value(realm, list[0]));
|
||
}));
|
||
}));
|
||
|
||
// 7. Return p.
|
||
return promise;
|
||
}
|
||
|
||
}
|