mirror of
https://github.com/servo/servo.git
synced 2025-07-22 23:03:42 +01:00
clean-up navigation
security: check target and source origin before executing JS url implement replacement-enabled flag as a HistoryEntryReplacement enum add source origin string on loaddata add LoadOrigin iframe: remove optional load-data auxiliaries: add load-data into info constellation: remove url from Pipeline::new check load origin: link to whatwg issue switch loadorigin toplevel to constellation
This commit is contained in:
parent
973a3448a4
commit
571beec179
14 changed files with 402 additions and 220 deletions
|
@ -32,6 +32,7 @@ use crate::dom::bindings::conversions::{
|
|||
};
|
||||
use crate::dom::bindings::inheritance::Castable;
|
||||
use crate::dom::bindings::num::Finite;
|
||||
use crate::dom::bindings::refcounted::Trusted;
|
||||
use crate::dom::bindings::reflector::DomObject;
|
||||
use crate::dom::bindings::root::ThreadLocalStackRoots;
|
||||
use crate::dom::bindings::root::{Dom, DomRoot, MutNullableDom, RootCollection};
|
||||
|
@ -82,6 +83,7 @@ use crate::task_source::performance_timeline::PerformanceTimelineTaskSource;
|
|||
use crate::task_source::remote_event::RemoteEventTaskSource;
|
||||
use crate::task_source::user_interaction::UserInteractionTaskSource;
|
||||
use crate::task_source::websocket::WebsocketTaskSource;
|
||||
use crate::task_source::TaskSource;
|
||||
use crate::task_source::TaskSourceName;
|
||||
use crate::webdriver_handlers;
|
||||
use bluetooth_traits::BluetoothRequest;
|
||||
|
@ -128,8 +130,10 @@ use script_traits::CompositorEvent::{
|
|||
WheelEvent,
|
||||
};
|
||||
use script_traits::{CompositorEvent, ConstellationControlMsg};
|
||||
use script_traits::{DiscardBrowsingContext, DocumentActivity, EventResult};
|
||||
use script_traits::{InitialScriptState, JsEvalResult, LayoutMsg, LoadData};
|
||||
use script_traits::{
|
||||
DiscardBrowsingContext, DocumentActivity, EventResult, HistoryEntryReplacement,
|
||||
};
|
||||
use script_traits::{InitialScriptState, JsEvalResult, LayoutMsg, LoadData, LoadOrigin};
|
||||
use script_traits::{MouseButton, MouseEventType, NewLayoutInfo};
|
||||
use script_traits::{Painter, ProgressiveWebMetricType, ScriptMsg, ScriptThreadFactory};
|
||||
use script_traits::{ScriptToConstellationChan, TimerEvent, TimerSchedulerMsg};
|
||||
|
@ -263,10 +267,6 @@ enum MixedMessage {
|
|||
pub enum MainThreadScriptMsg {
|
||||
/// Common variants associated with the script messages
|
||||
Common(CommonScriptMsg),
|
||||
/// Begins a content-initiated load on the specified pipeline (only
|
||||
/// dispatched to ScriptThread). Allows for a replace bool to be passed. If true,
|
||||
/// the current entry will be replaced instead of a new entry being added.
|
||||
Navigate(PipelineId, LoadData, bool),
|
||||
/// Notifies the script thread that a new worklet has been loaded, and thus the page should be
|
||||
/// reflowed.
|
||||
WorkletLoaded(PipelineId),
|
||||
|
@ -855,6 +855,74 @@ impl ScriptThread {
|
|||
});
|
||||
}
|
||||
|
||||
/// Check that two origins are "similar enough",
|
||||
/// for now only used to prevent cross-origin JS url evaluation.
|
||||
///
|
||||
/// https://github.com/whatwg/html/issues/2591
|
||||
pub fn check_load_origin(source: &LoadOrigin, target: &ImmutableOrigin) -> bool {
|
||||
match (source, target) {
|
||||
(LoadOrigin::Constellation, _) | (LoadOrigin::WebDriver, _) => {
|
||||
// Always allow loads initiated by the constellation or webdriver.
|
||||
true
|
||||
},
|
||||
(_, ImmutableOrigin::Opaque(_)) => {
|
||||
// If the target is opaque, allow.
|
||||
// This covers newly created about:blank auxiliaries, and iframe with no src.
|
||||
// TODO: https://github.com/servo/servo/issues/22879
|
||||
true
|
||||
},
|
||||
(LoadOrigin::Script(source_origin), _) => source_origin == target,
|
||||
}
|
||||
}
|
||||
|
||||
/// Step 13 of https://html.spec.whatwg.org/multipage/#navigate
|
||||
pub fn navigate(
|
||||
pipeline_id: PipelineId,
|
||||
mut load_data: LoadData,
|
||||
replace: HistoryEntryReplacement,
|
||||
) {
|
||||
SCRIPT_THREAD_ROOT.with(|root| {
|
||||
let script_thread = match root.get() {
|
||||
None => return,
|
||||
Some(script) => script,
|
||||
};
|
||||
let script_thread = unsafe { &*script_thread };
|
||||
let is_javascript = load_data.url.scheme() == "javascript";
|
||||
// If resource is a request whose url's scheme is "javascript"
|
||||
// https://html.spec.whatwg.org/multipage/#javascript-protocol
|
||||
if is_javascript {
|
||||
let window = match script_thread.documents.borrow().find_window(pipeline_id) {
|
||||
None => return,
|
||||
Some(window) => window,
|
||||
};
|
||||
let global = window.upcast::<GlobalScope>();
|
||||
let trusted_global = Trusted::new(global);
|
||||
let sender = script_thread.script_sender.clone();
|
||||
let task = task!(navigate_javascript: move || {
|
||||
// Important re security. See https://github.com/servo/servo/issues/23373
|
||||
// TODO: check according to https://w3c.github.io/webappsec-csp/#should-block-navigation-request
|
||||
if let Some(window) = trusted_global.root().downcast::<Window>() {
|
||||
if ScriptThread::check_load_origin(&load_data.load_origin, &window.get_url().origin()) {
|
||||
ScriptThread::eval_js_url(&trusted_global.root(), &mut load_data);
|
||||
sender
|
||||
.send((pipeline_id, ScriptMsg::LoadUrl(load_data, replace)))
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
});
|
||||
global
|
||||
.dom_manipulation_task_source()
|
||||
.queue(task, global.upcast())
|
||||
.expect("Enqueing navigate js task on the DOM manipulation task source failed");
|
||||
} else {
|
||||
script_thread
|
||||
.script_sender
|
||||
.send((pipeline_id, ScriptMsg::LoadUrl(load_data, replace)))
|
||||
.expect("Sending a LoadUrl message to the constellation failed");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
pub fn process_attach_layout(new_layout_info: NewLayoutInfo, origin: MutableOrigin) {
|
||||
SCRIPT_THREAD_ROOT.with(|root| {
|
||||
if let Some(script_thread) = root.get() {
|
||||
|
@ -1474,7 +1542,7 @@ impl ScriptThread {
|
|||
SetDocumentActivity(id, ..) => Some(id),
|
||||
ChangeFrameVisibilityStatus(id, ..) => Some(id),
|
||||
NotifyVisibilityChange(id, ..) => Some(id),
|
||||
Navigate(id, ..) => Some(id),
|
||||
NavigateIframe(id, ..) => Some(id),
|
||||
PostMessage { target: id, .. } => Some(id),
|
||||
UpdatePipelineId(_, _, _, id, _) => Some(id),
|
||||
UpdateHistoryState(id, ..) => Some(id),
|
||||
|
@ -1504,7 +1572,6 @@ impl ScriptThread {
|
|||
pipeline_id
|
||||
},
|
||||
MainThreadScriptMsg::Common(CommonScriptMsg::CollectReports(_)) => None,
|
||||
MainThreadScriptMsg::Navigate(pipeline_id, ..) => Some(pipeline_id),
|
||||
MainThreadScriptMsg::WorkletLoaded(pipeline_id) => Some(pipeline_id),
|
||||
MainThreadScriptMsg::RegisterPaintWorklet { pipeline_id, .. } => Some(pipeline_id),
|
||||
MainThreadScriptMsg::DispatchJobQueue { .. } => None,
|
||||
|
@ -1614,14 +1681,14 @@ impl ScriptThread {
|
|||
_ => unreachable!(),
|
||||
};
|
||||
},
|
||||
ConstellationControlMsg::Navigate(
|
||||
ConstellationControlMsg::NavigateIframe(
|
||||
parent_pipeline_id,
|
||||
browsing_context_id,
|
||||
load_data,
|
||||
replace,
|
||||
) => self.handle_navigate(
|
||||
) => self.handle_navigate_iframe(
|
||||
parent_pipeline_id,
|
||||
Some(browsing_context_id),
|
||||
browsing_context_id,
|
||||
load_data,
|
||||
replace,
|
||||
),
|
||||
|
@ -1736,9 +1803,6 @@ impl ScriptThread {
|
|||
|
||||
fn handle_msg_from_script(&self, msg: MainThreadScriptMsg) {
|
||||
match msg {
|
||||
MainThreadScriptMsg::Navigate(parent_pipeline_id, load_data, replace) => {
|
||||
self.handle_navigate(parent_pipeline_id, None, load_data, replace)
|
||||
},
|
||||
MainThreadScriptMsg::Common(CommonScriptMsg::Task(_, task, _, _)) => task.run_box(),
|
||||
MainThreadScriptMsg::Common(CommonScriptMsg::CollectReports(chan)) => {
|
||||
self.collect_reports(chan)
|
||||
|
@ -3248,50 +3312,30 @@ impl ScriptThread {
|
|||
document.handle_wheel_event(self.js_runtime.rt(), wheel_delta, point, node_address);
|
||||
}
|
||||
|
||||
/// <https://html.spec.whatwg.org/multipage/#navigating-across-documents>
|
||||
/// The entry point for content to notify that a new load has been requested
|
||||
/// for the given pipeline (specifically the "navigate" algorithm).
|
||||
fn handle_navigate(
|
||||
/// Handle a "navigate an iframe" message from the constellation.
|
||||
fn handle_navigate_iframe(
|
||||
&self,
|
||||
parent_pipeline_id: PipelineId,
|
||||
browsing_context_id: Option<BrowsingContextId>,
|
||||
mut load_data: LoadData,
|
||||
replace: bool,
|
||||
browsing_context_id: BrowsingContextId,
|
||||
load_data: LoadData,
|
||||
replace: HistoryEntryReplacement,
|
||||
) {
|
||||
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);
|
||||
if let Some(iframe) = iframe {
|
||||
iframe.navigate_or_reload_child_browsing_context(
|
||||
Some(load_data),
|
||||
NavigationType::Regular,
|
||||
replace,
|
||||
);
|
||||
}
|
||||
},
|
||||
None => {
|
||||
self.script_sender
|
||||
.send((parent_pipeline_id, ScriptMsg::LoadUrl(load_data, replace)))
|
||||
.unwrap();
|
||||
},
|
||||
let iframe = self
|
||||
.documents
|
||||
.borrow()
|
||||
.find_iframe(parent_pipeline_id, browsing_context_id);
|
||||
if let Some(iframe) = iframe {
|
||||
iframe.navigate_or_reload_child_browsing_context(
|
||||
load_data,
|
||||
NavigationType::Regular,
|
||||
replace,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Turn javascript: URL into JS code to eval, according to the steps in
|
||||
/// https://html.spec.whatwg.org/multipage/#javascript-protocol
|
||||
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;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue