diff --git a/Userland/Libraries/LibWeb/Bindings/ExceptionOrUtils.h b/Userland/Libraries/LibWeb/Bindings/ExceptionOrUtils.h index 61e7f9426408..1cf30601e5da 100644 --- a/Userland/Libraries/LibWeb/Bindings/ExceptionOrUtils.h +++ b/Userland/Libraries/LibWeb/Bindings/ExceptionOrUtils.h @@ -58,7 +58,7 @@ struct ExtractExceptionOrValueType> { } -ALWAYS_INLINE JS::Completion dom_exception_to_throw_completion(JS::VM& vm, auto&& exception) +ALWAYS_INLINE JS::Completion exception_to_throw_completion(JS::VM& vm, auto&& exception) { return exception.visit( [&](WebIDL::SimpleException const& exception) { @@ -97,7 +97,7 @@ JS::ThrowCompletionOr throw_dom_exception_if_needed(JS::VM& vm, F&& fn) auto&& result = fn(); if (result.is_exception()) - return dom_exception_to_throw_completion(vm, result.exception()); + return exception_to_throw_completion(vm, result.exception()); if constexpr (requires(T v) { v.value(); }) return result.value(); diff --git a/Userland/Libraries/LibWeb/Bindings/MainThreadVM.cpp b/Userland/Libraries/LibWeb/Bindings/MainThreadVM.cpp index d561e1f66dbd..721db86dd7d1 100644 --- a/Userland/Libraries/LibWeb/Bindings/MainThreadVM.cpp +++ b/Userland/Libraries/LibWeb/Bindings/MainThreadVM.cpp @@ -463,7 +463,7 @@ ErrorOr initialize_main_thread_vm(HTML::EventLoop::Type type) // 10. If the previous step threw an exception, then: if (url.is_exception()) { // 1. Let completion be Completion Record { [[Type]]: throw, [[Value]]: resolutionError, [[Target]]: empty }. - auto completion = dom_exception_to_throw_completion(main_thread_vm(), url.exception()); + auto completion = exception_to_throw_completion(main_thread_vm(), url.exception()); // 2. Perform FinishLoadingImportedModule(referrer, moduleRequest, payload, completion). HTML::TemporaryExecutionContext context { *module_map_realm }; diff --git a/Userland/Libraries/LibWeb/CSS/FontFaceSet.cpp b/Userland/Libraries/LibWeb/CSS/FontFaceSet.cpp index 997023ca7e39..585df8114a4b 100644 --- a/Userland/Libraries/LibWeb/CSS/FontFaceSet.cpp +++ b/Userland/Libraries/LibWeb/CSS/FontFaceSet.cpp @@ -242,7 +242,7 @@ JS::ThrowCompletionOr> FontFaceSet::load(Strin auto result = find_matching_font_faces(realm, font_face_set, font, text); if (result.is_error()) { HTML::TemporaryExecutionContext execution_context { realm, HTML::TemporaryExecutionContext::CallbacksEnabled::Yes }; - WebIDL::reject_promise(realm, promise, Bindings::dom_exception_to_throw_completion(realm.vm(), result.release_error()).release_value().value()); + WebIDL::reject_promise(realm, promise, Bindings::exception_to_throw_completion(realm.vm(), result.release_error()).release_value().value()); return; } diff --git a/Userland/Libraries/LibWeb/Crypto/SubtleCrypto.cpp b/Userland/Libraries/LibWeb/Crypto/SubtleCrypto.cpp index 253e9a247683..b3b504581e02 100644 --- a/Userland/Libraries/LibWeb/Crypto/SubtleCrypto.cpp +++ b/Userland/Libraries/LibWeb/Crypto/SubtleCrypto.cpp @@ -166,7 +166,7 @@ JS::NonnullGCPtr SubtleCrypto::encrypt(AlgorithmIdentifier cons // 10. Let ciphertext be the result of performing the encrypt operation specified by normalizedAlgorithm using algorithm and key and with data as plaintext. auto cipher_text = normalized_algorithm.methods->encrypt(*normalized_algorithm.parameter, key, data); if (cipher_text.is_error()) { - WebIDL::reject_promise(realm, promise, Bindings::dom_exception_to_throw_completion(realm.vm(), cipher_text.release_error()).release_value().value()); + WebIDL::reject_promise(realm, promise, Bindings::exception_to_throw_completion(realm.vm(), cipher_text.release_error()).release_value().value()); return; } @@ -223,7 +223,7 @@ JS::NonnullGCPtr SubtleCrypto::decrypt(AlgorithmIdentifier cons // 10. Let plaintext be the result of performing the decrypt operation specified by normalizedAlgorithm using algorithm and key and with data as ciphertext. auto plain_text = normalized_algorithm.methods->decrypt(*normalized_algorithm.parameter, key, data); if (plain_text.is_error()) { - WebIDL::reject_promise(realm, promise, Bindings::dom_exception_to_throw_completion(realm.vm(), plain_text.release_error()).release_value().value()); + WebIDL::reject_promise(realm, promise, Bindings::exception_to_throw_completion(realm.vm(), plain_text.release_error()).release_value().value()); return; } @@ -271,7 +271,7 @@ JS::NonnullGCPtr SubtleCrypto::digest(AlgorithmIdentifier const auto result = algorithm_object.methods->digest(*algorithm_object.parameter, data_buffer); if (result.is_exception()) { - WebIDL::reject_promise(realm, promise, Bindings::dom_exception_to_throw_completion(realm.vm(), result.release_error()).release_value().value()); + WebIDL::reject_promise(realm, promise, Bindings::exception_to_throw_completion(realm.vm(), result.release_error()).release_value().value()); return; } @@ -312,7 +312,7 @@ JS::ThrowCompletionOr> SubtleCrypto::generate_ auto result_or_error = normalized_algorithm.methods->generate_key(*normalized_algorithm.parameter, extractable, key_usages); if (result_or_error.is_error()) { - WebIDL::reject_promise(realm, promise, Bindings::dom_exception_to_throw_completion(realm.vm(), result_or_error.release_error()).release_value().value()); + WebIDL::reject_promise(realm, promise, Bindings::exception_to_throw_completion(realm.vm(), result_or_error.release_error()).release_value().value()); return; } auto result = result_or_error.release_value(); @@ -393,7 +393,7 @@ JS::ThrowCompletionOr> SubtleCrypto::import_ke // specified by normalizedAlgorithm using keyData, algorithm, format, extractable and usages. auto maybe_result = normalized_algorithm.methods->import_key(*normalized_algorithm.parameter, format, real_key_data.downcast(), extractable, key_usages); if (maybe_result.is_error()) { - WebIDL::reject_promise(realm, promise, Bindings::dom_exception_to_throw_completion(realm.vm(), maybe_result.release_error()).release_value().value()); + WebIDL::reject_promise(realm, promise, Bindings::exception_to_throw_completion(realm.vm(), maybe_result.release_error()).release_value().value()); return; } auto result = maybe_result.release_value(); @@ -439,7 +439,7 @@ JS::ThrowCompletionOr> SubtleCrypto::export_ke // FIXME: Stash the AlgorithmMethods on the KeyAlgorithm auto normalized_algorithm_or_error = normalize_an_algorithm(realm, algorithm.name(), "exportKey"_string); if (normalized_algorithm_or_error.is_error()) { - WebIDL::reject_promise(realm, promise, Bindings::dom_exception_to_throw_completion(realm.vm(), normalized_algorithm_or_error.release_error()).release_value().value()); + WebIDL::reject_promise(realm, promise, Bindings::exception_to_throw_completion(realm.vm(), normalized_algorithm_or_error.release_error()).release_value().value()); return; } auto normalized_algorithm = normalized_algorithm_or_error.release_value(); @@ -453,7 +453,7 @@ JS::ThrowCompletionOr> SubtleCrypto::export_ke // 7. Let result be the result of performing the export key operation specified by the [[algorithm]] internal slot of key using key and format. auto result_or_error = normalized_algorithm.methods->export_key(format, key); if (result_or_error.is_error()) { - WebIDL::reject_promise(realm, promise, Bindings::dom_exception_to_throw_completion(realm.vm(), result_or_error.release_error()).release_value().value()); + WebIDL::reject_promise(realm, promise, Bindings::exception_to_throw_completion(realm.vm(), result_or_error.release_error()).release_value().value()); return; } @@ -510,7 +510,7 @@ JS::ThrowCompletionOr> SubtleCrypto::sign(Algo // 10. Let result be the result of performing the sign operation specified by normalizedAlgorithm using key and algorithm and with data as message. auto result = normalized_algorithm.methods->sign(*normalized_algorithm.parameter, key, data); if (result.is_error()) { - WebIDL::reject_promise(realm, promise, Bindings::dom_exception_to_throw_completion(realm.vm(), result.release_error()).release_value().value()); + WebIDL::reject_promise(realm, promise, Bindings::exception_to_throw_completion(realm.vm(), result.release_error()).release_value().value()); return; } @@ -574,7 +574,7 @@ JS::ThrowCompletionOr> SubtleCrypto::verify(Al // 11. Let result be the result of performing the verify operation specified by normalizedAlgorithm using key, algorithm and signature and with data as message. auto result = normalized_algorithm.methods->verify(*normalized_algorithm.parameter, key, signature, data); if (result.is_error()) { - WebIDL::reject_promise(realm, promise, Bindings::dom_exception_to_throw_completion(realm.vm(), result.release_error()).release_value().value()); + WebIDL::reject_promise(realm, promise, Bindings::exception_to_throw_completion(realm.vm(), result.release_error()).release_value().value()); return; } @@ -621,7 +621,7 @@ JS::ThrowCompletionOr> SubtleCrypto::derive_bi // 9. Let result be the result of creating an ArrayBuffer containing the result of performing the derive bits operation specified by normalizedAlgorithm using baseKey, algorithm and length. auto result = normalized_algorithm.methods->derive_bits(*normalized_algorithm.parameter, base_key, length); if (result.is_error()) { - WebIDL::reject_promise(realm, promise, Bindings::dom_exception_to_throw_completion(realm.vm(), result.release_error()).release_value().value()); + WebIDL::reject_promise(realm, promise, Bindings::exception_to_throw_completion(realm.vm(), result.release_error()).release_value().value()); return; } @@ -682,7 +682,7 @@ JS::ThrowCompletionOr> SubtleCrypto::derive_ke // 13. Let length be the result of performing the get key length algorithm specified by normalizedDerivedKeyAlgorithmLength using derivedKeyType. auto length_result = normalized_derived_key_algorithm_length.methods->get_key_length(*normalized_derived_key_algorithm_length.parameter); if (length_result.is_error()) { - WebIDL::reject_promise(realm, promise, Bindings::dom_exception_to_throw_completion(realm.vm(), length_result.release_error()).release_value().value()); + WebIDL::reject_promise(realm, promise, Bindings::exception_to_throw_completion(realm.vm(), length_result.release_error()).release_value().value()); return; } @@ -701,14 +701,14 @@ JS::ThrowCompletionOr> SubtleCrypto::derive_ke // 14. Let secret be the result of performing the derive bits operation specified by normalizedAlgorithm using key, algorithm and length. auto secret = normalized_algorithm.methods->derive_bits(*normalized_algorithm.parameter, base_key, length); if (secret.is_error()) { - WebIDL::reject_promise(realm, promise, Bindings::dom_exception_to_throw_completion(realm.vm(), secret.release_error()).release_value().value()); + WebIDL::reject_promise(realm, promise, Bindings::exception_to_throw_completion(realm.vm(), secret.release_error()).release_value().value()); return; } // 15. Let result be the result of performing the import key operation specified by normalizedDerivedKeyAlgorithmImport using "raw" as format, secret as keyData, derivedKeyType as algorithm and using extractable and usages. auto result = normalized_derived_key_algorithm_import.methods->import_key(*normalized_derived_key_algorithm_import.parameter, Bindings::KeyFormat::Raw, secret.release_value()->buffer(), extractable, key_usages); if (result.is_error()) { - WebIDL::reject_promise(realm, promise, Bindings::dom_exception_to_throw_completion(realm.vm(), result.release_error()).release_value().value()); + WebIDL::reject_promise(realm, promise, Bindings::exception_to_throw_completion(realm.vm(), result.release_error()).release_value().value()); return; } diff --git a/Userland/Libraries/LibWeb/Fetch/BodyInit.cpp b/Userland/Libraries/LibWeb/Fetch/BodyInit.cpp index 4ec827ced5ed..5bd4c0eb29c1 100644 --- a/Userland/Libraries/LibWeb/Fetch/BodyInit.cpp +++ b/Userland/Libraries/LibWeb/Fetch/BodyInit.cpp @@ -23,7 +23,7 @@ namespace Web::Fetch { // https://fetch.spec.whatwg.org/#bodyinit-safely-extract -WebIDL::ExceptionOr safely_extract_body(JS::Realm& realm, BodyInitOrReadableBytes const& object) +Infrastructure::BodyWithType safely_extract_body(JS::Realm& realm, BodyInitOrReadableBytes const& object) { // 1. If object is a ReadableStream object, then: if (auto const* stream = object.get_pointer>()) { @@ -32,7 +32,7 @@ WebIDL::ExceptionOr safely_extract_body(JS::Realm& } // 2. Return the result of extracting object. - return extract_body(realm, object); + return MUST(extract_body(realm, object)); } // https://fetch.spec.whatwg.org/#concept-bodyinit-extract @@ -135,7 +135,6 @@ WebIDL::ExceptionOr extract_body(JS::Realm& realm, })); // 11. If source is a byte sequence, then set action to a step that returns source and length to source’s length. - // For now, do it synchronously. if (source.has()) { action = [source = MUST(ByteBuffer::copy(source.get()))]() mutable { return move(source); diff --git a/Userland/Libraries/LibWeb/Fetch/BodyInit.h b/Userland/Libraries/LibWeb/Fetch/BodyInit.h index 851661c94a60..d1e23ded1391 100644 --- a/Userland/Libraries/LibWeb/Fetch/BodyInit.h +++ b/Userland/Libraries/LibWeb/Fetch/BodyInit.h @@ -17,7 +17,7 @@ namespace Web::Fetch { using BodyInit = Variant, JS::Handle, JS::Handle, JS::Handle, JS::Handle, String>; using BodyInitOrReadableBytes = Variant, JS::Handle, JS::Handle, JS::Handle, JS::Handle, String, ReadonlyBytes>; -WebIDL::ExceptionOr safely_extract_body(JS::Realm&, BodyInitOrReadableBytes const&); +Infrastructure::BodyWithType safely_extract_body(JS::Realm&, BodyInitOrReadableBytes const&); WebIDL::ExceptionOr extract_body(JS::Realm&, BodyInitOrReadableBytes const&, bool keepalive = false); } diff --git a/Userland/Libraries/LibWeb/Fetch/FetchMethod.cpp b/Userland/Libraries/LibWeb/Fetch/FetchMethod.cpp index 42679f5e0bf9..ca96d368e80c 100644 --- a/Userland/Libraries/LibWeb/Fetch/FetchMethod.cpp +++ b/Userland/Libraries/LibWeb/Fetch/FetchMethod.cpp @@ -37,7 +37,7 @@ JS::NonnullGCPtr fetch(JS::VM& vm, RequestInfo const& input, Re // as arguments. If this throws an exception, reject p with it and return p. auto exception_or_request_object = Request::construct_impl(realm, input, init); if (exception_or_request_object.is_exception()) { - auto throw_completion = Bindings::dom_exception_to_throw_completion(vm, exception_or_request_object.exception()); + auto throw_completion = Bindings::exception_to_throw_completion(vm, exception_or_request_object.exception()); WebIDL::reject_promise(realm, promise_capability, *throw_completion.value()); return promise_capability; } diff --git a/Userland/Libraries/LibWeb/Fetch/Fetching/FetchedDataReceiver.cpp b/Userland/Libraries/LibWeb/Fetch/Fetching/FetchedDataReceiver.cpp index 8540cb1a4e92..4f5d76f5b5e5 100644 --- a/Userland/Libraries/LibWeb/Fetch/Fetching/FetchedDataReceiver.cpp +++ b/Userland/Libraries/LibWeb/Fetch/Fetching/FetchedDataReceiver.cpp @@ -70,7 +70,7 @@ void FetchedDataReceiver::on_data_received(ReadonlyBytes bytes) // 1. Pull from bytes buffer into stream. if (auto result = Streams::readable_stream_pull_from_bytes(m_stream, move(bytes)); result.is_error()) { - auto throw_completion = Bindings::dom_exception_to_throw_completion(m_stream->vm(), result.release_error()); + auto throw_completion = Bindings::exception_to_throw_completion(m_stream->vm(), result.release_error()); dbgln("FetchedDataReceiver: Stream error pulling bytes"); HTML::report_exception(throw_completion, m_stream->realm()); diff --git a/Userland/Libraries/LibWeb/Fetch/Fetching/Fetching.cpp b/Userland/Libraries/LibWeb/Fetch/Fetching/Fetching.cpp index ae4fc1884180..008839d61513 100644 --- a/Userland/Libraries/LibWeb/Fetch/Fetching/Fetching.cpp +++ b/Userland/Libraries/LibWeb/Fetch/Fetching/Fetching.cpp @@ -121,7 +121,7 @@ WebIDL::ExceptionOr> fetch(JS: // 8. If request’s body is a byte sequence, then set request’s body to request’s body as a body. if (auto const* buffer = request.body().get_pointer()) - request.set_body(TRY(Infrastructure::byte_sequence_as_body(realm, buffer->bytes()))); + request.set_body(Infrastructure::byte_sequence_as_body(realm, buffer->bytes())); // 9. If request’s window is "client", then set request’s window to request’s client, if request’s client’s global // object is a Window object; otherwise "no-window". @@ -567,7 +567,7 @@ WebIDL::ExceptionOr> main_fetch(JS::Realm& realm, Inf } // 3. Let processBody given bytes be these steps: - auto process_body = JS::create_heap_function(vm.heap(), [&realm, request, response, &fetch_params, process_body_error = move(process_body_error)](ByteBuffer bytes) { + auto process_body = JS::create_heap_function(vm.heap(), [&realm, request, response, &fetch_params, process_body_error](ByteBuffer bytes) { // 1. If bytes do not match request’s integrity metadata, then run processBodyError and abort these steps. if (!TRY_OR_IGNORE(SRI::do_bytes_match_metadata_list(bytes, request->integrity_metadata()))) { process_body_error->function()({}); @@ -575,7 +575,7 @@ WebIDL::ExceptionOr> main_fetch(JS::Realm& realm, Inf } // 2. Set response’s body to bytes as a body. - response->set_body(TRY_OR_IGNORE(Infrastructure::byte_sequence_as_body(realm, bytes))); + response->set_body(Infrastructure::byte_sequence_as_body(realm, bytes)); // 3. Run fetch response handover given fetchParams and response. fetch_response_handover(realm, fetch_params, *response); @@ -765,7 +765,7 @@ void fetch_response_handover(JS::Realm& realm, Infrastructure::FetchParams const // 3. If internalResponse's body is null, then queue a fetch task to run processBody given null, with // fetchParams’s task destination. if (!internal_response->body()) { - Infrastructure::queue_fetch_task(fetch_params.controller(), task_destination, JS::create_heap_function(vm.heap(), [process_body = move(process_body)]() { + Infrastructure::queue_fetch_task(fetch_params.controller(), task_destination, JS::create_heap_function(vm.heap(), [process_body]() { process_body->function()({}); })); } @@ -806,7 +806,7 @@ WebIDL::ExceptionOr> scheme_fetch(JS::Realm& r auto header = Infrastructure::Header::from_string_pair("Content-Type"sv, "text/html;charset=utf-8"sv); response->header_list()->append(move(header)); - response->set_body(MUST(Infrastructure::byte_sequence_as_body(realm, ""sv.bytes()))); + response->set_body(Infrastructure::byte_sequence_as_body(realm, ""sv.bytes())); return PendingResponse::create(vm, request, response); } @@ -844,13 +844,13 @@ WebIDL::ExceptionOr> scheme_fetch(JS::Realm& r // 8. If request’s header list does not contain `Range`: if (!request->header_list()->contains("Range"sv.bytes())) { // 1. Let bodyWithType be the result of safely extracting blob. - auto body_with_type = TRY(safely_extract_body(realm, blob->raw_bytes())); + auto body_with_type = safely_extract_body(realm, blob->raw_bytes()); // 2. Set response’s status message to `OK`. response->set_status_message(MUST(ByteBuffer::copy("OK"sv.bytes()))); // 3. Set response’s body to bodyWithType’s body. - response->set_body(move(body_with_type.body)); + response->set_body(body_with_type.body); // 4. Set response’s header list to « (`Content-Length`, serializedFullLength), (`Content-Type`, type) ». auto content_length_header = Infrastructure::Header::from_string_pair("Content-Length"sv, serialized_full_length); @@ -911,7 +911,7 @@ WebIDL::ExceptionOr> scheme_fetch(JS::Realm& r auto header = Infrastructure::Header::from_string_pair("Content-Type"sv, mime_type); response->header_list()->append(move(header)); - response->set_body(TRY(Infrastructure::byte_sequence_as_body(realm, data_url_struct.value().body))); + response->set_body(Infrastructure::byte_sequence_as_body(realm, data_url_struct.value().body)); return PendingResponse::create(vm, request, response); } // -> "file" @@ -1261,8 +1261,8 @@ WebIDL::ExceptionOr> http_redirect_fetch(JS::Realm& r auto converted_source = source.has() ? BodyInitOrReadableBytes { source.get() } : BodyInitOrReadableBytes { source.get>() }; - auto [body, _] = TRY(safely_extract_body(realm, converted_source)); - request->set_body(move(body)); + auto [body, _] = safely_extract_body(realm, converted_source); + request->set_body(body); } // 15. Let timingInfo be fetchParams’s timing info. @@ -2060,8 +2060,8 @@ WebIDL::ExceptionOr> http_network_or_cache_fet auto converted_source = source.has() ? BodyInitOrReadableBytes { source.get() } : BodyInitOrReadableBytes { source.get>() }; - auto [body, _] = TRY_OR_IGNORE(safely_extract_body(realm, converted_source)); - request->set_body(move(body)); + auto [body, _] = safely_extract_body(realm, converted_source); + request->set_body(body); } // 3. If request’s use-URL-credentials flag is unset or isAuthenticationFetch is true, then: diff --git a/Userland/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Bodies.cpp b/Userland/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Bodies.cpp index 0037d3548e9d..5e64eec66a61 100644 --- a/Userland/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Bodies.cpp +++ b/Userland/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Bodies.cpp @@ -1,10 +1,12 @@ /* * Copyright (c) 2022-2023, Linus Groh + * Copyright (c) 2024, Jelle Raaijmakers * * SPDX-License-Identifier: BSD-2-Clause */ #include +#include #include #include #include @@ -12,7 +14,6 @@ #include #include #include -#include namespace Web::Fetch::Infrastructure { @@ -70,38 +71,46 @@ void Body::fully_read(JS::Realm& realm, Web::Fetch::Infrastructure::Body::Proces VERIFY(!task_destination.has()); auto task_destination_object = task_destination.get>(); - // 2. Let successSteps given a byte sequence bytes be to queue a fetch task to run processBody given bytes, with taskDestination. - auto success_steps = [&realm, process_body, task_destination_object = task_destination_object](ReadonlyBytes bytes) -> ErrorOr { - // Make a copy of the bytes, as the source of the bytes may disappear between the time the task is queued and executed. - auto bytes_copy = TRY(ByteBuffer::copy(bytes)); - queue_fetch_task(*task_destination_object, JS::create_heap_function(realm.heap(), [process_body, bytes_copy = move(bytes_copy)]() mutable { - process_body->function()(move(bytes_copy)); + // FIXME: Spec issue: The acquired reader must be released, else the stream remains locked. + // https://github.com/whatwg/fetch/issues/1754 + auto release_reader = [](JS::NonnullGCPtr stream) { + if (auto reader = stream->reader(); reader.has_value()) + Streams::readable_stream_default_reader_release(reader->get>()); + }; + + // 2. Let successSteps given a byte sequence bytes be to queue a fetch task to run processBody + // given bytes, with taskDestination. + auto success_steps = [this, &realm, process_body, task_destination_object, release_reader](ByteBuffer bytes) { + queue_fetch_task(*task_destination_object, JS::create_heap_function(realm.heap(), [process_body, bytes = move(bytes)]() mutable { + process_body->function()(move(bytes)); })); - return {}; + release_reader(m_stream); }; - // 3. Let errorSteps optionally given an exception exception be to queue a fetch task to run processBodyError given exception, with taskDestination. - auto error_steps = [&realm, process_body_error, task_destination_object](JS::GCPtr exception) { + // 3. Let errorSteps optionally given an exception exception be to queue a fetch task to run + // processBodyError given exception, with taskDestination. + auto error_steps = [this, &realm, process_body_error, task_destination_object, release_reader](JS::Value exception) { queue_fetch_task(*task_destination_object, JS::create_heap_function(realm.heap(), [process_body_error, exception]() { process_body_error->function()(exception); })); + release_reader(m_stream); }; - // 4. Let reader be the result of getting a reader for body’s stream. If that threw an exception, then run errorSteps with that exception and return. + // 4. Let reader be the result of getting a reader for body’s stream. If that threw an + // exception, then run errorSteps with that exception and return. + HTML::TemporaryExecutionContext execution_context { realm, HTML::TemporaryExecutionContext::CallbacksEnabled::Yes }; + auto reader_or_exception = Streams::acquire_readable_stream_default_reader(*m_stream); + if (reader_or_exception.is_exception()) { + auto throw_completion = Bindings::exception_to_throw_completion(realm.vm(), reader_or_exception.release_error()); + error_steps(throw_completion.release_value().value()); + return; + } + auto reader = reader_or_exception.release_value(); + // 5. Read all bytes from reader, given successSteps and errorSteps. - // FIXME: Use streams for these steps. - m_source.visit( - [&](ByteBuffer const& byte_buffer) { - if (auto result = success_steps(byte_buffer); result.is_error()) - error_steps(WebIDL::UnknownError::create(realm, "Out-of-memory"_string)); - }, - [&](JS::Handle const& blob) { - if (auto result = success_steps(blob->raw_bytes()); result.is_error()) - error_steps(WebIDL::UnknownError::create(realm, "Out-of-memory"_string)); - }, - [&](Empty) { - error_steps(WebIDL::DOMException::create(realm, "DOMException"_fly_string, "Reading from Blob, FormData or null source is not yet implemented"_string)); - }); + reader->read_all_bytes( + JS::create_heap_function(realm.heap(), move(success_steps)), + JS::create_heap_function(realm.heap(), move(error_steps))); } // https://fetch.spec.whatwg.org/#body-incrementally-read @@ -123,7 +132,6 @@ void Body::incrementally_read(ProcessBodyChunkCallback process_body_chunk, Proce // https://fetch.spec.whatwg.org/#incrementally-read-loop void Body::incrementally_read_loop(Streams::ReadableStreamDefaultReader& reader, JS::NonnullGCPtr task_destination, ProcessBodyChunkCallback process_body_chunk, ProcessEndOfBodyCallback process_end_of_body, ProcessBodyErrorCallback process_body_error) - { auto& realm = reader.realm(); // 1. Let readRequest be the following read request: @@ -134,10 +142,10 @@ void Body::incrementally_read_loop(Streams::ReadableStreamDefaultReader& reader, } // https://fetch.spec.whatwg.org/#byte-sequence-as-a-body -WebIDL::ExceptionOr> byte_sequence_as_body(JS::Realm& realm, ReadonlyBytes bytes) +JS::NonnullGCPtr byte_sequence_as_body(JS::Realm& realm, ReadonlyBytes bytes) { // To get a byte sequence bytes as a body, return the body of the result of safely extracting bytes. - auto [body, _] = TRY(safely_extract_body(realm, bytes)); + auto [body, _] = safely_extract_body(realm, bytes); return body; } diff --git a/Userland/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Bodies.h b/Userland/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Bodies.h index 9a5f5be4d4fe..29dd023311b4 100644 --- a/Userland/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Bodies.h +++ b/Userland/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Bodies.h @@ -76,6 +76,6 @@ struct BodyWithType { Optional type; }; -WebIDL::ExceptionOr> byte_sequence_as_body(JS::Realm&, ReadonlyBytes); +JS::NonnullGCPtr byte_sequence_as_body(JS::Realm&, ReadonlyBytes); } diff --git a/Userland/Libraries/LibWeb/HTML/Navigable.cpp b/Userland/Libraries/LibWeb/HTML/Navigable.cpp index deafbed0d772..d371f0de1210 100644 --- a/Userland/Libraries/LibWeb/HTML/Navigable.cpp +++ b/Userland/Libraries/LibWeb/HTML/Navigable.cpp @@ -612,7 +612,7 @@ static JS::GCPtr attempt_to_create_a_non_fetch_scheme_document(No } // https://html.spec.whatwg.org/multipage/browsing-the-web.html#create-navigation-params-from-a-srcdoc-resource -static WebIDL::ExceptionOr> create_navigation_params_from_a_srcdoc_resource(JS::GCPtr entry, JS::GCPtr navigable, TargetSnapshotParams const& target_snapshot_params, Optional navigation_id) +static JS::NonnullGCPtr create_navigation_params_from_a_srcdoc_resource(JS::GCPtr entry, JS::GCPtr navigable, TargetSnapshotParams const& target_snapshot_params, Optional navigation_id) { auto& vm = navigable->vm(); VERIFY(navigable->active_window()); @@ -632,7 +632,7 @@ static WebIDL::ExceptionOr> create_navigation auto header = Fetch::Infrastructure::Header::from_string_pair("Content-Type"sv, "text/html"sv); response->header_list()->append(move(header)); - response->set_body(TRY(Fetch::Infrastructure::byte_sequence_as_body(realm, document_resource.get().bytes()))); + response->set_body(Fetch::Infrastructure::byte_sequence_as_body(realm, document_resource.get().bytes())); // 3. Let responseOrigin be the result of determining the origin given response's URL, targetSnapshotParams's sandboxing flags, and entry's document state's origin. auto response_origin = determine_the_origin(response->url(), target_snapshot_params.sandboxing_flags, entry->document_state()->origin()); @@ -1094,7 +1094,7 @@ WebIDL::ExceptionOr Navigable::populate_session_history_entry_document( // of creating navigation params from a srcdoc resource given entry, navigable, // targetSnapshotParams, navigationId, and navTimingType. if (document_resource.has()) { - navigation_params = TRY(create_navigation_params_from_a_srcdoc_resource(entry, this, target_snapshot_params, navigation_id)); + navigation_params = create_navigation_params_from_a_srcdoc_resource(entry, this, target_snapshot_params, navigation_id); } // 2. Otherwise, if all of the following are true: // - entry's URL's scheme is a fetch scheme; and @@ -1357,7 +1357,7 @@ WebIDL::ExceptionOr Navigable::navigate(NavigateParams params) // 1. Queue a global task on the navigation and traversal task source given navigable's active window to navigate to a javascript: URL given navigable, url, historyHandling, initiatorOriginSnapshot, and cspNavigationType. VERIFY(active_window()); queue_global_task(Task::Source::NavigationAndTraversal, *active_window(), JS::create_heap_function(heap(), [this, url, history_handling, initiator_origin_snapshot, csp_navigation_type, navigation_id] { - (void)navigate_to_a_javascript_url(url, to_history_handling_behavior(history_handling), initiator_origin_snapshot, csp_navigation_type, navigation_id); + navigate_to_a_javascript_url(url, to_history_handling_behavior(history_handling), initiator_origin_snapshot, csp_navigation_type, navigation_id); })); // 2. Return. @@ -1584,7 +1584,7 @@ WebIDL::ExceptionOr Navigable::navigate_to_a_fragment(URL::URL const& url, // https://html.spec.whatwg.org/multipage/browsing-the-web.html#evaluate-a-javascript:-url // https://whatpr.org/html/9893/browsing-the-web.html#evaluate-a-javascript:-url -WebIDL::ExceptionOr> Navigable::evaluate_javascript_url(URL::URL const& url, URL::Origin const& new_document_origin, String navigation_id) +JS::GCPtr Navigable::evaluate_javascript_url(URL::URL const& url, URL::Origin const& new_document_origin, String navigation_id) { auto& vm = this->vm(); VERIFY(active_window()); @@ -1632,7 +1632,7 @@ WebIDL::ExceptionOr> Navigable::evaluate_javascript_url auto header = Fetch::Infrastructure::Header::from_string_pair("Content-Type"sv, "text/html"sv); response->header_list()->append(move(header)); - response->set_body(TRY(Fetch::Infrastructure::byte_sequence_as_body(realm, result.bytes()))); + response->set_body(Fetch::Infrastructure::byte_sequence_as_body(realm, result.bytes())); // 12. Let policyContainer be targetNavigable's active document's policy container. auto const& policy_container = active_document()->policy_container(); @@ -1688,7 +1688,7 @@ WebIDL::ExceptionOr> Navigable::evaluate_javascript_url } // https://html.spec.whatwg.org/multipage/browsing-the-web.html#navigate-to-a-javascript:-url -WebIDL::ExceptionOr Navigable::navigate_to_a_javascript_url(URL::URL const& url, HistoryHandlingBehavior history_handling, URL::Origin const& initiator_origin, CSPNavigationType csp_navigation_type, String navigation_id) +void Navigable::navigate_to_a_javascript_url(URL::URL const& url, HistoryHandlingBehavior history_handling, URL::Origin const& initiator_origin, CSPNavigationType csp_navigation_type, String navigation_id) { // 1. Assert: historyHandling is "replace". VERIFY(history_handling == HistoryHandlingBehavior::Replace); @@ -1698,7 +1698,7 @@ WebIDL::ExceptionOr Navigable::navigate_to_a_javascript_url(URL::URL const // 3. If initiatorOrigin is not same origin-domain with targetNavigable's active document's origin, then return. if (!initiator_origin.is_same_origin_domain(active_document()->origin())) - return {}; + return; // FIXME: 4. Let request be a new request whose URL is url. @@ -1706,12 +1706,12 @@ WebIDL::ExceptionOr Navigable::navigate_to_a_javascript_url(URL::URL const (void)csp_navigation_type; // 6. Let newDocument be the result of evaluating a javascript: URL given targetNavigable, url, and initiatorOrigin. - auto new_document = TRY(evaluate_javascript_url(url, initiator_origin, navigation_id)); + auto new_document = evaluate_javascript_url(url, initiator_origin, navigation_id); // 7. If newDocument is null, then return. if (!new_document) { // NOTE: In this case, some JavaScript code was executed, but no new Document was created, so we will not perform a navigation. - return {}; + return; } // 8. Assert: initiatorOrigin is newDocument's origin. @@ -1756,8 +1756,6 @@ WebIDL::ExceptionOr Navigable::navigate_to_a_javascript_url(URL::URL const traversable_navigable()->append_session_history_traversal_steps(JS::create_heap_function(heap(), [this, history_entry, history_handling, navigation_id] { finalize_a_cross_document_navigation(*this, history_handling, history_entry); })); - - return {}; } // https://html.spec.whatwg.org/multipage/browsing-the-web.html#reload diff --git a/Userland/Libraries/LibWeb/HTML/Navigable.h b/Userland/Libraries/LibWeb/HTML/Navigable.h index 5d65b99ea9e2..d299d18f009a 100644 --- a/Userland/Libraries/LibWeb/HTML/Navigable.h +++ b/Userland/Libraries/LibWeb/HTML/Navigable.h @@ -154,8 +154,8 @@ class Navigable : public JS::Cell { WebIDL::ExceptionOr navigate_to_a_fragment(URL::URL const&, HistoryHandlingBehavior, UserNavigationInvolvement, Optional navigation_api_state, String navigation_id); - WebIDL::ExceptionOr> evaluate_javascript_url(URL::URL const&, URL::Origin const& new_document_origin, String navigation_id); - WebIDL::ExceptionOr navigate_to_a_javascript_url(URL::URL const&, HistoryHandlingBehavior, URL::Origin const& initiator_origin, CSPNavigationType csp_navigation_type, String navigation_id); + JS::GCPtr evaluate_javascript_url(URL::URL const&, URL::Origin const& new_document_origin, String navigation_id); + void navigate_to_a_javascript_url(URL::URL const&, HistoryHandlingBehavior, URL::Origin const& initiator_origin, CSPNavigationType csp_navigation_type, String navigation_id); bool allowed_by_sandboxing_to_navigate(Navigable const& target, SourceSnapshotParams const&); diff --git a/Userland/Libraries/LibWeb/HTML/Parser/HTMLParser.cpp b/Userland/Libraries/LibWeb/HTML/Parser/HTMLParser.cpp index 6f6f9ac19958..56fe324f9c67 100644 --- a/Userland/Libraries/LibWeb/HTML/Parser/HTMLParser.cpp +++ b/Userland/Libraries/LibWeb/HTML/Parser/HTMLParser.cpp @@ -1029,7 +1029,7 @@ void HTMLParser::handle_in_head(HTMLToken& token) // If an exception is thrown, then catch it, report the exception, insert an element at the adjusted insertion location with template, and return. auto result = declarative_shadow_host_element.attach_a_shadow_root(mode, clonable, serializable, delegates_focus, Bindings::SlotAssignmentMode::Named); if (result.is_error()) { - report_exception(Bindings::dom_exception_to_throw_completion(vm(), result.release_error()), realm()); + report_exception(Bindings::exception_to_throw_completion(vm(), result.release_error()), realm()); insert_an_element_at_the_adjusted_insertion_location(template_); return; } diff --git a/Userland/Libraries/LibWeb/HTML/Scripting/ImportMapParseResult.cpp b/Userland/Libraries/LibWeb/HTML/Scripting/ImportMapParseResult.cpp index 132cb0c873fb..318cfff52d95 100644 --- a/Userland/Libraries/LibWeb/HTML/Scripting/ImportMapParseResult.cpp +++ b/Userland/Libraries/LibWeb/HTML/Scripting/ImportMapParseResult.cpp @@ -68,7 +68,7 @@ void ImportMapParseResult::register_import_map(Window& global) { // 1. If result's error to rethrow is not null, then report the exception given by result's error to rethrow and return. if (m_error_to_rethrow.has_value()) { - auto completion = Web::Bindings::dom_exception_to_throw_completion(global.vm(), m_error_to_rethrow.value()); + auto completion = Web::Bindings::exception_to_throw_completion(global.vm(), m_error_to_rethrow.value()); HTML::report_exception(completion, global.realm()); return; } diff --git a/Userland/Libraries/LibWeb/Streams/AbstractOperations.cpp b/Userland/Libraries/LibWeb/Streams/AbstractOperations.cpp index ebab92f276be..9a1348efe5b3 100644 --- a/Userland/Libraries/LibWeb/Streams/AbstractOperations.cpp +++ b/Userland/Libraries/LibWeb/Streams/AbstractOperations.cpp @@ -315,16 +315,18 @@ JS::NonnullGCPtr readable_stream_pipe_to(ReadableStream& source WebIDL::resolve_promise(realm, promise, JS::js_undefined()); }); - auto success_steps = JS::create_heap_function(realm.heap(), [promise, &realm, writer](ByteBuffer) { + auto success_steps = JS::create_heap_function(realm.heap(), [promise, &realm, reader, writer](ByteBuffer) { // Make sure we close the acquired writer. WebIDL::resolve_promise(realm, writable_stream_default_writer_close(*writer), JS::js_undefined()); + readable_stream_default_reader_release(*reader); WebIDL::resolve_promise(realm, promise, JS::js_undefined()); }); - auto failure_steps = JS::create_heap_function(realm.heap(), [promise, &realm, writer](JS::Value error) { + auto failure_steps = JS::create_heap_function(realm.heap(), [promise, &realm, reader, writer](JS::Value error) { // Make sure we close the acquired writer. WebIDL::resolve_promise(realm, writable_stream_default_writer_close(*writer), JS::js_undefined()); + readable_stream_default_reader_release(*reader); WebIDL::reject_promise(realm, promise, error); }); @@ -421,7 +423,7 @@ class DefaultStreamTeeReadRequest final : public ReadRequest { // 2. If cloneResult is an abrupt completion, if (clone_result.is_exception()) { - auto completion = Bindings::dom_exception_to_throw_completion(m_realm->vm(), clone_result.release_error()); + auto completion = Bindings::exception_to_throw_completion(m_realm->vm(), clone_result.release_error()); // 1. Perform ! ReadableStreamDefaultControllerError(branch1.[[controller]], cloneResult.[[Value]]). readable_stream_default_controller_error(controller1, completion.value().value()); @@ -709,7 +711,7 @@ class ByteStreamTeeDefaultReadRequest final : public ReadRequest { { // 1. Queue a microtask to perform the following steps: HTML::queue_a_microtask(nullptr, JS::create_heap_function(m_realm->heap(), [this, chunk]() mutable { - HTML::TemporaryExecutionContext execution_context { m_realm }; + HTML::TemporaryExecutionContext execution_context { m_realm, HTML::TemporaryExecutionContext::CallbacksEnabled::Yes }; auto controller1 = m_params->branch1->controller()->get>(); auto controller2 = m_params->branch2->controller()->get>(); @@ -732,7 +734,7 @@ class ByteStreamTeeDefaultReadRequest final : public ReadRequest { // 2. If cloneResult is an abrupt completion, if (clone_result.is_exception()) { - auto completion = Bindings::dom_exception_to_throw_completion(m_realm->vm(), clone_result.release_error()); + auto completion = Bindings::exception_to_throw_completion(m_realm->vm(), clone_result.release_error()); // 1. Perform ! ReadableByteStreamControllerError(branch1.[[controller]], cloneResult.[[Value]]). readable_byte_stream_controller_error(controller1, completion.value().value()); @@ -872,7 +874,7 @@ class ByteStreamTeeBYOBReadRequest final : public ReadIntoRequest { // 1. Queue a microtask to perform the following steps: HTML::queue_a_microtask(nullptr, JS::create_heap_function(m_realm->heap(), [this, chunk = chunk_view]() { - HTML::TemporaryExecutionContext execution_context { m_realm }; + HTML::TemporaryExecutionContext execution_context { m_realm, HTML::TemporaryExecutionContext::CallbacksEnabled::Yes }; auto byob_controller = m_byob_branch->controller()->get>(); auto other_controller = m_other_branch->controller()->get>(); @@ -896,7 +898,7 @@ class ByteStreamTeeBYOBReadRequest final : public ReadIntoRequest { // 2. If cloneResult is an abrupt completion, if (clone_result.is_exception()) { - auto completion = Bindings::dom_exception_to_throw_completion(m_realm->vm(), clone_result.release_error()); + auto completion = Bindings::exception_to_throw_completion(m_realm->vm(), clone_result.release_error()); // 1. Perform ! ReadableByteStreamControllerError(byobBranch.[[controller]], cloneResult.[[Value]]). readable_byte_stream_controller_error(byob_controller, completion.value().value()); @@ -1849,7 +1851,7 @@ void readable_byte_stream_controller_pull_into(ReadableByteStreamController& con // 8. If bufferResult is an abrupt completion, if (buffer_result.is_exception()) { // 1. Perform readIntoRequest’s error steps, given bufferResult.[[Value]]. - auto throw_completion = Bindings::dom_exception_to_throw_completion(vm, buffer_result.exception()); + auto throw_completion = Bindings::exception_to_throw_completion(vm, buffer_result.exception()); read_into_request.on_error(*throw_completion.release_value()); // 2. Return. @@ -4804,7 +4806,7 @@ void set_up_transform_stream_default_controller_from_transformer(TransformStream // 2. If result is an abrupt completion, return a promise rejected with result.[[Value]]. if (result.is_error()) { - auto throw_completion = Bindings::dom_exception_to_throw_completion(vm, result.exception()); + auto throw_completion = Bindings::exception_to_throw_completion(vm, result.exception()); return WebIDL::create_rejected_promise(realm, *throw_completion.release_value()); } @@ -4892,7 +4894,7 @@ WebIDL::ExceptionOr transform_stream_default_controller_enqueue(TransformS // 5. If enqueueResult is an abrupt completion, if (enqueue_result.is_error()) { - auto throw_completion = Bindings::dom_exception_to_throw_completion(vm, enqueue_result.exception()); + auto throw_completion = Bindings::exception_to_throw_completion(vm, enqueue_result.exception()); // 1. Perform ! TransformStreamErrorWritableAndUnblockWrite(stream, enqueueResult.[[Value]]). transform_stream_error_writable_and_unblock_write(*stream, throw_completion.value().value()); diff --git a/Userland/Libraries/LibWeb/WebAssembly/WebAssembly.cpp b/Userland/Libraries/LibWeb/WebAssembly/WebAssembly.cpp index f2f52fed853d..6401bf1ac7b7 100644 --- a/Userland/Libraries/LibWeb/WebAssembly/WebAssembly.cpp +++ b/Userland/Libraries/LibWeb/WebAssembly/WebAssembly.cpp @@ -701,7 +701,7 @@ JS::NonnullGCPtr compile_potential_webassembly_response(JS::VM& // 8. Consume response’s body as an ArrayBuffer, and let bodyPromise be the result. auto body_promise_or_error = response_object.array_buffer(); if (body_promise_or_error.is_error()) { - auto throw_completion = Bindings::dom_exception_to_throw_completion(realm.vm(), body_promise_or_error.release_error()); + auto throw_completion = Bindings::exception_to_throw_completion(realm.vm(), body_promise_or_error.release_error()); WebIDL::reject_promise(realm, return_value, *throw_completion.value()); return JS::js_undefined(); } diff --git a/Userland/Libraries/LibWeb/WebIDL/Promise.cpp b/Userland/Libraries/LibWeb/WebIDL/Promise.cpp index 25de081d2053..f1b142c9c7d2 100644 --- a/Userland/Libraries/LibWeb/WebIDL/Promise.cpp +++ b/Userland/Libraries/LibWeb/WebIDL/Promise.cpp @@ -293,7 +293,7 @@ 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 throw_completion = Bindings::exception_to_throw_completion(realm.vm(), move(exception)); return WebIDL::create_rejected_promise(realm, *throw_completion.value()); } diff --git a/Userland/Libraries/LibWeb/XHR/XMLHttpRequest.cpp b/Userland/Libraries/LibWeb/XHR/XMLHttpRequest.cpp index 9f4d73448940..062f81409c60 100644 --- a/Userland/Libraries/LibWeb/XHR/XMLHttpRequest.cpp +++ b/Userland/Libraries/LibWeb/XHR/XMLHttpRequest.cpp @@ -574,15 +574,15 @@ WebIDL::ExceptionOr XMLHttpRequest::send(Optionalhas>()) { auto string_serialized_document = TRY(body->get>().cell()->serialize_fragment(DOMParsing::RequireWellFormed::No)); - m_request_body = TRY(Fetch::Infrastructure::byte_sequence_as_body(realm, string_serialized_document.bytes())); + m_request_body = Fetch::Infrastructure::byte_sequence_as_body(realm, string_serialized_document.bytes()); } // 3. Otherwise: else { // 1. Let bodyWithType be the result of safely extracting body. - auto body_with_type = TRY(Fetch::safely_extract_body(realm, body->downcast())); + auto body_with_type = Fetch::safely_extract_body(realm, body->downcast()); // 2. Set this’s request body to bodyWithType’s body. - m_request_body = move(body_with_type.body); + m_request_body = body_with_type.body; // 3. Set extractedContentType to bodyWithType’s type. extracted_content_type = move(body_with_type.type);