diff --git a/components/net/resource_thread.rs b/components/net/resource_thread.rs index b85532b22f1..95d360c62a6 100644 --- a/components/net/resource_thread.rs +++ b/components/net/resource_thread.rs @@ -27,7 +27,7 @@ use net_traits::{AsyncResponseTarget, Metadata, ProgressMsg, ResponseAction, Cor use net_traits::{CoreResourceMsg, CookieSource, FetchResponseMsg, LoadConsumer}; use net_traits::{LoadData, LoadResponse, NetworkError, ResourceId}; use net_traits::{WebSocketCommunicate, WebSocketConnectData, ResourceThreads}; -use net_traits::request::{Referer, Request}; +use net_traits::request::{Request, RequestInit}; use profile_traits::time::ProfilerChan; use rustc_serialize::json; use rustc_serialize::{Decodable, Encodable}; @@ -197,8 +197,8 @@ impl ResourceChannelManager { match self.from_client.recv().unwrap() { CoreResourceMsg::Load(load_data, consumer, id_sender) => self.resource_manager.load(load_data, consumer, id_sender, control_sender.clone()), - CoreResourceMsg::Fetch(load_data, sender) => - self.resource_manager.fetch(load_data, sender), + CoreResourceMsg::Fetch(init, sender) => + self.resource_manager.fetch(init, sender), CoreResourceMsg::WebsocketConnect(connect, connect_data) => self.resource_manager.websocket_connect(connect, connect_data), CoreResourceMsg::SetCookiesForUrl(request, cookie_list, source) => @@ -486,30 +486,13 @@ impl CoreResourceManager { cancel_listener)); } - fn fetch(&self, load_data: LoadData, sender: IpcSender) { - spawn_named(format!("fetch thread for {}", load_data.url), move || { - let mut request = Request::new(load_data.url, - None, false); - // todo handle origin - // todo consider replacing LoadData with a direct mapping - // to a subset of Request - // todo set is_service_worker_global_scope - *request.method.borrow_mut() = load_data.method; - *request.headers.borrow_mut() = load_data.headers; - *request.body.borrow_mut() = load_data.data.clone(); - if let Some(cors) = load_data.cors { - request.use_cors_preflight = cors.preflight; - } + fn fetch(&self, init: RequestInit, sender: IpcSender) { + spawn_named(format!("fetch thread for {}", init.url), move || { + let request = Request::from_init(init); // XXXManishearth: Check origin against pipeline id - request.use_url_credentials = load_data.credentials_flag; // todo load context / mimesniff in fetch // todo referrer policy? - if let Some(referer) = load_data.referrer_url { - request.referer = Referer::RefererUrl(referer); - } // todo worker stuff - - fetch(Rc::new(request), Some(Box::new(sender))); }) diff --git a/components/net_traits/lib.rs b/components/net_traits/lib.rs index 4760797cc2f..92251bf77d5 100644 --- a/components/net_traits/lib.rs +++ b/components/net_traits/lib.rs @@ -196,18 +196,22 @@ pub trait FetchResponseListener { impl FetchTaskTarget for IpcSender { fn process_request_body(&mut self, _: &request::Request) { + println!("PRqB"); let _ = self.send(FetchResponseMsg::ProcessRequestBody); } fn process_request_eof(&mut self, _: &request::Request) { + println!("PRqE"); let _ = self.send(FetchResponseMsg::ProcessRequestEOF); } fn process_response(&mut self, response: &response::Response) { + println!("PR"); let _ = self.send(FetchResponseMsg::ProcessResponse(response.metadata())); } fn process_response_eof(&mut self, response: &response::Response) { + println!("PRE"); if response.is_network_error() { // todo: finer grained errors let _ = self.send(FetchResponseMsg::ProcessResponse(Err(NetworkError::Internal("Network error".into())))); @@ -412,7 +416,7 @@ pub struct WebSocketConnectData { pub enum CoreResourceMsg { /// Request the data associated with a particular URL Load(LoadData, LoadConsumer, Option>), - Fetch(LoadData, IpcSender), + Fetch(request::RequestInit, IpcSender), /// Try to make a websocket connection to a URL. WebsocketConnect(WebSocketCommunicate, WebSocketConnectData), /// Store a set of cookies for a given originating URL diff --git a/components/net_traits/request.rs b/components/net_traits/request.rs index 0aa5417b3ba..70ac600bb25 100644 --- a/components/net_traits/request.rs +++ b/components/net_traits/request.rs @@ -25,7 +25,7 @@ pub enum Type { } /// A request [destination](https://fetch.spec.whatwg.org/#concept-request-destination) -#[derive(Copy, Clone, PartialEq)] +#[derive(Copy, Clone, PartialEq, Serialize, Deserialize)] pub enum Destination { None, Document, Embed, Font, Image, Manifest, Media, Object, Report, Script, ServiceWorker, @@ -49,7 +49,7 @@ pub enum Referer { } /// A [request mode](https://fetch.spec.whatwg.org/#concept-request-mode) -#[derive(Copy, Clone, PartialEq)] +#[derive(Copy, Clone, PartialEq, Serialize, Deserialize)] pub enum RequestMode { Navigate, SameOrigin, @@ -58,7 +58,7 @@ pub enum RequestMode { } /// Request [credentials mode](https://fetch.spec.whatwg.org/#concept-request-credentials-mode) -#[derive(Copy, Clone, PartialEq)] +#[derive(Copy, Clone, PartialEq, Serialize, Deserialize)] pub enum CredentialsMode { Omit, CredentialsSameOrigin, @@ -107,6 +107,26 @@ pub enum CORSSettings { UseCredentials } +#[derive(Serialize, Deserialize, Clone)] +pub struct RequestInit { + pub method: Method, + pub url: Url, + pub headers: Headers, + pub unsafe_request: bool, + pub same_origin_data: bool, + pub body: Option>, + // TODO: cleint object + pub destination: Destination, + pub synchronous: bool, + pub mode: RequestMode, + pub use_cors_preflight: bool, + pub credentials_mode: CredentialsMode, + pub use_url_credentials: bool, + // this should actually be set by fetch, but fetch + // doesn't have info about the client right now + pub origin: Url, +} + /// A [Request](https://fetch.spec.whatwg.org/#requests) as defined by the Fetch spec #[derive(Clone)] pub struct Request { @@ -186,6 +206,23 @@ impl Request { } } + pub fn from_init(init: RequestInit) -> Request { + let mut req = Request::new(init.url, None, false); + *req.method.borrow_mut() = init.method; + *req.headers.borrow_mut() = init.headers; + req.unsafe_request = init.unsafe_request; + req.same_origin_data.set(init.same_origin_data); + *req.body.borrow_mut() = init.body; + req.destination = init.destination; + req.synchronous = init.synchronous; + req.mode = init.mode; + req.use_cors_preflight = init.use_cors_preflight; + req.credentials_mode = init.credentials_mode; + req.use_url_credentials = init.use_url_credentials; + *req.origin.borrow_mut() = Origin::Origin(init.origin.origin()); + req + } + /// https://html.spec.whatwg.org/multipage/#create-a-potential-cors-request pub fn potential_cors_request(url: Url, cors_attribute_state: Option, diff --git a/components/script/dom/xmlhttprequest.rs b/components/script/dom/xmlhttprequest.rs index 400549dc714..7239ae5a745 100644 --- a/components/script/dom/xmlhttprequest.rs +++ b/components/script/dom/xmlhttprequest.rs @@ -33,7 +33,7 @@ use encoding::label::encoding_from_whatwg_label; use encoding::types::{DecoderTrap, EncoderTrap, Encoding, EncodingRef}; use euclid::length::Length; use hyper::header::Headers; -use hyper::header::{Accept, ContentLength, ContentType, qitem}; +use hyper::header::{ContentLength, ContentType}; use hyper::http::RawStatus; use hyper::method::Method; use hyper::mime::{self, Mime}; @@ -46,7 +46,8 @@ use msg::constellation_msg::{PipelineId, ReferrerPolicy}; use net_traits::CoreResourceMsg::Fetch; use net_traits::trim_http_whitespace; use net_traits::{FetchResponseListener, Metadata, NetworkError, RequestSource}; -use net_traits::{LoadContext, LoadData, CoreResourceThread, LoadOrigin}; +use net_traits::{CoreResourceThread, LoadOrigin}; +use net_traits::request::{CredentialsMode, Destination, RequestInit, RequestMode, Origin}; use network_listener::{NetworkListener, PreInvoke}; use parse::html::{ParseContext, parse_html}; use parse::xml::{self, parse_xml}; @@ -138,7 +139,6 @@ pub struct XMLHttpRequest { request_body_len: Cell, sync: Cell, upload_complete: Cell, - upload_events: Cell, send_flag: Cell, timeout_cancel: DOMRefCell>, @@ -183,7 +183,6 @@ impl XMLHttpRequest { request_body_len: Cell::new(0), sync: Cell::new(false), upload_complete: Cell::new(false), - upload_events: Cell::new(false), send_flag: Cell::new(false), timeout_cancel: DOMRefCell::new(None), @@ -215,7 +214,7 @@ impl XMLHttpRequest { fn initiate_async_xhr(context: Arc>, script_chan: Box, core_resource_thread: CoreResourceThread, - load_data: LoadData) { + init: RequestInit) { impl FetchResponseListener for XHRContext { fn process_request_body(&mut self) { // todo @@ -262,9 +261,10 @@ impl XMLHttpRequest { script_chan: script_chan, }; ROUTER.add_route(action_receiver.to_opaque(), box move |message| { + println!("routing"); listener.notify_fetch(message.to().unwrap()); }); - core_resource_thread.send(Fetch(load_data, action_sender)).unwrap(); + core_resource_thread.send(Fetch(init, action_sender)).unwrap(); } } @@ -527,8 +527,10 @@ impl XMLHttpRequestMethods for XMLHttpRequest { let extracted = data.as_ref().map(|d| d.extract()); self.request_body_len.set(extracted.as_ref().map_or(0, |e| e.0.len())); + // todo preserved headers? + // Step 6 - self.upload_events.set(false); + self.upload_complete.set(false); // Step 7 self.upload_complete.set(match extracted { None => true, @@ -540,11 +542,6 @@ impl XMLHttpRequestMethods for XMLHttpRequest { // Step 9 if !self.sync.get() { - let event_target = self.upload.upcast::(); - if event_target.has_handlers() { - self.upload_events.set(true); - } - // If one of the event handlers below aborts the fetch by calling // abort or open we will need the current generation id to detect it. // Substep 1 @@ -564,46 +561,50 @@ impl XMLHttpRequestMethods for XMLHttpRequest { } // Step 5 - let global = self.global(); - - let mut load_data = - LoadData::new(LoadContext::Browsing, - self.request_url.borrow().clone().unwrap(), - self); - - if load_data.url.origin().ne(&global.r().get_url().origin()) { - load_data.credentials_flag = self.WithCredentials(); - } - load_data.data = extracted.as_ref().map(|e| e.0.clone()); - + //TODO - set referrer_policy/referrer_url in request + let has_handlers = self.upload.upcast::().has_handlers(); + let credentials_mode = if self.with_credentials.get() { + CredentialsMode::Include + } else { + CredentialsMode::CredentialsSameOrigin + }; + let use_url_credentials = if let Some(ref url) = *self.request_url.borrow() { + url.username().len() != 0 || url.password().is_some() + } else { + unreachable!() + }; + let mut request = RequestInit { + method: self.request_method.borrow().clone(), + url: self.request_url.borrow().clone().unwrap(), + headers: (*self.request_headers.borrow()).clone(), + unsafe_request: true, + same_origin_data: true, + // XXXManishearth figure out how to avoid this clone + body: extracted.as_ref().map(|e| e.0.clone()), + // XXXManishearth actually "subresource", but it doesn't exist + // https://github.com/whatwg/xhr/issues/71 + destination: Destination::None, + synchronous: self.sync.get(), + mode: RequestMode::CORSMode, + use_cors_preflight: has_handlers, + credentials_mode: credentials_mode, + use_url_credentials: use_url_credentials, + origin: self.global().r().get_url(), + }; // XHR spec differs from http, and says UTF-8 should be in capitals, // instead of "utf-8", which is what Hyper defaults to. So not // using content types provided by Hyper. let n = "content-type"; match extracted { Some((_, Some(ref content_type))) => - load_data.headers.set_raw(n.to_owned(), vec![content_type.bytes().collect()]), + request.headers.set_raw(n.to_owned(), vec![content_type.bytes().collect()]), _ => (), } - load_data.preserved_headers = (*self.request_headers.borrow()).clone(); - - if !load_data.preserved_headers.has::() { - let mime = Mime(mime::TopLevel::Star, mime::SubLevel::Star, vec![]); - load_data.preserved_headers.set(Accept(vec![qitem(mime)])); - } - - load_data.method = (*self.request_method.borrow()).clone(); - - // CORS stuff - let global = self.global(); - let mut combined_headers = load_data.headers.clone(); - combined_headers.extend(load_data.preserved_headers.iter()); - debug!("request_headers = {:?}", *self.request_headers.borrow()); self.fetch_time.set(time::now().to_timespec().sec); - let rv = self.fetch(load_data, global.r()); + let rv = self.fetch(request, self.global().r()); // Step 10 if self.sync.get() { return rv; @@ -1230,7 +1231,7 @@ impl XMLHttpRequest { } fn fetch(&self, - load_data: LoadData, + init: RequestInit, global: GlobalRef) -> ErrorResult { let xhr = Trusted::new(self); @@ -1251,7 +1252,7 @@ impl XMLHttpRequest { let core_resource_thread = global.core_resource_thread(); XMLHttpRequest::initiate_async_xhr(context.clone(), script_chan, - core_resource_thread, load_data); + core_resource_thread, init); if let Some(script_port) = script_port { loop {