From 6ae6031468662161280a4353da9c0c23368cd83d Mon Sep 17 00:00:00 2001 From: Daniel Johnson Date: Mon, 28 Aug 2017 22:22:39 -0700 Subject: [PATCH] "javascript:" urls: evaluate in iframe src attribute - generalize the eval_js_url function so it can be called from multiple places. - call it in htmliframeelement. - if the js eval results in a non-string result, then it won't navigate to a new page, so don't block on the new page loading. --- components/constellation/constellation.rs | 2 +- components/script/dom/htmliframeelement.rs | 21 ++++++++-- components/script/script_thread.rs | 46 +++++++++++----------- 3 files changed, 41 insertions(+), 28 deletions(-) diff --git a/components/constellation/constellation.rs b/components/constellation/constellation.rs index fa58b1f7aed..6a6f4f5ce26 100644 --- a/components/constellation/constellation.rs +++ b/components/constellation/constellation.rs @@ -1056,7 +1056,7 @@ impl Constellation self.handle_load_url_msg(source_top_ctx_id, source_pipeline_id, load_data, replace); } FromScriptMsg::AbortLoadUrl => { - debug!("constellation got URL load message from script"); + debug!("constellation got abort URL load message from script"); self.handle_abort_load_url_msg(source_pipeline_id); } // A page loaded has completed all parsing, script, and reflow messages have been sent. diff --git a/components/script/dom/htmliframeelement.rs b/components/script/dom/htmliframeelement.rs index 47a1d2adfcb..0b6102ab165 100644 --- a/components/script/dom/htmliframeelement.rs +++ b/components/script/dom/htmliframeelement.rs @@ -44,7 +44,7 @@ use msg::constellation_msg::{FrameType, BrowsingContextId, PipelineId, TopLevelB use net_traits::response::HttpsState; use script_layout_interface::message::ReflowQueryType; use script_thread::{ScriptThread, Runnable}; -use script_traits::{IFrameLoadInfo, IFrameLoadInfoWithData, LoadData, UpdatePipelineIdReason}; +use script_traits::{IFrameLoadInfo, IFrameLoadInfoWithData, JsEvalResult, LoadData, UpdatePipelineIdReason}; use script_traits::{MozBrowserEvent, NewLayoutInfo, ScriptMsg}; use script_traits::IFrameSandboxState::{IFrameSandboxed, IFrameUnsandboxed}; use servo_atoms::Atom; @@ -114,7 +114,7 @@ impl HTMLIFrameElement { } pub fn navigate_or_reload_child_browsing_context(&self, - load_data: Option, + mut load_data: Option, nav_type: NavigationType, replace: bool) { let sandboxed = if self.is_sandboxed() { @@ -140,11 +140,26 @@ impl HTMLIFrameElement { // document; the new navigation will continue blocking it. LoadBlocker::terminate(&mut load_blocker); + if let Some(ref mut load_data) = load_data { + let is_javascript = load_data.url.scheme() == "javascript"; + if is_javascript { + let window_proxy = self.GetContentWindow(); + if let Some(window_proxy) = window_proxy { + ScriptThread::eval_js_url(&window_proxy.global(), load_data); + } + } + } + //TODO(#9592): Deal with the case where an iframe is being reloaded so url is None. // The iframe should always have access to the nested context's active // document URL through the browsing context. if let Some(ref load_data) = load_data { - *load_blocker = Some(LoadBlocker::new(&*document, LoadType::Subframe(load_data.url.clone()))); + match load_data.js_eval_result { + Some(JsEvalResult::NoContent) => (), + _ => { + *load_blocker = Some(LoadBlocker::new(&*document, LoadType::Subframe(load_data.url.clone()))); + } + }; } let window = window_from_node(self); diff --git a/components/script/script_thread.rs b/components/script/script_thread.rs index d3b5a81683b..6ca5b05bc67 100644 --- a/components/script/script_thread.rs +++ b/components/script/script_thread.rs @@ -2312,7 +2312,10 @@ impl ScriptThread { replace: bool) { let is_javascript = load_data.url.scheme() == "javascript"; if is_javascript { - self.eval_js_url(parent_pipeline_id, &mut load_data); + let window = self.documents.borrow().find_window(parent_pipeline_id); + if let Some(window) = window { + ScriptThread::eval_js_url(window.upcast::(), &mut load_data); + } } match browsing_context_id { @@ -2330,7 +2333,7 @@ impl ScriptThread { } } - fn eval_js_url(&self, pipeline_id: PipelineId, load_data: &mut LoadData) { + pub fn eval_js_url(global_scope: &GlobalScope, load_data: &mut LoadData) { { // Turn javascript: URL into JS code to eval, according to the steps in // https://html.spec.whatwg.org/multipage/#javascript-protocol @@ -2345,30 +2348,25 @@ impl ScriptThread { let script_source = percent_decode(encoded.as_bytes()).decode_utf8_lossy(); // Script source is ready to be evaluated (11.) - let window = self.documents.borrow().find_window(pipeline_id); + let _ac = JSAutoCompartment::new(global_scope.get_cx(), global_scope.reflector().get_jsobject().get()); + rooted!(in(global_scope.get_cx()) let mut jsval = UndefinedValue()); + global_scope.evaluate_js_on_global_with_result(&script_source, jsval.handle_mut()); - if let Some(window) = window { - let _ac = JSAutoCompartment::new(self.get_cx(), window.reflector().get_jsobject().get()); - rooted!(in(self.get_cx()) let mut jsval = UndefinedValue()); - window.upcast::().evaluate_js_on_global_with_result( - &script_source, jsval.handle_mut()); - - load_data.js_eval_result = if jsval.get().is_string() { - unsafe { - let strval = DOMString::from_jsval(self.get_cx(), - jsval.handle(), - StringificationBehavior::Empty); - match strval { - Ok(ConversionResult::Success(s)) => { - Some(JsEvalResult::Ok(String::from(s).as_bytes().to_vec())) - }, - _ => None, - } + load_data.js_eval_result = if jsval.get().is_string() { + unsafe { + let strval = DOMString::from_jsval(global_scope.get_cx(), + jsval.handle(), + StringificationBehavior::Empty); + match strval { + Ok(ConversionResult::Success(s)) => { + Some(JsEvalResult::Ok(String::from(s).as_bytes().to_vec())) + }, + _ => None, } - } else { - Some(JsEvalResult::NoContent) - }; - } + } + } else { + Some(JsEvalResult::NoContent) + }; }; load_data.url = ServoUrl::parse("about:blank").unwrap();