mirror of
https://github.com/servo/servo.git
synced 2025-08-06 06:00:15 +01:00
integrate readablestream with fetch and blob
This commit is contained in:
parent
0281acea95
commit
bd5796c90b
74 changed files with 2219 additions and 899 deletions
|
@ -2,11 +2,10 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use crate::body::{Extractable, ExtractedBody};
|
||||
use crate::document_loader::DocumentLoader;
|
||||
use crate::dom::bindings::cell::DomRefCell;
|
||||
use crate::dom::bindings::codegen::Bindings::BlobBinding::BlobBinding::BlobMethods;
|
||||
use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowMethods;
|
||||
use crate::dom::bindings::codegen::Bindings::XMLHttpRequestBinding::BodyInit;
|
||||
use crate::dom::bindings::codegen::Bindings::XMLHttpRequestBinding::XMLHttpRequestMethods;
|
||||
use crate::dom::bindings::codegen::Bindings::XMLHttpRequestBinding::XMLHttpRequestResponseType;
|
||||
use crate::dom::bindings::codegen::UnionTypes::DocumentOrBodyInit;
|
||||
|
@ -22,15 +21,13 @@ use crate::dom::document::DocumentSource;
|
|||
use crate::dom::document::{Document, HasBrowsingContext, IsHTMLDocument};
|
||||
use crate::dom::event::{Event, EventBubbles, EventCancelable};
|
||||
use crate::dom::eventtarget::EventTarget;
|
||||
use crate::dom::formdata::FormData;
|
||||
use crate::dom::globalscope::GlobalScope;
|
||||
use crate::dom::headers::is_forbidden_header_name;
|
||||
use crate::dom::htmlformelement::{encode_multipart_form_data, generate_boundary};
|
||||
use crate::dom::node::Node;
|
||||
use crate::dom::performanceresourcetiming::InitiatorType;
|
||||
use crate::dom::progressevent::ProgressEvent;
|
||||
use crate::dom::readablestream::ReadableStream;
|
||||
use crate::dom::servoparser::ServoParser;
|
||||
use crate::dom::urlsearchparams::URLSearchParams;
|
||||
use crate::dom::window::Window;
|
||||
use crate::dom::workerglobalscope::WorkerGlobalScope;
|
||||
use crate::dom::xmlhttprequesteventtarget::XMLHttpRequestEventTarget;
|
||||
|
@ -58,7 +55,9 @@ use js::jsval::{JSVal, NullValue, UndefinedValue};
|
|||
use js::rust::wrappers::JS_ParseJSON;
|
||||
use js::typedarray::{ArrayBuffer, CreateWith};
|
||||
use mime::{self, Mime, Name};
|
||||
use net_traits::request::{CredentialsMode, Destination, Referrer, RequestBuilder, RequestMode};
|
||||
use net_traits::request::{
|
||||
BodySource, CredentialsMode, Destination, Referrer, RequestBuilder, RequestMode,
|
||||
};
|
||||
use net_traits::trim_http_whitespace;
|
||||
use net_traits::CoreResourceMsg::Fetch;
|
||||
use net_traits::{FetchChannels, FetchMetadata, FilteredMetadata};
|
||||
|
@ -562,42 +561,96 @@ impl XMLHttpRequestMethods for XMLHttpRequest {
|
|||
_ => data,
|
||||
};
|
||||
// Step 4 (first half)
|
||||
let extracted_or_serialized = match data {
|
||||
let mut extracted_or_serialized = match data {
|
||||
Some(DocumentOrBodyInit::Document(ref doc)) => {
|
||||
let data = Vec::from(serialize_document(&doc)?.as_ref());
|
||||
let bytes = Vec::from(serialize_document(&doc)?.as_ref());
|
||||
let content_type = if doc.is_html_document() {
|
||||
"text/html;charset=UTF-8"
|
||||
} else {
|
||||
"application/xml;charset=UTF-8"
|
||||
};
|
||||
Some((data, Some(DOMString::from(content_type))))
|
||||
let total_bytes = bytes.len();
|
||||
let global = self.global();
|
||||
let stream = ReadableStream::new_from_bytes(&global, bytes);
|
||||
Some(ExtractedBody {
|
||||
stream,
|
||||
total_bytes: Some(total_bytes),
|
||||
content_type: Some(DOMString::from(content_type)),
|
||||
source: BodySource::Null,
|
||||
})
|
||||
},
|
||||
Some(DocumentOrBodyInit::Blob(ref b)) => Some(b.extract()),
|
||||
Some(DocumentOrBodyInit::FormData(ref formdata)) => Some(formdata.extract()),
|
||||
Some(DocumentOrBodyInit::String(ref str)) => Some(str.extract()),
|
||||
Some(DocumentOrBodyInit::URLSearchParams(ref urlsp)) => Some(urlsp.extract()),
|
||||
Some(DocumentOrBodyInit::Blob(ref b)) => {
|
||||
Some(b.extract(&self.global()).expect("Couldn't extract body."))
|
||||
},
|
||||
Some(DocumentOrBodyInit::FormData(ref formdata)) => Some(
|
||||
formdata
|
||||
.extract(&self.global())
|
||||
.expect("Couldn't extract body."),
|
||||
),
|
||||
Some(DocumentOrBodyInit::String(ref str)) => {
|
||||
Some(str.extract(&self.global()).expect("Couldn't extract body."))
|
||||
},
|
||||
Some(DocumentOrBodyInit::URLSearchParams(ref urlsp)) => Some(
|
||||
urlsp
|
||||
.extract(&self.global())
|
||||
.expect("Couldn't extract body."),
|
||||
),
|
||||
Some(DocumentOrBodyInit::ArrayBuffer(ref typedarray)) => {
|
||||
Some((typedarray.to_vec(), None))
|
||||
let bytes = typedarray.to_vec();
|
||||
let total_bytes = bytes.len();
|
||||
let global = self.global();
|
||||
let stream = ReadableStream::new_from_bytes(&global, bytes);
|
||||
Some(ExtractedBody {
|
||||
stream,
|
||||
total_bytes: Some(total_bytes),
|
||||
content_type: None,
|
||||
source: BodySource::BufferSource,
|
||||
})
|
||||
},
|
||||
Some(DocumentOrBodyInit::ArrayBufferView(ref typedarray)) => {
|
||||
Some((typedarray.to_vec(), None))
|
||||
let bytes = typedarray.to_vec();
|
||||
let total_bytes = bytes.len();
|
||||
let global = self.global();
|
||||
let stream = ReadableStream::new_from_bytes(&global, bytes);
|
||||
Some(ExtractedBody {
|
||||
stream,
|
||||
total_bytes: Some(total_bytes),
|
||||
content_type: None,
|
||||
source: BodySource::BufferSource,
|
||||
})
|
||||
},
|
||||
Some(DocumentOrBodyInit::ReadableStream(ref stream)) => {
|
||||
// TODO:
|
||||
// 1. If the keepalive flag is set, then throw a TypeError.
|
||||
|
||||
if stream.is_locked() || stream.is_disturbed() {
|
||||
return Err(Error::Type(
|
||||
"The body's stream is disturbed or locked".to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
Some(ExtractedBody {
|
||||
stream: stream.clone(),
|
||||
total_bytes: None,
|
||||
content_type: None,
|
||||
source: BodySource::Null,
|
||||
})
|
||||
},
|
||||
None => None,
|
||||
};
|
||||
|
||||
self.request_body_len
|
||||
.set(extracted_or_serialized.as_ref().map_or(0, |e| e.0.len()));
|
||||
self.request_body_len.set(
|
||||
extracted_or_serialized
|
||||
.as_ref()
|
||||
.map_or(0, |e| e.total_bytes.unwrap_or(0)),
|
||||
);
|
||||
|
||||
// todo preserved headers?
|
||||
|
||||
// Step 6
|
||||
self.upload_complete.set(false);
|
||||
// Step 7
|
||||
self.upload_complete.set(match extracted_or_serialized {
|
||||
None => true,
|
||||
Some(ref e) if e.0.is_empty() => true,
|
||||
_ => false,
|
||||
});
|
||||
self.upload_complete.set(extracted_or_serialized.is_none());
|
||||
// Step 8
|
||||
self.send_flag.set(true);
|
||||
|
||||
|
@ -634,12 +687,17 @@ impl XMLHttpRequestMethods for XMLHttpRequest {
|
|||
unreachable!()
|
||||
};
|
||||
|
||||
let content_type = match extracted_or_serialized.as_mut() {
|
||||
Some(body) => body.content_type.take(),
|
||||
None => None,
|
||||
};
|
||||
|
||||
let mut request = RequestBuilder::new(self.request_url.borrow().clone().unwrap())
|
||||
.method(self.request_method.borrow().clone())
|
||||
.headers((*self.request_headers.borrow()).clone())
|
||||
.unsafe_request(true)
|
||||
// XXXManishearth figure out how to avoid this clone
|
||||
.body(extracted_or_serialized.as_ref().map(|e| e.0.clone()))
|
||||
.body(extracted_or_serialized.map(|e| e.into_net_request_body().0))
|
||||
// XXXManishearth actually "subresource", but it doesn't exist
|
||||
// https://github.com/whatwg/xhr/issues/71
|
||||
.destination(Destination::None)
|
||||
|
@ -658,8 +716,8 @@ impl XMLHttpRequestMethods for XMLHttpRequest {
|
|||
.pipeline_id(Some(self.global().pipeline_id()));
|
||||
|
||||
// step 4 (second half)
|
||||
match extracted_or_serialized {
|
||||
Some((_, ref content_type)) => {
|
||||
match content_type {
|
||||
Some(content_type) => {
|
||||
let encoding = match data {
|
||||
Some(DocumentOrBodyInit::String(_)) | Some(DocumentOrBodyInit::Document(_)) =>
|
||||
// XHR spec differs from http, and says UTF-8 should be in capitals,
|
||||
|
@ -672,13 +730,12 @@ impl XMLHttpRequestMethods for XMLHttpRequest {
|
|||
};
|
||||
|
||||
let mut content_type_set = false;
|
||||
if let Some(ref ct) = *content_type {
|
||||
if !request.headers.contains_key(header::CONTENT_TYPE) {
|
||||
request
|
||||
.headers
|
||||
.insert(header::CONTENT_TYPE, HeaderValue::from_str(ct).unwrap());
|
||||
content_type_set = true;
|
||||
}
|
||||
if !request.headers.contains_key(header::CONTENT_TYPE) {
|
||||
request.headers.insert(
|
||||
header::CONTENT_TYPE,
|
||||
HeaderValue::from_str(&content_type).unwrap(),
|
||||
);
|
||||
content_type_set = true;
|
||||
}
|
||||
|
||||
if !content_type_set {
|
||||
|
@ -1555,56 +1612,6 @@ impl XHRTimeoutCallback {
|
|||
}
|
||||
}
|
||||
|
||||
pub trait Extractable {
|
||||
fn extract(&self) -> (Vec<u8>, Option<DOMString>);
|
||||
}
|
||||
|
||||
impl Extractable for Blob {
|
||||
fn extract(&self) -> (Vec<u8>, Option<DOMString>) {
|
||||
let content_type = if self.Type().as_ref().is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(self.Type())
|
||||
};
|
||||
let bytes = self.get_bytes().unwrap_or(vec![]);
|
||||
(bytes, content_type)
|
||||
}
|
||||
}
|
||||
|
||||
impl Extractable for DOMString {
|
||||
fn extract(&self) -> (Vec<u8>, Option<DOMString>) {
|
||||
(
|
||||
self.as_bytes().to_owned(),
|
||||
Some(DOMString::from("text/plain;charset=UTF-8")),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl Extractable for FormData {
|
||||
fn extract(&self) -> (Vec<u8>, Option<DOMString>) {
|
||||
let boundary = generate_boundary();
|
||||
let bytes = encode_multipart_form_data(&mut self.datums(), boundary.clone(), UTF_8);
|
||||
(
|
||||
bytes,
|
||||
Some(DOMString::from(format!(
|
||||
"multipart/form-data;boundary={}",
|
||||
boundary
|
||||
))),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl Extractable for URLSearchParams {
|
||||
fn extract(&self) -> (Vec<u8>, Option<DOMString>) {
|
||||
(
|
||||
self.serialize_utf8().into_bytes(),
|
||||
Some(DOMString::from(
|
||||
"application/x-www-form-urlencoded;charset=UTF-8",
|
||||
)),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn serialize_document(doc: &Document) -> Fallible<DOMString> {
|
||||
let mut writer = vec![];
|
||||
match serialize(&mut writer, &doc.upcast::<Node>(), SerializeOpts::default()) {
|
||||
|
@ -1613,20 +1620,6 @@ fn serialize_document(doc: &Document) -> Fallible<DOMString> {
|
|||
}
|
||||
}
|
||||
|
||||
impl Extractable for BodyInit {
|
||||
// https://fetch.spec.whatwg.org/#concept-bodyinit-extract
|
||||
fn extract(&self) -> (Vec<u8>, Option<DOMString>) {
|
||||
match *self {
|
||||
BodyInit::String(ref s) => s.extract(),
|
||||
BodyInit::URLSearchParams(ref usp) => usp.extract(),
|
||||
BodyInit::Blob(ref b) => b.extract(),
|
||||
BodyInit::FormData(ref formdata) => formdata.extract(),
|
||||
BodyInit::ArrayBuffer(ref typedarray) => ((typedarray.to_vec(), None)),
|
||||
BodyInit::ArrayBufferView(ref typedarray) => ((typedarray.to_vec(), None)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns whether `bs` is a `field-value`, as defined by
|
||||
/// [RFC 2616](http://tools.ietf.org/html/rfc2616#page-32).
|
||||
pub fn is_field_value(slice: &[u8]) -> bool {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue