mirror of
https://github.com/servo/servo.git
synced 2025-06-25 09:34:32 +01:00
Implement sync XHR by creating and spinning on-demand event loops.
This commit is contained in:
parent
2ee21ddbe7
commit
01e66035ff
6 changed files with 269 additions and 156 deletions
|
@ -12,8 +12,8 @@ use dom::bindings::js::{JS, JSRef, Root, Unrooted};
|
||||||
use dom::bindings::utils::{Reflectable, Reflector};
|
use dom::bindings::utils::{Reflectable, Reflector};
|
||||||
use dom::workerglobalscope::{WorkerGlobalScope, WorkerGlobalScopeHelpers};
|
use dom::workerglobalscope::{WorkerGlobalScope, WorkerGlobalScopeHelpers};
|
||||||
use dom::window::{self, WindowHelpers};
|
use dom::window::{self, WindowHelpers};
|
||||||
use script_task::ScriptChan;
|
|
||||||
use devtools_traits::DevtoolsControlChan;
|
use devtools_traits::DevtoolsControlChan;
|
||||||
|
use script_task::{ScriptChan, ScriptPort, ScriptMsg, ScriptTask};
|
||||||
|
|
||||||
use msg::constellation_msg::{PipelineId, WorkerId};
|
use msg::constellation_msg::{PipelineId, WorkerId};
|
||||||
use net_traits::ResourceTask;
|
use net_traits::ResourceTask;
|
||||||
|
@ -129,6 +129,24 @@ impl<'a> GlobalRef<'a> {
|
||||||
GlobalRef::Worker(ref worker) => worker.script_chan(),
|
GlobalRef::Worker(ref worker) => worker.script_chan(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// `ScriptChan` used to send messages to the event loop of this global's
|
||||||
|
/// thread.
|
||||||
|
pub fn new_script_pair(&self) -> (Box<ScriptChan+Send>, Box<ScriptPort+Send>) {
|
||||||
|
match *self {
|
||||||
|
GlobalRef::Window(ref window) => window.new_script_pair(),
|
||||||
|
GlobalRef::Worker(ref worker) => worker.new_script_pair(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Process a single event as if it were the next event in the task queue for
|
||||||
|
/// this global.
|
||||||
|
pub fn process_event(&self, msg: ScriptMsg) {
|
||||||
|
match *self {
|
||||||
|
GlobalRef::Window(_) => ScriptTask::process_event(msg),
|
||||||
|
GlobalRef::Worker(ref worker) => worker.process_event(msg),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Reflectable for GlobalRef<'a> {
|
impl<'a> Reflectable for GlobalRef<'a> {
|
||||||
|
|
|
@ -21,7 +21,7 @@ use dom::messageevent::MessageEvent;
|
||||||
use dom::worker::{TrustedWorkerAddress, WorkerMessageHandler, WorkerEventHandler, WorkerErrorHandler};
|
use dom::worker::{TrustedWorkerAddress, WorkerMessageHandler, WorkerEventHandler, WorkerErrorHandler};
|
||||||
use dom::workerglobalscope::{WorkerGlobalScope, WorkerGlobalScopeHelpers};
|
use dom::workerglobalscope::{WorkerGlobalScope, WorkerGlobalScopeHelpers};
|
||||||
use dom::workerglobalscope::WorkerGlobalScopeTypeId;
|
use dom::workerglobalscope::WorkerGlobalScopeTypeId;
|
||||||
use script_task::{ScriptTask, ScriptChan, ScriptMsg, TimerSource};
|
use script_task::{ScriptTask, ScriptChan, ScriptMsg, TimerSource, ScriptPort};
|
||||||
use script_task::StackRootTLS;
|
use script_task::StackRootTLS;
|
||||||
|
|
||||||
use msg::constellation_msg::PipelineId;
|
use msg::constellation_msg::PipelineId;
|
||||||
|
@ -38,7 +38,7 @@ use js::jsval::JSVal;
|
||||||
use js::rust::Cx;
|
use js::rust::Cx;
|
||||||
|
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::sync::mpsc::{Sender, Receiver};
|
use std::sync::mpsc::{Sender, Receiver, channel};
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
/// A ScriptChan that can be cloned freely and will silently send a TrustedWorkerAddress with
|
/// A ScriptChan that can be cloned freely and will silently send a TrustedWorkerAddress with
|
||||||
|
@ -198,6 +198,8 @@ impl DedicatedWorkerGlobalScope {
|
||||||
pub trait DedicatedWorkerGlobalScopeHelpers {
|
pub trait DedicatedWorkerGlobalScopeHelpers {
|
||||||
fn script_chan(self) -> Box<ScriptChan+Send>;
|
fn script_chan(self) -> Box<ScriptChan+Send>;
|
||||||
fn pipeline(self) -> PipelineId;
|
fn pipeline(self) -> PipelineId;
|
||||||
|
fn new_script_pair(self) -> (Box<ScriptChan+Send>, Box<ScriptPort+Send>);
|
||||||
|
fn process_event(self, msg: ScriptMsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> DedicatedWorkerGlobalScopeHelpers for JSRef<'a, DedicatedWorkerGlobalScope> {
|
impl<'a> DedicatedWorkerGlobalScopeHelpers for JSRef<'a, DedicatedWorkerGlobalScope> {
|
||||||
|
@ -213,6 +215,19 @@ impl<'a> DedicatedWorkerGlobalScopeHelpers for JSRef<'a, DedicatedWorkerGlobalSc
|
||||||
fn pipeline(self) -> PipelineId {
|
fn pipeline(self) -> PipelineId {
|
||||||
self.id
|
self.id
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn new_script_pair(self) -> (Box<ScriptChan+Send>, Box<ScriptPort+Send>) {
|
||||||
|
let (tx, rx) = channel();
|
||||||
|
let chan = box SendableWorkerScriptChan {
|
||||||
|
sender: tx,
|
||||||
|
worker: self.worker.borrow().as_ref().unwrap().clone(),
|
||||||
|
};
|
||||||
|
(chan, box rx)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn process_event(self, msg: ScriptMsg) {
|
||||||
|
self.handle_event(msg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
trait PrivateDedicatedWorkerGlobalScopeHelpers {
|
trait PrivateDedicatedWorkerGlobalScopeHelpers {
|
||||||
|
|
|
@ -29,7 +29,7 @@ use dom::storage::Storage;
|
||||||
use layout_interface::{ReflowGoal, ReflowQueryType, LayoutRPC, LayoutChan, Reflow, Msg};
|
use layout_interface::{ReflowGoal, ReflowQueryType, LayoutRPC, LayoutChan, Reflow, Msg};
|
||||||
use layout_interface::{ContentBoxResponse, ContentBoxesResponse, ScriptReflow};
|
use layout_interface::{ContentBoxResponse, ContentBoxesResponse, ScriptReflow};
|
||||||
use page::Page;
|
use page::Page;
|
||||||
use script_task::{TimerSource, ScriptChan};
|
use script_task::{TimerSource, ScriptChan, ScriptPort, NonWorkerScriptChan};
|
||||||
use script_task::ScriptMsg;
|
use script_task::ScriptMsg;
|
||||||
use script_traits::ScriptControlChan;
|
use script_traits::ScriptControlChan;
|
||||||
use timers::{IsInterval, TimerId, TimerManager, TimerCallback};
|
use timers::{IsInterval, TimerId, TimerManager, TimerCallback};
|
||||||
|
@ -198,6 +198,11 @@ impl Window {
|
||||||
self.parent_info
|
self.parent_info
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn new_script_pair(&self) -> (Box<ScriptChan+Send>, Box<ScriptPort+Send>) {
|
||||||
|
let (tx, rx) = channel();
|
||||||
|
(box NonWorkerScriptChan(tx), box rx)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn control_chan<'a>(&'a self) -> &'a ScriptControlChan {
|
pub fn control_chan<'a>(&'a self) -> &'a ScriptControlChan {
|
||||||
&self.control_chan
|
&self.control_chan
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@ use dom::eventtarget::{EventTarget, EventTargetTypeId};
|
||||||
use dom::workerlocation::WorkerLocation;
|
use dom::workerlocation::WorkerLocation;
|
||||||
use dom::workernavigator::WorkerNavigator;
|
use dom::workernavigator::WorkerNavigator;
|
||||||
use dom::window::{base64_atob, base64_btoa};
|
use dom::window::{base64_atob, base64_btoa};
|
||||||
use script_task::{ScriptChan, TimerSource};
|
use script_task::{ScriptChan, TimerSource, ScriptPort, ScriptMsg};
|
||||||
use timers::{IsInterval, TimerId, TimerManager, TimerCallback};
|
use timers::{IsInterval, TimerId, TimerManager, TimerCallback};
|
||||||
|
|
||||||
use devtools_traits::DevtoolsControlChan;
|
use devtools_traits::DevtoolsControlChan;
|
||||||
|
@ -216,6 +216,8 @@ pub trait WorkerGlobalScopeHelpers {
|
||||||
fn handle_fire_timer(self, timer_id: TimerId);
|
fn handle_fire_timer(self, timer_id: TimerId);
|
||||||
fn script_chan(self) -> Box<ScriptChan+Send>;
|
fn script_chan(self) -> Box<ScriptChan+Send>;
|
||||||
fn pipeline(self) -> PipelineId;
|
fn pipeline(self) -> PipelineId;
|
||||||
|
fn new_script_pair(self) -> (Box<ScriptChan+Send>, Box<ScriptPort+Send>);
|
||||||
|
fn process_event(self, msg: ScriptMsg);
|
||||||
fn get_cx(self) -> *mut JSContext;
|
fn get_cx(self) -> *mut JSContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -238,6 +240,24 @@ impl<'a> WorkerGlobalScopeHelpers for JSRef<'a, WorkerGlobalScope> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn new_script_pair(self) -> (Box<ScriptChan+Send>, Box<ScriptPort+Send>) {
|
||||||
|
let dedicated: Option<JSRef<DedicatedWorkerGlobalScope>> =
|
||||||
|
DedicatedWorkerGlobalScopeCast::to_ref(self);
|
||||||
|
match dedicated {
|
||||||
|
Some(dedicated) => dedicated.new_script_pair(),
|
||||||
|
None => panic!("need to implement creating isolated event loops for SharedWorker"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn process_event(self, msg: ScriptMsg) {
|
||||||
|
let dedicated: Option<JSRef<DedicatedWorkerGlobalScope>> =
|
||||||
|
DedicatedWorkerGlobalScopeCast::to_ref(self);
|
||||||
|
match dedicated {
|
||||||
|
Some(dedicated) => dedicated.process_event(msg),
|
||||||
|
None => panic!("need to implement processing single events for SharedWorker"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn handle_fire_timer(self, timer_id: TimerId) {
|
fn handle_fire_timer(self, timer_id: TimerId) {
|
||||||
self.timers.fire_timer(timer_id, self);
|
self.timers.fire_timer(timer_id, self);
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,7 @@ use dom::urlsearchparams::URLSearchParamsHelpers;
|
||||||
use dom::xmlhttprequesteventtarget::XMLHttpRequestEventTarget;
|
use dom::xmlhttprequesteventtarget::XMLHttpRequestEventTarget;
|
||||||
use dom::xmlhttprequesteventtarget::XMLHttpRequestEventTargetTypeId;
|
use dom::xmlhttprequesteventtarget::XMLHttpRequestEventTargetTypeId;
|
||||||
use dom::xmlhttprequestupload::XMLHttpRequestUpload;
|
use dom::xmlhttprequestupload::XMLHttpRequestUpload;
|
||||||
use script_task::{ScriptChan, ScriptMsg, Runnable};
|
use script_task::{ScriptChan, ScriptMsg, Runnable, ScriptPort};
|
||||||
|
|
||||||
use encoding::all::UTF_8;
|
use encoding::all::UTF_8;
|
||||||
use encoding::label::encoding_from_whatwg_label;
|
use encoding::label::encoding_from_whatwg_label;
|
||||||
|
@ -81,6 +81,16 @@ enum XMLHttpRequestState {
|
||||||
#[jstraceable]
|
#[jstraceable]
|
||||||
pub struct GenerationId(u32);
|
pub struct GenerationId(u32);
|
||||||
|
|
||||||
|
/// Closure of required data for each async network event that comprises the
|
||||||
|
/// XHR's response.
|
||||||
|
struct XHRContext {
|
||||||
|
xhr: TrustedXHRAddress,
|
||||||
|
gen_id: GenerationId,
|
||||||
|
cors_request: Option<CORSRequest>,
|
||||||
|
buf: DOMRefCell<Vec<u8>>,
|
||||||
|
sync_status: DOMRefCell<Option<ErrorResult>>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub enum XHRProgress {
|
pub enum XHRProgress {
|
||||||
/// Notify that headers have been received
|
/// Notify that headers have been received
|
||||||
|
@ -138,6 +148,7 @@ pub struct XMLHttpRequest {
|
||||||
timer: DOMRefCell<Timer>,
|
timer: DOMRefCell<Timer>,
|
||||||
fetch_time: Cell<i64>,
|
fetch_time: Cell<i64>,
|
||||||
terminate_sender: DOMRefCell<Option<Sender<TerminateReason>>>,
|
terminate_sender: DOMRefCell<Option<Sender<TerminateReason>>>,
|
||||||
|
timeout_target: DOMRefCell<Option<Box<ScriptChan+Send>>>,
|
||||||
generation_id: Cell<GenerationId>,
|
generation_id: Cell<GenerationId>,
|
||||||
response_status: Cell<Result<(), ()>>,
|
response_status: Cell<Result<(), ()>>,
|
||||||
}
|
}
|
||||||
|
@ -172,6 +183,7 @@ impl XMLHttpRequest {
|
||||||
timer: DOMRefCell::new(Timer::new().unwrap()),
|
timer: DOMRefCell::new(Timer::new().unwrap()),
|
||||||
fetch_time: Cell::new(0),
|
fetch_time: Cell::new(0),
|
||||||
terminate_sender: DOMRefCell::new(None),
|
terminate_sender: DOMRefCell::new(None),
|
||||||
|
timeout_target: DOMRefCell::new(None),
|
||||||
generation_id: Cell::new(GenerationId(0)),
|
generation_id: Cell::new(GenerationId(0)),
|
||||||
response_status: Cell::new(Ok(())),
|
response_status: Cell::new(Ok(())),
|
||||||
}
|
}
|
||||||
|
@ -187,43 +199,11 @@ impl XMLHttpRequest {
|
||||||
Ok(XMLHttpRequest::new(global))
|
Ok(XMLHttpRequest::new(global))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn handle_progress(addr: TrustedXHRAddress, progress: XHRProgress) {
|
fn check_cors(context: Arc<Mutex<XHRContext>>,
|
||||||
let xhr = addr.to_temporary().root();
|
load_data: LoadData,
|
||||||
xhr.r().process_partial_response(progress);
|
req: CORSRequest,
|
||||||
}
|
script_chan: Box<ScriptChan+Send>,
|
||||||
|
resource_task: ResourceTask) {
|
||||||
#[allow(unsafe_code)]
|
|
||||||
fn fetch2(xhr: TrustedXHRAddress, script_chan: Box<ScriptChan+Send>,
|
|
||||||
resource_task: ResourceTask, load_data: LoadData, sync: bool,
|
|
||||||
cors_request: Result<Option<CORSRequest>,()>, gen_id: GenerationId) {
|
|
||||||
let cors_request = match cors_request {
|
|
||||||
Err(_) => {
|
|
||||||
// Happens in case of cross-origin non-http URIs
|
|
||||||
let xhr = xhr.to_temporary().root();
|
|
||||||
xhr.r().process_partial_response(XHRProgress::Errored(
|
|
||||||
xhr.r().generation_id.get(), Network));
|
|
||||||
return; //XXXjdm Err(Network)
|
|
||||||
}
|
|
||||||
Ok(req) => req,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct XHRContext {
|
|
||||||
xhr: TrustedXHRAddress,
|
|
||||||
gen_id: GenerationId,
|
|
||||||
cors_request: Option<CORSRequest>,
|
|
||||||
buf: DOMRefCell<Vec<u8>>,
|
|
||||||
got_response_complete: Cell<bool>,
|
|
||||||
}
|
|
||||||
|
|
||||||
let context = Arc::new(Mutex::new(XHRContext {
|
|
||||||
xhr: xhr,
|
|
||||||
cors_request: cors_request.clone(),
|
|
||||||
gen_id: gen_id,
|
|
||||||
buf: DOMRefCell::new(vec!()),
|
|
||||||
got_response_complete: Cell::new(false),
|
|
||||||
}));
|
|
||||||
|
|
||||||
if let Some(req) = cors_request {
|
|
||||||
struct CORSContext {
|
struct CORSContext {
|
||||||
xhr: Arc<Mutex<XHRContext>>,
|
xhr: Arc<Mutex<XHRContext>>,
|
||||||
load_data: RefCell<Option<LoadData>>,
|
load_data: RefCell<Option<LoadData>>,
|
||||||
|
@ -235,10 +215,11 @@ 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 {
|
||||||
let context = self.xhr.lock().unwrap();
|
let mut context = self.xhr.lock().unwrap();
|
||||||
let xhr = context.xhr.to_temporary().root();
|
let xhr = context.xhr.to_temporary().root();
|
||||||
xhr.r().process_partial_response(XHRProgress::Errored(context.gen_id, Network));
|
xhr.r().process_partial_response(XHRProgress::Errored(context.gen_id, Network));
|
||||||
return; //XXXjdm Err(Network)
|
*context.sync_status.borrow_mut() = Some(Err(Network));
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut load_data = self.load_data.borrow_mut().take().unwrap();
|
let mut load_data = self.load_data.borrow_mut().take().unwrap();
|
||||||
|
@ -247,7 +228,7 @@ impl XMLHttpRequest {
|
||||||
origin: self.req.origin.clone()
|
origin: self.req.origin.clone()
|
||||||
});
|
});
|
||||||
|
|
||||||
initiate_async_xhr(self.xhr.clone(), self.script_chan.clone(),
|
XMLHttpRequest::initiate_async_xhr(self.xhr.clone(), self.script_chan.clone(),
|
||||||
self.resource_task.clone(), load_data);
|
self.resource_task.clone(), load_data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -280,7 +261,7 @@ impl XMLHttpRequest {
|
||||||
}
|
}
|
||||||
|
|
||||||
let cors_context = Arc::new(Mutex::new(CORSContext {
|
let cors_context = Arc::new(Mutex::new(CORSContext {
|
||||||
xhr: context.clone(),
|
xhr: context,
|
||||||
load_data: RefCell::new(Some(load_data)),
|
load_data: RefCell::new(Some(load_data)),
|
||||||
req: req.clone(),
|
req: req.clone(),
|
||||||
script_chan: script_chan.clone(),
|
script_chan: script_chan.clone(),
|
||||||
|
@ -291,16 +272,21 @@ impl XMLHttpRequest {
|
||||||
context: cors_context,
|
context: cors_context,
|
||||||
script_chan: script_chan
|
script_chan: script_chan
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
initiate_async_xhr(context.clone(), script_chan, resource_task, load_data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn initiate_async_xhr(context: Arc<Mutex<XHRContext>>,
|
||||||
|
script_chan: Box<ScriptChan+Send>,
|
||||||
|
resource_task: ResourceTask,
|
||||||
|
load_data: LoadData) {
|
||||||
impl AsyncResponseListener for XHRContext {
|
impl AsyncResponseListener for XHRContext {
|
||||||
fn headers_available(&self, metadata: Metadata) {
|
fn headers_available(&self, metadata: Metadata) {
|
||||||
let xhr = self.xhr.to_temporary().root();
|
let xhr = self.xhr.to_temporary().root();
|
||||||
let _decision = xhr.r().process_headers_available(self.cors_request.clone(),
|
let rv = xhr.r().process_headers_available(self.cors_request.clone(),
|
||||||
self.gen_id,
|
self.gen_id,
|
||||||
metadata);
|
metadata);
|
||||||
|
if rv.is_err() {
|
||||||
|
*self.sync_status.borrow_mut() = Some(rv);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn data_available(&self, payload: Vec<u8>) {
|
fn data_available(&self, payload: Vec<u8>) {
|
||||||
|
@ -311,8 +297,8 @@ impl XMLHttpRequest {
|
||||||
|
|
||||||
fn response_complete(&self, status: Result<(), String>) {
|
fn response_complete(&self, status: Result<(), String>) {
|
||||||
let xhr = self.xhr.to_temporary().root();
|
let xhr = self.xhr.to_temporary().root();
|
||||||
xhr.r().process_response_complete(self.gen_id, status);
|
let rv = xhr.r().process_response_complete(self.gen_id, status);
|
||||||
self.got_response_complete.set(true);
|
*self.sync_status.borrow_mut() = Some(rv);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -349,10 +335,6 @@ impl XMLHttpRequest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn initiate_async_xhr(context: Arc<Mutex<XHRContext>>,
|
|
||||||
script_chan: Box<ScriptChan+Send>,
|
|
||||||
resource_task: ResourceTask,
|
|
||||||
load_data: LoadData) {
|
|
||||||
let listener = box XHRListener {
|
let listener = box XHRListener {
|
||||||
context: context,
|
context: context,
|
||||||
script_chan: script_chan,
|
script_chan: script_chan,
|
||||||
|
@ -360,14 +342,6 @@ impl XMLHttpRequest {
|
||||||
resource_task.send(Load(load_data, LoadConsumer::Listener(listener))).unwrap();
|
resource_task.send(Load(load_data, LoadConsumer::Listener(listener))).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
if sync {
|
|
||||||
while !context.lock().unwrap().got_response_complete.get() {
|
|
||||||
//TODO: spin the event loop
|
|
||||||
panic!("don't know how to spin the event loop yet");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(unsafe_code)]
|
#[allow(unsafe_code)]
|
||||||
fn fetch(xhr: JSRef<XMLHttpRequest>, resource_task: ResourceTask,
|
fn fetch(xhr: JSRef<XMLHttpRequest>, resource_task: ResourceTask,
|
||||||
mut load_data: LoadData, terminate_receiver: Receiver<TerminateReason>,
|
mut load_data: LoadData, terminate_receiver: Receiver<TerminateReason>,
|
||||||
|
@ -725,8 +699,6 @@ impl<'a> XMLHttpRequestMethods for JSRef<'a, XMLHttpRequest> {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let global = self.global.root();
|
|
||||||
let resource_task = global.r().resource_task();
|
|
||||||
let mut load_data = LoadData::new(self.request_url.borrow().clone().unwrap());
|
let mut load_data = LoadData::new(self.request_url.borrow().clone().unwrap());
|
||||||
load_data.data = extracted;
|
load_data.data = extracted;
|
||||||
|
|
||||||
|
@ -764,6 +736,7 @@ impl<'a> XMLHttpRequestMethods for JSRef<'a, XMLHttpRequest> {
|
||||||
*self.terminate_sender.borrow_mut() = Some(terminate_sender);
|
*self.terminate_sender.borrow_mut() = Some(terminate_sender);
|
||||||
|
|
||||||
// CORS stuff
|
// CORS stuff
|
||||||
|
let global = self.global.root();
|
||||||
let referer_url = self.global.root().r().get_url();
|
let referer_url = self.global.root().r().get_url();
|
||||||
let mode = if self.upload_events.get() {
|
let mode = if self.upload_events.get() {
|
||||||
RequestMode::ForcedPreflight
|
RequestMode::ForcedPreflight
|
||||||
|
@ -794,25 +767,16 @@ impl<'a> XMLHttpRequestMethods for JSRef<'a, XMLHttpRequest> {
|
||||||
|
|
||||||
debug!("request_headers = {:?}", *self.request_headers.borrow());
|
debug!("request_headers = {:?}", *self.request_headers.borrow());
|
||||||
|
|
||||||
let gen_id = self.generation_id.get();
|
|
||||||
if self.sync.get() {
|
|
||||||
return XMLHttpRequest::fetch(self, resource_task, load_data,
|
|
||||||
terminate_receiver, cors_request, gen_id);
|
|
||||||
} else {
|
|
||||||
self.fetch_time.set(time::now().to_timespec().sec);
|
self.fetch_time.set(time::now().to_timespec().sec);
|
||||||
let script_chan = global.r().script_chan();
|
let rv = self.fetch2(load_data, cors_request, global.r());
|
||||||
// Pin the object before launching the fetch task. This is to ensure that
|
if self.sync.get() {
|
||||||
// the object will stay alive as long as there are (possibly cancelled)
|
return rv;
|
||||||
// inflight events queued up in the script task's port.
|
}
|
||||||
let addr = Trusted::new(self.global.root().r().get_cx(), self,
|
|
||||||
script_chan.clone());
|
|
||||||
XMLHttpRequest::fetch2(addr, script_chan, resource_task, load_data, self.sync.get(),
|
|
||||||
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);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -955,7 +919,7 @@ trait PrivateXMLHttpRequestHelpers {
|
||||||
fn process_headers_available(&self, cors_request: Option<CORSRequest>,
|
fn process_headers_available(&self, cors_request: Option<CORSRequest>,
|
||||||
gen_id: GenerationId, metadata: Metadata) -> Result<(), Error>;
|
gen_id: GenerationId, metadata: Metadata) -> Result<(), Error>;
|
||||||
fn process_data_available(self, gen_id: GenerationId, payload: Vec<u8>);
|
fn process_data_available(self, gen_id: GenerationId, payload: Vec<u8>);
|
||||||
fn process_response_complete(self, gen_id: GenerationId, status: Result<(), String>);
|
fn process_response_complete(self, gen_id: GenerationId, status: Result<(), String>) -> ErrorResult;
|
||||||
fn process_partial_response(self, progress: XHRProgress);
|
fn process_partial_response(self, progress: XHRProgress);
|
||||||
fn terminate_ongoing_fetch(self);
|
fn terminate_ongoing_fetch(self);
|
||||||
fn insert_trusted_header(self, name: String, value: String);
|
fn insert_trusted_header(self, name: String, value: String);
|
||||||
|
@ -967,6 +931,8 @@ trait PrivateXMLHttpRequestHelpers {
|
||||||
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);
|
fn discard_subsequent_responses(self);
|
||||||
|
fn fetch2(self, load_data: LoadData, cors_request: Result<Option<CORSRequest>,()>,
|
||||||
|
global: GlobalRef) -> ErrorResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> PrivateXMLHttpRequestHelpers for JSRef<'a, XMLHttpRequest> {
|
impl<'a> PrivateXMLHttpRequestHelpers for JSRef<'a, XMLHttpRequest> {
|
||||||
|
@ -1007,10 +973,17 @@ impl<'a> PrivateXMLHttpRequestHelpers for JSRef<'a, XMLHttpRequest> {
|
||||||
self.process_partial_response(XHRProgress::Loading(gen_id, ByteString::new(payload)));
|
self.process_partial_response(XHRProgress::Loading(gen_id, ByteString::new(payload)));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn process_response_complete(self, gen_id: GenerationId, status: Result<(), String>) {
|
fn process_response_complete(self, gen_id: GenerationId, status: Result<(), String>)
|
||||||
|
-> ErrorResult {
|
||||||
match status {
|
match status {
|
||||||
Ok(()) => self.process_partial_response(XHRProgress::Done(gen_id)),
|
Ok(()) => {
|
||||||
Err(_) => self.process_partial_response(XHRProgress::Errored(gen_id, Network)),
|
self.process_partial_response(XHRProgress::Done(gen_id));
|
||||||
|
Ok(())
|
||||||
|
},
|
||||||
|
Err(_) => {
|
||||||
|
self.process_partial_response(XHRProgress::Errored(gen_id, Network));
|
||||||
|
Err(Network)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1140,6 +1113,7 @@ impl<'a> PrivateXMLHttpRequestHelpers for JSRef<'a, XMLHttpRequest> {
|
||||||
let GenerationId(prev_id) = self.generation_id.get();
|
let GenerationId(prev_id) = self.generation_id.get();
|
||||||
self.generation_id.set(GenerationId(prev_id + 1));
|
self.generation_id.set(GenerationId(prev_id + 1));
|
||||||
self.terminate_sender.borrow().as_ref().map(|s| s.send(TerminateReason::AbortedOrReopened));
|
self.terminate_sender.borrow().as_ref().map(|s| s.send(TerminateReason::AbortedOrReopened));
|
||||||
|
*self.timeout_target.borrow_mut() = None;
|
||||||
self.response_status.set(Ok(()));
|
self.response_status.set(Ok(()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1198,14 +1172,14 @@ impl<'a> PrivateXMLHttpRequestHelpers for JSRef<'a, XMLHttpRequest> {
|
||||||
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 timeout_target = (*self.timeout_target.borrow().as_ref().unwrap()).clone();
|
||||||
let global = self.global.root();
|
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 xhr = Trusted::new(global.r().get_cx(), self, global.r().script_chan());
|
||||||
let gen_id = self.generation_id.get();
|
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 {
|
timeout_target.send(ScriptMsg::RunnableMsg(box XHRTimeout {
|
||||||
xhr: xhr,
|
xhr: xhr,
|
||||||
gen_id: gen_id,
|
gen_id: gen_id,
|
||||||
})).unwrap();
|
})).unwrap();
|
||||||
|
@ -1280,6 +1254,61 @@ impl<'a> PrivateXMLHttpRequestHelpers for JSRef<'a, XMLHttpRequest> {
|
||||||
fn discard_subsequent_responses(self) {
|
fn discard_subsequent_responses(self) {
|
||||||
self.response_status.set(Err(()));
|
self.response_status.set(Err(()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(unsafe_code)]
|
||||||
|
fn fetch2(self,
|
||||||
|
load_data: LoadData,
|
||||||
|
cors_request: Result<Option<CORSRequest>,()>,
|
||||||
|
global: GlobalRef) -> ErrorResult {
|
||||||
|
let cors_request = match cors_request {
|
||||||
|
Err(_) => {
|
||||||
|
// Happens in case of cross-origin non-http URIs
|
||||||
|
self.process_partial_response(XHRProgress::Errored(
|
||||||
|
self.generation_id.get(), Network));
|
||||||
|
return Err(Network);
|
||||||
|
}
|
||||||
|
Ok(req) => req,
|
||||||
|
};
|
||||||
|
|
||||||
|
let xhr = Trusted::new(global.get_cx(), self, global.script_chan());
|
||||||
|
|
||||||
|
let context = Arc::new(Mutex::new(XHRContext {
|
||||||
|
xhr: xhr,
|
||||||
|
cors_request: cors_request.clone(),
|
||||||
|
gen_id: self.generation_id.get(),
|
||||||
|
buf: DOMRefCell::new(vec!()),
|
||||||
|
sync_status: DOMRefCell::new(None),
|
||||||
|
}));
|
||||||
|
|
||||||
|
let (script_chan, script_port) = if self.sync.get() {
|
||||||
|
let (tx, rx) = global.new_script_pair();
|
||||||
|
(tx, Some(rx))
|
||||||
|
} else {
|
||||||
|
(global.script_chan(), None)
|
||||||
|
};
|
||||||
|
*self.timeout_target.borrow_mut() = Some(script_chan.clone());
|
||||||
|
|
||||||
|
let resource_task = global.resource_task();
|
||||||
|
if let Some(req) = cors_request {
|
||||||
|
XMLHttpRequest::check_cors(context.clone(), load_data, req.clone(),
|
||||||
|
script_chan.clone(), resource_task);
|
||||||
|
} else {
|
||||||
|
XMLHttpRequest::initiate_async_xhr(context.clone(), script_chan,
|
||||||
|
resource_task, load_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(script_port) = script_port {
|
||||||
|
loop {
|
||||||
|
global.process_event(script_port.recv());
|
||||||
|
let context = context.lock().unwrap();
|
||||||
|
let sync_status = context.sync_status.borrow();
|
||||||
|
if let Some(ref status) = *sync_status {
|
||||||
|
return status.clone();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
trait Extractable {
|
trait Extractable {
|
||||||
|
|
|
@ -38,6 +38,7 @@ use dom::uievent::UIEvent;
|
||||||
use dom::eventtarget::EventTarget;
|
use dom::eventtarget::EventTarget;
|
||||||
use dom::node::{self, Node, NodeHelpers, NodeDamage, window_from_node};
|
use dom::node::{self, Node, NodeHelpers, NodeDamage, window_from_node};
|
||||||
use dom::window::{Window, WindowHelpers, ScriptHelpers, ReflowReason};
|
use dom::window::{Window, WindowHelpers, ScriptHelpers, ReflowReason};
|
||||||
|
use dom::worker::TrustedWorkerAddress;
|
||||||
use parse::html::{HTMLInput, parse_html};
|
use parse::html::{HTMLInput, parse_html};
|
||||||
use layout_interface::{ScriptLayoutChan, LayoutChan, ReflowGoal, ReflowQueryType};
|
use layout_interface::{ScriptLayoutChan, LayoutChan, ReflowGoal, ReflowQueryType};
|
||||||
use layout_interface;
|
use layout_interface;
|
||||||
|
@ -200,6 +201,22 @@ pub trait ScriptChan {
|
||||||
fn clone(&self) -> Box<ScriptChan+Send>;
|
fn clone(&self) -> Box<ScriptChan+Send>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait ScriptPort {
|
||||||
|
fn recv(&self) -> ScriptMsg;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ScriptPort for Receiver<ScriptMsg> {
|
||||||
|
fn recv(&self) -> ScriptMsg {
|
||||||
|
self.recv().unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ScriptPort for Receiver<(TrustedWorkerAddress, ScriptMsg)> {
|
||||||
|
fn recv(&self) -> ScriptMsg {
|
||||||
|
self.recv().unwrap().1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Encapsulates internal communication within the script task.
|
/// Encapsulates internal communication within the script task.
|
||||||
#[jstraceable]
|
#[jstraceable]
|
||||||
pub struct NonWorkerScriptChan(pub Sender<ScriptMsg>);
|
pub struct NonWorkerScriptChan(pub Sender<ScriptMsg>);
|
||||||
|
@ -403,6 +420,15 @@ unsafe extern "C" fn debug_gc_callback(_rt: *mut JSRuntime, status: JSGCStatus)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ScriptTask {
|
impl ScriptTask {
|
||||||
|
pub fn process_event(msg: ScriptMsg) {
|
||||||
|
SCRIPT_TASK_ROOT.with(|root| {
|
||||||
|
if let Some(script_task) = *root.borrow() {
|
||||||
|
let script_task = unsafe { &*script_task };
|
||||||
|
script_task.handle_msg_from_script(msg);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/// Creates a new script task.
|
/// Creates a new script task.
|
||||||
pub fn new(compositor: Box<ScriptListener+'static>,
|
pub fn new(compositor: Box<ScriptListener+'static>,
|
||||||
port: Receiver<ScriptMsg>,
|
port: Receiver<ScriptMsg>,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue