mirror of
https://github.com/servo/servo.git
synced 2025-07-23 07:13:52 +01:00
Provide the fetched data to fetch() consumers.
This commit is contained in:
parent
6bd898626f
commit
cb7e6715fb
9 changed files with 102 additions and 59 deletions
|
@ -24,6 +24,7 @@ use std::rc::Rc;
|
||||||
use std::str;
|
use std::str;
|
||||||
use url::form_urlencoded;
|
use url::form_urlencoded;
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, JSTraceable, HeapSizeOf)]
|
||||||
pub enum BodyType {
|
pub enum BodyType {
|
||||||
Blob,
|
Blob,
|
||||||
FormData,
|
FormData,
|
||||||
|
@ -47,14 +48,32 @@ pub fn consume_body<T: BodyOperations + Reflectable>(object: &T, body_type: Body
|
||||||
if object.get_body_used() || object.is_locked() {
|
if object.get_body_used() || object.is_locked() {
|
||||||
promise.reject_error(promise.global().r().get_cx(), Error::Type(
|
promise.reject_error(promise.global().r().get_cx(), Error::Type(
|
||||||
"The response's stream is disturbed or locked".to_string()));
|
"The response's stream is disturbed or locked".to_string()));
|
||||||
|
return promise;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
object.set_body_promise(&promise, body_type);
|
||||||
|
|
||||||
// Steps 2-4
|
// Steps 2-4
|
||||||
// TODO: Body does not yet have a stream.
|
// TODO: Body does not yet have a stream.
|
||||||
|
|
||||||
|
consume_body_with_promise(object, body_type, &promise);
|
||||||
|
|
||||||
|
promise
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://fetch.spec.whatwg.org/#concept-body-consume-body
|
||||||
|
#[allow(unrooted_must_root)]
|
||||||
|
pub fn consume_body_with_promise<T: BodyOperations + Reflectable>(object: &T,
|
||||||
|
body_type: BodyType,
|
||||||
|
promise: &Promise) {
|
||||||
// Step 5
|
// Step 5
|
||||||
|
let body = match object.take_body() {
|
||||||
|
Some(body) => body,
|
||||||
|
None => return,
|
||||||
|
};
|
||||||
|
|
||||||
let pkg_data_results = run_package_data_algorithm(object,
|
let pkg_data_results = run_package_data_algorithm(object,
|
||||||
object.take_body(),
|
body,
|
||||||
body_type,
|
body_type,
|
||||||
object.get_mime_type());
|
object.get_mime_type());
|
||||||
|
|
||||||
|
@ -70,20 +89,15 @@ pub fn consume_body<T: BodyOperations + Reflectable>(object: &T, body_type: Body
|
||||||
},
|
},
|
||||||
Err(err) => promise.reject_error(cx, err),
|
Err(err) => promise.reject_error(cx, err),
|
||||||
}
|
}
|
||||||
promise
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://fetch.spec.whatwg.org/#concept-body-package-data
|
// https://fetch.spec.whatwg.org/#concept-body-package-data
|
||||||
#[allow(unsafe_code)]
|
#[allow(unsafe_code)]
|
||||||
fn run_package_data_algorithm<T: BodyOperations + Reflectable>(object: &T,
|
fn run_package_data_algorithm<T: BodyOperations + Reflectable>(object: &T,
|
||||||
bytes: Option<Vec<u8>>,
|
bytes: Vec<u8>,
|
||||||
body_type: BodyType,
|
body_type: BodyType,
|
||||||
mime_type: Ref<Vec<u8>>)
|
mime_type: Ref<Vec<u8>>)
|
||||||
-> Fallible<FetchedData> {
|
-> Fallible<FetchedData> {
|
||||||
let bytes = match bytes {
|
|
||||||
Some(b) => b,
|
|
||||||
_ => vec![],
|
|
||||||
};
|
|
||||||
let cx = object.global().r().get_cx();
|
let cx = object.global().r().get_cx();
|
||||||
let mime = &*mime_type;
|
let mime = &*mime_type;
|
||||||
match body_type {
|
match body_type {
|
||||||
|
@ -156,6 +170,9 @@ fn run_form_data_algorithm(root: GlobalRef, bytes: Vec<u8>, mime: &[u8]) -> Fall
|
||||||
|
|
||||||
pub trait BodyOperations {
|
pub trait BodyOperations {
|
||||||
fn get_body_used(&self) -> bool;
|
fn get_body_used(&self) -> bool;
|
||||||
|
fn set_body_promise(&self, p: &Rc<Promise>, body_type: BodyType);
|
||||||
|
/// Returns `Some(_)` if the body is complete, `None` if there is more to
|
||||||
|
/// come.
|
||||||
fn take_body(&self) -> Option<Vec<u8>>;
|
fn take_body(&self) -> Option<Vec<u8>>;
|
||||||
fn is_locked(&self) -> bool;
|
fn is_locked(&self) -> bool;
|
||||||
fn get_mime_type(&self) -> Ref<Vec<u8>>;
|
fn get_mime_type(&self) -> Ref<Vec<u8>>;
|
||||||
|
|
|
@ -36,7 +36,6 @@ 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, Ref};
|
use std::cell::{Cell, Ref};
|
||||||
use std::mem;
|
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
|
@ -47,6 +46,8 @@ pub struct Request {
|
||||||
body_used: Cell<bool>,
|
body_used: Cell<bool>,
|
||||||
headers: MutNullableHeap<JS<Headers>>,
|
headers: MutNullableHeap<JS<Headers>>,
|
||||||
mime_type: DOMRefCell<Vec<u8>>,
|
mime_type: DOMRefCell<Vec<u8>>,
|
||||||
|
#[ignore_heap_size_of = "Rc"]
|
||||||
|
body_promise: DOMRefCell<Option<(Rc<Promise>, BodyType)>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Request {
|
impl Request {
|
||||||
|
@ -62,6 +63,7 @@ impl Request {
|
||||||
body_used: Cell::new(false),
|
body_used: Cell::new(false),
|
||||||
headers: Default::default(),
|
headers: Default::default(),
|
||||||
mime_type: DOMRefCell::new("".to_string().into_bytes()),
|
mime_type: DOMRefCell::new("".to_string().into_bytes()),
|
||||||
|
body_promise: DOMRefCell::new(None),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -662,20 +664,20 @@ impl BodyOperations for Request {
|
||||||
self.BodyUsed()
|
self.BodyUsed()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn set_body_promise(&self, p: &Rc<Promise>, body_type: BodyType) {
|
||||||
|
assert!(self.body_promise.borrow().is_none());
|
||||||
|
self.body_used.set(true);
|
||||||
|
*self.body_promise.borrow_mut() = Some((p.clone(), body_type));
|
||||||
|
}
|
||||||
|
|
||||||
fn is_locked(&self) -> bool {
|
fn is_locked(&self) -> bool {
|
||||||
self.locked()
|
self.locked()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn take_body(&self) -> Option<Vec<u8>> {
|
fn take_body(&self) -> Option<Vec<u8>> {
|
||||||
let ref mut net_traits_req = *self.request.borrow_mut();
|
let request = self.request.borrow_mut();
|
||||||
let body: Option<Vec<u8>> = mem::replace(&mut *net_traits_req.body.borrow_mut(), None);
|
let body = request.body.borrow_mut().take();
|
||||||
match body {
|
Some(body.unwrap_or(vec![]))
|
||||||
Some(_) => {
|
|
||||||
self.body_used.set(true);
|
|
||||||
body
|
|
||||||
},
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_mime_type(&self) -> Ref<Vec<u8>> {
|
fn get_mime_type(&self) -> Ref<Vec<u8>> {
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
* 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 body::{BodyOperations, BodyType, consume_body, consume_body_with_promise};
|
||||||
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;
|
||||||
|
@ -44,6 +44,8 @@ pub struct Response {
|
||||||
url_list: DOMRefCell<Vec<Url>>,
|
url_list: DOMRefCell<Vec<Url>>,
|
||||||
// For now use the existing NetTraitsResponseBody enum
|
// For now use the existing NetTraitsResponseBody enum
|
||||||
body: DOMRefCell<NetTraitsResponseBody>,
|
body: DOMRefCell<NetTraitsResponseBody>,
|
||||||
|
#[ignore_heap_size_of = "Rc"]
|
||||||
|
body_promise: DOMRefCell<Option<(Rc<Promise>, BodyType)>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Response {
|
impl Response {
|
||||||
|
@ -59,6 +61,7 @@ impl Response {
|
||||||
url: DOMRefCell::new(None),
|
url: DOMRefCell::new(None),
|
||||||
url_list: DOMRefCell::new(vec![]),
|
url_list: DOMRefCell::new(vec![]),
|
||||||
body: DOMRefCell::new(NetTraitsResponseBody::Empty),
|
body: DOMRefCell::new(NetTraitsResponseBody::Empty),
|
||||||
|
body_promise: DOMRefCell::new(None),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -194,18 +197,26 @@ impl BodyOperations for Response {
|
||||||
self.BodyUsed()
|
self.BodyUsed()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn set_body_promise(&self, p: &Rc<Promise>, body_type: BodyType) {
|
||||||
|
assert!(self.body_promise.borrow().is_none());
|
||||||
|
self.body_used.set(true);
|
||||||
|
*self.body_promise.borrow_mut() = Some((p.clone(), body_type));
|
||||||
|
}
|
||||||
|
|
||||||
fn is_locked(&self) -> bool {
|
fn is_locked(&self) -> bool {
|
||||||
self.locked()
|
self.locked()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn take_body(&self) -> Option<Vec<u8>> {
|
fn take_body(&self) -> Option<Vec<u8>> {
|
||||||
let body: NetTraitsResponseBody = mem::replace(&mut *self.body.borrow_mut(), NetTraitsResponseBody::Empty);
|
let body = mem::replace(&mut *self.body.borrow_mut(), NetTraitsResponseBody::Empty);
|
||||||
match body {
|
match body {
|
||||||
NetTraitsResponseBody::Done(bytes) | NetTraitsResponseBody::Receiving(bytes) => {
|
NetTraitsResponseBody::Done(bytes) => {
|
||||||
self.body_used.set(true);
|
|
||||||
Some(bytes)
|
Some(bytes)
|
||||||
},
|
},
|
||||||
_ => None,
|
body => {
|
||||||
|
mem::replace(&mut *self.body.borrow_mut(), body);
|
||||||
|
None
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -366,4 +377,12 @@ impl Response {
|
||||||
pub fn set_final_url(&self, final_url: Url) {
|
pub fn set_final_url(&self, final_url: Url) {
|
||||||
*self.url.borrow_mut() = Some(final_url);
|
*self.url.borrow_mut() = Some(final_url);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(unrooted_must_root)]
|
||||||
|
pub fn finish(&self, body: Vec<u8>) {
|
||||||
|
*self.body.borrow_mut() = NetTraitsResponseBody::Done(body);
|
||||||
|
if let Some((p, body_type)) = self.body_promise.borrow_mut().take() {
|
||||||
|
consume_body_with_promise(self, body_type, &p);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@ use net_traits::CoreResourceMsg::Fetch as NetTraitsFetch;
|
||||||
use net_traits::request::Request as NetTraitsRequest;
|
use net_traits::request::Request as NetTraitsRequest;
|
||||||
use net_traits::request::RequestInit as NetTraitsRequestInit;
|
use net_traits::request::RequestInit as NetTraitsRequestInit;
|
||||||
use network_listener::{NetworkListener, PreInvoke};
|
use network_listener::{NetworkListener, PreInvoke};
|
||||||
|
use std::mem;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
@ -31,6 +32,7 @@ use url::Url;
|
||||||
struct FetchContext {
|
struct FetchContext {
|
||||||
fetch_promise: Option<TrustedPromise>,
|
fetch_promise: Option<TrustedPromise>,
|
||||||
response_object: Trusted<Response>,
|
response_object: Trusted<Response>,
|
||||||
|
body: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_referrer_to_referrer_url(request: &NetTraitsRequest) -> Option<Url> {
|
fn from_referrer_to_referrer_url(request: &NetTraitsRequest) -> Option<Url> {
|
||||||
|
@ -89,6 +91,7 @@ pub fn Fetch(global: GlobalRef, input: RequestOrUSVString, init: &RequestInit) -
|
||||||
let fetch_context = Arc::new(Mutex::new(FetchContext {
|
let fetch_context = Arc::new(Mutex::new(FetchContext {
|
||||||
fetch_promise: Some(TrustedPromise::new(promise.clone())),
|
fetch_promise: Some(TrustedPromise::new(promise.clone())),
|
||||||
response_object: Trusted::new(&*response),
|
response_object: Trusted::new(&*response),
|
||||||
|
body: vec![],
|
||||||
}));
|
}));
|
||||||
let listener = NetworkListener {
|
let listener = NetworkListener {
|
||||||
context: fetch_context,
|
context: fetch_context,
|
||||||
|
@ -153,12 +156,16 @@ impl FetchResponseListener for FetchContext {
|
||||||
self.fetch_promise = Some(TrustedPromise::new(promise));
|
self.fetch_promise = Some(TrustedPromise::new(promise));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn process_response_chunk(&mut self, _chunk: Vec<u8>) {
|
fn process_response_chunk(&mut self, mut chunk: Vec<u8>) {
|
||||||
// TODO when body is implemented
|
self.body.append(&mut chunk);
|
||||||
// ... this will append the chunk to Response's body.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn process_response_eof(&mut self, _response: Result<(), NetworkError>) {
|
fn process_response_eof(&mut self, _response: Result<(), NetworkError>) {
|
||||||
|
let response = self.response_object.root();
|
||||||
|
let global = response.global();
|
||||||
|
let cx = global.r().get_cx();
|
||||||
|
let _ac = JSAutoCompartment::new(cx, global.r().reflector().get_jsobject().get());
|
||||||
|
response.finish(mem::replace(&mut self.body, vec![]));
|
||||||
// TODO
|
// TODO
|
||||||
// ... trailerObject is not supported in Servo yet.
|
// ... trailerObject is not supported in Servo yet.
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,45 +18,21 @@
|
||||||
[UTF-8 without BOM with Response.text()]
|
[UTF-8 without BOM with Response.text()]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[UTF-8 without BOM with fetched data (UTF-8 charset)]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[UTF-8 without BOM with fetched data (UTF-16 charset)]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[UTF-16BE with BOM decoded as UTF-8 with Request.text()]
|
[UTF-16BE with BOM decoded as UTF-8 with Request.text()]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[UTF-16BE with BOM decoded as UTF-8 with Response.text()]
|
[UTF-16BE with BOM decoded as UTF-8 with Response.text()]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[UTF-16BE with BOM decoded as UTF-8 with fetched data (UTF-8 charset)]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[UTF-16BE with BOM decoded as UTF-8 with fetched data (UTF-16 charset)]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[UTF-16LE with BOM decoded as UTF-8 with Request.text()]
|
[UTF-16LE with BOM decoded as UTF-8 with Request.text()]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[UTF-16LE with BOM decoded as UTF-8 with Response.text()]
|
[UTF-16LE with BOM decoded as UTF-8 with Response.text()]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[UTF-16LE with BOM decoded as UTF-8 with fetched data (UTF-8 charset)]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[UTF-16LE with BOM decoded as UTF-8 with fetched data (UTF-16 charset)]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[UTF-16 without BOM decoded as UTF-8 with Request.text()]
|
[UTF-16 without BOM decoded as UTF-8 with Request.text()]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[UTF-16 without BOM decoded as UTF-8 with Response.text()]
|
[UTF-16 without BOM decoded as UTF-8 with Response.text()]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[UTF-16 without BOM decoded as UTF-8 with fetched data (UTF-8 charset)]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[UTF-16 without BOM decoded as UTF-8 with fetched data (UTF-16 charset)]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
|
|
|
@ -12,3 +12,12 @@
|
||||||
[Consume empty text request body as arrayBuffer]
|
[Consume empty text request body as arrayBuffer]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
[Consume request's body as text]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Consume request's body as blob]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Consume request's body as json]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -12,3 +12,6 @@
|
||||||
[Request construction failure should not set "bodyUsed"]
|
[Request construction failure should not set "bodyUsed"]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
[Request without body cannot be disturbed]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -1,14 +1,30 @@
|
||||||
[response-consume-empty.html]
|
[response-consume-empty.html]
|
||||||
type: testharness
|
type: testharness
|
||||||
|
expected: TIMEOUT
|
||||||
[Consume response's body as arrayBuffer]
|
[Consume response's body as arrayBuffer]
|
||||||
expected: FAIL
|
expected: NOTRUN
|
||||||
|
|
||||||
[Consume response's body as formData]
|
[Consume response's body as formData]
|
||||||
expected: FAIL
|
expected: NOTRUN
|
||||||
|
|
||||||
[Consume empty blob response body as arrayBuffer]
|
[Consume empty blob response body as arrayBuffer]
|
||||||
expected: FAIL
|
expected: NOTRUN
|
||||||
|
|
||||||
[Consume empty text response body as arrayBuffer]
|
[Consume empty text response body as arrayBuffer]
|
||||||
expected: FAIL
|
expected: NOTRUN
|
||||||
|
|
||||||
|
[Consume response's body as text]
|
||||||
|
expected: TIMEOUT
|
||||||
|
|
||||||
|
[Consume response's body as blob]
|
||||||
|
expected: NOTRUN
|
||||||
|
|
||||||
|
[Consume response's body as json]
|
||||||
|
expected: NOTRUN
|
||||||
|
|
||||||
|
[Consume empty blob response body as text]
|
||||||
|
expected: NOTRUN
|
||||||
|
|
||||||
|
[Consume empty text response body as text]
|
||||||
|
expected: NOTRUN
|
||||||
|
|
||||||
|
|
|
@ -21,12 +21,6 @@
|
||||||
[Consume stream response's body as arrayBuffer]
|
[Consume stream response's body as arrayBuffer]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[Consume fetched response's body as blob]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Consume fetched response's body as text]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Consume fetched response's body as arrayBuffer]
|
[Consume fetched response's body as arrayBuffer]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue