Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement async fetching of extenal script sources via interruptible parsing. #5197

Closed
wants to merge 14 commits into from

Make async XMLHttpRequest requests use async network events.

  • Loading branch information
jdm committed Mar 5, 2015
commit ef67d27a0b30bdacb104fdc1d185b359675688f1
@@ -51,14 +51,33 @@ pub fn global_init() {
}
}

#[must_use]
pub enum AsyncResponseResult {
ContinueNormalResponse,
AbortResponse,
}

pub struct ListenerWrapper(pub Box<for<'r> Invoke<(&'r (AsyncResponseListener+'r))> + Send>);

impl ListenerWrapper {
fn new<F>(f: Box<F>) -> ListenerWrapper
where F: for <'r> FnOnce(&'r (AsyncResponseListener+'r)) + Send {
ListenerWrapper(f)
}

pub fn invoke(self, listener: &AsyncResponseListener) {
(self.0).invoke(listener)
}
}

pub trait AsyncResponseListener {
fn headers_available(&self, metadata: Metadata);
fn headers_available(&self, metadata: Metadata) -> AsyncResponseResult;
fn data_available(&self, payload: Vec<u8>);
fn response_complete(&self, status: Result<(), String>);
}

pub trait AsyncResponseTarget {
fn invoke_with_listener<F>(&self, f: F) where F: FnOnce(&AsyncResponseListener);
fn invoke_with_listener(&self, listener: ListenerWrapper);
}

pub enum ControlMsg {
@@ -210,12 +229,12 @@ impl ProgressSender {
match *self {
ProgressSender::Channel(ref c) => c.send(msg).map_err(|_| ()),
ProgressSender::Listener(ref b) => {
b.invoke_with_listener(move |listener| {
b.invoke_with_listener(ListenerWrapper::new(box move |listener: &AsyncResponseListener| {
match msg {
ProgressMsg::Payload(buf) => listener.data_available(buf),
ProgressMsg::Done(status) => listener.response_complete(status),
}
});
}));
Ok(())
}
}
@@ -254,9 +273,9 @@ pub fn start_sending_opt(senders: ResponseSenders, metadata: Metadata) -> Result
}
}
ResponseSenders::Listener(target) => {
target.invoke_with_listener(move |listener| {
target.invoke_with_listener(ListenerWrapper(box move |listener: &AsyncResponseListener| {
listener.headers_available(metadata);
});
}));
Ok(ProgressSender::Listener(target))
}
}
@@ -10,6 +10,8 @@
//! with CORSRequest being expanded into FetchRequest (etc)

use std::ascii::AsciiExt;
use std::borrow::ToOwned;
use std::thunk::Invoke;
use time;
use time::{now, Timespec};

@@ -24,6 +26,28 @@ use hyper::method::Method;
use hyper::status::StatusClass::Success;

use url::{SchemeData, Url};
use util::task::spawn_named;

pub trait AsyncCORSResponseListener {
fn response_available(&self, response: CORSResponse);
}

pub trait AsyncCORSResponseTarget {
fn invoke_with_listener(&self, listener: CORSListenerWrapper);
}

pub struct CORSListenerWrapper(pub Box<for<'r> Invoke<(&'r (AsyncCORSResponseListener+'r))> + Send>);

impl CORSListenerWrapper {
fn new<F>(f: Box<F>) -> CORSListenerWrapper
where F: for <'r> FnOnce(&'r (AsyncCORSResponseListener+'r)) + Send {
CORSListenerWrapper(f)
}

pub fn invoke(self, listener: &AsyncCORSResponseListener) {
(self.0).invoke(listener)
}
}

#[derive(Clone)]
pub struct CORSRequest {
@@ -88,6 +112,18 @@ impl CORSRequest {
}
}

pub fn http_fetch_async(&self, listener: Box<AsyncCORSResponseTarget + Send>) {
// TODO: this exists only to make preflight check non-blocking
// perhaps should be handled by the resource task?
let req = self.clone();
spawn_named("cors".to_owned(), move || {
let response = req.http_fetch();
listener.invoke_with_listener(CORSListenerWrapper::new(box move |listener: &AsyncCORSResponseListener| {
listener.response_available(response);
}));
});
}

/// http://fetch.spec.whatwg.org/#concept-http-fetch
/// This method assumes that the CORS flag is set
/// This does not perform the full HTTP fetch, rather it handles part of the CORS filtering
@@ -16,6 +16,7 @@ use std::cell::{BorrowState, RefCell, Ref, RefMut};
///
/// This extends the API of `core::cell::RefCell` to allow unsafe access in
/// certain situations, with dynamic checking in debug builds.
#[derive(Clone)]
pub struct DOMRefCell<T> {
value: RefCell<T>,
}
@@ -179,6 +179,16 @@ impl<T: JSTraceable> JSTraceable for Option<T> {
}
}

impl<T: JSTraceable, U: JSTraceable> JSTraceable for Result<T, U> {
#[inline]
fn trace(&self, trc: *mut JSTracer) {
match *self {
Ok(ref inner) => inner.trace(trc),
Err(ref inner) => inner.trace(trc),
}
}
}

impl<K,V,S> JSTraceable for HashMap<K, V, S>
where K: Hash<<S as HashState>::Hasher> + Eq + JSTraceable,
V: JSTraceable,
@@ -262,3 +272,9 @@ impl JSTraceable for Box<LayoutRPC+'static> {
// Do nothing
}
}

impl JSTraceable for () {
#[inline]
fn trace(&self, trc: *mut JSTracer) {
}
}
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.