Add top-level creation URL for global scope (#37342)

Global scopes have two creation URLs: one for itself and one for the
"top-level" scope. It's not immediately obvious what is considered
top-level here (it is not strictly defined in the specification).

In any case, reports need the creation URL of the scope itself, not the
top-level version. Therefore, propagate this information from all
scopes, where the worker and worklets remain to pass in `None` for their
top-level scope.

Part of #37328

---------

Signed-off-by: Tim van der Lippe <tvanderlippe@gmail.com>
This commit is contained in:
Tim van der Lippe 2025-06-20 09:07:28 +02:00 committed by GitHub
parent a426a2e884
commit d70f6ace24
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 50 additions and 12 deletions

View file

@ -61,6 +61,7 @@ impl DissimilarOriginWindow {
global_to_clone_from.resource_threads().clone(),
global_to_clone_from.origin().clone(),
global_to_clone_from.creation_url().clone(),
global_to_clone_from.top_level_creation_url().clone(),
// FIXME(nox): The microtask queue is probably not important
// here, but this whole DOM interface is a hack anyway.
global_to_clone_from.microtask_queue().clone(),

View file

@ -283,7 +283,11 @@ pub(crate) struct GlobalScope {
/// <https://html.spec.whatwg.org/multipage/#concept-environment-creation-url>
#[no_trace]
creation_url: Option<ServoUrl>,
creation_url: ServoUrl,
/// <https://html.spec.whatwg.org/multipage/#concept-environment-top-level-creation-url>
#[no_trace]
top_level_creation_url: Option<ServoUrl>,
/// A map for storing the previous permission state read results.
permission_state_invocation_results: DomRefCell<HashMap<PermissionName, PermissionState>>,
@ -740,7 +744,8 @@ impl GlobalScope {
script_to_constellation_chan: ScriptToConstellationChan,
resource_threads: ResourceThreads,
origin: MutableOrigin,
creation_url: Option<ServoUrl>,
creation_url: ServoUrl,
top_level_creation_url: Option<ServoUrl>,
microtask_queue: Rc<MicrotaskQueue>,
#[cfg(feature = "webgpu")] gpu_id_hub: Arc<IdentityHub>,
inherited_secure_context: Option<bool>,
@ -769,6 +774,7 @@ impl GlobalScope {
timers: OnceCell::default(),
origin,
creation_url,
top_level_creation_url,
permission_state_invocation_results: Default::default(),
microtask_queue,
list_auto_close_worker: Default::default(),
@ -2474,10 +2480,15 @@ impl GlobalScope {
}
/// Get the creation_url for this global scope
pub(crate) fn creation_url(&self) -> &Option<ServoUrl> {
pub(crate) fn creation_url(&self) -> &ServoUrl {
&self.creation_url
}
/// Get the top_level_creation_url for this global scope
pub(crate) fn top_level_creation_url(&self) -> &Option<ServoUrl> {
&self.top_level_creation_url
}
pub(crate) fn image_cache(&self) -> Arc<dyn ImageCache> {
if let Some(window) = self.downcast::<Window>() {
return window.image_cache();
@ -3525,13 +3536,30 @@ impl GlobalScope {
if Some(false) == self.inherited_secure_context {
return false;
}
if let Some(creation_url) = self.creation_url() {
if creation_url.scheme() == "blob" && Some(true) == self.inherited_secure_context {
return true;
}
return creation_url.is_potentially_trustworthy();
// Step 1. If environment is an environment settings object, then:
// Step 1.1. Let global be environment's global object.
match self.top_level_creation_url() {
None => {
// Workers and worklets don't have a top-level creation URL
assert!(
self.downcast::<WorkerGlobalScope>().is_some() ||
self.downcast::<WorkletGlobalScope>().is_some()
);
true
},
Some(top_level_creation_url) => {
assert!(self.downcast::<Window>().is_some());
// Step 2. If the result of Is url potentially trustworthy?
// given environment's top-level creation URL is "Potentially Trustworthy", then return true.
// Step 3. Return false.
if top_level_creation_url.scheme() == "blob" &&
Some(true) == self.inherited_secure_context
{
return true;
}
top_level_creation_url.is_potentially_trustworthy()
},
}
false
}
/// <https://www.w3.org/TR/CSP/#get-csp-of-object>

View file

@ -3052,7 +3052,8 @@ impl Window {
parent_info: Option<PipelineId>,
viewport_details: ViewportDetails,
origin: MutableOrigin,
creator_url: ServoUrl,
creation_url: ServoUrl,
top_level_creation_url: ServoUrl,
navigation_start: CrossProcessInstant,
webgl_chan: Option<WebGLChan>,
#[cfg(feature = "webxr")] webxr_registry: Option<webxr_api::Registry>,
@ -3088,7 +3089,8 @@ impl Window {
constellation_chan,
resource_threads,
origin,
Some(creator_url),
creation_url,
Some(top_level_creation_url),
microtask_queue,
#[cfg(feature = "webgpu")]
gpu_id_hub,

View file

@ -171,6 +171,7 @@ impl WorkerGlobalScope {
init.resource_threads,
MutableOrigin::new(init.origin),
init.creation_url,
None,
runtime.microtask_queue.clone(),
#[cfg(feature = "webgpu")]
gpu_id_hub,

View file

@ -104,6 +104,7 @@ impl WorkletGlobalScope {
script_to_constellation_chan,
init.resource_threads.clone(),
MutableOrigin::new(ImmutableOrigin::new_opaque()),
base_url.clone(),
None,
Default::default(),
#[cfg(feature = "webgpu")]

View file

@ -3395,6 +3395,11 @@ impl ScriptThread {
incomplete.viewport_details,
origin.clone(),
final_url.clone(),
// TODO(37417): Set correct top-level URL here. Currently, we only specify the
// url of the current window. However, in case this is an iframe, we should
// pass in the URL from the frame that includes the iframe (which potentially
// is another nested iframe in a frame).
final_url.clone(),
incomplete.navigation_start,
self.webgl_chan.as_ref().map(|chan| chan.channel()),
#[cfg(feature = "webxr")]

View file

@ -443,7 +443,7 @@ pub struct WorkerGlobalScopeInit {
/// The origin
pub origin: ImmutableOrigin,
/// The creation URL
pub creation_url: Option<ServoUrl>,
pub creation_url: ServoUrl,
/// True if secure context
pub inherited_secure_context: Option<bool>,
}