aboutsummaryrefslogtreecommitdiffstats
path: root/components/script/dom
diff options
context:
space:
mode:
Diffstat (limited to 'components/script/dom')
-rw-r--r--components/script/dom/bindings/structuredclone.rs8
-rw-r--r--components/script/dom/blob.rs71
-rw-r--r--components/script/dom/headers.rs73
-rw-r--r--components/script/dom/readablestream.rs46
-rw-r--r--components/script/dom/transformstream.rs104
-rw-r--r--components/script/dom/webglrenderingcontext.rs3
-rw-r--r--components/script/dom/xmlhttprequest.rs155
7 files changed, 240 insertions, 220 deletions
diff --git a/components/script/dom/bindings/structuredclone.rs b/components/script/dom/bindings/structuredclone.rs
index 70638238123..c23156817cb 100644
--- a/components/script/dom/bindings/structuredclone.rs
+++ b/components/script/dom/bindings/structuredclone.rs
@@ -14,7 +14,7 @@ use base::id::{
};
use constellation_traits::{
BlobImpl, DomException, DomPoint, MessagePortImpl, Serializable as SerializableInterface,
- StructuredSerializedData, Transferrable as TransferrableInterface,
+ StructuredSerializedData, Transferrable as TransferrableInterface, TransformStreamData,
};
use js::gc::RootedVec;
use js::glue::{
@@ -517,6 +517,8 @@ pub(crate) struct StructuredDataReader<'a> {
/// used as part of the "transfer-receiving" steps of ports,
/// to produce the DOM ports stored in `message_ports` above.
pub(crate) port_impls: Option<HashMap<MessagePortId, MessagePortImpl>>,
+ /// A map of transform stream implementations,
+ pub(crate) transform_streams_port_impls: Option<HashMap<MessagePortId, TransformStreamData>>,
/// A map of blob implementations,
/// used as part of the "deserialize" steps of blobs,
/// to produce the DOM blobs stored in `blobs` above.
@@ -535,6 +537,8 @@ pub(crate) struct StructuredDataWriter {
pub(crate) errors: DOMErrorRecord,
/// Transferred ports.
pub(crate) ports: Option<HashMap<MessagePortId, MessagePortImpl>>,
+ /// Transferred transform streams.
+ pub(crate) transform_streams_port: Option<HashMap<MessagePortId, TransformStreamData>>,
/// Serialized points.
pub(crate) points: Option<HashMap<DomPointId, DomPoint>>,
/// Serialized exceptions.
@@ -591,6 +595,7 @@ pub(crate) fn write(
let data = StructuredSerializedData {
serialized: data,
ports: sc_writer.ports.take(),
+ transform_streams: sc_writer.transform_streams_port.take(),
points: sc_writer.points.take(),
exceptions: sc_writer.exceptions.take(),
blobs: sc_writer.blobs.take(),
@@ -613,6 +618,7 @@ pub(crate) fn read(
let mut sc_reader = StructuredDataReader {
roots,
port_impls: data.ports.take(),
+ transform_streams_port_impls: data.transform_streams.take(),
blob_impls: data.blobs.take(),
points: data.points.take(),
exceptions: data.exceptions.take(),
diff --git a/components/script/dom/blob.rs b/components/script/dom/blob.rs
index c5c5c480707..18e968aaa70 100644
--- a/components/script/dom/blob.rs
+++ b/components/script/dom/blob.rs
@@ -12,11 +12,10 @@ use dom_struct::dom_struct;
use encoding_rs::UTF_8;
use js::jsapi::JSObject;
use js::rust::HandleObject;
-use js::typedarray::Uint8;
+use js::typedarray::{ArrayBufferU8, Uint8};
use net_traits::filemanager_thread::RelativePos;
use uuid::Uuid;
-use crate::body::{FetchedData, run_array_buffer_data_algorithm};
use crate::dom::bindings::buffer_source::create_buffer_source;
use crate::dom::bindings::codegen::Bindings::BlobBinding;
use crate::dom::bindings::codegen::Bindings::BlobBinding::BlobMethods;
@@ -226,7 +225,7 @@ impl BlobMethods<crate::DomTypeHolder> for Blob {
Blob::new(&global, blob_impl, can_gc)
}
- // https://w3c.github.io/FileAPI/#text-method-algo
+ /// <https://w3c.github.io/FileAPI/#text-method-algo>
fn Text(&self, can_gc: CanGc) -> Rc<Promise> {
let global = self.global();
let in_realm_proof = AlreadyInRealm::assert::<crate::DomTypeHolder>();
@@ -250,35 +249,51 @@ impl BlobMethods<crate::DomTypeHolder> for Blob {
}
// https://w3c.github.io/FileAPI/#arraybuffer-method-algo
- fn ArrayBuffer(&self, can_gc: CanGc) -> Rc<Promise> {
- let global = self.global();
- let in_realm_proof = AlreadyInRealm::assert::<crate::DomTypeHolder>();
- let p = Promise::new_in_current_realm(InRealm::Already(&in_realm_proof), can_gc);
+ fn ArrayBuffer(&self, in_realm: InRealm, can_gc: CanGc) -> Rc<Promise> {
+ let cx = GlobalScope::get_cx();
+ let global = GlobalScope::from_safe_context(cx, in_realm);
+ let promise = Promise::new_in_current_realm(in_realm, can_gc);
- let id = self.get_blob_url_id();
+ // 1. Let stream be the result of calling get stream on this.
+ let stream = self.get_stream(can_gc);
- global.read_file_async(
- id,
- p.clone(),
- Box::new(|promise, bytes| {
- match bytes {
- Ok(b) => {
- let cx = GlobalScope::get_cx();
- let result = run_array_buffer_data_algorithm(cx, b, CanGc::note());
-
- match result {
- Ok(FetchedData::ArrayBuffer(a)) => {
- promise.resolve_native(&a, CanGc::note())
- },
- Err(e) => promise.reject_error(e, CanGc::note()),
- _ => panic!("Unexpected result from run_array_buffer_data_algorithm"),
- }
- },
- Err(e) => promise.reject_error(e, CanGc::note()),
- };
+ // 2. Let reader be the result of getting a reader from stream.
+ // If that threw an exception, return a new promise rejected with that exception.
+ let reader = match stream.and_then(|s| s.acquire_default_reader(can_gc)) {
+ Ok(reader) => reader,
+ Err(error) => {
+ promise.reject_error(error, can_gc);
+ return promise;
+ },
+ };
+
+ // 3. Let promise be the result of reading all bytes from stream with reader.
+ let success_promise = promise.clone();
+ let failure_promise = promise.clone();
+ reader.read_all_bytes(
+ cx,
+ &global,
+ Rc::new(move |bytes| {
+ rooted!(in(*cx) let mut js_object = ptr::null_mut::<JSObject>());
+ // 4. Return the result of transforming promise by a fulfillment handler that returns a new
+ // [ArrayBuffer]
+ let array_buffer = create_buffer_source::<ArrayBufferU8>(
+ cx,
+ bytes,
+ js_object.handle_mut(),
+ can_gc,
+ )
+ .expect("Converting input to ArrayBufferU8 should never fail");
+ success_promise.resolve_native(&array_buffer, can_gc);
}),
+ Rc::new(move |cx, value| {
+ failure_promise.reject(cx, value, can_gc);
+ }),
+ in_realm,
+ can_gc,
);
- p
+
+ promise
}
/// <https://w3c.github.io/FileAPI/#dom-blob-bytes>
diff --git a/components/script/dom/headers.rs b/components/script/dom/headers.rs
index 10a8be731bf..0e8dcf92ccd 100644
--- a/components/script/dom/headers.rs
+++ b/components/script/dom/headers.rs
@@ -5,12 +5,12 @@
use std::cell::Cell;
use std::str::{self, FromStr};
-use data_url::mime::Mime as DataUrlMime;
use dom_struct::dom_struct;
use http::header::{HeaderMap as HyperHeaders, HeaderName, HeaderValue};
use js::rust::HandleObject;
use net_traits::fetch::headers::{
- get_decode_and_split_header_value, get_value_from_header_list, is_forbidden_method,
+ extract_mime_type, get_decode_and_split_header_value, get_value_from_header_list,
+ is_forbidden_method,
};
use net_traits::request::is_cors_safelisted_request_header;
@@ -564,72 +564,3 @@ pub(crate) fn is_vchar(x: u8) -> bool {
pub(crate) fn is_obs_text(x: u8) -> bool {
matches!(x, 0x80..=0xFF)
}
-
-// https://fetch.spec.whatwg.org/#concept-header-extract-mime-type
-// This function uses data_url::Mime to parse the MIME Type because
-// mime::Mime does not provide a parser following the Fetch spec
-// see https://github.com/hyperium/mime/issues/106
-pub(crate) fn extract_mime_type(headers: &HyperHeaders) -> Option<Vec<u8>> {
- let mut charset: Option<String> = None;
- let mut essence: String = "".to_string();
- let mut mime_type: Option<DataUrlMime> = None;
-
- // Step 4
- let headers_values = headers.get_all(http::header::CONTENT_TYPE).iter();
-
- // Step 5
- if headers_values.size_hint() == (0, Some(0)) {
- return None;
- }
-
- // Step 6
- for header_value in headers_values {
- // Step 6.1
- match DataUrlMime::from_str(header_value.to_str().unwrap_or("")) {
- // Step 6.2
- Err(_) => continue,
- Ok(temp_mime) => {
- let temp_essence = format!("{}/{}", temp_mime.type_, temp_mime.subtype);
-
- // Step 6.2
- if temp_essence == "*/*" {
- continue;
- }
-
- let temp_charset = &temp_mime.get_parameter("charset");
-
- // Step 6.3
- mime_type = Some(DataUrlMime {
- type_: temp_mime.type_.to_string(),
- subtype: temp_mime.subtype.to_string(),
- parameters: temp_mime.parameters.clone(),
- });
-
- // Step 6.4
- if temp_essence != essence {
- charset = temp_charset.map(|c| c.to_string());
- temp_essence.clone_into(&mut essence);
- } else {
- // Step 6.5
- if temp_charset.is_none() && charset.is_some() {
- let DataUrlMime {
- type_: t,
- subtype: st,
- parameters: p,
- } = mime_type.unwrap();
- let mut params = p;
- params.push(("charset".to_string(), charset.clone().unwrap()));
- mime_type = Some(DataUrlMime {
- type_: t.to_string(),
- subtype: st.to_string(),
- parameters: params,
- })
- }
- }
- },
- }
- }
-
- // Step 7, 8
- mime_type.map(|m| format!("{}", m).into_bytes())
-}
diff --git a/components/script/dom/readablestream.rs b/components/script/dom/readablestream.rs
index d631a01e1e7..d2c1d853f86 100644
--- a/components/script/dom/readablestream.rs
+++ b/components/script/dom/readablestream.rs
@@ -24,7 +24,7 @@ use js::typedarray::ArrayBufferViewU8;
use crate::dom::bindings::codegen::Bindings::QueuingStrategyBinding::QueuingStrategy;
use crate::dom::bindings::codegen::Bindings::ReadableStreamBinding::{
ReadableStreamGetReaderOptions, ReadableStreamMethods, ReadableStreamReaderMode,
- StreamPipeOptions,
+ ReadableWritablePair, StreamPipeOptions,
};
use script_bindings::str::DOMString;
@@ -2006,6 +2006,50 @@ impl ReadableStreamMethods<crate::DomTypeHolder> for ReadableStream {
can_gc,
)
}
+
+ /// <https://streams.spec.whatwg.org/#rs-pipe-through>
+ fn PipeThrough(
+ &self,
+ transform: &ReadableWritablePair,
+ options: &StreamPipeOptions,
+ realm: InRealm,
+ can_gc: CanGc,
+ ) -> Fallible<DomRoot<ReadableStream>> {
+ let global = self.global();
+ let cx = GlobalScope::get_cx();
+
+ // If ! IsReadableStreamLocked(this) is true, throw a TypeError exception.
+ if self.is_locked() {
+ return Err(Error::Type("Source stream is locked".to_owned()));
+ }
+
+ // If ! IsWritableStreamLocked(transform["writable"]) is true, throw a TypeError exception.
+ if transform.writable.is_locked() {
+ return Err(Error::Type("Destination stream is locked".to_owned()));
+ }
+
+ // Let signal be options["signal"] if it exists, or undefined otherwise.
+ // TODO: implement AbortSignal.
+
+ // Let promise be ! ReadableStreamPipeTo(this, transform["writable"],
+ // options["preventClose"], options["preventAbort"], options["preventCancel"], signal).
+ let promise = self.pipe_to(
+ cx,
+ &global,
+ &transform.writable,
+ options.preventAbort,
+ options.preventCancel,
+ options.preventClose,
+ realm,
+ can_gc,
+ );
+
+ // Set promise.[[PromiseIsHandled]] to true.
+ promise.set_promise_is_handled();
+
+ // Return transform["readable"].
+ Ok(transform.readable.clone())
+ }
}
#[allow(unsafe_code)]
diff --git a/components/script/dom/transformstream.rs b/components/script/dom/transformstream.rs
index 0251498980d..446bf71f172 100644
--- a/components/script/dom/transformstream.rs
+++ b/components/script/dom/transformstream.rs
@@ -8,7 +8,7 @@ use std::ptr::{self};
use std::rc::Rc;
use base::id::{MessagePortId, MessagePortIndex};
-use constellation_traits::MessagePortImpl;
+use constellation_traits::TransformStreamData;
use dom_struct::dom_struct;
use js::jsapi::{Heap, IsPromiseObject, JSObject};
use js::jsval::{JSVal, ObjectValue, UndefinedValue};
@@ -1007,9 +1007,9 @@ impl TransformStreamMethods<crate::DomTypeHolder> for TransformStream {
/// <https://streams.spec.whatwg.org/#ts-transfer>
impl Transferable for TransformStream {
type Index = MessagePortIndex;
- type Data = MessagePortImpl;
+ type Data = TransformStreamData;
- fn transfer(&self) -> Result<(MessagePortId, MessagePortImpl), ()> {
+ fn transfer(&self) -> Result<(MessagePortId, TransformStreamData), ()> {
let global = self.global();
let realm = enter_realm(&*global);
let comp = InRealm::Entered(&realm);
@@ -1023,73 +1023,85 @@ impl Transferable for TransformStream {
let writable = self.get_writable();
// If ! IsReadableStreamLocked(readable) is true, throw a "DataCloneError" DOMException.
- if readable.is_locked() {
- return Err(());
- }
-
// If ! IsWritableStreamLocked(writable) is true, throw a "DataCloneError" DOMException.
- if writable.is_locked() {
+ if readable.is_locked() || writable.is_locked() {
return Err(());
}
- // Create the shared port pair
- let port_1 = MessagePort::new(&global, can_gc);
- global.track_message_port(&port_1, None);
- let port_2 = MessagePort::new(&global, can_gc);
- global.track_message_port(&port_2, None);
- global.entangle_ports(*port_1.message_port_id(), *port_2.message_port_id());
+ // First port pair (readable → proxy writable)
+ let port1 = MessagePort::new(&global, can_gc);
+ global.track_message_port(&port1, None);
+ let port1_peer = MessagePort::new(&global, can_gc);
+ global.track_message_port(&port1_peer, None);
+ global.entangle_ports(*port1.message_port_id(), *port1_peer.message_port_id());
+
+ let proxy_readable = ReadableStream::new_with_proto(&global, None, can_gc);
+ proxy_readable.setup_cross_realm_transform_readable(cx, &port1, can_gc);
+ proxy_readable
+ .pipe_to(cx, &global, &writable, false, false, false, comp, can_gc)
+ .set_promise_is_handled();
+
+ // Second port pair (proxy readable → writable)
+ let port2 = MessagePort::new(&global, can_gc);
+ global.track_message_port(&port2, None);
+ let port2_peer = MessagePort::new(&global, can_gc);
+ global.track_message_port(&port2_peer, None);
+ global.entangle_ports(*port2.message_port_id(), *port2_peer.message_port_id());
- // Create a proxy WritableStream wired to port_1
let proxy_writable = WritableStream::new_with_proto(&global, None, can_gc);
- proxy_writable.setup_cross_realm_transform_writable(cx, &port_1, can_gc);
+ proxy_writable.setup_cross_realm_transform_writable(cx, &port2, can_gc);
// Pipe readable into the proxy writable (→ port_1)
- let pipe1 = readable.pipe_to(
- cx,
- &global,
- &proxy_writable,
- false,
- false,
- false,
- comp,
- can_gc,
- );
- pipe1.set_promise_is_handled();
-
- // Create a proxy ReadableStream wired to port_1
- let proxy_readable = ReadableStream::new_with_proto(&global, None, can_gc);
- proxy_readable.setup_cross_realm_transform_readable(cx, &port_1, can_gc);
-
- // Pipe proxy readable (← port_1) into writable
- let pipe2 =
- proxy_readable.pipe_to(cx, &global, &writable, false, false, false, comp, can_gc);
- pipe2.set_promise_is_handled();
+ readable
+ .pipe_to(
+ cx,
+ &global,
+ &proxy_writable,
+ false,
+ false,
+ false,
+ comp,
+ can_gc,
+ )
+ .set_promise_is_handled();
// Set dataHolder.[[readable]] to ! StructuredSerializeWithTransfer(readable, « readable »).
// Set dataHolder.[[writable]] to ! StructuredSerializeWithTransfer(writable, « writable »).
- port_2.transfer()
+ Ok((
+ *port1_peer.message_port_id(),
+ TransformStreamData {
+ readable: port1_peer.transfer()?,
+ writable: port2_peer.transfer()?,
+ },
+ ))
}
fn transfer_receive(
owner: &GlobalScope,
- id: MessagePortId,
- port_impl: MessagePortImpl,
+ _id: MessagePortId,
+ data: TransformStreamData,
) -> Result<DomRoot<Self>, ()> {
let can_gc = CanGc::note();
+ let cx = GlobalScope::get_cx();
+
+ let port1 = MessagePort::transfer_receive(owner, data.readable.0, data.readable.1)?;
+ let port2 = MessagePort::transfer_receive(owner, data.writable.0, data.writable.1)?;
// Let readableRecord be ! StructuredDeserializeWithTransfer(dataHolder.[[readable]], the current Realm).
// Set value.[[readable]] to readableRecord.[[Deserialized]].
- let readable = ReadableStream::transfer_receive(owner, id, port_impl.clone())?;
-
// Let writableRecord be ! StructuredDeserializeWithTransfer(dataHolder.[[writable]], the current Realm).
- let writable = WritableStream::transfer_receive(owner, id, port_impl)?;
+ let proxy_readable = ReadableStream::new_with_proto(owner, None, can_gc);
+ proxy_readable.setup_cross_realm_transform_readable(cx, &port2, can_gc);
+
+ let proxy_writable = WritableStream::new_with_proto(owner, None, can_gc);
+ proxy_writable.setup_cross_realm_transform_writable(cx, &port1, can_gc);
// Set value.[[readable]] to readableRecord.[[Deserialized]].
// Set value.[[writable]] to writableRecord.[[Deserialized]].
// Set value.[[backpressure]], value.[[backpressureChangePromise]], and value.[[controller]] to undefined.
let stream = TransformStream::new_with_proto(owner, None, can_gc);
- stream.readable.set(Some(&readable));
- stream.writable.set(Some(&writable));
+ stream.readable.set(Some(&proxy_readable));
+ stream.writable.set(Some(&proxy_writable));
Ok(stream)
}
@@ -1098,8 +1110,8 @@ impl Transferable for TransformStream {
data: StructuredData<'a, '_>,
) -> &'a mut Option<HashMap<MessagePortId, Self::Data>> {
match data {
- StructuredData::Reader(r) => &mut r.port_impls,
- StructuredData::Writer(w) => &mut w.ports,
+ StructuredData::Reader(r) => &mut r.transform_streams_port_impls,
+ StructuredData::Writer(w) => &mut w.transform_streams_port,
}
}
}
diff --git a/components/script/dom/webglrenderingcontext.rs b/components/script/dom/webglrenderingcontext.rs
index 98170f9655b..b82051b3b12 100644
--- a/components/script/dom/webglrenderingcontext.rs
+++ b/components/script/dom/webglrenderingcontext.rs
@@ -619,7 +619,8 @@ impl WebGLRenderingContext {
let size = Size2D::new(img.width, img.height);
- TexPixels::new(img.bytes(), size, img.format, false)
+ let data = IpcSharedMemory::from_bytes(img.first_frame().bytes);
+ TexPixels::new(data, size, img.format, false)
},
// TODO(emilio): Getting canvas data is implemented in CanvasRenderingContext2D,
// but we need to refactor it moving it to `HTMLCanvasElement` and support
diff --git a/components/script/dom/xmlhttprequest.rs b/components/script/dom/xmlhttprequest.rs
index ca5bb72a1dc..4e7c136f42b 100644
--- a/components/script/dom/xmlhttprequest.rs
+++ b/components/script/dom/xmlhttprequest.rs
@@ -26,6 +26,7 @@ use js::jsval::{JSVal, NullValue};
use js::rust::wrappers::JS_ParseJSON;
use js::rust::{HandleObject, MutableHandleValue};
use js::typedarray::{ArrayBuffer, ArrayBufferU8};
+use net_traits::fetch::headers::extract_mime_type_as_dataurl_mime;
use net_traits::http_status::HttpStatus;
use net_traits::request::{CredentialsMode, Referrer, RequestBuilder, RequestId, RequestMode};
use net_traits::{
@@ -59,7 +60,7 @@ use crate::dom::document::{Document, DocumentSource, HasBrowsingContext, IsHTMLD
use crate::dom::event::{Event, EventBubbles, EventCancelable};
use crate::dom::eventtarget::EventTarget;
use crate::dom::globalscope::GlobalScope;
-use crate::dom::headers::{extract_mime_type, is_forbidden_request_header};
+use crate::dom::headers::is_forbidden_request_header;
use crate::dom::node::Node;
use crate::dom::performanceresourcetiming::InitiatorType;
use crate::dom::progressevent::ProgressEvent;
@@ -1324,11 +1325,7 @@ impl XMLHttpRequest {
return response;
}
// Step 2
- let mime = self
- .final_mime_type()
- .as_ref()
- .map(|m| normalize_type_string(&m.to_string()))
- .unwrap_or("".to_owned());
+ let mime = normalize_type_string(&self.final_mime_type().to_string());
// Step 3, 4
let bytes = self.response.borrow().to_vec();
@@ -1366,64 +1363,77 @@ impl XMLHttpRequest {
return response;
}
- // Step 1
+ // Step 1: If xhr’s response’s body is null, then return.
if self.response_status.get().is_err() {
return None;
}
- // Step 2
- let mime_type = self.final_mime_type();
- // Step 5.3, 7
- let charset = self.final_charset().unwrap_or(UTF_8);
- let temp_doc: DomRoot<Document>;
- match mime_type {
- Some(ref mime) if mime.matches(TEXT, HTML) => {
- // Step 4
- if self.response_type.get() == XMLHttpRequestResponseType::_empty {
- return None;
- } else {
- // TODO Step 5.2 "If charset is null, prescan the first 1024 bytes of xhr’s received bytes"
- // Step 5
- temp_doc = self.document_text_html(can_gc);
- }
- },
- // Step 7
- None => {
- temp_doc = self.handle_xml(can_gc);
- // Not sure it the parser should throw an error for this case
- // The specification does not indicates this test,
- // but for now we check the document has no child nodes
- let has_no_child_nodes = temp_doc.upcast::<Node>().children().next().is_none();
- if has_no_child_nodes {
- return None;
- }
- },
- Some(ref mime)
- if mime.matches(TEXT, XML) ||
- mime.matches(APPLICATION, XML) ||
- mime.has_suffix(XML) =>
- {
- temp_doc = self.handle_xml(can_gc);
- // Not sure it the parser should throw an error for this case
- // The specification does not indicates this test,
- // but for now we check the document has no child nodes
- let has_no_child_nodes = temp_doc.upcast::<Node>().children().next().is_none();
- if has_no_child_nodes {
- return None;
- }
- },
- // Step 3
- _ => {
+ // Step 2: Let finalMIME be the result of get a final MIME type for xhr.
+ let final_mime = self.final_mime_type();
+
+ // Step 3: If finalMIME is not an HTML MIME type or an XML MIME type, then return.
+ let is_xml_mime_type = final_mime.matches(TEXT, XML) ||
+ final_mime.matches(APPLICATION, XML) ||
+ final_mime.has_suffix(XML);
+ if !final_mime.matches(TEXT, HTML) && !is_xml_mime_type {
+ return None;
+ }
+
+ // Step 4: If xhr’s response type is the empty string and finalMIME is an HTML MIME
+ // type, then return.
+ let charset;
+ let temp_doc;
+ if final_mime.matches(TEXT, HTML) {
+ if self.response_type.get() == XMLHttpRequestResponseType::_empty {
return None;
- },
+ }
+
+ // Step 5: If finalMIME is an HTML MIME type, then:
+ // Step 5.1: Let charset be the result of get a final encoding for xhr.
+ // Step 5.2: If charset is null, prescan the first 1024 bytes of xhr’s received bytes
+ // and if that does not terminate unsuccessfully then let charset be the return value.
+ // TODO: This isn't happening right now.
+ // Step 5.3. If charset is null, then set charset to UTF-8.
+ charset = Some(self.final_charset().unwrap_or(UTF_8));
+
+ // Step 5.4: Let document be a document that represents the result parsing xhr’s
+ // received bytes following the rules set forth in the HTML Standard for an HTML parser
+ // with scripting disabled and a known definite encoding charset. [HTML]
+ temp_doc = self.document_text_html(can_gc);
+ } else {
+ assert!(is_xml_mime_type);
+
+ // Step 6: Otherwise, let document be a document that represents the result of running
+ // the XML parser with XML scripting support disabled on xhr’s received bytes. If that
+ // fails (unsupported character encoding, namespace well-formedness error, etc.), then
+ // return null. [HTML]
+ //
+ // TODO: The spec seems to suggest the charset should come from the XML parser here.
+ temp_doc = self.handle_xml(can_gc);
+ charset = self.final_charset();
+
+ // Not sure it the parser should throw an error for this case
+ // The specification does not indicates this test,
+ // but for now we check the document has no child nodes
+ let has_no_child_nodes = temp_doc.upcast::<Node>().children().next().is_none();
+ if has_no_child_nodes {
+ return None;
+ }
}
- // Step 8
+
+ // Step 7: If charset is null, then set charset to UTF-8.
+ let charset = charset.unwrap_or(UTF_8);
+
+ // Step 8: Set document’s encoding to charset.
temp_doc.set_encoding(charset);
- // Step 9 to 11
- // Done by handle_text_html and handle_xml
+ // Step 9: Set document’s content type to finalMIME.
+ // Step 10: Set document’s URL to xhr’s response’s URL.
+ // Step 11: Set document’s origin to xhr’s relevant settings object’s origin.
+ //
+ // Done by `handle_text_html()` and `handle_xml()`.
- // Step 12
+ // Step 12: Set xhr’s response object to document.
self.response_xml.set(Some(&temp_doc));
self.response_xml.get()
}
@@ -1507,7 +1517,7 @@ impl XMLHttpRequest {
Ok(parsed) => Some(parsed),
Err(_) => None, // Step 7
};
- let content_type = self.final_mime_type();
+ let content_type = Some(self.final_mime_type());
Document::new(
win,
HasBrowsingContext::No,
@@ -1598,14 +1608,16 @@ impl XMLHttpRequest {
// 3. If responseMIME’s parameters["charset"] exists, then set label to it.
let response_charset = self
.response_mime_type()
- .and_then(|mime| mime.get_parameter(CHARSET).map(|c| c.to_string()));
+ .get_parameter(CHARSET)
+ .map(ToString::to_string);
// 4. If xhr’s override MIME type’s parameters["charset"] exists, then set label to it.
let override_charset = self
.override_mime_type
.borrow()
.as_ref()
- .and_then(|mime| mime.get_parameter(CHARSET).map(|c| c.to_string()));
+ .and_then(|mime| mime.get_parameter(CHARSET))
+ .map(ToString::to_string);
// 5. If label is null, then return null.
// 6. Let encoding be the result of getting an encoding from label.
@@ -1617,23 +1629,22 @@ impl XMLHttpRequest {
}
/// <https://xhr.spec.whatwg.org/#response-mime-type>
- fn response_mime_type(&self) -> Option<Mime> {
- return extract_mime_type(&self.response_headers.borrow())
- .and_then(|mime_as_bytes| {
- String::from_utf8(mime_as_bytes)
- .unwrap_or_default()
- .parse()
- .ok()
- })
- .or(Some(Mime::new(TEXT, XML)));
+ fn response_mime_type(&self) -> Mime {
+ // 1. Let mimeType be the result of extracting a MIME type from xhr’s response’s
+ // header list.
+ // 2. If mimeType is failure, then set mimeType to text/xml.
+ // 3. Return mimeType.
+ extract_mime_type_as_dataurl_mime(&self.response_headers.borrow())
+ .unwrap_or_else(|| Mime::new(TEXT, XML))
}
/// <https://xhr.spec.whatwg.org/#final-mime-type>
- fn final_mime_type(&self) -> Option<Mime> {
- match *self.override_mime_type.borrow() {
- Some(ref override_mime) => Some(override_mime.clone()),
- None => self.response_mime_type(),
- }
+ fn final_mime_type(&self) -> Mime {
+ self.override_mime_type
+ .borrow()
+ .as_ref()
+ .map(MimeExt::clone)
+ .unwrap_or_else(|| self.response_mime_type())
}
}