Make sandboxed iframes run with different script tasks.

This commit is contained in:
Josh Matthews 2013-09-10 15:43:28 -07:00
parent 25a3d4a93f
commit 9640324721
9 changed files with 123 additions and 22 deletions

View file

@ -13,9 +13,9 @@ use geom::size::Size2D;
use geom::rect::Rect; use geom::rect::Rect;
use gfx::opts::Opts; use gfx::opts::Opts;
use pipeline::Pipeline; use pipeline::Pipeline;
use servo_msg::constellation_msg::{ConstellationChan, ExitMsg, FrameRectMsg}; use servo_msg::constellation_msg::{ConstellationChan, ExitMsg, FrameRectMsg, IFrameSandboxState};
use servo_msg::constellation_msg::{InitLoadUrlMsg, LoadIframeUrlMsg, LoadUrlMsg}; use servo_msg::constellation_msg::{InitLoadUrlMsg, LoadIframeUrlMsg, LoadUrlMsg};
use servo_msg::constellation_msg::{Msg, NavigateMsg, NavigationType}; use servo_msg::constellation_msg::{Msg, NavigateMsg, NavigationType, IFrameUnsandboxed};
use servo_msg::constellation_msg::{PipelineId, RendererReadyMsg, ResizedWindowMsg, SubpageId}; use servo_msg::constellation_msg::{PipelineId, RendererReadyMsg, ResizedWindowMsg, SubpageId};
use servo_msg::constellation_msg; use servo_msg::constellation_msg;
use script::script_task::{SendEventMsg, ResizeInactiveMsg, ExecuteMsg}; use script::script_task::{SendEventMsg, ResizeInactiveMsg, ExecuteMsg};
@ -328,8 +328,8 @@ impl Constellation {
FrameRectMsg(pipeline_id, subpage_id, rect) => { FrameRectMsg(pipeline_id, subpage_id, rect) => {
self.handle_frame_rect_msg(pipeline_id, subpage_id, rect); self.handle_frame_rect_msg(pipeline_id, subpage_id, rect);
} }
LoadIframeUrlMsg(url, source_pipeline_id, subpage_id, size_future) => { LoadIframeUrlMsg(url, source_pipeline_id, subpage_id, size_future, sandbox) => {
self.handle_load_iframe_url_msg(url, source_pipeline_id, subpage_id, size_future); self.handle_load_iframe_url_msg(url, source_pipeline_id, subpage_id, size_future, sandbox);
} }
// Load a new page, usually -- but not always -- from a mouse click or typed url // Load a new page, usually -- but not always -- from a mouse click or typed url
// If there is already a pending page (self.pending_frames), it will not be overridden; // If there is already a pending page (self.pending_frames), it will not be overridden;
@ -455,7 +455,8 @@ impl Constellation {
url: Url, url: Url,
source_pipeline_id: PipelineId, source_pipeline_id: PipelineId,
subpage_id: SubpageId, subpage_id: SubpageId,
size_future: Future<Size2D<uint>>) { size_future: Future<Size2D<uint>>,
sandbox: IFrameSandboxState) {
// A message from the script associated with pipeline_id that it has // A message from the script associated with pipeline_id that it has
// parsed an iframe during html parsing. This iframe will result in a // parsed an iframe during html parsing. This iframe will result in a
// new pipeline being spawned and a frame tree being added to pipeline_id's // new pipeline being spawned and a frame tree being added to pipeline_id's
@ -489,9 +490,10 @@ impl Constellation {
source's Url is None. There should never be a LoadUrlIframeMsg from a pipeline source's Url is None. There should never be a LoadUrlIframeMsg from a pipeline
that was never given a url to load."); that was never given a url to load.");
let same_script = (source_url.host == url.host &&
source_url.port == url.port) && sandbox == IFrameUnsandboxed;
// FIXME(tkuehn): Need to follow the standardized spec for checking same-origin // FIXME(tkuehn): Need to follow the standardized spec for checking same-origin
let pipeline = @mut if (source_url.host == url.host && let pipeline = @mut if same_script {
source_url.port == url.port) {
debug!("Constellation: loading same-origin iframe at %?", url); debug!("Constellation: loading same-origin iframe at %?", url);
// Reuse the script task if same-origin url's // Reuse the script task if same-origin url's
Pipeline::with_script(next_pipeline_id, Pipeline::with_script(next_pipeline_id,

View file

@ -27,12 +27,18 @@ impl ConstellationChan {
} }
} }
#[deriving(Eq)]
pub enum IFrameSandboxState {
IFrameSandboxed,
IFrameUnsandboxed
}
pub enum Msg { pub enum Msg {
ExitMsg(Chan<()>), ExitMsg(Chan<()>),
InitLoadUrlMsg(Url), InitLoadUrlMsg(Url),
FrameRectMsg(PipelineId, SubpageId, Rect<f32>), FrameRectMsg(PipelineId, SubpageId, Rect<f32>),
LoadUrlMsg(PipelineId, Url, Future<Size2D<uint>>), LoadUrlMsg(PipelineId, Url, Future<Size2D<uint>>),
LoadIframeUrlMsg(Url, PipelineId, SubpageId, Future<Size2D<uint>>), LoadIframeUrlMsg(Url, PipelineId, SubpageId, Future<Size2D<uint>>, IFrameSandboxState),
NavigateMsg(NavigationDirection), NavigateMsg(NavigationDirection),
RendererReadyMsg(PipelineId), RendererReadyMsg(PipelineId),
ResizedWindowMsg(Size2D<uint>), ResizedWindowMsg(Size2D<uint>),

View file

@ -139,9 +139,9 @@ impl<'self> Element {
return None; return None;
} }
pub fn set_attr(&mut self, name: &DOMString, value: &DOMString) { pub fn set_attr(&mut self, raw_name: &DOMString, raw_value: &DOMString) {
let name = name.to_str(); let name = raw_name.to_str();
let value_cell = Cell::new(value.to_str()); let value_cell = Cell::new(raw_value.to_str());
let mut found = false; let mut found = false;
for attr in self.attrs.mut_iter() { for attr in self.attrs.mut_iter() {
if eq_slice(attr.name, name) { if eq_slice(attr.name, name) {
@ -158,7 +158,15 @@ impl<'self> Element {
self.style_attribute = Some( self.style_attribute = Some(
Stylesheet::from_attribute( Stylesheet::from_attribute(
FromStr::from_str("http://www.example.com/").unwrap(), FromStr::from_str("http://www.example.com/").unwrap(),
value.get_ref())); raw_value.get_ref()));
}
//XXXjdm We really need something like a vtable so we can call AfterSetAttr.
// This hardcoding is awful.
if self.parent.abstract.unwrap().is_iframe_element() {
do self.parent.abstract.unwrap().with_mut_iframe_element |iframe| {
iframe.AfterSetAttr(raw_name, raw_value);
}
} }
match self.parent.owner_doc { match self.parent.owner_doc {

View file

@ -2,7 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use dom::bindings::utils::{DOMString, null_string, ErrorResult}; use dom::bindings::utils::{DOMString, null_string, ErrorResult, str};
use dom::document::AbstractDocument; use dom::document::AbstractDocument;
use dom::htmlelement::HTMLElement; use dom::htmlelement::HTMLElement;
use dom::windowproxy::WindowProxy; use dom::windowproxy::WindowProxy;
@ -11,14 +11,26 @@ use geom::rect::Rect;
use servo_msg::constellation_msg::{ConstellationChan, FrameRectMsg, PipelineId, SubpageId}; use servo_msg::constellation_msg::{ConstellationChan, FrameRectMsg, PipelineId, SubpageId};
use std::ascii::StrAsciiExt;
use std::comm::ChanOne; use std::comm::ChanOne;
use extra::url::Url; use extra::url::Url;
use std::util::replace; use std::util::replace;
enum SandboxAllowance {
AllowNothing = 0x00,
AllowSameOrigin = 0x01,
AllowTopNavigation = 0x02,
AllowForms = 0x04,
AllowScripts = 0x08,
AllowPointerLock = 0x10,
AllowPopups = 0x20
}
pub struct HTMLIFrameElement { pub struct HTMLIFrameElement {
parent: HTMLElement, parent: HTMLElement,
frame: Option<Url>, frame: Option<Url>,
size: Option<IFrameSize>, size: Option<IFrameSize>,
sandbox: Option<u8>
} }
struct IFrameSize { struct IFrameSize {
@ -39,6 +51,11 @@ impl IFrameSize {
} }
} }
impl HTMLIFrameElement {
pub fn is_sandboxed(&self) -> bool {
self.sandbox.is_some()
}
}
impl HTMLIFrameElement { impl HTMLIFrameElement {
pub fn Src(&self) -> DOMString { pub fn Src(&self) -> DOMString {
@ -63,10 +80,32 @@ impl HTMLIFrameElement {
} }
pub fn Sandbox(&self) -> DOMString { pub fn Sandbox(&self) -> DOMString {
null_string self.parent.parent.GetAttribute(&str(~"sandbox"))
} }
pub fn SetSandbox(&self, _sandbox: &DOMString) { pub fn SetSandbox(&mut self, sandbox: &DOMString) {
let mut rv = Ok(());
self.parent.parent.SetAttribute(&str(~"sandbox"), sandbox, &mut rv);
}
pub fn AfterSetAttr(&mut self, name: &DOMString, value: &DOMString) {
let name = name.to_str();
if "sandbox" == name {
let mut modes = AllowNothing as u8;
let words = value.to_str();
for word in words.split_iter(' ') {
modes |= match word.to_ascii_lower().as_slice() {
"allow-same-origin" => AllowSameOrigin,
"allow-forms" => AllowForms,
"allow-pointer-lock" => AllowPointerLock,
"allow-popups" => AllowPopups,
"allow-scripts" => AllowScripts,
"allow-top-navigation" => AllowTopNavigation,
_ => AllowNothing
} as u8;
}
self.sandbox = Some(modes);
}
} }
pub fn AllowFullscreen(&self) -> bool { pub fn AllowFullscreen(&self) -> bool {

View file

@ -93,7 +93,7 @@ enum JSMessage {
/// Messages generated by the HTML parser upon discovery of additional resources /// Messages generated by the HTML parser upon discovery of additional resources
pub enum HtmlDiscoveryMessage { pub enum HtmlDiscoveryMessage {
HtmlDiscoveredStyle(Stylesheet), HtmlDiscoveredStyle(Stylesheet),
HtmlDiscoveredIFrame((Url, SubpageId, Future<Size2D<uint>>)), HtmlDiscoveredIFrame((Url, SubpageId, Future<Size2D<uint>>, bool)),
HtmlDiscoveredScript(JSResult) HtmlDiscoveredScript(JSResult)
} }
@ -272,7 +272,7 @@ pub fn build_element_from_tag(cx: *JSContext, tag: &str) -> AbstractNode<ScriptV
handle_element!(cx, tag, "ul", HTMLUListElementTypeId, HTMLUListElement, []); handle_element!(cx, tag, "ul", HTMLUListElementTypeId, HTMLUListElement, []);
handle_element!(cx, tag, "img", HTMLImageElementTypeId, HTMLImageElement, [(image: None)]); handle_element!(cx, tag, "img", HTMLImageElementTypeId, HTMLImageElement, [(image: None)]);
handle_element!(cx, tag, "iframe", HTMLIframeElementTypeId, HTMLIFrameElement, [(frame: None), (size: None)]); handle_element!(cx, tag, "iframe", HTMLIframeElementTypeId, HTMLIFrameElement, [(frame: None), (size: None), (sandbox: None)]);
handle_element!(cx, tag, "h1", HTMLHeadingElementTypeId, HTMLHeadingElement, [(level: Heading1)]); handle_element!(cx, tag, "h1", HTMLHeadingElementTypeId, HTMLHeadingElement, [(level: Heading1)]);
handle_element!(cx, tag, "h2", HTMLHeadingElementTypeId, HTMLHeadingElement, [(level: Heading2)]); handle_element!(cx, tag, "h2", HTMLHeadingElementTypeId, HTMLHeadingElement, [(level: Heading2)]);
@ -401,6 +401,7 @@ pub fn parse_html(cx: *JSContext,
let iframe_chan = Cell::new(discovery_chan.clone()); let iframe_chan = Cell::new(discovery_chan.clone());
do node.with_mut_iframe_element |iframe_element| { do node.with_mut_iframe_element |iframe_element| {
let iframe_chan = iframe_chan.take(); let iframe_chan = iframe_chan.take();
let sandboxed = iframe_element.is_sandboxed();
let elem = &mut iframe_element.parent.parent; let elem = &mut iframe_element.parent.parent;
let src_opt = elem.get_attr("src").map(|x| x.to_str()); let src_opt = elem.get_attr("src").map(|x| x.to_str());
for src in src_opt.iter() { for src in src_opt.iter() {
@ -427,7 +428,8 @@ pub fn parse_html(cx: *JSContext,
future_chan: Some(chan), future_chan: Some(chan),
constellation_chan: constellation_chan.clone(), constellation_chan: constellation_chan.clone(),
}); });
iframe_chan.send(HtmlDiscoveredIFrame((iframe_url, subpage_id, size_future))); iframe_chan.send(HtmlDiscoveredIFrame((iframe_url, subpage_id,
size_future, sandboxed)));
} }
} }
} }

View file

@ -22,7 +22,7 @@ use layout_interface::ReflowMsg;
use layout_interface; use layout_interface;
use servo_msg::constellation_msg::{ConstellationChan, LoadUrlMsg, NavigationDirection}; use servo_msg::constellation_msg::{ConstellationChan, LoadUrlMsg, NavigationDirection};
use servo_msg::constellation_msg::{PipelineId, SubpageId, RendererReadyMsg}; use servo_msg::constellation_msg::{PipelineId, SubpageId, RendererReadyMsg};
use servo_msg::constellation_msg::{LoadIframeUrlMsg}; use servo_msg::constellation_msg::{LoadIframeUrlMsg, IFrameSandboxed, IFrameUnsandboxed};
use servo_msg::constellation_msg; use servo_msg::constellation_msg;
use std::cell::Cell; use std::cell::Cell;
@ -641,12 +641,18 @@ impl ScriptTask {
Some(HtmlDiscoveredStyle(sheet)) => { Some(HtmlDiscoveredStyle(sheet)) => {
page.layout_chan.send(AddStylesheetMsg(sheet)); page.layout_chan.send(AddStylesheetMsg(sheet));
} }
Some(HtmlDiscoveredIFrame((iframe_url, subpage_id, size_future))) => { Some(HtmlDiscoveredIFrame((iframe_url, subpage_id, size_future, sandboxed))) => {
page.next_subpage_id = SubpageId(*subpage_id + 1); page.next_subpage_id = SubpageId(*subpage_id + 1);
let sandboxed = if sandboxed {
IFrameSandboxed
} else {
IFrameUnsandboxed
};
self.constellation_chan.send(LoadIframeUrlMsg(iframe_url, self.constellation_chan.send(LoadIframeUrlMsg(iframe_url,
pipeline_id, pipeline_id,
subpage_id, subpage_id,
size_future)); size_future,
sandboxed));
} }
None => break None => break
} }

@ -1 +1 @@
Subproject commit 353ef00db32e526f054f1f7899cd93425cfb1c59 Subproject commit a9bc3b5cf968e279cfb082e58207c60e4f4a1a9b

View file

@ -0,0 +1,14 @@
<html>
<body>
<iframe sandbox="allow-scripts" src="test_sandboxed_iframe.html"
style="display:block; border: 1px; width: 400px; height: 400px"
frameborder="yes"
scrolling="yes"></iframe>
hiiiiiiiii
<iframe sandbox="allow-scripts" src="test_sandboxed_iframe.html"
style="display:block; border: 1px; width: 400px; height: 400px"
frameborder="yes"
scrolling="yes"></iframe>
byeeeeeeeeeeee
</body>
</html>

View file

@ -0,0 +1,24 @@
<html>
<body>
<script>
var a = 1;
var b = 1;
var c = 2;
var step = 1;
window.alert(Date.now());
var next = new Date();
window.alert(next);
while (true) {
if ((new Date()) >= next) {
window.alert("step " + step + ": " + c);
a = b;
b = c;
c = a + b;
step++;
next = new Date(Date.now() + 500);
}
}
</script>
hi there
</body>
</html>