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