diff --git a/components/constellation/constellation.rs b/components/constellation/constellation.rs index 5bef18b062b..62f19f3c28c 100644 --- a/components/constellation/constellation.rs +++ b/components/constellation/constellation.rs @@ -108,7 +108,10 @@ pub struct Constellation { compositor_proxy: Box, /// Channels through which messages can be sent to the resource-related threads. - resource_threads: ResourceThreads, + public_resource_threads: ResourceThreads, + + /// Channels through which messages can be sent to the resource-related threads. + private_resource_threads: ResourceThreads, /// A channel through which messages can be sent to the image cache thread. image_cache_thread: ImageCacheThread, @@ -201,7 +204,9 @@ pub struct InitialConstellationState { /// A channel to the font cache thread. pub font_cache_thread: FontCacheThread, /// A channel to the resource thread. - pub resource_threads: ResourceThreads, + pub public_resource_threads: ResourceThreads, + /// A channel to the resource thread. + pub private_resource_threads: ResourceThreads, /// A channel to the time profiler thread. pub time_profiler_chan: time::ProfilerChan, /// A channel to the memory profiler thread. @@ -331,7 +336,8 @@ impl Constellation compositor_proxy: state.compositor_proxy, devtools_chan: state.devtools_chan, bluetooth_thread: state.bluetooth_thread, - resource_threads: state.resource_threads, + public_resource_threads: state.public_resource_threads, + private_resource_threads: state.private_resource_threads, image_cache_thread: state.image_cache_thread, font_cache_thread: state.font_cache_thread, pipelines: HashMap::new(), @@ -404,9 +410,16 @@ impl Constellation parent_info: Option<(PipelineId, SubpageId, FrameType)>, initial_window_size: Option>, script_channel: Option>, - load_data: LoadData) { + load_data: LoadData, + is_private: bool) { if self.shutting_down { return; } + let resource_threads = if is_private { + self.private_resource_threads.clone() + } else { + self.public_resource_threads.clone() + }; + let parent_visibility = if let Some((parent_pipeline_id, _, _)) = parent_info { self.pipelines.get(&parent_pipeline_id).map(|pipeline| pipeline.visible) } else { @@ -425,7 +438,7 @@ impl Constellation bluetooth_thread: self.bluetooth_thread.clone(), image_cache_thread: self.image_cache_thread.clone(), font_cache_thread: self.font_cache_thread.clone(), - resource_threads: self.resource_threads.clone(), + resource_threads: resource_threads, time_profiler_chan: self.time_profiler_chan.clone(), mem_profiler_chan: self.mem_profiler_chan.clone(), window_size: initial_window_size, @@ -435,6 +448,7 @@ impl Constellation pipeline_namespace_id: self.next_pipeline_namespace_id(), parent_visibility: parent_visibility, webrender_api_sender: self.webrender_api_sender.clone(), + is_private: is_private, }); let (pipeline, child_process) = match result { @@ -850,7 +864,7 @@ impl Constellation self.image_cache_thread.exit(); debug!("Exiting core resource threads."); - if let Err(e) = self.resource_threads.send(net_traits::CoreResourceMsg::Exit(core_sender)) { + if let Err(e) = self.public_resource_threads.send(net_traits::CoreResourceMsg::Exit(core_sender)) { warn!("Exit resource thread failed ({})", e); } @@ -863,12 +877,12 @@ impl Constellation } debug!("Exiting storage resource threads."); - if let Err(e) = self.resource_threads.send(StorageThreadMsg::Exit(storage_sender)) { + if let Err(e) = self.public_resource_threads.send(StorageThreadMsg::Exit(storage_sender)) { warn!("Exit storage thread failed ({})", e); } debug!("Exiting file manager resource threads."); - if let Err(e) = self.resource_threads.send(FileManagerThreadMsg::Exit) { + if let Err(e) = self.public_resource_threads.send(FileManagerThreadMsg::Exit) { warn!("Exit storage thread failed ({})", e); } @@ -951,7 +965,7 @@ impl Constellation let new_pipeline_id = PipelineId::new(); let load_data = LoadData::new(failure_url, None, None); - self.new_pipeline(new_pipeline_id, parent_info, window_size, None, load_data); + self.new_pipeline(new_pipeline_id, parent_info, window_size, None, load_data, false); self.push_pending_frame(new_pipeline_id, Some(pipeline_id)); @@ -965,7 +979,7 @@ impl Constellation let root_pipeline_id = PipelineId::new(); debug_assert!(PipelineId::fake_root_pipeline_id() == root_pipeline_id); self.new_pipeline(root_pipeline_id, None, Some(window_size), None, - LoadData::new(url.clone(), None, None)); + LoadData::new(url.clone(), None, None), false); self.handle_load_start_msg(&root_pipeline_id); self.push_pending_frame(root_pipeline_id, None); self.compositor_proxy.send(ToCompositorMsg::ChangePageUrl(root_pipeline_id, url)); @@ -1030,7 +1044,7 @@ impl Constellation .and_then(|old_subpage_id| self.subpage_map.get(&(load_info.containing_pipeline_id, old_subpage_id))) .cloned(); - let (load_data, script_chan, window_size) = { + let (load_data, script_chan, window_size, is_private) = { let old_pipeline = old_pipeline_id .and_then(|old_pipeline_id| self.pipelines.get(&old_pipeline_id)); @@ -1054,11 +1068,14 @@ impl Constellation // then reuse the script thread in creating the new pipeline let source_url = &source_pipeline.url; + let is_private = load_info.is_private || source_pipeline.is_private; + // FIXME(#10968): this should probably match the origin check in // HTMLIFrameElement::contentDocument. let same_script = source_url.host() == load_data.url.host() && source_url.port() == load_data.url.port() && - load_info.sandbox == IFrameSandboxState::IFrameUnsandboxed; + load_info.sandbox == IFrameSandboxState::IFrameUnsandboxed && + source_pipeline.is_private == is_private; // Reuse the script thread if the URL is same-origin let script_chan = if same_script { @@ -1077,16 +1094,17 @@ impl Constellation old_pipeline.freeze(); } - (load_data, script_chan, window_size) - + (load_data, script_chan, window_size, is_private) }; + // Create the new pipeline, attached to the parent and push to pending frames self.new_pipeline(load_info.new_pipeline_id, Some((load_info.containing_pipeline_id, load_info.new_subpage_id, load_info.frame_type)), window_size, script_chan, - load_data); + load_data, + is_private); self.subpage_map.insert((load_info.containing_pipeline_id, load_info.new_subpage_id), load_info.new_pipeline_id); @@ -1217,7 +1235,7 @@ impl Constellation // Create the new pipeline let window_size = self.pipelines.get(&source_id).and_then(|source| source.size); let new_pipeline_id = PipelineId::new(); - self.new_pipeline(new_pipeline_id, None, window_size, None, load_data); + self.new_pipeline(new_pipeline_id, None, window_size, None, load_data, false); self.push_pending_frame(new_pipeline_id, Some(source_id)); // Send message to ScriptThread that will suspend all timers @@ -1906,25 +1924,6 @@ impl Constellation ReadyToSave::Ready } - /// Checks whether the pipeline or its ancestors are private - #[allow(dead_code)] - fn check_is_pipeline_private(&self, mut pipeline_id: PipelineId) -> bool { - loop { - match self.pipelines.get(&pipeline_id) { - Some(pipeline) if pipeline.is_private => return true, - Some(pipeline) => match pipeline.parent_info { - None => return false, - Some((_, _, FrameType::MozBrowserIFrame)) => return false, - Some((parent_id, _, _)) => pipeline_id = parent_id, - }, - None => { - warn!("Finding private ancestor for pipeline {} after closure.", pipeline_id); - return false; - }, - } - } - } - // Close a frame (and all children) fn close_frame(&mut self, frame_id: FrameId, exit_mode: ExitPipelineMode) { // Store information about the pipelines to be closed. Then close the diff --git a/components/constellation/pipeline.rs b/components/constellation/pipeline.rs index 8a48108ca81..23509e51d20 100644 --- a/components/constellation/pipeline.rs +++ b/components/constellation/pipeline.rs @@ -64,6 +64,7 @@ pub struct Pipeline { /// animations cause composites to be continually scheduled. pub running_animations: bool, pub children: Vec, + /// Whether this pipeline is considered distinct from public pipelines. pub is_private: bool, /// Whether this pipeline should be treated as visible for the purposes of scheduling and /// resource management. @@ -119,6 +120,8 @@ pub struct InitialPipelineState { pub parent_visibility: Option, /// Optional webrender api (if enabled). pub webrender_api_sender: Option, + /// Whether this pipeline is considered private. + pub is_private: bool, } impl Pipeline { @@ -254,6 +257,7 @@ impl Pipeline { pipeline_chan, state.compositor_proxy, chrome_to_paint_chan, + state.is_private, state.load_data.url, state.window_size, state.parent_visibility.unwrap_or(true)); @@ -269,6 +273,7 @@ impl Pipeline { layout_chan: IpcSender, compositor_proxy: Box, chrome_to_paint_chan: Sender, + is_private: bool, url: Url, size: Option>, visible: bool) @@ -285,8 +290,8 @@ impl Pipeline { children: vec!(), size: size, running_animations: false, - is_private: false, visible: visible, + is_private: is_private, } } diff --git a/components/net/resource_thread.rs b/components/net/resource_thread.rs index dfcbf1eedd3..45dd9e35bc2 100644 --- a/components/net/resource_thread.rs +++ b/components/net/resource_thread.rs @@ -19,11 +19,13 @@ use http_loader::{self, HttpState}; use hyper::client::pool::Pool; use hyper::header::{ContentType, Header, SetCookie}; use hyper::mime::{Mime, SubLevel, TopLevel}; -use ipc_channel::ipc::{self, IpcReceiver, IpcSender}; +use ipc_channel::ipc::{self, IpcReceiver, IpcSender, IpcReceiverSet}; use mime_classifier::{ApacheBugFlag, MIMEClassifier, NoSniffFlag}; use net_traits::LoadContext; use net_traits::ProgressMsg::Done; +use net_traits::filemanager_thread::FileManagerThreadMsg; use net_traits::request::{Request, RequestInit}; +use net_traits::storage_thread::StorageThreadMsg; use net_traits::{AsyncResponseTarget, Metadata, ProgressMsg, ResponseAction, CoreResourceThread}; use net_traits::{CoreResourceMsg, CookieSource, FetchResponseMsg, FetchTaskTarget, LoadConsumer}; use net_traits::{LoadData, LoadResponse, NetworkError, ResourceId}; @@ -56,6 +58,14 @@ pub enum ProgressSender { Listener(AsyncResponseTarget), } +#[derive(Clone)] +pub struct ResourceGroup { + cookie_jar: Arc>, + auth_cache: Arc>, + hsts_list: Arc>, + connector: Arc>, +} + impl ProgressSender { //XXXjdm return actual error pub fn send(&self, msg: ProgressMsg) -> Result<(), ()> { @@ -158,89 +168,149 @@ fn start_sending_opt(start_chan: LoadConsumer, metadata: Metadata, } } +/// Returns a tuple of (public, private) senders to the new threads. pub fn new_resource_threads(user_agent: String, devtools_chan: Option>, - profiler_chan: ProfilerChan) -> ResourceThreads { - ResourceThreads::new(new_core_resource_thread(user_agent, devtools_chan, profiler_chan), - StorageThreadFactory::new(), - FileManagerThreadFactory::new(TFD_PROVIDER)) + profiler_chan: ProfilerChan) -> (ResourceThreads, ResourceThreads) { + let (public_core, private_core) = new_core_resource_thread(user_agent, devtools_chan, profiler_chan); + let storage: IpcSender = StorageThreadFactory::new(); + let filemanager: IpcSender = FileManagerThreadFactory::new(TFD_PROVIDER); + (ResourceThreads::new(public_core, storage.clone(), filemanager.clone()), + ResourceThreads::new(private_core, storage, filemanager)) } /// Create a CoreResourceThread pub fn new_core_resource_thread(user_agent: String, devtools_chan: Option>, - profiler_chan: ProfilerChan) -> CoreResourceThread { - let hsts_preload = HstsList::from_servo_preload(); - let (setup_chan, setup_port) = ipc::channel().unwrap(); - let setup_chan_clone = setup_chan.clone(); + profiler_chan: ProfilerChan) + -> (CoreResourceThread, CoreResourceThread) { + let (public_setup_chan, public_setup_port) = ipc::channel().unwrap(); + let (private_setup_chan, private_setup_port) = ipc::channel().unwrap(); + let public_setup_chan_clone = public_setup_chan.clone(); + let private_setup_chan_clone = private_setup_chan.clone(); spawn_named("ResourceManager".to_owned(), move || { let resource_manager = CoreResourceManager::new( - user_agent, hsts_preload, devtools_chan, profiler_chan + user_agent, devtools_chan, profiler_chan ); let mut channel_manager = ResourceChannelManager { - from_client: setup_port, - resource_manager: resource_manager + resource_manager: resource_manager, }; - channel_manager.start(setup_chan_clone); + channel_manager.start(public_setup_chan_clone, + private_setup_chan_clone, + public_setup_port, + private_setup_port); }); - setup_chan + (public_setup_chan, private_setup_chan) } struct ResourceChannelManager { - from_client: IpcReceiver, - resource_manager: CoreResourceManager + resource_manager: CoreResourceManager, +} + +fn create_resource_groups() -> (ResourceGroup, ResourceGroup) { + let mut hsts_list = HstsList::from_servo_preload(); + let mut auth_cache = AuthCache::new(); + let mut cookie_jar = CookieStorage::new(); + if let Some(ref config_dir) = opts::get().config_dir { + read_json_from_file(&mut auth_cache, config_dir, "auth_cache.json"); + read_json_from_file(&mut hsts_list, config_dir, "hsts_list.json"); + read_json_from_file(&mut cookie_jar, config_dir, "cookie_jar.json"); + } + let resource_group = ResourceGroup { + cookie_jar: Arc::new(RwLock::new(cookie_jar)), + auth_cache: Arc::new(RwLock::new(auth_cache)), + hsts_list: Arc::new(RwLock::new(hsts_list.clone())), + connector: create_http_connector(), + }; + let private_resource_group = ResourceGroup { + cookie_jar: Arc::new(RwLock::new(CookieStorage::new())), + auth_cache: Arc::new(RwLock::new(AuthCache::new())), + hsts_list: Arc::new(RwLock::new(HstsList::new())), + connector: create_http_connector(), + }; + (resource_group, private_resource_group) } impl ResourceChannelManager { - fn start(&mut self, control_sender: CoreResourceThread) { - loop { - match self.from_client.recv().unwrap() { - CoreResourceMsg::Load(load_data, consumer, id_sender) => - self.resource_manager.load(load_data, consumer, id_sender, control_sender.clone()), - CoreResourceMsg::Fetch(init, sender) => - self.resource_manager.fetch(init, sender), - CoreResourceMsg::WebsocketConnect(connect, connect_data) => - self.resource_manager.websocket_connect(connect, connect_data), - CoreResourceMsg::SetCookiesForUrl(request, cookie_list, source) => - self.resource_manager.set_cookies_for_url(request, cookie_list, source), - CoreResourceMsg::GetCookiesForUrl(url, consumer, source) => { - let cookie_jar = &self.resource_manager.cookie_jar; - let mut cookie_jar = cookie_jar.write().unwrap(); - consumer.send(cookie_jar.cookies_for_url(&url, source)).unwrap(); - } - CoreResourceMsg::Cancel(res_id) => { - if let Some(cancel_sender) = self.resource_manager.cancel_load_map.get(&res_id) { - let _ = cancel_sender.send(()); - } - self.resource_manager.cancel_load_map.remove(&res_id); - } - CoreResourceMsg::Synchronize(sender) => { - let _ = sender.send(()); - } - CoreResourceMsg::Exit(sender) => { - if let Some(ref config_dir) = opts::get().config_dir { - match self.resource_manager.auth_cache.read() { - Ok(auth_cache) => write_json_to_file(&*auth_cache, config_dir, "auth_cache.json"), - Err(_) => warn!("Error writing auth cache to disk"), - } - match self.resource_manager.cookie_jar.read() { - Ok(jar) => write_json_to_file(&*jar, config_dir, "cookie_jar.json"), - Err(_) => warn!("Error writing cookie jar to disk"), - } - match self.resource_manager.hsts_list.read() { - Ok(hsts) => write_json_to_file(&*hsts, config_dir, "hsts_list.json"), - Err(_) => warn!("Error writing hsts list to disk"), - } - } - let _ = sender.send(()); - break; - } + #[allow(unsafe_code)] + fn start(&mut self, + public_control_sender: CoreResourceThread, + private_control_sender: CoreResourceThread, + public_receiver: IpcReceiver, + private_receiver: IpcReceiver) { + let (public_resource_group, private_resource_group) = create_resource_groups(); + let mut rx_set = IpcReceiverSet::new().unwrap(); + let private_id = rx_set.add(private_receiver).unwrap(); + let public_id = rx_set.add(public_receiver).unwrap(); + + loop { + for (id, data) in rx_set.select().unwrap().into_iter().map(|m| m.unwrap()) { + let (group, sender) = if id == private_id { + (&private_resource_group, &private_control_sender) + } else { + assert_eq!(id, public_id); + (&public_resource_group, &public_control_sender) + }; + if let Ok(msg) = data.to() { + if !self.process_msg(msg, group, &sender) { + break; + } + } } } } + + /// Returns false if the thread should exit. + fn process_msg(&mut self, + msg: CoreResourceMsg, + group: &ResourceGroup, + control_sender: &CoreResourceThread) -> bool { + match msg { + CoreResourceMsg::Load(load_data, consumer, id_sender) => + self.resource_manager.load(load_data, consumer, id_sender, control_sender.clone(), group), + CoreResourceMsg::Fetch(init, sender) => + self.resource_manager.fetch(init, sender, group), + CoreResourceMsg::WebsocketConnect(connect, connect_data) => + self.resource_manager.websocket_connect(connect, connect_data, group), + CoreResourceMsg::SetCookiesForUrl(request, cookie_list, source) => + self.resource_manager.set_cookies_for_url(request, cookie_list, source, group), + CoreResourceMsg::GetCookiesForUrl(url, consumer, source) => { + let mut cookie_jar = group.cookie_jar.write().unwrap(); + consumer.send(cookie_jar.cookies_for_url(&url, source)).unwrap(); + } + CoreResourceMsg::Cancel(res_id) => { + if let Some(cancel_sender) = self.resource_manager.cancel_load_map.get(&res_id) { + let _ = cancel_sender.send(()); + } + self.resource_manager.cancel_load_map.remove(&res_id); + } + CoreResourceMsg::Synchronize(sender) => { + let _ = sender.send(()); + } + CoreResourceMsg::Exit(sender) => { + if let Some(ref config_dir) = opts::get().config_dir { + match group.auth_cache.read() { + Ok(auth_cache) => write_json_to_file(&*auth_cache, config_dir, "auth_cache.json"), + Err(_) => warn!("Error writing auth cache to disk"), + } + match group.cookie_jar.read() { + Ok(jar) => write_json_to_file(&*jar, config_dir, "cookie_jar.json"), + Err(_) => warn!("Error writing cookie jar to disk"), + } + match group.hsts_list.read() { + Ok(hsts) => write_json_to_file(&*hsts, config_dir, "hsts_list.json"), + Err(_) => warn!("Error writing hsts list to disk"), + } + } + let _ = sender.send(()); + return false; + } + } + true + } } pub fn read_json_from_file(data: &mut T, config_dir: &str, filename: &str) { @@ -381,50 +451,37 @@ pub struct AuthCache { pub struct CoreResourceManager { user_agent: String, - cookie_jar: Arc>, - auth_cache: Arc>, mime_classifier: Arc, devtools_chan: Option>, profiler_chan: ProfilerChan, - hsts_list: Arc>, - connector: Arc>, cancel_load_map: HashMap>, next_resource_id: ResourceId, } impl CoreResourceManager { pub fn new(user_agent: String, - mut hsts_list: HstsList, devtools_channel: Option>, profiler_chan: ProfilerChan) -> CoreResourceManager { - let mut auth_cache = AuthCache::new(); - let mut cookie_jar = CookieStorage::new(); - if let Some(ref config_dir) = opts::get().config_dir { - read_json_from_file(&mut auth_cache, config_dir, "auth_cache.json"); - read_json_from_file(&mut hsts_list, config_dir, "hsts_list.json"); - read_json_from_file(&mut cookie_jar, config_dir, "cookie_jar.json"); - } CoreResourceManager { user_agent: user_agent, - cookie_jar: Arc::new(RwLock::new(cookie_jar)), - auth_cache: Arc::new(RwLock::new(auth_cache)), mime_classifier: Arc::new(MIMEClassifier::new()), devtools_chan: devtools_channel, profiler_chan: profiler_chan, - hsts_list: Arc::new(RwLock::new(hsts_list)), - connector: create_http_connector(), cancel_load_map: HashMap::new(), next_resource_id: ResourceId(0), } } - fn set_cookies_for_url(&mut self, request: Url, cookie_list: String, source: CookieSource) { + fn set_cookies_for_url(&mut self, + request: Url, + cookie_list: String, + source: CookieSource, + resource_group: &ResourceGroup) { let header = Header::parse_header(&[cookie_list.into_bytes()]); if let Ok(SetCookie(cookies)) = header { for bare_cookie in cookies { if let Some(cookie) = cookie::Cookie::new_wrapped(bare_cookie, &request, source) { - let cookie_jar = &self.cookie_jar; - let mut cookie_jar = cookie_jar.write().unwrap(); + let mut cookie_jar = resource_group.cookie_jar.write().unwrap(); cookie_jar.push(cookie, source); } } @@ -435,7 +492,8 @@ impl CoreResourceManager { load_data: LoadData, consumer: LoadConsumer, id_sender: Option>, - resource_thread: CoreResourceThread) { + resource_thread: CoreResourceThread, + resource_grp: &ResourceGroup) { fn from_factory(factory: fn(LoadData, LoadConsumer, Arc, CancellationListener)) -> Box from_factory(file_loader::factory), "http" | "https" | "view-source" => { let http_state = HttpState { - hsts_list: self.hsts_list.clone(), - cookie_jar: self.cookie_jar.clone(), - auth_cache: self.auth_cache.clone(), blocked_content: BLOCKED_CONTENT_RULES.clone(), + hsts_list: resource_grp.hsts_list.clone(), + cookie_jar: resource_grp.cookie_jar.clone(), + auth_cache: resource_grp.auth_cache.clone() }; http_loader::factory(self.user_agent.clone(), http_state, self.devtools_chan.clone(), self.profiler_chan.clone(), - self.connector.clone()) + resource_grp.connector.clone()) }, "data" => from_factory(data_loader::factory), "about" => from_factory(about_loader::factory), @@ -488,11 +546,14 @@ impl CoreResourceManager { cancel_listener)); } - fn fetch(&self, init: RequestInit, sender: IpcSender) { + fn fetch(&self, + init: RequestInit, + sender: IpcSender, + group: &ResourceGroup) { let http_state = HttpState { - hsts_list: self.hsts_list.clone(), - cookie_jar: self.cookie_jar.clone(), - auth_cache: self.auth_cache.clone(), + hsts_list: group.hsts_list.clone(), + cookie_jar: group.cookie_jar.clone(), + auth_cache: group.auth_cache.clone(), blocked_content: BLOCKED_CONTENT_RULES.clone(), }; let ua = self.user_agent.clone(); @@ -510,7 +571,8 @@ impl CoreResourceManager { fn websocket_connect(&self, connect: WebSocketCommunicate, - connect_data: WebSocketConnectData) { - websocket_loader::init(connect, connect_data, self.cookie_jar.clone()); + connect_data: WebSocketConnectData, + resource_grp: &ResourceGroup) { + websocket_loader::init(connect, connect_data, resource_grp.cookie_jar.clone()); } } diff --git a/components/net_traits/lib.rs b/components/net_traits/lib.rs index bb8638d7c3c..8323da3d515 100644 --- a/components/net_traits/lib.rs +++ b/components/net_traits/lib.rs @@ -39,7 +39,6 @@ use msg::constellation_msg::{PipelineId, ReferrerPolicy}; use request::{Request, RequestInit}; use response::{HttpsState, Response}; use std::io::Error as IOError; -use std::sync::mpsc::Sender; use std::thread; use storage_thread::StorageThreadMsg; use url::Url; @@ -649,9 +648,10 @@ pub fn unwrap_websocket_protocol(wsp: Option<&header::WebSocketProtocol>) -> Opt #[derive(Clone, PartialEq, Eq, Copy, Hash, Debug, Deserialize, Serialize, HeapSizeOf)] pub struct ResourceId(pub u32); +#[derive(Deserialize, Serialize)] pub enum ConstellationMsg { /// Queries whether a pipeline or its ancestors are private - IsPrivate(PipelineId, Sender), + IsPrivate(PipelineId, IpcSender), } /// Network errors that have to be exported out of the loaders diff --git a/components/script/dom/htmliframeelement.rs b/components/script/dom/htmliframeelement.rs index 22e67d162d9..d3359a40c89 100644 --- a/components/script/dom/htmliframeelement.rs +++ b/components/script/dom/htmliframeelement.rs @@ -562,6 +562,21 @@ impl HTMLIFrameElementMethods for HTMLIFrameElement { make_getter!(Height, "height"); // https://html.spec.whatwg.org/multipage/#dom-dim-height make_dimension_setter!(SetHeight, "height"); + + // check-tidy: no specs after this line + fn SetMozprivatebrowsing(&self, value: bool) { + let element = self.upcast::(); + element.set_bool_attribute(&Atom::from("mozprivatebrowsing"), value); + } + + fn Mozprivatebrowsing(&self) -> bool { + if window_from_node(self).is_mozbrowser() { + let element = self.upcast::(); + element.has_attribute(&Atom::from("mozprivatebrowsing")) + } else { + false + } + } } impl VirtualMethods for HTMLIFrameElement { diff --git a/components/script/dom/webidls/HTMLIFrameElement.webidl b/components/script/dom/webidls/HTMLIFrameElement.webidl index 5fe4ef7a661..ced089391d2 100644 --- a/components/script/dom/webidls/HTMLIFrameElement.webidl +++ b/components/script/dom/webidls/HTMLIFrameElement.webidl @@ -33,6 +33,9 @@ partial interface HTMLIFrameElement { partial interface HTMLIFrameElement { [Func="::dom::window::Window::global_is_mozbrowser"] attribute boolean mozbrowser; + + [Func="::dom::window::Window::global_is_mozbrowser"] + attribute boolean mozprivatebrowsing; }; HTMLIFrameElement implements BrowserElement; diff --git a/components/script/dom/websocket.rs b/components/script/dom/websocket.rs index dec5c509ece..1409936c6c7 100644 --- a/components/script/dom/websocket.rs +++ b/components/script/dom/websocket.rs @@ -489,8 +489,8 @@ impl Runnable for ConnectionEstablishedTask { for cookie in cookies.iter() { if let Ok(cookie_value) = String::from_utf8(cookie.clone()) { let _ = ws.global().r().core_resource_thread().send(SetCookiesForUrl(ws.url.clone(), - cookie_value, - HTTP)); + cookie_value, + HTTP)); } } } diff --git a/components/servo/lib.rs b/components/servo/lib.rs index 5f98a1894b6..28ccd87719f 100644 --- a/components/servo/lib.rs +++ b/components/servo/lib.rs @@ -209,12 +209,13 @@ fn create_constellation(opts: opts::Opts, webrender_api_sender: Option) -> Sender { let bluetooth_thread: IpcSender = BluetoothThreadFactory::new(); - let resource_threads = new_resource_threads(opts.user_agent.clone(), - devtools_chan.clone(), - time_profiler_chan.clone()); - let image_cache_thread = new_image_cache_thread(resource_threads.sender(), + let (public_resource_threads, private_resource_threads) = + new_resource_threads(opts.user_agent.clone(), + devtools_chan.clone(), + time_profiler_chan.clone()); + let image_cache_thread = new_image_cache_thread(public_resource_threads.sender(), webrender_api_sender.as_ref().map(|wr| wr.create_api())); - let font_cache_thread = FontCacheThread::new(resource_threads.sender(), + let font_cache_thread = FontCacheThread::new(public_resource_threads.sender(), webrender_api_sender.as_ref().map(|wr| wr.create_api())); let initial_state = InitialConstellationState { @@ -223,7 +224,8 @@ fn create_constellation(opts: opts::Opts, bluetooth_thread: bluetooth_thread, image_cache_thread: image_cache_thread, font_cache_thread: font_cache_thread, - resource_threads: resource_threads, + public_resource_threads: public_resource_threads, + private_resource_threads: private_resource_threads, time_profiler_chan: time_profiler_chan, mem_profiler_chan: mem_profiler_chan, supports_clipboard: supports_clipboard, diff --git a/tests/unit/net/resource_thread.rs b/tests/unit/net/resource_thread.rs index 39f329a3b56..15b7ad6f882 100644 --- a/tests/unit/net/resource_thread.rs +++ b/tests/unit/net/resource_thread.rs @@ -40,7 +40,7 @@ impl LoadOrigin for ResourceTest { fn test_exit() { let (tx, _rx) = ipc::channel().unwrap(); let (sender, receiver) = ipc::channel().unwrap(); - let resource_thread = new_core_resource_thread("".to_owned(), None, ProfilerChan(tx)); + let (resource_thread, _) = new_core_resource_thread("".to_owned(), None, ProfilerChan(tx)); resource_thread.send(CoreResourceMsg::Exit(sender)).unwrap(); receiver.recv().unwrap(); } @@ -49,7 +49,7 @@ fn test_exit() { fn test_bad_scheme() { let (tx, _rx) = ipc::channel().unwrap(); let (sender, receiver) = ipc::channel().unwrap(); - let resource_thread = new_core_resource_thread("".to_owned(), None, ProfilerChan(tx)); + let (resource_thread, _) = new_core_resource_thread("".to_owned(), None, ProfilerChan(tx)); let (start_chan, start) = ipc::channel().unwrap(); let url = Url::parse("bogus://whatever").unwrap(); resource_thread.send(CoreResourceMsg::Load(LoadData::new(LoadContext::Browsing, url, &ResourceTest), @@ -228,7 +228,7 @@ fn test_cancelled_listener() { let (tx, _rx) = ipc::channel().unwrap(); let (exit_sender, exit_receiver) = ipc::channel().unwrap(); - let resource_thread = new_core_resource_thread("".to_owned(), None, ProfilerChan(tx)); + let (resource_thread, _) = new_core_resource_thread("".to_owned(), None, ProfilerChan(tx)); let (sender, receiver) = ipc::channel().unwrap(); let (id_sender, id_receiver) = ipc::channel().unwrap(); let (sync_sender, sync_receiver) = ipc::channel().unwrap(); diff --git a/tests/wpt/mozilla/meta/MANIFEST.json b/tests/wpt/mozilla/meta/MANIFEST.json index fb6b4466bab..1c546649e56 100644 --- a/tests/wpt/mozilla/meta/MANIFEST.json +++ b/tests/wpt/mozilla/meta/MANIFEST.json @@ -6616,6 +6616,12 @@ "url": "/_mozilla/mozilla/mozbrowser/mozbrowsertitlechangedeagerly_event.html" } ], + "mozilla/mozbrowser/private_browsing.html": [ + { + "path": "mozilla/mozbrowser/private_browsing.html", + "url": "/_mozilla/mozilla/mozbrowser/private_browsing.html" + } + ], "mozilla/mozbrowser/redirect.html": [ { "path": "mozilla/mozbrowser/redirect.html", diff --git a/tests/wpt/mozilla/tests/mozilla/mozbrowser/iframe_contentDocument_inner.html b/tests/wpt/mozilla/tests/mozilla/mozbrowser/iframe_contentDocument_inner.html new file mode 100644 index 00000000000..8336b0744a8 --- /dev/null +++ b/tests/wpt/mozilla/tests/mozilla/mozbrowser/iframe_contentDocument_inner.html @@ -0,0 +1,3 @@ +
Normal iFrame
+ + diff --git a/tests/wpt/mozilla/tests/mozilla/mozbrowser/iframe_privateContent_grandchild.html b/tests/wpt/mozilla/tests/mozilla/mozbrowser/iframe_privateContent_grandchild.html new file mode 100644 index 00000000000..5af0ff72802 --- /dev/null +++ b/tests/wpt/mozilla/tests/mozilla/mozbrowser/iframe_privateContent_grandchild.html @@ -0,0 +1,4 @@ + + diff --git a/tests/wpt/mozilla/tests/mozilla/mozbrowser/iframe_privateContent_inner.html b/tests/wpt/mozilla/tests/mozilla/mozbrowser/iframe_privateContent_inner.html new file mode 100644 index 00000000000..30d5bc8598a --- /dev/null +++ b/tests/wpt/mozilla/tests/mozilla/mozbrowser/iframe_privateContent_inner.html @@ -0,0 +1,13 @@ + + +
Private iFrame
+ + + + + diff --git a/tests/wpt/mozilla/tests/mozilla/mozbrowser/private_browsing.html b/tests/wpt/mozilla/tests/mozilla/mozbrowser/private_browsing.html new file mode 100644 index 00000000000..7510998625f --- /dev/null +++ b/tests/wpt/mozilla/tests/mozilla/mozbrowser/private_browsing.html @@ -0,0 +1,44 @@ + + + Private browsing + + + + + +