aboutsummaryrefslogtreecommitdiffstats
path: root/components/script/script_thread.rs
diff options
context:
space:
mode:
authorbors-servo <lbergstrom+bors@mozilla.com>2017-09-09 04:39:43 -0500
committerGitHub <noreply@github.com>2017-09-09 04:39:43 -0500
commit40c8a6389afdad8fdffdf4a5616627f9a51b1822 (patch)
tree29694c5eea2b2066978b8e2b9cff019275b72b5b /components/script/script_thread.rs
parentc0c43da1f90afc37ac9d78bb7ef0f52cf02f2611 (diff)
parent452db052ff385e7abd112dec3b8147199b5d5b5f (diff)
downloadservo-40c8a6389afdad8fdffdf4a5616627f9a51b1822.tar.gz
servo-40c8a6389afdad8fdffdf4a5616627f9a51b1822.zip
Auto merge of #17083 - danielj41:javascript-url-global-3, r=jdm
"javascript:" urls: execute in correct global scope <!-- Please describe your changes on the following line: --> #### Summary This pull request makes `javascript:` urls execute in the correct global scope. #### Example ```html <script> var x = 4; </script> <!-- this branch: logs "4" --> <!-- master: undefined variable error --> <a href="javascript:console.log(x)">link</a> ``` #### Questions I'm new to servo and rust, so I'm unsure about these changes. In particular: * What's the appropriate place to evaluate the js? * I moved it to `handle_navigate`, but I'm not sure if this will catch all occurrences of `javascript:` urls. I also don't know if this will execute in the correct thread and the correct window. * What should I do with the result of the js evaluation? * I just ignored it. The previous behavior displayed it as the content of a new page load. --- <!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: --> - [x] `./mach build -d` does not report any errors - [x] `./mach test-tidy` does not report any errors - [x] These changes fix #15147, #16718 <!-- Either: --> - [x] There are tests for these changes <!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.--> <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. --> <!-- Reviewable:start --> --- This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/17083) <!-- Reviewable:end -->
Diffstat (limited to 'components/script/script_thread.rs')
-rw-r--r--components/script/script_thread.rs122
1 files changed, 78 insertions, 44 deletions
diff --git a/components/script/script_thread.rs b/components/script/script_thread.rs
index 207e47572e7..12afd67c7c5 100644
--- a/components/script/script_thread.rs
+++ b/components/script/script_thread.rs
@@ -89,8 +89,8 @@ use script_runtime::{CommonScriptMsg, ScriptChan, ScriptThreadEventCategory};
use script_runtime::{ScriptPort, StackRootTLS, get_reports, new_rt_and_cx};
use script_traits::{CompositorEvent, ConstellationControlMsg, PaintMetricType};
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};
@@ -122,6 +122,7 @@ use task_source::performance_timeline::PerformanceTimelineTaskSource;
use task_source::user_interaction::UserInteractionTaskSource;
use time::{get_time, precise_time_ns, Tm};
use url::Position;
+use url::percent_encoding::percent_decode;
use webdriver_handlers;
use webvr_traits::{WebVREvent, WebVRMsg};
@@ -1509,7 +1510,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);
}
@@ -1679,6 +1680,18 @@ impl ScriptThread {
// the pipeline exited before the page load completed.
match idx {
Some(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, _)), .. }) => {
+ self.script_sender
+ .send((id.clone(), ScriptMsg::AbortLoadUrl))
+ .unwrap();
+ return None;
+ },
+ _ => ()
+ };
+
let load = self.incomplete_loads.borrow_mut().remove(idx);
metadata.map(|meta| self.load(meta, load))
}
@@ -2118,39 +2131,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);
@@ -2329,8 +2310,16 @@ 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) {
+ let is_javascript = load_data.url.scheme() == "javascript";
+ if is_javascript {
+ let window = self.documents.borrow().find_window(parent_pipeline_id);
+ if let Some(window) = window {
+ ScriptThread::eval_js_url(window.upcast::<GlobalScope>(), &mut load_data);
+ }
+ }
+
match browsing_context_id {
Some(browsing_context_id) => {
let iframe = self.documents.borrow().find_iframe(parent_pipeline_id, browsing_context_id);
@@ -2346,6 +2335,43 @@ impl ScriptThread {
}
}
+ 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
+
+ // 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.clone()[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 _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());
+
+ 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)
+ };
+
+ load_data.url = ServoUrl::parse("about:blank").unwrap();
+ }
+
fn handle_resize_event(&self, pipeline_id: PipelineId, new_size: WindowSizeData, size_type: WindowSizeType) {
let document = match { self.documents.borrow().find_document(pipeline_id) } {
Some(document) => document,
@@ -2377,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,
@@ -2393,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));
@@ -2436,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);
@@ -2446,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(()));
}