aboutsummaryrefslogtreecommitdiffstats
path: root/components/script/dom
diff options
context:
space:
mode:
Diffstat (limited to 'components/script/dom')
-rw-r--r--components/script/dom/bindings/codegen/CodegenRust.py31
-rw-r--r--components/script/dom/bindings/global.rs47
-rw-r--r--components/script/dom/bindings/trace.rs7
-rw-r--r--components/script/dom/bindings/utils.rs26
-rw-r--r--components/script/dom/blob.rs2
-rw-r--r--components/script/dom/canvasrenderingcontext2d.rs2
-rw-r--r--components/script/dom/document.rs3
-rw-r--r--components/script/dom/filereader.rs4
-rw-r--r--components/script/dom/htmlbodyelement.rs2
-rw-r--r--components/script/dom/htmliframeelement.rs2
-rw-r--r--components/script/dom/htmlimageelement.rs4
-rw-r--r--components/script/dom/htmlinputelement.rs2
-rw-r--r--components/script/dom/htmllinkelement.rs4
-rw-r--r--components/script/dom/htmlscriptelement.rs42
-rw-r--r--components/script/dom/htmltextareaelement.rs4
-rw-r--r--components/script/dom/storage.rs2
-rw-r--r--components/script/dom/webglrenderingcontext.rs4
-rw-r--r--components/script/dom/webidls/XMLHttpRequest.webidl1
-rw-r--r--components/script/dom/websocket.rs162
-rw-r--r--components/script/dom/window.rs29
-rw-r--r--components/script/dom/worker.rs6
-rw-r--r--components/script/dom/workerglobalscope.rs6
-rw-r--r--components/script/dom/xmlhttprequest.rs151
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();