From cae0ab2139a26a7aafc1f5e34d60baaeaa956881 Mon Sep 17 00:00:00 2001 From: Luke Wilde Date: Mon, 25 Nov 2024 14:30:12 +0000 Subject: [PATCH] LibWeb: Make PolicyContainer GC allocated This is required to store Content Security Policies, as their Directives are implemented as subclasses with overridden virtual functions. Thus, they cannot be stored as generic Directive classes, as it'll lose the ability to call overridden functions when they are copied. --- Libraries/LibWeb/CMakeLists.txt | 2 + Libraries/LibWeb/DOM/Document.cpp | 55 ++++++++------- Libraries/LibWeb/DOM/Document.h | 8 +-- Libraries/LibWeb/DOM/DocumentLoading.h | 4 +- Libraries/LibWeb/Fetch/Fetching/Fetching.cpp | 8 +-- .../Fetch/Infrastructure/HTTP/Requests.cpp | 5 +- .../Fetch/Infrastructure/HTTP/Requests.h | 2 +- Libraries/LibWeb/Forward.h | 1 + Libraries/LibWeb/HTML/BrowsingContext.cpp | 2 +- Libraries/LibWeb/HTML/DocumentState.cpp | 3 + Libraries/LibWeb/HTML/DocumentState.h | 6 +- Libraries/LibWeb/HTML/EmbedderPolicy.cpp | 31 +++++++++ Libraries/LibWeb/HTML/EmbedderPolicy.h | 12 ++++ Libraries/LibWeb/HTML/HTMLLinkElement.cpp | 2 +- Libraries/LibWeb/HTML/HTMLLinkElement.h | 2 +- Libraries/LibWeb/HTML/Navigable.cpp | 67 +++++++++++-------- Libraries/LibWeb/HTML/Navigable.h | 2 +- Libraries/LibWeb/HTML/NavigationParams.cpp | 1 + Libraries/LibWeb/HTML/NavigationParams.h | 2 +- Libraries/LibWeb/HTML/PolicyContainers.cpp | 64 ++++++++++++++---- Libraries/LibWeb/HTML/PolicyContainers.h | 29 +++++--- .../Scripting/EnvironmentSettingsSnapshot.cpp | 10 ++- .../Scripting/EnvironmentSettingsSnapshot.h | 9 ++- .../LibWeb/HTML/Scripting/Environments.cpp | 4 +- .../LibWeb/HTML/Scripting/Environments.h | 4 +- .../SerializedEnvironmentSettingsObject.cpp | 2 +- .../SerializedEnvironmentSettingsObject.h | 4 +- .../WindowEnvironmentSettingsObject.cpp | 2 +- .../WindowEnvironmentSettingsObject.h | 2 +- .../WorkerEnvironmentSettingsObject.cpp | 2 +- .../WorkerEnvironmentSettingsObject.h | 2 +- .../LibWeb/HTML/SerializedPolicyContainer.cpp | 33 +++++++++ .../LibWeb/HTML/SerializedPolicyContainer.h | 29 ++++++++ Libraries/LibWeb/HTML/SessionHistoryEntry.cpp | 1 + Libraries/LibWeb/HTML/SessionHistoryEntry.h | 6 +- .../LibWeb/HTML/SourceSnapshotParams.cpp | 22 ++++++ Libraries/LibWeb/HTML/SourceSnapshotParams.h | 25 ++++++- .../LibWeb/HTML/TraversableNavigable.cpp | 20 +++--- Libraries/LibWeb/HTML/TraversableNavigable.h | 6 +- Libraries/LibWeb/HTML/WorkerGlobalScope.cpp | 11 +++ Libraries/LibWeb/HTML/WorkerGlobalScope.h | 5 +- Libraries/LibWeb/SVG/SVGDecodedImageData.cpp | 2 +- Services/WebWorker/DedicatedWorkerHost.cpp | 2 +- 43 files changed, 381 insertions(+), 130 deletions(-) create mode 100644 Libraries/LibWeb/HTML/SerializedPolicyContainer.cpp create mode 100644 Libraries/LibWeb/HTML/SerializedPolicyContainer.h create mode 100644 Libraries/LibWeb/HTML/SourceSnapshotParams.cpp diff --git a/Libraries/LibWeb/CMakeLists.txt b/Libraries/LibWeb/CMakeLists.txt index b169662a03c..2c1e7a8e035 100644 --- a/Libraries/LibWeb/CMakeLists.txt +++ b/Libraries/LibWeb/CMakeLists.txt @@ -485,11 +485,13 @@ set(SOURCES HTML/Scripting/SerializedEnvironmentSettingsObject.cpp HTML/SelectedFile.cpp HTML/SelectItem.cpp + HTML/SerializedPolicyContainer.cpp HTML/SessionHistoryEntry.cpp HTML/SessionHistoryTraversalQueue.cpp HTML/ShadowRealmGlobalScope.cpp HTML/SharedResourceRequest.cpp HTML/SourceSet.cpp + HTML/SourceSnapshotParams.cpp HTML/Storage.cpp HTML/StorageEvent.cpp HTML/StructuredSerialize.cpp diff --git a/Libraries/LibWeb/DOM/Document.cpp b/Libraries/LibWeb/DOM/Document.cpp index b56c73edefb..29808713d6b 100644 --- a/Libraries/LibWeb/DOM/Document.cpp +++ b/Libraries/LibWeb/DOM/Document.cpp @@ -1,7 +1,7 @@ /* * Copyright (c) 2018-2024, Andreas Kling * Copyright (c) 2021-2023, Linus Groh - * Copyright (c) 2021-2023, Luke Wilde + * Copyright (c) 2021-2025, Luke Wilde * Copyright (c) 2021-2024, Sam Atkins * Copyright (c) 2024, Matthew Olsson * Copyright (c) 2025, Jelle Raaijmakers @@ -118,6 +118,7 @@ #include #include #include +#include #include #include #include @@ -586,6 +587,7 @@ void Document::visit_edges(Cell::Visitor& visitor) visitor.visit(m_local_storage_holder); visitor.visit(m_session_storage_holder); visitor.visit(m_render_blocking_elements); + visitor.visit(m_policy_container); } // https://w3c.github.io/selection-api/#dom-document-getselection @@ -3705,39 +3707,46 @@ void Document::set_active_sandboxing_flag_set(HTML::SandboxingFlagSet sandboxing m_active_sandboxing_flag_set = sandboxing_flag_set; } -HTML::PolicyContainer Document::policy_container() const +GC::Ref Document::policy_container() const { - return m_policy_container; + auto& realm = this->realm(); + if (!m_policy_container) { + m_policy_container = realm.create(realm); + } + return *m_policy_container; } -void Document::set_policy_container(HTML::PolicyContainer policy_container) +void Document::set_policy_container(GC::Ref policy_container) { - m_policy_container = move(policy_container); + m_policy_container = policy_container; } // https://html.spec.whatwg.org/multipage/browsing-the-web.html#snapshotting-source-snapshot-params -HTML::SourceSnapshotParams Document::snapshot_source_snapshot_params() const +GC::Ref Document::snapshot_source_snapshot_params() const { + auto& realm = this->realm(); + // To snapshot source snapshot params given a Document sourceDocument, return a new source snapshot params with + return realm.create( + // has transient activation + // true if sourceDocument's relevant global object has transient activation; otherwise false + as(HTML::relevant_global_object(*this)).has_transient_activation(), - // has transient activation - // true if sourceDocument's relevant global object has transient activation; otherwise false - // sandboxing flags - // sourceDocument's active sandboxing flag set - // allows downloading - // false if sourceDocument's active sandboxing flag set has the sandboxed downloads browsing context flag set; otherwise true - // fetch client - // sourceDocument's relevant settings object - // source policy container - // a clone of sourceDocument's policy container + // sandboxing flags + // sourceDocument's active sandboxing flag set + m_active_sandboxing_flag_set, - return HTML::SourceSnapshotParams { - .has_transient_activation = as(HTML::relevant_global_object(*this)).has_transient_activation(), - .sandboxing_flags = m_active_sandboxing_flag_set, - .allows_downloading = !has_flag(m_active_sandboxing_flag_set, HTML::SandboxingFlagSet::SandboxedDownloads), - .fetch_client = relevant_settings_object(), - .source_policy_container = m_policy_container - }; + // allows downloading + // false if sourceDocument's active sandboxing flag set has the sandboxed downloads browsing context flag set; otherwise true + !has_flag(m_active_sandboxing_flag_set, HTML::SandboxingFlagSet::SandboxedDownloads), + + // fetch client + // sourceDocument's relevant settings object + relevant_settings_object(), + + // source policy container + // a clone of sourceDocument's policy container + policy_container()->clone(realm)); } // https://html.spec.whatwg.org/multipage/document-sequences.html#descendant-navigables diff --git a/Libraries/LibWeb/DOM/Document.h b/Libraries/LibWeb/DOM/Document.h index 40b0cc7c6d2..f17818f198a 100644 --- a/Libraries/LibWeb/DOM/Document.h +++ b/Libraries/LibWeb/DOM/Document.h @@ -548,8 +548,8 @@ public: void set_active_sandboxing_flag_set(HTML::SandboxingFlagSet); // https://html.spec.whatwg.org/multipage/dom.html#concept-document-policy-container - HTML::PolicyContainer policy_container() const; - void set_policy_container(HTML::PolicyContainer); + GC::Ref policy_container() const; + void set_policy_container(GC::Ref); Vector> descendant_navigables(); Vector> const descendant_navigables() const; @@ -635,7 +635,7 @@ public: u32 unload_counter() const { return m_unload_counter; } - HTML::SourceSnapshotParams snapshot_source_snapshot_params() const; + GC::Ref snapshot_source_snapshot_params() const; void update_for_history_step_application(GC::Ref, bool do_not_reactivate, size_t script_history_length, size_t script_history_index, Optional navigation_type, Optional>> entries_for_navigation_api = {}, GC::Ptr previous_entry_for_activation = {}, bool update_navigation_api = true); @@ -1018,7 +1018,7 @@ private: HTML::SandboxingFlagSet m_active_sandboxing_flag_set; // https://html.spec.whatwg.org/multipage/dom.html#concept-document-policy-container - HTML::PolicyContainer m_policy_container; + mutable GC::Ptr m_policy_container; // https://html.spec.whatwg.org/multipage/interaction.html#visibility-state HTML::VisibilityState m_visibility_state { HTML::VisibilityState::Hidden }; diff --git a/Libraries/LibWeb/DOM/DocumentLoading.h b/Libraries/LibWeb/DOM/DocumentLoading.h index acf8f74f479..356d2132606 100644 --- a/Libraries/LibWeb/DOM/DocumentLoading.h +++ b/Libraries/LibWeb/DOM/DocumentLoading.h @@ -21,6 +21,8 @@ template GC::Ref create_document_for_inline_content(GC::Ptr navigable, Optional navigation_id, HTML::UserNavigationInvolvement user_involvement, MutateDocument mutate_document) { auto& vm = navigable->vm(); + VERIFY(navigable->active_document()); + auto& realm = navigable->active_document()->realm(); // 1. Let origin be a new opaque origin. URL::Origin origin {}; @@ -66,7 +68,7 @@ GC::Ref create_document_for_inline_content(GC::Ptrcoop_enforcement_result = move(coop_enforcement_result); navigation_params->reserved_environment = {}; navigation_params->origin = move(origin); - navigation_params->policy_container = HTML::PolicyContainer {}; + navigation_params->policy_container = vm.heap().allocate(realm); navigation_params->final_sandboxing_flag_set = HTML::SandboxingFlagSet {}; navigation_params->opener_policy = move(coop); navigation_params->about_base_url = {}; diff --git a/Libraries/LibWeb/Fetch/Fetching/Fetching.cpp b/Libraries/LibWeb/Fetch/Fetching/Fetching.cpp index b55669ce1aa..311319b6f0a 100644 --- a/Libraries/LibWeb/Fetch/Fetching/Fetching.cpp +++ b/Libraries/LibWeb/Fetch/Fetching/Fetching.cpp @@ -181,10 +181,10 @@ WebIDL::ExceptionOr> fetch(JS::Realm& r // 1. If request’s client is non-null, then set request’s policy container to a clone of request’s client’s // policy container. if (request.client() != nullptr) - request.set_policy_container(request.client()->policy_container()); + request.set_policy_container(request.client()->policy_container()->clone(realm)); // 2. Otherwise, set request’s policy container to a new policy container. else - request.set_policy_container(HTML::PolicyContainer {}); + request.set_policy_container(realm.create(realm)); } // 13. If request’s header list does not contain `Accept`, then: @@ -301,8 +301,8 @@ WebIDL::ExceptionOr> main_fetch(JS::Realm& realm, Infra // 8. If request’s referrer policy is the empty string, then set request’s referrer policy to request’s policy // container’s referrer policy. if (request->referrer_policy() == ReferrerPolicy::ReferrerPolicy::EmptyString) { - VERIFY(request->policy_container().has()); - request->set_referrer_policy(request->policy_container().get().referrer_policy); + VERIFY(request->policy_container().has>()); + request->set_referrer_policy(request->policy_container().get>()->referrer_policy); } // 9. If request’s referrer is not "no-referrer", then set request’s referrer to the result of invoking determine diff --git a/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Requests.cpp b/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Requests.cpp index 3765115878c..c6b3b030182 100644 --- a/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Requests.cpp +++ b/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Requests.cpp @@ -33,6 +33,9 @@ void Request::visit_edges(JS::Cell::Visitor& visitor) [&](GC::Ptr const& value) { visitor.visit(value); }, [](auto const&) {}); visitor.visit(m_pending_responses); + m_policy_container.visit( + [&](GC::Ref const& policy_container) { visitor.visit(policy_container); }, + [](auto const&) {}); } GC::Ref Request::create(JS::VM& vm) @@ -359,7 +362,7 @@ bool Request::cross_origin_embedder_policy_allows_credentials() const return true; // 3. If request’s client’s policy container’s embedder policy’s value is not "credentialless", then return true. - if (m_policy_container.has() && m_policy_container.get().embedder_policy.value != HTML::EmbedderPolicyValue::Credentialless) + if (m_policy_container.has>() && m_policy_container.get>()->embedder_policy.value != HTML::EmbedderPolicyValue::Credentialless) return true; // 4. If request’s origin is same origin with request’s current URL’s origin and request does not have a redirect-tainted origin, then return true. diff --git a/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Requests.h b/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Requests.h index c6d8d103526..b113ccd343c 100644 --- a/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Requests.h +++ b/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Requests.h @@ -171,7 +171,7 @@ public: using BodyType = Variant>; using OriginType = Variant; - using PolicyContainerType = Variant; + using PolicyContainerType = Variant>; using ReferrerType = Variant; using ReservedClientType = GC::Ptr; using WindowType = Variant>; diff --git a/Libraries/LibWeb/Forward.h b/Libraries/LibWeb/Forward.h index 4756c21eaee..03d6b393ba5 100644 --- a/Libraries/LibWeb/Forward.h +++ b/Libraries/LibWeb/Forward.h @@ -583,6 +583,7 @@ struct POSTResource; struct ScrollOptions; struct ScrollToOptions; struct SerializedFormData; +struct SerializedPolicyContainer; struct StructuredSerializeOptions; struct SyntheticRealmSettings; struct ToggleTaskTracker; diff --git a/Libraries/LibWeb/HTML/BrowsingContext.cpp b/Libraries/LibWeb/HTML/BrowsingContext.cpp index 5abbbf51257..4812037674f 100644 --- a/Libraries/LibWeb/HTML/BrowsingContext.cpp +++ b/Libraries/LibWeb/HTML/BrowsingContext.cpp @@ -251,7 +251,7 @@ WebIDL::ExceptionOr BrowsingContext document->set_referrer(creator->url().serialize()); // 2. Set document's policy container to a clone of creator's policy container. - document->set_policy_container(creator->policy_container()); + document->set_policy_container(creator->policy_container()->clone(document->realm())); // 3. If creator's origin is same origin with creator's relevant settings object's top-level origin, if (creator->origin().is_same_origin(creator->relevant_settings_object().top_level_origin)) { diff --git a/Libraries/LibWeb/HTML/DocumentState.cpp b/Libraries/LibWeb/HTML/DocumentState.cpp index 4e50c2f4b92..ccb9411d1ab 100644 --- a/Libraries/LibWeb/HTML/DocumentState.cpp +++ b/Libraries/LibWeb/HTML/DocumentState.cpp @@ -38,6 +38,9 @@ void DocumentState::visit_edges(Cell::Visitor& visitor) { Base::visit_edges(visitor); visitor.visit(m_document); + m_history_policy_container.visit( + [&](GC::Ref const& policy_container) { visitor.visit(policy_container); }, + [](auto const&) {}); for (auto& nested_history : m_nested_histories) { visitor.visit(nested_history.entries); } diff --git a/Libraries/LibWeb/HTML/DocumentState.h b/Libraries/LibWeb/HTML/DocumentState.h index 04477379dba..99988513ece 100644 --- a/Libraries/LibWeb/HTML/DocumentState.h +++ b/Libraries/LibWeb/HTML/DocumentState.h @@ -40,8 +40,8 @@ public: [[nodiscard]] GC::Ptr document() const { return m_document; } void set_document(GC::Ptr document) { m_document = document; } - [[nodiscard]] Variant history_policy_container() const { return m_history_policy_container; } - void set_history_policy_container(Variant history_policy_container) { m_history_policy_container = move(history_policy_container); } + [[nodiscard]] Variant, Client> history_policy_container() const { return m_history_policy_container; } + void set_history_policy_container(Variant, Client> history_policy_container) { m_history_policy_container = move(history_policy_container); } [[nodiscard]] Fetch::Infrastructure::Request::ReferrerType request_referrer() const { return m_request_referrer; } void set_request_referrer(Fetch::Infrastructure::Request::ReferrerType request_referrer) { m_request_referrer = move(request_referrer); } @@ -82,7 +82,7 @@ private: GC::Ptr m_document; // https://html.spec.whatwg.org/multipage/browsing-the-web.html#document-state-history-policy-container - Variant m_history_policy_container { Client::Tag }; + Variant, Client> m_history_policy_container { Client::Tag }; // https://html.spec.whatwg.org/multipage/browsing-the-web.html#document-state-request-referrer Fetch::Infrastructure::Request::ReferrerType m_request_referrer { Fetch::Infrastructure::Request::Referrer::Client }; diff --git a/Libraries/LibWeb/HTML/EmbedderPolicy.cpp b/Libraries/LibWeb/HTML/EmbedderPolicy.cpp index 40e1af980c1..3da0ac1001b 100644 --- a/Libraries/LibWeb/HTML/EmbedderPolicy.cpp +++ b/Libraries/LibWeb/HTML/EmbedderPolicy.cpp @@ -1,9 +1,12 @@ /* * Copyright (c) 2024, Jamie Mansfield + * Copyright (c) 2025, Luke Wilde * * SPDX-License-Identifier: BSD-2-Clause */ +#include +#include #include namespace Web::HTML { @@ -33,3 +36,31 @@ Optional embedder_policy_value_from_string(StringView strin } } + +namespace IPC { + +template<> +ErrorOr encode(Encoder& encoder, Web::HTML::EmbedderPolicy const& embedder_policy) +{ + TRY(encoder.encode(embedder_policy.value)); + TRY(encoder.encode(embedder_policy.reporting_endpoint)); + TRY(encoder.encode(embedder_policy.report_only_value)); + TRY(encoder.encode(embedder_policy.report_only_reporting_endpoint)); + + return {}; +} + +template<> +ErrorOr decode(Decoder& decoder) +{ + Web::HTML::EmbedderPolicy embedder_policy {}; + + embedder_policy.value = TRY(decoder.decode()); + embedder_policy.reporting_endpoint = TRY(decoder.decode()); + embedder_policy.report_only_value = TRY(decoder.decode()); + embedder_policy.report_only_reporting_endpoint = TRY(decoder.decode()); + + return embedder_policy; +} + +} diff --git a/Libraries/LibWeb/HTML/EmbedderPolicy.h b/Libraries/LibWeb/HTML/EmbedderPolicy.h index 360c5132f42..ad385358055 100644 --- a/Libraries/LibWeb/HTML/EmbedderPolicy.h +++ b/Libraries/LibWeb/HTML/EmbedderPolicy.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2024, Jamie Mansfield + * Copyright (c) 2025, Luke Wilde * * SPDX-License-Identifier: BSD-2-Clause */ @@ -9,6 +10,7 @@ #include #include #include +#include namespace Web::HTML { @@ -42,3 +44,13 @@ struct EmbedderPolicy { }; } + +namespace IPC { + +template<> +ErrorOr encode(Encoder&, Web::HTML::EmbedderPolicy const&); + +template<> +ErrorOr decode(Decoder&); + +} diff --git a/Libraries/LibWeb/HTML/HTMLLinkElement.cpp b/Libraries/LibWeb/HTML/HTMLLinkElement.cpp index 8a074fe7d6f..7e5f295b4e1 100644 --- a/Libraries/LibWeb/HTML/HTMLLinkElement.cpp +++ b/Libraries/LibWeb/HTML/HTMLLinkElement.cpp @@ -286,7 +286,7 @@ GC::Ptr HTMLLinkElement::create_link_request(HTM auto request = create_potential_CORS_request(vm(), *url, options.destination, options.crossorigin); // 6. Set request's policy container to options's policy container. - request->set_policy_container(options.policy_container); + request->set_policy_container(GC::Ref { *options.policy_container }); // 7. Set request's integrity metadata to options's integrity. request->set_integrity_metadata(options.integrity); diff --git a/Libraries/LibWeb/HTML/HTMLLinkElement.h b/Libraries/LibWeb/HTML/HTMLLinkElement.h index 51230cadc4a..70734ea3015 100644 --- a/Libraries/LibWeb/HTML/HTMLLinkElement.h +++ b/Libraries/LibWeb/HTML/HTMLLinkElement.h @@ -92,7 +92,7 @@ private: GC::Ptr environment; // policy container // A policy container - HTML::PolicyContainer policy_container; + GC::Ptr policy_container; // document (default null) // Null or a Document GC::Ptr document; diff --git a/Libraries/LibWeb/HTML/Navigable.cpp b/Libraries/LibWeb/HTML/Navigable.cpp index 0dad9dd4a16..83879c8b759 100644 --- a/Libraries/LibWeb/HTML/Navigable.cpp +++ b/Libraries/LibWeb/HTML/Navigable.cpp @@ -1,6 +1,7 @@ /* * Copyright (c) 2022-2024, Andreas Kling * Copyright (c) 2023, Aliaksandr Kalenik + * Copyright (c) 2025, Luke Wilde * * SPDX-License-Identifier: BSD-2-Clause */ @@ -608,42 +609,41 @@ Vector>& Navigable::get_session_history_entries() c } // https://html.spec.whatwg.org/multipage/browsers.html#determining-navigation-params-policy-container -static PolicyContainer determine_navigation_params_policy_container(URL::URL const& response_url, - Optional history_policy_container, - Optional initiator_policy_container, - Optional parent_policy_container, - Optional response_policy_container) +static GC::Ref determine_navigation_params_policy_container(URL::URL const& response_url, + JS::Realm& realm, + GC::Ptr history_policy_container, + GC::Ptr initiator_policy_container, + GC::Ptr parent_policy_container, + GC::Ptr response_policy_container) { - // NOTE: The clone a policy container AO is just a C++ copy - // 1. If historyPolicyContainer is not null, then: - if (history_policy_container.has_value()) { + if (history_policy_container) { // FIXME: 1. Assert: responseURL requires storing the policy container in history. // 2. Return a clone of historyPolicyContainer. - return *history_policy_container; + return history_policy_container->clone(realm); } // 2. If responseURL is about:srcdoc, then: if (response_url == URL::about_srcdoc()) { // 1. Assert: parentPolicyContainer is not null. - VERIFY(parent_policy_container.has_value()); + VERIFY(parent_policy_container); // 2. Return a clone of parentPolicyContainer. - return *parent_policy_container; + return parent_policy_container->clone(realm); } // 3. If responseURL is local and initiatorPolicyContainer is not null, then return a clone of initiatorPolicyContainer. - if (Fetch::Infrastructure::is_local_url(response_url) && initiator_policy_container.has_value()) - return *initiator_policy_container; + if (Fetch::Infrastructure::is_local_url(response_url) && initiator_policy_container) + return initiator_policy_container->clone(realm); // 4. If responsePolicyContainer is not null, then return responsePolicyContainer. // FIXME: File a spec issue to say "a clone of" here for consistency - if (response_policy_container.has_value()) - return *response_policy_container; + if (response_policy_container) + return response_policy_container->clone(realm); // 5. Return a new policy container. - return {}; + return realm.create(realm); } // https://html.spec.whatwg.org/multipage/browsers.html#obtain-coop @@ -724,15 +724,17 @@ static GC::Ref create_navigation_params_from_a_srcdoc_resource // 6. Let policyContainer be the result of determining navigation params policy container given response's URL, // entry's document state's history policy container, null, navigable's container document's policy container, and null. - Optional history_policy_container = entry->document_state()->history_policy_container().visit( - [](PolicyContainer const& c) -> Optional { return c; }, - [](DocumentState::Client) -> Optional { return {}; }); - PolicyContainer policy_container; + GC::Ptr history_policy_container = entry->document_state()->history_policy_container().visit( + [](GC::Ref const& c) -> GC::Ptr { return c; }, + [](DocumentState::Client) -> GC::Ptr { return {}; }); + GC::Ptr policy_container; if (navigable->container()) { // NOTE: Specification assumes that only navigables corresponding to iframes can be navigated to about:srcdoc. // We also use srcdoc to implement load_html() for top level navigables so we need to null check container // because it might be null. - policy_container = determine_navigation_params_policy_container(*response->url(), history_policy_container, {}, navigable->container_document()->policy_container(), {}); + policy_container = determine_navigation_params_policy_container(*response->url(), realm, history_policy_container, {}, navigable->container_document()->policy_container(), {}); + } else { + policy_container = realm.create(realm); } // 7. Return a new navigation params, with @@ -757,7 +759,7 @@ static GC::Ref create_navigation_params_from_a_srcdoc_resource navigation_params->response = response; navigation_params->coop_enforcement_result = move(coop_enforcement_result); navigation_params->origin = move(response_origin); - navigation_params->policy_container = policy_container; + navigation_params->policy_container = *policy_container; navigation_params->final_sandboxing_flag_set = target_snapshot_params.sandboxing_flags; navigation_params->opener_policy = move(coop); navigation_params->about_base_url = entry->document_state()->about_base_url(); @@ -904,7 +906,7 @@ static WebIDL::ExceptionOr create_navigation SandboxingFlagSet final_sandbox_flags = {}; // 14. Let responsePolicyContainer be null. - Optional response_policy_container = {}; + GC::Ptr response_policy_container = {}; // 15. Let responseCOOP be a new opener policy. OpenerPolicy response_coop = {}; @@ -1096,10 +1098,10 @@ static WebIDL::ExceptionOr create_navigation // 23. Let resultPolicyContainer be the result of determining navigation params policy container given response's URL, // entry's document state's history policy container, sourceSnapshotParams's source policy container, null, and responsePolicyContainer. - Optional history_policy_container = entry->document_state()->history_policy_container().visit( - [](PolicyContainer const& c) -> Optional { return c; }, - [](DocumentState::Client) -> Optional { return {}; }); - auto result_policy_container = determine_navigation_params_policy_container(*response_holder->response()->url(), history_policy_container, source_snapshot_params.source_policy_container, {}, response_policy_container); + GC::Ptr history_policy_container = entry->document_state()->history_policy_container().visit( + [](GC::Ref const& c) -> GC::Ptr { return c; }, + [](DocumentState::Client) -> GC::Ptr { return {}; }); + auto result_policy_container = determine_navigation_params_policy_container(*response_holder->response()->url(), realm, history_policy_container, source_snapshot_params.source_policy_container, {}, response_policy_container); // 24. If navigable's container is an iframe, and response's timing allow passed flag is set, then set container's pending resource-timing start time to null. if (navigable->container() && is(*navigable->container()) && response_holder->response()->timing_allow_passed()) @@ -1298,7 +1300,14 @@ WebIDL::ExceptionOr Navigable::populate_session_history_entry_document( // 2. Set entry's document state's origin to document's origin. entry->document_state()->set_origin(document->origin()); - // FIXME: 3. If document's URL requires storing the policy container in history, then: + // 3. If document's URL requires storing the policy container in history, then: + if (url_requires_storing_the_policy_container_in_history(document->url())) { + // 1. Assert: navigationParams is a navigation params (i.e., neither null nor a non-fetch scheme navigation params). + VERIFY(navigation_params.has>()); + + // 2. Set entry's document state's history policy container to navigationParams's policy container. + entry->document_state()->set_history_policy_container(GC::Ref { *navigation_params.get>()->policy_container }); + } } // 3. If entry's document state's request referrer is "client", and navigationParams is a navigation params (i.e., neither null nor a non-fetch scheme navigation params), then: @@ -1810,7 +1819,7 @@ GC::Ptr Navigable::evaluate_javascript_url(URL::URL const& url, U } // https://html.spec.whatwg.org/multipage/browsing-the-web.html#navigate-to-a-javascript:-url -void Navigable::navigate_to_a_javascript_url(URL::URL const& url, HistoryHandlingBehavior history_handling, SourceSnapshotParams, URL::Origin const& initiator_origin, UserNavigationInvolvement user_involvement, CSPNavigationType csp_navigation_type, String navigation_id) +void Navigable::navigate_to_a_javascript_url(URL::URL const& url, HistoryHandlingBehavior history_handling, GC::Ref, URL::Origin const& initiator_origin, UserNavigationInvolvement user_involvement, CSPNavigationType csp_navigation_type, String navigation_id) { // 1. Assert: historyHandling is "replace". VERIFY(history_handling == HistoryHandlingBehavior::Replace); diff --git a/Libraries/LibWeb/HTML/Navigable.h b/Libraries/LibWeb/HTML/Navigable.h index 75d7566ffa2..64c6498833c 100644 --- a/Libraries/LibWeb/HTML/Navigable.h +++ b/Libraries/LibWeb/HTML/Navigable.h @@ -154,7 +154,7 @@ public: WebIDL::ExceptionOr navigate_to_a_fragment(URL::URL const&, HistoryHandlingBehavior, UserNavigationInvolvement, GC::Ptr source_element, Optional navigation_api_state, String navigation_id); GC::Ptr evaluate_javascript_url(URL::URL const&, URL::Origin const& new_document_origin, UserNavigationInvolvement, String navigation_id); - void navigate_to_a_javascript_url(URL::URL const&, HistoryHandlingBehavior, SourceSnapshotParams, URL::Origin const& initiator_origin, UserNavigationInvolvement, CSPNavigationType csp_navigation_type, String navigation_id); + void navigate_to_a_javascript_url(URL::URL const&, HistoryHandlingBehavior, GC::Ref, URL::Origin const& initiator_origin, UserNavigationInvolvement, CSPNavigationType csp_navigation_type, String navigation_id); bool allowed_by_sandboxing_to_navigate(Navigable const& target, SourceSnapshotParams const&); diff --git a/Libraries/LibWeb/HTML/NavigationParams.cpp b/Libraries/LibWeb/HTML/NavigationParams.cpp index 89dee2c07d0..1b08c742170 100644 --- a/Libraries/LibWeb/HTML/NavigationParams.cpp +++ b/Libraries/LibWeb/HTML/NavigationParams.cpp @@ -23,6 +23,7 @@ void NavigationParams::visit_edges(Visitor& visitor) visitor.visit(response); visitor.visit(fetch_controller); visitor.visit(reserved_environment); + visitor.visit(policy_container); } void NonFetchSchemeNavigationParams::visit_edges(Visitor& visitor) diff --git a/Libraries/LibWeb/HTML/NavigationParams.h b/Libraries/LibWeb/HTML/NavigationParams.h index 6fddc20cff5..077eda73aca 100644 --- a/Libraries/LibWeb/HTML/NavigationParams.h +++ b/Libraries/LibWeb/HTML/NavigationParams.h @@ -60,7 +60,7 @@ struct NavigationParams : JS::Cell { URL::Origin origin; // a policy container to use for the new Document - PolicyContainer policy_container; + GC::Ptr policy_container; // a sandboxing flag set to impose on the new Document SandboxingFlagSet final_sandboxing_flag_set = {}; diff --git a/Libraries/LibWeb/HTML/PolicyContainers.cpp b/Libraries/LibWeb/HTML/PolicyContainers.cpp index 55f820ab52d..c304ac4a4f2 100644 --- a/Libraries/LibWeb/HTML/PolicyContainers.cpp +++ b/Libraries/LibWeb/HTML/PolicyContainers.cpp @@ -1,29 +1,69 @@ /* * Copyright (c) 2024, Andrew Kaster + * Copyright (c) 2025, Luke Wilde * * SPDX-License-Identifier: BSD-2-Clause */ -#include -#include +#include +#include +#include #include +#include -namespace IPC { +namespace Web::HTML { -template<> -ErrorOr encode(IPC::Encoder& encoder, Web::HTML::PolicyContainer const& policy_container) +GC_DEFINE_ALLOCATOR(PolicyContainer); + +PolicyContainer::PolicyContainer(JS::Realm&) { - TRY(encode(encoder, policy_container.referrer_policy)); - - return {}; } -template<> -ErrorOr decode(IPC::Decoder& decoder) +// https://html.spec.whatwg.org/multipage/browsers.html#requires-storing-the-policy-container-in-history +bool url_requires_storing_the_policy_container_in_history(URL::URL const& url) { - auto referrer_policy = TRY(decoder.decode()); + // 1. If url's scheme is "blob", then return false. + if (url.scheme() == "blob"sv) + return false; - return Web::HTML::PolicyContainer { .referrer_policy = referrer_policy }; + // 2. If url is local, then return true. + // 3. Return false. + return Fetch::Infrastructure::is_local_url(url); +} + +GC::Ref create_a_policy_container_from_serialized_policy_container(JS::Realm& realm, SerializedPolicyContainer const& serialized_policy_container) +{ + GC::Ref result = realm.create(realm); + result->embedder_policy = serialized_policy_container.embedder_policy; + result->referrer_policy = serialized_policy_container.referrer_policy; + return result; +} + +// https://html.spec.whatwg.org/multipage/browsers.html#clone-a-policy-container +GC::Ref PolicyContainer::clone(JS::Realm& realm) const +{ + // 1. Let clone be a new policy container. + auto clone = realm.create(realm); + + // FIXME: 2. For each policy in policyContainer's CSP list, append a copy of policy into clone's CSP list. + + // 3. Set clone's embedder policy to a copy of policyContainer's embedder policy. + // NOTE: This is a C++ copy. + clone->embedder_policy = embedder_policy; + + // 4. Set clone's referrer policy to policyContainer's referrer policy. + clone->referrer_policy = referrer_policy; + + // 5. Return clone. + return clone; +} + +SerializedPolicyContainer PolicyContainer::serialize() const +{ + return SerializedPolicyContainer { + .embedder_policy = embedder_policy, + .referrer_policy = referrer_policy, + }; } } diff --git a/Libraries/LibWeb/HTML/PolicyContainers.h b/Libraries/LibWeb/HTML/PolicyContainers.h index d30bd3cadfa..0310dc68dcb 100644 --- a/Libraries/LibWeb/HTML/PolicyContainers.h +++ b/Libraries/LibWeb/HTML/PolicyContainers.h @@ -1,12 +1,16 @@ /* * Copyright (c) 2022, Linus Groh + * Copyright (c) 2025, Luke Wilde * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once -#include +#include +#include +#include +#include #include #include @@ -14,7 +18,13 @@ namespace Web::HTML { // https://html.spec.whatwg.org/multipage/origin.html#policy-container // A policy container is a struct containing policies that apply to a Document, a WorkerGlobalScope, or a WorkletGlobalScope. It has the following items: -struct PolicyContainer { +struct PolicyContainer : public JS::Cell { + GC_CELL(PolicyContainer, JS::Cell) + GC_DECLARE_ALLOCATOR(PolicyContainer); + +public: + virtual ~PolicyContainer() = default; + // https://html.spec.whatwg.org/multipage/origin.html#policy-container-csp-list // FIXME: A CSP list, which is a CSP list. It is initially empty. @@ -25,14 +35,17 @@ struct PolicyContainer { // https://html.spec.whatwg.org/multipage/origin.html#policy-container-referrer-policy // A referrer policy, which is a referrer policy. It is initially the default referrer policy. ReferrerPolicy::ReferrerPolicy referrer_policy { ReferrerPolicy::DEFAULT_REFERRER_POLICY }; + + [[nodiscard]] GC::Ref clone(JS::Realm&) const; + [[nodiscard]] SerializedPolicyContainer serialize() const; + +private: + PolicyContainer(JS::Realm&); }; -} +// https://html.spec.whatwg.org/multipage/browsers.html#requires-storing-the-policy-container-in-history +[[nodiscard]] bool url_requires_storing_the_policy_container_in_history(URL::URL const& url); -namespace IPC { -template<> -ErrorOr encode(IPC::Encoder&, Web::HTML::PolicyContainer const&); +[[nodiscard]] GC::Ref create_a_policy_container_from_serialized_policy_container(JS::Realm&, SerializedPolicyContainer const&); -template<> -ErrorOr decode(IPC::Decoder&); } diff --git a/Libraries/LibWeb/HTML/Scripting/EnvironmentSettingsSnapshot.cpp b/Libraries/LibWeb/HTML/Scripting/EnvironmentSettingsSnapshot.cpp index c0998753fd8..d324bd90169 100644 --- a/Libraries/LibWeb/HTML/Scripting/EnvironmentSettingsSnapshot.cpp +++ b/Libraries/LibWeb/HTML/Scripting/EnvironmentSettingsSnapshot.cpp @@ -10,12 +10,12 @@ namespace Web::HTML { GC_DEFINE_ALLOCATOR(EnvironmentSettingsSnapshot); -EnvironmentSettingsSnapshot::EnvironmentSettingsSnapshot(NonnullOwnPtr execution_context, SerializedEnvironmentSettingsObject const& serialized_settings) +EnvironmentSettingsSnapshot::EnvironmentSettingsSnapshot(JS::Realm& realm, NonnullOwnPtr execution_context, SerializedEnvironmentSettingsObject const& serialized_settings) : EnvironmentSettingsObject(move(execution_context)) , m_api_url_character_encoding(serialized_settings.api_url_character_encoding) , m_url(serialized_settings.api_base_url) , m_origin(serialized_settings.origin) - , m_policy_container(serialized_settings.policy_container) + , m_policy_container(create_a_policy_container_from_serialized_policy_container(realm, serialized_settings.policy_container)) , m_time_origin(serialized_settings.time_origin) { // Why can't we put these in the init list? grandparent class members are strange it seems @@ -27,4 +27,10 @@ EnvironmentSettingsSnapshot::EnvironmentSettingsSnapshot(NonnullOwnPtr, SerializedEnvironmentSettingsObject const&); + EnvironmentSettingsSnapshot(JS::Realm&, NonnullOwnPtr, SerializedEnvironmentSettingsObject const&); virtual ~EnvironmentSettingsSnapshot() override; @@ -26,15 +26,18 @@ public: String api_url_character_encoding() const override { return m_api_url_character_encoding; } URL::URL api_base_url() const override { return m_url; } URL::Origin origin() const override { return m_origin; } - PolicyContainer policy_container() const override { return m_policy_container; } + GC::Ref policy_container() const override { return m_policy_container; } CanUseCrossOriginIsolatedAPIs cross_origin_isolated_capability() const override { return CanUseCrossOriginIsolatedAPIs::No; } double time_origin() const override { return m_time_origin; } +protected: + virtual void visit_edges(Cell::Visitor&) override; + private: String m_api_url_character_encoding; URL::URL m_url; URL::Origin m_origin; - HTML::PolicyContainer m_policy_container; + GC::Ref m_policy_container; double m_time_origin { 0 }; }; diff --git a/Libraries/LibWeb/HTML/Scripting/Environments.cpp b/Libraries/LibWeb/HTML/Scripting/Environments.cpp index fc7d3c4f0ce..1f0140b4347 100644 --- a/Libraries/LibWeb/HTML/Scripting/Environments.cpp +++ b/Libraries/LibWeb/HTML/Scripting/Environments.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Luke Wilde + * Copyright (c) 2021-2025, Luke Wilde * Copyright (c) 2022, Linus Groh * Copyright (c) 2022, networkException * Copyright (c) 2024, Shannon Booth @@ -565,7 +565,7 @@ SerializedEnvironmentSettingsObject EnvironmentSettingsObject::serialize() object.api_url_character_encoding = api_url_character_encoding(); object.api_base_url = api_base_url(); object.origin = origin(); - object.policy_container = policy_container(); + object.policy_container = policy_container()->serialize(); object.cross_origin_isolated_capability = cross_origin_isolated_capability(); return object; diff --git a/Libraries/LibWeb/HTML/Scripting/Environments.h b/Libraries/LibWeb/HTML/Scripting/Environments.h index 84486042140..affcb5d3f27 100644 --- a/Libraries/LibWeb/HTML/Scripting/Environments.h +++ b/Libraries/LibWeb/HTML/Scripting/Environments.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Luke Wilde + * Copyright (c) 2021-2025, Luke Wilde * Copyright (c) 2022, Linus Groh * Copyright (c) 2024, Shannon Booth * @@ -83,7 +83,7 @@ public: virtual URL::Origin origin() const = 0; // A policy container https://html.spec.whatwg.org/multipage/webappapis.html#concept-settings-object-policy-container - virtual PolicyContainer policy_container() const = 0; + virtual GC::Ref policy_container() const = 0; // https://html.spec.whatwg.org/multipage/webappapis.html#concept-settings-object-cross-origin-isolated-capability virtual CanUseCrossOriginIsolatedAPIs cross_origin_isolated_capability() const = 0; diff --git a/Libraries/LibWeb/HTML/Scripting/SerializedEnvironmentSettingsObject.cpp b/Libraries/LibWeb/HTML/Scripting/SerializedEnvironmentSettingsObject.cpp index 1365a06f180..093ab9bda70 100644 --- a/Libraries/LibWeb/HTML/Scripting/SerializedEnvironmentSettingsObject.cpp +++ b/Libraries/LibWeb/HTML/Scripting/SerializedEnvironmentSettingsObject.cpp @@ -39,7 +39,7 @@ ErrorOr decode(Decoder& decoder) object.api_url_character_encoding = TRY(decoder.decode()); object.api_base_url = TRY(decoder.decode()); object.origin = TRY(decoder.decode()); - object.policy_container = TRY(decoder.decode()); + object.policy_container = TRY(decoder.decode()); object.cross_origin_isolated_capability = TRY(decoder.decode()); object.time_origin = TRY(decoder.decode()); diff --git a/Libraries/LibWeb/HTML/Scripting/SerializedEnvironmentSettingsObject.h b/Libraries/LibWeb/HTML/Scripting/SerializedEnvironmentSettingsObject.h index fb03d051d67..2dc49068ec3 100644 --- a/Libraries/LibWeb/HTML/Scripting/SerializedEnvironmentSettingsObject.h +++ b/Libraries/LibWeb/HTML/Scripting/SerializedEnvironmentSettingsObject.h @@ -10,7 +10,7 @@ #include #include #include -#include +#include namespace Web::HTML { @@ -28,7 +28,7 @@ struct SerializedEnvironmentSettingsObject { String api_url_character_encoding; URL::URL api_base_url; URL::Origin origin; - PolicyContainer policy_container; + SerializedPolicyContainer policy_container; CanUseCrossOriginIsolatedAPIs cross_origin_isolated_capability; double time_origin; }; diff --git a/Libraries/LibWeb/HTML/Scripting/WindowEnvironmentSettingsObject.cpp b/Libraries/LibWeb/HTML/Scripting/WindowEnvironmentSettingsObject.cpp index c81a35e503d..be50aff2f83 100644 --- a/Libraries/LibWeb/HTML/Scripting/WindowEnvironmentSettingsObject.cpp +++ b/Libraries/LibWeb/HTML/Scripting/WindowEnvironmentSettingsObject.cpp @@ -111,7 +111,7 @@ URL::Origin WindowEnvironmentSettingsObject::origin() const } // https://html.spec.whatwg.org/multipage/window-object.html#script-settings-for-window-objects:concept-settings-object-policy-container -PolicyContainer WindowEnvironmentSettingsObject::policy_container() const +GC::Ref WindowEnvironmentSettingsObject::policy_container() const { // Return the policy container of window's associated Document. return m_window->associated_document().policy_container(); diff --git a/Libraries/LibWeb/HTML/Scripting/WindowEnvironmentSettingsObject.h b/Libraries/LibWeb/HTML/Scripting/WindowEnvironmentSettingsObject.h index 8dab2734d65..790b45ba56c 100644 --- a/Libraries/LibWeb/HTML/Scripting/WindowEnvironmentSettingsObject.h +++ b/Libraries/LibWeb/HTML/Scripting/WindowEnvironmentSettingsObject.h @@ -24,7 +24,7 @@ public: virtual String api_url_character_encoding() const override; virtual URL::URL api_base_url() const override; virtual URL::Origin origin() const override; - virtual PolicyContainer policy_container() const override; + virtual GC::Ref policy_container() const override; virtual CanUseCrossOriginIsolatedAPIs cross_origin_isolated_capability() const override; virtual double time_origin() const override; diff --git a/Libraries/LibWeb/HTML/Scripting/WorkerEnvironmentSettingsObject.cpp b/Libraries/LibWeb/HTML/Scripting/WorkerEnvironmentSettingsObject.cpp index d6f6aef0d86..633c4fb929e 100644 --- a/Libraries/LibWeb/HTML/Scripting/WorkerEnvironmentSettingsObject.cpp +++ b/Libraries/LibWeb/HTML/Scripting/WorkerEnvironmentSettingsObject.cpp @@ -66,7 +66,7 @@ URL::Origin WorkerEnvironmentSettingsObject::origin() const return m_origin; } -PolicyContainer WorkerEnvironmentSettingsObject::policy_container() const +GC::Ref WorkerEnvironmentSettingsObject::policy_container() const { // Return worker global scope's policy container. return m_global_scope->policy_container(); diff --git a/Libraries/LibWeb/HTML/Scripting/WorkerEnvironmentSettingsObject.h b/Libraries/LibWeb/HTML/Scripting/WorkerEnvironmentSettingsObject.h index a160a8a3173..0836e7f202c 100644 --- a/Libraries/LibWeb/HTML/Scripting/WorkerEnvironmentSettingsObject.h +++ b/Libraries/LibWeb/HTML/Scripting/WorkerEnvironmentSettingsObject.h @@ -33,7 +33,7 @@ public: String api_url_character_encoding() const override { return m_api_url_character_encoding; } URL::URL api_base_url() const override; URL::Origin origin() const override; - PolicyContainer policy_container() const override; + GC::Ref policy_container() const override; CanUseCrossOriginIsolatedAPIs cross_origin_isolated_capability() const override; double time_origin() const override; diff --git a/Libraries/LibWeb/HTML/SerializedPolicyContainer.cpp b/Libraries/LibWeb/HTML/SerializedPolicyContainer.cpp new file mode 100644 index 00000000000..b47d1bc4d81 --- /dev/null +++ b/Libraries/LibWeb/HTML/SerializedPolicyContainer.cpp @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2025, Luke Wilde + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include + +namespace IPC { + +template<> +ErrorOr encode(Encoder& encoder, Web::HTML::SerializedPolicyContainer const& serialized_policy_container) +{ + TRY(encoder.encode(serialized_policy_container.embedder_policy)); + TRY(encoder.encode(serialized_policy_container.referrer_policy)); + + return {}; +} + +template<> +ErrorOr decode(Decoder& decoder) +{ + Web::HTML::SerializedPolicyContainer serialized_policy_container {}; + + serialized_policy_container.embedder_policy = TRY(decoder.decode()); + serialized_policy_container.referrer_policy = TRY(decoder.decode()); + + return serialized_policy_container; +} + +} diff --git a/Libraries/LibWeb/HTML/SerializedPolicyContainer.h b/Libraries/LibWeb/HTML/SerializedPolicyContainer.h new file mode 100644 index 00000000000..0cc49f3b3c9 --- /dev/null +++ b/Libraries/LibWeb/HTML/SerializedPolicyContainer.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2025, Luke Wilde + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include + +namespace Web::HTML { + +struct SerializedPolicyContainer { + EmbedderPolicy embedder_policy; + ReferrerPolicy::ReferrerPolicy referrer_policy; +}; + +} + +namespace IPC { + +template<> +ErrorOr encode(Encoder&, Web::HTML::SerializedPolicyContainer const&); + +template<> +ErrorOr decode(Decoder&); + +} diff --git a/Libraries/LibWeb/HTML/SessionHistoryEntry.cpp b/Libraries/LibWeb/HTML/SessionHistoryEntry.cpp index b85863618c9..1c298bd3757 100644 --- a/Libraries/LibWeb/HTML/SessionHistoryEntry.cpp +++ b/Libraries/LibWeb/HTML/SessionHistoryEntry.cpp @@ -18,6 +18,7 @@ void SessionHistoryEntry::visit_edges(Cell::Visitor& visitor) Base::visit_edges(visitor); visitor.visit(m_document_state); visitor.visit(m_original_source_browsing_context); + visitor.visit(m_policy_container); } SessionHistoryEntry::SessionHistoryEntry() diff --git a/Libraries/LibWeb/HTML/SessionHistoryEntry.h b/Libraries/LibWeb/HTML/SessionHistoryEntry.h index f2863a39ad0..b9ade2328f8 100644 --- a/Libraries/LibWeb/HTML/SessionHistoryEntry.h +++ b/Libraries/LibWeb/HTML/SessionHistoryEntry.h @@ -69,8 +69,8 @@ public: [[nodiscard]] ScrollRestorationMode scroll_restoration_mode() const { return m_scroll_restoration_mode; } void set_scroll_restoration_mode(ScrollRestorationMode scroll_restoration_mode) { m_scroll_restoration_mode = scroll_restoration_mode; } - [[nodiscard]] Optional const& policy_container() const { return m_policy_container; } - void set_policy_container(Optional policy_container) { m_policy_container = move(policy_container); } + [[nodiscard]] GC::Ptr policy_container() const { return m_policy_container; } + void set_policy_container(GC::Ptr policy_container) { m_policy_container = policy_container; } [[nodiscard]] Optional const& browsing_context_name() const { return m_browsing_context_name; } void set_browsing_context_name(Optional browsing_context_name) { m_browsing_context_name = move(browsing_context_name); } @@ -111,7 +111,7 @@ private: ScrollRestorationMode m_scroll_restoration_mode { ScrollRestorationMode::Auto }; // policy container, a policy container or null - Optional m_policy_container; + GC::Ptr m_policy_container; // https://html.spec.whatwg.org/multipage/browsing-the-web.html#she-scroll-position // FIXME: scroll position data, which is scroll position data for the document's restorable scrollable regions diff --git a/Libraries/LibWeb/HTML/SourceSnapshotParams.cpp b/Libraries/LibWeb/HTML/SourceSnapshotParams.cpp new file mode 100644 index 00000000000..95d165385bd --- /dev/null +++ b/Libraries/LibWeb/HTML/SourceSnapshotParams.cpp @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2025, Luke Wilde + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include + +namespace Web::HTML { + +GC_DEFINE_ALLOCATOR(SourceSnapshotParams); + +void SourceSnapshotParams::visit_edges(Cell::Visitor& visitor) +{ + Base::visit_edges(visitor); + visitor.visit(fetch_client); + visitor.visit(source_policy_container); +} + +} diff --git a/Libraries/LibWeb/HTML/SourceSnapshotParams.h b/Libraries/LibWeb/HTML/SourceSnapshotParams.h index 197257a8530..9058c23acad 100644 --- a/Libraries/LibWeb/HTML/SourceSnapshotParams.h +++ b/Libraries/LibWeb/HTML/SourceSnapshotParams.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2023, Aliaksandr Kalenik + * Copyright (c) 2025, Luke Wilde * * SPDX-License-Identifier: BSD-2-Clause */ @@ -12,7 +13,22 @@ namespace Web::HTML { // https://html.spec.whatwg.org/multipage/browsing-the-web.html#source-snapshot-params -struct SourceSnapshotParams { +struct SourceSnapshotParams : public JS::Cell { + GC_CELL(SourceSnapshotParams, JS::Cell) + GC_DECLARE_ALLOCATOR(SourceSnapshotParams); + +public: + SourceSnapshotParams(bool has_transient_activation, SandboxingFlagSet sandboxing_flags, bool allows_downloading, GC::Ref fetch_client, GC::Ref source_policy_container) + : has_transient_activation(has_transient_activation) + , sandboxing_flags(sandboxing_flags) + , allows_downloading(allows_downloading) + , fetch_client(fetch_client) + , source_policy_container(source_policy_container) + { + } + + virtual ~SourceSnapshotParams() = default; + // a boolean bool has_transient_activation; @@ -23,10 +39,13 @@ struct SourceSnapshotParams { bool allows_downloading; // an environment settings object, only to be used as a request client - GC::Ptr fetch_client; + GC::Ref fetch_client; // a policy container - PolicyContainer source_policy_container; + GC::Ref source_policy_container; + +protected: + virtual void visit_edges(Cell::Visitor&) override; }; } diff --git a/Libraries/LibWeb/HTML/TraversableNavigable.cpp b/Libraries/LibWeb/HTML/TraversableNavigable.cpp index 9a00a51a55f..365bf44ae32 100644 --- a/Libraries/LibWeb/HTML/TraversableNavigable.cpp +++ b/Libraries/LibWeb/HTML/TraversableNavigable.cpp @@ -438,7 +438,7 @@ GC_DEFINE_ALLOCATOR(ChangingNavigableContinuationState); TraversableNavigable::HistoryStepResult TraversableNavigable::apply_the_history_step( int step, bool check_for_cancelation, - IGNORE_USE_IN_ESCAPING_LAMBDA Optional source_snapshot_params, + GC::Ptr source_snapshot_params, GC::Ptr initiator_to_check, IGNORE_USE_IN_ESCAPING_LAMBDA UserNavigationInvolvement user_involvement, IGNORE_USE_IN_ESCAPING_LAMBDA Optional navigation_type, @@ -456,7 +456,7 @@ TraversableNavigable::HistoryStepResult TraversableNavigable::apply_the_history_ // 3. If initiatorToCheck is not null, then: if (initiator_to_check != nullptr) { // 1. Assert: sourceSnapshotParams is not null. - VERIFY(source_snapshot_params.has_value()); + VERIFY(source_snapshot_params); // 2. For each navigable of get all navigables whose current session history entry will change or reload: // if initiatorToCheck is not allowed by sandboxing to navigate navigable given sourceSnapshotParams, then return "initiator-disallowed". @@ -628,10 +628,10 @@ TraversableNavigable::HistoryStepResult TraversableNavigable::apply_the_history_ auto target_snapshot_params = navigable->snapshot_target_snapshot_params(); // 3. Let potentiallyTargetSpecificSourceSnapshotParams be sourceSnapshotParams. - Optional potentially_target_specific_source_snapshot_params = source_snapshot_params; + GC::Ptr potentially_target_specific_source_snapshot_params = source_snapshot_params; // 4. If potentiallyTargetSpecificSourceSnapshotParams is null, then set it to the result of snapshotting source snapshot params given navigable's active document. - if (!potentially_target_specific_source_snapshot_params.has_value()) { + if (!potentially_target_specific_source_snapshot_params) { potentially_target_specific_source_snapshot_params = navigable->active_document()->snapshot_source_snapshot_params(); } @@ -1134,17 +1134,17 @@ bool TraversableNavigable::can_go_forward() const } // https://html.spec.whatwg.org/multipage/browsing-the-web.html#traverse-the-history-by-a-delta -void TraversableNavigable::traverse_the_history_by_delta(int delta, Optional source_document) +void TraversableNavigable::traverse_the_history_by_delta(int delta, GC::Ptr source_document) { // 1. Let sourceSnapshotParams and initiatorToCheck be null. - Optional source_snapshot_params = {}; + GC::Ptr source_snapshot_params = nullptr; GC::Ptr initiator_to_check = nullptr; // 2. Let userInvolvement be "browser UI". UserNavigationInvolvement user_involvement = UserNavigationInvolvement::BrowserUI; // 1. If sourceDocument is given, then: - if (source_document.has_value()) { + if (source_document) { // 1. Set sourceSnapshotParams to the result of snapshotting source snapshot params given sourceDocument. source_snapshot_params = source_document->snapshot_source_snapshot_params(); @@ -1156,7 +1156,7 @@ void TraversableNavigable::traverse_the_history_by_delta(int delta, Optional source_snapshot_params, GC::Ptr initiator_to_check, UserNavigationInvolvement user_involvement) +TraversableNavigable::HistoryStepResult TraversableNavigable::apply_the_traverse_history_step(int step, GC::Ptr source_snapshot_params, GC::Ptr initiator_to_check, UserNavigationInvolvement user_involvement) { // 1. Return the result of applying the history step step to traversable given true, sourceSnapshotParams, initiatorToCheck, userInvolvement, and "traverse". - return apply_the_history_step(step, true, move(source_snapshot_params), initiator_to_check, user_involvement, Bindings::NavigationType::Traverse, SynchronousNavigation::No); + return apply_the_history_step(step, true, source_snapshot_params, initiator_to_check, user_involvement, Bindings::NavigationType::Traverse, SynchronousNavigation::No); } // https://html.spec.whatwg.org/multipage/document-sequences.html#close-a-top-level-traversable diff --git a/Libraries/LibWeb/HTML/TraversableNavigable.h b/Libraries/LibWeb/HTML/TraversableNavigable.h index d0d2f23eccb..51a980c8b60 100644 --- a/Libraries/LibWeb/HTML/TraversableNavigable.h +++ b/Libraries/LibWeb/HTML/TraversableNavigable.h @@ -60,7 +60,7 @@ public: Applied, }; - HistoryStepResult apply_the_traverse_history_step(int, Optional, GC::Ptr, UserNavigationInvolvement); + HistoryStepResult apply_the_traverse_history_step(int, GC::Ptr, GC::Ptr, UserNavigationInvolvement); HistoryStepResult apply_the_reload_history_step(UserNavigationInvolvement); enum class SynchronousNavigation : bool { Yes, @@ -76,7 +76,7 @@ public: Vector get_all_used_history_steps() const; void clear_the_forward_session_history(); - void traverse_the_history_by_delta(int delta, Optional source_document = {}); + void traverse_the_history_by_delta(int delta, GC::Ptr source_document = {}); void close_top_level_traversable(); void definitely_close_top_level_traversable(); @@ -125,7 +125,7 @@ private: HistoryStepResult apply_the_history_step( int step, bool check_for_cancelation, - Optional, + GC::Ptr, GC::Ptr initiator_to_check, UserNavigationInvolvement user_involvement, Optional navigation_type, diff --git a/Libraries/LibWeb/HTML/WorkerGlobalScope.cpp b/Libraries/LibWeb/HTML/WorkerGlobalScope.cpp index 12455cd4030..2ade7b02fce 100644 --- a/Libraries/LibWeb/HTML/WorkerGlobalScope.cpp +++ b/Libraries/LibWeb/HTML/WorkerGlobalScope.cpp @@ -1,5 +1,6 @@ /* * Copyright (c) 2022, Andrew Kaster + * Copyright (c) 2025, Luke Wilde * * SPDX-License-Identifier: BSD-2-Clause */ @@ -52,6 +53,7 @@ void WorkerGlobalScope::visit_edges(Cell::Visitor& visitor) visitor.visit(m_internal_port); visitor.visit(m_page); visitor.visit(m_fonts); + visitor.visit(m_policy_container); } void WorkerGlobalScope::finalize() @@ -165,4 +167,13 @@ GC::Ref WorkerGlobalScope::fonts() return *m_fonts; } +GC::Ref WorkerGlobalScope::policy_container() const +{ + auto& realm = this->realm(); + if (!m_policy_container) { + m_policy_container = realm.create(realm); + } + return *m_policy_container; +} + } diff --git a/Libraries/LibWeb/HTML/WorkerGlobalScope.h b/Libraries/LibWeb/HTML/WorkerGlobalScope.h index 181b0d85eda..cdc204ddfb7 100644 --- a/Libraries/LibWeb/HTML/WorkerGlobalScope.h +++ b/Libraries/LibWeb/HTML/WorkerGlobalScope.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2022, Andrew Kaster + * Copyright (c) 2025, Luke Wilde * * SPDX-License-Identifier: BSD-2-Clause */ @@ -92,7 +93,7 @@ public: Web::Page* page() { return m_page.ptr(); } - PolicyContainer policy_container() const { return m_policy_container; } + GC::Ref policy_container() const; bool is_closing() const { return m_closing; } @@ -137,7 +138,7 @@ private: // https://html.spec.whatwg.org/multipage/workers.html#concept-workerglobalscope-policy-container // A WorkerGlobalScope object has an associated policy container (a policy container). It is initially a new policy container. - PolicyContainer m_policy_container; + mutable GC::Ptr m_policy_container; // https://html.spec.whatwg.org/multipage/workers.html#concept-workerglobalscope-embedder-policy // A WorkerGlobalScope object has an associated embedder policy (an embedder policy). diff --git a/Libraries/LibWeb/SVG/SVGDecodedImageData.cpp b/Libraries/LibWeb/SVG/SVGDecodedImageData.cpp index db2191875fc..920a782d74d 100644 --- a/Libraries/LibWeb/SVG/SVGDecodedImageData.cpp +++ b/Libraries/LibWeb/SVG/SVGDecodedImageData.cpp @@ -40,7 +40,7 @@ ErrorOr> SVGDecodedImageData::create(JS::Realm& rea navigation_params->navigable = navigable; navigation_params->response = response; navigation_params->origin = URL::Origin {}; - navigation_params->policy_container = HTML::PolicyContainer {}; + navigation_params->policy_container = navigable->heap().allocate(navigable->active_document()->realm()); navigation_params->final_sandboxing_flag_set = HTML::SandboxingFlagSet {}; navigation_params->opener_policy = HTML::OpenerPolicy {}; diff --git a/Services/WebWorker/DedicatedWorkerHost.cpp b/Services/WebWorker/DedicatedWorkerHost.cpp index 0a28c47d33a..c39c4b3316e 100644 --- a/Services/WebWorker/DedicatedWorkerHost.cpp +++ b/Services/WebWorker/DedicatedWorkerHost.cpp @@ -76,7 +76,7 @@ void DedicatedWorkerHost::run(GC::Ref page, Web::HTML::TransferDataHo // FIXME: support for 'owner' set on WorkerGlobalScope // IMPLEMENTATION DEFINED: We need an object to represent the fetch response's client - auto outside_settings = inner_settings->realm().create(inner_settings->realm_execution_context().copy(), outside_settings_snapshot); + auto outside_settings = inner_settings->realm().create(inner_settings->realm(), inner_settings->realm_execution_context().copy(), outside_settings_snapshot); // 12. If is shared is true, then: if (is_shared) {