Make timeouts for async XHR post a runnable.

This commit is contained in:
Josh Matthews 2015-03-04 15:20:31 -05:00
parent 5c7be5c9c3
commit 17a88f1f81

View file

@ -218,7 +218,6 @@ impl XMLHttpRequest {
#[allow(unsafe_code)] #[allow(unsafe_code)]
fn fetch2(xhr: TrustedXHRAddress, script_chan: Box<ScriptChan+Send>, fn fetch2(xhr: TrustedXHRAddress, script_chan: Box<ScriptChan+Send>,
resource_task: ResourceTask, load_data: LoadData, sync: bool, resource_task: ResourceTask, load_data: LoadData, sync: bool,
terminate_receiver: Receiver<TerminateReason>,
cors_request: Result<Option<CORSRequest>,()>, gen_id: GenerationId) { cors_request: Result<Option<CORSRequest>,()>, gen_id: GenerationId) {
let cors_request = match cors_request { let cors_request = match cors_request {
Err(_) => { Err(_) => {
@ -229,13 +228,11 @@ impl XMLHttpRequest {
Ok(req) => req, Ok(req) => req,
}; };
#[derive(Clone)]
struct XHRContext { struct XHRContext {
xhr: TrustedXHRAddress, xhr: TrustedXHRAddress,
gen_id: GenerationId, gen_id: GenerationId,
cors_request: Option<CORSRequest>, cors_request: Option<CORSRequest>,
buf: DOMRefCell<Vec<u8>>, buf: DOMRefCell<Vec<u8>>,
terminate_receiver: Arc<Mutex<Receiver<TerminateReason>>>,
got_response_complete: Cell<bool>, got_response_complete: Cell<bool>,
} }
@ -243,7 +240,6 @@ impl XMLHttpRequest {
xhr: xhr, xhr: xhr,
cors_request: cors_request.clone(), cors_request: cors_request.clone(),
gen_id: gen_id, gen_id: gen_id,
terminate_receiver: Arc::new(Mutex::new(terminate_receiver)),
buf: DOMRefCell::new(vec!()), buf: DOMRefCell::new(vec!()),
got_response_complete: Cell::new(false), got_response_complete: Cell::new(false),
})); }));
@ -260,8 +256,10 @@ impl XMLHttpRequest {
impl AsyncCORSResponseListener for CORSContext { impl AsyncCORSResponseListener for CORSContext {
fn response_available(&self, response: CORSResponse) { fn response_available(&self, response: CORSResponse) {
if response.network_error { if response.network_error {
//notify_error_and_return!(Network); let context = self.xhr.lock().unwrap();
return; //XXXjdm let xhr = context.xhr.to_temporary().root();
xhr.r().process_partial_response(XHRProgress::Errored(context.gen_id, Network));
return; //XXXjdm Err(Network)
} }
let mut load_data = self.load_data.borrow_mut().take().unwrap(); let mut load_data = self.load_data.borrow_mut().take().unwrap();
@ -348,27 +346,12 @@ impl XMLHttpRequest {
fn handler(self: Box<XHRRunnable>) { fn handler(self: Box<XHRRunnable>) {
let this = *self; let this = *self;
let context = this.context.lock(); let context = this.context.lock().unwrap();
let context = context.unwrap();
let xhr = context.xhr.to_temporary().root(); let xhr = context.xhr.to_temporary().root();
if xhr.r().generation_id.get() != context.gen_id { if xhr.r().generation_id.get() != context.gen_id {
return; return;
} }
{
let terminate_receiver = context.terminate_receiver.lock().unwrap();
if let Ok(reason) = terminate_receiver.try_recv() {
match reason {
TerminateReason::AbortedOrReopened => return, //Err(Abort)
TerminateReason::TimedOut => {
xhr.r().process_partial_response(
XHRProgress::Errored(context.gen_id, Network));
return; //Err(Network)
}
}
}
}
this.action.process(&*context); this.action.process(&*context);
} }
} }
@ -856,7 +839,7 @@ impl<'a> XMLHttpRequestMethods for JSRef<'a, XMLHttpRequest> {
let addr = Trusted::new(self.global.root().r().get_cx(), self, let addr = Trusted::new(self.global.root().r().get_cx(), self,
script_chan.clone()); script_chan.clone());
XMLHttpRequest::fetch2(addr, script_chan, resource_task, load_data, self.sync.get(), XMLHttpRequest::fetch2(addr, script_chan, resource_task, load_data, self.sync.get(),
terminate_receiver, cors_request, gen_id); cors_request, gen_id);
let timeout = self.timeout.get(); let timeout = self.timeout.get();
if timeout > 0 { if timeout > 0 {
self.set_timeout(timeout); self.set_timeout(timeout);
@ -1015,6 +998,7 @@ trait PrivateXMLHttpRequestHelpers {
fn set_timeout(self, timeout:u32); fn set_timeout(self, timeout:u32);
fn cancel_timeout(self); fn cancel_timeout(self);
fn filter_response_headers(self) -> Headers; fn filter_response_headers(self) -> Headers;
fn discard_subsequent_responses(self);
} }
impl<'a> PrivateXMLHttpRequestHelpers for JSRef<'a, XMLHttpRequest> { impl<'a> PrivateXMLHttpRequestHelpers for JSRef<'a, XMLHttpRequest> {
@ -1078,7 +1062,7 @@ impl<'a> PrivateXMLHttpRequestHelpers for JSRef<'a, XMLHttpRequest> {
// Ignore message if it belongs to a terminated fetch // Ignore message if it belongs to a terminated fetch
return_if_fetch_was_terminated!(); return_if_fetch_was_terminated!();
// Ignore messages coming from previously-errored responses // Ignore messages coming from previously-errored responses or requests that have timed out
if self.response_status.get().is_err() { if self.response_status.get().is_err() {
return; return;
} }
@ -1134,6 +1118,8 @@ impl<'a> PrivateXMLHttpRequestHelpers for JSRef<'a, XMLHttpRequest> {
self.ready_state.get() == XMLHttpRequestState::Loading || self.ready_state.get() == XMLHttpRequestState::Loading ||
self.sync.get()); self.sync.get());
self.cancel_timeout();
// Part of step 11, send() (processing response end of file) // Part of step 11, send() (processing response end of file)
// XXXManishearth handle errors, if any (substep 2) // XXXManishearth handle errors, if any (substep 2)
@ -1149,7 +1135,9 @@ impl<'a> PrivateXMLHttpRequestHelpers for JSRef<'a, XMLHttpRequest> {
self.dispatch_response_progress_event("loadend".to_owned()); self.dispatch_response_progress_event("loadend".to_owned());
}, },
XHRProgress::Errored(_, e) => { XHRProgress::Errored(_, e) => {
self.response_status.set(Err(())); self.cancel_timeout();
self.discard_subsequent_responses();
self.send_flag.set(false); self.send_flag.set(false);
// XXXManishearth set response to NetworkError // XXXManishearth set response to NetworkError
self.change_ready_state(XMLHttpRequestState::Done); self.change_ready_state(XMLHttpRequestState::Done);
@ -1222,14 +1210,37 @@ impl<'a> PrivateXMLHttpRequestHelpers for JSRef<'a, XMLHttpRequest> {
self.dispatch_progress_event(false, type_, len, total); self.dispatch_progress_event(false, type_, len, total);
} }
fn set_timeout(self, timeout: u32) { fn set_timeout(self, timeout: u32) {
struct XHRTimeout {
xhr: TrustedXHRAddress,
gen_id: GenerationId,
}
impl Runnable for XHRTimeout {
fn handler(self: Box<XHRTimeout>) {
let this = *self;
let xhr = this.xhr.to_temporary().root();
if xhr.r().ready_state.get() != XMLHttpRequestState::Done {
xhr.r().process_partial_response(XHRProgress::Errored(this.gen_id, Timeout));
}
}
}
// Sets up the object to timeout in a given number of milliseconds // Sets up the object to timeout in a given number of milliseconds
// This will cancel all previous timeouts // This will cancel all previous timeouts
let oneshot = self.timer.borrow_mut() let oneshot = self.timer.borrow_mut()
.oneshot(Duration::milliseconds(timeout as i64)); .oneshot(Duration::milliseconds(timeout as i64));
let terminate_sender = (*self.terminate_sender.borrow()).clone(); let terminate_sender = (*self.terminate_sender.borrow()).clone();
let global = self.global.root();
let script_chan = global.r().script_chan();
let xhr = Trusted::new(global.r().get_cx(), self, global.r().script_chan());
let gen_id = self.generation_id.get();
spawn_named("XHR:Timer".to_owned(), move || { spawn_named("XHR:Timer".to_owned(), move || {
match oneshot.recv() { match oneshot.recv() {
Ok(_) => { Ok(_) => {
script_chan.send(ScriptMsg::RunnableMsg(box XHRTimeout {
xhr: xhr,
gen_id: gen_id,
})).unwrap();
terminate_sender.map(|s| s.send(TerminateReason::TimedOut)); terminate_sender.map(|s| s.send(TerminateReason::TimedOut));
}, },
Err(_) => { Err(_) => {
@ -1297,6 +1308,10 @@ impl<'a> PrivateXMLHttpRequestHelpers for JSRef<'a, XMLHttpRequest> {
// XXXManishearth additional CORS filtering goes here // XXXManishearth additional CORS filtering goes here
headers headers
} }
fn discard_subsequent_responses(self) {
self.response_status.set(Err(()));
}
} }
trait Extractable { trait Extractable {