Skip to content

Commit

Permalink
Add bytes() to Blob and PushMessageData
Browse files Browse the repository at this point in the history
https://bugs.webkit.org/show_bug.cgi?id=274119
rdar://128418858

Reviewed by Youenn Fablet.

This implements w3c/FileAPI#198 and
w3c/push-api#370 creating parity for these
APIs with Fetch's Body.

This incorporates the tests from
web-platform-tests/wpt#46232 modulo a typo fix.
PushMessageData test coverage is done through a local test that would
be good to upstream at some point.

* LayoutTests/http/wpt/push-api/pushEvent.any.js:
(test):
* LayoutTests/imported/w3c/web-platform-tests/FileAPI/Blob-methods-from-detached-frame-expected.txt:
* LayoutTests/imported/w3c/web-platform-tests/FileAPI/Blob-methods-from-detached-frame.html:
* LayoutTests/imported/w3c/web-platform-tests/FileAPI/blob/Blob-bytes.any-expected.txt: Added.
* LayoutTests/imported/w3c/web-platform-tests/FileAPI/blob/Blob-bytes.any.html: Added.
* LayoutTests/imported/w3c/web-platform-tests/FileAPI/blob/Blob-bytes.any.js: Added.
(string_appeared_here.promise_test.async const):
* LayoutTests/imported/w3c/web-platform-tests/FileAPI/blob/Blob-bytes.any.worker-expected.txt: Added.
* LayoutTests/imported/w3c/web-platform-tests/FileAPI/blob/Blob-bytes.any.worker.html: Added.
* LayoutTests/imported/w3c/web-platform-tests/FileAPI/blob/w3c-import.log:
* Source/WebCore/Modules/push-api/PushMessageData.cpp:
(WebCore::PushMessageData::arrayBuffer):
(WebCore::PushMessageData::bytes):
* Source/WebCore/Modules/push-api/PushMessageData.h:
* Source/WebCore/Modules/push-api/PushMessageData.idl:
* Source/WebCore/fileapi/Blob.cpp:
(WebCore::Blob::arrayBuffer):
(WebCore::Blob::bytes):
* Source/WebCore/fileapi/Blob.h:
* Source/WebCore/fileapi/Blob.idl:

Canonical link: https://commits.webkit.org/279263@main
  • Loading branch information
annevk committed May 24, 2024
1 parent 083dc3e commit d356276
Show file tree
Hide file tree
Showing 15 changed files with 123 additions and 15 deletions.
4 changes: 4 additions & 0 deletions LayoutTests/http/wpt/push-api/pushEvent.any.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,12 @@ test(() => {
assert_true(data instanceof PushMessageData);
assert_equals(data.text(), stringValue);
assert_true(data.blob() instanceof Blob);
assert_true(data.bytes() instanceof Uint8Array);
assert_equals(data.json().test, 1);
assert_equals(data.arrayBuffer().byteLength, stringValue.length);
assert_equals(data.bytes().length, stringValue.length);
assert_not_equals(data.bytes().buffer, data.arrayBuffer());
assert_not_equals(data.bytes(), data.bytes());
}
}, "PushEvent with data");

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@
PASS slice()
PASS text()
PASS arrayBuffer()
PASS bytes()
PASS stream()

Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@

assert_equals(await slicedBlob.text(), "oo");
assert_equals(charCodeBufferToString(await slicedBlob.arrayBuffer()), "oo");
assert_equals(charCodeArrayToString(await slicedBlob.bytes()), "oo");

const reader = slicedBlob.stream().getReader();
const { value } = await reader.read();
Expand All @@ -48,6 +49,14 @@
assert_equals(charCodeBufferToString(charCodeBuffer), "bar");
}, "arrayBuffer()");

promise_test(async () => {
const { bytes } = await BlobPrototypeFromDetachedFramePromise;
const blob = new Blob(["bar"]);

const charCodeBytes = await bytes.call(blob);
assert_equals(charCodeArrayToString(charCodeBytes), "bar");
}, "bytes()");

promise_test(async () => {
const { stream } = await BlobPrototypeFromDetachedFramePromise;
const blob = new Blob(["baz"]);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@

PASS Blob.bytes()
PASS Blob.bytes() empty Blob data
PASS Blob.bytes() non-ascii input
PASS Blob.bytes() non-unicode input
PASS Blob.bytes() concurrent reads

Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<!-- This file is required for WebKit test infrastructure to run the templated test -->
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// META: title=Blob bytes()
// META: script=../support/Blob.js
'use strict';

promise_test(async () => {
const input_arr = new TextEncoder().encode("PASS");
const blob = new Blob([input_arr]);
const uint8array = await blob.bytes();
assert_true(uint8array instanceof Uint8Array);
assert_equals_typed_array(uint8array, input_arr);
}, "Blob.bytes()")

promise_test(async () => {
const input_arr = new TextEncoder().encode("");
const blob = new Blob([input_arr]);
const uint8array = await blob.bytes();
assert_true(uint8array instanceof Uint8Array);
assert_equals_typed_array(uint8array, input_arr);
}, "Blob.bytes() empty Blob data")

promise_test(async () => {
const input_arr = new TextEncoder().encode("\u08B8\u000a");
const blob = new Blob([input_arr]);
const uint8array = await blob.bytes();
assert_equals_typed_array(uint8array, input_arr);
}, "Blob.bytes() non-ascii input")

promise_test(async () => {
const input_arr = [8, 241, 48, 123, 151];
const typed_arr = new Uint8Array(input_arr);
const blob = new Blob([typed_arr]);
const uint8array = await blob.bytes();
assert_equals_typed_array(uint8array, typed_arr);
}, "Blob.bytes() non-unicode input")

promise_test(async () => {
const input_arr = new TextEncoder().encode("PASS");
const blob = new Blob([input_arr]);
const uint8array_results = await Promise.all([blob.bytes(),
blob.bytes(), blob.bytes()]);
for (let uint8array of uint8array_results) {
assert_true(uint8array instanceof Uint8Array);
assert_equals_typed_array(uint8array, input_arr);
}
}, "Blob.bytes() concurrent reads")
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@

PASS Blob.bytes()
PASS Blob.bytes() empty Blob data
PASS Blob.bytes() non-ascii input
PASS Blob.bytes() non-unicode input
PASS Blob.bytes() concurrent reads

Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<!-- This file is required for WebKit test infrastructure to run the templated test -->
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ None
------------------------------------------------------------------------
List of files:
/LayoutTests/imported/w3c/web-platform-tests/FileAPI/blob/Blob-array-buffer.any.js
/LayoutTests/imported/w3c/web-platform-tests/FileAPI/blob/Blob-bytes.any.js
/LayoutTests/imported/w3c/web-platform-tests/FileAPI/blob/Blob-constructor-dom.window.js
/LayoutTests/imported/w3c/web-platform-tests/FileAPI/blob/Blob-constructor-endings.html
/LayoutTests/imported/w3c/web-platform-tests/FileAPI/blob/Blob-constructor.any.js
Expand Down
12 changes: 10 additions & 2 deletions Source/WebCore/Modules/push-api/PushMessageData.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021 Apple Inc. All rights reserved.
* Copyright (C) 2021-2024 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
Expand Down Expand Up @@ -40,7 +40,7 @@ WTF_MAKE_ISO_ALLOCATED_IMPL(PushMessageData);

ExceptionOr<RefPtr<JSC::ArrayBuffer>> PushMessageData::arrayBuffer()
{
auto buffer = ArrayBuffer::tryCreate(m_data.data(), m_data.size());
auto buffer = ArrayBuffer::tryCreate(m_data.span());
if (!buffer)
return Exception { ExceptionCode::OutOfMemoryError };
return buffer;
Expand All @@ -51,6 +51,14 @@ RefPtr<Blob> PushMessageData::blob(ScriptExecutionContext& context)
return Blob::create(&context, Vector<uint8_t> { m_data }, { });
}

ExceptionOr<RefPtr<JSC::Uint8Array>> PushMessageData::bytes()
{
auto view = Uint8Array::tryCreate(m_data.span());
if (!view)
return Exception { ExceptionCode::OutOfMemoryError };
return view;
}

ExceptionOr<JSC::JSValue> PushMessageData::json(JSDOMGlobalObject& globalObject)
{
JSC::JSLockHolder lock(&globalObject);
Expand Down
4 changes: 3 additions & 1 deletion Source/WebCore/Modules/push-api/PushMessageData.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021 Apple Inc. All rights reserved.
* Copyright (C) 2021-2024 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
Expand Down Expand Up @@ -28,6 +28,7 @@
#include "ExceptionOr.h"
#include <JavaScriptCore/ArrayBuffer.h>
#include <JavaScriptCore/JSCJSValue.h>
#include <JavaScriptCore/Uint8Array.h>
#include <wtf/IsoMalloc.h>
#include <wtf/Vector.h>

Expand All @@ -44,6 +45,7 @@ class PushMessageData final : public RefCounted<PushMessageData> {

ExceptionOr<RefPtr<JSC::ArrayBuffer>> arrayBuffer();
RefPtr<Blob> blob(ScriptExecutionContext&);
ExceptionOr<RefPtr<JSC::Uint8Array>> bytes();
ExceptionOr<JSC::JSValue> json(JSDOMGlobalObject&);
String text();

Expand Down
3 changes: 2 additions & 1 deletion Source/WebCore/Modules/push-api/PushMessageData.idl
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021 Apple Inc. All rights reserved.
* Copyright (C) 2021-2024 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
Expand Down Expand Up @@ -29,6 +29,7 @@
] interface PushMessageData {
ArrayBuffer arrayBuffer();
[CallWith=CurrentScriptExecutionContext] Blob blob();
Uint8Array bytes();
[CallWith=CurrentGlobalObject] any json();
USVString text();
};
33 changes: 24 additions & 9 deletions Source/WebCore/fileapi/Blob.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2010 Google Inc. All rights reserved.
* Copyright (C) 2012-2024 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
Expand Down Expand Up @@ -288,19 +289,33 @@ void Blob::text(Ref<DeferredPromise>&& promise)
});
}

void Blob::arrayBuffer(Ref<DeferredPromise>&& promise)
static ExceptionOr<Ref<JSC::ArrayBuffer>> arrayBufferFromBlobLoader(BlobLoader& blobLoader)
{
if (auto optionalErrorCode = blobLoader.errorCode())
return Exception { *optionalErrorCode };
RefPtr arrayBuffer = blobLoader.arrayBufferResult();
if (!arrayBuffer)
return Exception { ExceptionCode::InvalidStateError };
return arrayBuffer.releaseNonNull();
}

void Blob::arrayBuffer(DOMPromiseDeferred<IDLArrayBuffer>&& promise)
{
loadBlob(FileReaderLoader::ReadAsArrayBuffer, [promise = WTFMove(promise)](BlobLoader& blobLoader) mutable {
if (auto optionalErrorCode = blobLoader.errorCode()) {
promise->reject(Exception { *optionalErrorCode });
return;
}
auto arrayBuffer = blobLoader.arrayBufferResult();
if (!arrayBuffer) {
promise->reject(Exception { ExceptionCode::InvalidStateError });
promise.settle(arrayBufferFromBlobLoader(blobLoader));
});
}

void Blob::bytes(Ref<DeferredPromise>&& promise)
{
loadBlob(FileReaderLoader::ReadAsArrayBuffer, [promise = WTFMove(promise)](BlobLoader& blobLoader) mutable {
auto arrayBuffer = arrayBufferFromBlobLoader(blobLoader);
if (arrayBuffer.hasException()) {
promise->reject(arrayBuffer.releaseException());
return;
}
promise->resolve<IDLArrayBuffer>(*arrayBuffer);
Ref view = Uint8Array::create(arrayBuffer.releaseReturnValue());
promise->resolve<IDLUint8Array>(WTFMove(view));
});
}

Expand Down
8 changes: 6 additions & 2 deletions Source/WebCore/fileapi/Blob.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2010 Google Inc. All rights reserved.
* Copyright (C) 2012-2019 Apple Inc. All rights reserved.
* Copyright (C) 2012-2024 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
Expand Down Expand Up @@ -58,6 +58,9 @@ class ScriptExecutionContext;
class FragmentedSharedBuffer;
class WebCoreOpaqueRoot;

struct IDLArrayBuffer;

template<typename> class DOMPromiseDeferred;
template<typename> class ExceptionOr;

using BlobPartVariant = std::variant<RefPtr<JSC::ArrayBufferView>, RefPtr<JSC::ArrayBuffer>, RefPtr<Blob>, String>;
Expand Down Expand Up @@ -121,7 +124,8 @@ class Blob : public ScriptWrappable, public URLRegistrable, public RefCounted<Bl
Ref<Blob> slice(long long start, long long end, const String& contentType) const;

void text(Ref<DeferredPromise>&&);
void arrayBuffer(Ref<DeferredPromise>&&);
void arrayBuffer(DOMPromiseDeferred<IDLArrayBuffer>&&);
void bytes(Ref<DeferredPromise>&&);
ExceptionOr<Ref<ReadableStream>> stream();

size_t memoryCost() const { return m_memoryCost; }
Expand Down
2 changes: 2 additions & 0 deletions Source/WebCore/fileapi/Blob.idl
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2010 Google Inc. All rights reserved.
* Copyright (C) 2012-2024 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
Expand Down Expand Up @@ -48,4 +49,5 @@ typedef (BufferSource or Blob or USVString) BlobPart;
[NewObject] ReadableStream stream();
[NewObject] Promise<USVString> text();
[NewObject] Promise<ArrayBuffer> arrayBuffer();
[NewObject] Promise<Uint8Array> bytes();
};

0 comments on commit d356276

Please sign in to comment.