From e6d1123ce897f1ae3b12861a8019c17e3a66fed8 Mon Sep 17 00:00:00 2001 From: Shannon Booth Date: Thu, 31 Oct 2024 06:12:14 +1300 Subject: [PATCH] LibWeb: Make ResourceLoader callbacks HeapFunctions --- .../LibWeb/Fetch/Fetching/Fetching.cpp | 27 +++--- .../LibWeb/Loader/ResourceLoader.cpp | 84 +++++++++---------- .../Libraries/LibWeb/Loader/ResourceLoader.h | 16 ++-- 3 files changed, 65 insertions(+), 62 deletions(-) diff --git a/Userland/Libraries/LibWeb/Fetch/Fetching/Fetching.cpp b/Userland/Libraries/LibWeb/Fetch/Fetching/Fetching.cpp index d385980f2e9..aa428d39eb2 100644 --- a/Userland/Libraries/LibWeb/Fetch/Fetching/Fetching.cpp +++ b/Userland/Libraries/LibWeb/Fetch/Fetching/Fetching.cpp @@ -2260,7 +2260,8 @@ WebIDL::ExceptionOr> nonstandard_resource_load // 13. Set up stream with byte reading support with pullAlgorithm set to pullAlgorithm, cancelAlgorithm set to cancelAlgorithm. Streams::set_up_readable_stream_controller_with_byte_reading_support(stream, pull_algorithm, cancel_algorithm); - auto on_headers_received = [&vm, request, pending_response, stream](auto const& response_headers, Optional status_code) { + auto on_headers_received = JS::create_heap_function(vm.heap(), [&vm, request, pending_response, stream](HTTP::HeaderMap const& response_headers, Optional status_code) { + (void)request; if (pending_response->is_resolved()) { // RequestServer will send us the response headers twice, the second time being for HTTP trailers. This // fetch algorithm is not interested in trailers, so just drop them here. @@ -2290,11 +2291,11 @@ WebIDL::ExceptionOr> nonstandard_resource_load // 17. Return response. // NOTE: Typically response’s body’s stream is still being enqueued to after returning. pending_response->resolve(response); - }; + }); // 16. Run these steps in parallel: // FIXME: 1. Run these steps, but abort when fetchParams is canceled: - auto on_data_received = [fetched_data_receiver](auto bytes) { + auto on_data_received = JS::create_heap_function(vm.heap(), [fetched_data_receiver](ReadonlyBytes bytes) { // 1. If one or more bytes have been transmitted from response’s message body, then: if (!bytes.is_empty()) { // 1. Let bytes be the transmitted bytes. @@ -2311,9 +2312,9 @@ WebIDL::ExceptionOr> nonstandard_resource_load // FIXME: 8. If the size of buffer is larger than an upper limit chosen by the user agent, ask the user agent // to suspend the ongoing fetch. } - }; + }); - auto on_complete = [&vm, &realm, pending_response, stream](auto success, auto error_message) { + auto on_complete = JS::create_heap_function(vm.heap(), [&vm, &realm, pending_response, stream](bool success, Optional error_message) { HTML::TemporaryExecutionContext execution_context { Bindings::host_defined_environment_settings_object(realm), HTML::TemporaryExecutionContext::CallbacksEnabled::Yes }; // 16.1.1.2. Otherwise, if the bytes transmission for response’s message body is done normally and stream is readable, @@ -2332,11 +2333,12 @@ WebIDL::ExceptionOr> nonstandard_resource_load if (!pending_response->is_resolved()) pending_response->resolve(Infrastructure::Response::network_error(vm, error)); } - }; + }); - ResourceLoader::the().load_unbuffered(load_request, move(on_headers_received), move(on_data_received), move(on_complete)); + ResourceLoader::the().load_unbuffered(load_request, on_headers_received, on_data_received, on_complete); } else { - auto on_load_success = [&realm, &vm, request, pending_response](auto data, auto& response_headers, auto status_code) { + auto on_load_success = JS::create_heap_function(vm.heap(), [&realm, &vm, request, pending_response](ReadonlyBytes data, HTTP::HeaderMap const& response_headers, Optional status_code) { + (void)request; dbgln_if(WEB_FETCH_DEBUG, "Fetch: ResourceLoader load for '{}' complete", request->url()); if constexpr (WEB_FETCH_DEBUG) log_response(status_code, response_headers, data); @@ -2350,9 +2352,10 @@ WebIDL::ExceptionOr> nonstandard_resource_load } // FIXME: Set response status message pending_response->resolve(response); - }; + }); - auto on_load_error = [&realm, &vm, request, pending_response](auto& error, auto status_code, auto data, auto& response_headers) { + auto on_load_error = JS::create_heap_function(vm.heap(), [&realm, &vm, request, pending_response](ByteString const& error, Optional status_code, ReadonlyBytes data, HTTP::HeaderMap const& response_headers) { + (void)request; dbgln_if(WEB_FETCH_DEBUG, "Fetch: ResourceLoader load for '{}' failed: {} (status {})", request->url(), error, status_code.value_or(0)); if constexpr (WEB_FETCH_DEBUG) log_response(status_code, response_headers, data); @@ -2372,9 +2375,9 @@ WebIDL::ExceptionOr> nonstandard_resource_load // FIXME: Set response status message } pending_response->resolve(response); - }; + }); - ResourceLoader::the().load(load_request, move(on_load_success), move(on_load_error)); + ResourceLoader::the().load(load_request, on_load_success, on_load_error); } return pending_response; diff --git a/Userland/Libraries/LibWeb/Loader/ResourceLoader.cpp b/Userland/Libraries/LibWeb/Loader/ResourceLoader.cpp index ba772873ad4..1a2871f6d71 100644 --- a/Userland/Libraries/LibWeb/Loader/ResourceLoader.cpp +++ b/Userland/Libraries/LibWeb/Loader/ResourceLoader.cpp @@ -108,12 +108,12 @@ RefPtr ResourceLoader::load_resource(Resource::Type type, LoadRequest& load( request, - [=](auto data, auto& headers, auto status_code) { + JS::create_heap_function(m_heap, [=](ReadonlyBytes data, HTTP::HeaderMap const& headers, Optional status_code) { const_cast(*resource).did_load({}, data, headers, status_code); - }, - [=](auto& error, auto status_code, auto data, auto& headers) { + }), + JS::create_heap_function(m_heap, [=](ByteString const& error, Optional status_code, ReadonlyBytes data, HTTP::HeaderMap const& headers) { const_cast(*resource).did_fail({}, error, data, headers, status_code); - }); + })); return resource; } @@ -230,7 +230,7 @@ static bool should_block_request(LoadRequest const& request) return false; } -void ResourceLoader::load(LoadRequest& request, SuccessCallback success_callback, ErrorCallback error_callback, Optional timeout, TimeoutCallback timeout_callback) +void ResourceLoader::load(LoadRequest& request, JS::Handle success_callback, JS::Handle error_callback, Optional timeout, JS::Handle timeout_callback) { auto const& url = request.url(); @@ -238,23 +238,23 @@ void ResourceLoader::load(LoadRequest& request, SuccessCallback success_callback request.start_timer(); if (should_block_request(request)) { - error_callback("Request was blocked", {}, {}, {}); + error_callback->function()("Request was blocked", {}, {}, {}); return; } - auto respond_directory_page = [](LoadRequest const& request, URL::URL const& url, SuccessCallback const& success_callback, ErrorCallback const& error_callback) { + auto respond_directory_page = [](LoadRequest const& request, URL::URL const& url, JS::Handle success_callback, JS::Handle error_callback) { auto maybe_response = load_file_directory_page(url); if (maybe_response.is_error()) { log_failure(request, maybe_response.error()); if (error_callback) - error_callback(ByteString::formatted("{}", maybe_response.error()), 500u, {}, {}); + error_callback->function()(ByteString::formatted("{}", maybe_response.error()), 500u, {}, {}); return; } log_success(request); HTTP::HeaderMap response_headers; response_headers.set("Content-Type"sv, "text/html"sv); - success_callback(maybe_response.release_value().bytes(), response_headers, {}); + success_callback->function()(maybe_response.release_value().bytes(), response_headers, {}); }; if (url.scheme() == "about") { @@ -266,7 +266,7 @@ void ResourceLoader::load(LoadRequest& request, SuccessCallback success_callback // About version page if (url.path_segment_at_index(0) == "version") { - success_callback(MUST(load_about_version_page()).bytes(), response_headers, {}); + success_callback->function()(MUST(load_about_version_page()).bytes(), response_headers, {}); return; } @@ -274,12 +274,12 @@ void ResourceLoader::load(LoadRequest& request, SuccessCallback success_callback auto resource = Core::Resource::load_from_uri(MUST(String::formatted("resource://ladybird/{}.html", url.path_segment_at_index(0)))); if (!resource.is_error()) { auto data = resource.value()->data(); - success_callback(data, response_headers, {}); + success_callback->function()(data, response_headers, {}); return; } - Platform::EventLoopPlugin::the().deferred_invoke(JS::create_heap_function(m_heap, [success_callback = move(success_callback), response_headers = move(response_headers)] { - success_callback(ByteString::empty().to_byte_buffer(), response_headers, {}); + Platform::EventLoopPlugin::the().deferred_invoke(JS::create_heap_function(m_heap, [success_callback, response_headers = move(response_headers)] { + success_callback->function()(ByteString::empty().to_byte_buffer(), response_headers, {}); })); return; } @@ -289,7 +289,7 @@ void ResourceLoader::load(LoadRequest& request, SuccessCallback success_callback if (data_url_or_error.is_error()) { auto error_message = data_url_or_error.error().string_literal(); log_failure(request, error_message); - error_callback(error_message, {}, {}, {}); + error_callback->function()(error_message, {}, {}, {}); return; } auto data_url = data_url_or_error.release_value(); @@ -303,8 +303,8 @@ void ResourceLoader::load(LoadRequest& request, SuccessCallback success_callback log_success(request); - Platform::EventLoopPlugin::the().deferred_invoke(JS::create_heap_function(m_heap, [data = move(data_url.body), response_headers = move(response_headers), success_callback = move(success_callback)] { - success_callback(data, response_headers, {}); + Platform::EventLoopPlugin::the().deferred_invoke(JS::create_heap_function(m_heap, [data = move(data_url.body), response_headers = move(response_headers), success_callback] { + success_callback->function()(data, response_headers, {}); })); return; } @@ -314,7 +314,7 @@ void ResourceLoader::load(LoadRequest& request, SuccessCallback success_callback if (resource.is_error()) { log_failure(request, resource.error()); if (error_callback) - error_callback(ByteString::formatted("{}", resource.error()), {}, {}, {}); + error_callback->function()(ByteString::formatted("{}", resource.error()), {}, {}, {}); return; } @@ -328,7 +328,7 @@ void ResourceLoader::load(LoadRequest& request, SuccessCallback success_callback auto response_headers = response_headers_for_file(URL::percent_decode(url.serialize_path()), resource.value()->modified_time()); log_success(request); - success_callback(data, response_headers, {}); + success_callback->function()(data, response_headers, {}); return; } @@ -342,7 +342,7 @@ void ResourceLoader::load(LoadRequest& request, SuccessCallback success_callback return; } - FileRequest file_request(URL::percent_decode(url.serialize_path()), [this, success_callback = move(success_callback), error_callback = move(error_callback), request, respond_directory_page](ErrorOr file_or_error) { + FileRequest file_request(URL::percent_decode(url.serialize_path()), [this, success_callback, error_callback, request, respond_directory_page](ErrorOr file_or_error) { --m_pending_loads; if (on_load_counter_change) on_load_counter_change(); @@ -350,7 +350,7 @@ void ResourceLoader::load(LoadRequest& request, SuccessCallback success_callback if (file_or_error.is_error()) { log_failure(request, file_or_error.error()); if (error_callback) - error_callback(ByteString::formatted("{}", file_or_error.error()), {}, {}, {}); + error_callback->function()(ByteString::formatted("{}", file_or_error.error()), {}, {}, {}); return; } @@ -367,7 +367,7 @@ void ResourceLoader::load(LoadRequest& request, SuccessCallback success_callback if (st_or_error.is_error()) { log_failure(request, st_or_error.error()); if (error_callback) - error_callback(ByteString::formatted("{}", st_or_error.error()), {}, {}, {}); + error_callback->function()(ByteString::formatted("{}", st_or_error.error()), {}, {}, {}); return; } @@ -376,7 +376,7 @@ void ResourceLoader::load(LoadRequest& request, SuccessCallback success_callback if (maybe_file.is_error()) { log_failure(request, maybe_file.error()); if (error_callback) - error_callback(ByteString::formatted("{}", maybe_file.error()), {}, {}, {}); + error_callback->function()(ByteString::formatted("{}", maybe_file.error()), {}, {}, {}); return; } @@ -385,7 +385,7 @@ void ResourceLoader::load(LoadRequest& request, SuccessCallback success_callback if (maybe_data.is_error()) { log_failure(request, maybe_data.error()); if (error_callback) - error_callback(ByteString::formatted("{}", maybe_data.error()), {}, {}, {}); + error_callback->function()(ByteString::formatted("{}", maybe_data.error()), {}, {}, {}); return; } @@ -393,7 +393,7 @@ void ResourceLoader::load(LoadRequest& request, SuccessCallback success_callback auto response_headers = response_headers_for_file(URL::percent_decode(request.url().serialize_path()), st_or_error.value().st_mtime); log_success(request); - success_callback(data, response_headers, {}); + success_callback->function()(data, response_headers, {}); }); (*m_page)->client().request_file(move(file_request)); @@ -409,22 +409,22 @@ void ResourceLoader::load(LoadRequest& request, SuccessCallback success_callback auto protocol_request = start_network_request(request); if (!protocol_request) { if (error_callback) - error_callback("Failed to start network request"sv, {}, {}, {}); + error_callback->function()("Failed to start network request"sv, {}, {}, {}); return; } if (timeout.has_value() && timeout.value() > 0) { auto timer = Platform::Timer::create_single_shot(m_heap, timeout.value(), nullptr); - timer->on_timeout = JS::create_heap_function(m_heap, [timer = JS::make_handle(timer), protocol_request, timeout_callback = move(timeout_callback)] { + timer->on_timeout = JS::create_heap_function(m_heap, [timer = JS::make_handle(timer), protocol_request, timeout_callback] { (void)timer; protocol_request->stop(); if (timeout_callback) - timeout_callback(); + timeout_callback->function()(); }); timer->start(); } - auto on_buffered_request_finished = [this, success_callback = move(success_callback), error_callback = move(error_callback), request, &protocol_request = *protocol_request](auto, auto const& network_error, auto& response_headers, auto status_code, ReadonlyBytes payload) mutable { + auto on_buffered_request_finished = [this, success_callback, error_callback, request, &protocol_request = *protocol_request](auto, auto const& network_error, auto& response_headers, auto status_code, ReadonlyBytes payload) mutable { handle_network_response_headers(request, response_headers); finish_network_request(protocol_request); @@ -440,12 +440,12 @@ void ResourceLoader::load(LoadRequest& request, SuccessCallback success_callback log_failure(request, error_builder.string_view()); if (error_callback) - error_callback(error_builder.to_byte_string(), status_code, payload, response_headers); + error_callback->function()(error_builder.to_byte_string(), status_code, payload, response_headers); return; } log_success(request); - success_callback(payload, response_headers, status_code); + success_callback->function()(payload, response_headers, status_code); }; protocol_request->set_buffered_request_finished_callback(move(on_buffered_request_finished)); @@ -455,10 +455,10 @@ void ResourceLoader::load(LoadRequest& request, SuccessCallback success_callback auto not_implemented_error = ByteString::formatted("Protocol not implemented: {}", url.scheme()); log_failure(request, not_implemented_error); if (error_callback) - error_callback(not_implemented_error, {}, {}, {}); + error_callback->function()(not_implemented_error, {}, {}, {}); } -void ResourceLoader::load_unbuffered(LoadRequest& request, OnHeadersReceived on_headers_received, OnDataReceived on_data_received, OnComplete on_complete) +void ResourceLoader::load_unbuffered(LoadRequest& request, JS::Handle on_headers_received, JS::Handle on_data_received, JS::Handle on_complete) { auto const& url = request.url(); @@ -466,40 +466,40 @@ void ResourceLoader::load_unbuffered(LoadRequest& request, OnHeadersReceived on_ request.start_timer(); if (should_block_request(request)) { - on_complete(false, "Request was blocked"sv); + on_complete->function()(false, "Request was blocked"sv); return; } if (!url.scheme().is_one_of("http"sv, "https"sv)) { // FIXME: Non-network requests from fetch should not go through this path. - on_complete(false, "Cannot establish connection non-network scheme"sv); + on_complete->function()(false, "Cannot establish connection non-network scheme"sv); return; } auto protocol_request = start_network_request(request); if (!protocol_request) { - on_complete(false, "Failed to start network request"sv); + on_complete->function()(false, "Failed to start network request"sv); return; } - auto protocol_headers_received = [this, on_headers_received = move(on_headers_received), request](auto const& response_headers, auto status_code) { + auto protocol_headers_received = [this, on_headers_received, request](auto const& response_headers, auto status_code) { handle_network_response_headers(request, response_headers); - on_headers_received(response_headers, move(status_code)); + on_headers_received->function()(response_headers, move(status_code)); }; - auto protocol_data_received = [on_data_received = move(on_data_received)](auto data) { - on_data_received(data); + auto protocol_data_received = [on_data_received](auto data) { + on_data_received->function()(data); }; - auto protocol_complete = [this, on_complete = move(on_complete), request, &protocol_request = *protocol_request](u64, Optional const& network_error) { + auto protocol_complete = [this, on_complete, request, &protocol_request = *protocol_request](u64, Optional const& network_error) { finish_network_request(protocol_request); if (!network_error.has_value()) { log_success(request); - on_complete(true, {}); + on_complete->function()(true, {}); } else { log_failure(request, "Request finished with error"sv); - on_complete(false, "Request finished with error"sv); + on_complete->function()(false, "Request finished with error"sv); } }; diff --git a/Userland/Libraries/LibWeb/Loader/ResourceLoader.h b/Userland/Libraries/LibWeb/Loader/ResourceLoader.h index 34f3d32d487..df61e9a762f 100644 --- a/Userland/Libraries/LibWeb/Loader/ResourceLoader.h +++ b/Userland/Libraries/LibWeb/Loader/ResourceLoader.h @@ -27,17 +27,17 @@ public: RefPtr load_resource(Resource::Type, LoadRequest&); - using SuccessCallback = JS::SafeFunction status_code)>; - using ErrorCallback = JS::SafeFunction status_code, ReadonlyBytes payload, HTTP::HeaderMap const& response_headers)>; - using TimeoutCallback = JS::SafeFunction; + using SuccessCallback = JS::HeapFunction status_code)>; + using ErrorCallback = JS::HeapFunction status_code, ReadonlyBytes payload, HTTP::HeaderMap const& response_headers)>; + using TimeoutCallback = JS::HeapFunction; - void load(LoadRequest&, SuccessCallback success_callback, ErrorCallback error_callback = nullptr, Optional timeout = {}, TimeoutCallback timeout_callback = nullptr); + void load(LoadRequest&, JS::Handle success_callback, JS::Handle error_callback = nullptr, Optional timeout = {}, JS::Handle timeout_callback = nullptr); - using OnHeadersReceived = JS::SafeFunction status_code)>; - using OnDataReceived = JS::SafeFunction; - using OnComplete = JS::SafeFunction error_message)>; + using OnHeadersReceived = JS::HeapFunction status_code)>; + using OnDataReceived = JS::HeapFunction; + using OnComplete = JS::HeapFunction error_message)>; - void load_unbuffered(LoadRequest&, OnHeadersReceived, OnDataReceived, OnComplete); + void load_unbuffered(LoadRequest&, JS::Handle, JS::Handle, JS::Handle); Requests::RequestClient& request_client() { return *m_request_client; }