mirror of
https://github.com/servo/servo.git
synced 2025-07-24 07:40:27 +01:00
impl Body mixin for dom::Response and dom::Request
This commit is contained in:
parent
6a0c70a222
commit
a5e5cd0e9e
18 changed files with 332 additions and 167 deletions
164
components/script/body.rs
Normal file
164
components/script/body.rs
Normal file
|
@ -0,0 +1,164 @@
|
||||||
|
/* 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::codegen::Bindings::FormDataBinding::FormDataMethods;
|
||||||
|
use dom::bindings::error::{Error, Fallible};
|
||||||
|
use dom::bindings::global::GlobalRef;
|
||||||
|
use dom::bindings::js::Root;
|
||||||
|
use dom::bindings::reflector::Reflectable;
|
||||||
|
use dom::bindings::str::USVString;
|
||||||
|
use dom::blob::{Blob, BlobImpl};
|
||||||
|
use dom::formdata::FormData;
|
||||||
|
use dom::promise::Promise;
|
||||||
|
use encoding::all::UTF_8;
|
||||||
|
use encoding::types::{DecoderTrap, Encoding};
|
||||||
|
use js::jsapi::JSContext;
|
||||||
|
use js::jsapi::JS_ClearPendingException;
|
||||||
|
use js::jsapi::JS_ParseJSON;
|
||||||
|
use js::jsapi::Value as JSValue;
|
||||||
|
use js::jsval::UndefinedValue;
|
||||||
|
use mime::{Mime, TopLevel, SubLevel};
|
||||||
|
use std::rc::Rc;
|
||||||
|
use std::str;
|
||||||
|
use style::refcell::Ref;
|
||||||
|
use url::form_urlencoded;
|
||||||
|
|
||||||
|
pub enum BodyType {
|
||||||
|
ArrayBuffer,
|
||||||
|
Blob,
|
||||||
|
FormData,
|
||||||
|
Json,
|
||||||
|
Text
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum FetchedData {
|
||||||
|
Text(String),
|
||||||
|
Json(JSValue),
|
||||||
|
BlobData(Root<Blob>),
|
||||||
|
FormData(Root<FormData>),
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://fetch.spec.whatwg.org/#concept-body-consume-body
|
||||||
|
#[allow(unrooted_must_root)]
|
||||||
|
pub fn consume_body<T: BodyOperations + Reflectable>(object: &T, body_type: BodyType) -> Rc<Promise> {
|
||||||
|
let promise = Promise::new(object.global().r());
|
||||||
|
|
||||||
|
// Step 1
|
||||||
|
if object.get_body_used() || object.is_locked() {
|
||||||
|
promise.reject_error(promise.global().r().get_cx(), Error::Type(
|
||||||
|
"The response's stream is disturbed or locked".to_string()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Steps 2-4
|
||||||
|
// TODO: Body does not yet have a stream.
|
||||||
|
|
||||||
|
// Step 5
|
||||||
|
let pkg_data_results = run_package_data_algorithm(object,
|
||||||
|
object.take_body(),
|
||||||
|
body_type,
|
||||||
|
object.get_mime_type());
|
||||||
|
|
||||||
|
let cx = promise.global().r().get_cx();
|
||||||
|
match pkg_data_results {
|
||||||
|
Ok(results) => {
|
||||||
|
match results {
|
||||||
|
FetchedData::Text(s) => promise.resolve_native(cx, &USVString(s)),
|
||||||
|
FetchedData::Json(j) => promise.resolve_native(cx, &j),
|
||||||
|
FetchedData::BlobData(b) => promise.resolve_native(cx, &b),
|
||||||
|
FetchedData::FormData(f) => promise.resolve_native(cx, &f),
|
||||||
|
};
|
||||||
|
},
|
||||||
|
Err(err) => promise.reject_error(cx, err),
|
||||||
|
}
|
||||||
|
promise
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://fetch.spec.whatwg.org/#concept-body-package-data
|
||||||
|
#[allow(unsafe_code)]
|
||||||
|
fn run_package_data_algorithm<T: BodyOperations + Reflectable>(object: &T,
|
||||||
|
bytes: Option<Vec<u8>>,
|
||||||
|
body_type: BodyType,
|
||||||
|
mime_type: Ref<Vec<u8>>)
|
||||||
|
-> Fallible<FetchedData> {
|
||||||
|
let bytes = match bytes {
|
||||||
|
Some(b) => b,
|
||||||
|
_ => vec![],
|
||||||
|
};
|
||||||
|
let cx = object.global().r().get_cx();
|
||||||
|
let mime = &*mime_type;
|
||||||
|
match body_type {
|
||||||
|
BodyType::Text => run_text_data_algorithm(bytes),
|
||||||
|
BodyType::Json => run_json_data_algorithm(cx, bytes),
|
||||||
|
BodyType::Blob => run_blob_data_algorithm(object.global().r(), bytes, mime),
|
||||||
|
BodyType::FormData => run_form_data_algorithm(object.global().r(), bytes, mime),
|
||||||
|
_ => Err(Error::Type("Unable to process body type".to_string()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run_text_data_algorithm(bytes: Vec<u8>) -> Fallible<FetchedData> {
|
||||||
|
let text = UTF_8.decode(&bytes, DecoderTrap::Replace).unwrap();
|
||||||
|
Ok(FetchedData::Text(text))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(unsafe_code)]
|
||||||
|
fn run_json_data_algorithm(cx: *mut JSContext,
|
||||||
|
bytes: Vec<u8>) -> Fallible<FetchedData> {
|
||||||
|
let json_text = UTF_8.decode(&bytes, DecoderTrap::Replace).unwrap();
|
||||||
|
let json_text: Vec<u16> = json_text.encode_utf16().collect();
|
||||||
|
rooted!(in(cx) let mut rval = UndefinedValue());
|
||||||
|
unsafe {
|
||||||
|
if !JS_ParseJSON(cx,
|
||||||
|
json_text.as_ptr(),
|
||||||
|
json_text.len() as u32,
|
||||||
|
rval.handle_mut()) {
|
||||||
|
JS_ClearPendingException(cx);
|
||||||
|
// TODO: See issue #13464. Exception should be thrown instead of cleared.
|
||||||
|
return Err(Error::Type("Failed to parse JSON".to_string()));
|
||||||
|
}
|
||||||
|
Ok(FetchedData::Json(rval.get()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run_blob_data_algorithm(root: GlobalRef,
|
||||||
|
bytes: Vec<u8>,
|
||||||
|
mime: &[u8]) -> Fallible<FetchedData> {
|
||||||
|
let mime_string = if let Ok(s) = String::from_utf8(mime.to_vec()) {
|
||||||
|
s
|
||||||
|
} else {
|
||||||
|
"".to_string()
|
||||||
|
};
|
||||||
|
let blob = Blob::new(root, BlobImpl::new_from_bytes(bytes), mime_string);
|
||||||
|
Ok(FetchedData::BlobData(blob))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run_form_data_algorithm(root: GlobalRef, bytes: Vec<u8>, mime: &[u8]) -> Fallible<FetchedData> {
|
||||||
|
let mime_str = if let Ok(s) = str::from_utf8(mime) {
|
||||||
|
s
|
||||||
|
} else {
|
||||||
|
""
|
||||||
|
};
|
||||||
|
let mime: Mime = try!(mime_str.parse().map_err(
|
||||||
|
|_| Error::Type("Inappropriate MIME-type for Body".to_string())));
|
||||||
|
match mime {
|
||||||
|
// TODO
|
||||||
|
// ... Parser for Mime(TopLevel::Multipart, SubLevel::FormData, _)
|
||||||
|
// ... is not fully determined yet.
|
||||||
|
Mime(TopLevel::Application, SubLevel::WwwFormUrlEncoded, _) => {
|
||||||
|
let entries = form_urlencoded::parse(&bytes);
|
||||||
|
let formdata = FormData::new(None, root);
|
||||||
|
for (k, e) in entries {
|
||||||
|
formdata.Append(USVString(k.into_owned()), USVString(e.into_owned()));
|
||||||
|
}
|
||||||
|
return Ok(FetchedData::FormData(formdata));
|
||||||
|
},
|
||||||
|
_ => return Err(Error::Type("Inappropriate MIME-type for Body".to_string())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait BodyOperations {
|
||||||
|
fn get_body_used(&self) -> bool;
|
||||||
|
fn take_body(&self) -> Option<Vec<u8>>;
|
||||||
|
fn is_locked(&self) -> bool;
|
||||||
|
fn get_mime_type(&self) -> Ref<Vec<u8>>;
|
||||||
|
}
|
|
@ -2,8 +2,9 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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/. */
|
* 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::cell::DOMRefCell;
|
||||||
use dom::bindings::codegen::Bindings::HeadersBinding::HeadersInit;
|
use dom::bindings::codegen::Bindings::HeadersBinding::{HeadersInit, HeadersMethods};
|
||||||
use dom::bindings::codegen::Bindings::RequestBinding;
|
use dom::bindings::codegen::Bindings::RequestBinding;
|
||||||
use dom::bindings::codegen::Bindings::RequestBinding::ReferrerPolicy;
|
use dom::bindings::codegen::Bindings::RequestBinding::ReferrerPolicy;
|
||||||
use dom::bindings::codegen::Bindings::RequestBinding::RequestCache;
|
use dom::bindings::codegen::Bindings::RequestBinding::RequestCache;
|
||||||
|
@ -21,6 +22,8 @@ use dom::bindings::js::{JS, MutNullableHeap, Root};
|
||||||
use dom::bindings::reflector::{Reflectable, Reflector, reflect_dom_object};
|
use dom::bindings::reflector::{Reflectable, Reflector, reflect_dom_object};
|
||||||
use dom::bindings::str::{ByteString, DOMString, USVString};
|
use dom::bindings::str::{ByteString, DOMString, USVString};
|
||||||
use dom::headers::{Guard, Headers};
|
use dom::headers::{Guard, Headers};
|
||||||
|
use dom::promise::Promise;
|
||||||
|
use dom::xmlhttprequest::Extractable;
|
||||||
use hyper;
|
use hyper;
|
||||||
use msg::constellation_msg::ReferrerPolicy as MsgReferrerPolicy;
|
use msg::constellation_msg::ReferrerPolicy as MsgReferrerPolicy;
|
||||||
use net_traits::request::{Origin, Window};
|
use net_traits::request::{Origin, Window};
|
||||||
|
@ -33,6 +36,9 @@ use net_traits::request::Request as NetTraitsRequest;
|
||||||
use net_traits::request::RequestMode as NetTraitsRequestMode;
|
use net_traits::request::RequestMode as NetTraitsRequestMode;
|
||||||
use net_traits::request::Type as NetTraitsRequestType;
|
use net_traits::request::Type as NetTraitsRequestType;
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
|
use std::mem;
|
||||||
|
use std::rc::Rc;
|
||||||
|
use style::refcell::Ref;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
#[dom_struct]
|
#[dom_struct]
|
||||||
|
@ -340,7 +346,7 @@ impl Request {
|
||||||
try!(r.Headers().fill(Some(HeadersInit::Headers(headers_copy))));
|
try!(r.Headers().fill(Some(HeadersInit::Headers(headers_copy))));
|
||||||
|
|
||||||
// Step 32
|
// Step 32
|
||||||
let input_body = if let RequestInfo::Request(ref input_request) = input {
|
let mut input_body = if let RequestInfo::Request(ref input_request) = input {
|
||||||
let input_request_request = input_request.request.borrow();
|
let input_request_request = input_request.request.borrow();
|
||||||
let body = input_request_request.body.borrow();
|
let body = input_request_request.body.borrow();
|
||||||
body.clone()
|
body.clone()
|
||||||
|
@ -365,6 +371,20 @@ impl Request {
|
||||||
|
|
||||||
// Step 34
|
// Step 34
|
||||||
// TODO: `ReadableStream` object is not implemented in Servo yet.
|
// TODO: `ReadableStream` object is not implemented in Servo yet.
|
||||||
|
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 35
|
// Step 35
|
||||||
{
|
{
|
||||||
|
@ -382,6 +402,13 @@ impl Request {
|
||||||
// Step 38
|
// Step 38
|
||||||
Ok(r)
|
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 {
|
impl Request {
|
||||||
|
@ -602,6 +629,56 @@ impl RequestMethods for Request {
|
||||||
// Step 2
|
// Step 2
|
||||||
Ok(Request::clone_from(self))
|
Ok(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()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_locked(&self) -> bool {
|
||||||
|
self.locked()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn take_body(&self) -> Option<Vec<u8>> {
|
||||||
|
let ref mut net_traits_req = *self.request.borrow_mut();
|
||||||
|
let body: Option<Vec<u8>> = mem::replace(&mut *net_traits_req.body.borrow_mut(), None);
|
||||||
|
match body {
|
||||||
|
Some(_) => {
|
||||||
|
self.body_used.set(true);
|
||||||
|
body
|
||||||
|
},
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_mime_type(&self) -> Ref<Vec<u8>> {
|
||||||
|
self.mime_type.borrow()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Into<NetTraitsRequestCache> for RequestCache {
|
impl Into<NetTraitsRequestCache> for RequestCache {
|
||||||
|
|
|
@ -2,11 +2,13 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
use body::{BodyOperations, BodyType, consume_body};
|
||||||
use core::cell::Cell;
|
use core::cell::Cell;
|
||||||
use dom::bindings::cell::DOMRefCell;
|
use dom::bindings::cell::DOMRefCell;
|
||||||
use dom::bindings::codegen::Bindings::HeadersBinding::HeadersMethods;
|
use dom::bindings::codegen::Bindings::HeadersBinding::HeadersMethods;
|
||||||
use dom::bindings::codegen::Bindings::ResponseBinding;
|
use dom::bindings::codegen::Bindings::ResponseBinding;
|
||||||
use dom::bindings::codegen::Bindings::ResponseBinding::{ResponseMethods, ResponseType as DOMResponseType};
|
use dom::bindings::codegen::Bindings::ResponseBinding::{ResponseMethods, ResponseType as DOMResponseType};
|
||||||
|
use dom::bindings::codegen::Bindings::XMLHttpRequestBinding::BodyInit;
|
||||||
use dom::bindings::error::{Error, Fallible};
|
use dom::bindings::error::{Error, Fallible};
|
||||||
use dom::bindings::global::GlobalRef;
|
use dom::bindings::global::GlobalRef;
|
||||||
use dom::bindings::js::{JS, MutNullableHeap, Root};
|
use dom::bindings::js::{JS, MutNullableHeap, Root};
|
||||||
|
@ -14,9 +16,14 @@ use dom::bindings::reflector::{Reflectable, Reflector, reflect_dom_object};
|
||||||
use dom::bindings::str::{ByteString, USVString};
|
use dom::bindings::str::{ByteString, USVString};
|
||||||
use dom::headers::{Headers, Guard};
|
use dom::headers::{Headers, Guard};
|
||||||
use dom::headers::{is_vchar, is_obs_text};
|
use dom::headers::{is_vchar, is_obs_text};
|
||||||
|
use dom::promise::Promise;
|
||||||
|
use dom::xmlhttprequest::Extractable;
|
||||||
use hyper::status::StatusCode;
|
use hyper::status::StatusCode;
|
||||||
use net_traits::response::{ResponseBody as NetTraitsResponseBody};
|
use net_traits::response::{ResponseBody as NetTraitsResponseBody};
|
||||||
|
use std::mem;
|
||||||
|
use std::rc::Rc;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
use style::refcell::Ref;
|
||||||
use url::Position;
|
use url::Position;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
|
@ -33,8 +40,7 @@ pub struct Response {
|
||||||
response_type: DOMRefCell<DOMResponseType>,
|
response_type: DOMRefCell<DOMResponseType>,
|
||||||
url: DOMRefCell<Option<Url>>,
|
url: DOMRefCell<Option<Url>>,
|
||||||
url_list: DOMRefCell<Vec<Url>>,
|
url_list: DOMRefCell<Vec<Url>>,
|
||||||
// For now use the existing NetTraitsResponseBody enum, until body
|
// For now use the existing NetTraitsResponseBody enum
|
||||||
// is implemented.
|
|
||||||
body: DOMRefCell<NetTraitsResponseBody>,
|
body: DOMRefCell<NetTraitsResponseBody>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,7 +65,7 @@ impl Response {
|
||||||
reflect_dom_object(box Response::new_inherited(), global, ResponseBinding::Wrap)
|
reflect_dom_object(box Response::new_inherited(), global, ResponseBinding::Wrap)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn Constructor(global: GlobalRef, _body: Option<USVString>, init: &ResponseBinding::ResponseInit)
|
pub fn Constructor(global: GlobalRef, body: Option<BodyInit>, init: &ResponseBinding::ResponseInit)
|
||||||
-> Fallible<Root<Response>> {
|
-> Fallible<Root<Response>> {
|
||||||
// Step 1
|
// Step 1
|
||||||
if init.status < 200 || init.status > 599 {
|
if init.status < 200 || init.status > 599 {
|
||||||
|
@ -86,11 +92,6 @@ impl Response {
|
||||||
// Step 6
|
// Step 6
|
||||||
if let Some(ref headers_member) = init.headers {
|
if let Some(ref headers_member) = init.headers {
|
||||||
// Step 6.1
|
// Step 6.1
|
||||||
// TODO: Figure out how/if we should make r's response's
|
|
||||||
// header list and r's Headers object the same thing. For
|
|
||||||
// now just working with r's Headers object. Also, the
|
|
||||||
// header list should already be empty so this step may be
|
|
||||||
// unnecessary.
|
|
||||||
r.Headers().empty_header_list();
|
r.Headers().empty_header_list();
|
||||||
|
|
||||||
// Step 6.2
|
// Step 6.2
|
||||||
|
@ -98,23 +99,22 @@ impl Response {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 7
|
// Step 7
|
||||||
if let Some(_) = _body {
|
if let Some(ref body) = body {
|
||||||
// Step 7.1
|
// Step 7.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.2
|
|
||||||
let content_type: Option<ByteString> = None;
|
|
||||||
|
|
||||||
// Step 7.3
|
// Step 7.3
|
||||||
// TODO: Extract body and implement step 7.3.
|
let (extracted_body, content_type) = body.extract();
|
||||||
|
*r.body.borrow_mut() = NetTraitsResponseBody::Done(extracted_body);
|
||||||
|
|
||||||
// Step 7.4
|
// Step 7.4
|
||||||
if let Some(content_type_contents) = content_type {
|
if let Some(content_type_contents) = content_type {
|
||||||
if !r.Headers().Has(ByteString::new(b"Content-Type".to_vec())).unwrap() {
|
if !r.Headers().Has(ByteString::new(b"Content-Type".to_vec())).unwrap() {
|
||||||
try!(r.Headers().Append(ByteString::new(b"Content-Type".to_vec()), content_type_contents));
|
try!(r.Headers().Append(ByteString::new(b"Content-Type".to_vec()),
|
||||||
|
ByteString::new(content_type_contents.as_bytes().to_vec())));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -178,6 +178,38 @@ impl Response {
|
||||||
// Step 7
|
// Step 7
|
||||||
Ok(r)
|
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 BodyOperations for Response {
|
||||||
|
fn get_body_used(&self) -> bool {
|
||||||
|
self.BodyUsed()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_locked(&self) -> bool {
|
||||||
|
self.locked()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn take_body(&self) -> Option<Vec<u8>> {
|
||||||
|
let body: NetTraitsResponseBody = mem::replace(&mut *self.body.borrow_mut(), NetTraitsResponseBody::Empty);
|
||||||
|
match body {
|
||||||
|
NetTraitsResponseBody::Done(bytes) | NetTraitsResponseBody::Receiving(bytes) => {
|
||||||
|
self.body_used.set(true);
|
||||||
|
Some(bytes)
|
||||||
|
},
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_mime_type(&self) -> Ref<Vec<u8>> {
|
||||||
|
self.mime_type.borrow()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://fetch.spec.whatwg.org/#redirect-status
|
// https://fetch.spec.whatwg.org/#redirect-status
|
||||||
|
@ -283,6 +315,30 @@ impl ResponseMethods for Response {
|
||||||
fn BodyUsed(&self) -> bool {
|
fn BodyUsed(&self) -> bool {
|
||||||
self.body_used.get()
|
self.body_used.get()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_without_fragment(url: &Url) -> &str {
|
fn serialize_without_fragment(url: &Url) -> &str {
|
||||||
|
|
|
@ -10,10 +10,9 @@
|
||||||
interface Body {
|
interface Body {
|
||||||
readonly attribute boolean bodyUsed;
|
readonly attribute boolean bodyUsed;
|
||||||
|
|
||||||
// Servo does not support Promise at this moment.
|
|
||||||
// [NewObject] Promise<ArrayBuffer> arrayBuffer();
|
// [NewObject] Promise<ArrayBuffer> arrayBuffer();
|
||||||
// [NewObject] Promise<Blob> blob();
|
[NewObject] Promise<Blob> blob();
|
||||||
// [NewObject] Promise<FormData> formData();
|
[NewObject] Promise<FormData> formData();
|
||||||
// [NewObject] Promise<JSON> json();
|
[NewObject] Promise<any> json();
|
||||||
// [NewObject] Promise<USVString> text();
|
[NewObject] Promise<USVString> text();
|
||||||
};
|
};
|
||||||
|
|
|
@ -4,8 +4,7 @@
|
||||||
|
|
||||||
// https://fetch.spec.whatwg.org/#response-class
|
// https://fetch.spec.whatwg.org/#response-class
|
||||||
|
|
||||||
// TODO: pass 'optional ResponseBodyInit? body = null' to constructor in place of USVString
|
[Constructor(optional BodyInit? body = null, optional ResponseInit init),
|
||||||
[Constructor(optional USVString? body = null, optional ResponseInit init),
|
|
||||||
Exposed=(Window,Worker)]
|
Exposed=(Window,Worker)]
|
||||||
interface Response {
|
interface Response {
|
||||||
[NewObject] static Response error();
|
[NewObject] static Response error();
|
||||||
|
|
|
@ -1364,7 +1364,7 @@ impl XHRTimeoutCallback {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
trait Extractable {
|
pub trait Extractable {
|
||||||
fn extract(&self) -> (Vec<u8>, Option<DOMString>);
|
fn extract(&self) -> (Vec<u8>, Option<DOMString>);
|
||||||
}
|
}
|
||||||
impl Extractable for BodyInit {
|
impl Extractable for BodyInit {
|
||||||
|
|
|
@ -92,6 +92,7 @@ extern crate websocket;
|
||||||
extern crate xml5ever;
|
extern crate xml5ever;
|
||||||
|
|
||||||
pub mod bluetooth_blacklist;
|
pub mod bluetooth_blacklist;
|
||||||
|
mod body;
|
||||||
pub mod clipboard_provider;
|
pub mod clipboard_provider;
|
||||||
mod devtools;
|
mod devtools;
|
||||||
pub mod document_loader;
|
pub mod document_loader;
|
||||||
|
|
|
@ -1,17 +1,8 @@
|
||||||
[request-consume-empty.html]
|
[request-consume-empty.html]
|
||||||
type: testharness
|
type: testharness
|
||||||
[Consume request's body as text]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Consume request's body as blob]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Consume request's body as arrayBuffer]
|
[Consume request's body as arrayBuffer]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[Consume request's body as json]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Consume request's body as formData]
|
[Consume request's body as formData]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
@ -21,9 +12,3 @@
|
||||||
[Consume empty text request body as arrayBuffer]
|
[Consume empty text request body as arrayBuffer]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[Consume empty blob request body as text]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Consume empty text request body as text]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,5 @@
|
||||||
[request-consume.html]
|
[request-consume.html]
|
||||||
type: testharness
|
type: testharness
|
||||||
[Consume String request's body as text]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Consume String request's body as blob]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Consume String request's body as arrayBuffer]
|
[Consume String request's body as arrayBuffer]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
@ -15,30 +9,9 @@
|
||||||
[Consume String request's body as formData]
|
[Consume String request's body as formData]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[Consume blob response's body as blob]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Consume blob response's body as text]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Consume blob response's body as json]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Consume blob response's body as arrayBuffer]
|
[Consume blob response's body as arrayBuffer]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[Consume JSON from text: '"null"']
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Consume JSON from text: '"1"']
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Consume JSON from text: '"true"']
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Consume JSON from text: '"\\"string\\""']
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Trying to consume bad JSON text as JSON: 'undefined']
|
[Trying to consume bad JSON text as JSON: 'undefined']
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
@ -51,9 +24,6 @@
|
||||||
[Trying to consume bad JSON text as JSON: '[']
|
[Trying to consume bad JSON text as JSON: '[']
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[Consume String request's body as JSON]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Consume ArrayBuffer request's body as text]
|
[Consume ArrayBuffer request's body as text]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
@ -117,6 +87,3 @@
|
||||||
[Consume FormData request's body as FormData]
|
[Consume FormData request's body as FormData]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[Consume blob response's body as blob (empty blob as input)]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,14 @@
|
||||||
[request-disturbed.html]
|
[request-disturbed.html]
|
||||||
type: testharness
|
type: testharness
|
||||||
expected: ERROR
|
[Check cloning a disturbed request]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Check creating a new request from a disturbed request]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Input request used for creating new request became disturbed]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Request construction failure should not set "bodyUsed"]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
[request-error.html]
|
|
||||||
type: testharness
|
|
||||||
[Request should get its content-type from the body if none is provided]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -1,8 +1,5 @@
|
||||||
[request-headers.html]
|
[request-headers.html]
|
||||||
type: testharness
|
type: testharness
|
||||||
[Request should get its content-type from the body if none is provided]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Testing request header creations with various objects]
|
[Testing request header creations with various objects]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -1,20 +0,0 @@
|
||||||
[request-init-002.html]
|
|
||||||
type: testharness
|
|
||||||
[Initialize Request's body with undefined]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Initialize Request's body with null]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Initialize Request's body with application/octet-binary]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Initialize Request's body with multipart/form-data]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Initialize Request's body with text/plain;charset=UTF-8]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Initialize Request's body with application/x-www-form-urlencoded;charset=UTF-8]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -1,14 +1,5 @@
|
||||||
[request-init-003.sub.html]
|
[request-init-003.sub.html]
|
||||||
type: testharness
|
type: testharness
|
||||||
[Check request values when initialized from Request]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Check request values when initialized from Request and init values]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Check request values when initialized from url string]
|
[Check request values when initialized from url string]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[Check request values when initialized from url and init values]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
|
|
|
@ -3,18 +3,6 @@
|
||||||
[Request has arrayBuffer method]
|
[Request has arrayBuffer method]
|
||||||
expected: FAIL
|
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 referrer attribute]
|
[Check referrer attribute]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -1,17 +1,8 @@
|
||||||
[response-consume-empty.html]
|
[response-consume-empty.html]
|
||||||
type: testharness
|
type: testharness
|
||||||
[Consume response's body as text]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Consume response's body as blob]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Consume response's body as arrayBuffer]
|
[Consume response's body as arrayBuffer]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[Consume response's body as json]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Consume response's body as formData]
|
[Consume response's body as formData]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
@ -21,9 +12,3 @@
|
||||||
[Consume empty text response body as arrayBuffer]
|
[Consume empty text response body as arrayBuffer]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[Consume empty blob response body as text]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Consume empty text response body as text]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
|
|
|
@ -1,29 +1,11 @@
|
||||||
[response-consume.html]
|
[response-consume.html]
|
||||||
type: testharness
|
type: testharness
|
||||||
[Consume response's body as text]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Consume response's body as blob]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Consume response's body as arrayBuffer]
|
[Consume response's body as arrayBuffer]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[Consume response's body as json]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Consume response's body as formData]
|
[Consume response's body as formData]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[Consume blob response's body as blob]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Consume blob response's body as text]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Consume blob response's body as json]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Consume blob response's body as arrayBuffer]
|
[Consume blob response's body as arrayBuffer]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -1,17 +1,5 @@
|
||||||
[response-init-002.html]
|
[response-init-002.html]
|
||||||
type: testharness
|
type: testharness
|
||||||
[Initialize Response's body with application/octet-binary]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Initialize Response's body with multipart/form-data]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Initialize Response's body with application/x-www-form-urlencoded;charset=UTF-8]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Initialize Response's body with text/plain;charset=UTF-8]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Read Response's body as readableStream]
|
[Read Response's body as readableStream]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue