diff options
author | Lucas CHOLLET <lucas.chollet@free.fr> | 2022-02-26 17:50:31 +0100 |
---|---|---|
committer | Linus Groh <mail@linusgroh.de> | 2022-06-27 20:22:15 +0100 |
commit | 662711fa26de109d4c8fe1d93f17e1983d66ebf3 (patch) | |
tree | c138ed6b424be28e01db85e74f81f5a31632d6f4 | |
parent | 1ba9c821fbfc54562e10981a3403aa25fb6079b3 (diff) | |
download | serenity-662711fa26de109d4c8fe1d93f17e1983d66ebf3.zip |
Browser+LibWeb+WebContent: Allow Browser to load local files
To achieve this goal:
- The Browser unveils "/tmp/portal/filesystemaccess"
- Pass the page through LoadRequest => ResourceLoader
- ResourceLoader requests a file to the FileSystemAccessServer via IPC
- OutOfProcessWebView handles it and sends a file descriptor back to
the Page.
21 files changed, 165 insertions, 14 deletions
diff --git a/Userland/Applications/Browser/main.cpp b/Userland/Applications/Browser/main.cpp index cd437eb5ab..1c1f22ecc0 100644 --- a/Userland/Applications/Browser/main.cpp +++ b/Userland/Applications/Browser/main.cpp @@ -84,6 +84,7 @@ ErrorOr<int> serenity_main(Main::Arguments arguments) TRY(Core::System::unveil("/res", "r")); TRY(Core::System::unveil("/etc/passwd", "r")); TRY(Core::System::unveil("/etc/timezone", "r")); + TRY(Core::System::unveil("/tmp/portal/filesystemaccess", "rw")); TRY(Core::System::unveil("/tmp/portal/image", "rw")); TRY(Core::System::unveil("/tmp/portal/webcontent", "rw")); TRY(Core::System::unveil("/tmp/portal/request", "rw")); diff --git a/Userland/Libraries/LibWeb/CMakeLists.txt b/Userland/Libraries/LibWeb/CMakeLists.txt index d896049765..369e6d1be3 100644 --- a/Userland/Libraries/LibWeb/CMakeLists.txt +++ b/Userland/Libraries/LibWeb/CMakeLists.txt @@ -274,6 +274,7 @@ set(SOURCES Layout/TextNode.cpp Layout/TreeBuilder.cpp Loader/ContentFilter.cpp + Loader/FileRequest.cpp Loader/FrameLoader.cpp Loader/ImageLoader.cpp Loader/ImageResource.cpp diff --git a/Userland/Libraries/LibWeb/Loader/FileRequest.cpp b/Userland/Libraries/LibWeb/Loader/FileRequest.cpp new file mode 100644 index 0000000000..4a0f2df04d --- /dev/null +++ b/Userland/Libraries/LibWeb/Loader/FileRequest.cpp @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2022, Lucas Chollet <lucas.chollet@free.fr> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include "FileRequest.h" + +namespace Web { + +FileRequest::FileRequest(String path) + : m_path(move(path)) +{ +} + +String FileRequest::path() const +{ + return m_path; +} + +} diff --git a/Userland/Libraries/LibWeb/Loader/FileRequest.h b/Userland/Libraries/LibWeb/Loader/FileRequest.h new file mode 100644 index 0000000000..ca4251fbca --- /dev/null +++ b/Userland/Libraries/LibWeb/Loader/FileRequest.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2022, Lucas Chollet <lucas.chollet@free.fr> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include <AK/Error.h> +#include <AK/Function.h> +#include <AK/RefCounted.h> +#include <AK/String.h> + +namespace Web { + +class FileRequest : public RefCounted<FileRequest> { +public: + explicit FileRequest(String path); + + String path() const; + + Function<void(ErrorOr<i32>)> on_file_request_finish; + +private: + String m_path {}; +}; + +} diff --git a/Userland/Libraries/LibWeb/Loader/LoadRequest.cpp b/Userland/Libraries/LibWeb/Loader/LoadRequest.cpp index 02b671e3d2..cc0ffff211 100644 --- a/Userland/Libraries/LibWeb/Loader/LoadRequest.cpp +++ b/Userland/Libraries/LibWeb/Loader/LoadRequest.cpp @@ -19,6 +19,7 @@ LoadRequest LoadRequest::create_for_url_on_page(const AK::URL& url, Page* page) String cookie = page->client().page_did_request_cookie(url, Cookie::Source::Http); if (!cookie.is_empty()) request.set_header("Cookie", cookie); + request.set_page(*page); } return request; diff --git a/Userland/Libraries/LibWeb/Loader/LoadRequest.h b/Userland/Libraries/LibWeb/Loader/LoadRequest.h index 43e9bd3db7..2a73177024 100644 --- a/Userland/Libraries/LibWeb/Loader/LoadRequest.h +++ b/Userland/Libraries/LibWeb/Loader/LoadRequest.h @@ -12,6 +12,7 @@ #include <AK/URL.h> #include <LibCore/ElapsedTimer.h> #include <LibWeb/Forward.h> +#include <LibWeb/Page/Page.h> namespace Web { @@ -37,6 +38,9 @@ public: void start_timer() { m_load_timer.start(); }; Time load_time() const { return m_load_timer.elapsed_time(); } + Optional<Page&>& page() { return m_page; }; + void set_page(Page& page) { m_page = page; } + unsigned hash() const { auto body_hash = string_hash((char const*)m_body.data(), m_body.size()); @@ -70,6 +74,7 @@ private: HashMap<String, String> m_headers; ByteBuffer m_body; Core::ElapsedTimer m_load_timer; + Optional<Page&> m_page; }; } diff --git a/Userland/Libraries/LibWeb/Loader/ResourceLoader.cpp b/Userland/Libraries/LibWeb/Loader/ResourceLoader.cpp index c1b57ae08b..df2ec39e17 100644 --- a/Userland/Libraries/LibWeb/Loader/ResourceLoader.cpp +++ b/Userland/Libraries/LibWeb/Loader/ResourceLoader.cpp @@ -213,21 +213,51 @@ void ResourceLoader::load(LoadRequest& request, Function<void(ReadonlyBytes, Has } if (url.protocol() == "file") { - auto file_result = Core::File::open(url.path(), Core::OpenMode::ReadOnly); - if (file_result.is_error()) { - auto& error = file_result.error(); - log_failure(request, error); - if (error_callback) - error_callback(String::formatted("{}", error), error.code()); - return; - } + if (request.page().has_value()) + m_page = request.page().value(); - auto file = file_result.release_value(); - auto data = file->read_all(); - log_success(request); - deferred_invoke([data = move(data), success_callback = move(success_callback)] { + VERIFY(m_page.has_value()); + auto file_ref = make_ref_counted<FileRequest>(url.path()); + file_ref->on_file_request_finish = [this, success_callback = move(success_callback), error_callback = move(error_callback), log_success, log_failure, request, file_ref](ErrorOr<i32> file_or_error) { + --m_pending_loads; + if (on_load_counter_change) + on_load_counter_change(); + + if (file_or_error.is_error()) { + log_failure(request, file_or_error.error()); + if (error_callback) + error_callback(String::formatted("{}", file_or_error.error()), file_or_error.error().code()); + return; + } + + auto const fd = file_or_error.value(); + + auto maybe_file = Core::Stream::File::adopt_fd(fd, Core::Stream::OpenMode::Read); + if (maybe_file.is_error()) { + log_failure(request, maybe_file.error()); + if (error_callback) + error_callback(String::formatted("{}", maybe_file.error()), maybe_file.error().code()); + return; + } + + auto file = maybe_file.release_value(); + auto maybe_data = file->read_all(); + if (maybe_data.is_error()) { + log_failure(request, maybe_data.error()); + if (error_callback) + error_callback(String::formatted("{}", maybe_data.error()), maybe_data.error().code()); + return; + } + auto data = maybe_data.release_value(); + log_success(request); success_callback(data, {}, {}); - }); + }; + m_page->client().request_file(file_ref); + + ++m_pending_loads; + if (on_load_counter_change) + on_load_counter_change(); + return; } diff --git a/Userland/Libraries/LibWeb/Loader/ResourceLoader.h b/Userland/Libraries/LibWeb/Loader/ResourceLoader.h index ba1aa5879d..c8ed264668 100644 --- a/Userland/Libraries/LibWeb/Loader/ResourceLoader.h +++ b/Userland/Libraries/LibWeb/Loader/ResourceLoader.h @@ -14,6 +14,7 @@ #include <LibCore/Object.h> #include <LibCore/Proxy.h> #include <LibWeb/Loader/Resource.h> +#include <LibWeb/Page/Page.h> namespace Web { @@ -98,6 +99,7 @@ private: HashTable<NonnullRefPtr<ResourceLoaderConnectorRequest>> m_active_requests; NonnullRefPtr<ResourceLoaderConnector> m_connector; String m_user_agent; + Optional<Page&> m_page {}; }; } diff --git a/Userland/Libraries/LibWeb/Page/Page.h b/Userland/Libraries/LibWeb/Page/Page.h index d4880288e1..1312596ccb 100644 --- a/Userland/Libraries/LibWeb/Page/Page.h +++ b/Userland/Libraries/LibWeb/Page/Page.h @@ -18,6 +18,7 @@ #include <LibGfx/StandardCursor.h> #include <LibWeb/CSS/PreferredColorScheme.h> #include <LibWeb/Forward.h> +#include <LibWeb/Loader/FileRequest.h> namespace Web { @@ -111,6 +112,8 @@ public: virtual void page_did_set_cookie(const AK::URL&, Cookie::ParsedCookie const&, Cookie::Source) { } virtual void page_did_update_resource_count(i32) { } + virtual void request_file(NonnullRefPtr<FileRequest>&) = 0; + protected: virtual ~PageClient() = default; }; diff --git a/Userland/Libraries/LibWebView/CMakeLists.txt b/Userland/Libraries/LibWebView/CMakeLists.txt index 77852b5ed6..64aa178e56 100644 --- a/Userland/Libraries/LibWebView/CMakeLists.txt +++ b/Userland/Libraries/LibWebView/CMakeLists.txt @@ -16,6 +16,6 @@ set(GENERATED_SOURCES ) serenity_lib(LibWebView webview) -target_link_libraries(LibWebView LibGfx LibGUI LibImageDecoderClient LibIPC LibProtocol LibWeb) +target_link_libraries(LibWebView LibFileSystemAccessClient LibGfx LibGUI LibImageDecoderClient LibIPC LibProtocol LibWeb) add_subdirectory(DumpLayoutTree) diff --git a/Userland/Libraries/LibWebView/OutOfProcessWebView.cpp b/Userland/Libraries/LibWebView/OutOfProcessWebView.cpp index 1e248aed52..ed6967f567 100644 --- a/Userland/Libraries/LibWebView/OutOfProcessWebView.cpp +++ b/Userland/Libraries/LibWebView/OutOfProcessWebView.cpp @@ -7,6 +7,7 @@ #include "OutOfProcessWebView.h" #include "WebContentClient.h" #include <AK/String.h> +#include <LibFileSystemAccessClient/Client.h> #include <LibGUI/Application.h> #include <LibGUI/Desktop.h> #include <LibGUI/InputBox.h> @@ -400,6 +401,15 @@ void OutOfProcessWebView::notify_server_did_update_resource_count(i32 count_wait on_resource_status_change(count_waiting); } +void OutOfProcessWebView::notify_server_did_request_file(Badge<WebContentClient>, String const& path, i32 request_id) +{ + auto file = FileSystemAccessClient::Client::the().try_request_file_read_only_approved(window(), path); + if (file.is_error()) + client().async_handle_file_return(file.error().code(), {}, request_id); + else + client().async_handle_file_return(0, IPC::File(file.value()->leak_fd()), request_id); +} + void OutOfProcessWebView::did_scroll() { client().async_set_viewport_rect(visible_content_rect()); diff --git a/Userland/Libraries/LibWebView/OutOfProcessWebView.h b/Userland/Libraries/LibWebView/OutOfProcessWebView.h index ee24156ff8..2132fbf290 100644 --- a/Userland/Libraries/LibWebView/OutOfProcessWebView.h +++ b/Userland/Libraries/LibWebView/OutOfProcessWebView.h @@ -112,6 +112,7 @@ public: String notify_server_did_request_cookie(Badge<WebContentClient>, const AK::URL& url, Web::Cookie::Source source); void notify_server_did_set_cookie(Badge<WebContentClient>, const AK::URL& url, Web::Cookie::ParsedCookie const& cookie, Web::Cookie::Source source); void notify_server_did_update_resource_count(i32 count_waiting); + void notify_server_did_request_file(Badge<WebContentClient>, String const& path, i32); private: OutOfProcessWebView(); diff --git a/Userland/Libraries/LibWebView/WebContentClient.cpp b/Userland/Libraries/LibWebView/WebContentClient.cpp index f91e35bfed..b83307f115 100644 --- a/Userland/Libraries/LibWebView/WebContentClient.cpp +++ b/Userland/Libraries/LibWebView/WebContentClient.cpp @@ -200,4 +200,9 @@ void WebContentClient::did_update_resource_count(i32 count_waiting) m_view.notify_server_did_update_resource_count(count_waiting); } +void WebContentClient::did_request_file(String const& path, i32 request_id) +{ + m_view.notify_server_did_request_file({}, path, request_id); +} + } diff --git a/Userland/Libraries/LibWebView/WebContentClient.h b/Userland/Libraries/LibWebView/WebContentClient.h index 705c5fcea2..3dd0619cf4 100644 --- a/Userland/Libraries/LibWebView/WebContentClient.h +++ b/Userland/Libraries/LibWebView/WebContentClient.h @@ -61,6 +61,7 @@ private: virtual Messages::WebContentClient::DidRequestCookieResponse did_request_cookie(AK::URL const&, u8) override; virtual void did_set_cookie(AK::URL const&, Web::Cookie::ParsedCookie const&, u8) override; virtual void did_update_resource_count(i32 count_waiting) override; + virtual void did_request_file(String const& path, i32) override; OutOfProcessWebView& m_view; }; diff --git a/Userland/Services/WebContent/ConnectionFromClient.cpp b/Userland/Services/WebContent/ConnectionFromClient.cpp index 89f03fa9ea..f2f483ce1f 100644 --- a/Userland/Services/WebContent/ConnectionFromClient.cpp +++ b/Userland/Services/WebContent/ConnectionFromClient.cpp @@ -505,4 +505,22 @@ Messages::WebContentServer::GetSessionStorageEntriesResponse ConnectionFromClien auto session_storage = document->window().session_storage(); return session_storage->map(); } + +void ConnectionFromClient::handle_file_return(i32 error, Optional<IPC::File> const& file, i32 request_id) +{ + auto result = m_requested_files.get(request_id); + VERIFY(result.has_value()); + + VERIFY(result.value()->on_file_request_finish); + result.value()->on_file_request_finish(error != 0 ? Error::from_errno(error) : ErrorOr<i32> { file->take_fd() }); + m_requested_files.remove(request_id); +} + +void ConnectionFromClient::request_file(NonnullRefPtr<Web::FileRequest>& file_request) +{ + i32 const id = last_id++; + m_requested_files.set(id, file_request); + + async_did_request_file(file_request->path(), id); +} } diff --git a/Userland/Services/WebContent/ConnectionFromClient.h b/Userland/Services/WebContent/ConnectionFromClient.h index 943e4ff359..8071e5d3fe 100644 --- a/Userland/Services/WebContent/ConnectionFromClient.h +++ b/Userland/Services/WebContent/ConnectionFromClient.h @@ -13,6 +13,7 @@ #include <LibWeb/CSS/PreferredColorScheme.h> #include <LibWeb/Cookie/ParsedCookie.h> #include <LibWeb/Forward.h> +#include <LibWeb/Loader/FileRequest.h> #include <WebContent/Forward.h> #include <WebContent/WebContentClientEndpoint.h> #include <WebContent/WebContentConsoleClient.h> @@ -31,6 +32,8 @@ public: void initialize_js_console(Badge<PageHost>); + void request_file(NonnullRefPtr<Web::FileRequest>&); + private: explicit ConnectionFromClient(NonnullOwnPtr<Core::Stream::LocalSocket>); @@ -64,6 +67,7 @@ private: virtual void set_preferred_color_scheme(Web::CSS::PreferredColorScheme const&) override; virtual void set_has_focus(bool) override; virtual void set_is_scripting_enabled(bool) override; + virtual void handle_file_return(i32 error, Optional<IPC::File> const& file, i32 request_id) override; virtual void js_console_input(String const&) override; virtual void run_javascript(String const&) override; @@ -91,6 +95,9 @@ private: WeakPtr<JS::Interpreter> m_interpreter; OwnPtr<WebContentConsoleClient> m_console_client; JS::Handle<JS::GlobalObject> m_console_global_object; + + HashMap<int, NonnullRefPtr<Web::FileRequest>> m_requested_files {}; + int last_id { 0 }; }; } diff --git a/Userland/Services/WebContent/PageHost.cpp b/Userland/Services/WebContent/PageHost.cpp index e7cd81d63b..5e377d4117 100644 --- a/Userland/Services/WebContent/PageHost.cpp +++ b/Userland/Services/WebContent/PageHost.cpp @@ -263,4 +263,9 @@ void PageHost::page_did_update_resource_count(i32 count_waiting) m_client.async_did_update_resource_count(count_waiting); } +void PageHost::request_file(NonnullRefPtr<Web::FileRequest>& file_request) +{ + m_client.request_file(file_request); +} + } diff --git a/Userland/Services/WebContent/PageHost.h b/Userland/Services/WebContent/PageHost.h index a9815f2fec..13faaa5819 100644 --- a/Userland/Services/WebContent/PageHost.h +++ b/Userland/Services/WebContent/PageHost.h @@ -66,6 +66,7 @@ private: virtual String page_did_request_cookie(const URL&, Web::Cookie::Source) override; virtual void page_did_set_cookie(const URL&, Web::Cookie::ParsedCookie const&, Web::Cookie::Source) override; virtual void page_did_update_resource_count(i32) override; + virtual void request_file(NonnullRefPtr<Web::FileRequest>&) override; explicit PageHost(ConnectionFromClient&); diff --git a/Userland/Services/WebContent/WebContentClient.ipc b/Userland/Services/WebContent/WebContentClient.ipc index aaa5c67138..a2865d4ca6 100644 --- a/Userland/Services/WebContent/WebContentClient.ipc +++ b/Userland/Services/WebContent/WebContentClient.ipc @@ -35,6 +35,7 @@ endpoint WebContentClient did_request_cookie(URL url, u8 source) => (String cookie) did_set_cookie(URL url, Web::Cookie::ParsedCookie cookie, u8 source) =| did_update_resource_count(i32 count_waiting) =| + did_request_file(String path, i32 request_id) =| did_output_js_console_message(i32 message_index) =| did_get_js_console_messages(i32 start_index, Vector<String> message_types, Vector<String> messages) =| diff --git a/Userland/Services/WebContent/WebContentServer.ipc b/Userland/Services/WebContent/WebContentServer.ipc index 418c33a32d..b8b01749f3 100644 --- a/Userland/Services/WebContent/WebContentServer.ipc +++ b/Userland/Services/WebContent/WebContentServer.ipc @@ -1,4 +1,5 @@ #include <AK/URL.h> +#include <LibIPC/File.h> #include <LibCore/AnonymousBuffer.h> #include <LibGfx/ShareableBitmap.h> #include <LibWeb/CSS/PreferredColorScheme.h> @@ -51,4 +52,6 @@ endpoint WebContentServer get_local_storage_entries() => (OrderedHashMap<String,String> entries) get_session_storage_entries() => (OrderedHashMap<String,String> entries) + + handle_file_return(i32 error, Optional<IPC::File> file, i32 request_id) =| } diff --git a/Userland/Utilities/headless-browser.cpp b/Userland/Utilities/headless-browser.cpp index 924e619222..9485456c90 100644 --- a/Userland/Utilities/headless-browser.cpp +++ b/Userland/Utilities/headless-browser.cpp @@ -17,6 +17,7 @@ #include <LibCore/IODevice.h> #include <LibCore/MemoryStream.h> #include <LibCore/Stream.h> +#include <LibCore/System.h> #include <LibCore/Timer.h> #include <LibGemini/GeminiRequest.h> #include <LibGemini/GeminiResponse.h> @@ -214,6 +215,12 @@ public: { } + void request_file(NonnullRefPtr<Web::FileRequest>& request) override + { + auto const file = Core::System::open(request->path(), O_RDONLY); + request->on_file_request_finish(file); + } + private: HeadlessBrowserPageClient() : m_page(make<Web::Page>(*this)) |