Commit a283f958 authored by Olivier Yiptong's avatar Olivier Yiptong Committed by Commit Bot

[Native File System] FileSystemWriter::write takes non-stream data only

The implementation of `write` before this CL accepted a Blob or a
ReadableStream.

This change limits `write` to byte-array-like data, the stream-semantics
to be implemented in another dedicated API.

Bug: 955190
Change-Id: Icdec561a706bb18fc2b56bd3304b9e8346923fcc
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1589671
Auto-Submit: Olivier Yiptong <oyiptong@chromium.org>
Commit-Queue: Marijn Kruisselbrink <mek@chromium.org>
Reviewed-by: default avatarMarijn Kruisselbrink <mek@chromium.org>
Cr-Commit-Position: refs/heads/master@{#656209}
parent 3585346a
...@@ -4,16 +4,17 @@ ...@@ -4,16 +4,17 @@
#include "third_party/blink/renderer/modules/filesystem/file_system_writer.h" #include "third_party/blink/renderer/modules/filesystem/file_system_writer.h"
#include "third_party/blink/renderer/bindings/core/v8/array_buffer_or_array_buffer_view_or_blob_or_usv_string.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise.h" #include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_blob.h" #include "third_party/blink/renderer/bindings/core/v8/v8_blob.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_readable_stream.h" #include "third_party/blink/renderer/bindings/core/v8/v8_readable_stream.h"
#include "third_party/blink/renderer/bindings/modules/v8/blob_or_readable_stream.h"
#include "third_party/blink/renderer/core/dom/dom_exception.h" #include "third_party/blink/renderer/core/dom/dom_exception.h"
#include "third_party/blink/renderer/core/fetch/fetch_data_loader.h" #include "third_party/blink/renderer/core/fetch/fetch_data_loader.h"
#include "third_party/blink/renderer/core/fetch/readable_stream_bytes_consumer.h" #include "third_party/blink/renderer/core/fetch/readable_stream_bytes_consumer.h"
#include "third_party/blink/renderer/core/fileapi/blob.h" #include "third_party/blink/renderer/core/fileapi/blob.h"
#include "third_party/blink/renderer/core/fileapi/file_error.h" #include "third_party/blink/renderer/core/fileapi/file_error.h"
#include "third_party/blink/renderer/core/streams/readable_stream.h" #include "third_party/blink/renderer/core/streams/readable_stream.h"
#include "third_party/blink/renderer/platform/blob/blob_data.h"
#include "third_party/blink/renderer/platform/wtf/functional.h" #include "third_party/blink/renderer/platform/wtf/functional.h"
namespace blink { namespace blink {
...@@ -23,15 +24,36 @@ FileSystemWriter::FileSystemWriter(mojom::blink::FileWriterPtr writer) ...@@ -23,15 +24,36 @@ FileSystemWriter::FileSystemWriter(mojom::blink::FileWriterPtr writer)
DCHECK(writer_); DCHECK(writer_);
} }
ScriptPromise FileSystemWriter::write(ScriptState* script_state, ScriptPromise FileSystemWriter::write(
uint64_t position, ScriptState* script_state,
const BlobOrReadableStream& data, uint64_t position,
ExceptionState& exception_state) { const ArrayBufferOrArrayBufferViewOrBlobOrUSVString& data,
ExceptionState& exception_state) {
DCHECK(!data.IsNull()); DCHECK(!data.IsNull());
if (data.IsBlob())
return WriteBlob(script_state, position, data.GetAsBlob()); auto blob_data = std::make_unique<BlobData>();
return WriteStream(script_state, position, data.GetAsReadableStream(), Blob* blob = nullptr;
exception_state); if (data.IsArrayBuffer()) {
DOMArrayBuffer* array_buffer = data.GetAsArrayBuffer();
blob_data->AppendBytes(array_buffer->Data(), array_buffer->ByteLength());
} else if (data.IsArrayBufferView()) {
DOMArrayBufferView* array_buffer_view = data.GetAsArrayBufferView().View();
blob_data->AppendBytes(array_buffer_view->BaseAddress(),
array_buffer_view->byteLength());
} else if (data.IsBlob()) {
blob = data.GetAsBlob();
} else if (data.IsUSVString()) {
// Let the developer be explicit about line endings.
blob_data->AppendText(data.GetAsUSVString(),
/*normalize_line_endings_to_native=*/false);
}
if (!blob) {
uint64_t size = blob_data->length();
blob = Blob::Create(BlobDataHandle::Create(std::move(blob_data), size));
}
return WriteBlob(script_state, position, blob);
} }
ScriptPromise FileSystemWriter::WriteBlob(ScriptState* script_state, ScriptPromise FileSystemWriter::WriteBlob(ScriptState* script_state,
......
...@@ -6,12 +6,12 @@ ...@@ -6,12 +6,12 @@
#define THIRD_PARTY_BLINK_RENDERER_MODULES_FILESYSTEM_FILE_SYSTEM_WRITER_H_ #define THIRD_PARTY_BLINK_RENDERER_MODULES_FILESYSTEM_FILE_SYSTEM_WRITER_H_
#include "third_party/blink/public/mojom/filesystem/file_writer.mojom-blink.h" #include "third_party/blink/public/mojom/filesystem/file_writer.mojom-blink.h"
#include "third_party/blink/renderer/bindings/core/v8/array_buffer_or_array_buffer_view_or_blob_or_usv_string.h"
#include "third_party/blink/renderer/platform/bindings/script_wrappable.h" #include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
namespace blink { namespace blink {
class Blob; class Blob;
class BlobOrReadableStream;
class ExceptionState; class ExceptionState;
class FetchDataLoader; class FetchDataLoader;
class ReadableStream; class ReadableStream;
...@@ -27,7 +27,7 @@ class FileSystemWriter final : public ScriptWrappable { ...@@ -27,7 +27,7 @@ class FileSystemWriter final : public ScriptWrappable {
ScriptPromise write(ScriptState*, ScriptPromise write(ScriptState*,
uint64_t position, uint64_t position,
const BlobOrReadableStream& data, const ArrayBufferOrArrayBufferViewOrBlobOrUSVString& data,
ExceptionState&); ExceptionState&);
ScriptPromise truncate(ScriptState*, uint64_t size); ScriptPromise truncate(ScriptState*, uint64_t size);
ScriptPromise close(ScriptState*); ScriptPromise close(ScriptState*);
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
NoInterfaceObject, NoInterfaceObject,
RuntimeEnabled=NativeFileSystem RuntimeEnabled=NativeFileSystem
] interface FileSystemWriter { ] interface FileSystemWriter {
[CallWith=ScriptState, RaisesException] Promise<void> write(unsigned long long position, (Blob or ReadableStream) data); [CallWith=ScriptState, RaisesException] Promise<void> write(unsigned long long position, (BufferSource or Blob or USVString) data);
[CallWith=ScriptState] Promise<void> truncate(unsigned long long size); [CallWith=ScriptState] Promise<void> truncate(unsigned long long size);
[CallWith=ScriptState] Promise<void> close(); [CallWith=ScriptState] Promise<void> close();
......
...@@ -43,6 +43,66 @@ promise_test(async t => { ...@@ -43,6 +43,66 @@ promise_test(async t => {
assert_equals(await getFileSize(handle), 0); assert_equals(await getFileSize(handle), 0);
}, 'write() called with an invalid offset'); }, 'write() called with an invalid offset');
promise_test(async t => {
const handle = await createEmptyFile(t, 'empty_string');
const writer = await handle.createWriter();
await writer.write(0, '');
assert_equals(await getFileContents(handle), '');
assert_equals(await getFileSize(handle), 0);
}, 'write() with an empty string to an empty file');
promise_test(async t => {
const handle = await createEmptyFile(t, 'valid_utf8_string');
const writer = await handle.createWriter();
await writer.write(0, 'foo🤘');
assert_equals(await getFileContents(handle), 'foo🤘');
assert_equals(await getFileSize(handle), 7);
}, 'write() with a valid utf-8 string');
promise_test(async t => {
const handle = await createEmptyFile(t, 'string_with_unix_line_ending');
const writer = await handle.createWriter();
await writer.write(0, 'foo\n');
assert_equals(await getFileContents(handle), 'foo\n');
assert_equals(await getFileSize(handle), 4);
}, 'write() with a string with unix line ending preserved');
promise_test(async t => {
const handle = await createEmptyFile(t, 'string_with_windows_line_ending');
const writer = await handle.createWriter();
await writer.write(0, 'foo\r\n');
assert_equals(await getFileContents(handle), 'foo\r\n');
assert_equals(await getFileSize(handle), 5);
}, 'write() with a string with windows line ending preserved');
promise_test(async t => {
const handle = await createEmptyFile(t, 'empty_array_buffer');
const writer = await handle.createWriter();
let buf = new ArrayBuffer(0);
await writer.write(0, buf);
assert_equals(await getFileContents(handle), '');
assert_equals(await getFileSize(handle), 0);
}, 'write() with an empty array buffer to an empty file');
promise_test(async t => {
const handle = await createEmptyFile(t, 'valid_string_typed_byte_array');
const writer = await handle.createWriter();
let buf = new ArrayBuffer(3);
let intView = new Uint8Array(buf);
intView[0] = 0x66;
intView[1] = 0x6f;
intView[2] = 0x6f;
await writer.write(0, buf);
assert_equals(await getFileContents(handle), 'foo');
assert_equals(await getFileSize(handle), 3);
}, 'write() with a valid typed array buffer');
promise_test(async t => { promise_test(async t => {
const handle = await createEmptyFile(t, 'trunc_shrink'); const handle = await createEmptyFile(t, 'trunc_shrink');
const writer = await handle.createWriter(); const writer = await handle.createWriter();
...@@ -64,33 +124,3 @@ promise_test(async t => { ...@@ -64,33 +124,3 @@ promise_test(async t => {
assert_equals(await getFileContents(handle), 'abc\0\0'); assert_equals(await getFileContents(handle), 'abc\0\0');
assert_equals(await getFileSize(handle), 5); assert_equals(await getFileSize(handle), 5);
}, 'truncate() to grow a file'); }, 'truncate() to grow a file');
promise_test(async t => {
const handle = await createEmptyFile(t, 'write_stream');
const writer = await handle.createWriter();
const stream = new Response('1234567890').body;
await writer.write(0, stream);
assert_equals(await getFileContents(handle), '1234567890');
assert_equals(await getFileSize(handle), 10);
}, 'write() called with a ReadableStream');
promise_test(async t => {
const handle = await createEmptyFile(t, 'write_stream');
const handle_writer = await handle.createWriter();
const { writable, readable } = new TransformStream();
const write_result = handle_writer.write(0, readable);
const stream_writer = writable.getWriter();
stream_writer.write(new Uint8Array([0x73, 0x74, 0x72, 0x65, 0x61, 0x6D, 0x73, 0x21]));
garbageCollect();
stream_writer.write(new Uint8Array([0x21, 0x21]));
stream_writer.close();
await write_result;
assert_equals(await getFileContents(handle), 'streams!!!');
assert_equals(await getFileSize(handle), 10);
}, 'Using a WritableStream writer to write');
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment