diff options
Diffstat (limited to 'components/script/dom')
23 files changed, 328 insertions, 215 deletions
diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index d88e6d9fa32..c714bddb983 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -2164,13 +2164,10 @@ def CreateBindingJSObject(descriptor, parent=None): create += """ let handler = RegisterBindings::proxy_handlers[PrototypeList::Proxies::%s as usize]; let private = RootedValue::new(cx, PrivateValue(raw as *const libc::c_void)); -let obj = { - let _ac = JSAutoCompartment::new(cx, proto.ptr); - NewProxyObject(cx, handler, - private.handle(), - proto.ptr, %s.get(), - ptr::null_mut(), ptr::null_mut()) -}; +let obj = NewProxyObject(cx, handler, + private.handle(), + proto.ptr, %s.get(), + ptr::null_mut(), ptr::null_mut()); assert!(!obj.is_null()); let obj = RootedObject::new(cx, obj);\ """ % (descriptor.name, parent) @@ -2185,12 +2182,8 @@ let obj = RootedObject::new(cx, obj);\ ");\n" "assert!(!obj.ptr.is_null());" % TRACE_HOOK_NAME) else: - create += ("let obj = {\n" - " let _ac = JSAutoCompartment::new(cx, proto.ptr);\n" - " JS_NewObjectWithGivenProto(\n" - " cx, &Class.base as *const js::jsapi::Class as *const JSClass, proto.handle())\n" - "};\n" - "let obj = RootedObject::new(cx, obj);\n" + create += ("let obj = RootedObject::new(cx, JS_NewObjectWithGivenProto(\n" + " cx, &Class.base as *const js::jsapi::Class as *const JSClass, proto.handle()));\n" "assert!(!obj.ptr.is_null());\n" "\n" "JS_SetReservedSlot(obj.ptr, DOM_OBJECT_SLOT,\n" @@ -2236,11 +2229,7 @@ def CopyUnforgeablePropertiesToInstance(descriptor): # reflector, so we can make sure we don't get confused by named getters. if descriptor.proxy: copyCode += """\ -let mut expando = RootedObject::new(cx, ptr::null_mut()); -{ - let _ac = JSAutoCompartment::new(cx, scope.get()); - expando.handle_mut().set(ensure_expando_object(cx, obj.handle())); -} +let expando = RootedObject::new(cx, ensure_expando_object(cx, obj.handle())); """ obj = "expando" else: @@ -2291,10 +2280,8 @@ assert!(!scope.get().is_null()); assert!(((*JS_GetClass(scope.get())).flags & JSCLASS_IS_GLOBAL) != 0); let mut proto = RootedObject::new(cx, ptr::null_mut()); -{ - let _ac = JSAutoCompartment::new(cx, scope.get()); - GetProtoObject(cx, scope, scope, proto.handle_mut()) -} +let _ac = JSAutoCompartment::new(cx, scope.get()); +GetProtoObject(cx, scope, scope, proto.handle_mut()); assert!(!proto.ptr.is_null()); %(createObject)s diff --git a/components/script/dom/bindings/global.rs b/components/script/dom/bindings/global.rs index 6580b320a97..d3ece2ae98e 100644 --- a/components/script/dom/bindings/global.rs +++ b/components/script/dom/bindings/global.rs @@ -7,7 +7,7 @@ //! This module contains smart pointers to global scopes, to simplify writing //! code that works in workers as well as window scopes. -use devtools_traits::ScriptToDevtoolsControlMsg; +use devtools_traits::{ScriptToDevtoolsControlMsg, WorkerId}; use dom::bindings::codegen::Bindings::WindowBinding::WindowMethods; use dom::bindings::conversions::root_from_object; use dom::bindings::js::{JS, Root}; @@ -18,12 +18,11 @@ use ipc_channel::ipc::IpcSender; use js::jsapi::GetGlobalForObjectCrossCompartment; use js::jsapi::{JSContext, JSObject, JS_GetClass, MutableHandleValue}; use js::{JSCLASS_IS_DOMJSCLASS, JSCLASS_IS_GLOBAL}; -use msg::constellation_msg::ScriptMsg as ConstellationMsg; -use msg::constellation_msg::{ConstellationChan, PipelineId, WorkerId}; +use msg::constellation_msg::{ConstellationChan, PipelineId}; use net_traits::ResourceTask; use profile_traits::mem; use script_task::{CommonScriptMsg, ScriptChan, ScriptPort, ScriptTask}; -use script_traits::{MsDuration, TimerEventRequest}; +use script_traits::{MsDuration, ScriptMsg as ConstellationMsg, TimerEventRequest}; use timers::{ScheduledCallback, TimerHandle}; use url::Url; use util::mem::HeapSizeOf; @@ -155,9 +154,45 @@ impl<'a> GlobalRef<'a> { /// `ScriptChan` used to send messages to the event loop of this global's /// thread. - pub fn script_chan(&self) -> Box<ScriptChan + Send> { + pub fn dom_manipulation_task_source(&self) -> Box<ScriptChan + Send> { match *self { - GlobalRef::Window(ref window) => window.script_chan(), + GlobalRef::Window(ref window) => window.dom_manipulation_task_source(), + GlobalRef::Worker(ref worker) => worker.script_chan(), + } + } + + /// `ScriptChan` used to send messages to the event loop of this global's + /// thread. + pub fn user_interaction_task_source(&self) -> Box<ScriptChan + Send> { + match *self { + GlobalRef::Window(ref window) => window.user_interaction_task_source(), + GlobalRef::Worker(ref worker) => worker.script_chan(), + } + } + + /// `ScriptChan` used to send messages to the event loop of this global's + /// thread. + pub fn networking_task_source(&self) -> Box<ScriptChan + Send> { + match *self { + GlobalRef::Window(ref window) => window.networking_task_source(), + GlobalRef::Worker(ref worker) => worker.script_chan(), + } + } + + /// `ScriptChan` used to send messages to the event loop of this global's + /// thread. + pub fn history_traversal_task_source(&self) -> Box<ScriptChan + Send> { + match *self { + GlobalRef::Window(ref window) => window.history_traversal_task_source(), + GlobalRef::Worker(ref worker) => worker.script_chan(), + } + } + + /// `ScriptChan` used to send messages to the event loop of this global's + /// thread. + pub fn file_reading_task_source(&self) -> Box<ScriptChan + Send> { + match *self { + GlobalRef::Window(ref window) => window.file_reading_task_source(), GlobalRef::Worker(ref worker) => worker.script_chan(), } } diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs index e893f284978..cbe870f073c 100644 --- a/components/script/dom/bindings/trace.rs +++ b/components/script/dom/bindings/trace.rs @@ -33,6 +33,7 @@ use canvas_traits::WebGLError; use canvas_traits::{CanvasGradientStop, LinearGradientStyle, RadialGradientStyle}; use canvas_traits::{CompositionOrBlending, LineCapStyle, LineJoinStyle, RepetitionStyle}; use cssparser::RGBA; +use devtools_traits::WorkerId; use dom::bindings::js::{JS, Root}; use dom::bindings::refcounted::Trusted; use dom::bindings::reflector::{Reflectable, Reflector}; @@ -53,8 +54,8 @@ use js::jsval::JSVal; use js::rust::Runtime; use layout_interface::{LayoutChan, LayoutRPC}; use libc; -use msg::constellation_msg::{ConstellationChan, ScriptMsg}; -use msg::constellation_msg::{PipelineId, SubpageId, WindowSizeData, WorkerId}; +use msg::constellation_msg::ConstellationChan; +use msg::constellation_msg::{PipelineId, SubpageId, WindowSizeData}; use net_traits::Metadata; use net_traits::image::base::Image; use net_traits::image_cache_task::{ImageCacheChan, ImageCacheTask}; @@ -62,7 +63,7 @@ use net_traits::storage_task::StorageType; use profile_traits::mem::ProfilerChan as MemProfilerChan; use profile_traits::time::ProfilerChan as TimeProfilerChan; use script_task::ScriptChan; -use script_traits::{TimerEventId, TimerSource, UntrustedNodeAddress}; +use script_traits::{ScriptMsg, TimerEventId, TimerSource, UntrustedNodeAddress}; use selectors::parser::PseudoElement; use selectors::states::*; use serde::{Deserialize, Serialize}; diff --git a/components/script/dom/bindings/utils.rs b/components/script/dom/bindings/utils.rs index fe7c8030baa..13dbc46b9dc 100644 --- a/components/script/dom/bindings/utils.rs +++ b/components/script/dom/bindings/utils.rs @@ -379,20 +379,6 @@ pub unsafe extern "C" fn throwing_constructor(cx: *mut JSContext, /// An array of *mut JSObject of size PrototypeList::ID::Count pub type ProtoOrIfaceArray = [*mut JSObject; PrototypeList::ID::Count as usize]; -/// Construct and cache the ProtoOrIfaceArray for the given global. -/// Fails if the argument is not a DOM global. -pub fn initialize_global(global: *mut JSObject) { - let proto_array: Box<ProtoOrIfaceArray> = - box [0 as *mut JSObject; PrototypeList::ID::Count as usize]; - unsafe { - assert!(((*JS_GetClass(global)).flags & JSCLASS_DOM_GLOBAL) != 0); - let box_ = Box::into_raw(proto_array); - JS_SetReservedSlot(global, - DOM_PROTOTYPE_SLOT, - PrivateValue(box_ as *const libc::c_void)); - } -} - /// Gets the property `id` on `proxy`'s prototype. If it exists, `*found` is /// set to true and `*vp` to the value, otherwise `*found` is set to false. /// @@ -583,10 +569,18 @@ pub fn create_dom_global(cx: *mut JSContext, if obj.ptr.is_null() { return ptr::null_mut(); } - let _ac = JSAutoCompartment::new(cx, obj.ptr); + + // Initialize the reserved slots before doing amything that can GC, to + // avoid getting trace hooks called on a partially initialized object. JS_SetReservedSlot(obj.ptr, DOM_OBJECT_SLOT, PrivateValue(private)); + let proto_array: Box<ProtoOrIfaceArray> = + box [0 as *mut JSObject; PrototypeList::ID::Count as usize]; + JS_SetReservedSlot(obj.ptr, + DOM_PROTOTYPE_SLOT, + PrivateValue(Box::into_raw(proto_array) as *const libc::c_void)); + + let _ac = JSAutoCompartment::new(cx, obj.ptr); JS_InitStandardClasses(cx, obj.handle()); - initialize_global(obj.ptr); JS_FireOnNewGlobalObject(cx, obj.handle()); obj.ptr } diff --git a/components/script/dom/blob.rs b/components/script/dom/blob.rs index 5e5c13516c4..141516e333f 100644 --- a/components/script/dom/blob.rs +++ b/components/script/dom/blob.rs @@ -140,7 +140,7 @@ impl BlobMethods for Blob { let start = relativeStart.to_usize().unwrap(); let end = (relativeStart + span).to_usize().unwrap(); let mut bytes: Vec<u8> = Vec::new(); - bytes.push_all(&vec[start..end]); + bytes.extend_from_slice(&vec[start..end]); Blob::new(global.r(), Some(bytes), &relativeContentType) } } diff --git a/components/script/dom/canvasrenderingcontext2d.rs b/components/script/dom/canvasrenderingcontext2d.rs index 119f819cf8e..22e1c388f59 100644 --- a/components/script/dom/canvasrenderingcontext2d.rs +++ b/components/script/dom/canvasrenderingcontext2d.rs @@ -35,10 +35,10 @@ use euclid::point::Point2D; use euclid::rect::Rect; use euclid::size::Size2D; use ipc_channel::ipc::{self, IpcSender}; -use msg::constellation_msg::ScriptMsg as ConstellationMsg; use net_traits::image::base::PixelFormat; use net_traits::image_cache_task::ImageResponse; use num::{Float, ToPrimitive}; +use script_traits::ScriptMsg as ConstellationMsg; use std::str::FromStr; use std::sync::mpsc::channel; use std::{cmp, fmt}; diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index 7b375e34129..b816624b10c 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -81,7 +81,6 @@ use layout_interface::{HitTestResponse, MouseOverResponse}; use layout_interface::{LayoutChan, Msg}; use layout_interface::{ReflowGoal, ReflowQueryType}; use msg::compositor_msg::ScriptToCompositorMsg; -use msg::constellation_msg::ScriptMsg as ConstellationMsg; use msg::constellation_msg::{ALT, CONTROL, SHIFT, SUPER}; use msg::constellation_msg::{AnimationState, PipelineId}; use msg::constellation_msg::{ConstellationChan, Key, KeyModifiers, KeyState}; @@ -91,7 +90,7 @@ use net_traits::CookieSource::NonHTTP; use net_traits::{AsyncResponseTarget, PendingAsyncLoad}; use num::ToPrimitive; use script_task::{MainThreadScriptMsg, Runnable}; -use script_traits::{TouchEventType, TouchId, UntrustedNodeAddress}; +use script_traits::{ScriptMsg as ConstellationMsg, TouchEventType, TouchId, UntrustedNodeAddress}; use std::ascii::AsciiExt; use std::borrow::ToOwned; use std::boxed::FnBox; diff --git a/components/script/dom/filereader.rs b/components/script/dom/filereader.rs index 96b14caed9d..02aef5e3f01 100644 --- a/components/script/dom/filereader.rs +++ b/components/script/dom/filereader.rs @@ -360,10 +360,10 @@ impl FileReader { let load_data = ReadMetaData::new(String::from(type_), label.map(String::from), function); - let fr = Trusted::new(global.get_cx(), self, global.script_chan()); + let fr = Trusted::new(global.get_cx(), self, global.file_reading_task_source()); let gen_id = self.generation_id.get(); - let script_chan = global.script_chan(); + let script_chan = global.file_reading_task_source(); spawn_named("file reader async operation".to_owned(), move || { perform_annotated_read_operation(gen_id, load_data, bytes, fr, script_chan) diff --git a/components/script/dom/htmlbodyelement.rs b/components/script/dom/htmlbodyelement.rs index f7605ed5aa3..79c549fd55d 100644 --- a/components/script/dom/htmlbodyelement.rs +++ b/components/script/dom/htmlbodyelement.rs @@ -18,7 +18,7 @@ use dom::htmlelement::HTMLElement; use dom::node::{Node, document_from_node, window_from_node}; use dom::virtualmethods::VirtualMethods; use msg::constellation_msg::ConstellationChan; -use msg::constellation_msg::ScriptMsg as ConstellationMsg; +use script_traits::ScriptMsg as ConstellationMsg; use std::rc::Rc; use string_cache::Atom; use time; diff --git a/components/script/dom/htmliframeelement.rs b/components/script/dom/htmliframeelement.rs index 3798ab4f539..7039340ead2 100644 --- a/components/script/dom/htmliframeelement.rs +++ b/components/script/dom/htmliframeelement.rs @@ -25,10 +25,10 @@ use dom::window::Window; use js::jsapi::{JSAutoCompartment, JSAutoRequest, RootedValue, JSContext, MutableHandleValue}; use js::jsval::{UndefinedValue, NullValue}; use msg::constellation_msg::IFrameSandboxState::{IFrameSandboxed, IFrameUnsandboxed}; -use msg::constellation_msg::ScriptMsg as ConstellationMsg; use msg::constellation_msg::{ConstellationChan, IframeLoadInfo, MozBrowserEvent}; use msg::constellation_msg::{NavigationDirection, PipelineId, SubpageId}; use page::IterablePage; +use script_traits::ScriptMsg as ConstellationMsg; use std::ascii::AsciiExt; use std::cell::Cell; use string_cache::Atom; diff --git a/components/script/dom/htmlimageelement.rs b/components/script/dom/htmlimageelement.rs index 11ebf4360de..50f80b83a5d 100644 --- a/components/script/dom/htmlimageelement.rs +++ b/components/script/dom/htmlimageelement.rs @@ -106,9 +106,9 @@ impl HTMLImageElement { let img_url = img_url.unwrap(); *self.url.borrow_mut() = Some(img_url.clone()); - let trusted_node = Trusted::new(window.get_cx(), self, window.script_chan()); + let trusted_node = Trusted::new(window.get_cx(), self, window.networking_task_source()); let (responder_sender, responder_receiver) = ipc::channel().unwrap(); - let script_chan = window.script_chan(); + let script_chan = window.networking_task_source(); let wrapper = window.get_runnable_wrapper(); ROUTER.add_route(responder_receiver.to_opaque(), box move |message| { // Return the image via a message to the script task, which marks the element diff --git a/components/script/dom/htmlinputelement.rs b/components/script/dom/htmlinputelement.rs index cd640b83287..6c3e9cdfb56 100644 --- a/components/script/dom/htmlinputelement.rs +++ b/components/script/dom/htmlinputelement.rs @@ -28,7 +28,7 @@ use dom::node::{document_from_node, window_from_node}; use dom::nodelist::NodeList; use dom::virtualmethods::VirtualMethods; use msg::constellation_msg::ConstellationChan; -use msg::constellation_msg::ScriptMsg as ConstellationMsg; +use script_traits::ScriptMsg as ConstellationMsg; use selectors::states::*; use std::borrow::ToOwned; use std::cell::Cell; diff --git a/components/script/dom/htmllinkelement.rs b/components/script/dom/htmllinkelement.rs index b8d757920a8..d302430d756 100644 --- a/components/script/dom/htmllinkelement.rs +++ b/components/script/dom/htmllinkelement.rs @@ -24,10 +24,10 @@ use encoding::all::UTF_8; use ipc_channel::ipc; use ipc_channel::router::ROUTER; use layout_interface::{LayoutChan, Msg}; -use msg::constellation_msg::ScriptMsg as ConstellationMsg; use msg::constellation_msg::{ConstellationChan, MozBrowserEvent}; use net_traits::{AsyncResponseListener, AsyncResponseTarget, Metadata}; use network_listener::{NetworkListener, PreInvoke}; +use script_traits::ScriptMsg as ConstellationMsg; use std::ascii::AsciiExt; use std::borrow::ToOwned; use std::cell::Cell; @@ -197,7 +197,7 @@ impl HTMLLinkElement { // TODO: #8085 - Don't load external stylesheets if the node's mq doesn't match. let doc = window.Document(); - let script_chan = window.script_chan(); + let script_chan = window.networking_task_source(); let elem = Trusted::new(window.get_cx(), self, script_chan.clone()); let context = Arc::new(Mutex::new(StylesheetContext { diff --git a/components/script/dom/htmlscriptelement.rs b/components/script/dom/htmlscriptelement.rs index 5bc8b1bbc60..655254debae 100644 --- a/components/script/dom/htmlscriptelement.rs +++ b/components/script/dom/htmlscriptelement.rs @@ -216,7 +216,9 @@ impl HTMLScriptElement { return NextParserState::Continue; } - // Step 12. + // TODO: Step 12. + + // Step 13. let for_attribute = element.get_attribute(&ns!(), &atom!("for")); let event_attribute = element.get_attribute(&ns!(), &atom!("event")); match (for_attribute.r(), event_attribute.r()) { @@ -236,46 +238,45 @@ impl HTMLScriptElement { (_, _) => (), } - // Step 13. + // Step 14. if let Some(ref charset) = element.get_attribute(&ns!(), &atom!("charset")) { if let Some(encodingRef) = encoding_from_whatwg_label(&charset.Value()) { *self.block_character_encoding.borrow_mut() = encodingRef; } } - // Step 14. + // Step 15. let window = window_from_node(self); let window = window.r(); let base_url = window.get_url(); - let deferred = element.has_attribute(&atom!("defer")); let is_external = match element.get_attribute(&ns!(), &atom!("src")) { - // Step 14. + // Step 15. Some(ref src) => { - // Step 14.1 + // Step 15.1 let src = src.value(); - // Step 14.2 + // Step 15.2 if src.is_empty() { self.queue_error_event(); return NextParserState::Continue; } - // Step 14.3 + // Step 15.3 match UrlParser::new().base_url(&base_url).parse(&src) { Err(_) => { - // Step 14.4 + // Step 15.4 error!("error parsing URL for script {}", &**src); self.queue_error_event(); return NextParserState::Continue; } Ok(url) => { - // Step 14.5 + // Step 15.5 // TODO: Do a potentially CORS-enabled fetch with the mode being the current // state of the element's `crossorigin` content attribute, the origin being // the origin of the script element's node document, and the default origin // behaviour set to taint. - let script_chan = window.script_chan(); + let script_chan = window.networking_task_source(); let elem = Trusted::new(window.get_cx(), self, script_chan.clone()); let context = Arc::new(Mutex::new(ScriptContext { @@ -305,8 +306,9 @@ impl HTMLScriptElement { None => false, }; - // Step 15. - // Step 15.a, has src, has defer, was parser-inserted, is not async. + // Step 16. + let deferred = element.has_attribute(&atom!("defer")); + // Step 16.a, has src, has defer, was parser-inserted, is not async. if is_external && deferred && was_parser_inserted && @@ -314,13 +316,13 @@ impl HTMLScriptElement { doc.add_deferred_script(self); // Second part implemented in Document::process_deferred_scripts. return NextParserState::Continue; - // Step 15.b, has src, was parser-inserted, is not async. + // Step 16.b, has src, was parser-inserted, is not async. } else if is_external && was_parser_inserted && !async { doc.set_pending_parsing_blocking_script(Some(self)); // Second part implemented in the load result handler. - // Step 15.c, doesn't have src, was parser-inserted, is blocked on stylesheet. + // Step 16.c, doesn't have src, was parser-inserted, is blocked on stylesheet. } else if !is_external && was_parser_inserted && // TODO: check for script nesting levels. @@ -328,17 +330,17 @@ impl HTMLScriptElement { doc.set_pending_parsing_blocking_script(Some(self)); *self.load.borrow_mut() = Some(ScriptOrigin::Internal(text, base_url)); self.ready_to_be_parser_executed.set(true); - // Step 15.d, has src, isn't async, isn't non-blocking. + // Step 16.d, has src, isn't async, isn't non-blocking. } else if is_external && !async && !self.non_blocking.get() { doc.push_asap_in_order_script(self); // Second part implemented in Document::process_asap_scripts. - // Step 15.e, has src. + // Step 16.e, has src. } else if is_external { doc.add_asap_script(self); // Second part implemented in Document::process_asap_scripts. - // Step 15.f, otherwise. + // Step 16.f, otherwise. } else { assert!(!text.is_empty()); self.ready_to_be_parser_executed.set(true); @@ -453,7 +455,7 @@ impl HTMLScriptElement { if external { self.dispatch_load_event(); } else { - let chan = window.script_chan(); + let chan = window.dom_manipulation_task_source(); let handler = Trusted::new(window.get_cx(), self, chan.clone()); let dispatcher = box EventDispatcher { element: handler, @@ -466,7 +468,7 @@ impl HTMLScriptElement { pub fn queue_error_event(&self) { let window = window_from_node(self); let window = window.r(); - let chan = window.script_chan(); + let chan = window.dom_manipulation_task_source(); let handler = Trusted::new(window.get_cx(), self, chan.clone()); let dispatcher = box EventDispatcher { element: handler, diff --git a/components/script/dom/htmltextareaelement.rs b/components/script/dom/htmltextareaelement.rs index 17155a44983..1c77d98f69d 100644 --- a/components/script/dom/htmltextareaelement.rs +++ b/components/script/dom/htmltextareaelement.rs @@ -25,9 +25,9 @@ use dom::node::{document_from_node, window_from_node}; use dom::nodelist::NodeList; use dom::virtualmethods::VirtualMethods; use msg::constellation_msg::ConstellationChan; -use msg::constellation_msg::ScriptMsg as ConstellationMsg; use script_task::ScriptTaskEventCategory::InputEvent; use script_task::{CommonScriptMsg, Runnable}; +use script_traits::ScriptMsg as ConstellationMsg; use selectors::states::*; use std::cell::Cell; use string_cache::Atom; @@ -343,7 +343,7 @@ impl VirtualMethods for HTMLTextAreaElement { if event.IsTrusted() { let window = window_from_node(self); let window = window.r(); - let chan = window.script_chan(); + let chan = window.user_interaction_task_source(); let handler = Trusted::new(window.get_cx(), self, chan.clone()); let dispatcher = ChangeEventRunnable { element: handler, diff --git a/components/script/dom/storage.rs b/components/script/dom/storage.rs index 2d25bc8532a..ffae459e6f7 100644 --- a/components/script/dom/storage.rs +++ b/components/script/dom/storage.rs @@ -155,7 +155,7 @@ impl Storage { let global_root = self.global.root(); let global_ref = global_root.r(); let main_script_chan = global_ref.as_window().main_thread_script_chan(); - let script_chan = global_ref.script_chan(); + let script_chan = global_ref.dom_manipulation_task_source(); let trusted_storage = Trusted::new(global_ref.get_cx(), self, script_chan.clone()); main_script_chan.send(MainThreadScriptMsg::MainThreadRunnableMsg( diff --git a/components/script/dom/webglrenderingcontext.rs b/components/script/dom/webglrenderingcontext.rs index 37fc47d9d78..e9a8b922a48 100644 --- a/components/script/dom/webglrenderingcontext.rs +++ b/components/script/dom/webglrenderingcontext.rs @@ -31,10 +31,10 @@ use ipc_channel::ipc::{self, IpcSender}; use js::jsapi::{JSContext, JSObject, RootedValue}; use js::jsapi::{JS_GetFloat32ArrayData, JS_GetObjectAsArrayBufferView}; use js::jsval::{BooleanValue, Int32Value, JSVal, NullValue, UndefinedValue}; -use msg::constellation_msg::ScriptMsg as ConstellationMsg; use net_traits::image::base::PixelFormat; use net_traits::image_cache_task::ImageResponse; use offscreen_gl_context::GLContextAttributes; +use script_traits::ScriptMsg as ConstellationMsg; use std::cell::Cell; use std::sync::mpsc::channel; use std::{ptr, slice}; @@ -417,7 +417,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { } let data = match data { Some(data) => data, - None => return, + None => return self.webgl_error(InvalidValue), }; if offset < 0 { return self.webgl_error(InvalidValue); diff --git a/components/script/dom/webidls/XMLHttpRequest.webidl b/components/script/dom/webidls/XMLHttpRequest.webidl index aba1569957b..372627a0eca 100644 --- a/components/script/dom/webidls/XMLHttpRequest.webidl +++ b/components/script/dom/webidls/XMLHttpRequest.webidl @@ -72,5 +72,6 @@ interface XMLHttpRequest : XMLHttpRequestEventTarget { readonly attribute any response; [Throws] readonly attribute DOMString responseText; + [Throws] /*[Exposed=Window]*/ readonly attribute Document? responseXML; }; diff --git a/components/script/dom/websocket.rs b/components/script/dom/websocket.rs index d75662c157e..125ab9065ee 100644 --- a/components/script/dom/websocket.rs +++ b/components/script/dom/websocket.rs @@ -21,32 +21,25 @@ use dom::closeevent::CloseEvent; use dom::event::{Event, EventBubbles, EventCancelable}; use dom::eventtarget::EventTarget; use dom::messageevent::MessageEvent; -use hyper::header::Host; +use ipc_channel::ipc::{self, IpcReceiver, IpcSender}; use js::jsapi::{JSAutoCompartment, JSAutoRequest, RootedValue}; use js::jsapi::{JS_GetArrayBufferData, JS_NewArrayBuffer}; use js::jsval::UndefinedValue; use libc::{uint32_t, uint8_t}; +use net_traits::ControlMsg::WebsocketConnect; +use net_traits::MessageData; use net_traits::hosts::replace_hosts; +use net_traits::{WebSocketCommunicate, WebSocketConnectData, WebSocketDomAction, WebSocketNetworkEvent}; use ref_slice::ref_slice; use script_task::ScriptTaskEventCategory::WebSocketEvent; use script_task::{CommonScriptMsg, Runnable}; use std::borrow::ToOwned; use std::cell::Cell; use std::ptr; -use std::sync::{Arc, Mutex}; +use std::thread; use util::str::DOMString; -use util::task::spawn_named; -use websocket::client::receiver::Receiver; use websocket::client::request::Url; -use websocket::client::sender::Sender; -use websocket::header::Origin; -use websocket::message::Type; -use websocket::result::WebSocketResult; -use websocket::stream::WebSocketStream; -use websocket::ws::receiver::Receiver as WSReceiver; -use websocket::ws::sender::Sender as Sender_Object; use websocket::ws::util::url::parse_url; -use websocket::{Client, Message}; #[derive(JSTraceable, PartialEq, Copy, Clone, Debug, HeapSizeOf)] enum WebSocketRequestState { @@ -56,14 +49,6 @@ enum WebSocketRequestState { Closed = 3, } -no_jsmanaged_fields!(Sender<WebSocketStream>); - -#[derive(HeapSizeOf)] -enum MessageData { - Text(String), - Binary(Vec<u8>), -} - // list of blacklist ports according to // http://mxr.mozilla.org/mozilla-central/source/netwerk/base/nsIOService.cpp#87 const BLOCKED_PORTS_LIST: &'static [u16] = &[ @@ -154,7 +139,7 @@ pub struct WebSocket { buffered_amount: Cell<u32>, clearing_buffer: Cell<bool>, //Flag to tell if there is a running task to clear buffered_amount #[ignore_heap_size_of = "Defined in std"] - sender: DOMRefCell<Option<Arc<Mutex<Sender<WebSocketStream>>>>>, + sender: DOMRefCell<Option<IpcSender<WebSocketDomAction>>>, failed: Cell<bool>, //Flag to tell if websocket was closed due to failure full: Cell<bool>, //Flag to tell if websocket queue is full clean_close: Cell<bool>, //Flag to tell if the websocket closed cleanly (not due to full or fail) @@ -163,29 +148,6 @@ pub struct WebSocket { binary_type: Cell<BinaryType>, } -/// *Establish a WebSocket Connection* as defined in RFC 6455. -fn establish_a_websocket_connection(resource_url: &Url, net_url: (Host, String, bool), - origin: String) - -> WebSocketResult<(Sender<WebSocketStream>, Receiver<WebSocketStream>)> { - // URL that we actually fetch from the network, after applying the replacements - // specified in the hosts file. - - let host = Host { - hostname: resource_url.serialize_host().unwrap(), - port: resource_url.port_or_default() - }; - - let mut request = try!(Client::connect(net_url)); - request.headers.set(Origin(origin)); - request.headers.set(host); - - let response = try!(request.send()); - try!(response.validate()); - - Ok(response.begin().split()) -} - - impl WebSocket { fn new_inherited(global: GlobalRef, url: Url) -> WebSocket { WebSocket { @@ -217,8 +179,9 @@ impl WebSocket { -> Fallible<Root<WebSocket>> { // Step 1. let resource_url = try!(Url::parse(&url).map_err(|_| Error::Syntax)); - let net_url = try!(parse_url(&replace_hosts(&resource_url)).map_err(|_| Error::Syntax)); - + // Although we do this replace and parse operation again in the resource task, + // we try here to be able to immediately throw a syntax error on failure. + let _ = try!(parse_url(&replace_hosts(&resource_url)).map_err(|_| Error::Syntax)); // Step 2: Disallow https -> ws connections. // Step 3: Potentially block access to some ports. @@ -254,65 +217,61 @@ impl WebSocket { // Step 7. let ws = WebSocket::new(global, resource_url.clone()); - let address = Trusted::new(global.get_cx(), ws.r(), global.script_chan()); + let address = Trusted::new(global.get_cx(), ws.r(), global.networking_task_source()); let origin = global.get_url().serialize(); - let sender = global.script_chan(); - spawn_named(format!("WebSocket connection to {}", ws.Url()), move || { - // Step 8: Protocols. - - // Step 9. - let channel = establish_a_websocket_connection(&resource_url, net_url, origin); - let (ws_sender, mut receiver) = match channel { - Ok(channel) => channel, - Err(e) => { - debug!("Failed to establish a WebSocket connection: {:?}", e); - let task = box CloseTask { - addr: address, - }; - sender.send(CommonScriptMsg::RunnableMsg(WebSocketEvent, task)).unwrap(); - return; - } - }; - let ws_sender = Arc::new(Mutex::new(ws_sender)); - let open_task = box ConnectionEstablishedTask { - addr: address.clone(), - sender: ws_sender.clone(), - }; - sender.send(CommonScriptMsg::RunnableMsg(WebSocketEvent, open_task)).unwrap(); - - for message in receiver.incoming_messages() { - let message: Message = match message { - Ok(m) => m, - Err(_) => break, - }; - let message = match message.opcode { - Type::Text => MessageData::Text(String::from_utf8_lossy(&message.payload).into_owned()), - Type::Binary => MessageData::Binary(message.payload.into_owned()), - Type::Ping => { - let pong = Message::pong(message.payload); - ws_sender.lock().unwrap().send_message(&pong).unwrap(); - continue; + let connect_data = WebSocketConnectData { + resource_url: resource_url.clone(), + origin: origin, + }; + + // Create the interface for communication with the resource task + let (dom_action_sender, resource_action_receiver): + (IpcSender<WebSocketDomAction>, + IpcReceiver<WebSocketDomAction>) = ipc::channel().unwrap(); + let (resource_event_sender, dom_event_receiver): + (IpcSender<WebSocketNetworkEvent>, + IpcReceiver<WebSocketNetworkEvent>) = ipc::channel().unwrap(); + + let connect = WebSocketCommunicate { + event_sender: resource_event_sender, + action_receiver: resource_action_receiver, + }; + + let resource_task = global.resource_task(); + let _ = resource_task.send(WebsocketConnect(connect, connect_data)); + + *ws.sender.borrow_mut() = Some(dom_action_sender); + + let moved_address = address.clone(); + let sender = global.networking_task_source(); + + thread::spawn(move || { + while let Ok(event) = dom_event_receiver.recv() { + match event { + WebSocketNetworkEvent::ConnectionEstablished => { + let open_task = box ConnectionEstablishedTask { + addr: moved_address.clone(), + }; + sender.send(CommonScriptMsg::RunnableMsg(WebSocketEvent, open_task)).unwrap(); }, - Type::Pong => continue, - Type::Close => { - ws_sender.lock().unwrap().send_message(&message).unwrap(); + WebSocketNetworkEvent::MessageReceived(message) => { + let message_task = box MessageReceivedTask { + address: moved_address.clone(), + message: message, + }; + sender.send(CommonScriptMsg::RunnableMsg(WebSocketEvent, message_task)).unwrap(); + }, + WebSocketNetworkEvent::Close => { let task = box CloseTask { - addr: address, + addr: moved_address.clone(), }; sender.send(CommonScriptMsg::RunnableMsg(WebSocketEvent, task)).unwrap(); - break; }, - }; - let message_task = box MessageReceivedTask { - address: address.clone(), - message: message, - }; - sender.send(CommonScriptMsg::RunnableMsg(WebSocketEvent, message_task)).unwrap(); + } } }); - // Step 7. Ok(ws) } @@ -328,7 +287,7 @@ impl WebSocket { }; let global = self.global.root(); - let chan = global.r().script_chan(); + let chan = global.r().networking_task_source(); let address = Trusted::new(global.r().get_cx(), self, chan.clone()); let new_buffer_amount = (self.buffered_amount.get() as u64) + data_byte_len; @@ -408,7 +367,7 @@ impl WebSocketMethods for WebSocket { if send_data { let mut other_sender = self.sender.borrow_mut(); let my_sender = other_sender.as_mut().unwrap(); - let _ = my_sender.lock().unwrap().send_message(&Message::text(data.0)); + let _ = my_sender.send(WebSocketDomAction::SendMessage(MessageData::Text(data.0))); } Ok(()) @@ -427,7 +386,7 @@ impl WebSocketMethods for WebSocket { if send_data { let mut other_sender = self.sender.borrow_mut(); let my_sender = other_sender.as_mut().unwrap(); - let _ = my_sender.lock().unwrap().send_message(&Message::binary(data.clone_bytes())); + let _ = my_sender.send(WebSocketDomAction::SendMessage(MessageData::Binary(data.clone_bytes()))); } Ok(()) @@ -443,11 +402,10 @@ impl WebSocketMethods for WebSocket { if let Some(sender) = sender.as_mut() { let code: u16 = this.code.get(); let reason = this.reason.borrow().clone(); - let _ = sender.lock().unwrap().send_message(&Message::close_because(code, reason)); + let _ = sender.send(WebSocketDomAction::Close(code, reason)); } } - if let Some(code) = code { //Fail if the supplied code isn't normal and isn't reserved for libraries, frameworks, and applications if code != close_code::NORMAL && (code < 3000 || code > 4999) { @@ -490,15 +448,11 @@ impl WebSocketMethods for WebSocket { /// Task queued when *the WebSocket connection is established*. struct ConnectionEstablishedTask { addr: Trusted<WebSocket>, - sender: Arc<Mutex<Sender<WebSocketStream>>>, } impl Runnable for ConnectionEstablishedTask { fn handler(self: Box<Self>) { let ws = self.addr.root(); - - *ws.sender.borrow_mut() = Some(self.sender); - // Step 1: Protocols. // Step 2. diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs index f8af9be77b5..fd471cc4d38 100644 --- a/components/script/dom/window.rs +++ b/components/script/dom/window.rs @@ -3,7 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use app_units::Au; -use devtools_traits::{ScriptToDevtoolsControlMsg, TimelineMarker, TimelineMarkerType}; +use devtools_traits::{ScriptToDevtoolsControlMsg, TimelineMarker, TimelineMarkerType, WorkerId}; use dom::bindings::callback::ExceptionHandling; use dom::bindings::cell::DOMRefCell; use dom::bindings::codegen::Bindings::DocumentBinding::DocumentMethods; @@ -43,8 +43,7 @@ use layout_interface::{ContentBoxResponse, ContentBoxesResponse, ResolvedStyleRe use layout_interface::{LayoutChan, LayoutRPC, Msg, Reflow, ReflowGoal, ReflowQueryType}; use libc; use msg::compositor_msg::{LayerId, ScriptToCompositorMsg}; -use msg::constellation_msg::ScriptMsg as ConstellationMsg; -use msg::constellation_msg::{ConstellationChan, LoadData, PipelineId, SubpageId, WindowSizeData, WorkerId}; +use msg::constellation_msg::{ConstellationChan, LoadData, PipelineId, SubpageId, WindowSizeData}; use msg::webdriver_msg::{WebDriverJSError, WebDriverJSResult}; use net_traits::ResourceTask; use net_traits::image_cache_task::{ImageCacheChan, ImageCacheTask}; @@ -56,6 +55,7 @@ use reporter::CSSErrorReporter; use rustc_serialize::base64::{FromBase64, STANDARD, ToBase64}; use script_task::{ScriptChan, ScriptPort, MainThreadScriptMsg, RunnableWrapper}; use script_task::{SendableMainThreadScriptChan, MainThreadScriptChan}; +use script_traits::ScriptMsg as ConstellationMsg; use script_traits::{MsDuration, TimerEvent, TimerEventId, TimerEventRequest, TimerSource}; use selectors::parser::PseudoElement; use std::ascii::AsciiExt; @@ -237,7 +237,28 @@ impl Window { self.js_runtime.borrow().as_ref().unwrap().cx() } - pub fn script_chan(&self) -> Box<ScriptChan + Send> { + pub fn dom_manipulation_task_source(&self) -> Box<ScriptChan + Send> { + // FIXME: Use a different channel instead of the generic script_chan + self.script_chan.clone() + } + + pub fn user_interaction_task_source(&self) -> Box<ScriptChan + Send> { + // FIXME: Use a different channel instead of the generic script_chan + self.script_chan.clone() + } + + pub fn networking_task_source(&self) -> Box<ScriptChan + Send> { + // FIXME: Use a different channel instead of the generic script_chan + self.script_chan.clone() + } + + pub fn history_traversal_task_source(&self) -> Box<ScriptChan + Send> { + // FIXME: Use a different channel instead of the generic script_chan + self.script_chan.clone() + } + + pub fn file_reading_task_source(&self) -> Box<ScriptChan + Send> { + // FIXME: Use a different channel instead of the generic script_chan self.script_chan.clone() } diff --git a/components/script/dom/worker.rs b/components/script/dom/worker.rs index bb95138dd75..05c242a07ba 100644 --- a/components/script/dom/worker.rs +++ b/components/script/dom/worker.rs @@ -75,7 +75,7 @@ impl Worker { let (sender, receiver) = channel(); let worker = Worker::new(global, sender.clone()); - let worker_ref = Trusted::new(global.get_cx(), worker.r(), global.script_chan()); + let worker_ref = Trusted::new(global.get_cx(), worker.r(), global.dom_manipulation_task_source()); let worker_id = global.get_next_worker_id(); let (devtools_sender, devtools_receiver) = ipc::channel().unwrap(); @@ -106,7 +106,7 @@ impl Worker { }; DedicatedWorkerGlobalScope::run_worker_scope( init, worker_url, global.pipeline(), devtools_receiver, worker_ref, - global.script_chan(), sender, receiver); + global.dom_manipulation_task_source(), sender, receiver); Ok(worker) } @@ -150,7 +150,7 @@ impl WorkerMethods for Worker { // https://html.spec.whatwg.org/multipage/#dom-dedicatedworkerglobalscope-postmessage fn PostMessage(&self, cx: *mut JSContext, message: HandleValue) -> ErrorResult { let data = try!(StructuredCloneData::write(cx, message)); - let address = Trusted::new(cx, self, self.global.root().r().script_chan().clone()); + let address = Trusted::new(cx, self, self.global.root().r().dom_manipulation_task_source().clone()); self.sender.send((address, WorkerScriptMsg::DOMMessage(data))).unwrap(); Ok(()) } diff --git a/components/script/dom/workerglobalscope.rs b/components/script/dom/workerglobalscope.rs index 96a1786ff3c..7df9b312df5 100644 --- a/components/script/dom/workerglobalscope.rs +++ b/components/script/dom/workerglobalscope.rs @@ -2,7 +2,7 @@ * 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/. */ -use devtools_traits::{DevtoolScriptControlMsg, ScriptToDevtoolsControlMsg}; +use devtools_traits::{DevtoolScriptControlMsg, ScriptToDevtoolsControlMsg, WorkerId}; use dom::bindings::codegen::Bindings::FunctionBinding::Function; use dom::bindings::codegen::Bindings::WorkerGlobalScopeBinding::WorkerGlobalScopeMethods; use dom::bindings::error::{Error, ErrorResult, Fallible, report_pending_exception}; @@ -20,11 +20,11 @@ use dom::workernavigator::WorkerNavigator; use ipc_channel::ipc::IpcSender; use js::jsapi::{HandleValue, JSAutoRequest, JSContext}; use js::rust::Runtime; -use msg::constellation_msg::ScriptMsg as ConstellationMsg; -use msg::constellation_msg::{ConstellationChan, PipelineId, WorkerId}; +use msg::constellation_msg::{ConstellationChan, PipelineId}; use net_traits::{ResourceTask, load_whole_resource}; use profile_traits::mem; use script_task::{CommonScriptMsg, ScriptChan, ScriptPort}; +use script_traits::ScriptMsg as ConstellationMsg; use script_traits::{MsDuration, TimerEvent, TimerEventId, TimerEventRequest, TimerSource}; use std::cell::Cell; use std::default::Default; diff --git a/components/script/dom/xmlhttprequest.rs b/components/script/dom/xmlhttprequest.rs index 0f93410f0c1..c46f9b22d3c 100644 --- a/components/script/dom/xmlhttprequest.rs +++ b/components/script/dom/xmlhttprequest.rs @@ -4,8 +4,10 @@ use cors::CORSResponse; use cors::{AsyncCORSResponseListener, CORSRequest, RequestMode, allow_cross_origin_request}; +use document_loader::DocumentLoader; use dom::bindings::cell::DOMRefCell; use dom::bindings::codegen::Bindings::EventHandlerBinding::EventHandlerNonNull; +use dom::bindings::codegen::Bindings::WindowBinding::WindowMethods; use dom::bindings::codegen::Bindings::XMLHttpRequestBinding; use dom::bindings::codegen::Bindings::XMLHttpRequestBinding::XMLHttpRequestMethods; use dom::bindings::codegen::Bindings::XMLHttpRequestBinding::XMLHttpRequestResponseType; @@ -16,12 +18,13 @@ use dom::bindings::conversions::{ToJSValConvertible}; use dom::bindings::error::{Error, ErrorResult, Fallible}; use dom::bindings::global::{GlobalField, GlobalRef, GlobalRoot}; use dom::bindings::inheritance::Castable; -use dom::bindings::js::Root; use dom::bindings::js::{JS, MutNullableHeap}; +use dom::bindings::js::{Root, RootedReference}; use dom::bindings::refcounted::Trusted; use dom::bindings::reflector::{Reflectable, reflect_dom_object}; use dom::bindings::str::ByteString; -use dom::document::Document; +use dom::document::DocumentSource; +use dom::document::{Document, IsHTMLDocument}; use dom::event::{Event, EventBubbles, EventCancelable}; use dom::eventtarget::EventTarget; use dom::progressevent::ProgressEvent; @@ -45,6 +48,8 @@ use net_traits::ControlMsg::Load; use net_traits::{AsyncResponseListener, AsyncResponseTarget, Metadata}; use net_traits::{LoadConsumer, LoadData, ResourceCORSData, ResourceTask}; use network_listener::{NetworkListener, PreInvoke}; +use parse::html::{ParseContext, parse_html}; +use parse::xml::{self, parse_xml}; use script_task::{ScriptChan, ScriptPort}; use std::ascii::AsciiExt; use std::borrow::ToOwned; @@ -248,7 +253,7 @@ impl XMLHttpRequest { } fn data_available(&mut self, payload: Vec<u8>) { - self.buf.borrow_mut().push_all(&payload); + self.buf.borrow_mut().extend_from_slice(&payload); self.xhr.root().process_data_available(self.gen_id, self.buf.borrow().clone()); } @@ -398,8 +403,8 @@ impl XMLHttpRequestMethods for XMLHttpRequest { Some(raw) => { debug!("SetRequestHeader: old value = {:?}", raw[0]); let mut buf = raw[0].clone(); - buf.push_all(b", "); - buf.push_all(&value); + buf.extend_from_slice(b", "); + buf.extend_from_slice(&value); debug!("SetRequestHeader: new value = {:?}", buf); value = ByteString::new(buf); }, @@ -525,8 +530,8 @@ impl XMLHttpRequestMethods for XMLHttpRequest { fn join_raw(a: &str, b: &str) -> Vec<u8> { let len = a.len() + b.len(); let mut vec = Vec::with_capacity(len); - vec.push_all(a.as_bytes()); - vec.push_all(b.as_bytes()); + vec.extend_from_slice(a.as_bytes()); + vec.extend_from_slice(b.as_bytes()); vec } @@ -572,12 +577,20 @@ impl XMLHttpRequestMethods for XMLHttpRequest { let mut buf = String::new(); buf.push_str(&referer_url.scheme); buf.push_str("://"); - referer_url.serialize_host().map(|ref h| buf.push_str(h)); - referer_url.port().as_ref().map(|&p| { + + if let Some(ref h) = referer_url.serialize_host() { + buf.push_str(h); + } + + if let Some(ref p) = referer_url.port().as_ref() { buf.push_str(":"); buf.push_str(&p.to_string()); - }); - referer_url.serialize_path().map(|ref h| buf.push_str(h)); + } + + if let Some(ref h) = referer_url.serialize_path() { + buf.push_str(h); + } + self.request_headers.borrow_mut().set_raw("Referer".to_owned(), vec![buf.into_bytes()]); }, Ok(Some(ref req)) => self.insert_trusted_header("origin".to_owned(), @@ -701,6 +714,14 @@ impl XMLHttpRequestMethods for XMLHttpRequest { _ if self.ready_state.get() != XMLHttpRequestState::Done => { return NullValue() }, + XMLHttpRequestResponseType::Document => { + let op_doc = self.GetResponseXML(); + if let Ok(Some(doc)) = op_doc { + doc.to_jsval(cx, rval.handle_mut()); + } else { + return NullValue(); + } + }, Json => { let decoded = UTF_8.decode(&self.response.borrow(), DecoderTrap::Replace).unwrap().to_owned(); let decoded: Vec<u16> = decoded.utf16_units().collect(); @@ -735,8 +756,25 @@ impl XMLHttpRequestMethods for XMLHttpRequest { } // https://xhr.spec.whatwg.org/#the-responsexml-attribute - fn GetResponseXML(&self) -> Option<Root<Document>> { - self.response_xml.get() + fn GetResponseXML(&self) -> Fallible<Option<Root<Document>>> { + match self.response_type.get() { + _empty | XMLHttpRequestResponseType::Document => { + match self.ready_state.get() { + XMLHttpRequestState::Done => { + match self.response_xml.get() { + Some(response) => Ok(Some(response)), + None => { + let response = self.document_response(); + self.response_xml.set(response.r()); + Ok(response) + } + } + }, + _ => Ok(None) + } + }, + _ => { Err(Error::InvalidState) } + } } } @@ -984,7 +1022,7 @@ impl XMLHttpRequest { // This will cancel all previous timeouts let global = self.global.root(); let callback = ScheduledXHRTimeout { - xhr: Trusted::new(global.r().get_cx(), self, global.r().script_chan()), + xhr: Trusted::new(global.r().get_cx(), self, global.r().networking_task_source()), generation_id: self.generation_id.get(), }; let duration = Length::new(duration_ms as u64); @@ -1006,6 +1044,87 @@ impl XMLHttpRequest { // the result should be fine. XXXManishearth have a closer look at this later encoding.decode(&self.response.borrow(), DecoderTrap::Replace).unwrap().to_owned() } + + fn document_response(&self) -> Option<Root<Document>> { + let mime_type = self.final_mime_type(); + //TODO: prescan the response to determine encoding if final charset is null + let charset = self.final_charset().unwrap_or(UTF_8); + let temp_doc: Root<Document>; + match mime_type { + Some(Mime(mime::TopLevel::Text, mime::SubLevel::Html, _)) => { + if self.response_type.get() == XMLHttpRequestResponseType::_empty { + return None; + } + else { + temp_doc = self.document_text_html(); + } + }, + Some(Mime(mime::TopLevel::Text, mime::SubLevel::Xml, _)) | + Some(Mime(mime::TopLevel::Application, mime::SubLevel::Xml, _)) | + None => { + temp_doc = self.handle_xml(); + }, + Some(Mime(_, mime::SubLevel::Ext(sub), _)) => { + if sub.ends_with("+xml") { + temp_doc = self.handle_xml(); + } + else { + return None; + } + }, + _ => { return None; } + } + temp_doc.set_encoding_name(DOMString::from(charset.name())); + Some(temp_doc) + } + + fn document_text_html(&self) -> Root<Document>{ + let charset = self.final_charset().unwrap_or(UTF_8); + let wr = self.global.root(); + let wr = wr.r(); + let decoded = charset.decode(&self.response.borrow(), DecoderTrap::Replace).unwrap().to_owned(); + let document = self.new_doc(IsHTMLDocument::HTMLDocument); + // TODO: Disable scripting while parsing + parse_html(document.r(), DOMString::from(decoded), wr.get_url(), ParseContext::Owner(Some(wr.pipeline()))); + document + } + + fn handle_xml(&self) -> Root<Document> { + let charset = self.final_charset().unwrap_or(UTF_8); + let wr = self.global.root(); + let wr = wr.r(); + let decoded = charset.decode(&self.response.borrow(), DecoderTrap::Replace).unwrap().to_owned(); + let document = self.new_doc(IsHTMLDocument::NonHTMLDocument); + // TODO: Disable scripting while parsing + parse_xml(document.r(), DOMString::from(decoded), wr.get_url(), xml::ParseContext::Owner(Some(wr.pipeline()))); + document + } + + fn new_doc(&self, is_html_document: IsHTMLDocument) -> Root<Document> { + let wr = self.global.root(); + let wr = wr.r(); + let win = wr.as_window(); + let doc = win.Document(); + let doc = doc.r(); + let docloader = DocumentLoader::new(&*doc.loader()); + let base = self.global.root().r().get_url(); + let parsed_url = match UrlParser::new().base_url(&base).parse(&self.ResponseURL()) { + Ok(parsed) => Some(parsed), + Err(_) => None // Step 7 + }; + let mime_type = self.final_mime_type(); + let content_type = mime_type.map(|mime|{ + DOMString::from(format!("{}", mime)) + }); + let document = Document::new(win, + parsed_url, + is_html_document, + content_type, + None, + DocumentSource::FromParser, docloader); + document + } + fn filter_response_headers(&self) -> Headers { // https://fetch.spec.whatwg.org/#concept-response-header-list use hyper::error::Result; @@ -1056,7 +1175,7 @@ impl XMLHttpRequest { Ok(req) => req, }; - let xhr = Trusted::new(global.get_cx(), self, global.script_chan()); + let xhr = Trusted::new(global.get_cx(), self, global.networking_task_source()); let context = Arc::new(Mutex::new(XHRContext { xhr: xhr, @@ -1070,7 +1189,7 @@ impl XMLHttpRequest { let (tx, rx) = global.new_script_pair(); (tx, Some(rx)) } else { - (global.script_chan(), None) + (global.networking_task_source(), None) }; let resource_task = global.resource_task(); |