diff --git a/Userland/Libraries/LibWeb/Crypto/SubtleCrypto.cpp b/Userland/Libraries/LibWeb/Crypto/SubtleCrypto.cpp index edc2ddef39..fab1678be1 100644 --- a/Userland/Libraries/LibWeb/Crypto/SubtleCrypto.cpp +++ b/Userland/Libraries/LibWeb/Crypto/SubtleCrypto.cpp @@ -122,10 +122,8 @@ JS::NonnullGCPtr SubtleCrypto::digest(AlgorithmIdentifier const& al // 2. Let data be the result of getting a copy of the bytes held by the data parameter passed to the digest() method. auto data_buffer_or_error = WebIDL::get_buffer_source_copy(*data->raw_object()); - if (data_buffer_or_error.is_error()) { - auto promise = WebIDL::create_rejected_promise(realm, WebIDL::OperationError::create(realm, "Failed to copy bytes from ArrayBuffer"_fly_string)); - return verify_cast(*promise->promise()); - } + if (data_buffer_or_error.is_error()) + return WebIDL::create_rejected_promise_from_exception(realm, WebIDL::OperationError::create(realm, "Failed to copy bytes from ArrayBuffer"_fly_string)); auto data_buffer = data_buffer_or_error.release_value(); // 3. Let normalizedAlgorithm be the result of normalizing an algorithm, with alg set to algorithm and op set to "digest". @@ -133,10 +131,8 @@ JS::NonnullGCPtr SubtleCrypto::digest(AlgorithmIdentifier const& al // 4. If an error occurred, return a Promise rejected with normalizedAlgorithm. // FIXME: Spec bug: link to https://webidl.spec.whatwg.org/#a-promise-rejected-with - if (normalized_algorithm.is_error()) { - auto promise = WebIDL::create_rejected_promise(realm, normalized_algorithm.release_error().release_value().value()); - return verify_cast(*promise->promise()); - } + if (normalized_algorithm.is_error()) + return WebIDL::create_rejected_promise_from_exception(realm, normalized_algorithm.release_error()); // 5. Let promise be a new Promise. auto promise = WebIDL::create_promise(realm); @@ -219,10 +215,8 @@ JS::ThrowCompletionOr> SubtleCrypto::import_key(Bi auto normalized_algorithm = normalize_an_algorithm(algorithm, "importKey"_string); // 6. If an error occurred, return a Promise rejected with normalizedAlgorithm. - if (normalized_algorithm.is_error()) { - auto promise = WebIDL::create_rejected_promise(realm, normalized_algorithm.release_error().release_value().value()); - return verify_cast(*promise->promise()); - } + if (normalized_algorithm.is_error()) + return WebIDL::create_rejected_promise_from_exception(realm, normalized_algorithm.release_error()); // 7. Let promise be a new Promise. auto promise = WebIDL::create_promise(realm); diff --git a/Userland/Libraries/LibWeb/Fetch/Body.cpp b/Userland/Libraries/LibWeb/Fetch/Body.cpp index ac15e6f18d..ac34ca90c7 100644 --- a/Userland/Libraries/LibWeb/Fetch/Body.cpp +++ b/Userland/Libraries/LibWeb/Fetch/Body.cpp @@ -155,9 +155,8 @@ WebIDL::ExceptionOr> consume_body(JS::Realm& realm { // 1. If object is unusable, then return a promise rejected with a TypeError. if (object.is_unusable()) { - auto exception = JS::TypeError::create(realm, "Body is unusable"sv); - auto promise_capability = WebIDL::create_rejected_promise(realm, exception); - return JS::NonnullGCPtr { verify_cast(*promise_capability->promise().ptr()) }; + WebIDL::SimpleException exception { WebIDL::SimpleExceptionType::TypeError, "Body is unusable"sv }; + return WebIDL::create_rejected_promise_from_exception(realm, move(exception)); } // 2. Let promise be a new promise. diff --git a/Userland/Libraries/LibWeb/FileAPI/Blob.cpp b/Userland/Libraries/LibWeb/FileAPI/Blob.cpp index b1f8a3d9f1..4dabe0385e 100644 --- a/Userland/Libraries/LibWeb/FileAPI/Blob.cpp +++ b/Userland/Libraries/LibWeb/FileAPI/Blob.cpp @@ -367,11 +367,8 @@ WebIDL::ExceptionOr> Blob::text() // 2. Let reader be the result of getting a reader from stream. If that threw an exception, return a new promise rejected with that exception. auto reader_or_exception = acquire_readable_stream_default_reader(*stream); - if (reader_or_exception.is_exception()) { - auto throw_completion = Bindings::dom_exception_to_throw_completion(vm, reader_or_exception.exception()); - auto promise_capability = WebIDL::create_rejected_promise(realm, *throw_completion.value()); - return JS::NonnullGCPtr { verify_cast(*promise_capability->promise().ptr()) }; - } + if (reader_or_exception.is_exception()) + return WebIDL::create_rejected_promise_from_exception(realm, reader_or_exception.release_error()); auto reader = reader_or_exception.release_value(); // 3. Let promise be the result of reading all bytes from stream with reader @@ -393,18 +390,14 @@ WebIDL::ExceptionOr> Blob::text() WebIDL::ExceptionOr> Blob::array_buffer() { auto& realm = this->realm(); - auto& vm = realm.vm(); // 1. Let stream be the result of calling get stream on this. auto stream = TRY(this->get_stream()); // 2. Let reader be the result of getting a reader from stream. If that threw an exception, return a new promise rejected with that exception. auto reader_or_exception = acquire_readable_stream_default_reader(*stream); - if (reader_or_exception.is_exception()) { - auto throw_completion = Bindings::dom_exception_to_throw_completion(vm, reader_or_exception.exception()); - auto promise_capability = WebIDL::create_rejected_promise(realm, *throw_completion.value()); - return JS::NonnullGCPtr { verify_cast(*promise_capability->promise().ptr()) }; - } + if (reader_or_exception.is_exception()) + return WebIDL::create_rejected_promise_from_exception(realm, reader_or_exception.release_error()); auto reader = reader_or_exception.release_value(); // 3. Let promise be the result of reading all bytes from stream with reader. diff --git a/Userland/Libraries/LibWeb/HTML/HTMLMediaElement.cpp b/Userland/Libraries/LibWeb/HTML/HTMLMediaElement.cpp index 9ddb0b7755..4d9193a7a8 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLMediaElement.cpp +++ b/Userland/Libraries/LibWeb/HTML/HTMLMediaElement.cpp @@ -340,10 +340,8 @@ WebIDL::ExceptionOr> HTMLMediaElement::play() // 2. If the media element's error attribute is not null and its code is MEDIA_ERR_SRC_NOT_SUPPORTED, then return a promise // rejected with a "NotSupportedError" DOMException. if (m_error && m_error->code() == MediaError::Code::SrcNotSupported) { - auto error = WebIDL::NotSupportedError::create(realm, m_error->message()); - auto promise = WebIDL::create_rejected_promise(realm, error); - - return JS::NonnullGCPtr { verify_cast(*promise->promise()) }; + auto exception = WebIDL::NotSupportedError::create(realm, m_error->message()); + return WebIDL::create_rejected_promise_from_exception(realm, move(exception)); } // 3. Let promise be a new promise and append promise to the list of pending play promises. diff --git a/Userland/Libraries/LibWeb/Streams/ReadableStreamBYOBReader.cpp b/Userland/Libraries/LibWeb/Streams/ReadableStreamBYOBReader.cpp index 07cc7c8a9c..638871c214 100644 --- a/Userland/Libraries/LibWeb/Streams/ReadableStreamBYOBReader.cpp +++ b/Userland/Libraries/LibWeb/Streams/ReadableStreamBYOBReader.cpp @@ -110,30 +110,26 @@ WebIDL::ExceptionOr> ReadableStreamBYOBReader::rea // 1. If view.[[ByteLength]] is 0, return a promise rejected with a TypeError exception. if (view->byte_length() == 0) { - auto exception = JS::TypeError::create(realm, "Cannot read in an empty buffer"sv); - auto promise_capability = WebIDL::create_rejected_promise(realm, exception); - return JS::NonnullGCPtr { verify_cast(*promise_capability->promise()) }; + WebIDL::SimpleException exception { WebIDL::SimpleExceptionType::TypeError, "Cannot read in an empty buffer"sv }; + return WebIDL::create_rejected_promise_from_exception(realm, move(exception)); } // 2. If view.[[ViewedArrayBuffer]].[[ArrayBufferByteLength]] is 0, return a promise rejected with a TypeError exception. if (view->viewed_array_buffer()->byte_length() == 0) { - auto exception = JS::TypeError::create(realm, "Cannot read in an empty buffer"sv); - auto promise_capability = WebIDL::create_rejected_promise(realm, exception); - return JS::NonnullGCPtr { verify_cast(*promise_capability->promise()) }; + WebIDL::SimpleException exception { WebIDL::SimpleExceptionType::TypeError, "Cannot read in an empty buffer"sv }; + return WebIDL::create_rejected_promise_from_exception(realm, move(exception)); } // 3. If ! IsDetachedBuffer(view.[[ViewedArrayBuffer]]) is true, return a promise rejected with a TypeError exception. if (view->viewed_array_buffer()->is_detached()) { - auto exception = JS::TypeError::create(realm, "Cannot read in a detached buffer"sv); - auto promise_capability = WebIDL::create_rejected_promise(realm, exception); - return JS::NonnullGCPtr { verify_cast(*promise_capability->promise()) }; + WebIDL::SimpleException exception { WebIDL::SimpleExceptionType::TypeError, "Cannot read in a detached buffer"sv }; + return WebIDL::create_rejected_promise_from_exception(realm, move(exception)); } // 4. If this.[[stream]] is undefined, return a promise rejected with a TypeError exception. if (!m_stream) { - auto exception = JS::TypeError::create(realm, "Cannot read from an empty stream"sv); - auto promise_capability = WebIDL::create_rejected_promise(realm, exception); - return JS::NonnullGCPtr { verify_cast(*promise_capability->promise()) }; + WebIDL::SimpleException exception { WebIDL::SimpleExceptionType::TypeError, "Cannot read from an empty stream"sv }; + return WebIDL::create_rejected_promise_from_exception(realm, move(exception)); } // 5. Let promise be a new promise. diff --git a/Userland/Libraries/LibWeb/Streams/ReadableStreamDefaultReader.cpp b/Userland/Libraries/LibWeb/Streams/ReadableStreamDefaultReader.cpp index 53d055c08c..fa2df5f946 100644 --- a/Userland/Libraries/LibWeb/Streams/ReadableStreamDefaultReader.cpp +++ b/Userland/Libraries/LibWeb/Streams/ReadableStreamDefaultReader.cpp @@ -158,9 +158,8 @@ WebIDL::ExceptionOr> ReadableStreamDefaultReader:: // 1. If this.[[stream]] is undefined, return a promise rejected with a TypeError exception. if (!m_stream) { - auto exception = JS::TypeError::create(realm, "Cannot read from an empty stream"sv); - auto promise_capability = WebIDL::create_rejected_promise(realm, exception); - return JS::NonnullGCPtr { verify_cast(*promise_capability->promise()) }; + WebIDL::SimpleException exception { WebIDL::SimpleExceptionType::TypeError, "Cannot read from an empty stream"sv }; + return WebIDL::create_rejected_promise_from_exception(realm, move(exception)); } // 2. Let promise be a new promise. diff --git a/Userland/Libraries/LibWeb/Streams/ReadableStreamGenericReader.cpp b/Userland/Libraries/LibWeb/Streams/ReadableStreamGenericReader.cpp index 3e370c531f..6f1e5b49f2 100644 --- a/Userland/Libraries/LibWeb/Streams/ReadableStreamGenericReader.cpp +++ b/Userland/Libraries/LibWeb/Streams/ReadableStreamGenericReader.cpp @@ -26,9 +26,8 @@ WebIDL::ExceptionOr> ReadableStreamGenericReaderMi { // 1. If this.[[stream]] is undefined, return a promise rejected with a TypeError exception. if (!m_stream) { - auto exception = JS::TypeError::create(m_realm, "No stream present to cancel"sv); - auto promise_capability = WebIDL::create_rejected_promise(m_realm, exception); - return JS::NonnullGCPtr { verify_cast(*promise_capability->promise().ptr()) }; + WebIDL::SimpleException exception { WebIDL::SimpleExceptionType::TypeError, "No stream present to cancel"sv }; + return WebIDL::create_rejected_promise_from_exception(m_realm, move(exception)); } // 2. Return ! ReadableStreamReaderGenericCancel(this, reason). diff --git a/Userland/Libraries/LibWeb/WebIDL/ExceptionOr.h b/Userland/Libraries/LibWeb/WebIDL/ExceptionOr.h index 7b54991099..566222fa58 100644 --- a/Userland/Libraries/LibWeb/WebIDL/ExceptionOr.h +++ b/Userland/Libraries/LibWeb/WebIDL/ExceptionOr.h @@ -32,6 +32,8 @@ struct SimpleException { Variant message; }; +using Exception = Variant, JS::Completion>; + template class [[nodiscard]] ExceptionOr { public: @@ -78,7 +80,7 @@ public: VERIFY(completion.is_error()); } - ExceptionOr(Variant, JS::Completion> exception) + ExceptionOr(Exception exception) : m_result_or_exception(move(exception)) { if (auto* completion = m_result_or_exception.template get_pointer()) @@ -100,7 +102,7 @@ public: return move(m_result_or_exception.template get()); } - Variant, JS::Completion> exception() const + Exception exception() const { return m_result_or_exception.template downcast, JS::Completion>(); } @@ -118,7 +120,7 @@ public: // These are for compatibility with the TRY() macro in AK. [[nodiscard]] bool is_error() const { return is_exception(); } - Variant, JS::Completion> release_error() { return exception(); } + Exception release_error() { return exception(); } private: // https://webidl.spec.whatwg.org/#idl-exceptions diff --git a/Userland/Libraries/LibWeb/WebIDL/Promise.cpp b/Userland/Libraries/LibWeb/WebIDL/Promise.cpp index a3951cc0f0..d2e58a8128 100644 --- a/Userland/Libraries/LibWeb/WebIDL/Promise.cpp +++ b/Userland/Libraries/LibWeb/WebIDL/Promise.cpp @@ -13,7 +13,6 @@ #include #include #include -#include #include namespace Web::WebIDL { @@ -295,4 +294,11 @@ void wait_for_all(JS::Realm& realm, Vector> const& pro } } +JS::NonnullGCPtr create_rejected_promise_from_exception(JS::Realm& realm, Exception exception) +{ + auto throw_completion = Bindings::dom_exception_to_throw_completion(realm.vm(), move(exception)); + auto promise_capability = WebIDL::create_rejected_promise(realm, *throw_completion.value()); + return JS::NonnullGCPtr { verify_cast(*promise_capability->promise().ptr()) }; +} + } diff --git a/Userland/Libraries/LibWeb/WebIDL/Promise.h b/Userland/Libraries/LibWeb/WebIDL/Promise.h index 53b5a9d427..63a1f9586d 100644 --- a/Userland/Libraries/LibWeb/WebIDL/Promise.h +++ b/Userland/Libraries/LibWeb/WebIDL/Promise.h @@ -12,6 +12,7 @@ #include #include #include +#include namespace Web::WebIDL { @@ -31,4 +32,7 @@ JS::NonnullGCPtr upon_rejection(Promise const&, ReactionSteps); void mark_promise_as_handled(Promise const&); void wait_for_all(JS::Realm&, Vector> const& promises, Function const&)> success_steps, Function failure_steps); +// Non-spec, convenience method. +JS::NonnullGCPtr create_rejected_promise_from_exception(JS::Realm&, Exception); + }