1 use webapi::event_target::{IEventTarget, EventTarget}; 2 use webapi::dom_exception::{InvalidAccessError, InvalidStateError}; 3 use webcore::unsafe_typed_array::UnsafeTypedArray; 4 use webcore::value::{ 5 Reference, 6 Value, 7 }; 8 use webcore::try_from::{TryFrom, TryInto}; 9 use private::TODO; 10 11 /// Use XmlHttpRequest (XHR) objects to interact with servers. 12 /// You can retrieve data from a URL without having to do a full page refresh. 13 /// This enables a Web page to update just part of a page without disrupting 14 /// what the user is doing. XmlHttpRequest is used heavily in Ajax programming. 15 /// 16 /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/XmlHttpRequest) 17 // https://xhr.spec.whatwg.org/#xmlhttprequest 18 #[derive(Clone, Debug, PartialEq, Eq, ReferenceType)] 19 #[reference(instance_of = "XMLHttpRequest")] 20 #[reference(subclass_of(EventTarget))] 21 pub struct XmlHttpRequest( Reference ); 22 23 /// An enum indicating the state of the `XmlHttpRequest`. 24 /// 25 /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/readyState) 26 // https://xhr.spec.whatwg.org/#dom-xmlhttprequest-readystate 27 #[derive(Copy, Clone, PartialEq, Eq, Debug)] 28 pub enum XhrReadyState { 29 /// Client has been created. [open()](struct.XmlHttpRequest.html#method.open) not called yet. 30 Unsent, 31 /// [open()](struct.XmlHttpRequest.html#method.open) has been called. 32 Opened, 33 /// [send()](struct.XmlHttpRequest.html#method.send) has been called, and headers and [status()](struct.XmlHttpRequest.html#method.status) are available. 34 HeadersReceived, 35 /// Downloading; [reponse_text()](struct.XmlHttpRequest.html#method.reponse_text) holds partial data. 36 Loading, 37 /// The operation is complete. 38 Done, 39 } 40 41 /// An enum describing the type of the response to `XmlHttpRequest` 42 /// 43 /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/responseType) 44 // https://xhr.spec.whatwg.org/#dom-xmlhttprequest-responsetype 45 #[derive(Copy, Clone, PartialEq, Eq, Debug)] 46 pub enum XhrResponseType { 47 /// A JavaScript ArrayBuffer containing binary data 48 ArrayBuffer, 49 /// A Blob object container the binary data 50 Blob, 51 /// An HTML Document or XML XMLDocument 52 Document, 53 /// A JavaScript object parsed from JSON 54 Json, 55 /// Text in a String object 56 Text 57 } 58 59 impl IEventTarget for XmlHttpRequest {} 60 61 error_enum_boilerplate! { 62 /// An error returned from `XmlHttpRequest::set_response_type` 63 XhrSetResponseTypeError, 64 65 #[allow(missing_docs)] 66 InvalidStateError, 67 #[allow(missing_docs)] 68 InvalidAccessError 69 } 70 71 impl XmlHttpRequest { 72 /// Creates new `XmlHttpRequest`. 73 // https://xhr.spec.whatwg.org/#ref-for-dom-xmlhttprequest new() -> XmlHttpRequest74 pub fn new() -> XmlHttpRequest { 75 js!( return new XMLHttpRequest(); ).try_into().unwrap() 76 } 77 78 /// Returns the current state of the request as a [XhrReadyState](enum.XhrReadyState.html). 79 /// 80 /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/readyState) 81 // https://xhr.spec.whatwg.org/#ref-for-dom-xmlhttprequest-readystate ready_state(&self) -> XhrReadyState82 pub fn ready_state(&self) -> XhrReadyState { 83 use self::XhrReadyState::*; 84 let state: u16 = js!( return @{self}.readyState; ).try_into().unwrap(); 85 match state { 86 0 => Unsent, 87 1 => Opened, 88 2 => HeadersReceived, 89 3 => Loading, 90 4 => Done, 91 _ => unreachable!( "Unexpected value of XMLHttpRequest::readyState: {}", state ) 92 } 93 } 94 95 /// Returns the type of the request as a [XhrResponseType](enum.XhrResponseType.html) 96 /// 97 /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/responseType) 98 // https://xhr.spec.whatwg.org/#ref-for-dom-xmlhttprequest-responsetype response_type(&self) -> XhrResponseType99 pub fn response_type(&self) -> XhrResponseType { 100 use self::XhrResponseType::*; 101 let repsonse_type: String = js! ( return @{self}.responseType; ).try_into().unwrap(); 102 match repsonse_type.as_str() { 103 "arraybuffer" => ArrayBuffer, 104 "blob" => Blob, 105 "document" => Document, 106 "json" => Json, 107 "text" | "" => Text, 108 x => unreachable!( "Unexpected value of XMLHttpRequest::responseType:: {}", x) 109 } 110 } 111 112 /// Set the type that the XmlHttpRequest should return 113 /// 114 /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/responseType) 115 // https://xhr.spec.whatwg.org/#ref-for-dom-xmlhttprequest-responsetype set_response_type(&self, kind: XhrResponseType) -> Result<(), XhrSetResponseTypeError>116 pub fn set_response_type(&self, kind: XhrResponseType) -> Result<(), XhrSetResponseTypeError> { 117 use self::XhrResponseType::*; 118 let response_type = match kind { 119 ArrayBuffer => "arraybuffer", 120 Blob => "blob", 121 Document => "document", 122 Json => "json", 123 Text => "text" 124 }; 125 126 js_try!( 127 @{self}.responseType = @{response_type}; 128 ).unwrap() 129 } 130 131 /// Returns a string that contains the response to the request as text, or None 132 /// if the request was unsuccessful or has not yet been sent. 133 /// 134 ///[(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/responseText) 135 // https://xhr.spec.whatwg.org/#ref-for-dom-xmlhttprequest-responsetext response_text(&self) -> Result< Option< String >, TODO >136 pub fn response_text(&self) -> Result< Option< String >, TODO > { 137 let response = js!(return @{self}.responseText;); 138 match response { 139 Value::Null => Ok( None ), 140 Value::String( resp ) => Ok( Some( resp ) ), 141 _ => unreachable!(), 142 } 143 } 144 145 /// Returns the object representing the response 146 /// 147 ///[(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/response) 148 // https://xhr.spec.whatwg.org/#ref-for-dom-xmlhttprequest-response raw_response(&self) -> Value149 pub fn raw_response(&self) -> Value { 150 js!(return @{self}.response;) 151 } 152 153 /// Returns an unsigned short with the status of the response of the request. 154 /// 155 /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/status) 156 // https://xhr.spec.whatwg.org/#ref-for-dom-xmlhttprequest-status status(&self) -> u16157 pub fn status(&self) -> u16 { 158 js!(return @{self}.status;).try_into().unwrap() 159 } 160 161 /// Open connection with given method (ie GET or POST), and the url to hit. 162 /// 163 /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/open) 164 // https://xhr.spec.whatwg.org/#ref-for-dom-xmlhttprequest-open open(&self, method: &str, url: &str) -> Result< (), TODO >165 pub fn open(&self, method: &str, url: &str) -> Result< (), TODO > { 166 js! { @(no_return) 167 @{self}.open(@{method}, @{url}, true); 168 }; 169 170 Ok(()) 171 } 172 173 /// Returns the string containing the text of the specified header. If there 174 /// are multiple response headers with the same name, then their values are 175 /// returned as a single concatenated string. 176 /// 177 /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/getResponseHeader) 178 // https://xhr.spec.whatwg.org/#ref-for-dom-xmlhttprequest-getresponseheader get_response_header(&self, header: &str) -> Option<String>179 pub fn get_response_header(&self, header: &str) -> Option<String> { 180 let header = js!( return @{self}.getResponseHeader(@{header}); ); 181 match header { 182 Value::Null => None, 183 Value::String(text) => Some(text), 184 _ => unreachable!(), 185 } 186 } 187 188 /// Sets the value of an HTTP request header. Must be called after `open()`, 189 /// but before `send()`. If this method is called several times with the same 190 /// header, the values are merged into one single request header. 191 /// 192 /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/setRequestHeader) 193 // https://xhr.spec.whatwg.org/#ref-for-dom-xmlhttprequest-setrequestheader set_request_header(&self, header: &str, value: &str) -> Result< (), TODO >194 pub fn set_request_header(&self, header: &str, value: &str) -> Result< (), TODO > { 195 js! { @(no_return) 196 @{self}.setRequestHeader(@{header}, @{value}); 197 }; 198 199 Ok(()) 200 } 201 202 /// Send request on an open connection with no data 203 /// 204 /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/send) 205 // https://xhr.spec.whatwg.org/#ref-for-dom-xmlhttprequest-send send(&self) -> Result< (), TODO >206 pub fn send(&self) -> Result< (), TODO > { 207 js! { @(no_return) 208 @{self}.send(); 209 }; 210 211 Ok(()) 212 } 213 214 /// Send request on an open connection with string body 215 /// 216 /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/send) 217 // https://xhr.spec.whatwg.org/#ref-for-dom-xmlhttprequest-send send_with_string(&self, body: &str) -> Result< (), TODO >218 pub fn send_with_string(&self, body: &str) -> Result< (), TODO > { 219 js! { @(no_return) 220 @{self}.send(@{body}); 221 }; 222 223 Ok(()) 224 } 225 226 /// Send request on an open connection with a byte array body 227 /// 228 /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/send) 229 // https://xhr.spec.whatwg.org/#ref-for-dom-xmlhttprequest-send send_with_bytes(&self, body: &[u8]) -> Result< (), TODO >230 pub fn send_with_bytes(&self, body: &[u8]) -> Result< (), TODO > { 231 js! { @(no_return) 232 @{self}.send(@{UnsafeTypedArray(body)}); 233 }; 234 235 Ok(()) 236 } 237 238 /// Aborts the request if it has already been sent. 239 /// When a request is aborted, its [ready_state](struct.XmlHttpRequest.html#method.ready_state) is changed to [Done](enum.XhrReadyState.html#variant.Done) 240 /// and the [status](struct.XmlHttpRequest.html#method.status) code is set to 241 /// [Unsent](enum.XhrReadyState.html#variant.Unsent). 242 /// 243 /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/abort) 244 // https://xhr.spec.whatwg.org/#ref-for-dom-xmlhttprequest-abort abort(&self)245 pub fn abort(&self) { 246 js! { @(no_return) 247 @{self}.abort(); 248 }; 249 } 250 } 251