mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-08-27 20:58:16 +00:00
LibWeb: Implement CookieStore::get(name)
This commit is contained in:
parent
dc1b7b1925
commit
5545d38d7a
Notes:
github-actions[bot]
2025-08-08 17:12:25 +00:00
Author: https://github.com/IdanHo
Commit: 5545d38d7a
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/5766
Reviewed-by: https://github.com/trflynn89 ✅
14 changed files with 174 additions and 17 deletions
|
@ -7,13 +7,20 @@
|
|||
#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)
|
||||
CookieStore::CookieStore(JS::Realm& realm, PageClient& client)
|
||||
: DOM::EventTarget(realm)
|
||||
, m_client(client)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -23,4 +30,103 @@ void CookieStore::initialize(JS::Realm& realm)
|
|||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -6,19 +6,40 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <AK/Optional.h>
|
||||
#include <AK/String.h>
|
||||
#include <LibWeb/Bindings/CookieStorePrototype.h>
|
||||
#include <LibWeb/DOM/EventTarget.h>
|
||||
|
||||
namespace Web::CookieStore {
|
||||
|
||||
// https://cookiestore.spec.whatwg.org/#dictdef-cookielistitem
|
||||
struct CookieListItem {
|
||||
Optional<String> name;
|
||||
Optional<String> value;
|
||||
};
|
||||
|
||||
// https://cookiestore.spec.whatwg.org/#cookiestore
|
||||
class CookieStore final : public DOM::EventTarget {
|
||||
WEB_PLATFORM_OBJECT(CookieStore, DOM::EventTarget);
|
||||
GC_DECLARE_ALLOCATOR(CookieStore);
|
||||
|
||||
public:
|
||||
GC::Ref<WebIDL::Promise> get(String name);
|
||||
|
||||
private:
|
||||
CookieStore(JS::Realm&);
|
||||
CookieStore(JS::Realm&, PageClient&);
|
||||
|
||||
virtual void initialize(JS::Realm&) override;
|
||||
virtual void visit_edges(Cell::Visitor&) override;
|
||||
|
||||
GC::Ref<PageClient> m_client;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
namespace Web::Bindings {
|
||||
|
||||
JS::Value cookie_list_item_to_value(JS::Realm&, CookieStore::CookieListItem const&);
|
||||
|
||||
}
|
||||
|
|
|
@ -3,10 +3,16 @@
|
|||
#import <HTML/Window.idl>
|
||||
#import <ServiceWorker/ServiceWorkerGlobalScope.idl>
|
||||
|
||||
[GenerateToValue]
|
||||
dictionary CookieListItem {
|
||||
USVString name;
|
||||
USVString value;
|
||||
};
|
||||
|
||||
// https://cookiestore.spec.whatwg.org/#cookiestore
|
||||
[Exposed=(ServiceWorker,Window), SecureContext]
|
||||
interface CookieStore : EventTarget {
|
||||
|
||||
Promise<CookieListItem?> get(USVString name);
|
||||
};
|
||||
|
||||
// https://cookiestore.spec.whatwg.org/#Window
|
||||
|
|
|
@ -1130,7 +1130,7 @@ GC::Ref<CookieStore::CookieStore> Window::cookie_store()
|
|||
|
||||
// The cookieStore getter steps are to return this’s associated CookieStore.
|
||||
if (!m_cookie_store)
|
||||
m_cookie_store = realm.create<CookieStore::CookieStore>(realm);
|
||||
m_cookie_store = realm.create<CookieStore::CookieStore>(realm, page().client());
|
||||
return *m_cookie_store;
|
||||
}
|
||||
|
||||
|
|
|
@ -352,7 +352,8 @@ public:
|
|||
virtual void page_did_request_set_prompt_text(String const&) { }
|
||||
virtual void page_did_request_accept_dialog() { }
|
||||
virtual void page_did_request_dismiss_dialog() { }
|
||||
virtual Vector<Web::Cookie::Cookie> page_did_request_all_cookies(URL::URL const&) { return {}; }
|
||||
virtual Vector<Web::Cookie::Cookie> page_did_request_all_cookies_webdriver(URL::URL const&) { return {}; }
|
||||
virtual Vector<Web::Cookie::Cookie> page_did_request_all_cookies_cookiestore(URL::URL const&) { return {}; }
|
||||
virtual Optional<Web::Cookie::Cookie> page_did_request_named_cookie(URL::URL const&, String const&) { return {}; }
|
||||
virtual String page_did_request_cookie(URL::URL const&, Cookie::Source) { return {}; }
|
||||
virtual void page_did_set_cookie(URL::URL const&, Cookie::ParsedCookie const&, Cookie::Source) { }
|
||||
|
|
|
@ -93,7 +93,7 @@ GC::Ref<CookieStore::CookieStore> ServiceWorkerGlobalScope::cookie_store()
|
|||
|
||||
// The cookieStore getter steps are to return this’s associated CookieStore.
|
||||
if (!m_cookie_store)
|
||||
m_cookie_store = realm.create<CookieStore::CookieStore>(realm);
|
||||
m_cookie_store = realm.create<CookieStore::CookieStore>(realm, page()->client());
|
||||
return *m_cookie_store;
|
||||
}
|
||||
|
||||
|
|
|
@ -192,7 +192,7 @@ Vector<Web::Cookie::Cookie> CookieJar::get_all_cookies()
|
|||
}
|
||||
|
||||
// https://w3c.github.io/webdriver/#dfn-associated-cookies
|
||||
Vector<Web::Cookie::Cookie> CookieJar::get_all_cookies(URL::URL const& url)
|
||||
Vector<Web::Cookie::Cookie> CookieJar::get_all_cookies_webdriver(URL::URL const& url)
|
||||
{
|
||||
auto domain = canonicalize_domain(url);
|
||||
if (!domain.has_value())
|
||||
|
@ -201,6 +201,15 @@ Vector<Web::Cookie::Cookie> CookieJar::get_all_cookies(URL::URL const& url)
|
|||
return get_matching_cookies(url, domain.value(), Web::Cookie::Source::Http, MatchingCookiesSpecMode::WebDriver);
|
||||
}
|
||||
|
||||
Vector<Web::Cookie::Cookie> CookieJar::get_all_cookies_cookiestore(URL::URL const& url)
|
||||
{
|
||||
auto domain = canonicalize_domain(url);
|
||||
if (!domain.has_value())
|
||||
return {};
|
||||
|
||||
return get_matching_cookies(url, domain.value(), Web::Cookie::Source::NonHttp, MatchingCookiesSpecMode::RFC6265);
|
||||
}
|
||||
|
||||
Optional<Web::Cookie::Cookie> CookieJar::get_named_cookie(URL::URL const& url, StringView name)
|
||||
{
|
||||
auto domain = canonicalize_domain(url);
|
||||
|
|
|
@ -93,7 +93,8 @@ public:
|
|||
void dump_cookies();
|
||||
void clear_all_cookies();
|
||||
Vector<Web::Cookie::Cookie> get_all_cookies();
|
||||
Vector<Web::Cookie::Cookie> get_all_cookies(URL::URL const& url);
|
||||
Vector<Web::Cookie::Cookie> get_all_cookies_webdriver(URL::URL const& url);
|
||||
Vector<Web::Cookie::Cookie> get_all_cookies_cookiestore(URL::URL const& url);
|
||||
Optional<Web::Cookie::Cookie> get_named_cookie(URL::URL const& url, StringView name);
|
||||
void expire_cookies_with_time_offset(AK::Duration);
|
||||
|
||||
|
|
|
@ -485,9 +485,14 @@ void WebContentClient::did_change_favicon(u64 page_id, Gfx::ShareableBitmap favi
|
|||
}
|
||||
}
|
||||
|
||||
Messages::WebContentClient::DidRequestAllCookiesResponse WebContentClient::did_request_all_cookies(URL::URL url)
|
||||
Messages::WebContentClient::DidRequestAllCookiesWebdriverResponse WebContentClient::did_request_all_cookies_webdriver(URL::URL url)
|
||||
{
|
||||
return Application::cookie_jar().get_all_cookies(url);
|
||||
return Application::cookie_jar().get_all_cookies_webdriver(url);
|
||||
}
|
||||
|
||||
Messages::WebContentClient::DidRequestAllCookiesCookiestoreResponse WebContentClient::did_request_all_cookies_cookiestore(URL::URL url)
|
||||
{
|
||||
return Application::cookie_jar().get_all_cookies_cookiestore(url);
|
||||
}
|
||||
|
||||
Messages::WebContentClient::DidRequestNamedCookieResponse WebContentClient::did_request_named_cookie(URL::URL url, String name)
|
||||
|
|
|
@ -101,7 +101,8 @@ private:
|
|||
virtual void did_request_set_prompt_text(u64 page_id, String message) override;
|
||||
virtual void did_request_accept_dialog(u64 page_id) override;
|
||||
virtual void did_request_dismiss_dialog(u64 page_id) override;
|
||||
virtual Messages::WebContentClient::DidRequestAllCookiesResponse did_request_all_cookies(URL::URL) override;
|
||||
virtual Messages::WebContentClient::DidRequestAllCookiesWebdriverResponse did_request_all_cookies_webdriver(URL::URL) override;
|
||||
virtual Messages::WebContentClient::DidRequestAllCookiesCookiestoreResponse did_request_all_cookies_cookiestore(URL::URL) override;
|
||||
virtual Messages::WebContentClient::DidRequestNamedCookieResponse did_request_named_cookie(URL::URL, String) override;
|
||||
virtual Messages::WebContentClient::DidRequestCookieResponse did_request_cookie(URL::URL, Web::Cookie::Source) override;
|
||||
virtual void did_set_cookie(URL::URL, Web::Cookie::ParsedCookie, Web::Cookie::Source) override;
|
||||
|
|
|
@ -482,9 +482,14 @@ void PageClient::page_did_change_favicon(Gfx::Bitmap const& favicon)
|
|||
client().async_did_change_favicon(m_id, favicon.to_shareable_bitmap());
|
||||
}
|
||||
|
||||
Vector<Web::Cookie::Cookie> PageClient::page_did_request_all_cookies(URL::URL const& url)
|
||||
Vector<Web::Cookie::Cookie> PageClient::page_did_request_all_cookies_webdriver(URL::URL const& url)
|
||||
{
|
||||
return client().did_request_all_cookies(url);
|
||||
return client().did_request_all_cookies_webdriver(url);
|
||||
}
|
||||
|
||||
Vector<Web::Cookie::Cookie> PageClient::page_did_request_all_cookies_cookiestore(URL::URL const& url)
|
||||
{
|
||||
return client().did_request_all_cookies_cookiestore(url);
|
||||
}
|
||||
|
||||
Optional<Web::Cookie::Cookie> PageClient::page_did_request_named_cookie(URL::URL const& url, String const& name)
|
||||
|
|
|
@ -143,7 +143,8 @@ private:
|
|||
virtual void page_did_request_accept_dialog() override;
|
||||
virtual void page_did_request_dismiss_dialog() override;
|
||||
virtual void page_did_change_favicon(Gfx::Bitmap const&) override;
|
||||
virtual Vector<Web::Cookie::Cookie> page_did_request_all_cookies(URL::URL const&) override;
|
||||
virtual Vector<Web::Cookie::Cookie> page_did_request_all_cookies_webdriver(URL::URL const&) override;
|
||||
virtual Vector<Web::Cookie::Cookie> page_did_request_all_cookies_cookiestore(URL::URL const&) override;
|
||||
virtual Optional<Web::Cookie::Cookie> page_did_request_named_cookie(URL::URL const&, String const&) override;
|
||||
virtual String page_did_request_cookie(URL::URL const&, Web::Cookie::Source) override;
|
||||
virtual void page_did_set_cookie(URL::URL const&, Web::Cookie::ParsedCookie const&, Web::Cookie::Source) override;
|
||||
|
|
|
@ -72,7 +72,8 @@ endpoint WebContentClient
|
|||
did_get_internal_page_info(u64 page_id, WebView::PageInfoType type, String info) =|
|
||||
|
||||
did_change_favicon(u64 page_id, Gfx::ShareableBitmap favicon) =|
|
||||
did_request_all_cookies(URL::URL url) => (Vector<Web::Cookie::Cookie> cookies)
|
||||
did_request_all_cookies_webdriver(URL::URL url) => (Vector<Web::Cookie::Cookie> cookies)
|
||||
did_request_all_cookies_cookiestore(URL::URL url) => (Vector<Web::Cookie::Cookie> cookies)
|
||||
did_request_named_cookie(URL::URL url, String name) => (Optional<Web::Cookie::Cookie> cookie)
|
||||
did_request_cookie(URL::URL url, Web::Cookie::Source source) => (String cookie)
|
||||
did_set_cookie(URL::URL url, Web::Cookie::ParsedCookie cookie, Web::Cookie::Source source) => ()
|
||||
|
|
|
@ -2148,7 +2148,7 @@ Messages::WebDriverClient::GetAllCookiesResponse WebDriverConnection::get_all_co
|
|||
// 4. For each cookie in all associated cookies of the current browsing context’s active document:
|
||||
auto* document = current_browsing_context().active_document();
|
||||
|
||||
for (auto const& cookie : current_browsing_context().page().client().page_did_request_all_cookies(document->url())) {
|
||||
for (auto const& cookie : current_browsing_context().page().client().page_did_request_all_cookies_webdriver(document->url())) {
|
||||
// 1. Let serialized cookie be the result of serializing cookie.
|
||||
auto serialized_cookie = serialize_cookie(cookie);
|
||||
|
||||
|
@ -3070,7 +3070,7 @@ void WebDriverConnection::delete_cookies(Optional<StringView> const& name)
|
|||
// For each cookie among all associated cookies of the current browsing context’s active document, un the substeps of the first matching condition:
|
||||
auto* document = current_browsing_context().active_document();
|
||||
|
||||
for (auto& cookie : current_browsing_context().page().client().page_did_request_all_cookies(document->url())) {
|
||||
for (auto& cookie : current_browsing_context().page().client().page_did_request_all_cookies_webdriver(document->url())) {
|
||||
// -> name is undefined
|
||||
// -> name is equal to cookie name
|
||||
if (!name.has_value() || name.value() == cookie.name) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue