diff options
author | Gregory Terzian <gterzian@users.noreply.github.com> | 2020-02-29 11:59:10 +0800 |
---|---|---|
committer | Gregory Terzian <gterzian@users.noreply.github.com> | 2020-06-04 11:38:35 +0800 |
commit | bd5796c90b8e8e066a32e7da9cfa5251d1559046 (patch) | |
tree | aa5ed3de6608b8046924ef6e8e8ad43b91cf81a7 /components/script/dom/xmlhttprequest.rs | |
parent | 0281acea955085aec01a4fc6da5f89f326a14842 (diff) | |
download | servo-bd5796c90b8e8e066a32e7da9cfa5251d1559046.tar.gz servo-bd5796c90b8e8e066a32e7da9cfa5251d1559046.zip |
integrate readablestream with fetch and blob
Diffstat (limited to 'components/script/dom/xmlhttprequest.rs')
-rw-r--r-- | components/script/dom/xmlhttprequest.rs | 185 |
1 files changed, 89 insertions, 96 deletions
diff --git a/components/script/dom/xmlhttprequest.rs b/components/script/dom/xmlhttprequest.rs index 336d7a89f22..1bb0ebd60dd 100644 --- a/components/script/dom/xmlhttprequest.rs +++ b/components/script/dom/xmlhttprequest.rs @@ -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(&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::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::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 { |