LibWeb: Make a bunch of CSP classes not realm associated

These are not associated with a javascript realm, so to avoid
confusion about which realm these need to be created in, make
all of these objects a GC::Cell, and deal with the fallout.
This commit is contained in:
Shannon Booth 2025-04-26 11:35:51 +12:00 committed by Andreas Kling
commit 8a3c66d8a6
Notes: github-actions[bot] 2025-04-28 10:42:23 +00:00
20 changed files with 91 additions and 92 deletions

View file

@ -19,9 +19,9 @@ Directive::Directive(String name, Vector<String> value)
{
}
GC::Ref<Directive> Directive::clone(JS::Realm& realm) const
GC::Ref<Directive> Directive::clone(GC::Heap& heap) const
{
return create_directive(realm, m_name, m_value);
return create_directive(heap, m_name, m_value);
}
SerializedDirective Directive::serialize() const

View file

@ -17,8 +17,8 @@ namespace Web::ContentSecurityPolicy::Directives {
// https://w3c.github.io/webappsec-csp/#directives
// Each policy contains an ordered set of directives (its directive set), each of which controls a specific behavior.
// The directives defined in this document are described in detail in § 6 Content Security Policy Directives.
class Directive : public JS::Cell {
GC_CELL(Directive, JS::Cell)
class Directive : public GC::Cell {
GC_CELL(Directive, GC::Cell)
GC_DECLARE_ALLOCATOR(Directive);
public:
@ -94,7 +94,7 @@ public:
[[nodiscard]] String const& name() const { return m_name; }
[[nodiscard]] Vector<String> const& value() const { return m_value; }
[[nodiscard]] GC::Ref<Directive> clone(JS::Realm&) const;
[[nodiscard]] GC::Ref<Directive> clone(GC::Heap&) const;
[[nodiscard]] SerializedDirective serialize() const;
protected:

View file

@ -10,10 +10,10 @@
namespace Web::ContentSecurityPolicy::Directives {
GC::Ref<Directive> create_directive(JS::Realm& realm, String name, Vector<String> value)
GC::Ref<Directive> create_directive(GC::Heap& heap, String name, Vector<String> value)
{
dbgln("Potential FIXME: Creating unknown Content Security Policy directive: {}", name);
return realm.create<Directive>(move(name), move(value));
return heap.allocate<Directive>(move(name), move(value));
}
}

View file

@ -8,11 +8,12 @@
#include <AK/String.h>
#include <AK/Vector.h>
#include <LibGC/Forward.h>
#include <LibGC/Ptr.h>
#include <LibWeb/Forward.h>
namespace Web::ContentSecurityPolicy::Directives {
[[nodiscard]] GC::Ref<Directive> create_directive(JS::Realm&, String name, Vector<String> value);
[[nodiscard]] GC::Ref<Directive> create_directive(GC::Heap&, String name, Vector<String> value);
}

View file

@ -21,7 +21,7 @@ namespace Web::ContentSecurityPolicy {
GC_DEFINE_ALLOCATOR(Policy);
// https://w3c.github.io/webappsec-csp/#abstract-opdef-parse-a-serialized-csp
GC::Ref<Policy> Policy::parse_a_serialized_csp(JS::Realm& realm, Variant<ByteBuffer, String> serialized, Source source, Disposition disposition)
GC::Ref<Policy> Policy::parse_a_serialized_csp(GC::Heap& heap, Variant<ByteBuffer, String> serialized, Source source, Disposition disposition)
{
// To parse a serialized CSP, given a byte sequence or string serialized, a source source, and a disposition disposition,
// execute the following steps.
@ -34,14 +34,14 @@ GC::Ref<Policy> Policy::parse_a_serialized_csp(JS::Realm& realm, Variant<ByteBuf
: Infra::isomorphic_decode(serialized.get<ByteBuffer>());
// 2. Let policy be a new policy with an empty directive set, a source of source, and a disposition of disposition.
auto policy = realm.create<Policy>();
auto policy = heap.allocate<Policy>();
policy->m_pre_parsed_policy_string = serialized_string;
policy->m_source = source;
policy->m_disposition = disposition;
// 3. For each token returned by strictly splitting serialized on the U+003B SEMICOLON character (;):
auto tokens = MUST(serialized_string.split(';', SplitBehavior::KeepEmpty));
for (auto token : tokens) {
for (auto const& token : tokens) {
// 1. Strip leading and trailing ASCII whitespace from token.
auto stripped_token = MUST(token.trim(Infra::ASCII_WHITESPACE));
auto stripped_token_view = stripped_token.bytes_as_string_view();
@ -79,7 +79,7 @@ GC::Ref<Policy> Policy::parse_a_serialized_csp(JS::Realm& realm, Variant<ByteBuf
}
// 7. Let directive be a new directive whose name is directive name, and value is directive value.
auto directive = Directives::create_directive(realm, move(lowercase_directive_name), move(directive_value));
auto directive = Directives::create_directive(heap, move(lowercase_directive_name), move(directive_value));
// 8. Append directive to policys directive set.
policy->m_directives.append(directive);
@ -90,22 +90,22 @@ GC::Ref<Policy> Policy::parse_a_serialized_csp(JS::Realm& realm, Variant<ByteBuf
}
// https://w3c.github.io/webappsec-csp/#abstract-opdef-parse-a-responses-content-security-policies
GC::Ref<PolicyList> Policy::parse_a_responses_content_security_policies(JS::Realm& realm, GC::Ref<Fetch::Infrastructure::Response const> response)
GC::Ref<PolicyList> Policy::parse_a_responses_content_security_policies(GC::Heap& heap, GC::Ref<Fetch::Infrastructure::Response const> response)
{
// To parse a responses Content Security Policies given a response response, execute the following steps.
// This algorithm returns a list of Content Security Policy objects. If the policies cannot be parsed,
// the returned list will be empty.
// 1. Let policies be an empty list.
GC::RootVector<GC::Ref<Policy>> policies(realm.heap());
GC::RootVector<GC::Ref<Policy>> policies(heap);
// 2. For each token returned by extracting header list values given Content-Security-Policy and responses header
// list:
auto enforce_policy_tokens_or_failure = Fetch::Infrastructure::extract_header_list_values("Content-Security-Policy"sv.bytes(), response->header_list());
auto enforce_policy_tokens = enforce_policy_tokens_or_failure.has<Vector<ByteBuffer>>() ? enforce_policy_tokens_or_failure.get<Vector<ByteBuffer>>() : Vector<ByteBuffer> {};
for (auto enforce_policy_token : enforce_policy_tokens) {
for (auto const& enforce_policy_token : enforce_policy_tokens) {
// 1. Let policy be the result of parsing token, with a source of "header", and a disposition of "enforce".
auto policy = parse_a_serialized_csp(realm, enforce_policy_token, Policy::Source::Header, Policy::Disposition::Enforce);
auto policy = parse_a_serialized_csp(heap, enforce_policy_token, Policy::Source::Header, Policy::Disposition::Enforce);
// 2. If policys directive set is not empty, append policy to policies.
if (!policy->m_directives.is_empty()) {
@ -117,9 +117,9 @@ GC::Ref<PolicyList> Policy::parse_a_responses_content_security_policies(JS::Real
// responses header list:
auto report_policy_tokens_or_failure = Fetch::Infrastructure::extract_header_list_values("Content-Security-Policy-Report-Only"sv.bytes(), response->header_list());
auto report_policy_tokens = report_policy_tokens_or_failure.has<Vector<ByteBuffer>>() ? report_policy_tokens_or_failure.get<Vector<ByteBuffer>>() : Vector<ByteBuffer> {};
for (auto report_policy_token : report_policy_tokens) {
for (auto const& report_policy_token : report_policy_tokens) {
// 1. Let policy be the result of parsing token, with a source of "header", and a disposition of "report".
auto policy = parse_a_serialized_csp(realm, report_policy_token, Policy::Source::Header, Policy::Disposition::Report);
auto policy = parse_a_serialized_csp(heap, report_policy_token, Policy::Source::Header, Policy::Disposition::Report);
// 2. If policys directive set is not empty, append policy to policies.
if (!policy->m_directives.is_empty()) {
@ -134,15 +134,15 @@ GC::Ref<PolicyList> Policy::parse_a_responses_content_security_policies(JS::Real
}
// 5. Return policies.
return PolicyList::create(realm, policies);
return PolicyList::create(heap, policies);
}
GC::Ref<Policy> Policy::create_from_serialized_policy(JS::Realm& realm, SerializedPolicy const& serialized_policy)
GC::Ref<Policy> Policy::create_from_serialized_policy(GC::Heap& heap, SerializedPolicy const& serialized_policy)
{
auto policy = realm.create<Policy>();
auto policy = heap.allocate<Policy>();
for (auto const& serialized_directive : serialized_policy.directives) {
auto directive = Directives::create_directive(realm, serialized_directive.name, serialized_directive.value);
auto directive = Directives::create_directive(heap, serialized_directive.name, serialized_directive.value);
policy->m_directives.append(directive);
}
@ -173,12 +173,12 @@ GC::Ptr<Directives::Directive> Policy::get_directive_by_name(StringView name) co
return nullptr;
}
GC::Ref<Policy> Policy::clone(JS::Realm& realm) const
GC::Ref<Policy> Policy::clone(GC::Heap& heap) const
{
auto policy = realm.create<Policy>();
auto policy = heap.allocate<Policy>();
for (auto directive : m_directives) {
auto cloned_directive = directive->clone(realm);
auto cloned_directive = directive->clone(heap);
policy->m_directives.append(cloned_directive);
}

View file

@ -20,8 +20,8 @@ namespace Web::ContentSecurityPolicy {
// https://w3c.github.io/webappsec-csp/#content-security-policy-object
// A policy defines allowed and restricted behaviors, and may be applied to a Document, WorkerGlobalScope,
// or WorkletGlobalScope.
class Policy final : public JS::Cell {
GC_CELL(Policy, JS::Cell);
class Policy final : public GC::Cell {
GC_CELL(Policy, GC::Cell);
GC_DECLARE_ALLOCATOR(Policy);
public:
@ -38,9 +38,9 @@ public:
~Policy() = default;
[[nodiscard]] static GC::Ref<Policy> parse_a_serialized_csp(JS::Realm&, Variant<ByteBuffer, String> serialized, Source source, Disposition disposition);
[[nodiscard]] static GC::Ref<PolicyList> parse_a_responses_content_security_policies(JS::Realm&, GC::Ref<Fetch::Infrastructure::Response const> response);
[[nodiscard]] static GC::Ref<Policy> create_from_serialized_policy(JS::Realm&, SerializedPolicy const&);
[[nodiscard]] static GC::Ref<Policy> parse_a_serialized_csp(GC::Heap&, Variant<ByteBuffer, String> serialized, Source source, Disposition disposition);
[[nodiscard]] static GC::Ref<PolicyList> parse_a_responses_content_security_policies(GC::Heap&, GC::Ref<Fetch::Infrastructure::Response const> response);
[[nodiscard]] static GC::Ref<Policy> create_from_serialized_policy(GC::Heap&, SerializedPolicy const&);
[[nodiscard]] Vector<GC::Ref<Directives::Directive>> const& directives() const { return m_directives; }
[[nodiscard]] Disposition disposition() const { return m_disposition; }
@ -51,7 +51,7 @@ public:
[[nodiscard]] bool contains_directive_with_name(StringView name) const;
[[nodiscard]] GC::Ptr<Directives::Directive> get_directive_by_name(StringView) const;
[[nodiscard]] GC::Ref<Policy> clone(JS::Realm&) const;
[[nodiscard]] GC::Ref<Policy> clone(GC::Heap&) const;
[[nodiscard]] SerializedPolicy serialize() const;
protected:

View file

@ -18,19 +18,19 @@ namespace Web::ContentSecurityPolicy {
GC_DEFINE_ALLOCATOR(PolicyList);
GC::Ref<PolicyList> PolicyList::create(JS::Realm& realm, GC::RootVector<GC::Ref<Policy>> const& policies)
GC::Ref<PolicyList> PolicyList::create(GC::Heap& heap, GC::RootVector<GC::Ref<Policy>> const& policies)
{
auto policy_list = realm.create<PolicyList>();
auto policy_list = heap.allocate<PolicyList>();
for (auto policy : policies)
policy_list->m_policies.append(policy);
return policy_list;
}
GC::Ref<PolicyList> PolicyList::create(JS::Realm& realm, Vector<SerializedPolicy> const& serialized_policies)
GC::Ref<PolicyList> PolicyList::create(GC::Heap& heap, Vector<SerializedPolicy> const& serialized_policies)
{
auto policy_list = realm.create<PolicyList>();
auto policy_list = heap.allocate<PolicyList>();
for (auto const& serialized_policy : serialized_policies) {
auto policy = Policy::create_from_serialized_policy(realm, serialized_policy);
auto policy = Policy::create_from_serialized_policy(heap, serialized_policy);
policy_list->m_policies.append(policy);
}
return policy_list;
@ -79,11 +79,11 @@ HTML::SandboxingFlagSet PolicyList::csp_derived_sandboxing_flags() const
return HTML::SandboxingFlagSet {};
}
GC::Ref<PolicyList> PolicyList::clone(JS::Realm& realm) const
GC::Ref<PolicyList> PolicyList::clone(GC::Heap& heap) const
{
auto policy_list = realm.create<PolicyList>();
auto policy_list = heap.allocate<PolicyList>();
for (auto policy : m_policies) {
auto cloned_policy = policy->clone(realm);
auto cloned_policy = policy->clone(heap);
policy_list->m_policies.append(cloned_policy);
}
return policy_list;

View file

@ -12,13 +12,13 @@
namespace Web::ContentSecurityPolicy {
class PolicyList final : public JS::Cell {
GC_CELL(PolicyList, JS::Cell);
class PolicyList final : public GC::Cell {
GC_CELL(PolicyList, GC::Cell);
GC_DECLARE_ALLOCATOR(PolicyList);
public:
[[nodiscard]] static GC::Ref<PolicyList> create(JS::Realm&, GC::RootVector<GC::Ref<Policy>> const&);
[[nodiscard]] static GC::Ref<PolicyList> create(JS::Realm&, Vector<SerializedPolicy> const&);
[[nodiscard]] static GC::Ref<PolicyList> create(GC::Heap&, GC::RootVector<GC::Ref<Policy>> const&);
[[nodiscard]] static GC::Ref<PolicyList> create(GC::Heap&, Vector<SerializedPolicy> const&);
[[nodiscard]] static GC::Ptr<PolicyList> from_object(JS::Object&);
virtual ~PolicyList() = default;
@ -29,7 +29,7 @@ public:
[[nodiscard]] HTML::SandboxingFlagSet csp_derived_sandboxing_flags() const;
[[nodiscard]] GC::Ref<PolicyList> clone(JS::Realm&) const;
[[nodiscard]] GC::Ref<PolicyList> clone(GC::Heap&) const;
[[nodiscard]] Vector<SerializedPolicy> serialize() const;
protected: