Auto merge of #12700 - jeenalee:jeena-requestAPI, r=jdm

Implement the Request API

<!-- Please describe your changes on the following line: -->
This PR implements the [Request API](https://fetch.spec.whatwg.org/#request-class) for the Fetch API, including its attributes and constructor, and introduces changes in relevant files.

This Request integrates `net_traits::request::Request` and `dom::headers`.

There are few related TODOs and comments:
1. `net_traits::request::Request`'s `headers` field does not point to `dom::request::Request`'s `headers_reflector`.
2. Every Constructor step that involves `Readable Stream` object is not implemented.
3. Every Constructor step that involves `entry settings object` or `environment settings object` is not implemented.
4. `./mach build -d` does not report any error, but prints a few warnings about unused variables related to (1) and (2).
5. Enum `ReferrerPolicy` generated by `RequestBinding` does not match `net_traits::request::Request`'s implementation.
6. `Promise`s in Body webidl are commented out.

---
<!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: -->
- [X] `./mach build -d` does not report any errors
- [X] `./mach test-tidy` does not report any errors
- [X] These changes fix #11895 (github issue number if applicable).

<!-- Either: -->
- [ ] There are tests for these changes OR
- [X] These changes do not require tests  because tests for the Request API already exists, but this commit does not implement the interface fully.

<!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. -->

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/12700)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2016-08-12 23:54:49 -05:00 committed by GitHub
commit 78160bf3f9
18 changed files with 1082 additions and 399 deletions

View file

@ -10,7 +10,7 @@ use std::mem::swap;
use url::{Origin as UrlOrigin, Url};
/// An [initiator](https://fetch.spec.whatwg.org/#concept-request-initiator)
#[derive(Copy, Clone, PartialEq)]
#[derive(Copy, Clone, PartialEq, HeapSizeOf)]
pub enum Initiator {
None,
Download,
@ -20,14 +20,14 @@ pub enum Initiator {
}
/// A request [type](https://fetch.spec.whatwg.org/#concept-request-type)
#[derive(Copy, Clone, PartialEq)]
#[derive(Copy, Clone, PartialEq, HeapSizeOf)]
pub enum Type {
None, Audio, Font, Image,
Script, Style, Track, Video
}
/// A request [destination](https://fetch.spec.whatwg.org/#concept-request-destination)
#[derive(Copy, Clone, PartialEq, Serialize, Deserialize)]
#[derive(Copy, Clone, PartialEq, Serialize, Deserialize, HeapSizeOf)]
pub enum Destination {
None, Document, Embed, Font, Image, Manifest,
Media, Object, Report, Script, ServiceWorker,
@ -35,14 +35,14 @@ pub enum Destination {
}
/// A request [origin](https://fetch.spec.whatwg.org/#concept-request-origin)
#[derive(Clone, PartialEq, Debug)]
#[derive(Clone, PartialEq, Debug, HeapSizeOf)]
pub enum Origin {
Client,
Origin(UrlOrigin)
}
/// A [referer](https://fetch.spec.whatwg.org/#concept-request-referrer)
#[derive(Clone, PartialEq)]
#[derive(Clone, PartialEq, HeapSizeOf)]
pub enum Referer {
NoReferer,
/// Default referer if nothing is specified
@ -51,7 +51,7 @@ pub enum Referer {
}
/// A [request mode](https://fetch.spec.whatwg.org/#concept-request-mode)
#[derive(Copy, Clone, PartialEq, Serialize, Deserialize)]
#[derive(Copy, Clone, PartialEq, Serialize, Deserialize, HeapSizeOf)]
pub enum RequestMode {
Navigate,
SameOrigin,
@ -60,7 +60,7 @@ pub enum RequestMode {
}
/// Request [credentials mode](https://fetch.spec.whatwg.org/#concept-request-credentials-mode)
#[derive(Copy, Clone, PartialEq, Serialize, Deserialize)]
#[derive(Copy, Clone, PartialEq, Serialize, Deserialize, HeapSizeOf)]
pub enum CredentialsMode {
Omit,
CredentialsSameOrigin,
@ -68,7 +68,7 @@ pub enum CredentialsMode {
}
/// [Cache mode](https://fetch.spec.whatwg.org/#concept-request-cache-mode)
#[derive(Copy, Clone, PartialEq)]
#[derive(Copy, Clone, PartialEq, HeapSizeOf)]
pub enum CacheMode {
Default,
NoStore,
@ -79,7 +79,7 @@ pub enum CacheMode {
}
/// [Redirect mode](https://fetch.spec.whatwg.org/#concept-request-redirect-mode)
#[derive(Copy, Clone, PartialEq)]
#[derive(Copy, Clone, PartialEq, HeapSizeOf)]
pub enum RedirectMode {
Follow,
Error,
@ -87,7 +87,7 @@ pub enum RedirectMode {
}
/// [Response tainting](https://fetch.spec.whatwg.org/#concept-request-response-tainting)
#[derive(Copy, Clone, PartialEq)]
#[derive(Copy, Clone, PartialEq, HeapSizeOf)]
pub enum ResponseTainting {
Basic,
CORSTainting,
@ -95,7 +95,7 @@ pub enum ResponseTainting {
}
/// [Window](https://fetch.spec.whatwg.org/#concept-request-window)
#[derive(Copy, Clone, PartialEq)]
#[derive(Copy, Clone, PartialEq, HeapSizeOf)]
pub enum Window {
NoWindow,
Client,
@ -138,11 +138,13 @@ pub struct RequestInit {
}
/// A [Request](https://fetch.spec.whatwg.org/#requests) as defined by the Fetch spec
#[derive(Clone)]
#[derive(Clone, HeapSizeOf)]
pub struct Request {
#[ignore_heap_size_of = "Defined in hyper"]
pub method: RefCell<Method>,
pub local_urls_only: bool,
pub sandboxed_storage_area_urls: bool,
#[ignore_heap_size_of = "Defined in hyper"]
pub headers: RefCell<Headers>,
pub unsafe_request: bool,
pub body: RefCell<Option<Vec<u8>>>,

View file

@ -60,6 +60,7 @@ use msg::constellation_msg::{FrameType, PipelineId, SubpageId, WindowSizeType, R
use net_traits::filemanager_thread::{SelectedFileId, RelativePos};
use net_traits::image::base::{Image, ImageMetadata};
use net_traits::image_cache_thread::{ImageCacheChan, ImageCacheThread};
use net_traits::request::Request;
use net_traits::response::HttpsState;
use net_traits::storage_thread::StorageType;
use net_traits::{Metadata, NetworkError, ResourceThreads};
@ -325,6 +326,7 @@ no_jsmanaged_fields!(AttrIdentifier);
no_jsmanaged_fields!(AttrValue);
no_jsmanaged_fields!(ElementSnapshot);
no_jsmanaged_fields!(HttpsState);
no_jsmanaged_fields!(Request);
no_jsmanaged_fields!(SharedRt);
no_jsmanaged_fields!(TouchpadPressurePhase);
no_jsmanaged_fields!(USVString);

View file

@ -12,18 +12,19 @@ use dom::bindings::js::Root;
use dom::bindings::reflector::{Reflector, reflect_dom_object};
use dom::bindings::str::{ByteString, is_token};
use hyper::header::Headers as HyperHeaders;
use std::cell::Cell;
use std::result::Result;
#[dom_struct]
pub struct Headers {
reflector_: Reflector,
guard: Guard,
guard: Cell<Guard>,
#[ignore_heap_size_of = "Defined in hyper"]
header_list: DOMRefCell<HyperHeaders>
}
// https://fetch.spec.whatwg.org/#concept-headers-guard
#[derive(JSTraceable, HeapSizeOf, PartialEq)]
#[derive(Copy, Clone, JSTraceable, HeapSizeOf, PartialEq)]
pub enum Guard {
Immutable,
Request,
@ -36,81 +37,54 @@ impl Headers {
pub fn new_inherited() -> Headers {
Headers {
reflector_: Reflector::new(),
guard: Guard::None,
guard: Cell::new(Guard::None),
header_list: DOMRefCell::new(HyperHeaders::new()),
}
}
// https://fetch.spec.whatwg.org/#concept-headers-fill
pub fn new(global: GlobalRef, init: Option<HeadersBinding::HeadersInit>)
-> Fallible<Root<Headers>> {
let dom_headers_new = reflect_dom_object(box Headers::new_inherited(), global, HeadersBinding::Wrap);
match init {
// Step 1
Some(HeadersOrByteStringSequenceSequence::Headers(h)) => {
// header_list_copy has type hyper::header::Headers
let header_list_copy = h.header_list.clone();
for header in header_list_copy.borrow().iter() {
try!(dom_headers_new.Append(
ByteString::new(Vec::from(header.name())),
ByteString::new(Vec::from(header.value_string().into_bytes()))
));
}
Ok(dom_headers_new)
},
// Step 2
Some(HeadersOrByteStringSequenceSequence::ByteStringSequenceSequence(v)) => {
for mut seq in v {
if seq.len() == 2 {
let val = seq.pop().unwrap();
let name = seq.pop().unwrap();
try!(dom_headers_new.Append(name, val));
} else {
return Err(Error::Type(
format!("Each header object must be a sequence of length 2 - found one with length {}",
seq.len())));
}
}
Ok(dom_headers_new)
},
// Step 3 TODO constructor for when init is an open-ended dictionary
None => Ok(dom_headers_new),
}
pub fn new(global: GlobalRef) -> Root<Headers> {
reflect_dom_object(box Headers::new_inherited(), global, HeadersBinding::Wrap)
}
// https://fetch.spec.whatwg.org/#dom-headers
pub fn Constructor(global: GlobalRef, init: Option<HeadersBinding::HeadersInit>)
-> Fallible<Root<Headers>> {
Headers::new(global, init)
let dom_headers_new = Headers::new(global);
try!(dom_headers_new.fill(init));
Ok(dom_headers_new)
}
}
impl HeadersMethods for Headers {
// https://fetch.spec.whatwg.org/#concept-headers-append
fn Append(&self, name: ByteString, value: ByteString) -> Result<(), Error> {
fn Append(&self, name: ByteString, value: ByteString) -> ErrorResult {
// Step 1
let value = normalize_value(value);
// Step 2
let (mut valid_name, valid_value) = try!(validate_name_and_value(name, value));
valid_name = valid_name.to_lowercase();
// Step 3
if self.guard == Guard::Immutable {
if self.guard.get() == Guard::Immutable {
return Err(Error::Type("Guard is immutable".to_string()));
}
// Step 4
if self.guard == Guard::Request && is_forbidden_header_name(&valid_name) {
if self.guard.get() == Guard::Request && is_forbidden_header_name(&valid_name) {
return Ok(());
}
// Step 5
if self.guard == Guard::RequestNoCors && !is_cors_safelisted_request_header(&valid_name) {
if self.guard.get() == Guard::RequestNoCors && !is_cors_safelisted_request_header(&valid_name) {
return Ok(());
}
// Step 6
if self.guard == Guard::Response && is_forbidden_response_header(&valid_name) {
if self.guard.get() == Guard::Response && is_forbidden_response_header(&valid_name) {
return Ok(());
}
// Step 7
let mut combined_value = self.header_list.borrow_mut().get_raw(&valid_name).unwrap()[0].clone();
combined_value.push(b","[0]);
let mut combined_value: Vec<u8> = vec![];
if let Some(v) = self.header_list.borrow().get_raw(&valid_name) {
combined_value = v[0].clone();
combined_value.push(b","[0]);
}
combined_value.extend(valid_value.iter().cloned());
self.header_list.borrow_mut().set_raw(valid_name, vec![combined_value]);
Ok(())
@ -121,19 +95,19 @@ impl HeadersMethods for Headers {
// Step 1
let valid_name = try!(validate_name(name));
// Step 2
if self.guard == Guard::Immutable {
if self.guard.get() == Guard::Immutable {
return Err(Error::Type("Guard is immutable".to_string()));
}
// Step 3
if self.guard == Guard::Request && is_forbidden_header_name(&valid_name) {
if self.guard.get() == Guard::Request && is_forbidden_header_name(&valid_name) {
return Ok(());
}
// Step 4
if self.guard == Guard::RequestNoCors && !is_cors_safelisted_request_header(&valid_name) {
if self.guard.get() == Guard::RequestNoCors && !is_cors_safelisted_request_header(&valid_name) {
return Ok(());
}
// Step 5
if self.guard == Guard::Response && is_forbidden_response_header(&valid_name) {
if self.guard.get() == Guard::Response && is_forbidden_response_header(&valid_name) {
return Ok(());
}
// Step 6
@ -166,19 +140,19 @@ impl HeadersMethods for Headers {
let (mut valid_name, valid_value) = try!(validate_name_and_value(name, value));
valid_name = valid_name.to_lowercase();
// Step 3
if self.guard == Guard::Immutable {
if self.guard.get() == Guard::Immutable {
return Err(Error::Type("Guard is immutable".to_string()));
}
// Step 4
if self.guard == Guard::Request && is_forbidden_header_name(&valid_name) {
if self.guard.get() == Guard::Request && is_forbidden_header_name(&valid_name) {
return Ok(());
}
// Step 5
if self.guard == Guard::RequestNoCors && !is_cors_safelisted_request_header(&valid_name) {
if self.guard.get() == Guard::RequestNoCors && !is_cors_safelisted_request_header(&valid_name) {
return Ok(());
}
// Step 6
if self.guard == Guard::Response && is_forbidden_response_header(&valid_name) {
if self.guard.get() == Guard::Response && is_forbidden_response_header(&valid_name) {
return Ok(());
}
// Step 7
@ -188,6 +162,64 @@ impl HeadersMethods for Headers {
}
}
impl Headers {
// https://fetch.spec.whatwg.org/#concept-headers-fill
pub fn fill(&self, filler: Option<HeadersBinding::HeadersInit>) -> ErrorResult {
match filler {
// Step 1
Some(HeadersOrByteStringSequenceSequence::Headers(h)) => {
for header in h.header_list.borrow().iter() {
try!(self.Append(
ByteString::new(Vec::from(header.name())),
ByteString::new(Vec::from(header.value_string().into_bytes()))
));
}
Ok(())
},
// Step 2
Some(HeadersOrByteStringSequenceSequence::ByteStringSequenceSequence(v)) => {
for mut seq in v {
if seq.len() == 2 {
let val = seq.pop().unwrap();
let name = seq.pop().unwrap();
try!(self.Append(name, val));
} else {
return Err(Error::Type(
format!("Each header object must be a sequence of length 2 - found one with length {}",
seq.len())));
}
}
Ok(())
},
// Step 3 TODO constructor for when init is an open-ended dictionary
None => Ok(()),
}
}
pub fn for_request(global: GlobalRef) -> Root<Headers> {
let headers_for_request = Headers::new(global);
headers_for_request.guard.set(Guard::Request);
headers_for_request
}
pub fn set_guard(&self, new_guard: Guard) {
self.guard.set(new_guard)
}
pub fn get_guard(&self) -> Guard {
self.guard.get()
}
pub fn empty_header_list(&self) {
*self.header_list.borrow_mut() = HyperHeaders::new();
}
// https://fetch.spec.whatwg.org/#concept-header-extract-mime-type
pub fn extract_mime_type(&self) -> Vec<u8> {
self.header_list.borrow().get_raw("content-type").map_or(vec![], |v| v[0].clone())
}
}
// TODO
// "Content-Type" once parsed, the value should be
// `application/x-www-form-urlencoded`, `multipart/form-data`,
@ -315,20 +347,24 @@ fn is_field_name(name: &ByteString) -> bool {
// field-content = field-vchar [ 1*( SP / HTAB / field-vchar )
// field-vchar ]
fn is_field_content(value: &ByteString) -> bool {
if value.len() == 0 {
let value_len = value.len();
if value_len == 0 {
return false;
}
if !is_field_vchar(value[0]) {
return false;
}
for &ch in &value[1..value.len() - 1] {
if !is_field_vchar(ch) || !is_space(ch) || !is_htab(ch) {
return false;
if value_len > 2 {
for &ch in &value[1..value_len - 1] {
if !is_field_vchar(ch) && !is_space(ch) && !is_htab(ch) {
return false;
}
}
}
if !is_field_vchar(value[value.len() - 1]) {
if !is_field_vchar(value[value_len - 1]) {
return false;
}

View file

@ -368,6 +368,7 @@ pub mod processinginstruction;
pub mod progressevent;
pub mod radionodelist;
pub mod range;
pub mod request;
pub mod screen;
pub mod serviceworker;
pub mod serviceworkercontainer;

View file

@ -0,0 +1,820 @@
/* 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 dom::bindings::cell::DOMRefCell;
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::codegen::UnionTypes::HeadersOrByteStringSequenceSequence;
use dom::bindings::error::{Error, Fallible};
use dom::bindings::global::GlobalRef;
use dom::bindings::js::{JS, MutNullableHeap, Root};
use dom::bindings::reflector::{Reflectable, Reflector, reflect_dom_object};
use dom::bindings::str::{ByteString, USVString, DOMString};
use dom::headers::{Headers, Guard};
use hyper;
use msg::constellation_msg::{ReferrerPolicy as MsgReferrerPolicy};
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::Referer as NetTraitsRequestReferer;
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 std::cell::{Cell, Ref};
use url::Url;
#[dom_struct]
pub struct Request {
reflector_: Reflector,
request: DOMRefCell<NetTraitsRequest>,
body_used: Cell<bool>,
headers: MutNullableHeap<JS<Headers>>,
mime_type: DOMRefCell<Vec<u8>>,
}
impl Request {
fn new_inherited(global: GlobalRef,
url: Url,
is_service_worker_global_scope: bool) -> Request {
Request {
reflector_: Reflector::new(),
request: DOMRefCell::new(
net_request_from_global(global,
url,
is_service_worker_global_scope)),
body_used: Cell::new(false),
headers: Default::default(),
mime_type: DOMRefCell::new("".to_string().into_bytes()),
}
}
pub fn new(global: GlobalRef,
url: Url,
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)
}
// https://fetch.spec.whatwg.org/#dom-request
pub fn Constructor(global: GlobalRef,
input: RequestInfo,
init: &RequestInit)
-> Fallible<Root<Request>> {
// Step 1
let temporary_request: NetTraitsRequest;
// Step 2
let mut fallback_mode: Option<NetTraitsRequestMode> = None;
// Step 3
let mut fallback_credentials: Option<NetTraitsRequestCredentials> = None;
// Step 4
// TODO: `entry settings object` is not implemented in Servo yet.
let base_url = global.get_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,
false);
// 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 = global.get_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.is_undefined() && !init.window.is_null() {
return Err(Error::Type("Window is present and is not null".to_string()))
}
// Step 11
if !init.window.is_undefined() {
window = Window::NoWindow;
}
// Step 12
let mut request: NetTraitsRequest;
request = net_request_from_global(global,
get_current_url(&temporary_request).unwrap().clone(),
false);
request.method = temporary_request.method;
request.headers = temporary_request.headers.clone();
request.unsafe_request = true;
request.window.set(window);
// TODO: `entry settings object` is not implemented in Servo yet.
*request.origin.borrow_mut() = Origin::Client;
request.omit_origin_header = temporary_request.omit_origin_header;
request.same_origin_data.set(true);
request.referer = temporary_request.referer;
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.is_undefined() {
// Step 13.1
if request.mode == NetTraitsRequestMode::Navigate {
return Err(Error::Type(
"Init is present and request mode is 'navigate'".to_string()));
}
// Step 13.2
request.omit_origin_header.set(false);
// Step 13.3
*request.referer.borrow_mut() = NetTraitsRequestReferer::Client;
// Step 13.4
request.referrer_policy.set(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.referer.borrow_mut() = NetTraitsRequestReferer::NoReferer;
} 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" {
*request.referer.borrow_mut() = NetTraitsRequestReferer::Client;
} else {
// Step 14.6
if parsed_referrer.origin() != origin {
return Err(Error::Type(
"RequestInit's referrer has invalid origin".to_string()));
}
// TODO: Requires Step 7.
// Step 14.7
*request.referer.borrow_mut() = NetTraitsRequestReferer::RefererUrl(parsed_referrer);
}
}
}
}
// Step 15
if let Some(init_referrerpolicy) = init.referrerPolicy.as_ref() {
let init_referrer_policy = init_referrerpolicy.clone().into();
request.referrer_policy.set(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.set(cache);
}
// Step 22
if request.cache_mode.get() == 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.set(redirect);
}
// Step 24
if let Some(init_integrity) = init.integrity.as_ref() {
let integrity = init_integrity.clone().to_string();
*request.integrity_metadata.borrow_mut() = 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_lower = init_method.to_lower();
let method_string = match method_lower.as_str() {
Some(s) => s,
None => return Err(Error::Type("Method is not a valid UTF8".to_string())),
};
let normalized_method = normalize_method(method_string);
// Step 25.3
let hyper_method = normalized_method_to_typed_method(&normalized_method);
*request.method.borrow_mut() = hyper_method;
}
// Step 26
let r = Request::from_net_request(global,
false,
request);
r.headers.or_init(|| Headers::for_request(r.global().r()));
// Step 27
let mut headers_copy = r.Headers();
// This is equivalent to the specification's concept of
// "associated headers list".
if let RequestInfo::Request(ref input_request) = input {
headers_copy = input_request.Headers();
}
// Step 28
if let Some(possible_header) = init.headers.as_ref() {
if let &HeadersOrByteStringSequenceSequence::Headers(ref init_headers) = possible_header {
headers_copy = init_headers.clone();
}
}
// Step 29
r.Headers().empty_header_list();
// 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.borrow()) {
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.borrow().is_empty() {
return Err(Error::Type("Integrity metadata is not an empty string".to_string()));
}
// Step 30.3
r.Headers().set_guard(Guard::RequestNoCors);
}
// Step 31
r.Headers().fill(Some(HeadersOrByteStringSequenceSequence::Headers(headers_copy)));
// Step 32
let input_body = if let RequestInfo::Request(ref input_request) = input {
let input_request_request = input_request.request.borrow();
let body = input_request_request.body.borrow();
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.borrow();
match &*req_method {
&hyper::method::Method::Get => return Err(Error::Type(
"Init's body is non-null, and request method is GET".to_string())),
&hyper::method::Method::Head => return Err(Error::Type(
"Init's body is non-null, and request method is HEAD".to_string())),
_ => {},
}
}
}
// Step 34
// TODO: `ReadableStream` object is not implemented in Servo yet.
// Step 35
{
let borrowed_request = r.request.borrow();
*borrowed_request.body.borrow_mut() = 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)
}
}
impl Request {
fn from_net_request(global: GlobalRef,
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);
*r.request.borrow_mut() = net_request;
r
}
fn clone_from(r: &Request) -> Root<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 = reflect_dom_object(
box Request::new_inherited(r.global().r(),
url,
is_service_worker_global_scope),
r.global().r(), RequestBinding::Wrap);
r_clone.request.borrow_mut().pipeline_id.set(req.pipeline_id.get());
{
let mut borrowed_r_request = r_clone.request.borrow_mut();
*borrowed_r_request.origin.borrow_mut() = req.origin.borrow().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().set_guard(headers_guard);
r_clone
}
}
fn net_request_from_global(global: GlobalRef,
url: Url,
is_service_worker_global_scope: bool) -> NetTraitsRequest {
let origin = Origin::Origin(global.get_url().origin());
let pipeline_id = global.pipeline();
NetTraitsRequest::new(url,
Some(origin),
is_service_worker_global_scope,
Some(pipeline_id))
}
// https://fetch.spec.whatwg.org/#concept-request-current-url
fn get_current_url(req: &NetTraitsRequest) -> Option<Ref<Url>> {
let url_list = req.url_list.borrow();
if url_list.len() > 0 {
Some(Ref::map(url_list, |urls| urls.last().unwrap()))
} else {
None
}
}
fn normalized_method_to_typed_method(m: &str) -> hyper::method::Method {
match m {
"DELETE" => hyper::method::Method::Delete,
"GET" => hyper::method::Method::Get,
"HEAD" => hyper::method::Method::Head,
"OPTIONS" => hyper::method::Method::Options,
"POST" => hyper::method::Method::Post,
"PUT" => hyper::method::Method::Put,
a => hyper::method::Method::Extension(a.to_string())
}
}
// https://fetch.spec.whatwg.org/#concept-method-normalize
fn normalize_method(m: &str) -> String {
match m {
"delete" => "DELETE".to_string(),
"get" => "GET".to_string(),
"head" => "HEAD".to_string(),
"options" => "OPTIONS".to_string(),
"post" => "POST".to_string(),
"put" => "PUT".to_string(),
a => a.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: &hyper::method::Method) -> bool {
m == &hyper::method::Method::Get ||
m == &hyper::method::Method::Head ||
m == &hyper::method::Method::Post
}
// https://url.spec.whatwg.org/#include-credentials
fn includes_credentials(input: &Url) -> 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();
let m = r.method.borrow();
ByteString::new(m.as_ref().as_bytes().into())
}
// https://fetch.spec.whatwg.org/#dom-request-url
fn Url(&self) -> USVString {
let r = self.request.borrow();
let url = r.url_list.borrow();
USVString(url.get(0).map_or("", |u| u.as_str()).into())
}
// https://fetch.spec.whatwg.org/#dom-request-headers
fn Headers(&self) -> Root<Headers> {
self.headers.or_init(|| Headers::new(self.global().r()))
}
// 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();
let referrer = r.referer.borrow();
USVString(match &*referrer {
&NetTraitsRequestReferer::NoReferer => String::from("no-referrer"),
&NetTraitsRequestReferer::Client => String::from("client"),
&NetTraitsRequestReferer::RefererUrl(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.get().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.get().into()
}
// https://fetch.spec.whatwg.org/#dom-request-redirect
fn Redirect(&self) -> RequestRedirect {
let r = self.request.borrow().clone();
r.redirect_mode.get().into()
}
// https://fetch.spec.whatwg.org/#dom-request-integrity
fn Integrity(&self) -> DOMString {
let r = self.request.borrow();
let integrity = r.integrity_metadata.borrow();
DOMString::from_string(integrity.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<Root<Request>> {
// 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
Ok(Request::clone_from(self))
}
}
impl Into<NetTraitsRequestCache> 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<RequestCache> 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<NetTraitsRequestCredentials> for RequestCredentials {
fn into(self) -> NetTraitsRequestCredentials {
match self {
RequestCredentials::Omit => NetTraitsRequestCredentials::Omit,
RequestCredentials::Same_origin => NetTraitsRequestCredentials::CredentialsSameOrigin,
RequestCredentials::Include => NetTraitsRequestCredentials::Include,
}
}
}
impl Into<RequestCredentials> for NetTraitsRequestCredentials {
fn into(self) -> RequestCredentials {
match self {
NetTraitsRequestCredentials::Omit => RequestCredentials::Omit,
NetTraitsRequestCredentials::CredentialsSameOrigin => RequestCredentials::Same_origin,
NetTraitsRequestCredentials::Include => RequestCredentials::Include,
}
}
}
impl Into<NetTraitsRequestDestination> 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<RequestDestination> 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<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,
}
}
}
impl Into<NetTraitsRequestMode> 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<RequestMode> 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,
}
}
}
// TODO
// When whatwg/fetch PR #346 is merged, fix this.
impl Into<MsgReferrerPolicy> 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,
}
}
}
impl Into<ReferrerPolicy> 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,
}
}
}
impl Into<NetTraitsRequestRedirect> for RequestRedirect {
fn into(self) -> NetTraitsRequestRedirect {
match self {
RequestRedirect::Follow => NetTraitsRequestRedirect::Follow,
RequestRedirect::Error => NetTraitsRequestRedirect::Error,
RequestRedirect::Manual => NetTraitsRequestRedirect::Manual,
}
}
}
impl Into<RequestRedirect> for NetTraitsRequestRedirect {
fn into(self) -> RequestRedirect {
match self {
NetTraitsRequestRedirect::Follow => RequestRedirect::Follow,
NetTraitsRequestRedirect::Error => RequestRedirect::Error,
NetTraitsRequestRedirect::Manual => RequestRedirect::Manual,
}
}
}
impl Clone for HeadersOrByteStringSequenceSequence {
fn clone(&self) -> HeadersOrByteStringSequenceSequence {
match self {
&HeadersOrByteStringSequenceSequence::Headers(ref h) =>
HeadersOrByteStringSequenceSequence::Headers(h.clone()),
&HeadersOrByteStringSequenceSequence::ByteStringSequenceSequence(ref b) =>
HeadersOrByteStringSequenceSequence::ByteStringSequenceSequence(b.clone()),
}
}
}

View file

@ -0,0 +1,19 @@
/* 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/. */
// https://fetch.spec.whatwg.org/#body
[NoInterfaceObject,
Exposed=(Window,Worker)]
interface Body {
readonly attribute boolean bodyUsed;
// Servo does not support Promise at this moment.
// [NewObject] Promise<ArrayBuffer> arrayBuffer();
// [NewObject] Promise<Blob> blob();
// [NewObject] Promise<FormData> formData();
// [NewObject] Promise<JSON> json();
// [NewObject] Promise<USVString> text();
};

View file

@ -0,0 +1,108 @@
/* 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/. */
// https://fetch.spec.whatwg.org/#request-class
typedef (Request or USVString) RequestInfo;
[Constructor(RequestInfo input, optional RequestInit init),
Exposed=(Window,Worker)]
interface Request {
readonly attribute ByteString method;
readonly attribute USVString url;
[SameObject] readonly attribute Headers headers;
readonly attribute RequestType type;
readonly attribute RequestDestination destination;
readonly attribute USVString referrer;
readonly attribute ReferrerPolicy referrerPolicy;
readonly attribute RequestMode mode;
readonly attribute RequestCredentials credentials;
readonly attribute RequestCache cache;
readonly attribute RequestRedirect redirect;
readonly attribute DOMString integrity;
[NewObject, Throws] Request clone();
};
Request implements Body;
dictionary RequestInit {
ByteString method;
HeadersInit headers;
BodyInit? body;
USVString referrer;
ReferrerPolicy referrerPolicy;
RequestMode mode;
RequestCredentials credentials;
RequestCache cache;
RequestRedirect redirect;
DOMString integrity;
any window; // can only be set to null
};
enum RequestType {
"",
"audio",
"font",
"image",
"script",
"style",
"track",
"video"
};
enum RequestDestination {
"",
"document",
"embed",
"font",
"image",
"manifest",
"media",
"object",
"report",
"script",
"serviceworker",
"sharedworker",
"style",
"worker",
"xslt"
};
enum RequestMode {
"navigate",
"same-origin",
"no-cors",
"cors"
};
enum RequestCredentials {
"omit",
"same-origin",
"include"
};
enum RequestCache {
"default",
"no-store",
"reload",
"no-cache",
"force-cache",
"only-if-cached"
};
enum RequestRedirect {
"follow",
"error",
"manual"
};
enum ReferrerPolicy {
"",
"no-referrer",
"no-referrer-when-downgrade",
"origin",
"origin-when-cross-origin",
"unsafe-url"
};

View file

@ -3,21 +3,12 @@
[Create headers from empty object]
expected: FAIL
[Create headers with sequence]
expected: FAIL
[Create headers with OpenEndedDictionary]
expected: FAIL
[Create headers with existing headers]
expected: FAIL
[Check append method]
expected: FAIL
[Check set method]
expected: FAIL
[Check has method]
expected: FAIL

View file

@ -3,12 +3,3 @@
[Create headers, names use characters with different case]
expected: FAIL
[Check append method, names use characters with different case]
expected: FAIL
[Check set method, names use characters with different case]
expected: FAIL
[Check delete method, names use characters with different case]
expected: FAIL

View file

@ -3,12 +3,6 @@
[Create headers using same name for different values]
expected: FAIL
[Check delete and has methods when using same name for different values]
expected: FAIL
[Check set methods when called with already used name]
expected: FAIL
[Check append methods when called with already used name]
expected: FAIL

View file

@ -1,8 +1,5 @@
[headers-errors.html]
type: testharness
[Headers forEach throws if argument is not callable]
expected: FAIL
[Headers forEach loop should stop if callback is throwing exception]
expected: FAIL

View file

@ -3,9 +3,3 @@
[Create headers with not normalized values]
expected: FAIL
[Check append method whith not normalized values]
expected: FAIL
[Check set method whith not normalized values]
expected: FAIL

View file

@ -1,62 +1,5 @@
[request-error.html]
type: testharness
[RequestInit's window is not null]
expected: FAIL
[Input URL is not valid]
expected: FAIL
[Input URL has credentials]
expected: FAIL
[RequestInit's mode is navigate]
expected: FAIL
[RequestInit's referrer is invalid]
expected: FAIL
[RequestInit's referrer has invalid origin]
expected: FAIL
[RequestInit's method is invalid]
expected: FAIL
[RequestInit's method is forbidden]
expected: FAIL
[RequestInit's mode is no-cors and method is not simple]
expected: FAIL
[RequestInit's mode is no-cors and integrity is not empty]
expected: FAIL
[RequestInit's cache mode is only-if-cached and mode is not same-origin]
expected: FAIL
[Request should get its content-type from the init request]
expected: FAIL
[Request should not get its content-type from the init request if init headers are provided]
expected: FAIL
[Request should get its content-type from the body if none is provided]
expected: FAIL
[Request should get its content-type from init headers if one is provided]
expected: FAIL
[Bad referrerPolicy init parameter value]
expected: FAIL
[Bad mode init parameter value]
expected: FAIL
[Bad credentials init parameter value]
expected: FAIL
[Bad cache init parameter value]
expected: FAIL
[Bad redirect init parameter value]
expected: FAIL

View file

@ -1,110 +1,5 @@
[request-headers.html]
type: testharness
[Adding valid request header "Content-Type: OK"]
expected: FAIL
[Adding valid request header "Potato: OK"]
expected: FAIL
[Adding valid request header "proxy: OK"]
expected: FAIL
[Adding valid request header "proxya: OK"]
expected: FAIL
[Adding valid request header "sec: OK"]
expected: FAIL
[Adding valid request header "secb: OK"]
expected: FAIL
[Adding invalid request header "Accept-Charset: KO"]
expected: FAIL
[Adding invalid request header "accept-charset: KO"]
expected: FAIL
[Adding invalid request header "ACCEPT-ENCODING: KO"]
expected: FAIL
[Adding invalid request header "Accept-Encoding: KO"]
expected: FAIL
[Adding invalid request header "Access-Control-Request-Headers: KO"]
expected: FAIL
[Adding invalid request header "Access-Control-Request-Method: KO"]
expected: FAIL
[Adding invalid request header "Connection: KO"]
expected: FAIL
[Adding invalid request header "Content-Length: KO"]
expected: FAIL
[Adding invalid request header "Cookie: KO"]
expected: FAIL
[Adding invalid request header "Cookie2: KO"]
expected: FAIL
[Adding invalid request header "Date: KO"]
expected: FAIL
[Adding invalid request header "DNT: KO"]
expected: FAIL
[Adding invalid request header "Expect: KO"]
expected: FAIL
[Adding invalid request header "Host: KO"]
expected: FAIL
[Adding invalid request header "Keep-Alive: KO"]
expected: FAIL
[Adding invalid request header "Origin: KO"]
expected: FAIL
[Adding invalid request header "Referer: KO"]
expected: FAIL
[Adding invalid request header "TE: KO"]
expected: FAIL
[Adding invalid request header "Trailer: KO"]
expected: FAIL
[Adding invalid request header "Transfer-Encoding: KO"]
expected: FAIL
[Adding invalid request header "Upgrade: KO"]
expected: FAIL
[Adding invalid request header "Via: KO"]
expected: FAIL
[Adding invalid request header "Proxy-: KO"]
expected: FAIL
[Adding invalid request header "proxy-a: KO"]
expected: FAIL
[Adding invalid request header "Sec-: KO"]
expected: FAIL
[Adding invalid request header "sec-b: KO"]
expected: FAIL
[Adding valid no-cors request header "Accept: OK"]
expected: FAIL
[Adding valid no-cors request header "Accept-Language: OK"]
expected: FAIL
[Adding valid no-cors request header "content-language: OK"]
expected: FAIL
[Adding valid no-cors request header "content-type: application/x-www-form-urlencoded"]
expected: FAIL
@ -123,42 +18,6 @@
[Adding valid no-cors request header "CONTENT-type: text/plain;charset=UTF-8"]
expected: FAIL
[Adding invalid no-cors request header "Content-Type: KO"]
expected: FAIL
[Adding invalid no-cors request header "Potato: KO"]
expected: FAIL
[Adding invalid no-cors request header "proxy: KO"]
expected: FAIL
[Adding invalid no-cors request header "proxya: KO"]
expected: FAIL
[Adding invalid no-cors request header "sec: KO"]
expected: FAIL
[Adding invalid no-cors request header "secb: KO"]
expected: FAIL
[Check that request constructor is filtering headers provided as init parameter]
expected: FAIL
[Check that no-cors request constructor is filtering headers provided as init parameter]
expected: FAIL
[Check that no-cors request constructor is filtering headers provided as part of request parameter]
expected: FAIL
[Request should get its content-type from the init request]
expected: FAIL
[Request should not get its content-type from the init request if init headers are provided]
expected: FAIL
[Request should get its content-type from the body if none is provided]
expected: FAIL
[Request should get its content-type from init headers if one is provided]
expected: FAIL

View file

@ -1,35 +1,5 @@
[request-init-001.sub.html]
type: testharness
[Check method init value of GET and associated getter]
expected: FAIL
[Check method init value of HEAD and associated getter]
expected: FAIL
[Check method init value of POST and associated getter]
expected: FAIL
[Check method init value of PUT and associated getter]
expected: FAIL
[Check method init value of DELETE and associated getter]
expected: FAIL
[Check method init value of OPTIONS and associated getter]
expected: FAIL
[Check method init value of head and associated getter]
expected: FAIL
[Check referrer init value of /relative/ressource and associated getter]
expected: FAIL
[Check referrer init value of http://web-platform.test:8000/relative/ressource?query=true#fragment and associated getter]
expected: FAIL
[Check referrer init value of http://web-platform.test:8000/ and associated getter]
expected: FAIL
[Check referrer init value of about:client and associated getter]
expected: FAIL
@ -39,69 +9,3 @@
[Check referrerPolicy init value of and associated getter]
expected: FAIL
[Check referrerPolicy init value of no-referrer and associated getter]
expected: FAIL
[Check referrerPolicy init value of no-referrer-when-downgrade and associated getter]
expected: FAIL
[Check referrerPolicy init value of origin and associated getter]
expected: FAIL
[Check referrerPolicy init value of origin-when-cross-origin and associated getter]
expected: FAIL
[Check referrerPolicy init value of unsafe-url and associated getter]
expected: FAIL
[Check mode init value of same-origin and associated getter]
expected: FAIL
[Check mode init value of no-cors and associated getter]
expected: FAIL
[Check mode init value of cors and associated getter]
expected: FAIL
[Check credentials init value of omit and associated getter]
expected: FAIL
[Check credentials init value of same-origin and associated getter]
expected: FAIL
[Check credentials init value of include and associated getter]
expected: FAIL
[Check cache init value of default and associated getter]
expected: FAIL
[Check cache init value of no-store and associated getter]
expected: FAIL
[Check cache init value of reload and associated getter]
expected: FAIL
[Check cache init value of no-cache and associated getter]
expected: FAIL
[Check cache init value of force-cache and associated getter]
expected: FAIL
[Check redirect init value of follow and associated getter]
expected: FAIL
[Check redirect init value of error and associated getter]
expected: FAIL
[Check redirect init value of manual and associated getter]
expected: FAIL
[Check integrity init value of and associated getter]
expected: FAIL
[Check integrity init value of AZERTYUIOP1234567890 and associated getter]
expected: FAIL
[Check window init value of null and associated getter]
expected: FAIL

View file

@ -1,3 +1,23 @@
[request-structure.html]
type: testharness
expected: TIMEOUT
[Request has arrayBuffer method]
expected: FAIL
[Request has blob method]
expected: FAIL
[Request has formData method]
expected: FAIL
[Request has json method]
expected: FAIL
[Request has text method]
expected: FAIL
[Check headers attribute]
expected: FAIL
[Check referrer attribute]
expected: FAIL

View file

@ -147,6 +147,7 @@ test_interfaces([
"ProgressEvent",
"RadioNodeList",
"Range",
"Request",
"Screen",
"Storage",
"StorageEvent",

View file

@ -89,6 +89,7 @@ test_interfaces([
"ProgressEvent",
"RadioNodeList",
"Range",
"Request",
"Screen",
"Storage",
"StorageEvent",