Commit 4319a6eb authored by Miyoung Shin's avatar Miyoung Shin Committed by Commit Bot

Use [RaisesException] for immediate promise rejections in native_file_system, serial and websockets

This is a part of effort for using [RaisesException] when
synchronously rejecting a promise.

It uses [RaisesException] for
//third_party/blink/renderer/core/streams/underlying_sink_base.idl.

Bug: 1001114
Change-Id: I81c3012edec1c110e358e520f53d717313c0ed19
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1986475Reviewed-by: default avatarMarijn Kruisselbrink <mek@chromium.org>
Reviewed-by: default avatarReilly Grant <reillyg@chromium.org>
Reviewed-by: default avatarJeremy Roman <jbroman@chromium.org>
Commit-Queue: Miyoung Shin <myid.shin@igalia.com>
Cr-Commit-Position: refs/heads/master@{#729666}
parent b36d5d08
......@@ -13,6 +13,7 @@
namespace blink {
class ExceptionState;
class ScriptValue;
class ScriptState;
......@@ -26,22 +27,29 @@ class CORE_EXPORT UnderlyingSinkBase : public ScriptWrappable {
// |controller| and are called from IDL. Also we define virtual |start| and
// |write| which take WritableStreamDefaultController.
virtual ScriptPromise start(ScriptState*,
WritableStreamDefaultController*) = 0;
WritableStreamDefaultController*,
ExceptionState&) = 0;
virtual ScriptPromise write(ScriptState*,
ScriptValue chunk,
WritableStreamDefaultController*) = 0;
virtual ScriptPromise close(ScriptState*) = 0;
virtual ScriptPromise abort(ScriptState*, ScriptValue reason) = 0;
WritableStreamDefaultController*,
ExceptionState&) = 0;
virtual ScriptPromise close(ScriptState*, ExceptionState&) = 0;
virtual ScriptPromise abort(ScriptState*,
ScriptValue reason,
ExceptionState&) = 0;
ScriptPromise start(ScriptState* script_state, ScriptValue controller) {
ScriptPromise start(ScriptState* script_state,
ScriptValue controller,
ExceptionState& exception_state) {
controller_ = WritableStreamDefaultController::From(controller);
return start(script_state, controller_);
return start(script_state, controller_, exception_state);
}
ScriptPromise write(ScriptState* script_state,
ScriptValue chunk,
ScriptValue controller) {
ScriptValue controller,
ExceptionState& exception_state) {
DCHECK(controller_);
return write(script_state, chunk, controller_);
return write(script_state, chunk, controller_, exception_state);
}
void Trace(Visitor* visitor) override {
......
......@@ -10,8 +10,8 @@
NoInterfaceObject
]
interface UnderlyingSinkBase {
[CallWith=ScriptState] Promise<void> start(any controller);
[CallWith=ScriptState] Promise<void> write(any chunk, any controller);
[CallWith=ScriptState] Promise<void> close();
[CallWith=ScriptState] Promise<void> abort(any reason);
[CallWith=ScriptState, RaisesException] Promise<void> start(any controller);
[CallWith=ScriptState, RaisesException] Promise<void> write(any chunk, any controller);
[CallWith=ScriptState, RaisesException] Promise<void> close();
[CallWith=ScriptState, RaisesException] Promise<void> abort(any reason);
};
......@@ -30,18 +30,16 @@ NativeFileSystemUnderlyingSink::NativeFileSystemUnderlyingSink(
ScriptPromise NativeFileSystemUnderlyingSink::start(
ScriptState* script_state,
WritableStreamDefaultController* controller) {
WritableStreamDefaultController* controller,
ExceptionState& exception_state) {
return ScriptPromise::CastUndefined(script_state);
}
ScriptPromise NativeFileSystemUnderlyingSink::write(
ScriptState* script_state,
ScriptValue chunk,
WritableStreamDefaultController* controller) {
ExceptionState exception_state(script_state->GetIsolate(),
ExceptionState::kExecutionContext,
"NativeFileSystemUnderlyingSink", "write");
WritableStreamDefaultController* controller,
ExceptionState& exception_state) {
v8::Local<v8::Value> value = chunk.V8Value();
ArrayBufferOrArrayBufferViewOrBlobOrUSVStringOrWriteParams input;
......@@ -49,7 +47,7 @@ ScriptPromise NativeFileSystemUnderlyingSink::write(
script_state->GetIsolate(), value, input,
UnionTypeConversionMode::kNotNullable, exception_state);
if (exception_state.HadException())
return ScriptPromise::Reject(script_state, exception_state);
return ScriptPromise();
if (input.IsNull()) {
exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
......@@ -57,25 +55,28 @@ ScriptPromise NativeFileSystemUnderlyingSink::write(
return ScriptPromise();
}
if (input.IsWriteParams())
return HandleParams(script_state, std::move(*input.GetAsWriteParams()));
if (input.IsWriteParams()) {
return HandleParams(script_state, std::move(*input.GetAsWriteParams()),
exception_state);
}
ArrayBufferOrArrayBufferViewOrBlobOrUSVString write_data;
V8ArrayBufferOrArrayBufferViewOrBlobOrUSVString::ToImpl(
script_state->GetIsolate(), value, write_data,
UnionTypeConversionMode::kNotNullable, exception_state);
if (exception_state.HadException())
return ScriptPromise::Reject(script_state, exception_state);
return WriteData(script_state, offset_, std::move(write_data));
return ScriptPromise();
return WriteData(script_state, offset_, std::move(write_data),
exception_state);
}
ScriptPromise NativeFileSystemUnderlyingSink::close(ScriptState* script_state) {
ScriptPromise NativeFileSystemUnderlyingSink::close(
ScriptState* script_state,
ExceptionState& exception_state) {
if (!writer_remote_ || pending_operation_) {
return ScriptPromise::Reject(
script_state,
V8ThrowDOMException::CreateOrEmpty(script_state->GetIsolate(),
DOMExceptionCode::kInvalidStateError,
"Object reached an invalid state"));
exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
"Object reached an invalid state");
return ScriptPromise();
}
pending_operation_ =
MakeGarbageCollected<ScriptPromiseResolver>(script_state);
......@@ -86,8 +87,10 @@ ScriptPromise NativeFileSystemUnderlyingSink::close(ScriptState* script_state) {
return result;
}
ScriptPromise NativeFileSystemUnderlyingSink::abort(ScriptState* script_state,
ScriptValue reason) {
ScriptPromise NativeFileSystemUnderlyingSink::abort(
ScriptState* script_state,
ScriptValue reason,
ExceptionState& exception_state) {
// The specification guarantees that this will only be called after all
// pending writes have been aborted. Terminating the remote connection
// will ensure that the writes are not closed successfully.
......@@ -98,52 +101,49 @@ ScriptPromise NativeFileSystemUnderlyingSink::abort(ScriptState* script_state,
ScriptPromise NativeFileSystemUnderlyingSink::HandleParams(
ScriptState* script_state,
const WriteParams& params) {
const WriteParams& params,
ExceptionState& exception_state) {
if (params.type() == "truncate") {
if (!params.hasSize()) {
return ScriptPromise::Reject(
script_state,
V8ThrowDOMException::CreateOrEmpty(
script_state->GetIsolate(), DOMExceptionCode::kSyntaxError,
"Invalid params passed. truncate requires a size argument"));
exception_state.ThrowDOMException(
DOMExceptionCode::kSyntaxError,
"Invalid params passed. truncate requires a size argument");
return ScriptPromise();
}
return Truncate(script_state, params.size());
return Truncate(script_state, params.size(), exception_state);
}
if (params.type() == "seek") {
if (!params.hasPosition()) {
return ScriptPromise::Reject(
script_state,
V8ThrowDOMException::CreateOrEmpty(
script_state->GetIsolate(), DOMExceptionCode::kSyntaxError,
"Invalid params passed. seek requires a position argument"));
exception_state.ThrowDOMException(
DOMExceptionCode::kSyntaxError,
"Invalid params passed. seek requires a position argument");
return ScriptPromise();
}
return Seek(script_state, params.position());
return Seek(script_state, params.position(), exception_state);
}
if (params.type() == "write") {
uint64_t position = params.hasPosition() ? params.position() : offset_;
if (!params.hasData()) {
return ScriptPromise::Reject(
script_state,
V8ThrowDOMException::CreateOrEmpty(
script_state->GetIsolate(), DOMExceptionCode::kSyntaxError,
"Invalid params passed. write requires a data argument"));
exception_state.ThrowDOMException(
DOMExceptionCode::kSyntaxError,
"Invalid params passed. write requires a data argument");
return ScriptPromise();
}
return WriteData(script_state, position, params.data());
return WriteData(script_state, position, params.data(), exception_state);
}
return ScriptPromise::Reject(
script_state,
V8ThrowDOMException::CreateOrEmpty(script_state->GetIsolate(),
DOMExceptionCode::kInvalidStateError,
"Object reached an invalid state"));
exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
"Object reached an invalid state");
return ScriptPromise();
}
ScriptPromise NativeFileSystemUnderlyingSink::WriteData(
ScriptState* script_state,
uint64_t position,
const ArrayBufferOrArrayBufferViewOrBlobOrUSVString& data) {
const ArrayBufferOrArrayBufferViewOrBlobOrUSVString& data,
ExceptionState& exception_state) {
DCHECK(!data.IsNull());
auto blob_data = std::make_unique<BlobData>();
......@@ -170,19 +170,18 @@ ScriptPromise NativeFileSystemUnderlyingSink::WriteData(
BlobDataHandle::Create(std::move(blob_data), size));
}
return WriteBlob(script_state, position, blob);
return WriteBlob(script_state, position, blob, exception_state);
}
ScriptPromise NativeFileSystemUnderlyingSink::WriteBlob(
ScriptState* script_state,
uint64_t position,
Blob* blob) {
Blob* blob,
ExceptionState& exception_state) {
if (!writer_remote_ || pending_operation_) {
return ScriptPromise::Reject(
script_state,
V8ThrowDOMException::CreateOrEmpty(script_state->GetIsolate(),
DOMExceptionCode::kInvalidStateError,
"Object reached an invalid state"));
exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
"Object reached an invalid state");
return ScriptPromise();
}
pending_operation_ =
MakeGarbageCollected<ScriptPromiseResolver>(script_state);
......@@ -196,13 +195,12 @@ ScriptPromise NativeFileSystemUnderlyingSink::WriteBlob(
ScriptPromise NativeFileSystemUnderlyingSink::Truncate(
ScriptState* script_state,
uint64_t size) {
uint64_t size,
ExceptionState& exception_state) {
if (!writer_remote_ || pending_operation_) {
return ScriptPromise::Reject(
script_state,
V8ThrowDOMException::CreateOrEmpty(script_state->GetIsolate(),
DOMExceptionCode::kInvalidStateError,
"Object reached an invalid state"));
exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
"Object reached an invalid state");
return ScriptPromise();
}
pending_operation_ =
MakeGarbageCollected<ScriptPromiseResolver>(script_state);
......@@ -213,14 +211,14 @@ ScriptPromise NativeFileSystemUnderlyingSink::Truncate(
return result;
}
ScriptPromise NativeFileSystemUnderlyingSink::Seek(ScriptState* script_state,
uint64_t offset) {
ScriptPromise NativeFileSystemUnderlyingSink::Seek(
ScriptState* script_state,
uint64_t offset,
ExceptionState& exception_state) {
if (!writer_remote_ || pending_operation_) {
return ScriptPromise::Reject(
script_state,
V8ThrowDOMException::CreateOrEmpty(script_state->GetIsolate(),
DOMExceptionCode::kInvalidStateError,
"Object reached an invalid state"));
exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
"Object reached an invalid state");
return ScriptPromise();
}
offset_ = offset;
return ScriptPromise::CastUndefined(script_state);
......
......@@ -14,6 +14,7 @@
namespace blink {
class ExceptionState;
class ScriptPromiseResolver;
class WriteParams;
......@@ -27,25 +28,34 @@ class NativeFileSystemUnderlyingSink final : public UnderlyingSinkBase,
mojo::PendingRemote<mojom::blink::NativeFileSystemFileWriter>);
// UnderlyingSinkBase
ScriptPromise start(ScriptState*, WritableStreamDefaultController*) override;
ScriptPromise start(ScriptState*,
WritableStreamDefaultController*,
ExceptionState&) override;
ScriptPromise write(ScriptState*,
ScriptValue chunk,
WritableStreamDefaultController*) override;
ScriptPromise close(ScriptState*) override;
ScriptPromise abort(ScriptState*, ScriptValue reason) override;
WritableStreamDefaultController*,
ExceptionState&) override;
ScriptPromise close(ScriptState*, ExceptionState&) override;
ScriptPromise abort(ScriptState*,
ScriptValue reason,
ExceptionState&) override;
void Trace(Visitor*) override;
void ContextDestroyed(ExecutionContext*) override;
private:
ScriptPromise HandleParams(ScriptState*, const WriteParams&);
ScriptPromise HandleParams(ScriptState*, const WriteParams&, ExceptionState&);
ScriptPromise WriteData(
ScriptState*,
uint64_t position,
const ArrayBufferOrArrayBufferViewOrBlobOrUSVString& data);
ScriptPromise WriteBlob(ScriptState*, uint64_t position, Blob*);
ScriptPromise Truncate(ScriptState*, uint64_t size);
ScriptPromise Seek(ScriptState*, uint64_t offset);
const ArrayBufferOrArrayBufferViewOrBlobOrUSVString& data,
ExceptionState&);
ScriptPromise WriteBlob(ScriptState*,
uint64_t position,
Blob*,
ExceptionState&);
ScriptPromise Truncate(ScriptState*, uint64_t size, ExceptionState&);
ScriptPromise Seek(ScriptState*, uint64_t offset, ExceptionState&);
void WriteComplete(mojom::blink::NativeFileSystemErrorPtr result,
uint64_t bytes_written);
void TruncateComplete(uint64_t to_size,
......
......@@ -25,14 +25,16 @@ SerialPortUnderlyingSink::SerialPortUnderlyingSink(
ScriptPromise SerialPortUnderlyingSink::start(
ScriptState* script_state,
WritableStreamDefaultController* controller) {
WritableStreamDefaultController* controller,
ExceptionState& exception_state) {
return ScriptPromise::CastUndefined(script_state);
}
ScriptPromise SerialPortUnderlyingSink::write(
ScriptState* script_state,
ScriptValue chunk,
WritableStreamDefaultController* controller) {
WritableStreamDefaultController* controller,
ExceptionState& exception_state) {
// There can only be one call to write() in progress at a time.
DCHECK(buffer_source_.IsNull());
DCHECK_EQ(0u, offset_);
......@@ -42,18 +44,15 @@ ScriptPromise SerialPortUnderlyingSink::write(
DOMException* exception = pending_exception_;
pending_exception_ = nullptr;
serial_port_->UnderlyingSinkClosed();
return ScriptPromise::RejectWithDOMException(script_state, exception);
exception_state.RethrowV8Exception(ToV8(exception, script_state));
return ScriptPromise();
}
ExceptionState exception_state(script_state->GetIsolate(),
ExceptionState::kExecutionContext,
"SerialPortUnderlyingSink", "write");
V8ArrayBufferOrArrayBufferView::ToImpl(
script_state->GetIsolate(), chunk.V8Value(), buffer_source_,
UnionTypeConversionMode::kNotNullable, exception_state);
if (exception_state.HadException())
return ScriptPromise::Reject(script_state, exception_state);
return ScriptPromise();
pending_write_ = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
ScriptPromise promise = pending_write_->Promise();
......@@ -62,7 +61,8 @@ ScriptPromise SerialPortUnderlyingSink::write(
return promise;
}
ScriptPromise SerialPortUnderlyingSink::close(ScriptState* script_state) {
ScriptPromise SerialPortUnderlyingSink::close(ScriptState* script_state,
ExceptionState& exception_state) {
// The specification guarantees that this will only be called after all
// pending writes have been completed.
DCHECK(!pending_write_);
......@@ -74,7 +74,8 @@ ScriptPromise SerialPortUnderlyingSink::close(ScriptState* script_state) {
if (pending_exception_) {
DOMException* exception = pending_exception_;
pending_exception_ = nullptr;
return ScriptPromise::RejectWithDOMException(script_state, exception);
exception_state.RethrowV8Exception(ToV8(exception, script_state));
return ScriptPromise();
}
// TODO(crbug.com/989656): close() should wait for data to be flushed before
......@@ -83,12 +84,13 @@ ScriptPromise SerialPortUnderlyingSink::close(ScriptState* script_state) {
}
ScriptPromise SerialPortUnderlyingSink::abort(ScriptState* script_state,
ScriptValue reason) {
ScriptValue reason,
ExceptionState& exception_state) {
// The specification guarantees that this will only be called after all
// pending writes have been completed.
// TODO(crbug.com/969653): abort() should trigger a purge of the serial write
// buffers.
return close(script_state);
return close(script_state, exception_state);
}
void SerialPortUnderlyingSink::SignalErrorOnClose(DOMException* exception) {
......
......@@ -12,6 +12,7 @@
namespace blink {
class ExceptionState;
class ScriptPromiseResolver;
class SerialPort;
......@@ -20,12 +21,17 @@ class SerialPortUnderlyingSink final : public UnderlyingSinkBase {
SerialPortUnderlyingSink(SerialPort*, mojo::ScopedDataPipeProducerHandle);
// UnderlyingSinkBase
ScriptPromise start(ScriptState*, WritableStreamDefaultController*) override;
ScriptPromise start(ScriptState*,
WritableStreamDefaultController*,
ExceptionState&) override;
ScriptPromise write(ScriptState*,
ScriptValue chunk,
WritableStreamDefaultController*) override;
ScriptPromise close(ScriptState*) override;
ScriptPromise abort(ScriptState*, ScriptValue reason) override;
WritableStreamDefaultController*,
ExceptionState&) override;
ScriptPromise close(ScriptState*, ExceptionState&) override;
ScriptPromise abort(ScriptState*,
ScriptValue reason,
ExceptionState&) override;
// After |data_pipe_| has closed calls to write() will return a Promise
// rejected with this DOMException.
......
......@@ -68,12 +68,17 @@ class WebSocketStream::UnderlyingSink final : public UnderlyingSinkBase {
explicit UnderlyingSink(WebSocketStream* creator) : creator_(creator) {}
// UnderlyingSinkBase implementation.
ScriptPromise start(ScriptState*, WritableStreamDefaultController*) override;
ScriptPromise start(ScriptState*,
WritableStreamDefaultController*,
ExceptionState&) override;
ScriptPromise write(ScriptState*,
ScriptValue chunk,
WritableStreamDefaultController*) override;
ScriptPromise close(ScriptState*) override;
ScriptPromise abort(ScriptState*, ScriptValue reason) override;
WritableStreamDefaultController*,
ExceptionState&) override;
ScriptPromise close(ScriptState*, ExceptionState&) override;
ScriptPromise abort(ScriptState*,
ScriptValue reason,
ExceptionState&) override;
// API for WebSocketStream.
void DidStartClosingHandshake();
......@@ -93,7 +98,8 @@ class WebSocketStream::UnderlyingSink final : public UnderlyingSinkBase {
void SendAny(ScriptState*,
v8::Local<v8::Value> v8chunk,
ScriptPromiseResolver*,
base::OnceClosure callback);
base::OnceClosure callback,
ExceptionState&);
void SendArrayBuffer(ScriptState*,
DOMArrayBuffer*,
size_t offset,
......@@ -178,7 +184,8 @@ void WebSocketStream::UnderlyingSource::DidClose(bool was_clean,
ScriptPromise WebSocketStream::UnderlyingSink::start(
ScriptState* script_state,
WritableStreamDefaultController*) {
WritableStreamDefaultController*,
ExceptionState& exception_state) {
DVLOG(1) << "WebSocketStream::UnderlyingSink " << this << " start()";
return ScriptPromise::CastUndefined(script_state);
}
......@@ -186,7 +193,8 @@ ScriptPromise WebSocketStream::UnderlyingSink::start(
ScriptPromise WebSocketStream::UnderlyingSink::write(
ScriptState* script_state,
ScriptValue chunk,
WritableStreamDefaultController*) {
WritableStreamDefaultController*,
ExceptionState& exception_state) {
DVLOG(1) << "WebSocketStream::UnderlyingSink " << this << " write()";
is_writing_ = true;
auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
......@@ -195,12 +203,16 @@ ScriptPromise WebSocketStream::UnderlyingSink::write(
WTF::Bind(&UnderlyingSink::FinishWriteCallback, WrapWeakPersistent(this),
WrapPersistent(resolver));
v8::Local<v8::Value> v8chunk = chunk.V8Value();
SendAny(script_state, v8chunk, resolver, std::move(callback));
SendAny(script_state, v8chunk, resolver, std::move(callback),
exception_state);
if (exception_state.HadException())
return ScriptPromise();
return result;
}
ScriptPromise WebSocketStream::UnderlyingSink::close(
ScriptState* script_state) {
ScriptState* script_state,
ExceptionState& exception_state) {
DVLOG(1) << "WebSocketStream::UnderlyingSink " << this << " close()";
closed_ = true;
creator_->CloseWithUnspecifiedCode();
......@@ -209,8 +221,10 @@ ScriptPromise WebSocketStream::UnderlyingSink::close(
return close_resolver_->Promise();
}
ScriptPromise WebSocketStream::UnderlyingSink::abort(ScriptState* script_state,
ScriptValue reason) {
ScriptPromise WebSocketStream::UnderlyingSink::abort(
ScriptState* script_state,
ScriptValue reason,
ExceptionState& exception_state) {
DVLOG(1) << "WebSocketStream::UnderlyingSink " << this << " abort()";
closed_ = true;
......@@ -288,7 +302,8 @@ void WebSocketStream::UnderlyingSink::ResolveClose(bool was_clean) {
void WebSocketStream::UnderlyingSink::SendAny(ScriptState* script_state,
v8::Local<v8::Value> v8chunk,
ScriptPromiseResolver* resolver,
base::OnceClosure callback) {
base::OnceClosure callback,
ExceptionState& exception_state) {
DVLOG(1) << "WebSocketStream::UnderlyingSink " << this << " SendAny()";
auto* isolate = script_state->GetIsolate();
if (v8chunk->IsArrayBuffer()) {
......@@ -299,15 +314,12 @@ void WebSocketStream::UnderlyingSink::SendAny(ScriptState* script_state,
}
if (v8chunk->IsArrayBufferView()) {
ExceptionState exception_state(isolate, ExceptionState::kUnknownContext, "",
"");
NotShared<DOMArrayBufferView> data =
ToNotShared<NotShared<DOMArrayBufferView>>(isolate, v8chunk,
exception_state);
if (exception_state.HadException()) {
closed_ = true;
is_writing_ = false;
resolver->Reject(exception_state);
return;
}
......
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