diff --git a/builtins/web/blob.cpp b/builtins/web/blob.cpp index 8ab98f44..360b94e0 100644 --- a/builtins/web/blob.cpp +++ b/builtins/web/blob.cpp @@ -2,13 +2,15 @@ #include "builtin.h" #include "encode.h" #include "extension-api.h" -#include "mozilla/UniquePtr.h" +#include "js/UniquePtr.h" #include "rust-encoding.h" #include "streams/native-stream-source.h" +#include "mozilla/UniquePtr.h" #include "js/ArrayBuffer.h" #include "js/Conversions.h" #include "js/experimental/TypedData.h" +#include "js/HashTable.h" #include "js/Stream.h" #include "js/TypeDecls.h" #include "js/Value.h" @@ -149,6 +151,8 @@ namespace builtins { namespace web { namespace blob { +using js::Vector; + const JSFunctionSpec Blob::static_methods[] = { JS_FS_END, }; @@ -247,7 +251,7 @@ JSObject *Blob::data_to_owned_array_buffer(JSContext *cx, HandleObject self) { JSObject *Blob::data_to_owned_array_buffer(JSContext *cx, HandleObject self, size_t offset, size_t size, size_t *bytes_read) { auto blob = Blob::blob(self); - auto blob_size = blob->size(); + auto blob_size = blob->length(); *bytes_read = 0; MOZ_ASSERT(offset <= blob_size); @@ -255,7 +259,7 @@ JSObject *Blob::data_to_owned_array_buffer(JSContext *cx, HandleObject self, siz size_t available_bytes = blob_size - offset; size_t read_size = std::min(size, available_bytes); - auto span = std::span(blob->data() + offset, read_size); + auto span = std::span(blob->begin() + offset, read_size); auto array_buffer = new_array_buffer_from_span(cx, span); if (!array_buffer) { return nullptr; @@ -319,7 +323,7 @@ bool Blob::slice(JSContext *cx, unsigned argc, JS::Value *vp) { METHOD_HEADER(0) auto src = Blob::blob(self); - int64_t size = src->size(); + int64_t size = src->length(); int64_t start = 0; int64_t end = size; @@ -350,11 +354,14 @@ bool Blob::slice(JSContext *cx, unsigned argc, JS::Value *vp) { start = (start < 0) ? std::max((size + start), 0LL) : std::min(start, size); end = (end < 0) ? std::max((size + end), 0LL) : std::min(end, size); - auto dst = (end - start > 0) - ? std::make_unique>(src->begin() + start, src->begin() + end) - : std::make_unique>(); + auto slice_len = std::max(end - start, 0LL); + auto dst = (slice_len > 0) ? UniqueChars(js_pod_malloc(slice_len)) : nullptr; + + if (dst) { + std::copy(src->begin() + start, src->begin() + end, dst.get()); + } - JS::RootedObject new_blob(cx, create(cx, std::move(dst), contentType)); + JS::RootedObject new_blob(cx, create(cx, std::move(dst), slice_len, contentType)); if (!new_blob) { return false; } @@ -376,7 +383,7 @@ bool Blob::stream(JSContext *cx, unsigned argc, JS::Value *vp) { auto readers = Blob::readers(self); auto blob = Blob::blob(self); - auto span = std::span(blob->data(), blob->size()); + auto span = std::span(blob->begin(), blob->length()); if (!readers->put(source, BlobReader(span))) { return false; @@ -408,7 +415,7 @@ bool Blob::text(JSContext *cx, unsigned argc, JS::Value *vp) { auto decoder = jsencoding::encoding_new_decoder_with_bom_removal(encoding); MOZ_ASSERT(decoder); - auto src_len = src->size(); + auto src_len = src->length(); auto dst_len = jsencoding::decoder_max_utf16_buffer_length(decoder, src_len); JS::UniqueTwoByteChars dst(new char16_t[dst_len + 1]); @@ -420,7 +427,7 @@ bool Blob::text(JSContext *cx, unsigned argc, JS::Value *vp) { bool had_replacements; auto dst_data = reinterpret_cast(dst.get()); - jsencoding::decoder_decode_to_utf16(decoder, src->data(), &src_len, dst_data, &dst_len, true, + jsencoding::decoder_decode_to_utf16(decoder, src->begin(), &src_len, dst_data, &dst_len, true, &had_replacements); JS::RootedString str(cx, JS_NewUCString(cx, std::move(dst), dst_len)); @@ -474,9 +481,9 @@ bool Blob::stream_pull(JSContext *cx, JS::CallArgs args, JS::HandleObject source return true; } -std::vector *Blob::blob(JSObject *self) { +Blob::ByteBuffer *Blob::blob(JSObject *self) { MOZ_ASSERT(is_instance(self)); - auto blob = static_cast *>( + auto blob = static_cast( JS::GetReservedSlot(self, static_cast(Blob::Slots::Data)).toPrivate()); MOZ_ASSERT(blob); @@ -484,7 +491,7 @@ std::vector *Blob::blob(JSObject *self) { } size_t Blob::blob_size(JSObject *self) { - return blob(self)->size(); + return blob(self)->length(); } JSString *Blob::type(JSObject *self) { @@ -515,14 +522,16 @@ bool Blob::append_value(JSContext *cx, HandleObject self, HandleValue val) { if (Blob::is_instance(obj)) { auto src = Blob::blob(obj); - blob->insert(blob->end(), src->begin(), src->end()); - return true; + return blob->append(src->begin(), src->end()); } else if (JS_IsArrayBufferViewObject(obj) || JS::IsArrayBufferObject(obj)) { auto span = value_to_buffer(cx, val, "Blob Parts"); if (span.has_value()) { - blob->insert(blob->end(), span->begin(), span->end()); + auto src = span->data(); + auto len = span->size(); + return blob->append(src, src + len); + } else { + return true; } - return true; } } else if (val.isString()) { auto chars = core::encode(cx, val); @@ -534,14 +543,13 @@ bool Blob::append_value(JSContext *cx, HandleObject self, HandleValue val) { auto converted = convert_line_endings_to_native(chars); auto src = converted.data(); auto len = converted.length(); - blob->insert(blob->end(), src, src + len); + return blob->append(src, src + len); } else { auto src = chars.ptr.get(); auto len = chars.len; - blob->insert(blob->end(), src, src + len); + return blob->append(src, src + len); } - return true; } // FALLBACK: if we ever get here convert, to string and call append again @@ -645,13 +653,19 @@ bool Blob::init_options(JSContext *cx, HandleObject self, HandleValue initv) { return true; } -JSObject *Blob::create(JSContext *cx, std::unique_ptr data, HandleString type) { +JSObject *Blob::create(JSContext *cx, UniqueChars data, size_t data_len, HandleString type) { JSObject *self = JS_NewObjectWithGivenProto(cx, &class_, proto_obj); if (!self) { return nullptr; } - SetReservedSlot(self, static_cast(Slots::Data), JS::PrivateValue(data.release())); + auto blob = new ByteBuffer; + if (data != nullptr) { + // Take the ownership of given data. + blob->replaceRawBuffer(reinterpret_cast(data.release()), data_len); + } + + SetReservedSlot(self, static_cast(Slots::Data), JS::PrivateValue(blob)); SetReservedSlot(self, static_cast(Slots::Type), JS::StringValue(type)); SetReservedSlot(self, static_cast(Slots::Endings), JS::Int32Value(LineEndings::Transparent)); SetReservedSlot(self, static_cast(Slots::Readers), JS::PrivateValue(new ReadersMap)); @@ -669,9 +683,9 @@ bool Blob::constructor(JSContext *cx, unsigned argc, JS::Value *vp) { return false; } - SetReservedSlot(self, static_cast(Slots::Data), JS::PrivateValue(new std::vector())); SetReservedSlot(self, static_cast(Slots::Type), JS_GetEmptyStringValue(cx)); SetReservedSlot(self, static_cast(Slots::Endings), JS::Int32Value(LineEndings::Transparent)); + SetReservedSlot(self, static_cast(Slots::Data), JS::PrivateValue(new ByteBuffer)); SetReservedSlot(self, static_cast(Slots::Readers), JS::PrivateValue(new ReadersMap)); // Walk the blob parts and append them to the blob's buffer. diff --git a/builtins/web/blob.h b/builtins/web/blob.h index 0a578598..8efe2d25 100644 --- a/builtins/web/blob.h +++ b/builtins/web/blob.h @@ -6,6 +6,7 @@ #include "js/AllocPolicy.h" #include "js/GCHashTable.h" #include "js/TypeDecls.h" +#include "js/Vector.h" namespace builtins { namespace web { @@ -53,10 +54,9 @@ class Blob : public TraceableBuiltinImpl { enum Slots { Data, Type, Endings, Readers, Count }; enum LineEndings { Transparent, Native }; - using ByteBuffer = std::vector; using HeapObj = Heap; - using ReadersMap = - JS::GCHashMap, js::SystemAllocPolicy>; + using ByteBuffer = js::Vector; + using ReadersMap = JS::GCHashMap, js::SystemAllocPolicy>; static ReadersMap *readers(JSObject *self); static ByteBuffer *blob(JSObject *self); @@ -75,7 +75,7 @@ class Blob : public TraceableBuiltinImpl { static JSObject *data_to_owned_array_buffer(JSContext *cx, HandleObject self); static JSObject *data_to_owned_array_buffer(JSContext *cx, HandleObject self, size_t offset, size_t size, size_t *bytes_read); - static JSObject *create(JSContext *cx, std::unique_ptr data, HandleString type); + static JSObject *create(JSContext *cx, UniqueChars data, size_t data_len, HandleString type); static bool init_class(JSContext *cx, HandleObject global); static bool constructor(JSContext *cx, unsigned argc, Value *vp); diff --git a/builtins/web/fetch/request-response.cpp b/builtins/web/fetch/request-response.cpp index 73ac3163..855b9aa5 100644 --- a/builtins/web/fetch/request-response.cpp +++ b/builtins/web/fetch/request-response.cpp @@ -1,5 +1,6 @@ #include "request-response.h" +#include "../blob.h" #include "../streams/native-stream-source.h" #include "../streams/transform-stream.h" #include "../url.h" @@ -8,6 +9,7 @@ #include "extension-api.h" #include "fetch_event.h" #include "host_api.h" +#include "js/String.h" #include "picosha2.h" #include "js/Array.h" @@ -25,6 +27,8 @@ #include "js/experimental/TypedData.h" #pragma clang diagnostic pop +using builtins::web::blob::Blob; + namespace builtins::web::streams { bool NativeStreamSource::stream_is_body(JSContext *cx, JS::HandleObject stream) { @@ -288,6 +292,7 @@ bool RequestOrResponse::extract_body(JSContext *cx, JS::HandleObject self, // We currently support five types of body inputs: // - byte sequence // - buffer source + // - Blob // - USV strings // - URLSearchParams // - ReadableStream @@ -296,8 +301,24 @@ bool RequestOrResponse::extract_body(JSContext *cx, JS::HandleObject self, // TODO: Support the other possible inputs to Body. JS::RootedObject body_obj(cx, body_val.isObject() ? &body_val.toObject() : nullptr); + host_api::HostString host_type_str; + + if (Blob::is_instance(body_obj)) { + RootedValue stream(cx); + if (!Call(cx, body_obj, "stream", HandleValueArray::empty(), &stream)) { + return false; + } + + MOZ_ASSERT(stream.isObject()); + JS_SetReservedSlot(self, static_cast(RequestOrResponse::Slots::BodyStream), stream); - if (body_obj && JS::IsReadableStream(body_obj)) { + JS::RootedString type_str(cx, Blob::type(body_obj)); + if (JS::GetStringLength(type_str) > 0) { + host_type_str = core::encode(cx, type_str); + MOZ_ASSERT(host_type_str); + content_type = host_type_str.ptr.get(); + } + } else if (body_obj && JS::IsReadableStream(body_obj)) { if (RequestOrResponse::body_unusable(cx, body_obj)) { return api::throw_error(cx, FetchErrors::BodyStreamUnusable); } @@ -539,6 +560,15 @@ bool RequestOrResponse::parse_body(JSContext *cx, JS::HandleObject self, JS::Uni } static_cast(buf.release()); result.setObject(*array_buffer); + } else if constexpr (result_type == RequestOrResponse::BodyReadResult::Blob) { + JS::RootedString contentType(cx, JS_GetEmptyString(cx)); + JS::RootedObject blob(cx, blob::Blob::create(cx, std::move(buf), len, contentType)); + + if (!blob) { + return RejectPromiseWithPendingError(cx, result_promise); + } + + result.setObject(*blob); } else { JS::RootedString text(cx, JS_NewStringCopyUTF8N(cx, JS::UTF8Chars(buf.get(), len))); if (!text) { @@ -1303,6 +1333,7 @@ const JSPropertySpec Request::static_properties[] = { const JSFunctionSpec Request::methods[] = { JS_FN("arrayBuffer", Request::bodyAll, 0, JSPROP_ENUMERATE), + JS_FN("blob", Request::bodyAll, 0, JSPROP_ENUMERATE), JS_FN("json", Request::bodyAll, 0, JSPROP_ENUMERATE), JS_FN("text", Request::bodyAll, 0, JSPROP_ENUMERATE), JS_FN("clone", Request::clone, 0, JSPROP_ENUMERATE), @@ -2294,6 +2325,7 @@ const JSPropertySpec Response::static_properties[] = { const JSFunctionSpec Response::methods[] = { JS_FN("arrayBuffer", bodyAll, 0, JSPROP_ENUMERATE), + JS_FN("blob", bodyAll, 0, JSPROP_ENUMERATE), JS_FN("json", bodyAll, 0, JSPROP_ENUMERATE), JS_FN("text", bodyAll, 0, JSPROP_ENUMERATE), JS_FS_END, diff --git a/builtins/web/fetch/request-response.h b/builtins/web/fetch/request-response.h index b963ca25..0f216f3a 100644 --- a/builtins/web/fetch/request-response.h +++ b/builtins/web/fetch/request-response.h @@ -74,6 +74,7 @@ class RequestOrResponse final { enum class BodyReadResult { ArrayBuffer, + Blob, JSON, Text, }; diff --git a/builtins/web/structured-clone.cpp b/builtins/web/structured-clone.cpp index fc6c2c15..e19a54a0 100644 --- a/builtins/web/structured-clone.cpp +++ b/builtins/web/structured-clone.cpp @@ -1,6 +1,8 @@ #include "structured-clone.h" +#include "blob.h" #include "dom-exception.h" +#include "mozilla/Assertions.h" namespace builtins { namespace web { @@ -8,29 +10,20 @@ namespace structured_clone { // Magic number used in structured cloning as a tag to identify a // URLSearchParam. -#define SCTAG_DOM_URLSEARCHPARAMS JS_SCTAG_USER_MIN +#define SCTAG_DOM_URLSEARCHPARAMS (JS_SCTAG_USER_MIN) +#define SCTAG_DOM_BLOB (JS_SCTAG_USER_MIN + 1) /** * Reads non-JS builtins during structured cloning. * - * Currently the only relevant builtin is URLSearchParams, but that'll grow to - * include Blob and FormData, too. + * Currently the only relevant builtin is URLSearchParams and Blob, but that'll grow to + * include FormData, too. * * TODO: Add support for CryptoKeys */ JSObject *ReadStructuredClone(JSContext *cx, JSStructuredCloneReader *r, const JS::CloneDataPolicy &cloneDataPolicy, uint32_t tag, uint32_t len, void *closure) { - MOZ_ASSERT(tag == SCTAG_DOM_URLSEARCHPARAMS); - - RootedObject urlSearchParamsInstance(cx, - JS_NewObjectWithGivenProto(cx, &url::URLSearchParams::class_, - url::URLSearchParams::proto_obj)); - RootedObject params_obj(cx, url::URLSearchParams::create(cx, urlSearchParamsInstance)); - if (!params_obj) { - return nullptr; - } - void *bytes = JS_malloc(cx, len); if (!bytes) { JS_ReportOutOfMemory(cx); @@ -41,32 +34,62 @@ JSObject *ReadStructuredClone(JSContext *cx, JSStructuredCloneReader *r, return nullptr; } - jsurl::SpecString init((uint8_t *)bytes, len, len); - jsurl::params_init(url::URLSearchParams::get_params(params_obj), &init); + switch (tag) { + case SCTAG_DOM_URLSEARCHPARAMS: { + RootedObject urlSearchParamsInstance(cx, + JS_NewObjectWithGivenProto(cx, &url::URLSearchParams::class_, + url::URLSearchParams::proto_obj)); + RootedObject params_obj(cx, url::URLSearchParams::create(cx, urlSearchParamsInstance)); + if (!params_obj) { + return nullptr; + } + + jsurl::SpecString init((uint8_t *)bytes, len, len); + jsurl::params_init(url::URLSearchParams::get_params(params_obj), &init); + + return params_obj; - return params_obj; + } + case SCTAG_DOM_BLOB: { + JS::RootedString contentType(cx, JS_GetEmptyString(cx)); + UniqueChars chars(reinterpret_cast(bytes)); + + RootedObject blob(cx, blob::Blob::create(cx, std::move(chars), len, contentType)); + return blob; + } + default: { + MOZ_ASSERT_UNREACHABLE("structured-clone undefined tag"); + return nullptr; + } + } } /** * Writes non-JS builtins during structured cloning. * - * Currently the only relevant builtin is URLSearchParams, but that'll grow to - * include Blob and FormData, too. + * Currently the only relevant builtin is URLSearchParams and Blob, but that'll grow to + * include FormData, too. * * TODO: Add support for CryptoKeys */ bool WriteStructuredClone(JSContext *cx, JSStructuredCloneWriter *w, JS::HandleObject obj, bool *sameProcessScopeRequired, void *closure) { - if (!url::URLSearchParams::is_instance(obj)) { + if (url::URLSearchParams::is_instance(obj)) { + auto slice = url::URLSearchParams::serialize(cx, obj); + if (!JS_WriteUint32Pair(w, SCTAG_DOM_URLSEARCHPARAMS, slice.len) || + !JS_WriteBytes(w, (void *)slice.data, slice.len)) { + return false; + } + } else if (blob::Blob::is_instance(obj)) { + auto data = blob::Blob::blob(obj); + if (!JS_WriteUint32Pair(w, SCTAG_DOM_BLOB, data->length()) || + !JS_WriteBytes(w, (void *)data->begin(), data->length())) { + return false; + } + } else { return dom_exception::DOMException::raise(cx, "The object could not be cloned", "DataCloneError"); } - auto slice = url::URLSearchParams::serialize(cx, obj); - if (!JS_WriteUint32Pair(w, SCTAG_DOM_URLSEARCHPARAMS, slice.len) || - !JS_WriteBytes(w, (void *)slice.data, slice.len)) { - return false; - } - return true; } diff --git a/tests/wpt-harness/expectations/fetch/api/body/cloned-any.js.json b/tests/wpt-harness/expectations/fetch/api/body/cloned-any.js.json index 2a5fcc1a..a8a9143d 100644 --- a/tests/wpt-harness/expectations/fetch/api/body/cloned-any.js.json +++ b/tests/wpt-harness/expectations/fetch/api/body/cloned-any.js.json @@ -12,6 +12,6 @@ "status": "PASS" }, "Blob is cloned": { - "status": "FAIL" + "status": "PASS" } } \ No newline at end of file diff --git a/tests/wpt-harness/expectations/fetch/api/request/request-consume-empty.any.js.json b/tests/wpt-harness/expectations/fetch/api/request/request-consume-empty.any.js.json index f62ab9cb..0539b451 100644 --- a/tests/wpt-harness/expectations/fetch/api/request/request-consume-empty.any.js.json +++ b/tests/wpt-harness/expectations/fetch/api/request/request-consume-empty.any.js.json @@ -3,7 +3,7 @@ "status": "PASS" }, "Consume request's body as blob": { - "status": "FAIL" + "status": "PASS" }, "Consume request's body as arrayBuffer": { "status": "PASS" @@ -21,13 +21,13 @@ "status": "FAIL" }, "Consume empty blob request body as arrayBuffer": { - "status": "FAIL" + "status": "PASS" }, "Consume empty text request body as arrayBuffer": { "status": "PASS" }, "Consume empty blob request body as text": { - "status": "FAIL" + "status": "PASS" }, "Consume empty text request body as text": { "status": "PASS" diff --git a/tests/wpt-harness/expectations/fetch/api/request/request-consume.any.js.json b/tests/wpt-harness/expectations/fetch/api/request/request-consume.any.js.json index 29eb926e..7b1401b5 100644 --- a/tests/wpt-harness/expectations/fetch/api/request/request-consume.any.js.json +++ b/tests/wpt-harness/expectations/fetch/api/request/request-consume.any.js.json @@ -3,7 +3,7 @@ "status": "PASS" }, "Consume String request's body as blob": { - "status": "FAIL" + "status": "PASS" }, "Consume String request's body as arrayBuffer": { "status": "PASS" @@ -18,7 +18,7 @@ "status": "PASS" }, "Consume ArrayBuffer request's body as blob": { - "status": "FAIL" + "status": "PASS" }, "Consume ArrayBuffer request's body as arrayBuffer": { "status": "PASS" @@ -33,7 +33,7 @@ "status": "PASS" }, "Consume Uint8Array request's body as blob": { - "status": "FAIL" + "status": "PASS" }, "Consume Uint8Array request's body as arrayBuffer": { "status": "PASS" @@ -48,7 +48,7 @@ "status": "PASS" }, "Consume Int8Array request's body as blob": { - "status": "FAIL" + "status": "PASS" }, "Consume Int8Array request's body as arrayBuffer": { "status": "PASS" @@ -63,7 +63,7 @@ "status": "PASS" }, "Consume Float32Array request's body as blob": { - "status": "FAIL" + "status": "PASS" }, "Consume Float32Array request's body as arrayBuffer": { "status": "PASS" @@ -78,7 +78,7 @@ "status": "PASS" }, "Consume DataView request's body as blob": { - "status": "FAIL" + "status": "PASS" }, "Consume DataView request's body as arrayBuffer": { "status": "PASS" @@ -93,22 +93,22 @@ "status": "FAIL" }, "Consume blob response's body as blob": { - "status": "FAIL" + "status": "PASS" }, "Consume blob response's body as text": { - "status": "FAIL" + "status": "PASS" }, "Consume blob response's body as json": { - "status": "FAIL" + "status": "PASS" }, "Consume blob response's body as arrayBuffer": { - "status": "FAIL" + "status": "PASS" }, "Consume blob response's body as bytes": { "status": "FAIL" }, "Consume blob response's body as blob (empty blob as input)": { - "status": "FAIL" + "status": "PASS" }, "Consume JSON from text: '\"null\"'": { "status": "PASS" diff --git a/tests/wpt-harness/expectations/fetch/api/request/request-disturbed.any.js.json b/tests/wpt-harness/expectations/fetch/api/request/request-disturbed.any.js.json new file mode 100644 index 00000000..d2068740 --- /dev/null +++ b/tests/wpt-harness/expectations/fetch/api/request/request-disturbed.any.js.json @@ -0,0 +1,29 @@ +{ + "Request's body: initial state": { + "status": "PASS" + }, + "Request without body cannot be disturbed": { + "status": "PASS" + }, + "Check cloning a disturbed request": { + "status": "FAIL" + }, + "Check creating a new request from a disturbed request": { + "status": "PASS" + }, + "Check creating a new request with a new body from a disturbed request": { + "status": "PASS" + }, + "Input request used for creating new request became disturbed": { + "status": "FAIL" + }, + "Input request used for creating new request became disturbed even if body is not used": { + "status": "FAIL" + }, + "Check consuming a disturbed request": { + "status": "PASS" + }, + "Request construction failure should not set \"bodyUsed\"": { + "status": "FAIL" + } +} \ No newline at end of file diff --git a/tests/wpt-harness/expectations/fetch/api/request/request-headers.any.js.json b/tests/wpt-harness/expectations/fetch/api/request/request-headers.any.js.json index 98c21422..9aef7b26 100644 --- a/tests/wpt-harness/expectations/fetch/api/request/request-headers.any.js.json +++ b/tests/wpt-harness/expectations/fetch/api/request/request-headers.any.js.json @@ -177,7 +177,7 @@ "status": "PASS" }, "Testing empty Request Content-Type header": { - "status": "FAIL" + "status": "PASS" }, "Test that Request.headers has the [SameObject] extended attribute": { "status": "PASS" diff --git a/tests/wpt-harness/expectations/fetch/api/request/request-init-contenttype.any.js.json b/tests/wpt-harness/expectations/fetch/api/request/request-init-contenttype.any.js.json index 1d538608..180d3949 100644 --- a/tests/wpt-harness/expectations/fetch/api/request/request-init-contenttype.any.js.json +++ b/tests/wpt-harness/expectations/fetch/api/request/request-init-contenttype.any.js.json @@ -3,13 +3,13 @@ "status": "PASS" }, "Default Content-Type for Request with Blob body (no type set)": { - "status": "FAIL" + "status": "PASS" }, "Default Content-Type for Request with Blob body (empty type)": { - "status": "FAIL" + "status": "PASS" }, "Default Content-Type for Request with Blob body (set type)": { - "status": "FAIL" + "status": "PASS" }, "Default Content-Type for Request with buffer source body": { "status": "PASS" diff --git a/tests/wpt-harness/expectations/fetch/api/request/request-structure.any.js.json b/tests/wpt-harness/expectations/fetch/api/request/request-structure.any.js.json index be010b84..c01e04b2 100644 --- a/tests/wpt-harness/expectations/fetch/api/request/request-structure.any.js.json +++ b/tests/wpt-harness/expectations/fetch/api/request/request-structure.any.js.json @@ -6,7 +6,7 @@ "status": "PASS" }, "Request has blob method": { - "status": "FAIL" + "status": "PASS" }, "Request has formData method": { "status": "FAIL" @@ -71,4 +71,4 @@ "Request does not expose blocking attribute": { "status": "PASS" } -} +} \ No newline at end of file diff --git a/tests/wpt-harness/expectations/fetch/api/response/response-consume-empty.any.js.json b/tests/wpt-harness/expectations/fetch/api/response/response-consume-empty.any.js.json index 26ee5254..095fa14b 100644 --- a/tests/wpt-harness/expectations/fetch/api/response/response-consume-empty.any.js.json +++ b/tests/wpt-harness/expectations/fetch/api/response/response-consume-empty.any.js.json @@ -3,7 +3,7 @@ "status": "PASS" }, "Consume response's body as blob": { - "status": "FAIL" + "status": "PASS" }, "Consume response's body as arrayBuffer": { "status": "PASS" @@ -21,13 +21,13 @@ "status": "FAIL" }, "Consume empty blob response body as arrayBuffer": { - "status": "FAIL" + "status": "PASS" }, "Consume empty text response body as arrayBuffer": { "status": "PASS" }, "Consume empty blob response body as text": { - "status": "FAIL" + "status": "PASS" }, "Consume empty text response body as text": { "status": "PASS" diff --git a/tests/wpt-harness/expectations/fetch/api/response/response-error-from-stream.any.js.json b/tests/wpt-harness/expectations/fetch/api/response/response-error-from-stream.any.js.json index 14ffc379..9c67f745 100644 --- a/tests/wpt-harness/expectations/fetch/api/response/response-error-from-stream.any.js.json +++ b/tests/wpt-harness/expectations/fetch/api/response/response-error-from-stream.any.js.json @@ -9,7 +9,7 @@ "status": "PASS" }, "ReadableStream start() Error propagates to Response.blob() Promise": { - "status": "FAIL" + "status": "PASS" }, "ReadableStream start() Error propagates to Response.bytes() Promise": { "status": "FAIL" @@ -27,7 +27,7 @@ "status": "PASS" }, "ReadableStream pull() Error propagates to Response.blob() Promise": { - "status": "FAIL" + "status": "PASS" }, "ReadableStream pull() Error propagates to Response.bytes() Promise": { "status": "FAIL" diff --git a/tests/wpt-harness/expectations/fetch/api/response/response-init-contenttype.any.js.json b/tests/wpt-harness/expectations/fetch/api/response/response-init-contenttype.any.js.json index 153dc318..c5436211 100644 --- a/tests/wpt-harness/expectations/fetch/api/response/response-init-contenttype.any.js.json +++ b/tests/wpt-harness/expectations/fetch/api/response/response-init-contenttype.any.js.json @@ -3,13 +3,13 @@ "status": "PASS" }, "Default Content-Type for Response with Blob body (no type set)": { - "status": "FAIL" + "status": "PASS" }, "Default Content-Type for Response with Blob body (empty type)": { - "status": "FAIL" + "status": "PASS" }, "Default Content-Type for Response with Blob body (set type)": { - "status": "FAIL" + "status": "PASS" }, "Default Content-Type for Response with buffer source body": { "status": "PASS" diff --git a/tests/wpt-harness/expectations/fetch/api/response/response-stream-bad-chunk.any.js.json b/tests/wpt-harness/expectations/fetch/api/response/response-stream-bad-chunk.any.js.json index 78654577..6e4cd277 100644 --- a/tests/wpt-harness/expectations/fetch/api/response/response-stream-bad-chunk.any.js.json +++ b/tests/wpt-harness/expectations/fetch/api/response/response-stream-bad-chunk.any.js.json @@ -3,7 +3,7 @@ "status": "PASS" }, "ReadableStream with non-Uint8Array chunk passed to Response.blob() causes TypeError": { - "status": "FAIL" + "status": "PASS" }, "ReadableStream with non-Uint8Array chunk passed to Response.bytes() causes TypeError": { "status": "FAIL" diff --git a/tests/wpt-harness/expectations/fetch/api/response/response-stream-disturbed-1.any.js.json b/tests/wpt-harness/expectations/fetch/api/response/response-stream-disturbed-1.any.js.json index 3dad7f0b..e3fb83ca 100644 --- a/tests/wpt-harness/expectations/fetch/api/response/response-stream-disturbed-1.any.js.json +++ b/tests/wpt-harness/expectations/fetch/api/response/response-stream-disturbed-1.any.js.json @@ -1,6 +1,6 @@ { "Getting blob after getting the Response body - not disturbed, not locked (body source: fetch)": { - "status": "FAIL" + "status": "PASS" }, "Getting text after getting the Response body - not disturbed, not locked (body source: fetch)": { "status": "PASS" @@ -12,7 +12,7 @@ "status": "PASS" }, "Getting blob after getting the Response body - not disturbed, not locked (body source: stream)": { - "status": "FAIL" + "status": "PASS" }, "Getting text after getting the Response body - not disturbed, not locked (body source: stream)": { "status": "PASS" @@ -24,7 +24,7 @@ "status": "PASS" }, "Getting blob after getting the Response body - not disturbed, not locked (body source: string)": { - "status": "FAIL" + "status": "PASS" }, "Getting text after getting the Response body - not disturbed, not locked (body source: string)": { "status": "PASS" diff --git a/tests/wpt-harness/expectations/fetch/api/response/response-stream-disturbed-2.any.js.json b/tests/wpt-harness/expectations/fetch/api/response/response-stream-disturbed-2.any.js.json index d81b359d..590e3c31 100644 --- a/tests/wpt-harness/expectations/fetch/api/response/response-stream-disturbed-2.any.js.json +++ b/tests/wpt-harness/expectations/fetch/api/response/response-stream-disturbed-2.any.js.json @@ -1,6 +1,6 @@ { "Getting blob after getting a locked Response body (body source: fetch)": { - "status": "FAIL" + "status": "PASS" }, "Getting text after getting a locked Response body (body source: fetch)": { "status": "PASS" @@ -12,7 +12,7 @@ "status": "PASS" }, "Getting blob after getting a locked Response body (body source: stream)": { - "status": "FAIL" + "status": "PASS" }, "Getting text after getting a locked Response body (body source: stream)": { "status": "PASS" @@ -24,7 +24,7 @@ "status": "PASS" }, "Getting blob after getting a locked Response body (body source: string)": { - "status": "FAIL" + "status": "PASS" }, "Getting text after getting a locked Response body (body source: string)": { "status": "PASS" diff --git a/tests/wpt-harness/expectations/fetch/api/response/response-stream-disturbed-3.any.js.json b/tests/wpt-harness/expectations/fetch/api/response/response-stream-disturbed-3.any.js.json index b306c09e..9e7c0598 100644 --- a/tests/wpt-harness/expectations/fetch/api/response/response-stream-disturbed-3.any.js.json +++ b/tests/wpt-harness/expectations/fetch/api/response/response-stream-disturbed-3.any.js.json @@ -1,6 +1,6 @@ { "Getting blob after reading the Response body (body source: fetch)": { - "status": "FAIL" + "status": "PASS" }, "Getting text after reading the Response body (body source: fetch)": { "status": "PASS" @@ -12,7 +12,7 @@ "status": "PASS" }, "Getting blob after reading the Response body (body source: stream)": { - "status": "FAIL" + "status": "PASS" }, "Getting text after reading the Response body (body source: stream)": { "status": "PASS" @@ -24,7 +24,7 @@ "status": "PASS" }, "Getting blob after reading the Response body (body source: string)": { - "status": "FAIL" + "status": "PASS" }, "Getting text after reading the Response body (body source: string)": { "status": "PASS" diff --git a/tests/wpt-harness/expectations/fetch/api/response/response-stream-disturbed-4.any.js.json b/tests/wpt-harness/expectations/fetch/api/response/response-stream-disturbed-4.any.js.json index 4b94a293..f0a89799 100644 --- a/tests/wpt-harness/expectations/fetch/api/response/response-stream-disturbed-4.any.js.json +++ b/tests/wpt-harness/expectations/fetch/api/response/response-stream-disturbed-4.any.js.json @@ -1,6 +1,6 @@ { "Getting blob after cancelling the Response body (body source: fetch)": { - "status": "FAIL" + "status": "PASS" }, "Getting text after cancelling the Response body (body source: fetch)": { "status": "PASS" @@ -12,7 +12,7 @@ "status": "PASS" }, "Getting blob after cancelling the Response body (body source: stream)": { - "status": "FAIL" + "status": "PASS" }, "Getting text after cancelling the Response body (body source: stream)": { "status": "PASS" @@ -24,7 +24,7 @@ "status": "PASS" }, "Getting blob after cancelling the Response body (body source: string)": { - "status": "FAIL" + "status": "PASS" }, "Getting text after cancelling the Response body (body source: string)": { "status": "PASS" diff --git a/tests/wpt-harness/expectations/html/webappapis/structured-clone/structured-clone.any.js.json b/tests/wpt-harness/expectations/html/webappapis/structured-clone/structured-clone.any.js.json index f85c26b6..2bf9ca36 100644 --- a/tests/wpt-harness/expectations/html/webappapis/structured-clone/structured-clone.any.js.json +++ b/tests/wpt-harness/expectations/html/webappapis/structured-clone/structured-clone.any.js.json @@ -246,37 +246,37 @@ "status": "FAIL" }, "Blob unpaired high surrogate (invalid utf-8)": { - "status": "FAIL" + "status": "PASS" }, "Blob unpaired low surrogate (invalid utf-8)": { - "status": "FAIL" + "status": "PASS" }, "Blob paired surrogates (invalid utf-8)": { - "status": "FAIL" + "status": "PASS" }, "Blob empty": { - "status": "FAIL" + "status": "PASS" }, "Blob NUL": { - "status": "FAIL" + "status": "PASS" }, "Array Blob object, Blob basic": { "status": "FAIL" }, "Array Blob object, Blob unpaired high surrogate (invalid utf-8)": { - "status": "FAIL" + "status": "PASS" }, "Array Blob object, Blob unpaired low surrogate (invalid utf-8)": { - "status": "FAIL" + "status": "PASS" }, "Array Blob object, Blob paired surrogates (invalid utf-8)": { - "status": "FAIL" + "status": "PASS" }, "Array Blob object, Blob empty": { - "status": "FAIL" + "status": "PASS" }, "Array Blob object, Blob NUL": { - "status": "FAIL" + "status": "PASS" }, "Array Blob object, two Blobs": { "status": "FAIL" @@ -285,19 +285,19 @@ "status": "FAIL" }, "Object Blob object, Blob unpaired high surrogate (invalid utf-8)": { - "status": "FAIL" + "status": "PASS" }, "Object Blob object, Blob unpaired low surrogate (invalid utf-8)": { - "status": "FAIL" + "status": "PASS" }, "Object Blob object, Blob paired surrogates (invalid utf-8)": { - "status": "FAIL" + "status": "PASS" }, "Object Blob object, Blob empty": { - "status": "FAIL" + "status": "PASS" }, "Object Blob object, Blob NUL": { - "status": "FAIL" + "status": "PASS" }, "File basic": { "status": "FAIL" @@ -345,7 +345,7 @@ "status": "PASS" }, "An object whose interface is deleted from the global must still deserialize": { - "status": "FAIL" + "status": "PASS" }, "A subclass instance will deserialize as its closest serializable superclass": { "status": "FAIL"