Update steps comment to match latest (2023-04-14) spec

This commit is contained in:
cybai 2023-04-14 14:32:28 +09:00
parent 445c90e5c5
commit c4882aab7e
3 changed files with 81 additions and 97 deletions

View file

@ -272,10 +272,6 @@ impl Headers {
self.guard.get() self.guard.get()
} }
pub fn empty_header_list(&self) {
*self.header_list.borrow_mut() = HyperHeaders::new();
}
pub fn set_headers(&self, hyper_headers: HyperHeaders) { pub fn set_headers(&self, hyper_headers: HyperHeaders) {
*self.header_list.borrow_mut() = hyper_headers; *self.header_list.borrow_mut() = hyper_headers;
} }

View file

@ -79,69 +79,71 @@ impl Request {
// Step 2 // Step 2
let mut fallback_mode: Option<NetTraitsRequestMode> = None; let mut fallback_mode: Option<NetTraitsRequestMode> = None;
// Step 3 // FIXME(cybai): As the spec changed in https://github.com/whatwg/fetch/pull/1153,
// we will need to change the default value of credentials for
// NetTraitsRequest and then remove fallback here.
let mut fallback_credentials: Option<NetTraitsRequestCredentials> = None; let mut fallback_credentials: Option<NetTraitsRequestCredentials> = None;
// Step 4 // Step 3
let base_url = global.api_base_url(); let base_url = global.api_base_url();
// Step 5 TODO: "Let signal be null." // Step 4 TODO: "Let signal be null."
match input { match input {
// Step 6 // Step 5
RequestInfo::USVString(USVString(ref usv_string)) => { RequestInfo::USVString(USVString(ref usv_string)) => {
// Step 6.1 // Step 5.1
let parsed_url = base_url.join(&usv_string); let parsed_url = base_url.join(&usv_string);
// Step 6.2 // Step 5.2
if parsed_url.is_err() { 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 6.3 // Step 5.3
let url = parsed_url.unwrap(); let url = parsed_url.unwrap();
if includes_credentials(&url) { if includes_credentials(&url) {
return Err(Error::Type("Url includes credentials".to_string())); return Err(Error::Type("Url includes credentials".to_string()));
} }
// Step 6.4 // Step 5.4
temporary_request = net_request_from_global(global, url); temporary_request = net_request_from_global(global, url);
// Step 6.5 // Step 5.5
fallback_mode = Some(NetTraitsRequestMode::CorsMode); fallback_mode = Some(NetTraitsRequestMode::CorsMode);
// Step 6.6 // FIXME(cybai): remove this line when we can remove the fallback of credentials
fallback_credentials = Some(NetTraitsRequestCredentials::CredentialsSameOrigin); fallback_credentials = Some(NetTraitsRequestCredentials::CredentialsSameOrigin);
}, },
// Step 7 // Step 6
RequestInfo::Request(ref input_request) => { RequestInfo::Request(ref input_request) => {
// This looks like Step 38 // This looks like Step 38
// TODO do this in the right place to not mask other errors // TODO do this in the right place to not mask other errors
if request_is_disturbed(input_request) || request_is_locked(input_request) { 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 7.1 // Step 6.1
temporary_request = input_request.request.borrow().clone(); temporary_request = input_request.request.borrow().clone();
// Step 7.2 TODO: "Set signal to input's signal." // Step 6.2 TODO: "Set signal to input's signal."
}, },
} }
// Step 8 // Step 7
// TODO: `entry settings object` is not implemented yet. // TODO: `entry settings object` is not implemented yet.
let origin = base_url.origin(); let origin = base_url.origin();
// Step 9 // Step 8
let mut window = Window::Client; let mut window = Window::Client;
// Step 10 // Step 9
// TODO: `environment settings object` is not implemented in Servo yet. // TODO: `environment settings object` is not implemented in Servo yet.
// Step 11 // Step 10
if !init.window.handle().is_null_or_undefined() { 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 12 // Step 11
if !init.window.handle().is_undefined() { if !init.window.handle().is_undefined() {
window = Window::NoWindow; window = Window::NoWindow;
} }
// Step 13 // Step 12
let mut request: NetTraitsRequest; let mut request: NetTraitsRequest;
request = net_request_from_global(global, temporary_request.current_url()); request = net_request_from_global(global, temporary_request.current_url());
request.method = temporary_request.method; request.method = temporary_request.method;
@ -158,7 +160,7 @@ impl Request {
request.redirect_mode = temporary_request.redirect_mode; request.redirect_mode = temporary_request.redirect_mode;
request.integrity_metadata = temporary_request.integrity_metadata; request.integrity_metadata = temporary_request.integrity_metadata;
// Step 14 // Step 13
if init.body.is_some() || if init.body.is_some() ||
init.cache.is_some() || init.cache.is_some() ||
init.credentials.is_some() || init.credentials.is_some() ||
@ -171,33 +173,33 @@ impl Request {
init.referrerPolicy.is_some() || init.referrerPolicy.is_some() ||
!init.window.handle().is_undefined() !init.window.handle().is_undefined()
{ {
// Step 14.1 // Step 13.1
if request.mode == NetTraitsRequestMode::Navigate { if request.mode == NetTraitsRequestMode::Navigate {
request.mode = NetTraitsRequestMode::SameOrigin; request.mode = NetTraitsRequestMode::SameOrigin;
} }
// Step 14.2 TODO: "Unset request's reload-navigation flag." // Step 13.2 TODO: "Unset request's reload-navigation flag."
// Step 14.3 TODO: "Unset request's history-navigation flag." // Step 13.3 TODO: "Unset request's history-navigation flag."
// Step 14.4 // Step 13.4
request.referrer = global.get_referrer(); request.referrer = global.get_referrer();
// Step 14.5 // Step 13.5
request.referrer_policy = None; request.referrer_policy = None;
} }
// Step 15 // Step 14
if let Some(init_referrer) = init.referrer.as_ref() { if let Some(init_referrer) = init.referrer.as_ref() {
// Step 15.1 // Step 14.1
let ref referrer = init_referrer.0; let ref referrer = init_referrer.0;
// Step 15.2 // Step 14.2
if referrer.is_empty() { if referrer.is_empty() {
request.referrer = NetTraitsRequestReferrer::NoReferrer; request.referrer = NetTraitsRequestReferrer::NoReferrer;
} else { } else {
// Step 15.3.1 // Step 14.3.1
let parsed_referrer = base_url.join(referrer); let parsed_referrer = base_url.join(referrer);
// Step 15.3.2 // Step 14.3.2
if parsed_referrer.is_err() { 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 15.3.3 // Step 14.3.3
if let Ok(parsed_referrer) = parsed_referrer { if let Ok(parsed_referrer) = parsed_referrer {
if (parsed_referrer.cannot_be_a_base() && if (parsed_referrer.cannot_be_a_base() &&
parsed_referrer.scheme() == "about" && parsed_referrer.scheme() == "about" &&
@ -206,55 +208,54 @@ impl Request {
{ {
request.referrer = global.get_referrer(); request.referrer = global.get_referrer();
} else { } else {
// Step 15.3.4 // Step 14.3.4
request.referrer = NetTraitsRequestReferrer::ReferrerUrl(parsed_referrer); request.referrer = NetTraitsRequestReferrer::ReferrerUrl(parsed_referrer);
} }
} }
} }
} }
// Step 16 // Step 15
if let Some(init_referrerpolicy) = init.referrerPolicy.as_ref() { if let Some(init_referrerpolicy) = init.referrerPolicy.as_ref() {
let init_referrer_policy = init_referrerpolicy.clone().into(); let init_referrer_policy = init_referrerpolicy.clone().into();
request.referrer_policy = Some(init_referrer_policy); request.referrer_policy = Some(init_referrer_policy);
} }
// Step 17 // Step 16
let mode = init let mode = init
.mode .mode
.as_ref() .as_ref()
.map(|m| m.clone().into()) .map(|m| m.clone().into())
.or(fallback_mode); .or(fallback_mode);
// Step 18 // Step 17
if let Some(NetTraitsRequestMode::Navigate) = mode { if let Some(NetTraitsRequestMode::Navigate) = mode {
return Err(Error::Type("Request mode is Navigate".to_string())); return Err(Error::Type("Request mode is Navigate".to_string()));
} }
// Step 19 // Step 18
if let Some(m) = mode { if let Some(m) = mode {
request.mode = m; request.mode = m;
} }
// Step 20 // Step 19
let credentials = init let credentials = init
.credentials .credentials
.as_ref() .as_ref()
.map(|m| m.clone().into()) .map(|m| m.clone().into())
.or(fallback_credentials); .or(fallback_credentials);
// Step 21
if let Some(c) = credentials { if let Some(c) = credentials {
request.credentials_mode = c; request.credentials_mode = c;
} }
// Step 22 // Step 20
if let Some(init_cache) = init.cache.as_ref() { if let Some(init_cache) = init.cache.as_ref() {
let cache = init_cache.clone().into(); let cache = init_cache.clone().into();
request.cache_mode = cache; request.cache_mode = cache;
} }
// Step 23 // Step 21
if request.cache_mode == NetTraitsRequestCache::OnlyIfCached { if request.cache_mode == NetTraitsRequestCache::OnlyIfCached {
if request.mode != NetTraitsRequestMode::SameOrigin { if request.mode != NetTraitsRequestMode::SameOrigin {
return Err(Error::Type( return Err(Error::Type(
@ -263,44 +264,46 @@ impl Request {
} }
} }
// Step 24 // Step 22
if let Some(init_redirect) = init.redirect.as_ref() { if let Some(init_redirect) = init.redirect.as_ref() {
let redirect = init_redirect.clone().into(); let redirect = init_redirect.clone().into();
request.redirect_mode = redirect; request.redirect_mode = redirect;
} }
// Step 25 // Step 23
if let Some(init_integrity) = init.integrity.as_ref() { if let Some(init_integrity) = init.integrity.as_ref() {
let integrity = init_integrity.clone().to_string(); let integrity = init_integrity.clone().to_string();
request.integrity_metadata = integrity; request.integrity_metadata = integrity;
} }
// Step 26 TODO: "If init["keepalive"] exists..." // Step 24 TODO: "If init["keepalive"] exists..."
// Step 27.1 // Step 25.1
if let Some(init_method) = init.method.as_ref() { if let Some(init_method) = init.method.as_ref() {
// Step 27.2
if !is_method(&init_method) { if !is_method(&init_method) {
return Err(Error::Type("Method is not a method".to_string())); return Err(Error::Type("Method is not a method".to_string()));
} }
// Step 25.2
if is_forbidden_method(&init_method) { if is_forbidden_method(&init_method) {
return Err(Error::Type("Method is forbidden".to_string())); return Err(Error::Type("Method is forbidden".to_string()));
} }
// Step 27.3 // Step 25.3
let method = match init_method.as_str() { 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)))?, .map_err(|e| Error::Type(format!("Method is not valid: {:?}", e)))?,
None => return Err(Error::Type("Method is not a valid UTF8".to_string())), None => return Err(Error::Type("Method is not a valid UTF8".to_string())),
}; };
// Step 27.4 // Step 25.4
request.method = method; request.method = method;
} }
// Step 28 TODO: "If init["signal"] exists..." // Step 26 TODO: "If init["signal"] exists..."
// Step 27 TODO: "If init["priority"] exists..."
// Step 29 // Step 28
let r = Request::from_net_request(global, request); let r = Request::from_net_request(global, request);
// Step 29 TODO: "Set this's signal to new AbortSignal object..."
// Step 30 TODO: "If signal is not null..." // Step 30 TODO: "If signal is not null..."
// Step 31 // Step 31
@ -308,7 +311,7 @@ impl Request {
// hasn't had any other way to initialize its headers // hasn't had any other way to initialize its headers
r.headers.or_init(|| Headers::for_request(&r.global())); r.headers.or_init(|| Headers::for_request(&r.global()));
// Step 32 - but spec says this should only be when non-empty init? // Step 33 - but spec says this should only be when non-empty init?
let headers_copy = init let headers_copy = init
.headers .headers
.as_ref() .as_ref()
@ -321,30 +324,30 @@ impl Request {
}, },
}); });
// Step 32.3 // Step 33.3
// We cannot empty `r.Headers().header_list` because // We cannot empty `r.Headers().header_list` because
// we would undo the Step 27 above. One alternative is to set // we would undo the Step 25 above. One alternative is to set
// `headers_copy` as a deep copy of `r.Headers()`. However, // `headers_copy` as a deep copy of `r.Headers()`. However,
// `r.Headers()` is a `DomRoot<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 // to obtain a mutable reference to `r.Headers()`. Without the
// mutable reference, we cannot mutate `r.Headers()` to be the // mutable reference, we cannot mutate `r.Headers()` to be the
// deep copied headers in Step 27. // deep copied headers in Step 25.
// Step 32.4 // Step 32
if r.request.borrow().mode == NetTraitsRequestMode::NoCors { if r.request.borrow().mode == NetTraitsRequestMode::NoCors {
let borrowed_request = r.request.borrow(); let borrowed_request = r.request.borrow();
// Step 32.4.1 // Step 32.1
if !is_cors_safelisted_method(&borrowed_request.method) { if !is_cors_safelisted_method(&borrowed_request.method) {
return Err(Error::Type( return Err(Error::Type(
"The mode is 'no-cors' but the method is not a cors-safelisted method" "The mode is 'no-cors' but the method is not a cors-safelisted method"
.to_string(), .to_string(),
)); ));
} }
// Step 32.4.2 // Step 32.2
r.Headers().set_guard(Guard::RequestNoCors); r.Headers().set_guard(Guard::RequestNoCors);
} }
// Step 32.5 // Step 33.5
match headers_copy { match headers_copy {
None => { None => {
// This is equivalent to the specification's concept of // This is equivalent to the specification's concept of
@ -358,11 +361,11 @@ impl Request {
Some(headers_copy) => r.Headers().fill(Some(headers_copy))?, Some(headers_copy) => r.Headers().fill(Some(headers_copy))?,
} }
// Step 32.5-6 depending on how we got here // Step 33.5 depending on how we got here
// Copy the headers list onto the headers of net_traits::Request // Copy the headers list onto the headers of net_traits::Request
r.request.borrow_mut().headers = r.Headers().get_headers_list(); r.request.borrow_mut().headers = r.Headers().get_headers_list();
// Step 33 // Step 34
let mut input_body = if let RequestInfo::Request(ref mut input_request) = input { let mut input_body = if let RequestInfo::Request(ref mut input_request) = input {
let mut input_request_request = input_request.request.borrow_mut(); let mut input_request_request = input_request.request.borrow_mut();
input_request_request.body.take() input_request_request.body.take()
@ -370,7 +373,7 @@ impl Request {
None None
}; };
// Step 34 // Step 35
if let Some(init_body_option) = init.body.as_ref() { if let Some(init_body_option) = init.body.as_ref() {
if init_body_option.is_some() || input_body.is_some() { if init_body_option.is_some() || input_body.is_some() {
let req = r.request.borrow(); let req = r.request.borrow();
@ -391,14 +394,14 @@ impl Request {
} }
} }
// Step 35-36 // Step 36-37
if let Some(Some(ref init_body)) = init.body { if let Some(Some(ref init_body)) = init.body {
// Step 36.2 TODO "If init["keepalive"] exists and is true..." // Step 37.1 TODO "If init["keepalive"] exists and is true..."
// Step 36.3 // Step 37.2
let mut extracted_body = init_body.extract(global)?; let mut extracted_body = init_body.extract(global)?;
// Step 36.4 // Step 37.3
if let Some(contents) = extracted_body.content_type.take() { if let Some(contents) = extracted_body.content_type.take() {
let ct_header_name = b"Content-Type"; let ct_header_name = b"Content-Type";
if !r if !r
@ -412,6 +415,7 @@ impl Request {
ByteString::new(ct_header_val.to_vec()), ByteString::new(ct_header_val.to_vec()),
)?; )?;
// Step 37.4
// In Servo r.Headers's header list isn't a pointer to // 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 // the same actual list as r.request's, and so we need to
// append to both lists to keep them in sync. // append to both lists to keep them in sync.
@ -429,19 +433,16 @@ impl Request {
input_body = Some(net_body); input_body = Some(net_body);
} }
// Step 37 "TODO if body is non-null and body's source is null..." // Step 38 is done earlier
// Step 39 "TODO if body is non-null and body's source is null..."
// This looks like where we need to set the use-preflight flag // 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. // if the request has a body and nothing else has set the flag.
// Step 38 is done earlier // Step 40 is done earlier
// Step 39
// TODO: `ReadableStream` object is not implemented in Servo yet.
// Step 40
r.request.borrow_mut().body = input_body;
// Step 41 // Step 41
r.request.borrow_mut().body = input_body;
// Step 42 // Step 42
Ok(r) Ok(r)

View file

@ -77,6 +77,7 @@ impl Response {
reflect_dom_object(Box::new(Response::new_inherited(global)), global) reflect_dom_object(Box::new(Response::new_inherited(global)), global)
} }
// https://fetch.spec.whatwg.org/#initialize-a-response
pub fn Constructor( pub fn Constructor(
global: &GlobalScope, global: &GlobalScope,
body: Option<BodyInit>, body: Option<BodyInit>,
@ -98,34 +99,29 @@ impl Response {
)); ));
} }
// Step 3
let r = Response::new(global); let r = Response::new(global);
// Step 4 // Step 3
*r.status.borrow_mut() = Some(StatusCode::from_u16(init.status).unwrap()); *r.status.borrow_mut() = Some(StatusCode::from_u16(init.status).unwrap());
// Step 5 // Step 4
*r.raw_status.borrow_mut() = Some((init.status, init.statusText.clone().into())); *r.raw_status.borrow_mut() = Some((init.status, init.statusText.clone().into()));
// Step 6 // Step 5
if let Some(ref headers_member) = init.headers { if let Some(ref headers_member) = init.headers {
// Step 6.1
r.Headers().empty_header_list();
// Step 6.2
r.Headers().fill(Some(headers_member.clone()))?; r.Headers().fill(Some(headers_member.clone()))?;
} }
// Step 7 // Step 6
if let Some(ref body) = body { if let Some(ref body) = body {
// Step 7.1 // Step 6.1
if is_null_body_status(init.status) { if is_null_body_status(init.status) {
return Err(Error::Type( return Err(Error::Type(
"Body is non-null but init's status member is a null body status".to_string(), "Body is non-null but init's status member is a null body status".to_string(),
)); ));
}; };
// Step 7.3 // Step 6.2
let ExtractedBody { let ExtractedBody {
stream, stream,
total_bytes: _, total_bytes: _,
@ -135,7 +131,7 @@ impl Response {
r.body_stream.set(Some(&*stream)); r.body_stream.set(Some(&*stream));
// Step 7.4 // Step 6.3
if let Some(content_type_contents) = content_type { if let Some(content_type_contents) = content_type {
if !r if !r
.Headers() .Headers()
@ -150,15 +146,6 @@ impl Response {
}; };
} }
// Step 8
// Step 9
// TODO: `entry settings object` is not implemented in Servo yet.
// Step 10
// TODO: Write this step once Promises are merged in
// Step 11
Ok(r) Ok(r)
} }