diff options
author | Daniel Johnson <danielj41@gmail.com> | 2017-08-20 14:50:02 -0700 |
---|---|---|
committer | Daniel Johnson <danielj41@gmail.com> | 2017-08-22 23:14:53 -0700 |
commit | fa3e9ab2444daab2c67b7e25fd6a5f88264b4ddb (patch) | |
tree | 739bec56b6885cfc83bc0e2dc53b63c5708d8462 /components/script/script_thread.rs | |
parent | 20c73e7f7d620600f161f3c00cbe5a80b5e2a5a9 (diff) | |
download | servo-fa3e9ab2444daab2c67b7e25fd6a5f88264b4ddb.tar.gz servo-fa3e9ab2444daab2c67b7e25fd6a5f88264b4ddb.zip |
"javascript:" urls: run in correct global
Make some changes to javascript scheme url evaluation to bring it
closer to
https://html.spec.whatwg.org/multipage/browsing-the-web.html#navigating-across-documents
- Evaluate the js before the page load so that it happens in the
correct `window` global.
- If the result is not a string, the response should be a 204.
This required saving some data in load_data, since it's not
possible to modify the response at the point where we're evaluating
the js.
Diffstat (limited to 'components/script/script_thread.rs')
-rw-r--r-- | components/script/script_thread.rs | 124 |
1 files changed, 80 insertions, 44 deletions
diff --git a/components/script/script_thread.rs b/components/script/script_thread.rs index d4911627a6f..e234805f0b6 100644 --- a/components/script/script_thread.rs +++ b/components/script/script_thread.rs @@ -87,8 +87,8 @@ use script_runtime::{CommonScriptMsg, ScriptChan, ScriptThreadEventCategory}; use script_runtime::{ScriptPort, StackRootTLS, get_reports, new_rt_and_cx}; use script_traits::{CompositorEvent, ConstellationControlMsg}; use script_traits::{DocumentActivity, DiscardBrowsingContext, EventResult}; -use script_traits::{InitialScriptState, LayoutMsg, LoadData, MouseButton, MouseEventType, MozBrowserEvent}; -use script_traits::{NewLayoutInfo, ScriptToConstellationChan, ScriptMsg, UpdatePipelineIdReason}; +use script_traits::{InitialScriptState, JsEvalResult, LayoutMsg, LoadData, MouseButton, MouseEventType}; +use script_traits::{MozBrowserEvent, NewLayoutInfo, ScriptToConstellationChan, ScriptMsg, UpdatePipelineIdReason}; use script_traits::{ScriptThreadFactory, TimerEvent, TimerSchedulerMsg, TimerSource}; use script_traits::{TouchEventType, TouchId, UntrustedNodeAddress, WindowSizeData, WindowSizeType}; use script_traits::CompositorEvent::{KeyEvent, MouseButtonEvent, MouseMoveEvent, ResizeEvent}; @@ -1506,7 +1506,7 @@ impl ScriptThread { load_data.url.clone(), origin); if load_data.url.as_str() == "about:blank" { - self.start_page_load_about_blank(new_load); + self.start_page_load_about_blank(new_load, load_data.js_eval_result); } else { self.pre_page_load(new_load, load_data); } @@ -1677,6 +1677,18 @@ impl ScriptThread { match idx { Some(idx) => { let load = self.incomplete_loads.borrow_mut().remove(idx); + + // https://html.spec.whatwg.org/multipage/#process-a-navigate-response + // 2. If response's status is 204 or 205, then abort these steps. + match metadata { + Some(Metadata { status: Some((204 ... 205, _)), .. }) => { + // TODO: This leaves the page in a broken state where you can't follow + // other links. Fix this. + return None; + }, + _ => () + }; + metadata.map(|meta| self.load(meta, load)) } None => { @@ -2116,39 +2128,7 @@ impl ScriptThread { // Notify devtools that a new script global exists. self.notify_devtools(document.Title(), final_url.clone(), (incomplete.pipeline_id, None)); - let is_javascript = incomplete.url.scheme() == "javascript"; - let parse_input = if is_javascript { - use url::percent_encoding::percent_decode; - - // Turn javascript: URL into JS code to eval, according to the steps in - // https://html.spec.whatwg.org/multipage/#javascript-protocol - - // This slice of the URL’s serialization is equivalent to (5.) to (7.): - // Start with the scheme data of the parsed URL; - // append question mark and query component, if any; - // append number sign and fragment component if any. - let encoded = &incomplete.url[Position::BeforePath..]; - - // Percent-decode (8.) and UTF-8 decode (9.) - let script_source = percent_decode(encoded.as_bytes()).decode_utf8_lossy(); - - // Script source is ready to be evaluated (11.) - unsafe { - let _ac = JSAutoCompartment::new(self.get_cx(), window.reflector().get_jsobject().get()); - rooted!(in(self.get_cx()) let mut jsval = UndefinedValue()); - window.upcast::<GlobalScope>().evaluate_js_on_global_with_result( - &script_source, jsval.handle_mut()); - let strval = DOMString::from_jsval(self.get_cx(), - jsval.handle(), - StringificationBehavior::Empty); - match strval { - Ok(ConversionResult::Success(s)) => s, - _ => DOMString::new(), - } - } - } else { - DOMString::new() - }; + let parse_input = DOMString::new(); document.set_https_state(metadata.https_state); @@ -2327,7 +2307,7 @@ impl ScriptThread { /// for the given pipeline (specifically the "navigate" algorithm). fn handle_navigate(&self, parent_pipeline_id: PipelineId, browsing_context_id: Option<BrowsingContextId>, - load_data: LoadData, + mut load_data: LoadData, replace: bool) { match browsing_context_id { Some(browsing_context_id) => { @@ -2335,8 +2315,56 @@ impl ScriptThread { if let Some(iframe) = iframe { iframe.navigate_or_reload_child_browsing_context(Some(load_data), NavigationType::Regular, replace); } + + // TODO: Test javascript: urls in iframes } None => { + let is_javascript = load_data.url.scheme() == "javascript"; + if is_javascript { + use url::percent_encoding::percent_decode; + + // Turn javascript: URL into JS code to eval, according to the steps in + // https://html.spec.whatwg.org/multipage/#javascript-protocol + + // This slice of the URL’s serialization is equivalent to (5.) to (7.): + // Start with the scheme data of the parsed URL; + // append question mark and query component, if any; + // append number sign and fragment component if any. + let encoded = &load_data.url[Position::BeforePath..]; + + // Percent-decode (8.) and UTF-8 decode (9.) + 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(parent_pipeline_id); + 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::<GlobalScope>().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, + } + } + } else { + Some(JsEvalResult::NoContent) + }; + } + } + + if is_javascript { + load_data.url = ServoUrl::parse("about:blank").unwrap(); + } + self.script_sender .send((parent_pipeline_id, ScriptMsg::LoadUrl(load_data, replace))) .unwrap(); @@ -2375,7 +2403,7 @@ impl ScriptThread { /// argument until a notification is received that the fetch is complete. fn pre_page_load(&self, incomplete: InProgressLoad, load_data: LoadData) { let id = incomplete.pipeline_id.clone(); - let mut req_init = RequestInit { + let req_init = RequestInit { url: load_data.url.clone(), method: load_data.method, destination: Destination::Document, @@ -2391,10 +2419,6 @@ impl ScriptThread { .. RequestInit::default() }; - if req_init.url.scheme() == "javascript" { - req_init.url = ServoUrl::parse("about:blank").unwrap(); - } - let context = ParserContext::new(id, load_data.url); self.incomplete_parser_contexts.borrow_mut().push((id, context)); @@ -2434,7 +2458,7 @@ impl ScriptThread { /// Synchronously fetch `about:blank`. Stores the `InProgressLoad` /// argument until a notification is received that the fetch is complete. - fn start_page_load_about_blank(&self, incomplete: InProgressLoad) { + fn start_page_load_about_blank(&self, incomplete: InProgressLoad, js_eval_result: Option<JsEvalResult>) { let id = incomplete.pipeline_id; self.incomplete_loads.borrow_mut().push(incomplete); @@ -2444,8 +2468,20 @@ impl ScriptThread { let mut meta = Metadata::default(url); meta.set_content_type(Some(&mime!(Text / Html))); + + // If this page load is the result of a javascript scheme url, map + // the evaluation result into a response. + let chunk = match js_eval_result { + Some(JsEvalResult::Ok(content)) => content, + Some(JsEvalResult::NoContent) => { + meta.status = Some((204, b"No Content".to_vec())); + vec![] + }, + None => vec![] + }; + context.process_response(Ok(FetchMetadata::Unfiltered(meta))); - context.process_response_chunk(vec![]); + context.process_response_chunk(chunk); context.process_response_eof(Ok(())); } |