Enable inline event handlers for XHR, and add most progressevent calls

This commit is contained in:
Manish Goregaokar 2014-05-29 19:15:56 +05:30
parent 43beda87b2
commit 6f728cb2ca
5 changed files with 196 additions and 21 deletions

View file

@ -22,6 +22,11 @@ impl ByteString {
vector.as_slice() vector.as_slice()
} }
pub fn len(&self) -> uint {
let ByteString(ref vector) = *self;
vector.len()
}
pub fn eq_ignore_case(&self, other: &ByteString) -> bool { pub fn eq_ignore_case(&self, other: &ByteString) -> bool {
// XXXManishearth make this more efficient // XXXManishearth make this more efficient
self.to_lower() == other.to_lower() self.to_lower() == other.to_lower()
@ -60,7 +65,7 @@ impl ByteString {
Other, Other,
CR, CR,
LF, LF,
SP_HT // SP or HT SPHT // SP or HT
} }
let ByteString(ref vec) = *self; let ByteString(ref vec) = *self;
let mut prev = Other; // The previous character let mut prev = Other; // The previous character
@ -68,7 +73,7 @@ impl ByteString {
// http://tools.ietf.org/html/rfc2616#section-2.2 // http://tools.ietf.org/html/rfc2616#section-2.2
match x { match x {
13 => { // CR 13 => { // CR
if prev == Other || prev == SP_HT { if prev == Other || prev == SPHT {
prev = CR; prev = CR;
true true
} else { } else {
@ -84,8 +89,8 @@ impl ByteString {
} }
}, },
32 | 9 => { // SP | HT 32 | 9 => { // SP | HT
if prev == LF || prev == SP_HT { if prev == LF || prev == SPHT {
prev = SP_HT; prev = SPHT;
true true
} else { } else {
false false
@ -93,7 +98,7 @@ impl ByteString {
}, },
0..31 | 127 => false, // CTLs 0..31 | 127 => false, // CTLs
x if x > 127 => false, // non ASCII x if x > 127 => false, // non ASCII
_ if prev == Other || prev == SP_HT => { _ if prev == Other || prev == SPHT => {
prev = Other; prev = Other;
true true
}, },

View file

@ -26,7 +26,7 @@ enum XMLHttpRequestResponseType {
Exposed=Window,Worker] Exposed=Window,Worker]
interface XMLHttpRequest : XMLHttpRequestEventTarget { interface XMLHttpRequest : XMLHttpRequestEventTarget {
// event handler // event handler
// attribute EventHandler onreadystatechange; attribute EventHandler onreadystatechange;
// states // states
const unsigned short UNSENT = 0; const unsigned short UNSENT = 0;

View file

@ -16,7 +16,6 @@
/* https://github.com/mozilla/servo/issues/1223: [NoInterfaceObject] */ /* https://github.com/mozilla/servo/issues/1223: [NoInterfaceObject] */
interface XMLHttpRequestEventTarget : EventTarget { interface XMLHttpRequestEventTarget : EventTarget {
// event handlers // event handlers
/* Needs EventHandler: https://github.com/mozilla/servo/issues/1238
attribute EventHandler onloadstart; attribute EventHandler onloadstart;
attribute EventHandler onprogress; attribute EventHandler onprogress;
attribute EventHandler onabort; attribute EventHandler onabort;
@ -24,5 +23,4 @@ interface XMLHttpRequestEventTarget : EventTarget {
attribute EventHandler onload; attribute EventHandler onload;
attribute EventHandler ontimeout; attribute EventHandler ontimeout;
attribute EventHandler onloadend; attribute EventHandler onloadend;
*/
}; };

View file

@ -3,21 +3,23 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use dom::bindings::codegen::BindingDeclarations::XMLHttpRequestBinding; use dom::bindings::codegen::BindingDeclarations::XMLHttpRequestBinding;
use dom::bindings::codegen::EventHandlerBinding::EventHandlerNonNull;
use dom::bindings::str::ByteString; use dom::bindings::str::ByteString;
use dom::bindings::codegen::BindingDeclarations::XMLHttpRequestBinding::XMLHttpRequestResponseType; use dom::bindings::codegen::BindingDeclarations::XMLHttpRequestBinding::XMLHttpRequestResponseType;
use dom::bindings::codegen::BindingDeclarations::XMLHttpRequestBinding::XMLHttpRequestResponseTypeValues::{_empty, Text}; use dom::bindings::codegen::BindingDeclarations::XMLHttpRequestBinding::XMLHttpRequestResponseTypeValues::{_empty, Text};
use dom::bindings::codegen::InheritTypes::{EventTargetCast, XMLHttpRequestDerived}; use dom::bindings::codegen::InheritTypes::{EventCast, EventTargetCast, XMLHttpRequestDerived};
use dom::bindings::error::{ErrorResult, InvalidState, Network, Syntax, Security}; use dom::bindings::error::{ErrorResult, InvalidState, Network, Syntax, Security};
use dom::document::Document; use dom::document::Document;
use dom::event::{Event, EventMethods}; use dom::event::{Event, EventMethods};
use dom::eventtarget::{EventTarget, EventTargetHelpers, XMLHttpRequestTargetTypeId}; use dom::eventtarget::{EventTarget, EventTargetHelpers, XMLHttpRequestTargetTypeId};
use dom::bindings::conversions::ToJSValConvertible; use dom::bindings::conversions::ToJSValConvertible;
use dom::bindings::error::Fallible; use dom::bindings::error::Fallible;
use dom::bindings::js::{JS, JSRef, Temporary, OptionalSettable}; use dom::bindings::js::{JS, JSRef, Temporary, OptionalSettable, OptionalRootedRootable};
use dom::bindings::trace::Untraceable; use dom::bindings::trace::Untraceable;
use js::jsapi::{JS_AddObjectRoot, JS_RemoveObjectRoot, JSContext}; use js::jsapi::{JS_AddObjectRoot, JS_RemoveObjectRoot, JSContext};
use js::jsval::{JSVal, NullValue}; use js::jsval::{JSVal, NullValue};
use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object}; use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object};
use dom::progressevent::ProgressEvent;
use dom::window::Window; use dom::window::Window;
use dom::xmlhttprequesteventtarget::XMLHttpRequestEventTarget; use dom::xmlhttprequesteventtarget::XMLHttpRequestEventTarget;
use dom::xmlhttprequestupload::XMLHttpRequestUpload; use dom::xmlhttprequestupload::XMLHttpRequestUpload;
@ -215,6 +217,8 @@ impl XMLHttpRequest {
} }
pub trait XMLHttpRequestMethods<'a> { pub trait XMLHttpRequestMethods<'a> {
fn GetOnreadystatechange(&self) -> Option<EventHandlerNonNull>;
fn SetOnreadystatechange(&mut self, listener: Option<EventHandlerNonNull>);
fn ReadyState(&self) -> u16; fn ReadyState(&self) -> u16;
fn Open(&mut self, _method: ByteString, _url: DOMString) -> ErrorResult; fn Open(&mut self, _method: ByteString, _url: DOMString) -> ErrorResult;
fn Open_(&mut self, _method: ByteString, _url: DOMString, _async: bool, fn Open_(&mut self, _method: ByteString, _url: DOMString, _async: bool,
@ -241,9 +245,20 @@ pub trait XMLHttpRequestMethods<'a> {
} }
impl<'a> XMLHttpRequestMethods<'a> for JSRef<'a, XMLHttpRequest> { impl<'a> XMLHttpRequestMethods<'a> for JSRef<'a, XMLHttpRequest> {
fn GetOnreadystatechange(&self) -> Option<EventHandlerNonNull> {
let eventtarget: &JSRef<EventTarget> = EventTargetCast::from_ref(self);
eventtarget.get_event_handler_common("readystatechange")
}
fn SetOnreadystatechange(&mut self, listener: Option<EventHandlerNonNull>) {
let eventtarget: &mut JSRef<EventTarget> = EventTargetCast::from_mut_ref(self);
eventtarget.set_event_handler_common("readystatechange", listener)
}
fn ReadyState(&self) -> u16 { fn ReadyState(&self) -> u16 {
self.ready_state as u16 self.ready_state as u16
} }
fn Open(&mut self, method: ByteString, url: DOMString) -> ErrorResult { fn Open(&mut self, method: ByteString, url: DOMString) -> ErrorResult {
let maybe_method: Option<Method> = method.as_str().and_then(|s| { let maybe_method: Option<Method> = method.as_str().and_then(|s| {
FromStr::from_str(s.to_ascii_upper()) // rust-http tests against the uppercase versions FromStr::from_str(s.to_ascii_upper()) // rust-http tests against the uppercase versions
@ -383,12 +398,29 @@ impl<'a> XMLHttpRequestMethods<'a> for JSRef<'a, XMLHttpRequest> {
}; };
// Step 6 // Step 6
self.upload_complete = false;
self.upload_events = false; self.upload_events = false;
// XXXManishearth handle upload events // Step 7
self.upload_complete = match data {
None => true,
Some (ref s) if s.len() == 0 => true,
_ => false
};
if !self.sync {
// Step 8
let upload_target = &*self.upload.root().unwrap();
let event_target: &JSRef<EventTarget> = EventTargetCast::from_ref(upload_target);
if event_target.handlers.iter().len() > 0 {
self.upload_events = true;
}
// Step 9
self.send_flag = true;
self.dispatch_response_progress_event("loadstart".to_owned());
if !self.upload_complete {
self.dispatch_upload_progress_event("loadstart".to_owned(), Some(0));
}
}
// Step 9
self.send_flag = true;
let mut global = self.global.root(); let mut global = self.global.root();
let resource_task = global.page().resource_task.deref().clone(); let resource_task = global.page().resource_task.deref().clone();
let mut load_data = LoadData::new((*self.request_url).clone()); let mut load_data = LoadData::new((*self.request_url).clone());
@ -506,6 +538,9 @@ trait PrivateXMLHttpRequestHelpers {
fn change_ready_state(&mut self, XMLHttpRequestState); fn change_ready_state(&mut self, XMLHttpRequestState);
fn process_partial_response(&mut self, progress: XHRProgress); fn process_partial_response(&mut self, progress: XHRProgress);
fn insert_trusted_header(&mut self, name: ~str, value: ~str); fn insert_trusted_header(&mut self, name: ~str, value: ~str);
fn dispatch_progress_event(&self, upload: bool, type_: DOMString, loaded: u64, total: Option<u64>);
fn dispatch_upload_progress_event(&self, type_: DOMString, partial_load: Option<u64>);
fn dispatch_response_progress_event(&self, type_: DOMString);
} }
impl<'a> PrivateXMLHttpRequestHelpers for JSRef<'a, XMLHttpRequest> { impl<'a> PrivateXMLHttpRequestHelpers for JSRef<'a, XMLHttpRequest> {
@ -537,6 +572,12 @@ impl<'a> PrivateXMLHttpRequestHelpers for JSRef<'a, XMLHttpRequest> {
fn process_partial_response(&mut self, progress: XHRProgress) { fn process_partial_response(&mut self, progress: XHRProgress) {
match progress { match progress {
HeadersReceivedMsg(headers) => { HeadersReceivedMsg(headers) => {
// XXXManishearth Find a way to track partial progress of the send (onprogresss for XHRUpload)
self.upload_complete = true;
self.dispatch_upload_progress_event("progress".to_owned(), None);
self.dispatch_upload_progress_event("load".to_owned(), None);
self.dispatch_upload_progress_event("loadend".to_owned(), None);
match headers { match headers {
Some(ref h) => *self.response_headers = h.clone(), Some(ref h) => *self.response_headers = h.clone(),
None => {} None => {}
@ -545,23 +586,36 @@ impl<'a> PrivateXMLHttpRequestHelpers for JSRef<'a, XMLHttpRequest> {
}, },
LoadingMsg(partial_response) => { LoadingMsg(partial_response) => {
self.response = partial_response; self.response = partial_response;
self.dispatch_response_progress_event("progress".to_owned());
if self.ready_state == HeadersReceived { if self.ready_state == HeadersReceived {
self.change_ready_state(Loading); self.change_ready_state(Loading);
} }
}, },
DoneMsg => { DoneMsg => {
let len = self.response.len() as u64;
self.dispatch_response_progress_event("progress".to_owned());
self.dispatch_response_progress_event("load".to_owned());
self.dispatch_response_progress_event("loadend".to_owned());
self.send_flag = false; self.send_flag = false;
self.change_ready_state(XHRDone); self.change_ready_state(XHRDone);
}, },
ErroredMsg => { ErroredMsg => {
self.send_flag = false; self.send_flag = false;
// XXXManishearth set response to NetworkError // XXXManishearth set response to NetworkError
if !self.upload_complete { // XXXManishearth also handle terminated requests (timeout/abort/fatal)
self.upload_complete = true;
// XXXManishearth handle upload progress
}
// XXXManishearth fire some progress events
self.change_ready_state(XHRDone); self.change_ready_state(XHRDone);
if !self.sync {
if !self.upload_complete {
self.upload_complete = true;
self.dispatch_upload_progress_event("progress".to_owned(), None);
self.dispatch_upload_progress_event("load".to_owned(), None);
self.dispatch_upload_progress_event("loadend".to_owned(), None);
}
self.dispatch_response_progress_event("progress".to_owned());
self.dispatch_response_progress_event("load".to_owned());
self.dispatch_response_progress_event("loadend".to_owned());
}
}, },
ReleaseMsg => { ReleaseMsg => {
self.release(); self.release();
@ -580,4 +634,33 @@ impl<'a> PrivateXMLHttpRequestHelpers for JSRef<'a, XMLHttpRequest> {
&mut HeaderValueByteIterator::new(&mut reader)); &mut HeaderValueByteIterator::new(&mut reader));
collection.insert(maybe_header.unwrap()); collection.insert(maybe_header.unwrap());
} }
fn dispatch_progress_event(&self, upload: bool, type_: DOMString, loaded: u64, total: Option<u64>) {
let win = &*self.global.root();
let upload_target = &*self.upload.root().unwrap();
let mut progressevent = ProgressEvent::new(win, type_, false, false,
total.is_some(), loaded,
total.unwrap_or(0)).root();
let target: &JSRef<EventTarget> = if upload {
EventTargetCast::from_ref(upload_target)
} else {
EventTargetCast::from_ref(self)
};
let event: &mut JSRef<Event> = EventCast::from_mut_ref(&mut *progressevent);
target.dispatch_event_with_target(None, &mut *event).ok();
}
fn dispatch_upload_progress_event(&self, type_: DOMString, partial_load: Option<u64>) {
// If partial_load is None, loading has completed and we can just use the value from the request body
let total = self.request_body.len() as u64;
self.dispatch_progress_event(true, type_, partial_load.unwrap_or(total), Some(total));
}
fn dispatch_response_progress_event(&self, type_: DOMString) {
let win = &*self.global.root();
let len = self.response.len() as u64;
let total = self.response_headers.deref().content_length.map(|x| {x as u64});
self.dispatch_progress_event(false, type_, len, total);
}
} }

View file

@ -3,8 +3,11 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use dom::bindings::codegen::InheritTypes::XMLHttpRequestEventTargetDerived; use dom::bindings::codegen::InheritTypes::XMLHttpRequestEventTargetDerived;
use dom::bindings::codegen::EventHandlerBinding::EventHandlerNonNull;
use dom::bindings::codegen::InheritTypes::EventTargetCast;
use dom::bindings::js::JSRef;
use dom::bindings::utils::{Reflectable, Reflector}; use dom::bindings::utils::{Reflectable, Reflector};
use dom::eventtarget::{EventTarget, XMLHttpRequestTargetTypeId}; use dom::eventtarget::{EventTarget, EventTargetHelpers, XMLHttpRequestTargetTypeId};
use dom::xmlhttprequest::XMLHttpRequestId; use dom::xmlhttprequest::XMLHttpRequestId;
#[deriving(Encodable)] #[deriving(Encodable)]
@ -40,4 +43,90 @@ impl Reflectable for XMLHttpRequestEventTarget {
} }
pub trait XMLHttpRequestEventTargetMethods { pub trait XMLHttpRequestEventTargetMethods {
fn GetOnloadstart(&self) -> Option<EventHandlerNonNull>;
fn SetOnloadstart(&mut self, listener: Option<EventHandlerNonNull>);
fn GetOnprogress(&self) -> Option<EventHandlerNonNull>;
fn SetOnprogress(&mut self, listener: Option<EventHandlerNonNull>);
fn GetOnabort(&self) -> Option<EventHandlerNonNull>;
fn SetOnabort(&mut self, listener: Option<EventHandlerNonNull>);
fn GetOnerror(&self) -> Option<EventHandlerNonNull>;
fn SetOnerror(&mut self, listener: Option<EventHandlerNonNull>);
fn GetOnload(&self) -> Option<EventHandlerNonNull>;
fn SetOnload(&mut self, listener: Option<EventHandlerNonNull>);
fn GetOntimeout(&self) -> Option<EventHandlerNonNull>;
fn SetOntimeout(&mut self, listener: Option<EventHandlerNonNull>);
fn GetOnloadend(&self) -> Option<EventHandlerNonNull>;
fn SetOnloadend(&mut self, listener: Option<EventHandlerNonNull>);
}
impl<'a> XMLHttpRequestEventTargetMethods for JSRef<'a, XMLHttpRequestEventTarget> {
fn GetOnloadstart(&self) -> Option<EventHandlerNonNull> {
let eventtarget: &JSRef<EventTarget> = EventTargetCast::from_ref(self);
eventtarget.get_event_handler_common("loadstart")
}
fn SetOnloadstart(&mut self, listener: Option<EventHandlerNonNull>) {
let eventtarget: &mut JSRef<EventTarget> = EventTargetCast::from_mut_ref(self);
eventtarget.set_event_handler_common("loadstart", listener)
}
fn GetOnprogress(&self) -> Option<EventHandlerNonNull> {
let eventtarget: &JSRef<EventTarget> = EventTargetCast::from_ref(self);
eventtarget.get_event_handler_common("progress")
}
fn SetOnprogress(&mut self, listener: Option<EventHandlerNonNull>) {
let eventtarget: &mut JSRef<EventTarget> = EventTargetCast::from_mut_ref(self);
eventtarget.set_event_handler_common("progress", listener)
}
fn GetOnabort(&self) -> Option<EventHandlerNonNull> {
let eventtarget: &JSRef<EventTarget> = EventTargetCast::from_ref(self);
eventtarget.get_event_handler_common("abort")
}
fn SetOnabort(&mut self, listener: Option<EventHandlerNonNull>) {
let eventtarget: &mut JSRef<EventTarget> = EventTargetCast::from_mut_ref(self);
eventtarget.set_event_handler_common("abort", listener)
}
fn GetOnerror(&self) -> Option<EventHandlerNonNull> {
let eventtarget: &JSRef<EventTarget> = EventTargetCast::from_ref(self);
eventtarget.get_event_handler_common("error")
}
fn SetOnerror(&mut self, listener: Option<EventHandlerNonNull>) {
let eventtarget: &mut JSRef<EventTarget> = EventTargetCast::from_mut_ref(self);
eventtarget.set_event_handler_common("error", listener)
}
fn GetOnload(&self) -> Option<EventHandlerNonNull> {
let eventtarget: &JSRef<EventTarget> = EventTargetCast::from_ref(self);
eventtarget.get_event_handler_common("load")
}
fn SetOnload(&mut self, listener: Option<EventHandlerNonNull>) {
let eventtarget: &mut JSRef<EventTarget> = EventTargetCast::from_mut_ref(self);
eventtarget.set_event_handler_common("load", listener)
}
fn GetOntimeout(&self) -> Option<EventHandlerNonNull> {
let eventtarget: &JSRef<EventTarget> = EventTargetCast::from_ref(self);
eventtarget.get_event_handler_common("timeout")
}
fn SetOntimeout(&mut self, listener: Option<EventHandlerNonNull>) {
let eventtarget: &mut JSRef<EventTarget> = EventTargetCast::from_mut_ref(self);
eventtarget.set_event_handler_common("timeout", listener)
}
fn GetOnloadend(&self) -> Option<EventHandlerNonNull> {
let eventtarget: &JSRef<EventTarget> = EventTargetCast::from_ref(self);
eventtarget.get_event_handler_common("loadend")
}
fn SetOnloadend(&mut self, listener: Option<EventHandlerNonNull>) {
let eventtarget: &mut JSRef<EventTarget> = EventTargetCast::from_mut_ref(self);
eventtarget.set_event_handler_common("loadend", listener)
}
} }