diff --git a/components/script/document_loader.rs b/components/script/document_loader.rs index 6761f175a3f..e5bcdbc978a 100644 --- a/components/script/document_loader.rs +++ b/components/script/document_loader.rs @@ -8,6 +8,7 @@ use dom::bindings::root::Dom; use dom::document::Document; +use fetch::FetchCanceller; use ipc_channel::ipc::IpcSender; use net_traits::{CoreResourceMsg, FetchChannels, FetchResponseMsg}; use net_traits::{ResourceThreads, IpcSend}; @@ -87,6 +88,7 @@ pub struct DocumentLoader { resource_threads: ResourceThreads, blocking_loads: Vec, events_inhibited: bool, + cancellers: Vec, } impl DocumentLoader { @@ -103,9 +105,17 @@ impl DocumentLoader { resource_threads: resource_threads, blocking_loads: initial_loads, events_inhibited: false, + cancellers: Vec::new() } } + pub fn cancel_all_loads(&mut self) -> bool { + let canceled_any = !self.cancellers.is_empty(); + // Associated fetches will be canceled when dropping the canceller. + self.cancellers.clear(); + canceled_any + } + /// Add a load to the list of blocking loads. fn add_blocking_load(&mut self, load: LoadType) { debug!("Adding blocking load {:?} ({}).", load, self.blocking_loads.len()); @@ -122,11 +132,14 @@ impl DocumentLoader { } /// Initiate a new fetch that does not block the document load event. - pub fn fetch_async_background(&self, + pub fn fetch_async_background(&mut self, request: RequestInit, fetch_target: IpcSender) { + let mut canceller = FetchCanceller::new(); + let cancel_receiver = canceller.initialize(); + self.cancellers.push(canceller); self.resource_threads.sender().send( - CoreResourceMsg::Fetch(request, FetchChannels::ResponseMsg(fetch_target, None))).unwrap(); + CoreResourceMsg::Fetch(request, FetchChannels::ResponseMsg(fetch_target, Some(cancel_receiver)))).unwrap(); } /// Mark an in-progress network request complete. diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index 26c59bdb8ec..1ff29786491 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -141,7 +141,7 @@ use style::shared_lock::{SharedRwLock as StyleSharedRwLock, SharedRwLockReadGuar use style::str::{split_html_space_chars, str_join}; use style::stylesheet_set::DocumentStylesheetSet; use style::stylesheets::{CssRule, Stylesheet, Origin, OriginSet}; -use task_source::TaskSource; +use task_source::{TaskSource, TaskSourceName}; use time; use timers::OneshotTimerCallback; use url::Host; @@ -2010,7 +2010,7 @@ impl Document { } // https://html.spec.whatwg.org/multipage/#abort-a-document - fn abort(&self) { + pub fn abort(&self) { // We need to inhibit the loader before anything else. self.loader.borrow_mut().inhibit_events(); @@ -2029,14 +2029,21 @@ impl Document { *self.asap_scripts_set.borrow_mut() = vec![]; self.asap_in_order_scripts_list.clear(); self.deferred_scripts.clear(); + if self.loader.borrow_mut().cancel_all_loads() { + // If any loads were canceled. + self.salvageable.set(false); + }; - // TODO: https://github.com/servo/servo/issues/15236 - self.window.cancel_all_tasks(); + // Also Step 2. + // Note: the spec says to discard any tasks queued for fetch. + // This cancels all tasks on the networking task source, which might be too broad. + // See https://github.com/whatwg/html/issues/3837 + self.window.cancel_all_tasks_from_source(TaskSourceName::Networking); // Step 3. if let Some(parser) = self.get_current_parser() { parser.abort(); - // TODO: salvageable flag. + self.salvageable.set(false); } } diff --git a/components/script/dom/htmlimageelement.rs b/components/script/dom/htmlimageelement.rs index 668c66d7734..de084a82de8 100644 --- a/components/script/dom/htmlimageelement.rs +++ b/components/script/dom/htmlimageelement.rs @@ -268,7 +268,7 @@ impl HTMLImageElement { // This is a background load because the load blocker already fulfills the // purpose of delaying the document's load event. - document.loader().fetch_async_background(request, action_sender); + document.loader_mut().fetch_async_background(request, action_sender); } /// Step 14 of https://html.spec.whatwg.org/multipage/#update-the-image-data diff --git a/components/script/dom/htmlmediaelement.rs b/components/script/dom/htmlmediaelement.rs index 466bcae3280..83ad930337c 100644 --- a/components/script/dom/htmlmediaelement.rs +++ b/components/script/dom/htmlmediaelement.rs @@ -613,7 +613,7 @@ impl HTMLMediaElement { ROUTER.add_route(action_receiver.to_opaque(), Box::new(move |message| { listener.notify_fetch(message.to().unwrap()); })); - document.loader().fetch_async_background(request, action_sender); + document.loader_mut().fetch_async_background(request, action_sender); }, Resource::Object => { // FIXME(nox): Actually do something with the object. diff --git a/components/script/dom/webidls/Window.webidl b/components/script/dom/webidls/Window.webidl index 7fb00fbc05a..d7e22b1f60c 100644 --- a/components/script/dom/webidls/Window.webidl +++ b/components/script/dom/webidls/Window.webidl @@ -25,7 +25,7 @@ attribute DOMString status; void close(); readonly attribute boolean closed; - //void stop(); + void stop(); //void focus(); //void blur(); diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs index ea3a92e0f37..5e1829f0c62 100644 --- a/components/script/dom/window.rs +++ b/components/script/dom/window.rs @@ -552,6 +552,13 @@ impl WindowMethods for Window { receiver.recv().unwrap(); } + // https://html.spec.whatwg.org/multipage/#dom-window-stop + fn Stop(&self) { + // TODO: Cancel ongoing navigation. + let doc = self.Document(); + doc.abort(); + } + // https://html.spec.whatwg.org/multipage/#dom-window-closed fn Closed(&self) -> bool { self.window_proxy.get() @@ -1110,6 +1117,16 @@ impl Window { } } + /// Cancels all the tasks from a given task source. + /// This sets the current sentinel value to + /// `true` and replaces it with a brand new one for future tasks. + pub fn cancel_all_tasks_from_source(&self, task_source_name: TaskSourceName) { + let mut ignore_flags = self.ignore_further_async_events.borrow_mut(); + let flag = ignore_flags.entry(task_source_name).or_insert(Default::default()); + let cancelled = mem::replace(&mut *flag, Default::default()); + cancelled.store(true, Ordering::Relaxed); + } + pub fn clear_js_runtime(&self) { // We tear down the active document, which causes all the attached // nodes to dispose of their layout data. This messages the layout diff --git a/components/script/layout_image.rs b/components/script/layout_image.rs index 553972d24b1..91bb021d060 100644 --- a/components/script/layout_image.rs +++ b/components/script/layout_image.rs @@ -78,5 +78,5 @@ pub fn fetch_image_for_layout(url: ServoUrl, }; // Layout image loads do not delay the document load event. - document.loader().fetch_async_background(request, action_sender); + document.loader_mut().fetch_async_background(request, action_sender); } diff --git a/tests/wpt/metadata/html/browsers/the-window-object/window-properties.https.html.ini b/tests/wpt/metadata/html/browsers/the-window-object/window-properties.https.html.ini index 27597793aa0..c691ea29632 100644 --- a/tests/wpt/metadata/html/browsers/the-window-object/window-properties.https.html.ini +++ b/tests/wpt/metadata/html/browsers/the-window-object/window-properties.https.html.ini @@ -1,7 +1,4 @@ [window-properties.https.html] - [Window method: stop] - expected: FAIL - [Window method: focus] expected: FAIL diff --git a/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/script-onerror-insertion-point-2.html.ini b/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/script-onerror-insertion-point-2.html.ini deleted file mode 100644 index 39c3a3d651b..00000000000 --- a/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/script-onerror-insertion-point-2.html.ini +++ /dev/null @@ -1,3 +0,0 @@ -[script-onerror-insertion-point-2.html] - type: testharness - expected: TIMEOUT diff --git a/tests/wpt/metadata/performance-timeline/webtiming-resolution.any.js.ini b/tests/wpt/metadata/performance-timeline/webtiming-resolution.any.js.ini index c9bacb01f1a..7f9b8e85550 100644 --- a/tests/wpt/metadata/performance-timeline/webtiming-resolution.any.js.ini +++ b/tests/wpt/metadata/performance-timeline/webtiming-resolution.any.js.ini @@ -4,7 +4,7 @@ [webtiming-resolution.any.worker.html] expected: TIMEOUT [Verifies the resolution of performance.now() is at least 20 microseconds.] - expected: FAIL + expected: FAIL [Verifies the resolution of entry.startTime is at least 20 microseconds.] expected: TIMEOUT