1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4 
5 use body::{BodyOperations, BodyType, consume_body};
6 use dom::bindings::cell::DomRefCell;
7 use dom::bindings::codegen::Bindings::HeadersBinding::{HeadersInit, HeadersMethods};
8 use dom::bindings::codegen::Bindings::RequestBinding;
9 use dom::bindings::codegen::Bindings::RequestBinding::ReferrerPolicy;
10 use dom::bindings::codegen::Bindings::RequestBinding::RequestCache;
11 use dom::bindings::codegen::Bindings::RequestBinding::RequestCredentials;
12 use dom::bindings::codegen::Bindings::RequestBinding::RequestDestination;
13 use dom::bindings::codegen::Bindings::RequestBinding::RequestInfo;
14 use dom::bindings::codegen::Bindings::RequestBinding::RequestInit;
15 use dom::bindings::codegen::Bindings::RequestBinding::RequestMethods;
16 use dom::bindings::codegen::Bindings::RequestBinding::RequestMode;
17 use dom::bindings::codegen::Bindings::RequestBinding::RequestRedirect;
18 use dom::bindings::error::{Error, Fallible};
19 use dom::bindings::reflector::{DomObject, Reflector, reflect_dom_object};
20 use dom::bindings::root::{DomRoot, MutNullableDom};
21 use dom::bindings::str::{ByteString, DOMString, USVString};
22 use dom::bindings::trace::RootedTraceableBox;
23 use dom::globalscope::GlobalScope;
24 use dom::headers::{Guard, Headers};
25 use dom::promise::Promise;
26 use dom::xmlhttprequest::Extractable;
27 use dom_struct::dom_struct;
28 use hyper::method::Method as HttpMethod;
29 use net_traits::ReferrerPolicy as MsgReferrerPolicy;
30 use net_traits::request::{Origin, Window};
31 use net_traits::request::CacheMode as NetTraitsRequestCache;
32 use net_traits::request::CredentialsMode as NetTraitsRequestCredentials;
33 use net_traits::request::Destination as NetTraitsRequestDestination;
34 use net_traits::request::RedirectMode as NetTraitsRequestRedirect;
35 use net_traits::request::Referrer as NetTraitsRequestReferrer;
36 use net_traits::request::Request as NetTraitsRequest;
37 use net_traits::request::RequestMode as NetTraitsRequestMode;
38 use servo_url::ServoUrl;
39 use std::cell::{Cell, Ref};
40 use std::rc::Rc;
41 
42 #[dom_struct]
43 pub struct Request {
44     reflector_: Reflector,
45     request: DomRefCell<NetTraitsRequest>,
46     body_used: Cell<bool>,
47     headers: MutNullableDom<Headers>,
48     mime_type: DomRefCell<Vec<u8>>,
49     #[ignore_malloc_size_of = "Rc"]
50     body_promise: DomRefCell<Option<(Rc<Promise>, BodyType)>>,
51 }
52 
53 impl Request {
new_inherited(global: &GlobalScope, url: ServoUrl) -> Request54     fn new_inherited(global: &GlobalScope,
55                      url: ServoUrl) -> Request {
56         Request {
57             reflector_: Reflector::new(),
58             request: DomRefCell::new(
59                 net_request_from_global(global, url)),
60             body_used: Cell::new(false),
61             headers: Default::default(),
62             mime_type: DomRefCell::new("".to_string().into_bytes()),
63             body_promise: DomRefCell::new(None),
64         }
65     }
66 
new(global: &GlobalScope, url: ServoUrl) -> DomRoot<Request>67     pub fn new(global: &GlobalScope,
68                url: ServoUrl) -> DomRoot<Request> {
69         reflect_dom_object(Box::new(Request::new_inherited(global, url)),
70                            global, RequestBinding::Wrap)
71     }
72 
73     // https://fetch.spec.whatwg.org/#dom-request
Constructor(global: &GlobalScope, input: RequestInfo, init: RootedTraceableBox<RequestInit>) -> Fallible<DomRoot<Request>>74     pub fn Constructor(global: &GlobalScope,
75                        input: RequestInfo,
76                        init: RootedTraceableBox<RequestInit>)
77                        -> Fallible<DomRoot<Request>> {
78         // Step 1
79         let temporary_request: NetTraitsRequest;
80 
81         // Step 2
82         let mut fallback_mode: Option<NetTraitsRequestMode> = None;
83 
84         // Step 3
85         let mut fallback_credentials: Option<NetTraitsRequestCredentials> = None;
86 
87         // Step 4
88         let base_url = global.api_base_url();
89 
90         match input {
91             // Step 5
92             RequestInfo::USVString(USVString(ref usv_string)) => {
93                 // Step 5.1
94                 let parsed_url = base_url.join(&usv_string);
95                 // Step 5.2
96                 if parsed_url.is_err() {
97                     return Err(Error::Type("Url could not be parsed".to_string()))
98                 }
99                 // Step 5.3
100                 let url = parsed_url.unwrap();
101                 if includes_credentials(&url) {
102                     return Err(Error::Type("Url includes credentials".to_string()))
103                 }
104                 // Step 5.4
105                 temporary_request = net_request_from_global(global, url);
106                 // Step 5.5
107                 fallback_mode = Some(NetTraitsRequestMode::CorsMode);
108                 // Step 5.6
109                 fallback_credentials = Some(NetTraitsRequestCredentials::Omit);
110             }
111             // Step 6
112             RequestInfo::Request(ref input_request) => {
113                 // Step 6.1
114                 if request_is_disturbed(input_request) || request_is_locked(input_request) {
115                     return Err(Error::Type("Input is disturbed or locked".to_string()))
116                 }
117                 // Step 6.2
118                 temporary_request = input_request.request.borrow().clone();
119             }
120         }
121 
122         // Step 7
123         // TODO: `entry settings object` is not implemented yet.
124         let origin = base_url.origin();
125 
126         // Step 8
127         let mut window = Window::Client;
128 
129         // Step 9
130         // TODO: `environment settings object` is not implemented in Servo yet.
131 
132         // Step 10
133         if !init.window.handle().is_null_or_undefined() {
134             return Err(Error::Type("Window is present and is not null".to_string()))
135         }
136 
137         // Step 11
138         if !init.window.handle().is_undefined() {
139             window = Window::NoWindow;
140         }
141 
142         // Step 12
143         let mut request: NetTraitsRequest;
144         request = net_request_from_global(global, temporary_request.current_url());
145         request.method = temporary_request.method;
146         request.headers = temporary_request.headers.clone();
147         request.unsafe_request = true;
148         request.window = window;
149         // TODO: `entry settings object` is not implemented in Servo yet.
150         request.origin = Origin::Client;
151         request.referrer = temporary_request.referrer;
152         request.referrer_policy = temporary_request.referrer_policy;
153         request.mode = temporary_request.mode;
154         request.credentials_mode = temporary_request.credentials_mode;
155         request.cache_mode = temporary_request.cache_mode;
156         request.redirect_mode = temporary_request.redirect_mode;
157         request.integrity_metadata = temporary_request.integrity_metadata;
158 
159         // Step 13
160         if init.body.is_some() ||
161             init.cache.is_some() ||
162             init.credentials.is_some() ||
163             init.integrity.is_some() ||
164             init.headers.is_some() ||
165             init.method.is_some() ||
166             init.mode.is_some() ||
167             init.redirect.is_some() ||
168             init.referrer.is_some() ||
169             init.referrerPolicy.is_some() ||
170             !init.window.handle().is_undefined() {
171                 // Step 13.1
172                 if request.mode == NetTraitsRequestMode::Navigate {
173                     request.mode = NetTraitsRequestMode::SameOrigin;
174                 }
175                 // Step 13.2
176                 request.referrer = NetTraitsRequestReferrer::Client;
177                 // Step 13.3
178                 request.referrer_policy = None;
179             }
180 
181         // Step 14
182         if let Some(init_referrer) = init.referrer.as_ref() {
183             // Step 14.1
184             let ref referrer = init_referrer.0;
185             // Step 14.2
186             if referrer.is_empty() {
187                 request.referrer = NetTraitsRequestReferrer::NoReferrer;
188             } else {
189                 // Step 14.3
190                 let parsed_referrer = base_url.join(referrer);
191                 // Step 14.4
192                 if parsed_referrer.is_err() {
193                     return Err(Error::Type(
194                         "Failed to parse referrer url".to_string()));
195                 }
196                 // Step 14.5
197                 if let Ok(parsed_referrer) = parsed_referrer {
198                     if (parsed_referrer.cannot_be_a_base() &&
199                         parsed_referrer.scheme() == "about" &&
200                         parsed_referrer.path() == "client") ||
201                        parsed_referrer.origin() != origin {
202                             request.referrer = NetTraitsRequestReferrer::Client;
203                         } else {
204                             // Step 14.6
205                             request.referrer = NetTraitsRequestReferrer::ReferrerUrl(parsed_referrer);
206                         }
207                 }
208             }
209         }
210 
211         // Step 15
212         if let Some(init_referrerpolicy) = init.referrerPolicy.as_ref() {
213             let init_referrer_policy = init_referrerpolicy.clone().into();
214             request.referrer_policy = Some(init_referrer_policy);
215         }
216 
217         // Step 16
218         let mode = init.mode.as_ref().map(|m| m.clone().into()).or(fallback_mode);
219 
220         // Step 17
221         if let Some(NetTraitsRequestMode::Navigate) = mode {
222             return Err(Error::Type("Request mode is Navigate".to_string()));
223         }
224 
225         // Step 18
226         if let Some(m) = mode {
227             request.mode = m;
228         }
229 
230         // Step 19
231         let credentials = init.credentials.as_ref().map(|m| m.clone().into()).or(fallback_credentials);
232 
233         // Step 20
234         if let Some(c) = credentials {
235             request.credentials_mode = c;
236         }
237 
238         // Step 21
239         if let Some(init_cache) = init.cache.as_ref() {
240             let cache = init_cache.clone().into();
241             request.cache_mode = cache;
242         }
243 
244         // Step 22
245         if request.cache_mode == NetTraitsRequestCache::OnlyIfCached {
246             if request.mode != NetTraitsRequestMode::SameOrigin {
247                 return Err(Error::Type(
248                     "Cache is 'only-if-cached' and mode is not 'same-origin'".to_string()));
249             }
250         }
251 
252         // Step 23
253         if let Some(init_redirect) = init.redirect.as_ref() {
254             let redirect = init_redirect.clone().into();
255             request.redirect_mode = redirect;
256         }
257 
258         // Step 24
259         if let Some(init_integrity) = init.integrity.as_ref() {
260             let integrity = init_integrity.clone().to_string();
261             request.integrity_metadata = integrity;
262         }
263 
264         // Step 25
265         if let Some(init_method) = init.method.as_ref() {
266             // Step 25.1
267             if !is_method(&init_method) {
268                 return Err(Error::Type("Method is not a method".to_string()));
269             }
270             if is_forbidden_method(&init_method) {
271                 return Err(Error::Type("Method is forbidden".to_string()));
272             }
273             // Step 25.2
274             let method = match init_method.as_str() {
275                 Some(s) => normalize_method(s),
276                 None => return Err(Error::Type("Method is not a valid UTF8".to_string())),
277             };
278             // Step 25.3
279             request.method = method;
280         }
281 
282         // Step 26
283         let r = Request::from_net_request(global, request);
284         r.headers.or_init(|| Headers::for_request(&r.global()));
285 
286         // Step 27
287         let mut headers_copy = r.Headers();
288 
289         // Step 28
290         if let Some(possible_header) = init.headers.as_ref() {
291             match possible_header {
292                 &HeadersInit::Headers(ref init_headers) => {
293                     headers_copy = DomRoot::from_ref(&*init_headers);
294                 }
295                 &HeadersInit::ByteStringSequenceSequence(ref init_sequence) => {
296                     headers_copy.fill(Some(
297                         HeadersInit::ByteStringSequenceSequence(init_sequence.clone())))?;
298                 },
299                 &HeadersInit::StringByteStringRecord(ref init_map) => {
300                     headers_copy.fill(Some(
301                         HeadersInit::StringByteStringRecord(init_map.clone())))?;
302                 },
303             }
304         }
305 
306         // Step 29
307         // We cannot empty `r.Headers().header_list` because
308         // we would undo the Step 27 above.  One alternative is to set
309         // `headers_copy` as a deep copy of `r.Headers()`. However,
310         // `r.Headers()` is a `DomRoot<T>`, and therefore it is difficult
311         // to obtain a mutable reference to `r.Headers()`. Without the
312         // mutable reference, we cannot mutate `r.Headers()` to be the
313         // deep copied headers in Step 27.
314 
315         // Step 30
316         if r.request.borrow().mode == NetTraitsRequestMode::NoCors {
317             let borrowed_request = r.request.borrow();
318             // Step 30.1
319             if !is_cors_safelisted_method(&borrowed_request.method) {
320                 return Err(Error::Type(
321                     "The mode is 'no-cors' but the method is not a cors-safelisted method".to_string()));
322             }
323             // Step 30.2
324             r.Headers().set_guard(Guard::RequestNoCors);
325         }
326 
327         // Step 31
328         match init.headers {
329             None => {
330                 // This is equivalent to the specification's concept of
331                 // "associated headers list". If an init headers is not given,
332                 // but an input with headers is given, set request's
333                 // headers as the input's Headers.
334                 if let RequestInfo::Request(ref input_request) = input {
335                     r.Headers().fill(Some(HeadersInit::Headers(input_request.Headers())))?;
336                 }
337             },
338             Some(HeadersInit::Headers(_)) => r.Headers().fill(Some(HeadersInit::Headers(headers_copy)))?,
339             _ => {},
340         }
341 
342         // Copy the headers list onto the headers of net_traits::Request
343         r.request.borrow_mut().headers = r.Headers().get_headers_list();
344 
345         // Step 32
346         let mut input_body = if let RequestInfo::Request(ref input_request) = input {
347             let input_request_request = input_request.request.borrow();
348             input_request_request.body.clone()
349         } else {
350             None
351         };
352 
353         // Step 33
354         if let Some(init_body_option) = init.body.as_ref() {
355             if init_body_option.is_some() || input_body.is_some() {
356                 let req = r.request.borrow();
357                 let req_method = &req.method;
358                 match *req_method {
359                     HttpMethod::Get => return Err(Error::Type(
360                         "Init's body is non-null, and request method is GET".to_string())),
361                     HttpMethod::Head => return Err(Error::Type(
362                         "Init's body is non-null, and request method is HEAD".to_string())),
363                     _ => {},
364                 }
365             }
366         }
367 
368         // Step 34
369         if let Some(Some(ref init_body)) = init.body {
370             // Step 34.2
371             let extracted_body_tmp = init_body.extract();
372             input_body = Some(extracted_body_tmp.0);
373             let content_type = extracted_body_tmp.1;
374 
375             // Step 34.3
376             if let Some(contents) = content_type {
377                 if !r.Headers().Has(ByteString::new(b"Content-Type".to_vec())).unwrap() {
378                     r.Headers().Append(ByteString::new(b"Content-Type".to_vec()),
379                                             ByteString::new(contents.as_bytes().to_vec()))?;
380                 }
381             }
382         }
383 
384         // Step 35
385         r.request.borrow_mut().body = input_body;
386 
387         // Step 36
388         let extracted_mime_type = r.Headers().extract_mime_type();
389         *r.mime_type.borrow_mut() = extracted_mime_type;
390 
391         // Step 37
392         // TODO: `ReadableStream` object is not implemented in Servo yet.
393 
394         // Step 38
395         Ok(r)
396     }
397 
398     // https://fetch.spec.whatwg.org/#concept-body-locked
locked(&self) -> bool399     fn locked(&self) -> bool {
400         // TODO: ReadableStream is unimplemented. Just return false
401         // for now.
402         false
403     }
404 }
405 
406 impl Request {
from_net_request(global: &GlobalScope, net_request: NetTraitsRequest) -> DomRoot<Request>407     fn from_net_request(global: &GlobalScope,
408                         net_request: NetTraitsRequest) -> DomRoot<Request> {
409         let r = Request::new(global,
410                              net_request.current_url());
411         *r.request.borrow_mut() = net_request;
412         r
413     }
414 
clone_from(r: &Request) -> Fallible<DomRoot<Request>>415     fn clone_from(r: &Request) -> Fallible<DomRoot<Request>> {
416         let req = r.request.borrow();
417         let url = req.url();
418         let body_used = r.body_used.get();
419         let mime_type = r.mime_type.borrow().clone();
420         let headers_guard = r.Headers().get_guard();
421         let r_clone = Request::new(&r.global(), url);
422         r_clone.request.borrow_mut().pipeline_id = req.pipeline_id;
423         {
424             let mut borrowed_r_request = r_clone.request.borrow_mut();
425             borrowed_r_request.origin = req.origin.clone();
426         }
427         *r_clone.request.borrow_mut() = req.clone();
428         r_clone.body_used.set(body_used);
429         *r_clone.mime_type.borrow_mut() = mime_type;
430         r_clone.Headers().fill(Some(HeadersInit::Headers(r.Headers())))?;
431         r_clone.Headers().set_guard(headers_guard);
432         Ok(r_clone)
433     }
434 
get_request(&self) -> NetTraitsRequest435     pub fn get_request(&self) -> NetTraitsRequest {
436         self.request.borrow().clone()
437     }
438 }
439 
net_request_from_global(global: &GlobalScope, url: ServoUrl) -> NetTraitsRequest440 fn net_request_from_global(global: &GlobalScope,
441                            url: ServoUrl) -> NetTraitsRequest {
442     let origin = Origin::Origin(global.get_url().origin());
443     let pipeline_id = global.pipeline_id();
444     NetTraitsRequest::new(url,
445                           Some(origin),
446                           Some(pipeline_id))
447 }
448 
449 // https://fetch.spec.whatwg.org/#concept-method-normalize
normalize_method(m: &str) -> HttpMethod450 fn normalize_method(m: &str) -> HttpMethod {
451     match_ignore_ascii_case! { m,
452         "delete" => return HttpMethod::Delete,
453         "get" => return HttpMethod::Get,
454         "head" => return HttpMethod::Head,
455         "options" => return HttpMethod::Options,
456         "post" => return HttpMethod::Post,
457         "put" => return HttpMethod::Put,
458         _ => (),
459     }
460     HttpMethod::Extension(m.to_string())
461 }
462 
463 // https://fetch.spec.whatwg.org/#concept-method
is_method(m: &ByteString) -> bool464 fn is_method(m: &ByteString) -> bool {
465     m.as_str().is_some()
466 }
467 
468 // https://fetch.spec.whatwg.org/#forbidden-method
is_forbidden_method(m: &ByteString) -> bool469 fn is_forbidden_method(m: &ByteString) -> bool {
470     match m.to_lower().as_str() {
471         Some("connect") => true,
472         Some("trace") => true,
473         Some("track") => true,
474         _ => false,
475     }
476 }
477 
478 // https://fetch.spec.whatwg.org/#cors-safelisted-method
is_cors_safelisted_method(m: &HttpMethod) -> bool479 fn is_cors_safelisted_method(m: &HttpMethod) -> bool {
480     m == &HttpMethod::Get ||
481         m == &HttpMethod::Head ||
482         m == &HttpMethod::Post
483 }
484 
485 // https://url.spec.whatwg.org/#include-credentials
includes_credentials(input: &ServoUrl) -> bool486 fn includes_credentials(input: &ServoUrl) -> bool {
487     !input.username().is_empty() || input.password().is_some()
488 }
489 
490 // TODO: `Readable Stream` object is not implemented in Servo yet.
491 // https://fetch.spec.whatwg.org/#concept-body-disturbed
request_is_disturbed(_input: &Request) -> bool492 fn request_is_disturbed(_input: &Request) -> bool {
493     false
494 }
495 
496 // TODO: `Readable Stream` object is not implemented in Servo yet.
497 // https://fetch.spec.whatwg.org/#concept-body-locked
request_is_locked(_input: &Request) -> bool498 fn request_is_locked(_input: &Request) -> bool {
499     false
500 }
501 
502 impl RequestMethods for Request {
503     // https://fetch.spec.whatwg.org/#dom-request-method
Method(&self) -> ByteString504     fn Method(&self) -> ByteString {
505         let r = self.request.borrow();
506         ByteString::new(r.method.as_ref().as_bytes().into())
507     }
508 
509     // https://fetch.spec.whatwg.org/#dom-request-url
Url(&self) -> USVString510     fn Url(&self) -> USVString {
511         let r = self.request.borrow();
512         USVString(r.url_list.get(0).map_or("", |u| u.as_str()).into())
513     }
514 
515     // https://fetch.spec.whatwg.org/#dom-request-headers
Headers(&self) -> DomRoot<Headers>516     fn Headers(&self) -> DomRoot<Headers> {
517         self.headers.or_init(|| Headers::new(&self.global()))
518     }
519 
520     // https://fetch.spec.whatwg.org/#dom-request-destination
Destination(&self) -> RequestDestination521     fn Destination(&self) -> RequestDestination {
522         self.request.borrow().destination.into()
523     }
524 
525     // https://fetch.spec.whatwg.org/#dom-request-referrer
Referrer(&self) -> USVString526     fn Referrer(&self) -> USVString {
527         let r = self.request.borrow();
528         USVString(match r.referrer {
529             NetTraitsRequestReferrer::NoReferrer => String::from("no-referrer"),
530             NetTraitsRequestReferrer::Client => String::from("about:client"),
531             NetTraitsRequestReferrer::ReferrerUrl(ref u) => {
532                 let u_c = u.clone();
533                 u_c.into_string()
534             }
535         })
536     }
537 
538     // https://fetch.spec.whatwg.org/#dom-request-referrerpolicy
ReferrerPolicy(&self) -> ReferrerPolicy539     fn ReferrerPolicy(&self) -> ReferrerPolicy {
540         self.request.borrow().referrer_policy.map(|m| m.into()).unwrap_or(ReferrerPolicy::_empty)
541     }
542 
543     // https://fetch.spec.whatwg.org/#dom-request-mode
Mode(&self) -> RequestMode544     fn Mode(&self) -> RequestMode {
545         self.request.borrow().mode.clone().into()
546     }
547 
548     // https://fetch.spec.whatwg.org/#dom-request-credentials
Credentials(&self) -> RequestCredentials549     fn Credentials(&self) -> RequestCredentials {
550         let r = self.request.borrow().clone();
551         r.credentials_mode.into()
552     }
553 
554     // https://fetch.spec.whatwg.org/#dom-request-cache
Cache(&self) -> RequestCache555     fn Cache(&self) -> RequestCache {
556         let r = self.request.borrow().clone();
557         r.cache_mode.into()
558     }
559 
560     // https://fetch.spec.whatwg.org/#dom-request-redirect
Redirect(&self) -> RequestRedirect561     fn Redirect(&self) -> RequestRedirect {
562         let r = self.request.borrow().clone();
563         r.redirect_mode.into()
564     }
565 
566     // https://fetch.spec.whatwg.org/#dom-request-integrity
Integrity(&self) -> DOMString567     fn Integrity(&self) -> DOMString {
568         let r = self.request.borrow();
569         DOMString::from_string(r.integrity_metadata.clone())
570     }
571 
572     // https://fetch.spec.whatwg.org/#dom-body-bodyused
BodyUsed(&self) -> bool573     fn BodyUsed(&self) -> bool {
574         self.body_used.get()
575     }
576 
577     // https://fetch.spec.whatwg.org/#dom-request-clone
Clone(&self) -> Fallible<DomRoot<Request>>578     fn Clone(&self) -> Fallible<DomRoot<Request>> {
579         // Step 1
580         if request_is_locked(self) {
581             return Err(Error::Type("Request is locked".to_string()));
582         }
583         if request_is_disturbed(self) {
584             return Err(Error::Type("Request is disturbed".to_string()));
585         }
586 
587         // Step 2
588         Request::clone_from(self)
589     }
590 
591     #[allow(unrooted_must_root)]
592     // https://fetch.spec.whatwg.org/#dom-body-text
Text(&self) -> Rc<Promise>593     fn Text(&self) -> Rc<Promise> {
594         consume_body(self, BodyType::Text)
595     }
596 
597     #[allow(unrooted_must_root)]
598     // https://fetch.spec.whatwg.org/#dom-body-blob
Blob(&self) -> Rc<Promise>599     fn Blob(&self) -> Rc<Promise> {
600         consume_body(self, BodyType::Blob)
601     }
602 
603     #[allow(unrooted_must_root)]
604     // https://fetch.spec.whatwg.org/#dom-body-formdata
FormData(&self) -> Rc<Promise>605     fn FormData(&self) -> Rc<Promise> {
606         consume_body(self, BodyType::FormData)
607     }
608 
609     #[allow(unrooted_must_root)]
610     // https://fetch.spec.whatwg.org/#dom-body-json
Json(&self) -> Rc<Promise>611     fn Json(&self) -> Rc<Promise> {
612         consume_body(self, BodyType::Json)
613     }
614 }
615 
616 impl BodyOperations for Request {
get_body_used(&self) -> bool617     fn get_body_used(&self) -> bool {
618         self.BodyUsed()
619     }
620 
set_body_promise(&self, p: &Rc<Promise>, body_type: BodyType)621     fn set_body_promise(&self, p: &Rc<Promise>, body_type: BodyType) {
622         assert!(self.body_promise.borrow().is_none());
623         self.body_used.set(true);
624         *self.body_promise.borrow_mut() = Some((p.clone(), body_type));
625     }
626 
is_locked(&self) -> bool627     fn is_locked(&self) -> bool {
628         self.locked()
629     }
630 
take_body(&self) -> Option<Vec<u8>>631     fn take_body(&self) -> Option<Vec<u8>> {
632         let mut request = self.request.borrow_mut();
633         let body = request.body.take();
634         Some(body.unwrap_or(vec![]))
635     }
636 
get_mime_type(&self) -> Ref<Vec<u8>>637     fn get_mime_type(&self) -> Ref<Vec<u8>> {
638         self.mime_type.borrow()
639     }
640 }
641 
642 impl Into<NetTraitsRequestCache> for RequestCache {
into(self) -> NetTraitsRequestCache643     fn into(self) -> NetTraitsRequestCache {
644         match self {
645             RequestCache::Default => NetTraitsRequestCache::Default,
646             RequestCache::No_store => NetTraitsRequestCache::NoStore,
647             RequestCache::Reload => NetTraitsRequestCache::Reload,
648             RequestCache::No_cache => NetTraitsRequestCache::NoCache,
649             RequestCache::Force_cache => NetTraitsRequestCache::ForceCache,
650             RequestCache::Only_if_cached => NetTraitsRequestCache::OnlyIfCached,
651         }
652     }
653 }
654 
655 impl Into<RequestCache> for NetTraitsRequestCache {
into(self) -> RequestCache656     fn into(self) -> RequestCache {
657         match self {
658             NetTraitsRequestCache::Default => RequestCache::Default,
659             NetTraitsRequestCache::NoStore => RequestCache::No_store,
660             NetTraitsRequestCache::Reload => RequestCache::Reload,
661             NetTraitsRequestCache::NoCache => RequestCache::No_cache,
662             NetTraitsRequestCache::ForceCache => RequestCache::Force_cache,
663             NetTraitsRequestCache::OnlyIfCached => RequestCache::Only_if_cached,
664         }
665     }
666 }
667 
668 impl Into<NetTraitsRequestCredentials> for RequestCredentials {
into(self) -> NetTraitsRequestCredentials669     fn into(self) -> NetTraitsRequestCredentials {
670         match self {
671             RequestCredentials::Omit => NetTraitsRequestCredentials::Omit,
672             RequestCredentials::Same_origin => NetTraitsRequestCredentials::CredentialsSameOrigin,
673             RequestCredentials::Include => NetTraitsRequestCredentials::Include,
674         }
675     }
676 }
677 
678 impl Into<RequestCredentials> for NetTraitsRequestCredentials {
into(self) -> RequestCredentials679     fn into(self) -> RequestCredentials {
680         match self {
681             NetTraitsRequestCredentials::Omit => RequestCredentials::Omit,
682             NetTraitsRequestCredentials::CredentialsSameOrigin => RequestCredentials::Same_origin,
683             NetTraitsRequestCredentials::Include => RequestCredentials::Include,
684         }
685     }
686 }
687 
688 impl Into<NetTraitsRequestDestination> for RequestDestination {
into(self) -> NetTraitsRequestDestination689     fn into(self) -> NetTraitsRequestDestination {
690         match self {
691             RequestDestination::_empty => NetTraitsRequestDestination::None,
692             RequestDestination::Audio => NetTraitsRequestDestination::Audio,
693             RequestDestination::Document => NetTraitsRequestDestination::Document,
694             RequestDestination::Embed => NetTraitsRequestDestination::Embed,
695             RequestDestination::Font => NetTraitsRequestDestination::Font,
696             RequestDestination::Image => NetTraitsRequestDestination::Image,
697             RequestDestination::Manifest => NetTraitsRequestDestination::Manifest,
698             RequestDestination::Object => NetTraitsRequestDestination::Object,
699             RequestDestination::Report => NetTraitsRequestDestination::Report,
700             RequestDestination::Script => NetTraitsRequestDestination::Script,
701             RequestDestination::Sharedworker => NetTraitsRequestDestination::SharedWorker,
702             RequestDestination::Style => NetTraitsRequestDestination::Style,
703             RequestDestination::Track => NetTraitsRequestDestination::Track,
704             RequestDestination::Video => NetTraitsRequestDestination::Video,
705             RequestDestination::Worker => NetTraitsRequestDestination::Worker,
706             RequestDestination::Xslt => NetTraitsRequestDestination::Xslt,
707         }
708     }
709 }
710 
711 impl Into<RequestDestination> for NetTraitsRequestDestination {
into(self) -> RequestDestination712     fn into(self) -> RequestDestination {
713         match self {
714             NetTraitsRequestDestination::None => RequestDestination::_empty,
715             NetTraitsRequestDestination::Audio => RequestDestination::Audio,
716             NetTraitsRequestDestination::Document => RequestDestination::Document,
717             NetTraitsRequestDestination::Embed => RequestDestination::Embed,
718             NetTraitsRequestDestination::Font => RequestDestination::Font,
719             NetTraitsRequestDestination::Image => RequestDestination::Image,
720             NetTraitsRequestDestination::Manifest => RequestDestination::Manifest,
721             NetTraitsRequestDestination::Object => RequestDestination::Object,
722             NetTraitsRequestDestination::Report => RequestDestination::Report,
723             NetTraitsRequestDestination::Script => RequestDestination::Script,
724             NetTraitsRequestDestination::ServiceWorker
725                 => panic!("ServiceWorker request destination should not be exposed to DOM"),
726             NetTraitsRequestDestination::SharedWorker => RequestDestination::Sharedworker,
727             NetTraitsRequestDestination::Style => RequestDestination::Style,
728             NetTraitsRequestDestination::Track => RequestDestination::Track,
729             NetTraitsRequestDestination::Video => RequestDestination::Video,
730             NetTraitsRequestDestination::Worker => RequestDestination::Worker,
731             NetTraitsRequestDestination::Xslt => RequestDestination::Xslt,
732         }
733     }
734 }
735 
736 impl Into<NetTraitsRequestMode> for RequestMode {
into(self) -> NetTraitsRequestMode737     fn into(self) -> NetTraitsRequestMode {
738         match self {
739             RequestMode::Navigate => NetTraitsRequestMode::Navigate,
740             RequestMode::Same_origin => NetTraitsRequestMode::SameOrigin,
741             RequestMode::No_cors => NetTraitsRequestMode::NoCors,
742             RequestMode::Cors => NetTraitsRequestMode::CorsMode,
743         }
744     }
745 }
746 
747 impl Into<RequestMode> for NetTraitsRequestMode {
into(self) -> RequestMode748     fn into(self) -> RequestMode {
749         match self {
750             NetTraitsRequestMode::Navigate => RequestMode::Navigate,
751             NetTraitsRequestMode::SameOrigin => RequestMode::Same_origin,
752             NetTraitsRequestMode::NoCors => RequestMode::No_cors,
753             NetTraitsRequestMode::CorsMode => RequestMode::Cors,
754             NetTraitsRequestMode::WebSocket { .. } =>
755                 unreachable!("Websocket request mode should never be exposed to Dom"),
756         }
757     }
758 }
759 
760 // TODO
761 // When whatwg/fetch PR #346 is merged, fix this.
762 impl Into<MsgReferrerPolicy> for ReferrerPolicy {
into(self) -> MsgReferrerPolicy763     fn into(self) -> MsgReferrerPolicy {
764         match self {
765             ReferrerPolicy::_empty => MsgReferrerPolicy::NoReferrer,
766             ReferrerPolicy::No_referrer => MsgReferrerPolicy::NoReferrer,
767             ReferrerPolicy::No_referrer_when_downgrade =>
768                 MsgReferrerPolicy::NoReferrerWhenDowngrade,
769             ReferrerPolicy::Origin => MsgReferrerPolicy::Origin,
770             ReferrerPolicy::Origin_when_cross_origin => MsgReferrerPolicy::OriginWhenCrossOrigin,
771             ReferrerPolicy::Unsafe_url => MsgReferrerPolicy::UnsafeUrl,
772             ReferrerPolicy::Strict_origin => MsgReferrerPolicy::StrictOrigin,
773             ReferrerPolicy::Strict_origin_when_cross_origin =>
774                 MsgReferrerPolicy::StrictOriginWhenCrossOrigin,
775         }
776     }
777 }
778 
779 impl Into<ReferrerPolicy> for MsgReferrerPolicy {
into(self) -> ReferrerPolicy780     fn into(self) -> ReferrerPolicy {
781         match self {
782             MsgReferrerPolicy::NoReferrer => ReferrerPolicy::No_referrer,
783             MsgReferrerPolicy::NoReferrerWhenDowngrade =>
784                 ReferrerPolicy::No_referrer_when_downgrade,
785             MsgReferrerPolicy::Origin => ReferrerPolicy::Origin,
786             MsgReferrerPolicy::SameOrigin => ReferrerPolicy::Origin,
787             MsgReferrerPolicy::OriginWhenCrossOrigin => ReferrerPolicy::Origin_when_cross_origin,
788             MsgReferrerPolicy::UnsafeUrl => ReferrerPolicy::Unsafe_url,
789             MsgReferrerPolicy::StrictOrigin => ReferrerPolicy::Strict_origin,
790             MsgReferrerPolicy::StrictOriginWhenCrossOrigin =>
791                 ReferrerPolicy::Strict_origin_when_cross_origin,
792         }
793     }
794 }
795 
796 impl Into<NetTraitsRequestRedirect> for RequestRedirect {
into(self) -> NetTraitsRequestRedirect797     fn into(self) -> NetTraitsRequestRedirect {
798         match self {
799             RequestRedirect::Follow => NetTraitsRequestRedirect::Follow,
800             RequestRedirect::Error => NetTraitsRequestRedirect::Error,
801             RequestRedirect::Manual => NetTraitsRequestRedirect::Manual,
802         }
803     }
804 }
805 
806 impl Into<RequestRedirect> for NetTraitsRequestRedirect {
into(self) -> RequestRedirect807     fn into(self) -> RequestRedirect {
808         match self {
809             NetTraitsRequestRedirect::Follow => RequestRedirect::Follow,
810             NetTraitsRequestRedirect::Error => RequestRedirect::Error,
811             NetTraitsRequestRedirect::Manual => RequestRedirect::Manual,
812         }
813     }
814 }
815 
816 impl Clone for HeadersInit {
clone(&self) -> HeadersInit817     fn clone(&self) -> HeadersInit {
818     match self {
819         &HeadersInit::Headers(ref h) =>
820             HeadersInit::Headers(h.clone()),
821         &HeadersInit::ByteStringSequenceSequence(ref b) =>
822             HeadersInit::ByteStringSequenceSequence(b.clone()),
823         &HeadersInit::StringByteStringRecord(ref m) =>
824             HeadersInit::StringByteStringRecord(m.clone()),
825         }
826     }
827 }
828