LibWeb: Implement WritableStream.abort()

This commit is contained in:
Matthew Olsson 2023-04-02 08:27:37 -07:00 committed by Linus Groh
parent ae2d67c28b
commit c421b6113c
5 changed files with 72 additions and 3 deletions

View file

@ -8,6 +8,7 @@
#include <LibJS/Runtime/PromiseCapability.h>
#include <LibJS/Runtime/PromiseConstructor.h>
#include <LibWeb/Bindings/ExceptionOrUtils.h>
#include <LibWeb/DOM/AbortSignal.h>
#include <LibWeb/Streams/AbstractOperations.h>
#include <LibWeb/Streams/ReadableStream.h>
#include <LibWeb/Streams/ReadableStreamDefaultController.h>
@ -839,6 +840,59 @@ WebIDL::ExceptionOr<void> set_up_writable_stream_default_writer(WritableStreamDe
return {};
}
// https://streams.spec.whatwg.org/#writable-stream-abort
WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> writable_stream_abort(WritableStream& stream, JS::Value reason)
{
auto& realm = stream.realm();
// 1. If stream.[[state]] is "closed" or "errored", return a promise resolved with undefined.
auto state = stream.state();
if (state == WritableStream::State::Closed || state == WritableStream::State::Errored)
return WebIDL::create_resolved_promise(realm, JS::js_undefined());
// 2. Signal abort on stream.[[controller]].[[signal]] with reason.
stream.controller()->signal()->signal_abort(reason);
// 3. Let state be stream.[[state]].
state = stream.state();
// 4. If state is "closed" or "errored", return a promise resolved with undefined.
if (state == WritableStream::State::Closed || state == WritableStream::State::Errored)
return WebIDL::create_resolved_promise(realm, JS::js_undefined());
// 5. If stream.[[pendingAbortRequest]] is not undefined, return stream.[[pendingAbortRequest]]'s promise.
if (stream.pending_abort_request().has_value())
return stream.pending_abort_request()->promise;
// 6. Assert: state is "writable" or "erroring".
VERIFY(state == WritableStream::State::Writable || state == WritableStream::State::Erroring);
// 7. Let wasAlreadyErroring be false.
auto was_already_erroring = false;
// 8. If state is "erroring",
if (state == WritableStream::State::Erroring) {
// 1. Set wasAlreadyErroring to true.
was_already_erroring = true;
// 2. Set reason to undefined.
reason = JS::js_undefined();
}
// 9. Let promise be a new promise.
auto promise = WebIDL::create_promise(realm);
// 10. Set stream.[[pendingAbortRequest]] to a new pending abort request whose promise is promise, reason is reason, and was already erroring is wasAlreadyErroring.
stream.set_pending_abort_request(PendingAbortRequest { promise, reason, was_already_erroring });
// 11. If wasAlreadyErroring is false, perform ! WritableStreamStartErroring(stream, reason).
if (!was_already_erroring)
TRY(writable_stream_start_erroring(stream, reason));
// 12. Return promise.
return promise;
}
// https://streams.spec.whatwg.org/#writable-stream-close
WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> writable_stream_close(WritableStream& stream)
{

View file

@ -56,6 +56,7 @@ WebIDL::ExceptionOr<void> set_up_readable_stream_default_controller_from_underly
WebIDL::ExceptionOr<JS::NonnullGCPtr<WritableStreamDefaultWriter>> acquire_writable_stream_default_writer(WritableStream&);
bool is_writable_stream_locked(WritableStream const&);
WebIDL::ExceptionOr<void> set_up_writable_stream_default_writer(WritableStreamDefaultWriter&, WritableStream&);
WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> writable_stream_abort(WritableStream&, JS::Value reason);
WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> writable_stream_close(WritableStream&);
bool writable_stream_close_queued_or_in_flight(WritableStream const&);

View file

@ -76,6 +76,21 @@ WebIDL::ExceptionOr<JS::GCPtr<JS::Object>> WritableStream::close()
return TRY(writable_stream_close(*this))->promise();
}
// https://streams.spec.whatwg.org/#ws-abort
WebIDL::ExceptionOr<JS::GCPtr<JS::Object>> WritableStream::abort(JS::Value reason)
{
auto& realm = this->realm();
// 1. If ! IsWritableStreamLocked(this) is true, return a promise rejected with a TypeError exception.
if (is_writable_stream_locked(*this)) {
auto exception = MUST_OR_THROW_OOM(JS::TypeError::create(realm, "Cannot abort a locked stream"sv));
return WebIDL::create_rejected_promise(realm, exception)->promise();
}
// 2. Return ! WritableStreamAbort(this, reason).
return TRY(writable_stream_abort(*this, reason))->promise();
}
// https://streams.spec.whatwg.org/#ws-get-writer
WebIDL::ExceptionOr<JS::NonnullGCPtr<WritableStreamDefaultWriter>> WritableStream::get_writer()
{

View file

@ -47,6 +47,7 @@ public:
virtual ~WritableStream() = default;
bool locked() const;
WebIDL::ExceptionOr<JS::GCPtr<JS::Object>> abort(JS::Value reason);
WebIDL::ExceptionOr<JS::GCPtr<JS::Object>> close();
WebIDL::ExceptionOr<JS::NonnullGCPtr<WritableStreamDefaultWriter>> get_writer();

View file

@ -7,9 +7,7 @@ interface WritableStream {
readonly attribute boolean locked;
// FIXME:
// Promise<undefined> abort(optional any reason);
Promise<undefined> abort(optional any reason);
Promise<undefined> close();
WritableStreamDefaultWriter getWriter();
};