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) {