mirror of
https://github.com/servo/servo.git
synced 2025-06-06 16:45:39 +00:00
script: Implement the Bytes() method on Request and Response (#35250)
* Implement the Bytes() method on Request and Response Signed-off-by: Shane Handley <shanehandley@fastmail.com> * avoid unsafe code during buffer creation Signed-off-by: Shane Handley <shanehandley@fastmail.com> --------- Signed-off-by: Shane Handley <shanehandley@fastmail.com>
This commit is contained in:
parent
f364b3f6ea
commit
938baf6bf3
10 changed files with 33 additions and 149 deletions
|
@ -12,7 +12,7 @@ use js::jsapi::{Heap, JSObject, JS_ClearPendingException, Value as JSValue};
|
|||
use js::jsval::{JSVal, UndefinedValue};
|
||||
use js::rust::wrappers::{JS_GetPendingException, JS_ParseJSON};
|
||||
use js::rust::HandleValue;
|
||||
use js::typedarray::{ArrayBuffer, CreateWith};
|
||||
use js::typedarray::{ArrayBufferU8, Uint8};
|
||||
use mime::{self, Mime};
|
||||
use net_traits::request::{
|
||||
BodyChunkRequest, BodyChunkResponse, BodySource as NetBodySource, RequestBody,
|
||||
|
@ -20,6 +20,7 @@ use net_traits::request::{
|
|||
use script_traits::serializable::BlobImpl;
|
||||
use url::form_urlencoded;
|
||||
|
||||
use crate::dom::bindings::buffer_source::create_buffer_source;
|
||||
use crate::dom::bindings::cell::DomRefCell;
|
||||
use crate::dom::bindings::codegen::Bindings::BlobBinding::Blob_Binding::BlobMethods;
|
||||
use crate::dom::bindings::codegen::Bindings::FormDataBinding::FormDataMethods;
|
||||
|
@ -572,6 +573,7 @@ impl Extractable for URLSearchParams {
|
|||
#[derive(Clone, Copy, JSTraceable, MallocSizeOf)]
|
||||
pub(crate) enum BodyType {
|
||||
Blob,
|
||||
Bytes,
|
||||
FormData,
|
||||
Json,
|
||||
Text,
|
||||
|
@ -582,6 +584,7 @@ pub(crate) enum FetchedData {
|
|||
Text(String),
|
||||
Json(RootedTraceableBox<Heap<JSValue>>),
|
||||
BlobData(DomRoot<Blob>),
|
||||
Bytes(RootedTraceableBox<Heap<*mut JSObject>>),
|
||||
FormData(DomRoot<FormData>),
|
||||
ArrayBuffer(RootedTraceableBox<Heap<*mut JSObject>>),
|
||||
JSException(RootedTraceableBox<Heap<JSVal>>),
|
||||
|
@ -633,6 +636,7 @@ impl ConsumeBodyPromiseHandler {
|
|||
FetchedData::Json(j) => self.result_promise.resolve_native(&j),
|
||||
FetchedData::BlobData(b) => self.result_promise.resolve_native(&b),
|
||||
FetchedData::FormData(f) => self.result_promise.resolve_native(&f),
|
||||
FetchedData::Bytes(b) => self.result_promise.resolve_native(&b),
|
||||
FetchedData::ArrayBuffer(a) => self.result_promise.resolve_native(&a),
|
||||
FetchedData::JSException(e) => self.result_promise.reject_native(&e.handle()),
|
||||
};
|
||||
|
@ -810,6 +814,7 @@ fn run_package_data_algorithm(
|
|||
BodyType::Blob => run_blob_data_algorithm(&global, bytes, mime, can_gc),
|
||||
BodyType::FormData => run_form_data_algorithm(&global, bytes, mime, can_gc),
|
||||
BodyType::ArrayBuffer => run_array_buffer_data_algorithm(cx, bytes),
|
||||
BodyType::Bytes => run_bytes_data_algorithm(cx, bytes),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -891,22 +896,25 @@ fn run_form_data_algorithm(
|
|||
Err(Error::Type("Inappropriate MIME-type for Body".to_string()))
|
||||
}
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
fn run_bytes_data_algorithm(cx: JSContext, bytes: Vec<u8>) -> Fallible<FetchedData> {
|
||||
rooted!(in(*cx) let mut array_buffer_ptr = ptr::null_mut::<JSObject>());
|
||||
|
||||
create_buffer_source::<Uint8>(cx, &bytes, array_buffer_ptr.handle_mut())
|
||||
.map_err(|_| Error::JSFailed)?;
|
||||
|
||||
let rooted_heap = RootedTraceableBox::from_box(Heap::boxed(array_buffer_ptr.get()));
|
||||
Ok(FetchedData::Bytes(rooted_heap))
|
||||
}
|
||||
|
||||
pub(crate) fn run_array_buffer_data_algorithm(
|
||||
cx: JSContext,
|
||||
bytes: Vec<u8>,
|
||||
) -> Fallible<FetchedData> {
|
||||
rooted!(in(*cx) let mut array_buffer_ptr = ptr::null_mut::<JSObject>());
|
||||
let arraybuffer = unsafe {
|
||||
ArrayBuffer::create(
|
||||
*cx,
|
||||
CreateWith::Slice(&bytes),
|
||||
array_buffer_ptr.handle_mut(),
|
||||
)
|
||||
};
|
||||
if arraybuffer.is_err() {
|
||||
return Err(Error::JSFailed);
|
||||
}
|
||||
|
||||
create_buffer_source::<ArrayBufferU8>(cx, &bytes, array_buffer_ptr.handle_mut())
|
||||
.map_err(|_| Error::JSFailed)?;
|
||||
|
||||
let rooted_heap = RootedTraceableBox::from_box(Heap::boxed(array_buffer_ptr.get()));
|
||||
Ok(FetchedData::ArrayBuffer(rooted_heap))
|
||||
}
|
||||
|
|
|
@ -643,6 +643,11 @@ impl RequestMethods<crate::DomTypeHolder> for Request {
|
|||
fn ArrayBuffer(&self, can_gc: CanGc) -> Rc<Promise> {
|
||||
consume_body(self, BodyType::ArrayBuffer, can_gc)
|
||||
}
|
||||
|
||||
/// <https://fetch.spec.whatwg.org/#dom-body-bytes>
|
||||
fn Bytes(&self, can_gc: CanGc) -> std::rc::Rc<Promise> {
|
||||
consume_body(self, BodyType::Bytes, can_gc)
|
||||
}
|
||||
}
|
||||
|
||||
impl BodyMixin for Request {
|
||||
|
|
|
@ -386,6 +386,11 @@ impl ResponseMethods<crate::DomTypeHolder> for Response {
|
|||
fn ArrayBuffer(&self, can_gc: CanGc) -> Rc<Promise> {
|
||||
consume_body(self, BodyType::ArrayBuffer, can_gc)
|
||||
}
|
||||
|
||||
/// <https://fetch.spec.whatwg.org/#dom-body-bytes>
|
||||
fn Bytes(&self, can_gc: CanGc) -> std::rc::Rc<Promise> {
|
||||
consume_body(self, BodyType::Bytes, can_gc)
|
||||
}
|
||||
}
|
||||
|
||||
fn serialize_without_fragment(url: &ServoUrl) -> &str {
|
||||
|
|
|
@ -414,11 +414,11 @@ DOMInterfaces = {
|
|||
},
|
||||
|
||||
'Request': {
|
||||
'canGc': ['Headers', 'Text', 'Blob', 'FormData', 'Json', 'ArrayBuffer', 'Clone'],
|
||||
'canGc': ['Headers', 'Text', 'Blob', 'FormData', 'Json', 'ArrayBuffer', 'Clone', 'Bytes'],
|
||||
},
|
||||
|
||||
'Response': {
|
||||
'canGc': ['Error', 'Redirect', 'Clone', 'Text', 'Blob', 'FormData', 'Json', 'ArrayBuffer', 'Headers'],
|
||||
'canGc': ['Error', 'Redirect', 'Clone', 'Text', 'Blob', 'FormData', 'Json', 'ArrayBuffer', 'Headers', 'Bytes'],
|
||||
},
|
||||
|
||||
'RTCPeerConnection': {
|
||||
|
|
|
@ -11,6 +11,7 @@ interface mixin Body {
|
|||
|
||||
[NewObject] Promise<ArrayBuffer> arrayBuffer();
|
||||
[NewObject] Promise<Blob> blob();
|
||||
[NewObject] Promise<Uint8Array> bytes();
|
||||
[NewObject] Promise<FormData> formData();
|
||||
[NewObject] Promise<any> json();
|
||||
[NewObject] Promise<USVString> text();
|
||||
|
|
72
tests/wpt/meta/fetch/api/idlharness.any.js.ini
vendored
72
tests/wpt/meta/fetch/api/idlharness.any.js.ini
vendored
|
@ -14,16 +14,6 @@
|
|||
[Request interface: attribute duplex]
|
||||
expected: FAIL
|
||||
|
||||
[Request interface: operation arrayBuffer()]
|
||||
|
||||
[Request interface: operation blob()]
|
||||
|
||||
[Request interface: operation formData()]
|
||||
|
||||
[Request interface: operation json()]
|
||||
|
||||
[Request interface: operation text()]
|
||||
|
||||
[Request interface: new Request('about:blank') must inherit property "keepalive" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
|
@ -42,35 +32,9 @@
|
|||
[Response interface: operation json(any, optional ResponseInit)]
|
||||
expected: FAIL
|
||||
|
||||
[Response interface: operation arrayBuffer()]
|
||||
|
||||
[Response interface: operation blob()]
|
||||
|
||||
[Response interface: operation formData()]
|
||||
|
||||
[Response interface: operation json()]
|
||||
|
||||
[Response interface: operation text()]
|
||||
|
||||
[Response interface: calling json(any, optional ResponseInit) on new Response() with too few arguments must throw TypeError]
|
||||
expected: FAIL
|
||||
|
||||
[WorkerGlobalScope interface: operation fetch(RequestInfo, optional RequestInit)]
|
||||
|
||||
[WorkerGlobalScope interface: calling fetch(RequestInfo, optional RequestInit) on self with too few arguments must throw TypeError]
|
||||
|
||||
[Request interface: operation bytes()]
|
||||
expected: FAIL
|
||||
|
||||
[Request interface: new Request('about:blank') must inherit property "bytes()" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[Response interface: operation bytes()]
|
||||
expected: FAIL
|
||||
|
||||
[Response interface: new Response() must inherit property "bytes()" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
|
||||
[idlharness.any.sharedworker.html]
|
||||
expected: ERROR
|
||||
|
@ -91,16 +55,6 @@
|
|||
[Request interface: attribute duplex]
|
||||
expected: FAIL
|
||||
|
||||
[Request interface: operation arrayBuffer()]
|
||||
|
||||
[Request interface: operation blob()]
|
||||
|
||||
[Request interface: operation formData()]
|
||||
|
||||
[Request interface: operation json()]
|
||||
|
||||
[Request interface: operation text()]
|
||||
|
||||
[Request interface: new Request('about:blank') must inherit property "keepalive" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
|
@ -119,35 +73,9 @@
|
|||
[Response interface: operation json(any, optional ResponseInit)]
|
||||
expected: FAIL
|
||||
|
||||
[Response interface: operation arrayBuffer()]
|
||||
|
||||
[Response interface: operation blob()]
|
||||
|
||||
[Response interface: operation formData()]
|
||||
|
||||
[Response interface: operation json()]
|
||||
|
||||
[Response interface: operation text()]
|
||||
|
||||
[Response interface: calling json(any, optional ResponseInit) on new Response() with too few arguments must throw TypeError]
|
||||
expected: FAIL
|
||||
|
||||
[Window interface: operation fetch(RequestInfo, optional RequestInit)]
|
||||
|
||||
[Window interface: calling fetch(RequestInfo, optional RequestInit) on window with too few arguments must throw TypeError]
|
||||
|
||||
[Request interface: operation bytes()]
|
||||
expected: FAIL
|
||||
|
||||
[Request interface: new Request('about:blank') must inherit property "bytes()" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[Response interface: operation bytes()]
|
||||
expected: FAIL
|
||||
|
||||
[Response interface: new Response() must inherit property "bytes()" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
|
||||
[idlharness.any.serviceworker.html]
|
||||
expected: ERROR
|
||||
|
|
|
@ -2,53 +2,11 @@
|
|||
[Consume FormData request's body as FormData]
|
||||
expected: FAIL
|
||||
|
||||
[Consume String request's body as bytes]
|
||||
expected: FAIL
|
||||
|
||||
[Consume ArrayBuffer request's body as bytes]
|
||||
expected: FAIL
|
||||
|
||||
[Consume Uint8Array request's body as bytes]
|
||||
expected: FAIL
|
||||
|
||||
[Consume Int8Array request's body as bytes]
|
||||
expected: FAIL
|
||||
|
||||
[Consume Float32Array request's body as bytes]
|
||||
expected: FAIL
|
||||
|
||||
[Consume DataView request's body as bytes]
|
||||
expected: FAIL
|
||||
|
||||
[Consume blob response's body as bytes]
|
||||
expected: FAIL
|
||||
|
||||
|
||||
[request-consume.any.worker.html]
|
||||
[Consume FormData request's body as FormData]
|
||||
expected: FAIL
|
||||
|
||||
[Consume String request's body as bytes]
|
||||
expected: FAIL
|
||||
|
||||
[Consume ArrayBuffer request's body as bytes]
|
||||
expected: FAIL
|
||||
|
||||
[Consume Uint8Array request's body as bytes]
|
||||
expected: FAIL
|
||||
|
||||
[Consume Int8Array request's body as bytes]
|
||||
expected: FAIL
|
||||
|
||||
[Consume Float32Array request's body as bytes]
|
||||
expected: FAIL
|
||||
|
||||
[Consume DataView request's body as bytes]
|
||||
expected: FAIL
|
||||
|
||||
[Consume blob response's body as bytes]
|
||||
expected: FAIL
|
||||
|
||||
|
||||
[request-consume.any.serviceworker.html]
|
||||
expected: ERROR
|
||||
|
|
|
@ -1,7 +1,4 @@
|
|||
[response-blob-realm.any.html]
|
||||
[realm of the Uint8Array from Response bytes()]
|
||||
expected: FAIL
|
||||
|
||||
|
||||
[response-blob-realm.any.worker.html]
|
||||
[realm of the Uint8Array from Response bytes()]
|
||||
|
|
|
@ -1,21 +1,9 @@
|
|||
[response-error-from-stream.any.worker.html]
|
||||
[ReadableStream start() Error propagates to Response.bytes() Promise]
|
||||
expected: FAIL
|
||||
|
||||
[ReadableStream pull() Error propagates to Response.bytes() Promise]
|
||||
expected: FAIL
|
||||
|
||||
|
||||
[response-error-from-stream.any.serviceworker.html]
|
||||
expected: ERROR
|
||||
|
||||
[response-error-from-stream.any.html]
|
||||
[ReadableStream start() Error propagates to Response.bytes() Promise]
|
||||
expected: FAIL
|
||||
|
||||
[ReadableStream pull() Error propagates to Response.bytes() Promise]
|
||||
expected: FAIL
|
||||
|
||||
|
||||
[response-error-from-stream.any.sharedworker.html]
|
||||
expected: ERROR
|
||||
|
|
|
@ -2,14 +2,8 @@
|
|||
expected: ERROR
|
||||
|
||||
[response-stream-bad-chunk.any.html]
|
||||
[ReadableStream with non-Uint8Array chunk passed to Response.bytes() causes TypeError]
|
||||
expected: FAIL
|
||||
|
||||
|
||||
[response-stream-bad-chunk.any.worker.html]
|
||||
[ReadableStream with non-Uint8Array chunk passed to Response.bytes() causes TypeError]
|
||||
expected: FAIL
|
||||
|
||||
|
||||
[response-stream-bad-chunk.any.serviceworker.html]
|
||||
expected: ERROR
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue