diff options
author | yvt <i@yvt.jp> | 2021-07-10 17:24:27 +0900 |
---|---|---|
committer | yvt <i@yvt.jp> | 2021-07-10 17:55:42 +0900 |
commit | 01a7de50ab1843d85295f9dccad7f4c099e7208c (patch) | |
tree | ee53fb6e8889deb7b880ee969e6c662e6128d210 /components/script/dom/request.rs | |
parent | ff8d2cdbbfc7a9dc7f38b7dd47cb350fde39388f (diff) | |
parent | 94b613fbdaa2b98f2179fc0bbda13c64e6fa0d38 (diff) | |
download | servo-01a7de50ab1843d85295f9dccad7f4c099e7208c.tar.gz servo-01a7de50ab1843d85295f9dccad7f4c099e7208c.zip |
Merge remote-tracking branch 'upstream/master' into feat-cow-infra
`tests/wpt/web-platform-tests/html/browsers/origin/cross-origin-objects/cross-origin-objects.html`
was reverted to the upstream version.
Diffstat (limited to 'components/script/dom/request.rs')
-rw-r--r-- | components/script/dom/request.rs | 660 |
1 files changed, 328 insertions, 332 deletions
diff --git a/components/script/dom/request.rs b/components/script/dom/request.rs index f33c9eed48d..e301d360cc4 100644 --- a/components/script/dom/request.rs +++ b/components/script/dom/request.rs @@ -1,34 +1,35 @@ /* 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::js::{MutNullableJS, Root}; -use dom::bindings::reflector::{DomObject, Reflector, reflect_dom_object}; -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; + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +use crate::body::Extractable; +use crate::body::{consume_body, BodyMixin, BodyType}; +use crate::dom::bindings::cell::DomRefCell; +use crate::dom::bindings::codegen::Bindings::HeadersBinding::{HeadersInit, HeadersMethods}; +use crate::dom::bindings::codegen::Bindings::RequestBinding::ReferrerPolicy; +use crate::dom::bindings::codegen::Bindings::RequestBinding::RequestCache; +use crate::dom::bindings::codegen::Bindings::RequestBinding::RequestCredentials; +use crate::dom::bindings::codegen::Bindings::RequestBinding::RequestDestination; +use crate::dom::bindings::codegen::Bindings::RequestBinding::RequestInfo; +use crate::dom::bindings::codegen::Bindings::RequestBinding::RequestInit; +use crate::dom::bindings::codegen::Bindings::RequestBinding::RequestMethods; +use crate::dom::bindings::codegen::Bindings::RequestBinding::RequestMode; +use crate::dom::bindings::codegen::Bindings::RequestBinding::RequestRedirect; +use crate::dom::bindings::error::{Error, Fallible}; +use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector}; +use crate::dom::bindings::root::{DomRoot, MutNullableDom}; +use crate::dom::bindings::str::{ByteString, DOMString, USVString}; +use crate::dom::bindings::trace::RootedTraceableBox; +use crate::dom::globalscope::GlobalScope; +use crate::dom::headers::{Guard, Headers}; +use crate::dom::promise::Promise; +use crate::dom::readablestream::ReadableStream; +use crate::script_runtime::JSContext as SafeJSContext; use dom_struct::dom_struct; -use hyper::method::Method as HttpMethod; -use net_traits::ReferrerPolicy as MsgReferrerPolicy; -use net_traits::request::{Origin, Window}; +use http::header::{HeaderName, HeaderValue}; +use http::method::InvalidMethod; +use http::Method as HttpMethod; +use js::jsapi::JSObject; use net_traits::request::CacheMode as NetTraitsRequestCache; use net_traits::request::CredentialsMode as NetTraitsRequestCredentials; use net_traits::request::Destination as NetTraitsRequestDestination; @@ -36,54 +37,44 @@ 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 net_traits::request::{Origin, Window}; +use net_traits::ReferrerPolicy as MsgReferrerPolicy; use servo_url::ServoUrl; -use std::ascii::AsciiExt; -use std::cell::{Cell, Ref}; +use std::ptr::NonNull; use std::rc::Rc; +use std::str::FromStr; #[dom_struct] pub struct Request { reflector_: Reflector, - request: DOMRefCell<NetTraitsRequest>, - body_used: Cell<bool>, - headers: MutNullableJS<Headers>, - mime_type: DOMRefCell<Vec<u8>>, - #[ignore_heap_size_of = "Rc"] - body_promise: DOMRefCell<Option<(Rc<Promise>, BodyType)>>, + request: DomRefCell<NetTraitsRequest>, + body_stream: MutNullableDom<ReadableStream>, + headers: MutNullableDom<Headers>, + mime_type: DomRefCell<Vec<u8>>, } impl Request { - fn new_inherited(global: &GlobalScope, - url: ServoUrl, - is_service_worker_global_scope: bool) -> Request { + fn new_inherited(global: &GlobalScope, url: ServoUrl) -> Request { Request { reflector_: Reflector::new(), - request: DOMRefCell::new( - net_request_from_global(global, - url, - is_service_worker_global_scope)), - body_used: Cell::new(false), + request: DomRefCell::new(net_request_from_global(global, url)), + body_stream: MutNullableDom::new(None), headers: Default::default(), - mime_type: DOMRefCell::new("".to_string().into_bytes()), - body_promise: DOMRefCell::new(None), + mime_type: DomRefCell::new("".to_string().into_bytes()), } } - pub fn new(global: &GlobalScope, - url: ServoUrl, - is_service_worker_global_scope: bool) -> Root<Request> { - reflect_dom_object(box Request::new_inherited(global, - url, - is_service_worker_global_scope), - global, RequestBinding::Wrap) + pub fn new(global: &GlobalScope, url: ServoUrl) -> DomRoot<Request> { + reflect_dom_object(Box::new(Request::new_inherited(global, url)), global) } // https://fetch.spec.whatwg.org/#dom-request - pub fn Constructor(global: &GlobalScope, - input: RequestInfo, - init: RootedTraceableBox<RequestInit>) - -> Fallible<Root<Request>> { + #[allow(non_snake_case)] + pub fn Constructor( + global: &GlobalScope, + mut input: RequestInfo, + init: RootedTraceableBox<RequestInit>, + ) -> Fallible<DomRoot<Request>> { // Step 1 let temporary_request: NetTraitsRequest; @@ -96,65 +87,65 @@ impl Request { // Step 4 let base_url = global.api_base_url(); + // Step 5 TODO: "Let signal be null." + match input { - // Step 5 + // Step 6 RequestInfo::USVString(USVString(ref usv_string)) => { - // Step 5.1 + // Step 6.1 let parsed_url = base_url.join(&usv_string); - // Step 5.2 + // Step 6.2 if parsed_url.is_err() { - return Err(Error::Type("Url could not be parsed".to_string())) + return Err(Error::Type("Url could not be parsed".to_string())); } - // Step 5.3 + // Step 6.3 let url = parsed_url.unwrap(); if includes_credentials(&url) { - return Err(Error::Type("Url includes credentials".to_string())) + return Err(Error::Type("Url includes credentials".to_string())); } - // Step 5.4 - temporary_request = net_request_from_global(global, - url, - false); - // Step 5.5 + // Step 6.4 + temporary_request = net_request_from_global(global, url); + // Step 6.5 fallback_mode = Some(NetTraitsRequestMode::CorsMode); - // Step 5.6 - fallback_credentials = Some(NetTraitsRequestCredentials::Omit); - } - // Step 6 + // Step 6.6 + fallback_credentials = Some(NetTraitsRequestCredentials::CredentialsSameOrigin); + }, + // Step 7 RequestInfo::Request(ref input_request) => { - // Step 6.1 + // This looks like Step 38 + // TODO do this in the right place to not mask other errors if request_is_disturbed(input_request) || request_is_locked(input_request) { - return Err(Error::Type("Input is disturbed or locked".to_string())) + return Err(Error::Type("Input is disturbed or locked".to_string())); } - // Step 6.2 + // Step 7.1 temporary_request = input_request.request.borrow().clone(); - } + // Step 7.2 TODO: "Set signal to input's signal." + }, } - // Step 7 + // Step 8 // TODO: `entry settings object` is not implemented yet. let origin = base_url.origin(); - // Step 8 + // Step 9 let mut window = Window::Client; - // Step 9 + // Step 10 // TODO: `environment settings object` is not implemented in Servo yet. - // Step 10 + // Step 11 if !init.window.handle().is_null_or_undefined() { - return Err(Error::Type("Window is present and is not null".to_string())) + return Err(Error::Type("Window is present and is not null".to_string())); } - // Step 11 + // Step 12 if !init.window.handle().is_undefined() { window = Window::NoWindow; } - // Step 12 + // Step 13 let mut request: NetTraitsRequest; - request = net_request_from_global(global, - temporary_request.current_url(), - false); + 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; @@ -169,7 +160,7 @@ impl Request { request.redirect_mode = temporary_request.redirect_mode; request.integrity_metadata = temporary_request.integrity_metadata; - // Step 13 + // Step 14 if init.body.is_some() || init.cache.is_some() || init.credentials.is_some() || @@ -180,273 +171,308 @@ impl Request { 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; + !init.window.handle().is_undefined() + { + // Step 14.1 + if request.mode == NetTraitsRequestMode::Navigate { + request.mode = NetTraitsRequestMode::SameOrigin; } + // Step 14.2 TODO: "Unset request's reload-navigation flag." + // Step 14.3 TODO: "Unset request's history-navigation flag." + // Step 14.4 + request.referrer = global.get_referrer(); + // Step 14.5 + request.referrer_policy = None; + } - // Step 14 + // Step 15 if let Some(init_referrer) = init.referrer.as_ref() { - // Step 14.1 + // Step 15.1 let ref referrer = init_referrer.0; - // Step 14.2 + // Step 15.2 if referrer.is_empty() { request.referrer = NetTraitsRequestReferrer::NoReferrer; } else { - // Step 14.3 + // Step 15.3.1 let parsed_referrer = base_url.join(referrer); - // Step 14.4 + // Step 15.3.2 if parsed_referrer.is_err() { - return Err(Error::Type( - "Failed to parse referrer url".to_string())); + return Err(Error::Type("Failed to parse referrer url".to_string())); } - // Step 14.5 + // Step 15.3.3 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); - } + parsed_referrer.origin() != origin + { + request.referrer = global.get_referrer(); + } else { + // Step 15.3.4 + request.referrer = NetTraitsRequestReferrer::ReferrerUrl(parsed_referrer); + } } } } - // Step 15 + // Step 16 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 + let mode = init + .mode + .as_ref() + .map(|m| m.clone().into()) + .or(fallback_mode); + + // Step 18 if let Some(NetTraitsRequestMode::Navigate) = mode { return Err(Error::Type("Request mode is Navigate".to_string())); } - // Step 18 + // Step 19 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 + let credentials = init + .credentials + .as_ref() + .map(|m| m.clone().into()) + .or(fallback_credentials); + + // Step 21 if let Some(c) = credentials { request.credentials_mode = c; } - // Step 21 + // Step 22 if let Some(init_cache) = init.cache.as_ref() { let cache = init_cache.clone().into(); request.cache_mode = cache; } - // Step 22 + // Step 23 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())); + "Cache is 'only-if-cached' and mode is not 'same-origin'".to_string(), + )); } } - // Step 23 + // Step 24 if let Some(init_redirect) = init.redirect.as_ref() { let redirect = init_redirect.clone().into(); request.redirect_mode = redirect; } - // Step 24 + // Step 25 if let Some(init_integrity) = init.integrity.as_ref() { let integrity = init_integrity.clone().to_string(); request.integrity_metadata = integrity; } - // Step 25 + // Step 26 TODO: "If init["keepalive"] exists..." + + // Step 27.1 if let Some(init_method) = init.method.as_ref() { - // Step 25.1 + // Step 27.2 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 + // Step 27.3 let method = match init_method.as_str() { - Some(s) => normalize_method(s), + Some(s) => normalize_method(s) + .map_err(|e| Error::Type(format!("Method is not valid: {:?}", e)))?, None => return Err(Error::Type("Method is not a valid UTF8".to_string())), }; - // Step 25.3 + // Step 27.4 request.method = method; } - // Step 26 - let r = Request::from_net_request(global, - false, - request); - r.headers.or_init(|| Headers::for_request(&r.global())); + // Step 28 TODO: "If init["signal"] exists..." - // Step 27 - let mut headers_copy = r.Headers(); + // Step 29 + let r = Request::from_net_request(global, request); - // Step 28 - if let Some(possible_header) = init.headers.as_ref() { - match possible_header { - &HeadersInit::Headers(ref init_headers) => { - headers_copy = Root::from_ref(&*init_headers); - } - &HeadersInit::ByteStringSequenceSequence(ref init_sequence) => { - try!(headers_copy.fill(Some( - HeadersInit::ByteStringSequenceSequence(init_sequence.clone())))); + // Step 30 TODO: "If signal is not null..." + + // Step 31 + // "or_init" looks unclear here, but it always enters the block since r + // hasn't had any other way to initialize its headers + r.headers.or_init(|| Headers::for_request(&r.global())); + + // Step 32 - but spec says this should only be when non-empty init? + let headers_copy = init + .headers + .as_ref() + .map(|possible_header| match possible_header { + HeadersInit::ByteStringSequenceSequence(init_sequence) => { + HeadersInit::ByteStringSequenceSequence(init_sequence.clone()) }, - &HeadersInit::ByteStringMozMap(ref init_map) => { - try!(headers_copy.fill(Some( - HeadersInit::ByteStringMozMap(init_map.clone())))); + HeadersInit::ByteStringByteStringRecord(init_map) => { + HeadersInit::ByteStringByteStringRecord(init_map.clone()) }, - } - } + }); - // Step 29 + // Step 32.3 // 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 `Root<T>`, and therefore it is difficult + // `r.Headers()` is a `DomRoot<T>`, 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 + // Step 32.4 if r.request.borrow().mode == NetTraitsRequestMode::NoCors { let borrowed_request = r.request.borrow(); - // Step 30.1 + // Step 32.4.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 - if !borrowed_request.integrity_metadata.is_empty() { - return Err(Error::Type("Integrity metadata is not an empty string".to_string())); + "The mode is 'no-cors' but the method is not a cors-safelisted method" + .to_string(), + )); } - // Step 30.3 + // Step 32.4.2 r.Headers().set_guard(Guard::RequestNoCors); } - // Step 31 - match init.headers { + // Step 32.5 + match headers_copy { 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 { - try!(r.Headers().fill(Some(HeadersInit::Headers(input_request.Headers())))); + r.Headers().copy_from_headers(input_request.Headers())?; } }, - Some(HeadersInit::Headers(_)) => try!(r.Headers().fill(Some(HeadersInit::Headers(headers_copy)))), - _ => {}, + Some(headers_copy) => r.Headers().fill(Some(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() + // Step 32.5-6 depending on how we got here + // Copy the headers list onto the headers of net_traits::Request + r.request.borrow_mut().headers = r.Headers().get_headers_list(); + + // Step 33 + let mut input_body = if let RequestInfo::Request(ref mut input_request) = input { + let mut input_request_request = input_request.request.borrow_mut(); + input_request_request.body.take() } else { None }; - // Step 33 + // Step 34 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())), + 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 + // Step 35-36 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() { - try!(r.Headers().Append(ByteString::new(b"Content-Type".to_vec()), - ByteString::new(contents.as_bytes().to_vec()))); + // Step 36.2 TODO "If init["keepalive"] exists and is true..." + + // Step 36.3 + let mut extracted_body = init_body.extract(global)?; + + // Step 36.4 + if let Some(contents) = extracted_body.content_type.take() { + let ct_header_name = b"Content-Type"; + if !r + .Headers() + .Has(ByteString::new(ct_header_name.to_vec())) + .unwrap() + { + let ct_header_val = contents.as_bytes(); + r.Headers().Append( + ByteString::new(ct_header_name.to_vec()), + ByteString::new(ct_header_val.to_vec()), + )?; + + // In Servo r.Headers's header list isn't a pointer to + // the same actual list as r.request's, and so we need to + // append to both lists to keep them in sync. + if let Ok(v) = HeaderValue::from_bytes(ct_header_val) { + r.request + .borrow_mut() + .headers + .insert(HeaderName::from_bytes(ct_header_name).unwrap(), v); + } } } + + let (net_body, stream) = extracted_body.into_net_request_body(); + r.body_stream.set(Some(&*stream)); + input_body = Some(net_body); } - // Step 35 + // Step 37 "TODO if body is non-null and body's source is null..." + // This looks like where we need to set the use-preflight flag + // if the request has a body and nothing else has set the flag. + + // Step 38 is done earlier + + // Step 39 + // TODO: `ReadableStream` object is not implemented in Servo yet. + + // Step 40 r.request.borrow_mut().body = input_body; - // Step 36 + // Step 41 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 + // Step 42 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, - is_service_worker_global_scope: bool, - net_request: NetTraitsRequest) -> Root<Request> { - let r = Request::new(global, - net_request.current_url(), - is_service_worker_global_scope); + fn from_net_request(global: &GlobalScope, net_request: NetTraitsRequest) -> DomRoot<Request> { + let r = Request::new(global, net_request.current_url()); *r.request.borrow_mut() = net_request; r } - fn clone_from(r: &Request) -> Fallible<Root<Request>> { + fn clone_from(r: &Request) -> Fallible<DomRoot<Request>> { let req = r.request.borrow(); let url = req.url(); - let is_service_worker_global_scope = req.is_service_worker_global_scope; - 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, is_service_worker_global_scope); + 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; - try!(r_clone.Headers().fill(Some(HeadersInit::Headers(r.Headers())))); + r_clone.Headers().copy_from_headers(r.Headers())?; r_clone.Headers().set_guard(headers_guard); Ok(r_clone) } @@ -456,43 +482,32 @@ impl Request { } } -fn net_request_from_global(global: &GlobalScope, - url: ServoUrl, - is_service_worker_global_scope: bool) -> NetTraitsRequest { +fn net_request_from_global(global: &GlobalScope, url: ServoUrl) -> NetTraitsRequest { let origin = Origin::Origin(global.get_url().origin()); + let https_state = global.get_https_state(); let pipeline_id = global.pipeline_id(); - NetTraitsRequest::new(url, - Some(origin), - is_service_worker_global_scope, - Some(pipeline_id)) + let referrer = global.get_referrer(); + NetTraitsRequest::new(url, Some(origin), referrer, Some(pipeline_id), https_state) } // https://fetch.spec.whatwg.org/#concept-method-normalize -fn normalize_method(m: &str) -> HttpMethod { - match m { - m if m.eq_ignore_ascii_case("DELETE") => HttpMethod::Delete, - m if m.eq_ignore_ascii_case("GET") => HttpMethod::Get, - m if m.eq_ignore_ascii_case("HEAD") => HttpMethod::Head, - m if m.eq_ignore_ascii_case("OPTIONS") => HttpMethod::Options, - m if m.eq_ignore_ascii_case("POST") => HttpMethod::Post, - m if m.eq_ignore_ascii_case("PUT") => HttpMethod::Put, - m => HttpMethod::Extension(m.to_string()), - } +fn normalize_method(m: &str) -> Result<HttpMethod, InvalidMethod> { + match_ignore_ascii_case! { m, + "delete" => return Ok(HttpMethod::DELETE), + "get" => return Ok(HttpMethod::GET), + "head" => return Ok(HttpMethod::HEAD), + "options" => return Ok(HttpMethod::OPTIONS), + "post" => return Ok(HttpMethod::POST), + "put" => return Ok(HttpMethod::PUT), + _ => (), + } + debug!("Method: {:?}", m); + HttpMethod::from_str(m) } // 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, - } + m.as_str().is_some() } // https://fetch.spec.whatwg.org/#forbidden-method @@ -507,9 +522,7 @@ fn is_forbidden_method(m: &ByteString) -> bool { // 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 + m == &HttpMethod::GET || m == &HttpMethod::HEAD || m == &HttpMethod::POST } // https://url.spec.whatwg.org/#include-credentials @@ -517,16 +530,14 @@ 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 +fn request_is_disturbed(input: &Request) -> bool { + input.is_disturbed() } -// 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 +fn request_is_locked(input: &Request) -> bool { + input.is_locked() } impl RequestMethods for Request { @@ -543,15 +554,10 @@ impl RequestMethods for Request { } // https://fetch.spec.whatwg.org/#dom-request-headers - fn Headers(&self) -> Root<Headers> { + fn Headers(&self) -> DomRoot<Headers> { 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() @@ -561,23 +567,27 @@ impl RequestMethods for Request { 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::NoReferrer => String::from(""), + 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) + 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() + self.request.borrow().mode.clone().into() } // https://fetch.spec.whatwg.org/#dom-request-credentials @@ -604,13 +614,18 @@ impl RequestMethods for Request { DOMString::from_string(r.integrity_metadata.clone()) } + /// <https://fetch.spec.whatwg.org/#dom-body-body> + fn GetBody(&self, _cx: SafeJSContext) -> Option<NonNull<JSObject>> { + self.body().map(|stream| stream.get_js_stream()) + } + // https://fetch.spec.whatwg.org/#dom-body-bodyused fn BodyUsed(&self) -> bool { - self.body_used.get() + self.is_disturbed() } // https://fetch.spec.whatwg.org/#dom-request-clone - fn Clone(&self) -> Fallible<Root<Request>> { + fn Clone(&self) -> Fallible<DomRoot<Request>> { // Step 1 if request_is_locked(self) { return Err(Error::Type("Request is locked".to_string())); @@ -623,54 +638,51 @@ impl RequestMethods for Request { Request::clone_from(self) } - #[allow(unrooted_must_root)] // https://fetch.spec.whatwg.org/#dom-body-text fn Text(&self) -> Rc<Promise> { consume_body(self, BodyType::Text) } - #[allow(unrooted_must_root)] // https://fetch.spec.whatwg.org/#dom-body-blob fn Blob(&self) -> Rc<Promise> { consume_body(self, BodyType::Blob) } - #[allow(unrooted_must_root)] // https://fetch.spec.whatwg.org/#dom-body-formdata fn FormData(&self) -> Rc<Promise> { consume_body(self, BodyType::FormData) } - #[allow(unrooted_must_root)] // https://fetch.spec.whatwg.org/#dom-body-json fn Json(&self) -> Rc<Promise> { consume_body(self, BodyType::Json) } -} -impl BodyOperations for Request { - fn get_body_used(&self) -> bool { - self.BodyUsed() + // https://fetch.spec.whatwg.org/#dom-body-arraybuffer + fn ArrayBuffer(&self) -> Rc<Promise> { + consume_body(self, BodyType::ArrayBuffer) } +} - fn set_body_promise(&self, p: &Rc<Promise>, 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)); +impl BodyMixin for Request { + fn is_disturbed(&self) -> bool { + let body_stream = self.body_stream.get(); + body_stream + .as_ref() + .map_or(false, |stream| stream.is_disturbed()) } fn is_locked(&self) -> bool { - self.locked() + let body_stream = self.body_stream.get(); + body_stream.map_or(false, |stream| stream.is_locked()) } - fn take_body(&self) -> Option<Vec<u8>> { - let mut request = self.request.borrow_mut(); - let body = request.body.take(); - Some(body.unwrap_or(vec![])) + fn body(&self) -> Option<DomRoot<ReadableStream>> { + self.body_stream.get() } - fn get_mime_type(&self) -> Ref<Vec<u8>> { - self.mime_type.borrow() + fn get_mime_type(&self) -> Vec<u8> { + self.mime_type.borrow().clone() } } @@ -724,20 +736,21 @@ impl Into<NetTraitsRequestDestination> for RequestDestination { fn into(self) -> NetTraitsRequestDestination { match self { RequestDestination::_empty => NetTraitsRequestDestination::None, + RequestDestination::Audio => NetTraitsRequestDestination::Audio, 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::Track => NetTraitsRequestDestination::Track, + RequestDestination::Video => NetTraitsRequestDestination::Video, RequestDestination::Worker => NetTraitsRequestDestination::Worker, - RequestDestination::Xslt => NetTraitsRequestDestination::XSLT, + RequestDestination::Xslt => NetTraitsRequestDestination::Xslt, } } } @@ -746,50 +759,26 @@ impl Into<RequestDestination> for NetTraitsRequestDestination { fn into(self) -> RequestDestination { match self { NetTraitsRequestDestination::None => RequestDestination::_empty, + NetTraitsRequestDestination::Audio => RequestDestination::Audio, 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::ServiceWorker | + NetTraitsRequestDestination::AudioWorklet | + NetTraitsRequestDestination::PaintWorklet => { + panic!("ServiceWorker request destination should not be exposed to DOM") + }, NetTraitsRequestDestination::SharedWorker => RequestDestination::Sharedworker, NetTraitsRequestDestination::Style => RequestDestination::Style, - NetTraitsRequestDestination::XSLT => RequestDestination::Xslt, + NetTraitsRequestDestination::Track => RequestDestination::Track, + NetTraitsRequestDestination::Video => RequestDestination::Video, NetTraitsRequestDestination::Worker => RequestDestination::Worker, - } - } -} - -impl Into<NetTraitsRequestType> 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<RequestType> 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, + NetTraitsRequestDestination::Xslt => RequestDestination::Xslt, } } } @@ -812,7 +801,9 @@ impl Into<RequestMode> for NetTraitsRequestMode { 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 JS"), + NetTraitsRequestMode::WebSocket { .. } => { + unreachable!("Websocket request mode should never be exposed to Dom") + }, } } } @@ -824,14 +815,17 @@ impl Into<MsgReferrerPolicy> for ReferrerPolicy { match self { ReferrerPolicy::_empty => MsgReferrerPolicy::NoReferrer, ReferrerPolicy::No_referrer => MsgReferrerPolicy::NoReferrer, - ReferrerPolicy::No_referrer_when_downgrade => - MsgReferrerPolicy::NoReferrerWhenDowngrade, + ReferrerPolicy::No_referrer_when_downgrade => { + MsgReferrerPolicy::NoReferrerWhenDowngrade + }, ReferrerPolicy::Origin => MsgReferrerPolicy::Origin, ReferrerPolicy::Origin_when_cross_origin => MsgReferrerPolicy::OriginWhenCrossOrigin, ReferrerPolicy::Unsafe_url => MsgReferrerPolicy::UnsafeUrl, + ReferrerPolicy::Same_origin => MsgReferrerPolicy::SameOrigin, ReferrerPolicy::Strict_origin => MsgReferrerPolicy::StrictOrigin, - ReferrerPolicy::Strict_origin_when_cross_origin => - MsgReferrerPolicy::StrictOriginWhenCrossOrigin, + ReferrerPolicy::Strict_origin_when_cross_origin => { + MsgReferrerPolicy::StrictOriginWhenCrossOrigin + }, } } } @@ -840,15 +834,17 @@ impl Into<ReferrerPolicy> for MsgReferrerPolicy { fn into(self) -> ReferrerPolicy { match self { MsgReferrerPolicy::NoReferrer => ReferrerPolicy::No_referrer, - MsgReferrerPolicy::NoReferrerWhenDowngrade => - ReferrerPolicy::No_referrer_when_downgrade, + 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::SameOrigin => ReferrerPolicy::Same_origin, MsgReferrerPolicy::StrictOrigin => ReferrerPolicy::Strict_origin, - MsgReferrerPolicy::StrictOriginWhenCrossOrigin => - ReferrerPolicy::Strict_origin_when_cross_origin, + MsgReferrerPolicy::StrictOriginWhenCrossOrigin => { + ReferrerPolicy::Strict_origin_when_cross_origin + }, } } } @@ -875,13 +871,13 @@ impl Into<RequestRedirect> for NetTraitsRequestRedirect { 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::ByteStringMozMap(ref m) => - HeadersInit::ByteStringMozMap(m.clone()), + match self { + &HeadersInit::ByteStringSequenceSequence(ref b) => { + HeadersInit::ByteStringSequenceSequence(b.clone()) + }, + &HeadersInit::ByteStringByteStringRecord(ref m) => { + HeadersInit::ByteStringByteStringRecord(m.clone()) + }, } } } |