/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use body::{BodyOperations, BodyType, consume_body}; use dom::bindings::cell::DomRefCell; use dom::bindings::codegen::Bindings::HeadersBinding::{HeadersInit, HeadersMethods}; use dom::bindings::codegen::Bindings::RequestBinding; use dom::bindings::codegen::Bindings::RequestBinding::ReferrerPolicy; use dom::bindings::codegen::Bindings::RequestBinding::RequestCache; use dom::bindings::codegen::Bindings::RequestBinding::RequestCredentials; use dom::bindings::codegen::Bindings::RequestBinding::RequestDestination; use dom::bindings::codegen::Bindings::RequestBinding::RequestInfo; use dom::bindings::codegen::Bindings::RequestBinding::RequestInit; use dom::bindings::codegen::Bindings::RequestBinding::RequestMethods; use dom::bindings::codegen::Bindings::RequestBinding::RequestMode; use dom::bindings::codegen::Bindings::RequestBinding::RequestRedirect; use dom::bindings::codegen::Bindings::RequestBinding::RequestType; use dom::bindings::error::{Error, Fallible}; use dom::bindings::reflector::{DomObject, Reflector, reflect_dom_object}; use dom::bindings::root::{DomRoot, MutNullableDom}; use dom::bindings::str::{ByteString, DOMString, USVString}; use dom::bindings::trace::RootedTraceableBox; use dom::globalscope::GlobalScope; use dom::headers::{Guard, Headers}; use dom::promise::Promise; use dom::xmlhttprequest::Extractable; use dom_struct::dom_struct; use hyper::method::Method as HttpMethod; use net_traits::ReferrerPolicy as MsgReferrerPolicy; use net_traits::request::{Origin, Window}; use net_traits::request::CacheMode as NetTraitsRequestCache; use net_traits::request::CredentialsMode as NetTraitsRequestCredentials; use net_traits::request::Destination as NetTraitsRequestDestination; use net_traits::request::RedirectMode as NetTraitsRequestRedirect; use net_traits::request::Referrer as NetTraitsRequestReferrer; use net_traits::request::Request as NetTraitsRequest; use net_traits::request::RequestMode as NetTraitsRequestMode; use net_traits::request::Type as NetTraitsRequestType; use servo_url::ServoUrl; use std::cell::{Cell, Ref}; use std::rc::Rc; #[dom_struct] pub struct Request { reflector_: Reflector, request: DomRefCell, body_used: Cell, headers: MutNullableDom, mime_type: DomRefCell>, #[ignore_heap_size_of = "Rc"] body_promise: DomRefCell, BodyType)>>, } impl Request { fn new_inherited(global: &GlobalScope, url: ServoUrl) -> Request { Request { reflector_: Reflector::new(), request: DomRefCell::new( net_request_from_global(global, url)), body_used: Cell::new(false), headers: Default::default(), mime_type: DomRefCell::new("".to_string().into_bytes()), body_promise: DomRefCell::new(None), } } pub fn new(global: &GlobalScope, url: ServoUrl) -> DomRoot { reflect_dom_object(Box::new(Request::new_inherited(global, url)), global, RequestBinding::Wrap) } // https://fetch.spec.whatwg.org/#dom-request pub fn Constructor(global: &GlobalScope, input: RequestInfo, init: RootedTraceableBox) -> Fallible> { // Step 1 let temporary_request: NetTraitsRequest; // Step 2 let mut fallback_mode: Option = None; // Step 3 let mut fallback_credentials: Option = None; // Step 4 let base_url = global.api_base_url(); match input { // Step 5 RequestInfo::USVString(USVString(ref usv_string)) => { // Step 5.1 let parsed_url = base_url.join(&usv_string); // Step 5.2 if parsed_url.is_err() { return Err(Error::Type("Url could not be parsed".to_string())) } // Step 5.3 let url = parsed_url.unwrap(); if includes_credentials(&url) { return Err(Error::Type("Url includes credentials".to_string())) } // Step 5.4 temporary_request = net_request_from_global(global, url); // Step 5.5 fallback_mode = Some(NetTraitsRequestMode::CorsMode); // Step 5.6 fallback_credentials = Some(NetTraitsRequestCredentials::Omit); } // Step 6 RequestInfo::Request(ref input_request) => { // Step 6.1 if request_is_disturbed(input_request) || request_is_locked(input_request) { return Err(Error::Type("Input is disturbed or locked".to_string())) } // Step 6.2 temporary_request = input_request.request.borrow().clone(); } } // Step 7 // TODO: `entry settings object` is not implemented yet. let origin = base_url.origin(); // Step 8 let mut window = Window::Client; // Step 9 // TODO: `environment settings object` is not implemented in Servo yet. // Step 10 if !init.window.handle().is_null_or_undefined() { return Err(Error::Type("Window is present and is not null".to_string())) } // Step 11 if !init.window.handle().is_undefined() { window = Window::NoWindow; } // Step 12 let mut request: NetTraitsRequest; request = net_request_from_global(global, temporary_request.current_url()); request.method = temporary_request.method; request.headers = temporary_request.headers.clone(); request.unsafe_request = true; request.window = window; // TODO: `entry settings object` is not implemented in Servo yet. request.origin = Origin::Client; request.referrer = temporary_request.referrer; request.referrer_policy = temporary_request.referrer_policy; request.mode = temporary_request.mode; request.credentials_mode = temporary_request.credentials_mode; request.cache_mode = temporary_request.cache_mode; request.redirect_mode = temporary_request.redirect_mode; request.integrity_metadata = temporary_request.integrity_metadata; // Step 13 if init.body.is_some() || init.cache.is_some() || init.credentials.is_some() || init.integrity.is_some() || init.headers.is_some() || init.method.is_some() || init.mode.is_some() || init.redirect.is_some() || init.referrer.is_some() || init.referrerPolicy.is_some() || !init.window.handle().is_undefined() { // Step 13.1 if request.mode == NetTraitsRequestMode::Navigate { request.mode = NetTraitsRequestMode::SameOrigin; } // Step 13.2 request.referrer = NetTraitsRequestReferrer::Client; // Step 13.3 request.referrer_policy = None; } // Step 14 if let Some(init_referrer) = init.referrer.as_ref() { // Step 14.1 let ref referrer = init_referrer.0; // Step 14.2 if referrer.is_empty() { request.referrer = NetTraitsRequestReferrer::NoReferrer; } else { // Step 14.3 let parsed_referrer = base_url.join(referrer); // Step 14.4 if parsed_referrer.is_err() { return Err(Error::Type( "Failed to parse referrer url".to_string())); } // Step 14.5 if let Ok(parsed_referrer) = parsed_referrer { if (parsed_referrer.cannot_be_a_base() && parsed_referrer.scheme() == "about" && parsed_referrer.path() == "client") || parsed_referrer.origin() != origin { request.referrer = NetTraitsRequestReferrer::Client; } else { // Step 14.6 request.referrer = NetTraitsRequestReferrer::ReferrerUrl(parsed_referrer); } } } } // Step 15 if let Some(init_referrerpolicy) = init.referrerPolicy.as_ref() { let init_referrer_policy = init_referrerpolicy.clone().into(); request.referrer_policy = Some(init_referrer_policy); } // Step 16 let mode = init.mode.as_ref().map(|m| m.clone().into()).or(fallback_mode); // Step 17 if let Some(NetTraitsRequestMode::Navigate) = mode { return Err(Error::Type("Request mode is Navigate".to_string())); } // Step 18 if let Some(m) = mode { request.mode = m; } // Step 19 let credentials = init.credentials.as_ref().map(|m| m.clone().into()).or(fallback_credentials); // Step 20 if let Some(c) = credentials { request.credentials_mode = c; } // Step 21 if let Some(init_cache) = init.cache.as_ref() { let cache = init_cache.clone().into(); request.cache_mode = cache; } // Step 22 if request.cache_mode == NetTraitsRequestCache::OnlyIfCached { if request.mode != NetTraitsRequestMode::SameOrigin { return Err(Error::Type( "Cache is 'only-if-cached' and mode is not 'same-origin'".to_string())); } } // Step 23 if let Some(init_redirect) = init.redirect.as_ref() { let redirect = init_redirect.clone().into(); request.redirect_mode = redirect; } // Step 24 if let Some(init_integrity) = init.integrity.as_ref() { let integrity = init_integrity.clone().to_string(); request.integrity_metadata = integrity; } // Step 25 if let Some(init_method) = init.method.as_ref() { // Step 25.1 if !is_method(&init_method) { return Err(Error::Type("Method is not a method".to_string())); } if is_forbidden_method(&init_method) { return Err(Error::Type("Method is forbidden".to_string())); } // Step 25.2 let method = match init_method.as_str() { Some(s) => normalize_method(s), None => return Err(Error::Type("Method is not a valid UTF8".to_string())), }; // Step 25.3 request.method = method; } // Step 26 let r = Request::from_net_request(global, request); r.headers.or_init(|| Headers::for_request(&r.global())); // Step 27 let mut headers_copy = r.Headers(); // Step 28 if let Some(possible_header) = init.headers.as_ref() { match possible_header { &HeadersInit::Headers(ref init_headers) => { headers_copy = DomRoot::from_ref(&*init_headers); } &HeadersInit::ByteStringSequenceSequence(ref init_sequence) => { headers_copy.fill(Some( HeadersInit::ByteStringSequenceSequence(init_sequence.clone())))?; }, &HeadersInit::StringByteStringRecord(ref init_map) => { headers_copy.fill(Some( HeadersInit::StringByteStringRecord(init_map.clone())))?; }, } } // Step 29 // We cannot empty `r.Headers().header_list` because // we would undo the Step 27 above. One alternative is to set // `headers_copy` as a deep copy of `r.Headers()`. However, // `r.Headers()` is a `DomRoot`, and therefore it is difficult // to obtain a mutable reference to `r.Headers()`. Without the // mutable reference, we cannot mutate `r.Headers()` to be the // deep copied headers in Step 27. // Step 30 if r.request.borrow().mode == NetTraitsRequestMode::NoCors { let borrowed_request = r.request.borrow(); // Step 30.1 if !is_cors_safelisted_method(&borrowed_request.method) { return Err(Error::Type( "The mode is 'no-cors' but the method is not a cors-safelisted method".to_string())); } // Step 30.2 r.Headers().set_guard(Guard::RequestNoCors); } // Step 31 match init.headers { None => { // This is equivalent to the specification's concept of // "associated headers list". If an init headers is not given, // but an input with headers is given, set request's // headers as the input's Headers. if let RequestInfo::Request(ref input_request) = input { r.Headers().fill(Some(HeadersInit::Headers(input_request.Headers())))?; } }, Some(HeadersInit::Headers(_)) => r.Headers().fill(Some(HeadersInit::Headers(headers_copy)))?, _ => {}, } // Step 32 let mut input_body = if let RequestInfo::Request(ref input_request) = input { let input_request_request = input_request.request.borrow(); input_request_request.body.clone() } else { None }; // Step 33 if let Some(init_body_option) = init.body.as_ref() { if init_body_option.is_some() || input_body.is_some() { let req = r.request.borrow(); let req_method = &req.method; match *req_method { HttpMethod::Get => return Err(Error::Type( "Init's body is non-null, and request method is GET".to_string())), HttpMethod::Head => return Err(Error::Type( "Init's body is non-null, and request method is HEAD".to_string())), _ => {}, } } } // Step 34 if let Some(Some(ref init_body)) = init.body { // Step 34.2 let extracted_body_tmp = init_body.extract(); input_body = Some(extracted_body_tmp.0); let content_type = extracted_body_tmp.1; // Step 34.3 if let Some(contents) = content_type { if !r.Headers().Has(ByteString::new(b"Content-Type".to_vec())).unwrap() { r.Headers().Append(ByteString::new(b"Content-Type".to_vec()), ByteString::new(contents.as_bytes().to_vec()))?; } } } // Step 35 r.request.borrow_mut().body = input_body; // Step 36 let extracted_mime_type = r.Headers().extract_mime_type(); *r.mime_type.borrow_mut() = extracted_mime_type; // Step 37 // TODO: `ReadableStream` object is not implemented in Servo yet. // Step 38 Ok(r) } // https://fetch.spec.whatwg.org/#concept-body-locked fn locked(&self) -> bool { // TODO: ReadableStream is unimplemented. Just return false // for now. false } } impl Request { fn from_net_request(global: &GlobalScope, net_request: NetTraitsRequest) -> DomRoot { let r = Request::new(global, net_request.current_url()); *r.request.borrow_mut() = net_request; r } fn clone_from(r: &Request) -> Fallible> { let req = r.request.borrow(); let url = req.url(); let body_used = r.body_used.get(); let mime_type = r.mime_type.borrow().clone(); let headers_guard = r.Headers().get_guard(); let r_clone = Request::new(&r.global(), url); r_clone.request.borrow_mut().pipeline_id = req.pipeline_id; { let mut borrowed_r_request = r_clone.request.borrow_mut(); borrowed_r_request.origin = req.origin.clone(); } *r_clone.request.borrow_mut() = req.clone(); r_clone.body_used.set(body_used); *r_clone.mime_type.borrow_mut() = mime_type; r_clone.Headers().fill(Some(HeadersInit::Headers(r.Headers())))?; r_clone.Headers().set_guard(headers_guard); Ok(r_clone) } pub fn get_request(&self) -> NetTraitsRequest { self.request.borrow().clone() } } fn net_request_from_global(global: &GlobalScope, url: ServoUrl) -> NetTraitsRequest { let origin = Origin::Origin(global.get_url().origin()); let pipeline_id = global.pipeline_id(); NetTraitsRequest::new(url, Some(origin), Some(pipeline_id)) } // https://fetch.spec.whatwg.org/#concept-method-normalize fn normalize_method(m: &str) -> HttpMethod { match_ignore_ascii_case! { m, "delete" => return HttpMethod::Delete, "get" => return HttpMethod::Get, "head" => return HttpMethod::Head, "options" => return HttpMethod::Options, "post" => return HttpMethod::Post, "put" => return HttpMethod::Put, _ => (), } HttpMethod::Extension(m.to_string()) } // https://fetch.spec.whatwg.org/#concept-method fn is_method(m: &ByteString) -> bool { match m.to_lower().as_str() { Some("get") => true, Some("head") => true, Some("post") => true, Some("put") => true, Some("delete") => true, Some("connect") => true, Some("options") => true, Some("trace") => true, _ => false, } } // https://fetch.spec.whatwg.org/#forbidden-method fn is_forbidden_method(m: &ByteString) -> bool { match m.to_lower().as_str() { Some("connect") => true, Some("trace") => true, Some("track") => true, _ => false, } } // https://fetch.spec.whatwg.org/#cors-safelisted-method fn is_cors_safelisted_method(m: &HttpMethod) -> bool { m == &HttpMethod::Get || m == &HttpMethod::Head || m == &HttpMethod::Post } // https://url.spec.whatwg.org/#include-credentials fn includes_credentials(input: &ServoUrl) -> bool { !input.username().is_empty() || input.password().is_some() } // TODO: `Readable Stream` object is not implemented in Servo yet. // https://fetch.spec.whatwg.org/#concept-body-disturbed fn request_is_disturbed(_input: &Request) -> bool { false } // TODO: `Readable Stream` object is not implemented in Servo yet. // https://fetch.spec.whatwg.org/#concept-body-locked fn request_is_locked(_input: &Request) -> bool { false } impl RequestMethods for Request { // https://fetch.spec.whatwg.org/#dom-request-method fn Method(&self) -> ByteString { let r = self.request.borrow(); ByteString::new(r.method.as_ref().as_bytes().into()) } // https://fetch.spec.whatwg.org/#dom-request-url fn Url(&self) -> USVString { let r = self.request.borrow(); USVString(r.url_list.get(0).map_or("", |u| u.as_str()).into()) } // https://fetch.spec.whatwg.org/#dom-request-headers fn Headers(&self) -> DomRoot { self.headers.or_init(|| Headers::new(&self.global())) } // https://fetch.spec.whatwg.org/#dom-request-type fn Type(&self) -> RequestType { self.request.borrow().type_.into() } // https://fetch.spec.whatwg.org/#dom-request-destination fn Destination(&self) -> RequestDestination { self.request.borrow().destination.into() } // https://fetch.spec.whatwg.org/#dom-request-referrer fn Referrer(&self) -> USVString { let r = self.request.borrow(); USVString(match r.referrer { NetTraitsRequestReferrer::NoReferrer => String::from("no-referrer"), NetTraitsRequestReferrer::Client => String::from("about:client"), NetTraitsRequestReferrer::ReferrerUrl(ref u) => { let u_c = u.clone(); u_c.into_string() } }) } // https://fetch.spec.whatwg.org/#dom-request-referrerpolicy fn ReferrerPolicy(&self) -> ReferrerPolicy { self.request.borrow().referrer_policy.map(|m| m.into()).unwrap_or(ReferrerPolicy::_empty) } // https://fetch.spec.whatwg.org/#dom-request-mode fn Mode(&self) -> RequestMode { self.request.borrow().mode.into() } // https://fetch.spec.whatwg.org/#dom-request-credentials fn Credentials(&self) -> RequestCredentials { let r = self.request.borrow().clone(); r.credentials_mode.into() } // https://fetch.spec.whatwg.org/#dom-request-cache fn Cache(&self) -> RequestCache { let r = self.request.borrow().clone(); r.cache_mode.into() } // https://fetch.spec.whatwg.org/#dom-request-redirect fn Redirect(&self) -> RequestRedirect { let r = self.request.borrow().clone(); r.redirect_mode.into() } // https://fetch.spec.whatwg.org/#dom-request-integrity fn Integrity(&self) -> DOMString { let r = self.request.borrow(); DOMString::from_string(r.integrity_metadata.clone()) } // https://fetch.spec.whatwg.org/#dom-body-bodyused fn BodyUsed(&self) -> bool { self.body_used.get() } // https://fetch.spec.whatwg.org/#dom-request-clone fn Clone(&self) -> Fallible> { // Step 1 if request_is_locked(self) { return Err(Error::Type("Request is locked".to_string())); } if request_is_disturbed(self) { return Err(Error::Type("Request is disturbed".to_string())); } // Step 2 Request::clone_from(self) } #[allow(unrooted_must_root)] // https://fetch.spec.whatwg.org/#dom-body-text fn Text(&self) -> Rc { consume_body(self, BodyType::Text) } #[allow(unrooted_must_root)] // https://fetch.spec.whatwg.org/#dom-body-blob fn Blob(&self) -> Rc { consume_body(self, BodyType::Blob) } #[allow(unrooted_must_root)] // https://fetch.spec.whatwg.org/#dom-body-formdata fn FormData(&self) -> Rc { consume_body(self, BodyType::FormData) } #[allow(unrooted_must_root)] // https://fetch.spec.whatwg.org/#dom-body-json fn Json(&self) -> Rc { consume_body(self, BodyType::Json) } } impl BodyOperations for Request { fn get_body_used(&self) -> bool { self.BodyUsed() } fn set_body_promise(&self, p: &Rc, body_type: BodyType) { assert!(self.body_promise.borrow().is_none()); self.body_used.set(true); *self.body_promise.borrow_mut() = Some((p.clone(), body_type)); } fn is_locked(&self) -> bool { self.locked() } fn take_body(&self) -> Option> { let mut request = self.request.borrow_mut(); let body = request.body.take(); Some(body.unwrap_or(vec![])) } fn get_mime_type(&self) -> Ref> { self.mime_type.borrow() } } impl Into for RequestCache { fn into(self) -> NetTraitsRequestCache { match self { RequestCache::Default => NetTraitsRequestCache::Default, RequestCache::No_store => NetTraitsRequestCache::NoStore, RequestCache::Reload => NetTraitsRequestCache::Reload, RequestCache::No_cache => NetTraitsRequestCache::NoCache, RequestCache::Force_cache => NetTraitsRequestCache::ForceCache, RequestCache::Only_if_cached => NetTraitsRequestCache::OnlyIfCached, } } } impl Into for NetTraitsRequestCache { fn into(self) -> RequestCache { match self { NetTraitsRequestCache::Default => RequestCache::Default, NetTraitsRequestCache::NoStore => RequestCache::No_store, NetTraitsRequestCache::Reload => RequestCache::Reload, NetTraitsRequestCache::NoCache => RequestCache::No_cache, NetTraitsRequestCache::ForceCache => RequestCache::Force_cache, NetTraitsRequestCache::OnlyIfCached => RequestCache::Only_if_cached, } } } impl Into for RequestCredentials { fn into(self) -> NetTraitsRequestCredentials { match self { RequestCredentials::Omit => NetTraitsRequestCredentials::Omit, RequestCredentials::Same_origin => NetTraitsRequestCredentials::CredentialsSameOrigin, RequestCredentials::Include => NetTraitsRequestCredentials::Include, } } } impl Into for NetTraitsRequestCredentials { fn into(self) -> RequestCredentials { match self { NetTraitsRequestCredentials::Omit => RequestCredentials::Omit, NetTraitsRequestCredentials::CredentialsSameOrigin => RequestCredentials::Same_origin, NetTraitsRequestCredentials::Include => RequestCredentials::Include, } } } impl Into for RequestDestination { fn into(self) -> NetTraitsRequestDestination { match self { RequestDestination::_empty => NetTraitsRequestDestination::None, RequestDestination::Document => NetTraitsRequestDestination::Document, RequestDestination::Embed => NetTraitsRequestDestination::Embed, RequestDestination::Font => NetTraitsRequestDestination::Font, RequestDestination::Image => NetTraitsRequestDestination::Image, RequestDestination::Manifest => NetTraitsRequestDestination::Manifest, RequestDestination::Media => NetTraitsRequestDestination::Media, RequestDestination::Object => NetTraitsRequestDestination::Object, RequestDestination::Report => NetTraitsRequestDestination::Report, RequestDestination::Script => NetTraitsRequestDestination::Script, RequestDestination::Serviceworker => NetTraitsRequestDestination::ServiceWorker, RequestDestination::Sharedworker => NetTraitsRequestDestination::SharedWorker, RequestDestination::Style => NetTraitsRequestDestination::Style, RequestDestination::Worker => NetTraitsRequestDestination::Worker, RequestDestination::Xslt => NetTraitsRequestDestination::XSLT, } } } impl Into for NetTraitsRequestDestination { fn into(self) -> RequestDestination { match self { NetTraitsRequestDestination::None => RequestDestination::_empty, NetTraitsRequestDestination::Document => RequestDestination::Document, NetTraitsRequestDestination::Embed => RequestDestination::Embed, NetTraitsRequestDestination::Font => RequestDestination::Font, NetTraitsRequestDestination::Image => RequestDestination::Image, NetTraitsRequestDestination::Manifest => RequestDestination::Manifest, NetTraitsRequestDestination::Media => RequestDestination::Media, NetTraitsRequestDestination::Object => RequestDestination::Object, NetTraitsRequestDestination::Report => RequestDestination::Report, NetTraitsRequestDestination::Script => RequestDestination::Script, NetTraitsRequestDestination::ServiceWorker => RequestDestination::Serviceworker, NetTraitsRequestDestination::SharedWorker => RequestDestination::Sharedworker, NetTraitsRequestDestination::Style => RequestDestination::Style, NetTraitsRequestDestination::XSLT => RequestDestination::Xslt, NetTraitsRequestDestination::Worker => RequestDestination::Worker, } } } impl Into for RequestType { fn into(self) -> NetTraitsRequestType { match self { RequestType::_empty => NetTraitsRequestType::None, RequestType::Audio => NetTraitsRequestType::Audio, RequestType::Font => NetTraitsRequestType::Font, RequestType::Image => NetTraitsRequestType::Image, RequestType::Script => NetTraitsRequestType::Script, RequestType::Style => NetTraitsRequestType::Style, RequestType::Track => NetTraitsRequestType::Track, RequestType::Video => NetTraitsRequestType::Video, } } } impl Into for NetTraitsRequestType { fn into(self) -> RequestType { match self { NetTraitsRequestType::None => RequestType::_empty, NetTraitsRequestType::Audio => RequestType::Audio, NetTraitsRequestType::Font => RequestType::Font, NetTraitsRequestType::Image => RequestType::Image, NetTraitsRequestType::Script => RequestType::Script, NetTraitsRequestType::Style => RequestType::Style, NetTraitsRequestType::Track => RequestType::Track, NetTraitsRequestType::Video => RequestType::Video, } } } impl Into for RequestMode { fn into(self) -> NetTraitsRequestMode { match self { RequestMode::Navigate => NetTraitsRequestMode::Navigate, RequestMode::Same_origin => NetTraitsRequestMode::SameOrigin, RequestMode::No_cors => NetTraitsRequestMode::NoCors, RequestMode::Cors => NetTraitsRequestMode::CorsMode, } } } impl Into for NetTraitsRequestMode { fn into(self) -> RequestMode { match self { NetTraitsRequestMode::Navigate => RequestMode::Navigate, NetTraitsRequestMode::SameOrigin => RequestMode::Same_origin, NetTraitsRequestMode::NoCors => RequestMode::No_cors, NetTraitsRequestMode::CorsMode => RequestMode::Cors, NetTraitsRequestMode::WebSocket => unreachable!("Websocket request mode should never be exposed to Dom"), } } } // TODO // When whatwg/fetch PR #346 is merged, fix this. impl Into for ReferrerPolicy { fn into(self) -> MsgReferrerPolicy { match self { ReferrerPolicy::_empty => MsgReferrerPolicy::NoReferrer, ReferrerPolicy::No_referrer => MsgReferrerPolicy::NoReferrer, ReferrerPolicy::No_referrer_when_downgrade => MsgReferrerPolicy::NoReferrerWhenDowngrade, ReferrerPolicy::Origin => MsgReferrerPolicy::Origin, ReferrerPolicy::Origin_when_cross_origin => MsgReferrerPolicy::OriginWhenCrossOrigin, ReferrerPolicy::Unsafe_url => MsgReferrerPolicy::UnsafeUrl, ReferrerPolicy::Strict_origin => MsgReferrerPolicy::StrictOrigin, ReferrerPolicy::Strict_origin_when_cross_origin => MsgReferrerPolicy::StrictOriginWhenCrossOrigin, } } } impl Into for MsgReferrerPolicy { fn into(self) -> ReferrerPolicy { match self { MsgReferrerPolicy::NoReferrer => ReferrerPolicy::No_referrer, MsgReferrerPolicy::NoReferrerWhenDowngrade => ReferrerPolicy::No_referrer_when_downgrade, MsgReferrerPolicy::Origin => ReferrerPolicy::Origin, MsgReferrerPolicy::SameOrigin => ReferrerPolicy::Origin, MsgReferrerPolicy::OriginWhenCrossOrigin => ReferrerPolicy::Origin_when_cross_origin, MsgReferrerPolicy::UnsafeUrl => ReferrerPolicy::Unsafe_url, MsgReferrerPolicy::StrictOrigin => ReferrerPolicy::Strict_origin, MsgReferrerPolicy::StrictOriginWhenCrossOrigin => ReferrerPolicy::Strict_origin_when_cross_origin, } } } impl Into for RequestRedirect { fn into(self) -> NetTraitsRequestRedirect { match self { RequestRedirect::Follow => NetTraitsRequestRedirect::Follow, RequestRedirect::Error => NetTraitsRequestRedirect::Error, RequestRedirect::Manual => NetTraitsRequestRedirect::Manual, } } } impl Into for NetTraitsRequestRedirect { fn into(self) -> RequestRedirect { match self { NetTraitsRequestRedirect::Follow => RequestRedirect::Follow, NetTraitsRequestRedirect::Error => RequestRedirect::Error, NetTraitsRequestRedirect::Manual => RequestRedirect::Manual, } } } impl Clone for HeadersInit { fn clone(&self) -> HeadersInit { match self { &HeadersInit::Headers(ref h) => HeadersInit::Headers(h.clone()), &HeadersInit::ByteStringSequenceSequence(ref b) => HeadersInit::ByteStringSequenceSequence(b.clone()), &HeadersInit::StringByteStringRecord(ref m) => HeadersInit::StringByteStringRecord(m.clone()), } } }