mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 12:12:45 +00:00 
			
		
		
		
	LibWeb: Add and use a helper to reject a promise with an exception
This commit is contained in:
		
							parent
							
								
									24951a039e
								
							
						
					
					
						commit
						4bdb7dba8c
					
				
					 10 changed files with 42 additions and 52 deletions
				
			
		|  | @ -122,10 +122,8 @@ JS::NonnullGCPtr<JS::Promise> 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<JS::Promise>(*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<JS::Promise> 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<JS::Promise>(*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<JS::NonnullGCPtr<JS::Promise>> 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<JS::Promise>(*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); | ||||
|  |  | |||
|  | @ -155,9 +155,8 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> 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<JS::Promise>(*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.
 | ||||
|  |  | |||
|  | @ -367,11 +367,8 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> 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<JS::Promise>(*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<JS::NonnullGCPtr<JS::Promise>> Blob::text() | |||
| WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> 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<JS::Promise>(*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.
 | ||||
|  |  | |||
|  | @ -340,10 +340,8 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> 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<JS::Promise>(*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.
 | ||||
|  |  | |||
|  | @ -110,30 +110,26 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> 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<JS::Promise>(*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<JS::Promise>(*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<JS::Promise>(*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<JS::Promise>(*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.
 | ||||
|  |  | |||
|  | @ -158,9 +158,8 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> 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<JS::Promise>(*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.
 | ||||
|  |  | |||
|  | @ -26,9 +26,8 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> 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<JS::Promise>(*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).
 | ||||
|  |  | |||
|  | @ -32,6 +32,8 @@ struct SimpleException { | |||
|     Variant<String, StringView> message; | ||||
| }; | ||||
| 
 | ||||
| using Exception = Variant<SimpleException, JS::NonnullGCPtr<DOMException>, JS::Completion>; | ||||
| 
 | ||||
| template<typename ValueType> | ||||
| class [[nodiscard]] ExceptionOr { | ||||
| public: | ||||
|  | @ -78,7 +80,7 @@ public: | |||
|         VERIFY(completion.is_error()); | ||||
|     } | ||||
| 
 | ||||
|     ExceptionOr(Variant<SimpleException, JS::NonnullGCPtr<DOMException>, JS::Completion> exception) | ||||
|     ExceptionOr(Exception exception) | ||||
|         : m_result_or_exception(move(exception)) | ||||
|     { | ||||
|         if (auto* completion = m_result_or_exception.template get_pointer<JS::Completion>()) | ||||
|  | @ -100,7 +102,7 @@ public: | |||
|         return move(m_result_or_exception.template get<ValueType>()); | ||||
|     } | ||||
| 
 | ||||
|     Variant<SimpleException, JS::NonnullGCPtr<DOMException>, JS::Completion> exception() const | ||||
|     Exception exception() const | ||||
|     { | ||||
|         return m_result_or_exception.template downcast<SimpleException, JS::NonnullGCPtr<DOMException>, 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<SimpleException, JS::NonnullGCPtr<DOMException>, JS::Completion> release_error() { return exception(); } | ||||
|     Exception release_error() { return exception(); } | ||||
| 
 | ||||
| private: | ||||
|     // https://webidl.spec.whatwg.org/#idl-exceptions
 | ||||
|  |  | |||
|  | @ -13,7 +13,6 @@ | |||
| #include <LibWeb/Bindings/ExceptionOrUtils.h> | ||||
| #include <LibWeb/Bindings/HostDefined.h> | ||||
| #include <LibWeb/HTML/Scripting/ExceptionReporter.h> | ||||
| #include <LibWeb/WebIDL/ExceptionOr.h> | ||||
| #include <LibWeb/WebIDL/Promise.h> | ||||
| 
 | ||||
| namespace Web::WebIDL { | ||||
|  | @ -295,4 +294,11 @@ void wait_for_all(JS::Realm& realm, Vector<JS::NonnullGCPtr<Promise>> const& pro | |||
|     } | ||||
| } | ||||
| 
 | ||||
| JS::NonnullGCPtr<JS::Promise> 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<JS::Promise>(*promise_capability->promise().ptr()) }; | ||||
| } | ||||
| 
 | ||||
| } | ||||
|  |  | |||
|  | @ -12,6 +12,7 @@ | |||
| #include <LibJS/Runtime/Value.h> | ||||
| #include <LibJS/SafeFunction.h> | ||||
| #include <LibWeb/Forward.h> | ||||
| #include <LibWeb/WebIDL/ExceptionOr.h> | ||||
| 
 | ||||
| namespace Web::WebIDL { | ||||
| 
 | ||||
|  | @ -31,4 +32,7 @@ JS::NonnullGCPtr<JS::Promise> upon_rejection(Promise const&, ReactionSteps); | |||
| void mark_promise_as_handled(Promise const&); | ||||
| void wait_for_all(JS::Realm&, Vector<JS::NonnullGCPtr<Promise>> const& promises, Function<void(Vector<JS::Value> const&)> success_steps, Function<void(JS::Value)> failure_steps); | ||||
| 
 | ||||
| // Non-spec, convenience method.
 | ||||
| JS::NonnullGCPtr<JS::Promise> create_rejected_promise_from_exception(JS::Realm&, Exception); | ||||
| 
 | ||||
| } | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Sam Atkins
						Sam Atkins