Skip to content

Commit

Permalink
LibWeb: Make PolicyContainer GC allocated
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
Lubrsi authored and AtkinsSJ committed Feb 21, 2025
1 parent 2e27ffa commit cae0ab2
Show file tree
Hide file tree
Showing 43 changed files with 382 additions and 131 deletions.
2 changes: 2 additions & 0 deletions Libraries/LibWeb/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
59 changes: 34 additions & 25 deletions Libraries/LibWeb/DOM/Document.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
* Copyright (c) 2018-2024, Andreas Kling <andreas@ladybird.org>
* Copyright (c) 2021-2023, Linus Groh <linusg@serenityos.org>
* Copyright (c) 2021-2023, Luke Wilde <lukew@serenityos.org>
* Copyright (c) 2021-2025, Luke Wilde <luke@ladybird.org>
* Copyright (c) 2021-2024, Sam Atkins <sam@ladybird.org>
* Copyright (c) 2024, Matthew Olsson <mattco@serenityos.org>
* Copyright (c) 2025, Jelle Raaijmakers <jelle@ladybird.org>
Expand Down Expand Up @@ -118,6 +118,7 @@
#include <LibWeb/HTML/NavigationParams.h>
#include <LibWeb/HTML/Numbers.h>
#include <LibWeb/HTML/Parser/HTMLParser.h>
#include <LibWeb/HTML/PolicyContainers.h>
#include <LibWeb/HTML/PopStateEvent.h>
#include <LibWeb/HTML/Scripting/Agent.h>
#include <LibWeb/HTML/Scripting/ClassicScript.h>
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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<HTML::PolicyContainer> Document::policy_container() const
{
return m_policy_container;
auto& realm = this->realm();
if (!m_policy_container) {
m_policy_container = realm.create<HTML::PolicyContainer>(realm);
}
return *m_policy_container;
}

void Document::set_policy_container(HTML::PolicyContainer policy_container)
void Document::set_policy_container(GC::Ref<HTML::PolicyContainer> 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<HTML::SourceSnapshotParams> Document::snapshot_source_snapshot_params() const
{
// To snapshot source snapshot params given a Document sourceDocument, return a new source snapshot params with
auto& realm = this->realm();

// 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

return HTML::SourceSnapshotParams {
.has_transient_activation = as<HTML::Window>(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
};
// To snapshot source snapshot params given a Document sourceDocument, return a new source snapshot params with
return realm.create<HTML::SourceSnapshotParams>(
// has transient activation
// true if sourceDocument's relevant global object has transient activation; otherwise false
as<HTML::Window>(HTML::relevant_global_object(*this)).has_transient_activation(),

// sandboxing flags
// sourceDocument's active sandboxing flag set
m_active_sandboxing_flag_set,

// 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
Expand Down
8 changes: 4 additions & 4 deletions Libraries/LibWeb/DOM/Document.h
Original file line number Diff line number Diff line change
Expand Up @@ -548,8 +548,8 @@ class Document
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<HTML::PolicyContainer> policy_container() const;
void set_policy_container(GC::Ref<HTML::PolicyContainer>);

Vector<GC::Root<HTML::Navigable>> descendant_navigables();
Vector<GC::Root<HTML::Navigable>> const descendant_navigables() const;
Expand Down Expand Up @@ -635,7 +635,7 @@ class Document

u32 unload_counter() const { return m_unload_counter; }

HTML::SourceSnapshotParams snapshot_source_snapshot_params() const;
GC::Ref<HTML::SourceSnapshotParams> snapshot_source_snapshot_params() const;

void update_for_history_step_application(GC::Ref<HTML::SessionHistoryEntry>, bool do_not_reactivate, size_t script_history_length, size_t script_history_index, Optional<Bindings::NavigationType> navigation_type, Optional<Vector<GC::Ref<HTML::SessionHistoryEntry>>> entries_for_navigation_api = {}, GC::Ptr<HTML::SessionHistoryEntry> previous_entry_for_activation = {}, bool update_navigation_api = true);

Expand Down Expand Up @@ -1018,7 +1018,7 @@ class Document
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<HTML::PolicyContainer> m_policy_container;

// https://html.spec.whatwg.org/multipage/interaction.html#visibility-state
HTML::VisibilityState m_visibility_state { HTML::VisibilityState::Hidden };
Expand Down
4 changes: 3 additions & 1 deletion Libraries/LibWeb/DOM/DocumentLoading.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ template<typename MutateDocument>
GC::Ref<DOM::Document> create_document_for_inline_content(GC::Ptr<HTML::Navigable> navigable, Optional<String> 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 {};
Expand Down Expand Up @@ -66,7 +68,7 @@ GC::Ref<DOM::Document> create_document_for_inline_content(GC::Ptr<HTML::Navigabl
navigation_params->coop_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<HTML::PolicyContainer>(realm);
navigation_params->final_sandboxing_flag_set = HTML::SandboxingFlagSet {};
navigation_params->opener_policy = move(coop);
navigation_params->about_base_url = {};
Expand Down
8 changes: 4 additions & 4 deletions Libraries/LibWeb/Fetch/Fetching/Fetching.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -181,10 +181,10 @@ WebIDL::ExceptionOr<GC::Ref<Infrastructure::FetchController>> 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<HTML::PolicyContainer>(realm));
}

// 13. If request’s header list does not contain `Accept`, then:
Expand Down Expand Up @@ -301,8 +301,8 @@ WebIDL::ExceptionOr<GC::Ptr<PendingResponse>> 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<HTML::PolicyContainer>());
request->set_referrer_policy(request->policy_container().get<HTML::PolicyContainer>().referrer_policy);
VERIFY(request->policy_container().has<GC::Ref<HTML::PolicyContainer>>());
request->set_referrer_policy(request->policy_container().get<GC::Ref<HTML::PolicyContainer>>()->referrer_policy);
}

// 9. If request’s referrer is not "no-referrer", then set request’s referrer to the result of invoking determine
Expand Down
5 changes: 4 additions & 1 deletion Libraries/LibWeb/Fetch/Infrastructure/HTTP/Requests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ void Request::visit_edges(JS::Cell::Visitor& visitor)
[&](GC::Ptr<HTML::EnvironmentSettingsObject> const& value) { visitor.visit(value); },
[](auto const&) {});
visitor.visit(m_pending_responses);
m_policy_container.visit(
[&](GC::Ref<HTML::PolicyContainer> const& policy_container) { visitor.visit(policy_container); },
[](auto const&) {});
}

GC::Ref<Request> Request::create(JS::VM& vm)
Expand Down Expand Up @@ -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<HTML::PolicyContainer>() && m_policy_container.get<HTML::PolicyContainer>().embedder_policy.value != HTML::EmbedderPolicyValue::Credentialless)
if (m_policy_container.has<GC::Ref<HTML::PolicyContainer>>() && m_policy_container.get<GC::Ref<HTML::PolicyContainer>>()->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.
Expand Down
2 changes: 1 addition & 1 deletion Libraries/LibWeb/Fetch/Infrastructure/HTTP/Requests.h
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ class Request final : public JS::Cell {

using BodyType = Variant<Empty, ByteBuffer, GC::Ref<Body>>;
using OriginType = Variant<Origin, URL::Origin>;
using PolicyContainerType = Variant<PolicyContainer, HTML::PolicyContainer>;
using PolicyContainerType = Variant<PolicyContainer, GC::Ref<HTML::PolicyContainer>>;
using ReferrerType = Variant<Referrer, URL::URL>;
using ReservedClientType = GC::Ptr<HTML::Environment>;
using WindowType = Variant<Window, GC::Ptr<HTML::EnvironmentSettingsObject>>;
Expand Down
1 change: 1 addition & 0 deletions Libraries/LibWeb/Forward.h
Original file line number Diff line number Diff line change
Expand Up @@ -583,6 +583,7 @@ struct POSTResource;
struct ScrollOptions;
struct ScrollToOptions;
struct SerializedFormData;
struct SerializedPolicyContainer;
struct StructuredSerializeOptions;
struct SyntheticRealmSettings;
struct ToggleTaskTracker;
Expand Down
2 changes: 1 addition & 1 deletion Libraries/LibWeb/HTML/BrowsingContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,7 @@ WebIDL::ExceptionOr<BrowsingContext::BrowsingContextAndDocument> 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)) {
Expand Down
3 changes: 3 additions & 0 deletions Libraries/LibWeb/HTML/DocumentState.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<PolicyContainer> const& policy_container) { visitor.visit(policy_container); },
[](auto const&) {});
for (auto& nested_history : m_nested_histories) {
visitor.visit(nested_history.entries);
}
Expand Down
6 changes: 3 additions & 3 deletions Libraries/LibWeb/HTML/DocumentState.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ class DocumentState final : public JS::Cell {
[[nodiscard]] GC::Ptr<DOM::Document> document() const { return m_document; }
void set_document(GC::Ptr<DOM::Document> document) { m_document = document; }

[[nodiscard]] Variant<PolicyContainer, Client> history_policy_container() const { return m_history_policy_container; }
void set_history_policy_container(Variant<PolicyContainer, Client> history_policy_container) { m_history_policy_container = move(history_policy_container); }
[[nodiscard]] Variant<GC::Ref<PolicyContainer>, Client> history_policy_container() const { return m_history_policy_container; }
void set_history_policy_container(Variant<GC::Ref<PolicyContainer>, 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); }
Expand Down Expand Up @@ -82,7 +82,7 @@ class DocumentState final : public JS::Cell {
GC::Ptr<DOM::Document> m_document;

// https://html.spec.whatwg.org/multipage/browsing-the-web.html#document-state-history-policy-container
Variant<PolicyContainer, Client> m_history_policy_container { Client::Tag };
Variant<GC::Ref<PolicyContainer>, 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 };
Expand Down
31 changes: 31 additions & 0 deletions Libraries/LibWeb/HTML/EmbedderPolicy.cpp
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
/*
* Copyright (c) 2024, Jamie Mansfield <jmansfield@cadixdev.org>
* Copyright (c) 2025, Luke Wilde <luke@ladybird.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/

#include <LibIPC/Decoder.h>
#include <LibIPC/Encoder.h>
#include <LibWeb/HTML/EmbedderPolicy.h>

namespace Web::HTML {
Expand Down Expand Up @@ -33,3 +36,31 @@ Optional<EmbedderPolicyValue> embedder_policy_value_from_string(StringView strin
}

}

namespace IPC {

template<>
ErrorOr<void> 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<Web::HTML::EmbedderPolicy> decode(Decoder& decoder)
{
Web::HTML::EmbedderPolicy embedder_policy {};

embedder_policy.value = TRY(decoder.decode<Web::HTML::EmbedderPolicyValue>());
embedder_policy.reporting_endpoint = TRY(decoder.decode<String>());
embedder_policy.report_only_value = TRY(decoder.decode<Web::HTML::EmbedderPolicyValue>());
embedder_policy.report_only_reporting_endpoint = TRY(decoder.decode<String>());

return embedder_policy;
}

}
12 changes: 12 additions & 0 deletions Libraries/LibWeb/HTML/EmbedderPolicy.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2024, Jamie Mansfield <jmansfield@cadixdev.org>
* Copyright (c) 2025, Luke Wilde <luke@ladybird.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
Expand All @@ -9,6 +10,7 @@
#include <AK/Optional.h>
#include <AK/String.h>
#include <AK/StringView.h>
#include <LibIPC/Forward.h>

namespace Web::HTML {

Expand Down Expand Up @@ -42,3 +44,13 @@ struct EmbedderPolicy {
};

}

namespace IPC {

template<>
ErrorOr<void> encode(Encoder&, Web::HTML::EmbedderPolicy const&);

template<>
ErrorOr<Web::HTML::EmbedderPolicy> decode(Decoder&);

}
2 changes: 1 addition & 1 deletion Libraries/LibWeb/HTML/HTMLLinkElement.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,7 @@ GC::Ptr<Fetch::Infrastructure::Request> 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);
Expand Down
2 changes: 1 addition & 1 deletion Libraries/LibWeb/HTML/HTMLLinkElement.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ class HTMLLinkElement final
GC::Ptr<HTML::EnvironmentSettingsObject> environment;
// policy container
// A policy container
HTML::PolicyContainer policy_container;
GC::Ptr<HTML::PolicyContainer> policy_container;
// document (default null)
// Null or a Document
GC::Ptr<Web::DOM::Document> document;
Expand Down
Loading

0 comments on commit cae0ab2

Please sign in to comment.