Implement trusted types for setTimeout/setInterval (#38736)

I had a difficult time figuring out where the relevant steps had to be
added. Therefore, I aggressively commented the spec steps so eventually
I discovered where I should add them.

Part of #36258

---------

Signed-off-by: Tim van der Lippe <tvanderlippe@gmail.com>
Signed-off-by: Tim van der Lippe <TimvdLippe@users.noreply.github.com>
Co-authored-by: Josh Matthews <josh@joshmatthews.net>
This commit is contained in:
Tim van der Lippe 2025-08-17 22:53:16 +02:00 committed by GitHub
parent a31235e52b
commit 4de9a9d100
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
16 changed files with 149 additions and 120 deletions

View file

@ -2894,7 +2894,8 @@ impl GlobalScope {
arguments: Vec<HandleValue>,
timeout: Duration,
is_interval: IsInterval,
) -> i32 {
can_gc: CanGc,
) -> Fallible<i32> {
self.timers().set_timeout_or_interval(
self,
callback,
@ -2902,6 +2903,7 @@ impl GlobalScope {
timeout,
is_interval,
self.timer_source(),
can_gc,
)
}

View file

@ -110,7 +110,9 @@ use crate::dom::bindings::codegen::Bindings::WindowBinding::{
self, FrameRequestCallback, ScrollBehavior, ScrollToOptions, WindowMethods,
WindowPostMessageOptions,
};
use crate::dom::bindings::codegen::UnionTypes::{RequestOrUSVString, StringOrFunction};
use crate::dom::bindings::codegen::UnionTypes::{
RequestOrUSVString, TrustedScriptOrString, TrustedScriptOrStringOrFunction,
};
use crate::dom::bindings::error::{Error, ErrorResult, Fallible};
use crate::dom::bindings::inheritance::{Castable, ElementTypeId, HTMLElementTypeId, NodeTypeId};
use crate::dom::bindings::num::Finite;
@ -1098,23 +1100,30 @@ impl WindowMethods<crate::DomTypeHolder> for Window {
.or_init(|| Navigator::new(self, CanGc::note()))
}
// https://html.spec.whatwg.org/multipage/#dom-windowtimers-settimeout
// https://html.spec.whatwg.org/multipage/#dom-settimeout
fn SetTimeout(
&self,
_cx: JSContext,
callback: StringOrFunction,
callback: TrustedScriptOrStringOrFunction,
timeout: i32,
args: Vec<HandleValue>,
) -> i32 {
can_gc: CanGc,
) -> Fallible<i32> {
let callback = match callback {
StringOrFunction::String(i) => TimerCallback::StringTimerCallback(i),
StringOrFunction::Function(i) => TimerCallback::FunctionTimerCallback(i),
TrustedScriptOrStringOrFunction::String(i) => {
TimerCallback::StringTimerCallback(TrustedScriptOrString::String(i))
},
TrustedScriptOrStringOrFunction::TrustedScript(i) => {
TimerCallback::StringTimerCallback(TrustedScriptOrString::TrustedScript(i))
},
TrustedScriptOrStringOrFunction::Function(i) => TimerCallback::FunctionTimerCallback(i),
};
self.as_global_scope().set_timeout_or_interval(
callback,
args,
Duration::from_millis(timeout.max(0) as u64),
IsInterval::NonInterval,
can_gc,
)
}
@ -1127,19 +1136,26 @@ impl WindowMethods<crate::DomTypeHolder> for Window {
fn SetInterval(
&self,
_cx: JSContext,
callback: StringOrFunction,
callback: TrustedScriptOrStringOrFunction,
timeout: i32,
args: Vec<HandleValue>,
) -> i32 {
can_gc: CanGc,
) -> Fallible<i32> {
let callback = match callback {
StringOrFunction::String(i) => TimerCallback::StringTimerCallback(i),
StringOrFunction::Function(i) => TimerCallback::FunctionTimerCallback(i),
TrustedScriptOrStringOrFunction::String(i) => {
TimerCallback::StringTimerCallback(TrustedScriptOrString::String(i))
},
TrustedScriptOrStringOrFunction::TrustedScript(i) => {
TimerCallback::StringTimerCallback(TrustedScriptOrString::TrustedScript(i))
},
TrustedScriptOrStringOrFunction::Function(i) => TimerCallback::FunctionTimerCallback(i),
};
self.as_global_scope().set_timeout_or_interval(
callback,
args,
Duration::from_millis(timeout.max(0) as u64),
IsInterval::Interval,
can_gc,
)
}

View file

@ -42,7 +42,8 @@ use crate::dom::bindings::codegen::Bindings::VoidFunctionBinding::VoidFunction;
use crate::dom::bindings::codegen::Bindings::WorkerBinding::WorkerType;
use crate::dom::bindings::codegen::Bindings::WorkerGlobalScopeBinding::WorkerGlobalScopeMethods;
use crate::dom::bindings::codegen::UnionTypes::{
RequestOrUSVString, StringOrFunction, TrustedScriptURLOrUSVString,
RequestOrUSVString, TrustedScriptOrString, TrustedScriptOrStringOrFunction,
TrustedScriptURLOrUSVString,
};
use crate::dom::bindings::error::{Error, ErrorResult, Fallible, report_pending_exception};
use crate::dom::bindings::inheritance::Castable;
@ -485,19 +486,26 @@ impl WorkerGlobalScopeMethods<crate::DomTypeHolder> for WorkerGlobalScope {
fn SetTimeout(
&self,
_cx: JSContext,
callback: StringOrFunction,
callback: TrustedScriptOrStringOrFunction,
timeout: i32,
args: Vec<HandleValue>,
) -> i32 {
can_gc: CanGc,
) -> Fallible<i32> {
let callback = match callback {
StringOrFunction::String(i) => TimerCallback::StringTimerCallback(i),
StringOrFunction::Function(i) => TimerCallback::FunctionTimerCallback(i),
TrustedScriptOrStringOrFunction::String(i) => {
TimerCallback::StringTimerCallback(TrustedScriptOrString::String(i))
},
TrustedScriptOrStringOrFunction::TrustedScript(i) => {
TimerCallback::StringTimerCallback(TrustedScriptOrString::TrustedScript(i))
},
TrustedScriptOrStringOrFunction::Function(i) => TimerCallback::FunctionTimerCallback(i),
};
self.upcast::<GlobalScope>().set_timeout_or_interval(
callback,
args,
Duration::from_millis(timeout.max(0) as u64),
IsInterval::NonInterval,
can_gc,
)
}
@ -511,19 +519,26 @@ impl WorkerGlobalScopeMethods<crate::DomTypeHolder> for WorkerGlobalScope {
fn SetInterval(
&self,
_cx: JSContext,
callback: StringOrFunction,
callback: TrustedScriptOrStringOrFunction,
timeout: i32,
args: Vec<HandleValue>,
) -> i32 {
can_gc: CanGc,
) -> Fallible<i32> {
let callback = match callback {
StringOrFunction::String(i) => TimerCallback::StringTimerCallback(i),
StringOrFunction::Function(i) => TimerCallback::FunctionTimerCallback(i),
TrustedScriptOrStringOrFunction::String(i) => {
TimerCallback::StringTimerCallback(TrustedScriptOrString::String(i))
},
TrustedScriptOrStringOrFunction::TrustedScript(i) => {
TimerCallback::StringTimerCallback(TrustedScriptOrString::TrustedScript(i))
},
TrustedScriptOrStringOrFunction::Function(i) => TimerCallback::FunctionTimerCallback(i),
};
self.upcast::<GlobalScope>().set_timeout_or_interval(
callback,
args,
Duration::from_millis(timeout.max(0) as u64),
IsInterval::Interval,
can_gc,
)
}

View file

@ -21,6 +21,8 @@ use timers::{BoxedTimerCallback, TimerEventRequest};
use crate::dom::bindings::callback::ExceptionHandling::Report;
use crate::dom::bindings::cell::DomRefCell;
use crate::dom::bindings::codegen::Bindings::FunctionBinding::Function;
use crate::dom::bindings::codegen::UnionTypes::TrustedScriptOrString;
use crate::dom::bindings::error::Fallible;
use crate::dom::bindings::inheritance::Castable;
use crate::dom::bindings::refcounted::Trusted;
use crate::dom::bindings::reflector::{DomGlobal, DomObject};
@ -32,6 +34,7 @@ use crate::dom::eventsource::EventSourceTimeoutCallback;
use crate::dom::globalscope::GlobalScope;
#[cfg(feature = "testbinding")]
use crate::dom::testbinding::TestBindingCallback;
use crate::dom::trustedscript::TrustedScript;
use crate::dom::types::{Window, WorkerGlobalScope};
use crate::dom::xmlhttprequest::XHRTimeoutCallback;
use crate::script_module::ScriptFetchOptions;
@ -185,7 +188,9 @@ impl OneshotTimers {
}
}
/// <https://html.spec.whatwg.org/multipage/#timer-initialisation-steps>
pub(crate) fn fire_timer(&self, id: TimerEventId, global: &GlobalScope, can_gc: CanGc) {
// Step 9.2. If id does not exist in global's map of setTimeout and setInterval IDs, then abort these steps.
let expected_id = self.expected_event_id.get();
if expected_id != id {
debug!(
@ -278,6 +283,7 @@ impl OneshotTimers {
self.schedule_timer_call();
}
/// <https://html.spec.whatwg.org/multipage/#timer-initialisation-steps>
fn schedule_timer_call(&self) {
if self.suspended_since.get().is_some() {
// The timer will be scheduled when the pipeline is fully activated.
@ -290,6 +296,8 @@ impl OneshotTimers {
};
let expected_event_id = self.invalidate_expected_event_id();
// Step 12. Let completionStep be an algorithm step which queues a global
// task on the timer task source given global to run task.
let callback = TimerListener {
context: Trusted::new(&*self.global_scope),
task_source: self
@ -321,6 +329,7 @@ impl OneshotTimers {
next_id
}
#[allow(clippy::too_many_arguments)]
pub(crate) fn set_timeout_or_interval(
&self,
global: &GlobalScope,
@ -329,7 +338,8 @@ impl OneshotTimers {
timeout: Duration,
is_interval: IsInterval,
source: TimerSource,
) -> i32 {
can_gc: CanGc,
) -> Fallible<i32> {
self.js_timers.set_timeout_or_interval(
global,
callback,
@ -337,6 +347,7 @@ impl OneshotTimers {
timeout,
is_interval,
source,
can_gc,
)
}
@ -388,9 +399,8 @@ pub(crate) enum IsInterval {
NonInterval,
}
#[derive(Clone)]
pub(crate) enum TimerCallback {
StringTimerCallback(DOMString),
StringTimerCallback(TrustedScriptOrString),
FunctionTimerCallback(Rc<Function>),
}
@ -416,7 +426,8 @@ impl Default for JsTimers {
}
impl JsTimers {
// see https://html.spec.whatwg.org/multipage/#timer-initialisation-steps
/// <https://html.spec.whatwg.org/multipage/#timer-initialisation-steps>
#[allow(clippy::too_many_arguments)]
#[cfg_attr(crown, allow(crown::unrooted_must_root))]
pub(crate) fn set_timeout_or_interval(
&self,
@ -426,16 +437,42 @@ impl JsTimers {
timeout: Duration,
is_interval: IsInterval,
source: TimerSource,
) -> i32 {
can_gc: CanGc,
) -> Fallible<i32> {
let callback = match callback {
TimerCallback::StringTimerCallback(code_str) => {
TimerCallback::StringTimerCallback(trusted_script_or_string) => {
// Step 9.6.1.1. Let globalName be "Window" if global is a Window object; "WorkerGlobalScope" otherwise.
let global_name = if global.is::<Window>() {
"Window"
} else {
"WorkerGlobalScope"
};
// Step 9.6.1.2. Let methodName be "setInterval" if repeat is true; "setTimeout" otherwise.
let method_name = if is_interval == IsInterval::Interval {
"setInterval"
} else {
"setTimeout"
};
// Step 9.6.1.3. Let sink be a concatenation of globalName, U+0020 SPACE, and methodName.
let sink = format!("{} {}", global_name, method_name);
// Step 9.6.1.4. Set handler to the result of invoking the
// Get Trusted Type compliant string algorithm with TrustedScript, global, handler, sink, and "script".
let code_str = TrustedScript::get_trusted_script_compliant_string(
global,
trusted_script_or_string,
&sink,
can_gc,
)?;
// Step 9.6.3. Perform EnsureCSPDoesNotBlockStringCompilation(realm, « », handler, handler, timer, « », handler).
// If this throws an exception, catch it, report it for global, and abort these steps.
if global
.get_csp_list()
.is_js_evaluation_allowed(global, code_str.as_ref())
{
// Step 9.6.2. Assert: handler is a string.
InternalTimerCallback::StringTimerCallback(code_str)
} else {
return 0;
return Ok(0);
}
},
TimerCallback::FunctionTimerCallback(function) => {
@ -448,6 +485,8 @@ impl JsTimers {
for (i, item) in arguments.iter().enumerate() {
args.get_mut(i).unwrap().set(item.get());
}
// Step 9.5. If handler is a Function, then invoke handler given arguments and "report",
// and with callback this value set to thisArg.
InternalTimerCallback::FunctionTimerCallback(
function,
Rc::new(args.into_boxed_slice()),
@ -455,13 +494,15 @@ impl JsTimers {
},
};
// step 2
// Step 2. If previousId was given, let id be previousId; otherwise,
// let id be an implementation-defined integer that is greater than zero
// and does not already exist in global's map of setTimeout and setInterval IDs.
let JsTimerHandle(new_handle) = self.next_timer_handle.get();
self.next_timer_handle.set(JsTimerHandle(new_handle + 1));
// step 3 as part of initialize_and_schedule below
// step 4
// Step 3. If the surrounding agent's event loop's currently running task
// is a task that was created by this algorithm, then let nesting level
// be the task's timer nesting level. Otherwise, let nesting level be 0.
let mut task = JsTimerTask {
handle: JsTimerHandle(new_handle),
source,
@ -472,14 +513,13 @@ impl JsTimers {
duration: Duration::ZERO,
};
// step 5
// Step 4. If timeout is less than 0, then set timeout to 0.
task.duration = timeout.max(Duration::ZERO);
// step 3, 6-9, 11-14
self.initialize_and_schedule(global, task);
// step 10
new_handle
// Step 15. Return id.
Ok(new_handle)
}
pub(crate) fn clear_timeout_or_interval(&self, global: &GlobalScope, handle: i32) {
@ -506,24 +546,27 @@ impl JsTimers {
}
}
// see https://html.spec.whatwg.org/multipage/#timer-initialisation-steps
/// <https://html.spec.whatwg.org/multipage/#timer-initialisation-steps>
fn initialize_and_schedule(&self, global: &GlobalScope, mut task: JsTimerTask) {
let handle = task.handle;
let mut active_timers = self.active_timers.borrow_mut();
// step 6
// Step 3. If the surrounding agent's event loop's currently running task
// is a task that was created by this algorithm, then let nesting level be
// the task's timer nesting level. Otherwise, let nesting level be 0.
let nesting_level = self.nesting_level.get();
// step 7, 13
let duration = self.user_agent_pad(clamp_duration(nesting_level, task.duration));
// step 8, 9
// Step 10. Increment nesting level by one.
// Step 11. Set task's timer nesting level to nesting level.
task.nesting_level = nesting_level + 1;
// essentially step 11, 12, and 14
// Step 13. Set uniqueHandle to the result of running steps after a timeout given global,
// "setTimeout/setInterval", timeout, and completionStep.
let callback = OneshotTimerCallback::JsTimer(task);
let oneshot_handle = global.schedule_callback(callback, duration);
// step 3
// Step 14. Set global's map of setTimeout and setInterval IDs[id] to uniqueHandle.
let entry = active_timers
.entry(handle)
.or_insert(JsTimerEntry { oneshot_handle });
@ -531,8 +574,9 @@ impl JsTimers {
}
}
// see step 7 of https://html.spec.whatwg.org/multipage/#timer-initialisation-steps
/// Step 5 of <https://html.spec.whatwg.org/multipage/#timer-initialisation-steps>
fn clamp_duration(nesting_level: u32, unclamped: Duration) -> Duration {
// Step 5. If nesting level is greater than 5, and timeout is less than 4, then set timeout to 4.
let lower_bound_ms = if nesting_level > 5 { 4 } else { 0 };
let lower_bound = Duration::from_millis(lower_bound_ms);
lower_bound.max(unclamped)
@ -541,30 +585,47 @@ fn clamp_duration(nesting_level: u32, unclamped: Duration) -> Duration {
impl JsTimerTask {
// see https://html.spec.whatwg.org/multipage/#timer-initialisation-steps
pub(crate) fn invoke<T: DomObject>(self, this: &T, timers: &JsTimers, can_gc: CanGc) {
// step 4.1 can be ignored, because we proactively prevent execution
// step 9.2 can be ignored, because we proactively prevent execution
// of this task when its scheduled execution is canceled.
// prep for step 6 in nested set_timeout_or_interval calls
// prep for step ? in nested set_timeout_or_interval calls
timers.nesting_level.set(self.nesting_level);
// step 4.2
let was_user_interacting = ScriptThread::is_user_interacting();
ScriptThread::set_user_interacting(self.is_user_interacting);
match self.callback {
InternalTimerCallback::StringTimerCallback(ref code_str) => {
// Step 6.4. Let settings object be global's relevant settings object.
// Step 6. Let realm be global's relevant realm.
let global = this.global();
// Step 7. Let initiating script be the active script.
let cx = GlobalScope::get_cx();
// Step 9.6.7. If initiating script is not null, then:
rooted!(in(*cx) let mut rval = UndefinedValue());
// Step 9.6.7.1. Set fetch options to a script fetch options whose cryptographic nonce
// is initiating script's fetch options's cryptographic nonce,
// integrity metadata is the empty string, parser metadata is "not-parser-inserted",
// credentials mode is initiating script's fetch options's credentials mode,
// referrer policy is initiating script's fetch options's referrer policy,
// and fetch priority is "auto".
// Step 9.6.8. Let script be the result of creating a classic script given handler,
// settings object, base URL, and fetch options.
// Step 9.6.9. Run the classic script script.
//
// FIXME(cybai): Use base url properly by saving private reference for timers (#27260)
_ = global.evaluate_js_on_global_with_result(
code_str,
rval.handle_mut(),
ScriptFetchOptions::default_classic_script(&global),
// Step 9.6. Let base URL be settings object's API base URL.
// Step 9.7.2. Set base URL to initiating script's base URL.
global.api_base_url(),
can_gc,
Some(IntroductionType::DOM_TIMER),
);
},
// Step 9.5. If handler is a Function, then invoke handler given arguments and
// "report", and with callback this value set to thisArg.
InternalTimerCallback::FunctionTimerCallback(ref function, ref arguments) => {
let arguments = self.collect_heap_args(arguments);
rooted!(in(*GlobalScope::get_cx()) let mut value: JSVal);
@ -576,7 +637,9 @@ impl JsTimerTask {
// reset nesting level (see above)
timers.nesting_level.set(0);
// step 4.3
// Step 9.9. If repeat is true, then perform the timer initialization steps again,
// given global, handler, timeout, arguments, true, and id.
//
// Since we choose proactively prevent execution (see 4.1 above), we must only
// reschedule repeating timers when they were not canceled as part of step 4.2.
if self.is_interval == IsInterval::Interval &&
@ -622,10 +685,10 @@ struct TimerListener {
impl TimerListener {
/// Handle a timer-event coming from the [`timers::TimerScheduler`]
/// by queuing the appropriate task on the relevant event-loop.
/// <https://html.spec.whatwg.org/multipage/#timer-initialisation-steps>
fn handle(&self, event: TimerEvent) {
let context = self.context.clone();
// Step 18, queue a task,
// https://html.spec.whatwg.org/multipage/#timer-initialisation-steps
// Step 9. Let task be a task that runs the following substeps:
self.task_source.queue(task!(timer_event: move || {
let global = context.root();
let TimerEvent(source, id) = event;
@ -638,7 +701,6 @@ impl TimerListener {
global.downcast::<Window>().expect("Worker timer delivered to window");
},
};
// Step 7, substeps run in a task.
global.fire_timer(id, CanGc::note());
})
);

View file

@ -651,7 +651,7 @@ DOMInterfaces = {
},
'Window': {
'canGc': ['Stop', 'Fetch', 'Stop', 'Fetch', 'Open', 'CreateImageBitmap', 'CreateImageBitmap_', 'TrustedTypes', 'WebdriverCallback', 'WebdriverException'],
'canGc': ['Stop', 'Fetch', 'Stop', 'Fetch', 'Open', 'CreateImageBitmap', 'CreateImageBitmap_', 'SetInterval', 'SetTimeout', 'TrustedTypes', 'WebdriverCallback', 'WebdriverException'],
'inRealms': ['Fetch', 'GetOpener', 'WebdriverCallback', 'WebdriverException'],
'additionalTraits': ['crate::interfaces::WindowHelpers'],
},
@ -663,7 +663,7 @@ DOMInterfaces = {
'WorkerGlobalScope': {
'inRealms': ['Fetch'],
'canGc': ['Fetch', 'CreateImageBitmap', 'CreateImageBitmap_', 'ImportScripts', 'TrustedTypes'],
'canGc': ['Fetch', 'CreateImageBitmap', 'CreateImageBitmap_', 'ImportScripts', 'SetInterval', 'SetTimeout', 'TrustedTypes'],
},
'Worklet': {

View file

@ -4,7 +4,7 @@
// https://html.spec.whatwg.org/multipage/#windoworworkerglobalscope
typedef (DOMString or Function) TimerHandler;
typedef (TrustedScript or DOMString or Function) TimerHandler;
[Exposed=(Window,Worker)]
interface mixin WindowOrWorkerGlobalScope {
@ -15,9 +15,9 @@ interface mixin WindowOrWorkerGlobalScope {
[Throws] DOMString atob(DOMString data);
// timers
long setTimeout(TimerHandler handler, optional long timeout = 0, any... arguments);
[Throws] long setTimeout(TimerHandler handler, optional long timeout = 0, any... arguments);
undefined clearTimeout(optional long handle = 0);
long setInterval(TimerHandler handler, optional long timeout = 0, any... arguments);
[Throws] long setInterval(TimerHandler handler, optional long timeout = 0, any... arguments);
undefined clearInterval(optional long handle = 0);
// microtask queuing

View file

@ -1,7 +0,0 @@
[DedicatedWorker-setTimeout-setInterval.html]
expected: TIMEOUT
[DedicatedWorkerGlobalScope.setTimeout assigned via default policy (successful Script transformation).]
expected: TIMEOUT
[DedicatedWorkerGlobalScope.setInterval assigned via default policy (successful Script transformation).]
expected: TIMEOUT

View file

@ -1,7 +0,0 @@
[Window-setTimeout-setInterval.html]
expected: TIMEOUT
[Window.setTimeout assigned via default policy (successful Script transformation).]
expected: TIMEOUT
[Window.setInterval assigned via default policy (successful Script transformation).]
expected: TIMEOUT

View file

@ -1,12 +0,0 @@
[block-string-assignment-to-DedicatedWorker-setTimeout-setInterval.html]
[`DedicatedWorkerGlobalScope.setTimeout(string)` throws.]
expected: FAIL
[`DedicatedWorkerGlobalScope.setTimeout(null)` throws.]
expected: FAIL
[`DedicatedWorkerGlobalScope.setInterval(string)` throws.]
expected: FAIL
[`DedicatedWorkerGlobalScope.setInterval(null)` throws.]
expected: FAIL

View file

@ -1,13 +0,0 @@
[block-string-assignment-to-Window-setTimeout-setInterval.html]
expected: ERROR
[`Window.setTimeout(string)` throws.]
expected: FAIL
[`Window.setTimeout(null)` throws.]
expected: FAIL
[`Window.setInterval(string)` throws.]
expected: FAIL
[`Window.setInterval(null)` throws.]
expected: FAIL

View file

@ -1,6 +0,0 @@
[should-sink-type-mismatch-violation-be-blocked-by-csp-002-worker.html]
[Checking reported violations for setTimeout(';;;;;') from DedicatedWorker]
expected: FAIL
[Location of required-trusted-types-for violations.]
expected: FAIL

View file

@ -1,3 +0,0 @@
[should-sink-type-mismatch-violation-be-blocked-by-csp-003.html]
[Location of required-trusted-types-for violations.]
expected: FAIL

View file

@ -1,3 +0,0 @@
[trusted-types-reporting-check-report-DedicatedWorker-sink-mismatch.html]
[Test number of sent reports.]
expected: FAIL

View file

@ -1,3 +0,0 @@
[trusted-types-reporting-check-report-Window-sink-mismatch.html]
[Test number of sent reports.]
expected: FAIL

View file

@ -1,6 +0,0 @@
[trusted-types-reporting-for-DedicatedWorker-setTimeout-setInterval.html]
[Violation report for setTimeout with plain string.]
expected: FAIL
[Violation report for setInterval with plain string.]
expected: FAIL

View file

@ -1,6 +0,0 @@
[trusted-types-reporting-for-Window-setTimeout-setInterval.html]
[Violation report for setTimeout with plain string.]
expected: FAIL
[Violation report for setInterval with plain string.]
expected: FAIL