diff --git a/Tests/LibWeb/Text/expected/cookie.txt b/Tests/LibWeb/Text/expected/cookie.txt index bfd83b6c895..fe59ec60691 100644 --- a/Tests/LibWeb/Text/expected/cookie.txt +++ b/Tests/LibWeb/Text/expected/cookie.txt @@ -1,3 +1,4 @@ +Cookie averse test: "" Basic test: "cookie=value" Multiple cookies: "cookie1=value1; cookie2=value2; cookie3=value3" Nameless cookie: "value" diff --git a/Tests/LibWeb/Text/input/cookie.html b/Tests/LibWeb/Text/input/cookie.html index cd439f213d8..2d4cc511778 100644 --- a/Tests/LibWeb/Text/input/cookie.html +++ b/Tests/LibWeb/Text/input/cookie.html @@ -12,6 +12,11 @@ document.cookie = `${name}=""; max-age=-9999`; }; + const cookieAverseTest = () => { + document.cookie = "cookie=value"; + printCookies("Cookie averse test"); + }; + const basicTest = () => { document.cookie = "cookie=value"; printCookies("Basic test"); @@ -178,6 +183,10 @@ }; test(() => { + cookieAverseTest(); + + internals.enableCookiesOnFileDomains(); + basicTest(); multipleCookiesTest(); diff --git a/Userland/Libraries/LibWeb/DOM/Document.cpp b/Userland/Libraries/LibWeb/DOM/Document.cpp index fd7400a1441..8c8cf6cb55e 100644 --- a/Userland/Libraries/LibWeb/DOM/Document.cpp +++ b/Userland/Libraries/LibWeb/DOM/Document.cpp @@ -2492,18 +2492,58 @@ void Document::completely_finish_loading() } } -String Document::cookie(Cookie::Source source) +// https://html.spec.whatwg.org/#dom-document-cookie +WebIDL::ExceptionOr Document::cookie(Cookie::Source source) { + // On getting, if the document is a cookie-averse Document object, then the user agent must return the empty string. + if (is_cookie_averse()) + return String {}; + + // Otherwise, if the Document's origin is an opaque origin, the user agent must throw a "SecurityError" DOMException. + if (origin().is_opaque()) + return WebIDL::SecurityError::create(realm(), "Document origin is opaque"_string); + + // Otherwise, the user agent must return the cookie-string for the document's URL for a "non-HTTP" API, decoded using + // UTF-8 decode without BOM. return page().client().page_did_request_cookie(m_url, source); } -void Document::set_cookie(StringView cookie_string, Cookie::Source source) +// https://html.spec.whatwg.org/#dom-document-cookie +WebIDL::ExceptionOr Document::set_cookie(StringView cookie_string, Cookie::Source source) { - auto cookie = Cookie::parse_cookie(url(), cookie_string); - if (!cookie.has_value()) - return; + // On setting, if the document is a cookie-averse Document object, then the user agent must do nothing. + if (is_cookie_averse()) + return {}; - page().client().page_did_set_cookie(m_url, cookie.value(), source); + // Otherwise, if the Document's origin is an opaque origin, the user agent must throw a "SecurityError" DOMException. + if (origin().is_opaque()) + return WebIDL::SecurityError::create(realm(), "Document origin is opaque"_string); + + // Otherwise, the user agent must act as it would when receiving a set-cookie-string for the document's URL via a + // "non-HTTP" API, consisting of the new value encoded as UTF-8. + if (auto cookie = Cookie::parse_cookie(url(), cookie_string); cookie.has_value()) + page().client().page_did_set_cookie(m_url, cookie.value(), source); + + return {}; +} + +// https://html.spec.whatwg.org/#cookie-averse-document-object +bool Document::is_cookie_averse() const +{ + // A Document object that falls into one of the following conditions is a cookie-averse Document object: + + // * A Document object whose browsing context is null. + if (!browsing_context()) + return true; + + // * A Document whose URL's scheme is not an HTTP(S) scheme. + if (!url().scheme().is_one_of("http"sv, "https"sv)) { + // AD-HOC: This allows us to write cookie integration tests. + if (!m_enable_cookies_on_file_domains || url().scheme() != "file"sv) + return true; + } + + return false; } String Document::fg_color() const diff --git a/Userland/Libraries/LibWeb/DOM/Document.h b/Userland/Libraries/LibWeb/DOM/Document.h index 19dedc61103..8ed42f85e81 100644 --- a/Userland/Libraries/LibWeb/DOM/Document.h +++ b/Userland/Libraries/LibWeb/DOM/Document.h @@ -116,8 +116,10 @@ public: JS::GCPtr get_selection() const; - String cookie(Cookie::Source = Cookie::Source::NonHttp); - void set_cookie(StringView, Cookie::Source = Cookie::Source::NonHttp); + WebIDL::ExceptionOr cookie(Cookie::Source = Cookie::Source::NonHttp); + WebIDL::ExceptionOr set_cookie(StringView, Cookie::Source = Cookie::Source::NonHttp); + bool is_cookie_averse() const; + void enable_cookies_on_file_domains(Badge) { m_enable_cookies_on_file_domains = true; } String fg_color() const; void set_fg_color(String const&); @@ -1020,6 +1022,8 @@ private: bool m_needs_repaint { false }; + bool m_enable_cookies_on_file_domains { false }; + Optional m_cached_display_list_paint_config; RefPtr m_cached_display_list; diff --git a/Userland/Libraries/LibWeb/Internals/Internals.cpp b/Userland/Libraries/LibWeb/Internals/Internals.cpp index 4eb9558e67c..9b6f682d0e8 100644 --- a/Userland/Libraries/LibWeb/Internals/Internals.cpp +++ b/Userland/Libraries/LibWeb/Internals/Internals.cpp @@ -183,6 +183,11 @@ void Internals::simulate_drop(double x, double y) page.handle_drag_and_drop_event(DragEvent::Type::Drop, position, position, UIEvents::MouseButton::Primary, 0, 0, {}); } +void Internals::enable_cookies_on_file_domains() +{ + internals_window().associated_document().enable_cookies_on_file_domains({}); +} + void Internals::expire_cookies_with_time_offset(WebIDL::LongLong seconds) { internals_page().client().page_did_expire_cookies_with_time_offset(AK::Duration::from_seconds(seconds)); diff --git a/Userland/Libraries/LibWeb/Internals/Internals.h b/Userland/Libraries/LibWeb/Internals/Internals.h index 69336c8d0fd..83e155f9802 100644 --- a/Userland/Libraries/LibWeb/Internals/Internals.h +++ b/Userland/Libraries/LibWeb/Internals/Internals.h @@ -44,6 +44,7 @@ public: void simulate_drag_move(double x, double y); void simulate_drop(double x, double y); + void enable_cookies_on_file_domains(); void expire_cookies_with_time_offset(WebIDL::LongLong seconds); private: diff --git a/Userland/Libraries/LibWeb/Internals/Internals.idl b/Userland/Libraries/LibWeb/Internals/Internals.idl index d6b2c14327e..ee26ff48c5c 100644 --- a/Userland/Libraries/LibWeb/Internals/Internals.idl +++ b/Userland/Libraries/LibWeb/Internals/Internals.idl @@ -34,5 +34,6 @@ interface Internals { undefined simulateDragMove(double x, double y); undefined simulateDrop(double x, double y); + undefined enableCookiesOnFileDomains(); undefined expireCookiesWithTimeOffset(long long seconds); };