mirror of
https://github.com/servo/servo.git
synced 2025-07-23 07:13:52 +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
|
@ -145,11 +145,11 @@ use script_traits::{
|
||||||
use script_traits::{
|
use script_traits::{
|
||||||
ConstellationControlMsg, ConstellationMsg as FromCompositorMsg, DiscardBrowsingContext,
|
ConstellationControlMsg, ConstellationMsg as FromCompositorMsg, DiscardBrowsingContext,
|
||||||
};
|
};
|
||||||
use script_traits::{DocumentActivity, DocumentState, LayoutControlMsg, LoadData};
|
use script_traits::{DocumentActivity, DocumentState, LayoutControlMsg, LoadData, LoadOrigin};
|
||||||
|
use script_traits::{HistoryEntryReplacement, IFrameSizeMsg, WindowSizeData, WindowSizeType};
|
||||||
use script_traits::{
|
use script_traits::{
|
||||||
IFrameLoadInfo, IFrameLoadInfoWithData, IFrameSandboxState, TimerSchedulerMsg,
|
IFrameLoadInfo, IFrameLoadInfoWithData, IFrameSandboxState, TimerSchedulerMsg,
|
||||||
};
|
};
|
||||||
use script_traits::{IFrameSizeMsg, WindowSizeData, WindowSizeType};
|
|
||||||
use script_traits::{LayoutMsg as FromLayoutMsg, ScriptMsg as FromScriptMsg, ScriptThreadFactory};
|
use script_traits::{LayoutMsg as FromLayoutMsg, ScriptMsg as FromScriptMsg, ScriptThreadFactory};
|
||||||
use script_traits::{SWManagerMsg, ScopeThings, UpdatePipelineIdReason, WebDriverCommandMsg};
|
use script_traits::{SWManagerMsg, ScopeThings, UpdatePipelineIdReason, WebDriverCommandMsg};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
@ -171,7 +171,7 @@ use style_traits::viewport::ViewportConstraints;
|
||||||
use style_traits::CSSPixel;
|
use style_traits::CSSPixel;
|
||||||
use webvr_traits::{WebVREvent, WebVRMsg};
|
use webvr_traits::{WebVREvent, WebVRMsg};
|
||||||
|
|
||||||
type PendingApprovalNavigations = HashMap<PipelineId, (LoadData, bool)>;
|
type PendingApprovalNavigations = HashMap<PipelineId, (LoadData, HistoryEntryReplacement)>;
|
||||||
|
|
||||||
/// Servo supports tabs (referred to as browsers), so `Constellation` needs to
|
/// Servo supports tabs (referred to as browsers), so `Constellation` needs to
|
||||||
/// store browser specific data for bookkeeping.
|
/// store browser specific data for bookkeeping.
|
||||||
|
@ -1320,7 +1320,7 @@ where
|
||||||
// If there is already a pending page (self.pending_changes), it will not be overridden;
|
// If there is already a pending page (self.pending_changes), it will not be overridden;
|
||||||
// However, if the id is not encompassed by another change, it will be.
|
// However, if the id is not encompassed by another change, it will be.
|
||||||
FromCompositorMsg::LoadUrl(top_level_browsing_context_id, url) => {
|
FromCompositorMsg::LoadUrl(top_level_browsing_context_id, url) => {
|
||||||
let load_data = LoadData::new(url, None, None, None);
|
let load_data = LoadData::new(LoadOrigin::Constellation, url, None, None, None);
|
||||||
let ctx_id = BrowsingContextId::from(top_level_browsing_context_id);
|
let ctx_id = BrowsingContextId::from(top_level_browsing_context_id);
|
||||||
let pipeline_id = match self.browsing_contexts.get(&ctx_id) {
|
let pipeline_id = match self.browsing_contexts.get(&ctx_id) {
|
||||||
Some(ctx) => ctx.pipeline_id,
|
Some(ctx) => ctx.pipeline_id,
|
||||||
|
@ -1333,7 +1333,12 @@ where
|
||||||
};
|
};
|
||||||
// Since this is a top-level load, initiated by the embedder, go straight to load_url,
|
// Since this is a top-level load, initiated by the embedder, go straight to load_url,
|
||||||
// bypassing schedule_navigation.
|
// bypassing schedule_navigation.
|
||||||
self.load_url(top_level_browsing_context_id, pipeline_id, load_data, false);
|
self.load_url(
|
||||||
|
top_level_browsing_context_id,
|
||||||
|
pipeline_id,
|
||||||
|
load_data,
|
||||||
|
HistoryEntryReplacement::Disabled,
|
||||||
|
);
|
||||||
},
|
},
|
||||||
FromCompositorMsg::IsReadyToSaveImage(pipeline_states) => {
|
FromCompositorMsg::IsReadyToSaveImage(pipeline_states) => {
|
||||||
let is_ready = self.handle_is_ready_to_save_image(pipeline_states);
|
let is_ready = self.handle_is_ready_to_save_image(pipeline_states);
|
||||||
|
@ -1916,7 +1921,7 @@ where
|
||||||
warn!("creating replacement pipeline for about:failure");
|
warn!("creating replacement pipeline for about:failure");
|
||||||
|
|
||||||
let new_pipeline_id = PipelineId::new();
|
let new_pipeline_id = PipelineId::new();
|
||||||
let load_data = LoadData::new(failure_url, None, None, None);
|
let load_data = LoadData::new(LoadOrigin::Constellation, failure_url, None, None, None);
|
||||||
let sandbox = IFrameSandboxState::IFrameSandboxed;
|
let sandbox = IFrameSandboxState::IFrameSandboxed;
|
||||||
let is_private = false;
|
let is_private = false;
|
||||||
self.new_pipeline(
|
self.new_pipeline(
|
||||||
|
@ -2035,7 +2040,7 @@ where
|
||||||
);
|
);
|
||||||
self.embedder_proxy.send(msg);
|
self.embedder_proxy.send(msg);
|
||||||
let browsing_context_id = BrowsingContextId::from(top_level_browsing_context_id);
|
let browsing_context_id = BrowsingContextId::from(top_level_browsing_context_id);
|
||||||
let load_data = LoadData::new(url, None, None, None);
|
let load_data = LoadData::new(LoadOrigin::Constellation, url, None, None, None);
|
||||||
let sandbox = IFrameSandboxState::IFrameUnsandboxed;
|
let sandbox = IFrameSandboxState::IFrameUnsandboxed;
|
||||||
let is_private = false;
|
let is_private = false;
|
||||||
let is_visible = true;
|
let is_visible = true;
|
||||||
|
@ -2196,7 +2201,9 @@ where
|
||||||
// see https://html.spec.whatwg.org/multipage/#the-iframe-element:completely-loaded
|
// see https://html.spec.whatwg.org/multipage/#the-iframe-element:completely-loaded
|
||||||
debug!("checking old pipeline? {:?}", load_info.old_pipeline_id);
|
debug!("checking old pipeline? {:?}", load_info.old_pipeline_id);
|
||||||
if let Some(old_pipeline) = old_pipeline {
|
if let Some(old_pipeline) = old_pipeline {
|
||||||
replace |= !old_pipeline.completely_loaded;
|
if !old_pipeline.completely_loaded {
|
||||||
|
replace = HistoryEntryReplacement::Enabled;
|
||||||
|
}
|
||||||
debug!(
|
debug!(
|
||||||
"old pipeline is {}completely loaded",
|
"old pipeline is {}completely loaded",
|
||||||
if old_pipeline.completely_loaded {
|
if old_pipeline.completely_loaded {
|
||||||
|
@ -2207,16 +2214,6 @@ where
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let load_data = load_info.load_data.unwrap_or_else(|| {
|
|
||||||
let url = match old_pipeline {
|
|
||||||
Some(old_pipeline) => old_pipeline.url.clone(),
|
|
||||||
None => ServoUrl::parse("about:blank").expect("infallible"),
|
|
||||||
};
|
|
||||||
|
|
||||||
// TODO - loaddata here should have referrer info (not None, None)
|
|
||||||
LoadData::new(url, Some(parent_pipeline_id), None, None)
|
|
||||||
});
|
|
||||||
|
|
||||||
let is_parent_private = {
|
let is_parent_private = {
|
||||||
let parent_browsing_context_id = match self.pipelines.get(&parent_pipeline_id) {
|
let parent_browsing_context_id = match self.pipelines.get(&parent_pipeline_id) {
|
||||||
Some(pipeline) => pipeline.browsing_context_id,
|
Some(pipeline) => pipeline.browsing_context_id,
|
||||||
|
@ -2250,10 +2247,11 @@ where
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
let replace = if replace {
|
let replace = match replace {
|
||||||
Some(NeedsToReload::No(browsing_context.pipeline_id))
|
HistoryEntryReplacement::Enabled => {
|
||||||
} else {
|
Some(NeedsToReload::No(browsing_context.pipeline_id))
|
||||||
None
|
},
|
||||||
|
HistoryEntryReplacement::Disabled => None,
|
||||||
};
|
};
|
||||||
|
|
||||||
// https://github.com/rust-lang/rust/issues/59159
|
// https://github.com/rust-lang/rust/issues/59159
|
||||||
|
@ -2268,7 +2266,7 @@ where
|
||||||
Some(parent_pipeline_id),
|
Some(parent_pipeline_id),
|
||||||
None,
|
None,
|
||||||
browsing_context_size,
|
browsing_context_size,
|
||||||
load_data,
|
load_info.load_data,
|
||||||
load_info.sandbox,
|
load_info.sandbox,
|
||||||
is_private,
|
is_private,
|
||||||
browsing_context_is_visible,
|
browsing_context_is_visible,
|
||||||
|
@ -2285,7 +2283,7 @@ where
|
||||||
|
|
||||||
fn handle_script_new_iframe(
|
fn handle_script_new_iframe(
|
||||||
&mut self,
|
&mut self,
|
||||||
load_info: IFrameLoadInfo,
|
load_info: IFrameLoadInfoWithData,
|
||||||
layout_sender: IpcSender<LayoutControlMsg>,
|
layout_sender: IpcSender<LayoutControlMsg>,
|
||||||
) {
|
) {
|
||||||
let IFrameLoadInfo {
|
let IFrameLoadInfo {
|
||||||
|
@ -2295,12 +2293,7 @@ where
|
||||||
top_level_browsing_context_id,
|
top_level_browsing_context_id,
|
||||||
is_private,
|
is_private,
|
||||||
..
|
..
|
||||||
} = load_info;
|
} = load_info.info;
|
||||||
|
|
||||||
let url = ServoUrl::parse("about:blank").expect("infallible");
|
|
||||||
|
|
||||||
// TODO: Referrer?
|
|
||||||
let load_data = LoadData::new(url.clone(), Some(parent_pipeline_id), None, None);
|
|
||||||
|
|
||||||
let (script_sender, parent_browsing_context_id) =
|
let (script_sender, parent_browsing_context_id) =
|
||||||
match self.pipelines.get(&parent_pipeline_id) {
|
match self.pipelines.get(&parent_pipeline_id) {
|
||||||
|
@ -2326,9 +2319,8 @@ where
|
||||||
script_sender,
|
script_sender,
|
||||||
layout_sender,
|
layout_sender,
|
||||||
self.compositor_proxy.clone(),
|
self.compositor_proxy.clone(),
|
||||||
url,
|
|
||||||
is_parent_visible,
|
is_parent_visible,
|
||||||
load_data,
|
load_info.load_data,
|
||||||
);
|
);
|
||||||
|
|
||||||
assert!(!self.pipelines.contains_key(&new_pipeline_id));
|
assert!(!self.pipelines.contains_key(&new_pipeline_id));
|
||||||
|
@ -2353,17 +2345,13 @@ where
|
||||||
layout_sender: IpcSender<LayoutControlMsg>,
|
layout_sender: IpcSender<LayoutControlMsg>,
|
||||||
) {
|
) {
|
||||||
let AuxiliaryBrowsingContextLoadInfo {
|
let AuxiliaryBrowsingContextLoadInfo {
|
||||||
|
load_data,
|
||||||
opener_pipeline_id,
|
opener_pipeline_id,
|
||||||
new_top_level_browsing_context_id,
|
new_top_level_browsing_context_id,
|
||||||
new_browsing_context_id,
|
new_browsing_context_id,
|
||||||
new_pipeline_id,
|
new_pipeline_id,
|
||||||
} = load_info;
|
} = load_info;
|
||||||
|
|
||||||
let url = ServoUrl::parse("about:blank").expect("infallible");
|
|
||||||
|
|
||||||
// TODO: Referrer?
|
|
||||||
let load_data = LoadData::new(url.clone(), None, None, None);
|
|
||||||
|
|
||||||
let (script_sender, opener_browsing_context_id) =
|
let (script_sender, opener_browsing_context_id) =
|
||||||
match self.pipelines.get(&opener_pipeline_id) {
|
match self.pipelines.get(&opener_pipeline_id) {
|
||||||
Some(pipeline) => (pipeline.event_loop.clone(), pipeline.browsing_context_id),
|
Some(pipeline) => (pipeline.event_loop.clone(), pipeline.browsing_context_id),
|
||||||
|
@ -2392,7 +2380,6 @@ where
|
||||||
script_sender,
|
script_sender,
|
||||||
layout_sender,
|
layout_sender,
|
||||||
self.compositor_proxy.clone(),
|
self.compositor_proxy.clone(),
|
||||||
url,
|
|
||||||
is_opener_visible,
|
is_opener_visible,
|
||||||
load_data,
|
load_data,
|
||||||
);
|
);
|
||||||
|
@ -2496,7 +2483,7 @@ where
|
||||||
top_level_browsing_context_id: TopLevelBrowsingContextId,
|
top_level_browsing_context_id: TopLevelBrowsingContextId,
|
||||||
source_id: PipelineId,
|
source_id: PipelineId,
|
||||||
load_data: LoadData,
|
load_data: LoadData,
|
||||||
replace: bool,
|
replace: HistoryEntryReplacement,
|
||||||
) {
|
) {
|
||||||
match self.pending_approval_navigations.entry(source_id) {
|
match self.pending_approval_navigations.entry(source_id) {
|
||||||
Entry::Occupied(_) => {
|
Entry::Occupied(_) => {
|
||||||
|
@ -2522,13 +2509,15 @@ where
|
||||||
top_level_browsing_context_id: TopLevelBrowsingContextId,
|
top_level_browsing_context_id: TopLevelBrowsingContextId,
|
||||||
source_id: PipelineId,
|
source_id: PipelineId,
|
||||||
load_data: LoadData,
|
load_data: LoadData,
|
||||||
replace: bool,
|
replace: HistoryEntryReplacement,
|
||||||
) -> Option<PipelineId> {
|
) -> Option<PipelineId> {
|
||||||
|
let replace_debug = match replace {
|
||||||
|
HistoryEntryReplacement::Enabled => "",
|
||||||
|
HistoryEntryReplacement::Disabled => "not",
|
||||||
|
};
|
||||||
debug!(
|
debug!(
|
||||||
"Loading {} in pipeline {}, {}replacing.",
|
"Loading {} in pipeline {}, {}replacing.",
|
||||||
load_data.url,
|
load_data.url, source_id, replace_debug
|
||||||
source_id,
|
|
||||||
if replace { "" } else { "not " }
|
|
||||||
);
|
);
|
||||||
// If this load targets an iframe, its framing element may exist
|
// If this load targets an iframe, its framing element may exist
|
||||||
// in a separate script thread than the framed document that initiated
|
// in a separate script thread than the framed document that initiated
|
||||||
|
@ -2569,7 +2558,7 @@ where
|
||||||
Some(parent_pipeline_id) => {
|
Some(parent_pipeline_id) => {
|
||||||
// Find the script thread for the pipeline containing the iframe
|
// Find the script thread for the pipeline containing the iframe
|
||||||
// and issue an iframe load through there.
|
// and issue an iframe load through there.
|
||||||
let msg = ConstellationControlMsg::Navigate(
|
let msg = ConstellationControlMsg::NavigateIframe(
|
||||||
parent_pipeline_id,
|
parent_pipeline_id,
|
||||||
browsing_context_id,
|
browsing_context_id,
|
||||||
load_data,
|
load_data,
|
||||||
|
@ -2612,10 +2601,9 @@ where
|
||||||
|
|
||||||
// Create the new pipeline
|
// Create the new pipeline
|
||||||
|
|
||||||
let replace = if replace {
|
let replace = match replace {
|
||||||
Some(NeedsToReload::No(pipeline_id))
|
HistoryEntryReplacement::Enabled => Some(NeedsToReload::No(pipeline_id)),
|
||||||
} else {
|
HistoryEntryReplacement::Disabled => None,
|
||||||
None
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let new_pipeline_id = PipelineId::new();
|
let new_pipeline_id = PipelineId::new();
|
||||||
|
@ -2730,7 +2718,7 @@ where
|
||||||
&mut self,
|
&mut self,
|
||||||
pipeline_id: PipelineId,
|
pipeline_id: PipelineId,
|
||||||
new_url: ServoUrl,
|
new_url: ServoUrl,
|
||||||
replacement_enabled: bool,
|
replacement_enabled: HistoryEntryReplacement,
|
||||||
) {
|
) {
|
||||||
let (top_level_browsing_context_id, old_url) = match self.pipelines.get_mut(&pipeline_id) {
|
let (top_level_browsing_context_id, old_url) = match self.pipelines.get_mut(&pipeline_id) {
|
||||||
Some(pipeline) => {
|
Some(pipeline) => {
|
||||||
|
@ -2745,15 +2733,18 @@ where
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
if !replacement_enabled {
|
match replacement_enabled {
|
||||||
let diff = SessionHistoryDiff::HashDiff {
|
HistoryEntryReplacement::Disabled => {
|
||||||
pipeline_reloader: NeedsToReload::No(pipeline_id),
|
let diff = SessionHistoryDiff::HashDiff {
|
||||||
new_url,
|
pipeline_reloader: NeedsToReload::No(pipeline_id),
|
||||||
old_url,
|
new_url,
|
||||||
};
|
old_url,
|
||||||
self.get_joint_session_history(top_level_browsing_context_id)
|
};
|
||||||
.push_diff(diff);
|
self.get_joint_session_history(top_level_browsing_context_id)
|
||||||
self.notify_history_changed(top_level_browsing_context_id);
|
.push_diff(diff);
|
||||||
|
self.notify_history_changed(top_level_browsing_context_id);
|
||||||
|
},
|
||||||
|
HistoryEntryReplacement::Enabled => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3395,7 +3386,12 @@ where
|
||||||
));
|
));
|
||||||
},
|
},
|
||||||
WebDriverCommandMsg::LoadUrl(top_level_browsing_context_id, load_data, reply) => {
|
WebDriverCommandMsg::LoadUrl(top_level_browsing_context_id, load_data, reply) => {
|
||||||
self.load_url_for_webdriver(top_level_browsing_context_id, load_data, reply, false);
|
self.load_url_for_webdriver(
|
||||||
|
top_level_browsing_context_id,
|
||||||
|
load_data,
|
||||||
|
reply,
|
||||||
|
HistoryEntryReplacement::Disabled,
|
||||||
|
);
|
||||||
},
|
},
|
||||||
WebDriverCommandMsg::Refresh(top_level_browsing_context_id, reply) => {
|
WebDriverCommandMsg::Refresh(top_level_browsing_context_id, reply) => {
|
||||||
let browsing_context_id = BrowsingContextId::from(top_level_browsing_context_id);
|
let browsing_context_id = BrowsingContextId::from(top_level_browsing_context_id);
|
||||||
|
@ -3412,7 +3408,12 @@ where
|
||||||
Some(pipeline) => pipeline.load_data.clone(),
|
Some(pipeline) => pipeline.load_data.clone(),
|
||||||
None => return warn!("Pipeline {} refresh after closure.", pipeline_id),
|
None => return warn!("Pipeline {} refresh after closure.", pipeline_id),
|
||||||
};
|
};
|
||||||
self.load_url_for_webdriver(top_level_browsing_context_id, load_data, reply, true);
|
self.load_url_for_webdriver(
|
||||||
|
top_level_browsing_context_id,
|
||||||
|
load_data,
|
||||||
|
reply,
|
||||||
|
HistoryEntryReplacement::Enabled,
|
||||||
|
);
|
||||||
},
|
},
|
||||||
WebDriverCommandMsg::ScriptCommand(browsing_context_id, cmd) => {
|
WebDriverCommandMsg::ScriptCommand(browsing_context_id, cmd) => {
|
||||||
let pipeline_id = match self.browsing_contexts.get(&browsing_context_id) {
|
let pipeline_id = match self.browsing_contexts.get(&browsing_context_id) {
|
||||||
|
@ -3595,7 +3596,7 @@ where
|
||||||
top_level_browsing_context_id: TopLevelBrowsingContextId,
|
top_level_browsing_context_id: TopLevelBrowsingContextId,
|
||||||
load_data: LoadData,
|
load_data: LoadData,
|
||||||
reply: IpcSender<webdriver_msg::LoadStatus>,
|
reply: IpcSender<webdriver_msg::LoadStatus>,
|
||||||
replace: bool,
|
replace: HistoryEntryReplacement,
|
||||||
) {
|
) {
|
||||||
let browsing_context_id = BrowsingContextId::from(top_level_browsing_context_id);
|
let browsing_context_id = BrowsingContextId::from(top_level_browsing_context_id);
|
||||||
let pipeline_id = match self.browsing_contexts.get(&browsing_context_id) {
|
let pipeline_id = match self.browsing_contexts.get(&browsing_context_id) {
|
||||||
|
|
|
@ -215,8 +215,6 @@ impl Pipeline {
|
||||||
device_pixel_ratio: state.device_pixel_ratio,
|
device_pixel_ratio: state.device_pixel_ratio,
|
||||||
};
|
};
|
||||||
|
|
||||||
let url = state.load_data.url.clone();
|
|
||||||
|
|
||||||
let (script_chan, sampler_chan) = match state.event_loop {
|
let (script_chan, sampler_chan) = match state.event_loop {
|
||||||
Some(script_chan) => {
|
Some(script_chan) => {
|
||||||
let new_layout_info = NewLayoutInfo {
|
let new_layout_info = NewLayoutInfo {
|
||||||
|
@ -336,7 +334,6 @@ impl Pipeline {
|
||||||
script_chan,
|
script_chan,
|
||||||
pipeline_chan,
|
pipeline_chan,
|
||||||
state.compositor_proxy,
|
state.compositor_proxy,
|
||||||
url,
|
|
||||||
state.prev_visibility,
|
state.prev_visibility,
|
||||||
state.load_data,
|
state.load_data,
|
||||||
);
|
);
|
||||||
|
@ -356,7 +353,6 @@ impl Pipeline {
|
||||||
event_loop: Rc<EventLoop>,
|
event_loop: Rc<EventLoop>,
|
||||||
layout_chan: IpcSender<LayoutControlMsg>,
|
layout_chan: IpcSender<LayoutControlMsg>,
|
||||||
compositor_proxy: CompositorProxy,
|
compositor_proxy: CompositorProxy,
|
||||||
url: ServoUrl,
|
|
||||||
is_visible: bool,
|
is_visible: bool,
|
||||||
load_data: LoadData,
|
load_data: LoadData,
|
||||||
) -> Pipeline {
|
) -> Pipeline {
|
||||||
|
@ -368,7 +364,7 @@ impl Pipeline {
|
||||||
event_loop: event_loop,
|
event_loop: event_loop,
|
||||||
layout_chan: layout_chan,
|
layout_chan: layout_chan,
|
||||||
compositor_proxy: compositor_proxy,
|
compositor_proxy: compositor_proxy,
|
||||||
url: url,
|
url: load_data.url.clone(),
|
||||||
children: vec![],
|
children: vec![],
|
||||||
running_animations: false,
|
running_animations: false,
|
||||||
load_data: load_data,
|
load_data: load_data,
|
||||||
|
|
|
@ -11,6 +11,7 @@ use crate::dom::bindings::codegen::Bindings::HTMLAnchorElementBinding::HTMLAncho
|
||||||
use crate::dom::bindings::codegen::Bindings::MouseEventBinding::MouseEventMethods;
|
use crate::dom::bindings::codegen::Bindings::MouseEventBinding::MouseEventMethods;
|
||||||
use crate::dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
|
use crate::dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
|
||||||
use crate::dom::bindings::inheritance::Castable;
|
use crate::dom::bindings::inheritance::Castable;
|
||||||
|
use crate::dom::bindings::refcounted::Trusted;
|
||||||
use crate::dom::bindings::root::{DomRoot, MutNullableDom};
|
use crate::dom::bindings::root::{DomRoot, MutNullableDom};
|
||||||
use crate::dom::bindings::str::{DOMString, USVString};
|
use crate::dom::bindings::str::{DOMString, USVString};
|
||||||
use crate::dom::document::determine_policy_for_token;
|
use crate::dom::document::determine_policy_for_token;
|
||||||
|
@ -19,16 +20,19 @@ use crate::dom::domtokenlist::DOMTokenList;
|
||||||
use crate::dom::element::Element;
|
use crate::dom::element::Element;
|
||||||
use crate::dom::event::Event;
|
use crate::dom::event::Event;
|
||||||
use crate::dom::eventtarget::EventTarget;
|
use crate::dom::eventtarget::EventTarget;
|
||||||
|
use crate::dom::globalscope::GlobalScope;
|
||||||
use crate::dom::htmlelement::HTMLElement;
|
use crate::dom::htmlelement::HTMLElement;
|
||||||
use crate::dom::htmlimageelement::HTMLImageElement;
|
use crate::dom::htmlimageelement::HTMLImageElement;
|
||||||
use crate::dom::mouseevent::MouseEvent;
|
use crate::dom::mouseevent::MouseEvent;
|
||||||
use crate::dom::node::{document_from_node, Node};
|
use crate::dom::node::{document_from_node, Node};
|
||||||
use crate::dom::urlhelper::UrlHelper;
|
use crate::dom::urlhelper::UrlHelper;
|
||||||
use crate::dom::virtualmethods::VirtualMethods;
|
use crate::dom::virtualmethods::VirtualMethods;
|
||||||
|
use crate::task_source::TaskSource;
|
||||||
use dom_struct::dom_struct;
|
use dom_struct::dom_struct;
|
||||||
use html5ever::{LocalName, Prefix};
|
use html5ever::{LocalName, Prefix};
|
||||||
use net_traits::request::Referrer;
|
use net_traits::request::Referrer;
|
||||||
use num_traits::ToPrimitive;
|
use num_traits::ToPrimitive;
|
||||||
|
use script_traits::{HistoryEntryReplacement, LoadData, LoadOrigin};
|
||||||
use servo_url::ServoUrl;
|
use servo_url::ServoUrl;
|
||||||
use std::default::Default;
|
use std::default::Default;
|
||||||
use style::attr::AttrValue;
|
use style::attr::AttrValue;
|
||||||
|
@ -624,8 +628,19 @@ pub fn follow_hyperlink(subject: &Element, hyperlink_suffix: Option<String>) {
|
||||||
|
|
||||||
// Step 7.
|
// Step 7.
|
||||||
let (maybe_chosen, replace) = match target_attribute_value {
|
let (maybe_chosen, replace) = match target_attribute_value {
|
||||||
Some(name) => source.choose_browsing_context(name.Value(), noopener),
|
Some(name) => {
|
||||||
None => (Some(window.window_proxy()), false),
|
let (maybe_chosen, new) = source.choose_browsing_context(name.Value(), noopener);
|
||||||
|
let replace = if new {
|
||||||
|
HistoryEntryReplacement::Enabled
|
||||||
|
} else {
|
||||||
|
HistoryEntryReplacement::Disabled
|
||||||
|
};
|
||||||
|
(maybe_chosen, replace)
|
||||||
|
},
|
||||||
|
None => (
|
||||||
|
Some(window.window_proxy()),
|
||||||
|
HistoryEntryReplacement::Disabled,
|
||||||
|
),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Step 8.
|
// Step 8.
|
||||||
|
@ -667,7 +682,23 @@ pub fn follow_hyperlink(subject: &Element, hyperlink_suffix: Option<String>) {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Step 14
|
// Step 14
|
||||||
debug!("following hyperlink to {}", url);
|
let pipeline_id = target_window.upcast::<GlobalScope>().pipeline_id();
|
||||||
target_window.load_url(url, replace, false, referrer, referrer_policy);
|
let load_data = LoadData::new(
|
||||||
|
LoadOrigin::Script(document.origin().immutable().clone()),
|
||||||
|
url,
|
||||||
|
Some(pipeline_id),
|
||||||
|
Some(referrer),
|
||||||
|
referrer_policy,
|
||||||
|
);
|
||||||
|
let target = Trusted::new(target_window);
|
||||||
|
let task = task!(navigate_follow_hyperlink: move || {
|
||||||
|
debug!("following hyperlink to {}", load_data.url);
|
||||||
|
target.root().load_url(replace, false, load_data);
|
||||||
|
});
|
||||||
|
target_window
|
||||||
|
.task_manager()
|
||||||
|
.dom_manipulation_task_source()
|
||||||
|
.queue(task, target_window.upcast())
|
||||||
|
.unwrap();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use crate::dom::bindings::cell::DomRefCell;
|
use crate::dom::bindings::cell::DomRefCell;
|
||||||
|
use crate::dom::bindings::codegen::Bindings::AttrBinding::AttrBinding::AttrMethods;
|
||||||
use crate::dom::bindings::codegen::Bindings::BlobBinding::BlobMethods;
|
use crate::dom::bindings::codegen::Bindings::BlobBinding::BlobMethods;
|
||||||
use crate::dom::bindings::codegen::Bindings::DocumentBinding::DocumentMethods;
|
use crate::dom::bindings::codegen::Bindings::DocumentBinding::DocumentMethods;
|
||||||
use crate::dom::bindings::codegen::Bindings::EventBinding::EventMethods;
|
use crate::dom::bindings::codegen::Bindings::EventBinding::EventMethods;
|
||||||
|
@ -12,6 +13,7 @@ use crate::dom::bindings::codegen::Bindings::HTMLFormElementBinding;
|
||||||
use crate::dom::bindings::codegen::Bindings::HTMLFormElementBinding::HTMLFormElementMethods;
|
use crate::dom::bindings::codegen::Bindings::HTMLFormElementBinding::HTMLFormElementMethods;
|
||||||
use crate::dom::bindings::codegen::Bindings::HTMLInputElementBinding::HTMLInputElementMethods;
|
use crate::dom::bindings::codegen::Bindings::HTMLInputElementBinding::HTMLInputElementMethods;
|
||||||
use crate::dom::bindings::codegen::Bindings::HTMLTextAreaElementBinding::HTMLTextAreaElementMethods;
|
use crate::dom::bindings::codegen::Bindings::HTMLTextAreaElementBinding::HTMLTextAreaElementMethods;
|
||||||
|
use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowBinding::WindowMethods;
|
||||||
use crate::dom::bindings::inheritance::{Castable, ElementTypeId, HTMLElementTypeId, NodeTypeId};
|
use crate::dom::bindings::inheritance::{Castable, ElementTypeId, HTMLElementTypeId, NodeTypeId};
|
||||||
use crate::dom::bindings::refcounted::Trusted;
|
use crate::dom::bindings::refcounted::Trusted;
|
||||||
use crate::dom::bindings::reflector::DomObject;
|
use crate::dom::bindings::reflector::DomObject;
|
||||||
|
@ -46,7 +48,6 @@ use crate::dom::node::{UnbindContext, VecPreOrderInsertionHelper};
|
||||||
use crate::dom::validitystate::ValidationFlags;
|
use crate::dom::validitystate::ValidationFlags;
|
||||||
use crate::dom::virtualmethods::VirtualMethods;
|
use crate::dom::virtualmethods::VirtualMethods;
|
||||||
use crate::dom::window::Window;
|
use crate::dom::window::Window;
|
||||||
use crate::script_thread::MainThreadScriptMsg;
|
|
||||||
use crate::task_source::TaskSource;
|
use crate::task_source::TaskSource;
|
||||||
use dom_struct::dom_struct;
|
use dom_struct::dom_struct;
|
||||||
use encoding_rs::{Encoding, UTF_8};
|
use encoding_rs::{Encoding, UTF_8};
|
||||||
|
@ -57,7 +58,7 @@ use hyper::Method;
|
||||||
use mime::{self, Mime};
|
use mime::{self, Mime};
|
||||||
use net_traits::http_percent_encode;
|
use net_traits::http_percent_encode;
|
||||||
use net_traits::request::Referrer;
|
use net_traits::request::Referrer;
|
||||||
use script_traits::LoadData;
|
use script_traits::{HistoryEntryReplacement, LoadData, LoadOrigin};
|
||||||
use servo_rand::random;
|
use servo_rand::random;
|
||||||
use std::borrow::ToOwned;
|
use std::borrow::ToOwned;
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
|
@ -400,6 +401,7 @@ impl HTMLFormElement {
|
||||||
};
|
};
|
||||||
let target_window = target_document.window();
|
let target_window = target_document.window();
|
||||||
let mut load_data = LoadData::new(
|
let mut load_data = LoadData::new(
|
||||||
|
LoadOrigin::Script(doc.origin().immutable().clone()),
|
||||||
action_components,
|
action_components,
|
||||||
None,
|
None,
|
||||||
Some(Referrer::ReferrerUrl(target_document.url())),
|
Some(Referrer::ReferrerUrl(target_document.url())),
|
||||||
|
@ -530,7 +532,7 @@ impl HTMLFormElement {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// [Planned navigation](https://html.spec.whatwg.org/multipage/#planned-navigation)
|
/// [Planned navigation](https://html.spec.whatwg.org/multipage/#planned-navigation)
|
||||||
fn plan_to_navigate(&self, load_data: LoadData, target: &Window) {
|
fn plan_to_navigate(&self, mut load_data: LoadData, target: &Window) {
|
||||||
// Step 1
|
// Step 1
|
||||||
// Each planned navigation task is tagged with a generation ID, and
|
// Each planned navigation task is tagged with a generation ID, and
|
||||||
// before the task is handled, it first checks whether the HTMLFormElement's
|
// before the task is handled, it first checks whether the HTMLFormElement's
|
||||||
|
@ -538,19 +540,35 @@ impl HTMLFormElement {
|
||||||
let generation_id = GenerationId(self.generation_id.get().0 + 1);
|
let generation_id = GenerationId(self.generation_id.get().0 + 1);
|
||||||
self.generation_id.set(generation_id);
|
self.generation_id.set(generation_id);
|
||||||
|
|
||||||
// Step 2.
|
// Step 2
|
||||||
|
let elem = self.upcast::<Element>();
|
||||||
|
let referrer = match elem.get_attribute(&ns!(), &local_name!("rel")) {
|
||||||
|
Some(ref link_types) if link_types.Value().contains("noreferrer") => {
|
||||||
|
Referrer::NoReferrer
|
||||||
|
},
|
||||||
|
_ => Referrer::Client,
|
||||||
|
};
|
||||||
|
|
||||||
|
let referrer_policy = target.Document().get_referrer_policy();
|
||||||
let pipeline_id = target.upcast::<GlobalScope>().pipeline_id();
|
let pipeline_id = target.upcast::<GlobalScope>().pipeline_id();
|
||||||
let script_chan = target.main_thread_script_chan().clone();
|
load_data.creator_pipeline_id = Some(pipeline_id);
|
||||||
|
load_data.referrer = Some(referrer);
|
||||||
|
load_data.referrer_policy = referrer_policy;
|
||||||
|
|
||||||
|
// Step 4.
|
||||||
let this = Trusted::new(self);
|
let this = Trusted::new(self);
|
||||||
|
let window = Trusted::new(target);
|
||||||
let task = task!(navigate_to_form_planned_navigation: move || {
|
let task = task!(navigate_to_form_planned_navigation: move || {
|
||||||
if generation_id != this.root().generation_id.get() {
|
if generation_id != this.root().generation_id.get() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
script_chan.send(MainThreadScriptMsg::Navigate(
|
window
|
||||||
pipeline_id,
|
.root()
|
||||||
load_data,
|
.load_url(
|
||||||
false,
|
HistoryEntryReplacement::Disabled,
|
||||||
)).unwrap();
|
false,
|
||||||
|
load_data,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Step 3.
|
// Step 3.
|
||||||
|
|
|
@ -37,8 +37,8 @@ use profile_traits::ipc as ProfiledIpc;
|
||||||
use script_layout_interface::message::ReflowGoal;
|
use script_layout_interface::message::ReflowGoal;
|
||||||
use script_traits::IFrameSandboxState::{IFrameSandboxed, IFrameUnsandboxed};
|
use script_traits::IFrameSandboxState::{IFrameSandboxed, IFrameUnsandboxed};
|
||||||
use script_traits::{
|
use script_traits::{
|
||||||
IFrameLoadInfo, IFrameLoadInfoWithData, JsEvalResult, LoadData, UpdatePipelineIdReason,
|
HistoryEntryReplacement, IFrameLoadInfo, IFrameLoadInfoWithData, JsEvalResult, LoadData,
|
||||||
WindowSizeData,
|
LoadOrigin, UpdatePipelineIdReason, WindowSizeData,
|
||||||
};
|
};
|
||||||
use script_traits::{NewLayoutInfo, ScriptMsg};
|
use script_traits::{NewLayoutInfo, ScriptMsg};
|
||||||
use servo_url::ServoUrl;
|
use servo_url::ServoUrl;
|
||||||
|
@ -109,9 +109,9 @@ impl HTMLIFrameElement {
|
||||||
|
|
||||||
pub fn navigate_or_reload_child_browsing_context(
|
pub fn navigate_or_reload_child_browsing_context(
|
||||||
&self,
|
&self,
|
||||||
mut load_data: Option<LoadData>,
|
mut load_data: LoadData,
|
||||||
nav_type: NavigationType,
|
nav_type: NavigationType,
|
||||||
replace: bool,
|
replace: HistoryEntryReplacement,
|
||||||
) {
|
) {
|
||||||
let sandboxed = if self.is_sandboxed() {
|
let sandboxed = if self.is_sandboxed() {
|
||||||
IFrameSandboxed
|
IFrameSandboxed
|
||||||
|
@ -136,30 +136,27 @@ impl HTMLIFrameElement {
|
||||||
// document; the new navigation will continue blocking it.
|
// document; the new navigation will continue blocking it.
|
||||||
LoadBlocker::terminate(&mut load_blocker);
|
LoadBlocker::terminate(&mut load_blocker);
|
||||||
|
|
||||||
if let Some(ref mut load_data) = load_data {
|
if load_data.url.scheme() == "javascript" {
|
||||||
let is_javascript = load_data.url.scheme() == "javascript";
|
let window_proxy = self.GetContentWindow();
|
||||||
if is_javascript {
|
if let Some(window_proxy) = window_proxy {
|
||||||
let window_proxy = self.GetContentWindow();
|
// Important re security. See https://github.com/servo/servo/issues/23373
|
||||||
if let Some(window_proxy) = window_proxy {
|
// TODO: check according to https://w3c.github.io/webappsec-csp/#should-block-navigation-request
|
||||||
ScriptThread::eval_js_url(&window_proxy.global(), load_data);
|
if ScriptThread::check_load_origin(&load_data.load_origin, &document.url().origin())
|
||||||
|
{
|
||||||
|
ScriptThread::eval_js_url(&window_proxy.global(), &mut load_data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO(#9592): Deal with the case where an iframe is being reloaded so url is None.
|
match load_data.js_eval_result {
|
||||||
// The iframe should always have access to the nested context's active
|
Some(JsEvalResult::NoContent) => (),
|
||||||
// document URL through the browsing context.
|
_ => {
|
||||||
if let Some(ref load_data) = load_data {
|
*load_blocker = Some(LoadBlocker::new(
|
||||||
match load_data.js_eval_result {
|
&*document,
|
||||||
Some(JsEvalResult::NoContent) => (),
|
LoadType::Subframe(load_data.url.clone()),
|
||||||
_ => {
|
));
|
||||||
*load_blocker = Some(LoadBlocker::new(
|
},
|
||||||
&*document,
|
};
|
||||||
LoadType::Subframe(load_data.url.clone()),
|
|
||||||
));
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
let window = window_from_node(self);
|
let window = window_from_node(self);
|
||||||
let old_pipeline_id = self.pipeline_id();
|
let old_pipeline_id = self.pipeline_id();
|
||||||
|
@ -182,6 +179,12 @@ impl HTMLIFrameElement {
|
||||||
|
|
||||||
self.about_blank_pipeline_id.set(Some(new_pipeline_id));
|
self.about_blank_pipeline_id.set(Some(new_pipeline_id));
|
||||||
|
|
||||||
|
let load_info = IFrameLoadInfoWithData {
|
||||||
|
info: load_info,
|
||||||
|
load_data: load_data.clone(),
|
||||||
|
old_pipeline_id: old_pipeline_id,
|
||||||
|
sandbox: sandboxed,
|
||||||
|
};
|
||||||
global_scope
|
global_scope
|
||||||
.script_to_constellation_chan()
|
.script_to_constellation_chan()
|
||||||
.send(ScriptMsg::ScriptNewIFrame(load_info, pipeline_sender))
|
.send(ScriptMsg::ScriptNewIFrame(load_info, pipeline_sender))
|
||||||
|
@ -193,7 +196,7 @@ impl HTMLIFrameElement {
|
||||||
browsing_context_id: browsing_context_id,
|
browsing_context_id: browsing_context_id,
|
||||||
top_level_browsing_context_id: top_level_browsing_context_id,
|
top_level_browsing_context_id: top_level_browsing_context_id,
|
||||||
opener: None,
|
opener: None,
|
||||||
load_data: load_data.unwrap(),
|
load_data: load_data,
|
||||||
pipeline_port: pipeline_receiver,
|
pipeline_port: pipeline_receiver,
|
||||||
content_process_shutdown_chan: None,
|
content_process_shutdown_chan: None,
|
||||||
window_size: WindowSizeData {
|
window_size: WindowSizeData {
|
||||||
|
@ -270,6 +273,7 @@ impl HTMLIFrameElement {
|
||||||
|
|
||||||
let document = document_from_node(self);
|
let document = document_from_node(self);
|
||||||
let load_data = LoadData::new(
|
let load_data = LoadData::new(
|
||||||
|
LoadOrigin::Script(document.origin().immutable().clone()),
|
||||||
url,
|
url,
|
||||||
creator_pipeline_id,
|
creator_pipeline_id,
|
||||||
Some(Referrer::ReferrerUrl(document.url())),
|
Some(Referrer::ReferrerUrl(document.url())),
|
||||||
|
@ -281,12 +285,12 @@ impl HTMLIFrameElement {
|
||||||
// see https://html.spec.whatwg.org/multipage/#the-iframe-element:about:blank-3
|
// see https://html.spec.whatwg.org/multipage/#the-iframe-element:about:blank-3
|
||||||
let is_about_blank =
|
let is_about_blank =
|
||||||
pipeline_id.is_some() && pipeline_id == self.about_blank_pipeline_id.get();
|
pipeline_id.is_some() && pipeline_id == self.about_blank_pipeline_id.get();
|
||||||
let replace = is_about_blank;
|
let replace = if is_about_blank {
|
||||||
self.navigate_or_reload_child_browsing_context(
|
HistoryEntryReplacement::Enabled
|
||||||
Some(load_data),
|
} else {
|
||||||
NavigationType::Regular,
|
HistoryEntryReplacement::Disabled
|
||||||
replace,
|
};
|
||||||
);
|
self.navigate_or_reload_child_browsing_context(load_data, NavigationType::Regular, replace);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_nested_browsing_context(&self) {
|
fn create_nested_browsing_context(&self) {
|
||||||
|
@ -296,6 +300,7 @@ impl HTMLIFrameElement {
|
||||||
let window = window_from_node(self);
|
let window = window_from_node(self);
|
||||||
let pipeline_id = Some(window.upcast::<GlobalScope>().pipeline_id());
|
let pipeline_id = Some(window.upcast::<GlobalScope>().pipeline_id());
|
||||||
let load_data = LoadData::new(
|
let load_data = LoadData::new(
|
||||||
|
LoadOrigin::Script(document.origin().immutable().clone()),
|
||||||
url,
|
url,
|
||||||
pipeline_id,
|
pipeline_id,
|
||||||
Some(Referrer::ReferrerUrl(document.url().clone())),
|
Some(Referrer::ReferrerUrl(document.url().clone())),
|
||||||
|
@ -309,9 +314,9 @@ impl HTMLIFrameElement {
|
||||||
.set(Some(top_level_browsing_context_id));
|
.set(Some(top_level_browsing_context_id));
|
||||||
self.browsing_context_id.set(Some(browsing_context_id));
|
self.browsing_context_id.set(Some(browsing_context_id));
|
||||||
self.navigate_or_reload_child_browsing_context(
|
self.navigate_or_reload_child_browsing_context(
|
||||||
Some(load_data),
|
load_data,
|
||||||
NavigationType::InitialAboutBlank,
|
NavigationType::InitialAboutBlank,
|
||||||
false,
|
HistoryEntryReplacement::Disabled,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@ use crate::dom::bindings::codegen::Bindings::LocationBinding;
|
||||||
use crate::dom::bindings::codegen::Bindings::LocationBinding::LocationMethods;
|
use crate::dom::bindings::codegen::Bindings::LocationBinding::LocationMethods;
|
||||||
use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowBinding::WindowMethods;
|
use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowBinding::WindowMethods;
|
||||||
use crate::dom::bindings::error::{Error, ErrorResult, Fallible};
|
use crate::dom::bindings::error::{Error, ErrorResult, Fallible};
|
||||||
|
use crate::dom::bindings::inheritance::Castable;
|
||||||
use crate::dom::bindings::reflector::{reflect_dom_object, Reflector};
|
use crate::dom::bindings::reflector::{reflect_dom_object, Reflector};
|
||||||
use crate::dom::bindings::root::{Dom, DomRoot};
|
use crate::dom::bindings::root::{Dom, DomRoot};
|
||||||
use crate::dom::bindings::str::{DOMString, USVString};
|
use crate::dom::bindings::str::{DOMString, USVString};
|
||||||
|
@ -14,6 +15,7 @@ use crate::dom::urlhelper::UrlHelper;
|
||||||
use crate::dom::window::Window;
|
use crate::dom::window::Window;
|
||||||
use dom_struct::dom_struct;
|
use dom_struct::dom_struct;
|
||||||
use net_traits::request::Referrer;
|
use net_traits::request::Referrer;
|
||||||
|
use script_traits::{HistoryEntryReplacement, LoadData, LoadOrigin};
|
||||||
use servo_url::{MutableOrigin, ServoUrl};
|
use servo_url::{MutableOrigin, ServoUrl};
|
||||||
|
|
||||||
#[dom_struct]
|
#[dom_struct]
|
||||||
|
@ -38,6 +40,29 @@ impl Location {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// https://html.spec.whatwg.org/multipage/#location-object-navigate
|
||||||
|
fn navigate(
|
||||||
|
&self,
|
||||||
|
url: ServoUrl,
|
||||||
|
referrer: Referrer,
|
||||||
|
replacement_flag: HistoryEntryReplacement,
|
||||||
|
reload_triggered: bool,
|
||||||
|
) {
|
||||||
|
let document = self.window.Document();
|
||||||
|
let referrer_policy = document.get_referrer_policy();
|
||||||
|
let pipeline_id = self.window.upcast::<GlobalScope>().pipeline_id();
|
||||||
|
let load_data = LoadData::new(
|
||||||
|
LoadOrigin::Script(document.origin().immutable().clone()),
|
||||||
|
url,
|
||||||
|
Some(pipeline_id),
|
||||||
|
Some(referrer),
|
||||||
|
referrer_policy,
|
||||||
|
);
|
||||||
|
// TODO: rethrow exceptions, set exceptions enabled flag.
|
||||||
|
self.window
|
||||||
|
.load_url(replacement_flag, reload_triggered, load_data);
|
||||||
|
}
|
||||||
|
|
||||||
fn get_url(&self) -> ServoUrl {
|
fn get_url(&self) -> ServoUrl {
|
||||||
self.window.get_url()
|
self.window.get_url()
|
||||||
}
|
}
|
||||||
|
@ -46,7 +71,7 @@ impl Location {
|
||||||
let mut url = self.window.get_url();
|
let mut url = self.window.get_url();
|
||||||
let referrer = Referrer::ReferrerUrl(url.clone());
|
let referrer = Referrer::ReferrerUrl(url.clone());
|
||||||
setter(&mut url, value);
|
setter(&mut url, value);
|
||||||
self.window.load_url(url, false, false, referrer, None);
|
self.navigate(url, referrer, HistoryEntryReplacement::Disabled, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_same_origin_domain(&self) -> ErrorResult {
|
fn check_same_origin_domain(&self) -> ErrorResult {
|
||||||
|
@ -66,7 +91,7 @@ impl Location {
|
||||||
pub fn reload_without_origin_check(&self) {
|
pub fn reload_without_origin_check(&self) {
|
||||||
let url = self.get_url();
|
let url = self.get_url();
|
||||||
let referrer = Referrer::ReferrerUrl(url.clone());
|
let referrer = Referrer::ReferrerUrl(url.clone());
|
||||||
self.window.load_url(url, true, true, referrer, None);
|
self.navigate(url, referrer, HistoryEntryReplacement::Enabled, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
|
@ -84,7 +109,7 @@ impl LocationMethods for Location {
|
||||||
let base_url = self.window.get_url();
|
let base_url = self.window.get_url();
|
||||||
if let Ok(url) = base_url.join(&url.0) {
|
if let Ok(url) = base_url.join(&url.0) {
|
||||||
let referrer = Referrer::ReferrerUrl(base_url.clone());
|
let referrer = Referrer::ReferrerUrl(base_url.clone());
|
||||||
self.window.load_url(url, false, false, referrer, None);
|
self.navigate(url, referrer, HistoryEntryReplacement::Disabled, false);
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Err(Error::Syntax)
|
Err(Error::Syntax)
|
||||||
|
@ -96,7 +121,7 @@ impl LocationMethods for Location {
|
||||||
self.check_same_origin_domain()?;
|
self.check_same_origin_domain()?;
|
||||||
let url = self.get_url();
|
let url = self.get_url();
|
||||||
let referrer = Referrer::ReferrerUrl(url.clone());
|
let referrer = Referrer::ReferrerUrl(url.clone());
|
||||||
self.window.load_url(url, true, true, referrer, None);
|
self.navigate(url, referrer, HistoryEntryReplacement::Enabled, true);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,7 +133,7 @@ impl LocationMethods for Location {
|
||||||
let base_url = self.window.get_url();
|
let base_url = self.window.get_url();
|
||||||
if let Ok(url) = base_url.join(&url.0) {
|
if let Ok(url) = base_url.join(&url.0) {
|
||||||
let referrer = Referrer::ReferrerUrl(base_url.clone());
|
let referrer = Referrer::ReferrerUrl(base_url.clone());
|
||||||
self.window.load_url(url, true, false, referrer, None);
|
self.navigate(url, referrer, HistoryEntryReplacement::Enabled, false);
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Err(Error::Syntax)
|
Err(Error::Syntax)
|
||||||
|
@ -178,7 +203,7 @@ impl LocationMethods for Location {
|
||||||
Err(e) => return Err(Error::Type(format!("Couldn't parse URL: {}", e))),
|
Err(e) => return Err(Error::Type(format!("Couldn't parse URL: {}", e))),
|
||||||
};
|
};
|
||||||
let referrer = Referrer::ReferrerUrl(current_url.clone());
|
let referrer = Referrer::ReferrerUrl(current_url.clone());
|
||||||
self.window.load_url(url, false, false, referrer, None);
|
self.navigate(url, referrer, HistoryEntryReplacement::Disabled, false);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -88,9 +88,8 @@ use js::rust::HandleValue;
|
||||||
use msg::constellation_msg::PipelineId;
|
use msg::constellation_msg::PipelineId;
|
||||||
use net_traits::image_cache::{ImageCache, ImageResponder, ImageResponse};
|
use net_traits::image_cache::{ImageCache, ImageResponder, ImageResponse};
|
||||||
use net_traits::image_cache::{PendingImageId, PendingImageResponse};
|
use net_traits::image_cache::{PendingImageId, PendingImageResponse};
|
||||||
use net_traits::request::Referrer;
|
|
||||||
use net_traits::storage_thread::StorageType;
|
use net_traits::storage_thread::StorageType;
|
||||||
use net_traits::{ReferrerPolicy, ResourceThreads};
|
use net_traits::ResourceThreads;
|
||||||
use num_traits::ToPrimitive;
|
use num_traits::ToPrimitive;
|
||||||
use profile_traits::ipc as ProfiledIpc;
|
use profile_traits::ipc as ProfiledIpc;
|
||||||
use profile_traits::mem::ProfilerChan as MemProfilerChan;
|
use profile_traits::mem::ProfilerChan as MemProfilerChan;
|
||||||
|
@ -102,7 +101,7 @@ use script_layout_interface::rpc::{
|
||||||
};
|
};
|
||||||
use script_layout_interface::{PendingImageState, TrustedNodeAddress};
|
use script_layout_interface::{PendingImageState, TrustedNodeAddress};
|
||||||
use script_traits::webdriver_msg::{WebDriverJSError, WebDriverJSResult};
|
use script_traits::webdriver_msg::{WebDriverJSError, WebDriverJSResult};
|
||||||
use script_traits::{ConstellationControlMsg, DocumentState, LoadData};
|
use script_traits::{ConstellationControlMsg, DocumentState, HistoryEntryReplacement, LoadData};
|
||||||
use script_traits::{ScriptMsg, ScriptToConstellationChan, ScrollState, TimerEvent, TimerEventId};
|
use script_traits::{ScriptMsg, ScriptToConstellationChan, ScrollState, TimerEvent, TimerEventId};
|
||||||
use script_traits::{TimerSchedulerMsg, WindowSizeData, WindowSizeType};
|
use script_traits::{TimerSchedulerMsg, WindowSizeData, WindowSizeType};
|
||||||
use selectors::attr::CaseSensitivity;
|
use selectors::attr::CaseSensitivity;
|
||||||
|
@ -1729,27 +1728,31 @@ impl Window {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Commence a new URL load which will either replace this window or scroll to a fragment.
|
/// Commence a new URL load which will either replace this window or scroll to a fragment.
|
||||||
|
///
|
||||||
|
/// https://html.spec.whatwg.org/multipage/#navigating-across-documents
|
||||||
pub fn load_url(
|
pub fn load_url(
|
||||||
&self,
|
&self,
|
||||||
url: ServoUrl,
|
replace: HistoryEntryReplacement,
|
||||||
replace: bool,
|
|
||||||
force_reload: bool,
|
force_reload: bool,
|
||||||
referrer: Referrer,
|
load_data: LoadData,
|
||||||
referrer_policy: Option<ReferrerPolicy>,
|
|
||||||
) {
|
) {
|
||||||
let doc = self.Document();
|
let doc = self.Document();
|
||||||
let referrer_policy = referrer_policy.or(doc.get_referrer_policy());
|
// TODO: Important re security. See https://github.com/servo/servo/issues/23373
|
||||||
// https://html.spec.whatwg.org/multipage/#navigating-across-documents
|
// Step 3: check that the source browsing-context is "allowed to navigate" this window.
|
||||||
if !force_reload &&
|
if !force_reload &&
|
||||||
url.as_url()[..Position::AfterQuery] == doc.url().as_url()[..Position::AfterQuery]
|
load_data.url.as_url()[..Position::AfterQuery] ==
|
||||||
|
doc.url().as_url()[..Position::AfterQuery]
|
||||||
{
|
{
|
||||||
// Step 6
|
// Step 6
|
||||||
if let Some(fragment) = url.fragment() {
|
if let Some(fragment) = load_data.url.fragment() {
|
||||||
self.send_to_constellation(ScriptMsg::NavigatedToFragment(url.clone(), replace));
|
self.send_to_constellation(ScriptMsg::NavigatedToFragment(
|
||||||
|
load_data.url.clone(),
|
||||||
|
replace,
|
||||||
|
));
|
||||||
doc.check_and_scroll_fragment(fragment);
|
doc.check_and_scroll_fragment(fragment);
|
||||||
let this = Trusted::new(self);
|
let this = Trusted::new(self);
|
||||||
let old_url = doc.url().into_string();
|
let old_url = doc.url().into_string();
|
||||||
let new_url = url.clone().into_string();
|
let new_url = load_data.url.clone().into_string();
|
||||||
let task = task!(hashchange_event: move || {
|
let task = task!(hashchange_event: move || {
|
||||||
let this = this.root();
|
let this = this.root();
|
||||||
let event = HashChangeEvent::new(
|
let event = HashChangeEvent::new(
|
||||||
|
@ -1772,7 +1775,7 @@ impl Window {
|
||||||
self.pipeline_id(),
|
self.pipeline_id(),
|
||||||
TaskSourceName::DOMManipulation,
|
TaskSourceName::DOMManipulation,
|
||||||
));
|
));
|
||||||
doc.set_url(url.clone());
|
doc.set_url(load_data.url.clone());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1797,13 +1800,9 @@ impl Window {
|
||||||
// then put it in the delaying load events mode.
|
// then put it in the delaying load events mode.
|
||||||
self.window_proxy().start_delaying_load_events_mode();
|
self.window_proxy().start_delaying_load_events_mode();
|
||||||
}
|
}
|
||||||
self.main_thread_script_chan()
|
// TODO: step 11, navigationType.
|
||||||
.send(MainThreadScriptMsg::Navigate(
|
// Step 12, 13
|
||||||
pipeline_id,
|
ScriptThread::navigate(pipeline_id, load_data, replace);
|
||||||
LoadData::new(url, Some(pipeline_id), Some(referrer), referrer_policy),
|
|
||||||
replace,
|
|
||||||
))
|
|
||||||
.unwrap();
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -46,7 +46,10 @@ use msg::constellation_msg::BrowsingContextId;
|
||||||
use msg::constellation_msg::PipelineId;
|
use msg::constellation_msg::PipelineId;
|
||||||
use msg::constellation_msg::TopLevelBrowsingContextId;
|
use msg::constellation_msg::TopLevelBrowsingContextId;
|
||||||
use net_traits::request::Referrer;
|
use net_traits::request::Referrer;
|
||||||
use script_traits::{AuxiliaryBrowsingContextLoadInfo, LoadData, NewLayoutInfo, ScriptMsg};
|
use script_traits::{
|
||||||
|
AuxiliaryBrowsingContextLoadInfo, HistoryEntryReplacement, LoadData, LoadOrigin,
|
||||||
|
};
|
||||||
|
use script_traits::{NewLayoutInfo, ScriptMsg};
|
||||||
use servo_url::ServoUrl;
|
use servo_url::ServoUrl;
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
|
@ -267,24 +270,28 @@ impl WindowProxy {
|
||||||
let new_browsing_context_id =
|
let new_browsing_context_id =
|
||||||
BrowsingContextId::from(new_top_level_browsing_context_id);
|
BrowsingContextId::from(new_top_level_browsing_context_id);
|
||||||
let new_pipeline_id = PipelineId::new();
|
let new_pipeline_id = PipelineId::new();
|
||||||
let load_info = AuxiliaryBrowsingContextLoadInfo {
|
|
||||||
opener_pipeline_id: self.currently_active.get().unwrap(),
|
|
||||||
new_browsing_context_id: new_browsing_context_id,
|
|
||||||
new_top_level_browsing_context_id: new_top_level_browsing_context_id,
|
|
||||||
new_pipeline_id: new_pipeline_id,
|
|
||||||
};
|
|
||||||
let document = self
|
let document = self
|
||||||
.currently_active
|
.currently_active
|
||||||
.get()
|
.get()
|
||||||
.and_then(|id| ScriptThread::find_document(id))
|
.and_then(|id| ScriptThread::find_document(id))
|
||||||
.unwrap();
|
.expect("A WindowProxy creating an auxiliary to have an active document");
|
||||||
|
|
||||||
let blank_url = ServoUrl::parse("about:blank").ok().unwrap();
|
let blank_url = ServoUrl::parse("about:blank").ok().unwrap();
|
||||||
let load_data = LoadData::new(
|
let load_data = LoadData::new(
|
||||||
|
LoadOrigin::Script(document.origin().immutable().clone()),
|
||||||
blank_url,
|
blank_url,
|
||||||
None,
|
None,
|
||||||
Some(Referrer::ReferrerUrl(document.url().clone())),
|
Some(Referrer::ReferrerUrl(document.url().clone())),
|
||||||
document.get_referrer_policy(),
|
document.get_referrer_policy(),
|
||||||
);
|
);
|
||||||
|
let load_info = AuxiliaryBrowsingContextLoadInfo {
|
||||||
|
load_data: load_data.clone(),
|
||||||
|
opener_pipeline_id: self.currently_active.get().unwrap(),
|
||||||
|
new_browsing_context_id: new_browsing_context_id,
|
||||||
|
new_top_level_browsing_context_id: new_top_level_browsing_context_id,
|
||||||
|
new_pipeline_id: new_pipeline_id,
|
||||||
|
};
|
||||||
|
|
||||||
let (pipeline_sender, pipeline_receiver) = ipc::channel().unwrap();
|
let (pipeline_sender, pipeline_receiver) = ipc::channel().unwrap();
|
||||||
let new_layout_info = NewLayoutInfo {
|
let new_layout_info = NewLayoutInfo {
|
||||||
parent_info: None,
|
parent_info: None,
|
||||||
|
@ -436,13 +443,21 @@ impl WindowProxy {
|
||||||
Referrer::Client
|
Referrer::Client
|
||||||
};
|
};
|
||||||
// Step 14.5
|
// Step 14.5
|
||||||
target_window.load_url(
|
let referrer_policy = target_document.get_referrer_policy();
|
||||||
|
let pipeline_id = target_window.upcast::<GlobalScope>().pipeline_id();
|
||||||
|
let load_data = LoadData::new(
|
||||||
|
LoadOrigin::Script(existing_document.origin().immutable().clone()),
|
||||||
url,
|
url,
|
||||||
new,
|
Some(pipeline_id),
|
||||||
false,
|
Some(referrer),
|
||||||
referrer,
|
referrer_policy,
|
||||||
target_document.get_referrer_policy(),
|
|
||||||
);
|
);
|
||||||
|
let replacement_flag = if new {
|
||||||
|
HistoryEntryReplacement::Enabled
|
||||||
|
} else {
|
||||||
|
HistoryEntryReplacement::Disabled
|
||||||
|
};
|
||||||
|
target_window.load_url(replacement_flag, false, load_data);
|
||||||
}
|
}
|
||||||
if noopener {
|
if noopener {
|
||||||
// Step 15 (Dis-owning has been done in create_auxiliary_browsing_context).
|
// Step 15 (Dis-owning has been done in create_auxiliary_browsing_context).
|
||||||
|
|
|
@ -32,6 +32,7 @@ use crate::dom::bindings::conversions::{
|
||||||
};
|
};
|
||||||
use crate::dom::bindings::inheritance::Castable;
|
use crate::dom::bindings::inheritance::Castable;
|
||||||
use crate::dom::bindings::num::Finite;
|
use crate::dom::bindings::num::Finite;
|
||||||
|
use crate::dom::bindings::refcounted::Trusted;
|
||||||
use crate::dom::bindings::reflector::DomObject;
|
use crate::dom::bindings::reflector::DomObject;
|
||||||
use crate::dom::bindings::root::ThreadLocalStackRoots;
|
use crate::dom::bindings::root::ThreadLocalStackRoots;
|
||||||
use crate::dom::bindings::root::{Dom, DomRoot, MutNullableDom, RootCollection};
|
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::remote_event::RemoteEventTaskSource;
|
||||||
use crate::task_source::user_interaction::UserInteractionTaskSource;
|
use crate::task_source::user_interaction::UserInteractionTaskSource;
|
||||||
use crate::task_source::websocket::WebsocketTaskSource;
|
use crate::task_source::websocket::WebsocketTaskSource;
|
||||||
|
use crate::task_source::TaskSource;
|
||||||
use crate::task_source::TaskSourceName;
|
use crate::task_source::TaskSourceName;
|
||||||
use crate::webdriver_handlers;
|
use crate::webdriver_handlers;
|
||||||
use bluetooth_traits::BluetoothRequest;
|
use bluetooth_traits::BluetoothRequest;
|
||||||
|
@ -128,8 +130,10 @@ use script_traits::CompositorEvent::{
|
||||||
WheelEvent,
|
WheelEvent,
|
||||||
};
|
};
|
||||||
use script_traits::{CompositorEvent, ConstellationControlMsg};
|
use script_traits::{CompositorEvent, ConstellationControlMsg};
|
||||||
use script_traits::{DiscardBrowsingContext, DocumentActivity, EventResult};
|
use script_traits::{
|
||||||
use script_traits::{InitialScriptState, JsEvalResult, LayoutMsg, LoadData};
|
DiscardBrowsingContext, DocumentActivity, EventResult, HistoryEntryReplacement,
|
||||||
|
};
|
||||||
|
use script_traits::{InitialScriptState, JsEvalResult, LayoutMsg, LoadData, LoadOrigin};
|
||||||
use script_traits::{MouseButton, MouseEventType, NewLayoutInfo};
|
use script_traits::{MouseButton, MouseEventType, NewLayoutInfo};
|
||||||
use script_traits::{Painter, ProgressiveWebMetricType, ScriptMsg, ScriptThreadFactory};
|
use script_traits::{Painter, ProgressiveWebMetricType, ScriptMsg, ScriptThreadFactory};
|
||||||
use script_traits::{ScriptToConstellationChan, TimerEvent, TimerSchedulerMsg};
|
use script_traits::{ScriptToConstellationChan, TimerEvent, TimerSchedulerMsg};
|
||||||
|
@ -263,10 +267,6 @@ enum MixedMessage {
|
||||||
pub enum MainThreadScriptMsg {
|
pub enum MainThreadScriptMsg {
|
||||||
/// Common variants associated with the script messages
|
/// Common variants associated with the script messages
|
||||||
Common(CommonScriptMsg),
|
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
|
/// Notifies the script thread that a new worklet has been loaded, and thus the page should be
|
||||||
/// reflowed.
|
/// reflowed.
|
||||||
WorkletLoaded(PipelineId),
|
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) {
|
pub fn process_attach_layout(new_layout_info: NewLayoutInfo, origin: MutableOrigin) {
|
||||||
SCRIPT_THREAD_ROOT.with(|root| {
|
SCRIPT_THREAD_ROOT.with(|root| {
|
||||||
if let Some(script_thread) = root.get() {
|
if let Some(script_thread) = root.get() {
|
||||||
|
@ -1474,7 +1542,7 @@ impl ScriptThread {
|
||||||
SetDocumentActivity(id, ..) => Some(id),
|
SetDocumentActivity(id, ..) => Some(id),
|
||||||
ChangeFrameVisibilityStatus(id, ..) => Some(id),
|
ChangeFrameVisibilityStatus(id, ..) => Some(id),
|
||||||
NotifyVisibilityChange(id, ..) => Some(id),
|
NotifyVisibilityChange(id, ..) => Some(id),
|
||||||
Navigate(id, ..) => Some(id),
|
NavigateIframe(id, ..) => Some(id),
|
||||||
PostMessage { target: id, .. } => Some(id),
|
PostMessage { target: id, .. } => Some(id),
|
||||||
UpdatePipelineId(_, _, _, id, _) => Some(id),
|
UpdatePipelineId(_, _, _, id, _) => Some(id),
|
||||||
UpdateHistoryState(id, ..) => Some(id),
|
UpdateHistoryState(id, ..) => Some(id),
|
||||||
|
@ -1504,7 +1572,6 @@ impl ScriptThread {
|
||||||
pipeline_id
|
pipeline_id
|
||||||
},
|
},
|
||||||
MainThreadScriptMsg::Common(CommonScriptMsg::CollectReports(_)) => None,
|
MainThreadScriptMsg::Common(CommonScriptMsg::CollectReports(_)) => None,
|
||||||
MainThreadScriptMsg::Navigate(pipeline_id, ..) => Some(pipeline_id),
|
|
||||||
MainThreadScriptMsg::WorkletLoaded(pipeline_id) => Some(pipeline_id),
|
MainThreadScriptMsg::WorkletLoaded(pipeline_id) => Some(pipeline_id),
|
||||||
MainThreadScriptMsg::RegisterPaintWorklet { pipeline_id, .. } => Some(pipeline_id),
|
MainThreadScriptMsg::RegisterPaintWorklet { pipeline_id, .. } => Some(pipeline_id),
|
||||||
MainThreadScriptMsg::DispatchJobQueue { .. } => None,
|
MainThreadScriptMsg::DispatchJobQueue { .. } => None,
|
||||||
|
@ -1614,14 +1681,14 @@ impl ScriptThread {
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
ConstellationControlMsg::Navigate(
|
ConstellationControlMsg::NavigateIframe(
|
||||||
parent_pipeline_id,
|
parent_pipeline_id,
|
||||||
browsing_context_id,
|
browsing_context_id,
|
||||||
load_data,
|
load_data,
|
||||||
replace,
|
replace,
|
||||||
) => self.handle_navigate(
|
) => self.handle_navigate_iframe(
|
||||||
parent_pipeline_id,
|
parent_pipeline_id,
|
||||||
Some(browsing_context_id),
|
browsing_context_id,
|
||||||
load_data,
|
load_data,
|
||||||
replace,
|
replace,
|
||||||
),
|
),
|
||||||
|
@ -1736,9 +1803,6 @@ impl ScriptThread {
|
||||||
|
|
||||||
fn handle_msg_from_script(&self, msg: MainThreadScriptMsg) {
|
fn handle_msg_from_script(&self, msg: MainThreadScriptMsg) {
|
||||||
match msg {
|
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::Task(_, task, _, _)) => task.run_box(),
|
||||||
MainThreadScriptMsg::Common(CommonScriptMsg::CollectReports(chan)) => {
|
MainThreadScriptMsg::Common(CommonScriptMsg::CollectReports(chan)) => {
|
||||||
self.collect_reports(chan)
|
self.collect_reports(chan)
|
||||||
|
@ -3248,50 +3312,30 @@ impl ScriptThread {
|
||||||
document.handle_wheel_event(self.js_runtime.rt(), wheel_delta, point, node_address);
|
document.handle_wheel_event(self.js_runtime.rt(), wheel_delta, point, node_address);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <https://html.spec.whatwg.org/multipage/#navigating-across-documents>
|
/// Handle a "navigate an iframe" message from the constellation.
|
||||||
/// The entry point for content to notify that a new load has been requested
|
fn handle_navigate_iframe(
|
||||||
/// for the given pipeline (specifically the "navigate" algorithm).
|
|
||||||
fn handle_navigate(
|
|
||||||
&self,
|
&self,
|
||||||
parent_pipeline_id: PipelineId,
|
parent_pipeline_id: PipelineId,
|
||||||
browsing_context_id: Option<BrowsingContextId>,
|
browsing_context_id: BrowsingContextId,
|
||||||
mut load_data: LoadData,
|
load_data: LoadData,
|
||||||
replace: bool,
|
replace: HistoryEntryReplacement,
|
||||||
) {
|
) {
|
||||||
let is_javascript = load_data.url.scheme() == "javascript";
|
let iframe = self
|
||||||
if is_javascript {
|
.documents
|
||||||
let window = self.documents.borrow().find_window(parent_pipeline_id);
|
.borrow()
|
||||||
if let Some(window) = window {
|
.find_iframe(parent_pipeline_id, browsing_context_id);
|
||||||
ScriptThread::eval_js_url(window.upcast::<GlobalScope>(), &mut load_data);
|
if let Some(iframe) = iframe {
|
||||||
}
|
iframe.navigate_or_reload_child_browsing_context(
|
||||||
}
|
load_data,
|
||||||
|
NavigationType::Regular,
|
||||||
match browsing_context_id {
|
replace,
|
||||||
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();
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 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) {
|
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.):
|
// This slice of the URL’s serialization is equivalent to (5.) to (7.):
|
||||||
// Start with the scheme data of the parsed URL;
|
// Start with the scheme data of the parsed URL;
|
||||||
// append question mark and query component, if any;
|
// append question mark and query component, if any;
|
||||||
|
|
|
@ -62,7 +62,8 @@ use webrender_api::{
|
||||||
use webvr_traits::{WebVREvent, WebVRMsg};
|
use webvr_traits::{WebVREvent, WebVRMsg};
|
||||||
|
|
||||||
pub use crate::script_msg::{
|
pub use crate::script_msg::{
|
||||||
DOMMessage, SWManagerMsg, SWManagerSenders, ScopeThings, ServiceWorkerMsg,
|
DOMMessage, HistoryEntryReplacement, SWManagerMsg, SWManagerSenders, ScopeThings,
|
||||||
|
ServiceWorkerMsg,
|
||||||
};
|
};
|
||||||
pub use crate::script_msg::{
|
pub use crate::script_msg::{
|
||||||
EventResult, IFrameSize, IFrameSizeMsg, LayoutMsg, LogEntry, ScriptMsg,
|
EventResult, IFrameSize, IFrameSizeMsg, LayoutMsg, LogEntry, ScriptMsg,
|
||||||
|
@ -117,10 +118,24 @@ pub enum LayoutControlMsg {
|
||||||
PaintMetric(Epoch, u64),
|
PaintMetric(Epoch, u64),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The origin where a given load was initiated.
|
||||||
|
/// Useful for origin checks, for example before evaluation a JS URL.
|
||||||
|
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||||
|
pub enum LoadOrigin {
|
||||||
|
/// A load originating in the constellation.
|
||||||
|
Constellation,
|
||||||
|
/// A load originating in webdriver.
|
||||||
|
WebDriver,
|
||||||
|
/// A load originating in script.
|
||||||
|
Script(ImmutableOrigin),
|
||||||
|
}
|
||||||
|
|
||||||
/// can be passed to `LoadUrl` to load a page with GET/POST
|
/// can be passed to `LoadUrl` to load a page with GET/POST
|
||||||
/// parameters or headers
|
/// parameters or headers
|
||||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||||
pub struct LoadData {
|
pub struct LoadData {
|
||||||
|
/// The origin where the load started.
|
||||||
|
pub load_origin: LoadOrigin,
|
||||||
/// The URL.
|
/// The URL.
|
||||||
pub url: ServoUrl,
|
pub url: ServoUrl,
|
||||||
/// The creator pipeline id if this is an about:blank load.
|
/// The creator pipeline id if this is an about:blank load.
|
||||||
|
@ -160,12 +175,14 @@ pub enum JsEvalResult {
|
||||||
impl LoadData {
|
impl LoadData {
|
||||||
/// Create a new `LoadData` object.
|
/// Create a new `LoadData` object.
|
||||||
pub fn new(
|
pub fn new(
|
||||||
|
load_origin: LoadOrigin,
|
||||||
url: ServoUrl,
|
url: ServoUrl,
|
||||||
creator_pipeline_id: Option<PipelineId>,
|
creator_pipeline_id: Option<PipelineId>,
|
||||||
referrer: Option<Referrer>,
|
referrer: Option<Referrer>,
|
||||||
referrer_policy: Option<ReferrerPolicy>,
|
referrer_policy: Option<ReferrerPolicy>,
|
||||||
) -> LoadData {
|
) -> LoadData {
|
||||||
LoadData {
|
LoadData {
|
||||||
|
load_origin,
|
||||||
url: url,
|
url: url,
|
||||||
creator_pipeline_id: creator_pipeline_id,
|
creator_pipeline_id: creator_pipeline_id,
|
||||||
method: Method::GET,
|
method: Method::GET,
|
||||||
|
@ -289,7 +306,12 @@ pub enum ConstellationControlMsg {
|
||||||
NotifyVisibilityChange(PipelineId, BrowsingContextId, bool),
|
NotifyVisibilityChange(PipelineId, BrowsingContextId, bool),
|
||||||
/// Notifies script thread that a url should be loaded in this iframe.
|
/// Notifies script thread that a url should be loaded in this iframe.
|
||||||
/// PipelineId is for the parent, BrowsingContextId is for the nested browsing context
|
/// PipelineId is for the parent, BrowsingContextId is for the nested browsing context
|
||||||
Navigate(PipelineId, BrowsingContextId, LoadData, bool),
|
NavigateIframe(
|
||||||
|
PipelineId,
|
||||||
|
BrowsingContextId,
|
||||||
|
LoadData,
|
||||||
|
HistoryEntryReplacement,
|
||||||
|
),
|
||||||
/// Post a message to a given window.
|
/// Post a message to a given window.
|
||||||
PostMessage {
|
PostMessage {
|
||||||
/// The target of the message.
|
/// The target of the message.
|
||||||
|
@ -376,7 +398,7 @@ impl fmt::Debug for ConstellationControlMsg {
|
||||||
SetDocumentActivity(..) => "SetDocumentActivity",
|
SetDocumentActivity(..) => "SetDocumentActivity",
|
||||||
ChangeFrameVisibilityStatus(..) => "ChangeFrameVisibilityStatus",
|
ChangeFrameVisibilityStatus(..) => "ChangeFrameVisibilityStatus",
|
||||||
NotifyVisibilityChange(..) => "NotifyVisibilityChange",
|
NotifyVisibilityChange(..) => "NotifyVisibilityChange",
|
||||||
Navigate(..) => "Navigate",
|
NavigateIframe(..) => "NavigateIframe",
|
||||||
PostMessage { .. } => "PostMessage",
|
PostMessage { .. } => "PostMessage",
|
||||||
UpdatePipelineId(..) => "UpdatePipelineId",
|
UpdatePipelineId(..) => "UpdatePipelineId",
|
||||||
UpdateHistoryState(..) => "UpdateHistoryState",
|
UpdateHistoryState(..) => "UpdateHistoryState",
|
||||||
|
@ -659,6 +681,8 @@ pub enum IFrameSandboxState {
|
||||||
/// Specifies the information required to load an auxiliary browsing context.
|
/// Specifies the information required to load an auxiliary browsing context.
|
||||||
#[derive(Debug, Deserialize, Serialize)]
|
#[derive(Debug, Deserialize, Serialize)]
|
||||||
pub struct AuxiliaryBrowsingContextLoadInfo {
|
pub struct AuxiliaryBrowsingContextLoadInfo {
|
||||||
|
/// Load data containing the url to load
|
||||||
|
pub load_data: LoadData,
|
||||||
/// The pipeline opener browsing context.
|
/// The pipeline opener browsing context.
|
||||||
pub opener_pipeline_id: PipelineId,
|
pub opener_pipeline_id: PipelineId,
|
||||||
/// The new top-level ID for the auxiliary.
|
/// The new top-level ID for the auxiliary.
|
||||||
|
@ -684,7 +708,7 @@ pub struct IFrameLoadInfo {
|
||||||
pub is_private: bool,
|
pub is_private: bool,
|
||||||
/// Wether this load should replace the current entry (reload). If true, the current
|
/// Wether this load should replace the current entry (reload). If true, the current
|
||||||
/// entry will be replaced instead of a new entry being added.
|
/// entry will be replaced instead of a new entry being added.
|
||||||
pub replace: bool,
|
pub replace: HistoryEntryReplacement,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Specifies the information required to load a URL in an iframe.
|
/// Specifies the information required to load a URL in an iframe.
|
||||||
|
@ -693,7 +717,7 @@ pub struct IFrameLoadInfoWithData {
|
||||||
/// The information required to load an iframe.
|
/// The information required to load an iframe.
|
||||||
pub info: IFrameLoadInfo,
|
pub info: IFrameLoadInfo,
|
||||||
/// Load data containing the url to load
|
/// Load data containing the url to load
|
||||||
pub load_data: Option<LoadData>,
|
pub load_data: LoadData,
|
||||||
/// The old pipeline ID for this iframe, if a page was previously loaded.
|
/// The old pipeline ID for this iframe, if a page was previously loaded.
|
||||||
pub old_pipeline_id: Option<PipelineId>,
|
pub old_pipeline_id: Option<PipelineId>,
|
||||||
/// Sandbox type of this iframe
|
/// Sandbox type of this iframe
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
use crate::AnimationState;
|
use crate::AnimationState;
|
||||||
use crate::AuxiliaryBrowsingContextLoadInfo;
|
use crate::AuxiliaryBrowsingContextLoadInfo;
|
||||||
use crate::DocumentState;
|
use crate::DocumentState;
|
||||||
use crate::IFrameLoadInfo;
|
|
||||||
use crate::IFrameLoadInfoWithData;
|
use crate::IFrameLoadInfoWithData;
|
||||||
use crate::LayoutControlMsg;
|
use crate::LayoutControlMsg;
|
||||||
use crate::LoadData;
|
use crate::LoadData;
|
||||||
|
@ -97,6 +96,15 @@ pub enum LogEntry {
|
||||||
Warn(String),
|
Warn(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// https://html.spec.whatwg.org/multipage/#replacement-enabled
|
||||||
|
#[derive(Debug, Deserialize, Serialize)]
|
||||||
|
pub enum HistoryEntryReplacement {
|
||||||
|
/// Traverse the history with replacement enabled.
|
||||||
|
Enabled,
|
||||||
|
/// Traverse the history with replacement disabled.
|
||||||
|
Disabled,
|
||||||
|
}
|
||||||
|
|
||||||
/// Messages from the script to the constellation.
|
/// Messages from the script to the constellation.
|
||||||
#[derive(Deserialize, Serialize)]
|
#[derive(Deserialize, Serialize)]
|
||||||
pub enum ScriptMsg {
|
pub enum ScriptMsg {
|
||||||
|
@ -145,7 +153,7 @@ pub enum ScriptMsg {
|
||||||
LoadComplete,
|
LoadComplete,
|
||||||
/// A new load has been requested, with an option to replace the current entry once loaded
|
/// A new load has been requested, with an option to replace the current entry once loaded
|
||||||
/// instead of adding a new entry.
|
/// instead of adding a new entry.
|
||||||
LoadUrl(LoadData, bool),
|
LoadUrl(LoadData, HistoryEntryReplacement),
|
||||||
/// Abort loading after sending a LoadUrl message.
|
/// Abort loading after sending a LoadUrl message.
|
||||||
AbortLoadUrl,
|
AbortLoadUrl,
|
||||||
/// Post a message to the currently active window of a given browsing context.
|
/// Post a message to the currently active window of a given browsing context.
|
||||||
|
@ -160,7 +168,7 @@ pub enum ScriptMsg {
|
||||||
data: Vec<u8>,
|
data: Vec<u8>,
|
||||||
},
|
},
|
||||||
/// Inform the constellation that a fragment was navigated to and whether or not it was a replacement navigation.
|
/// Inform the constellation that a fragment was navigated to and whether or not it was a replacement navigation.
|
||||||
NavigatedToFragment(ServoUrl, bool),
|
NavigatedToFragment(ServoUrl, HistoryEntryReplacement),
|
||||||
/// HTMLIFrameElement Forward or Back traversal.
|
/// HTMLIFrameElement Forward or Back traversal.
|
||||||
TraverseHistory(TraversalDirection),
|
TraverseHistory(TraversalDirection),
|
||||||
/// Inform the constellation of a pushed history state.
|
/// Inform the constellation of a pushed history state.
|
||||||
|
@ -177,7 +185,7 @@ pub enum ScriptMsg {
|
||||||
/// A load has been requested in an IFrame.
|
/// A load has been requested in an IFrame.
|
||||||
ScriptLoadedURLInIFrame(IFrameLoadInfoWithData),
|
ScriptLoadedURLInIFrame(IFrameLoadInfoWithData),
|
||||||
/// A load of the initial `about:blank` has been completed in an IFrame.
|
/// A load of the initial `about:blank` has been completed in an IFrame.
|
||||||
ScriptNewIFrame(IFrameLoadInfo, IpcSender<LayoutControlMsg>),
|
ScriptNewIFrame(IFrameLoadInfoWithData, IpcSender<LayoutControlMsg>),
|
||||||
/// Script has opened a new auxiliary browsing context.
|
/// Script has opened a new auxiliary browsing context.
|
||||||
ScriptNewAuxiliary(
|
ScriptNewAuxiliary(
|
||||||
AuxiliaryBrowsingContextLoadInfo,
|
AuxiliaryBrowsingContextLoadInfo,
|
||||||
|
|
|
@ -30,7 +30,7 @@ use script_traits::webdriver_msg::{LoadStatus, WebDriverCookieError, WebDriverFr
|
||||||
use script_traits::webdriver_msg::{
|
use script_traits::webdriver_msg::{
|
||||||
WebDriverJSError, WebDriverJSResult, WebDriverJSValue, WebDriverScriptCommand,
|
WebDriverJSError, WebDriverJSResult, WebDriverJSValue, WebDriverScriptCommand,
|
||||||
};
|
};
|
||||||
use script_traits::{ConstellationMsg, LoadData, WebDriverCommandMsg};
|
use script_traits::{ConstellationMsg, LoadData, LoadOrigin, WebDriverCommandMsg};
|
||||||
use serde::de::{Deserialize, Deserializer, MapAccess, Visitor};
|
use serde::de::{Deserialize, Deserializer, MapAccess, Visitor};
|
||||||
use serde::ser::{Serialize, Serializer};
|
use serde::ser::{Serialize, Serializer};
|
||||||
use serde_json::{json, Value};
|
use serde_json::{json, Value};
|
||||||
|
@ -581,7 +581,7 @@ impl Handler {
|
||||||
|
|
||||||
let (sender, receiver) = ipc::channel().unwrap();
|
let (sender, receiver) = ipc::channel().unwrap();
|
||||||
|
|
||||||
let load_data = LoadData::new(url, None, None, None);
|
let load_data = LoadData::new(LoadOrigin::WebDriver, url, None, None, None);
|
||||||
let cmd_msg =
|
let cmd_msg =
|
||||||
WebDriverCommandMsg::LoadUrl(top_level_browsing_context_id, load_data, sender.clone());
|
WebDriverCommandMsg::LoadUrl(top_level_browsing_context_id, load_data, sender.clone());
|
||||||
self.constellation_chan
|
self.constellation_chan
|
||||||
|
|
|
@ -624872,7 +624872,7 @@
|
||||||
"testharness"
|
"testharness"
|
||||||
],
|
],
|
||||||
"html/semantics/scripting-1/the-script-element/execution-timing/029.html": [
|
"html/semantics/scripting-1/the-script-element/execution-timing/029.html": [
|
||||||
"c74665ec1e5f37d4e9ec0ecc65f626e79d4942d4",
|
"33548e566ac67823f9c19af7785a13e394c4964b",
|
||||||
"testharness"
|
"testharness"
|
||||||
],
|
],
|
||||||
"html/semantics/scripting-1/the-script-element/execution-timing/030.html": [
|
"html/semantics/scripting-1/the-script-element/execution-timing/030.html": [
|
||||||
|
|
|
@ -10,6 +10,9 @@
|
||||||
<div id="log">FAILED (This TC requires JavaScript enabled)</div>
|
<div id="log">FAILED (This TC requires JavaScript enabled)</div>
|
||||||
<p><a href="javascript:log('JS URL')"></a></p>
|
<p><a href="javascript:log('JS URL')"></a></p>
|
||||||
<script>log('inline script #1');
|
<script>log('inline script #1');
|
||||||
|
window.addEventListener("beforeunload", function( event ) {
|
||||||
|
log('beforeunload event');
|
||||||
|
});
|
||||||
if(document.links[0].click){
|
if(document.links[0].click){
|
||||||
document.links[0].click();
|
document.links[0].click();
|
||||||
}else{
|
}else{
|
||||||
|
@ -25,13 +28,26 @@
|
||||||
log( 'inline script #2' );
|
log( 'inline script #2' );
|
||||||
var t = async_test()
|
var t = async_test()
|
||||||
|
|
||||||
function test() {
|
function final_test() {
|
||||||
|
// The JS URL part is required to run in an additional task,
|
||||||
|
// altough that is not fully consistently implemented,
|
||||||
|
// see https://github.com/whatwg/html/issues/3730#issuecomment-492071447
|
||||||
assert_any(assert_array_equals, eventOrder, [
|
assert_any(assert_array_equals, eventOrder, [
|
||||||
['inline script #1', 'end script #1', 'JS URL', 'inline script #2'],
|
['inline script #1', 'end script #1', 'beforeunload event', 'inline script #2', 'JS URL'],
|
||||||
['inline script #1', 'end script #1', 'inline script #2', 'JS URL']]);
|
['inline script #1', 'end script #1', 'inline script #2', 'beforeunload event', 'JS URL']]);
|
||||||
t.done();
|
t.done();
|
||||||
}
|
}
|
||||||
onload = t.step_func(test)
|
|
||||||
|
function test_on_load() {
|
||||||
|
// When the page loads, a task to run the navigate steps
|
||||||
|
// previously enqueued as part of following-hyperlinks,
|
||||||
|
// should have run, and have enqueued another task to execute the JS URL.
|
||||||
|
assert_any(assert_array_equals, eventOrder, [
|
||||||
|
['inline script #1', 'end script #1', 'beforeunload event', 'inline script #2'],
|
||||||
|
['inline script #1', 'end script #1', 'inline script #2', 'beforeunload event']]);
|
||||||
|
t.step_timeout(final_test, 1000)
|
||||||
|
}
|
||||||
|
onload = t.step_func(test_on_load);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
</body></html>
|
</body></html>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue