From 678dc10c4f38d5313262a16f5742036e389471bb Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Fri, 11 Jul 2014 23:44:16 +0530 Subject: [PATCH] Allow URLSearchParams to be passed to XHR Send() --- src/components/net/http_loader.rs | 2 +- src/components/net/resource_task.rs | 2 +- .../script/dom/webidls/XMLHttpRequest.webidl | 5 +- src/components/script/dom/xmlhttprequest.rs | 63 +++++++++++++------ 4 files changed, 51 insertions(+), 21 deletions(-) diff --git a/src/components/net/http_loader.rs b/src/components/net/http_loader.rs index 1d6e95a60b2..2b7ae74970a 100644 --- a/src/components/net/http_loader.rs +++ b/src/components/net/http_loader.rs @@ -78,7 +78,7 @@ fn load(load_data: LoadData, start_chan: Sender) { match load_data.data { Some(ref data) => { writer.headers.content_length = Some(data.len()); - match writer.write(data.clone().into_bytes().as_slice()) { + match writer.write(data.as_slice()) { Err(e) => { send_error(url, e.desc.to_string(), start_chan); return; diff --git a/src/components/net/resource_task.rs b/src/components/net/resource_task.rs index 6489ff65128..409fd1c7acc 100644 --- a/src/components/net/resource_task.rs +++ b/src/components/net/resource_task.rs @@ -33,7 +33,7 @@ pub struct LoadData { pub url: Url, pub method: Method, pub headers: RequestHeaderCollection, - pub data: Option + pub data: Option> } impl LoadData { diff --git a/src/components/script/dom/webidls/XMLHttpRequest.webidl b/src/components/script/dom/webidls/XMLHttpRequest.webidl index 42b657275de..ba100ca23ad 100644 --- a/src/components/script/dom/webidls/XMLHttpRequest.webidl +++ b/src/components/script/dom/webidls/XMLHttpRequest.webidl @@ -13,6 +13,9 @@ * http://www.openwebfoundation.org/legal/the-owf-1-0-agreements/owfa-1-0. */ +// http://fetch.spec.whatwg.org/#fetchbodyinit +typedef (/*ArrayBuffer or ArrayBufferView or Blob or FormData or */DOMString or URLSearchParams) FetchBodyInit; + enum XMLHttpRequestResponseType { "", "arraybuffer", @@ -50,7 +53,7 @@ interface XMLHttpRequest : XMLHttpRequestEventTarget { attribute boolean withCredentials; readonly attribute XMLHttpRequestUpload upload; [Throws] - void send(optional /*(ArrayBufferView or Blob or Document or [EnsureUTF16] */ DOMString/* or FormData or URLSearchParams)*/? data = null); + void send(optional /*Document or*/ FetchBodyInit? data = null); void abort(); // response diff --git a/src/components/script/dom/xmlhttprequest.rs b/src/components/script/dom/xmlhttprequest.rs index afb529426ab..c20feae0437 100644 --- a/src/components/script/dom/xmlhttprequest.rs +++ b/src/components/script/dom/xmlhttprequest.rs @@ -18,13 +18,14 @@ use dom::document::Document; use dom::event::Event; use dom::eventtarget::{EventTarget, EventTargetHelpers, XMLHttpRequestTargetTypeId}; use dom::progressevent::ProgressEvent; +use dom::urlsearchparams::URLSearchParamsHelpers; use dom::window::Window; use dom::xmlhttprequesteventtarget::XMLHttpRequestEventTarget; use dom::xmlhttprequestupload::XMLHttpRequestUpload; use encoding::all::UTF_8; use encoding::label::encoding_from_whatwg_label; -use encoding::types::{DecodeReplace, Encoding}; +use encoding::types::{DecodeReplace, Encoding, EncodeReplace}; use ResponseHeaderCollection = http::headers::response::HeaderCollection; use RequestHeaderCollection = http::headers::request::HeaderCollection; @@ -56,10 +57,9 @@ use std::task::TaskBuilder; use time; use url::Url; -// As send() start accepting more and more parameter types, -// change this to the appropriate type from UnionTypes, eg -// use SendParam = dom::bindings::codegen::UnionTypes::StringOrFormData; -pub type SendParam = DOMString; +use dom::bindings::codegen::UnionTypes::StringOrURLSearchParams::{eString, eURLSearchParams, StringOrURLSearchParams}; +pub type SendParam = StringOrURLSearchParams; + #[deriving(PartialEq,Encodable)] pub enum XMLHttpRequestId { @@ -114,7 +114,7 @@ pub struct XMLHttpRequest { request_method: Untraceable>, request_url: Untraceable>, request_headers: Untraceable>, - request_body: SendParam, + request_body_len: Traceable>, sync: Traceable>, upload_complete: Traceable>, upload_events: Traceable>, @@ -147,7 +147,7 @@ impl XMLHttpRequest { request_method: Untraceable::new(RefCell::new(Get)), request_url: Untraceable::new(RefCell::new(parse_url("", None))), request_headers: Untraceable::new(RefCell::new(RequestHeaderCollection::new())), - request_body: "".to_string(), + request_body_len: Traceable::new(Cell::new(0)), sync: Traceable::new(Cell::new(false)), send_flag: Traceable::new(Cell::new(false)), @@ -241,7 +241,7 @@ pub trait XMLHttpRequestMethods<'a> { fn WithCredentials(&self) -> bool; fn SetWithCredentials(&self, with_credentials: bool); fn Upload(&self) -> Temporary; - fn Send(&self, _data: Option) -> ErrorResult; + fn Send(&self, data: Option) -> ErrorResult; fn Abort(&self); fn ResponseURL(&self) -> DOMString; fn Status(&self) -> u16; @@ -435,7 +435,7 @@ impl<'a> XMLHttpRequestMethods<'a> for JSRef<'a, XMLHttpRequest> { fn Upload(&self) -> Temporary { Temporary::new(self.upload.get()) } - fn Send(&self, data: Option) -> ErrorResult { + fn Send(&self, data: Option) -> ErrorResult { if self.ready_state.deref().get() != Opened || self.send_flag.deref().get() { return Err(InvalidState); // Step 1, 2 } @@ -444,13 +444,15 @@ impl<'a> XMLHttpRequestMethods<'a> for JSRef<'a, XMLHttpRequest> { Get | Head => None, // Step 3 _ => data }; + let extracted = data.map(|d| d.extract()); + self.request_body_len.set(extracted.as_ref().map(|e| e.len()).unwrap_or(0)); // Step 6 self.upload_events.deref().set(false); // Step 7 - self.upload_complete.deref().set(match data { + self.upload_complete.deref().set(match extracted { None => true, - Some (ref s) if s.len() == 0 => true, + Some (ref v) if v.len() == 0 => true, _ => false }); let mut addr = None; @@ -485,16 +487,27 @@ impl<'a> XMLHttpRequestMethods<'a> for JSRef<'a, XMLHttpRequest> { let global = self.global.root(); let resource_task = global.deref().page().resource_task.deref().clone(); let mut load_data = LoadData::new(self.request_url.deref().borrow().clone()); - load_data.data = data; + load_data.data = extracted; // Default headers let request_headers = self.request_headers.deref(); if request_headers.borrow().content_type.is_none() { - request_headers.borrow_mut().content_type = Some(MediaType { - type_: String::from_str("text"), - subtype: String::from_str("plain"), - parameters: vec!((String::from_str("charset"), String::from_str("UTF-8"))) - }); + let parameters = vec!((String::from_str("charset"), String::from_str("UTF-8"))); + request_headers.borrow_mut().content_type = match data { + Some(eString(_)) => + Some(MediaType { + type_: String::from_str("text"), + subtype: String::from_str("plain"), + parameters: parameters + }), + Some(eURLSearchParams(_)) => + Some(MediaType { + type_: String::from_str("application"), + subtype: String::from_str("x-www-form-urlencoded"), + parameters: parameters + }), + None => None + } } if request_headers.borrow().accept.is_none() { @@ -839,7 +852,7 @@ impl<'a> PrivateXMLHttpRequestHelpers for JSRef<'a, XMLHttpRequest> { fn dispatch_upload_progress_event(&self, type_: DOMString, partial_load: Option) { // 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; + let total = self.request_body_len.get() as u64; self.dispatch_progress_event(true, type_, partial_load.unwrap_or(total), Some(total)); } @@ -917,3 +930,17 @@ impl<'a> PrivateXMLHttpRequestHelpers for JSRef<'a, XMLHttpRequest> { headers } } + +trait Extractable { + fn extract(&self) -> Vec; +} +impl Extractable for SendParam { + fn extract(&self) -> Vec { + // http://fetch.spec.whatwg.org/#concept-fetchbodyinit-extract + let encoding = UTF_8 as &Encoding+Send; + match *self { + eString(ref s) => encoding.encode(s.as_slice(), EncodeReplace).unwrap(), + eURLSearchParams(ref usp) => usp.root().serialize(None) // Default encoding is UTF8 + } + } +}