diff --git a/Libraries/LibWeb/HTML/Navigable.cpp b/Libraries/LibWeb/HTML/Navigable.cpp index 6072da8ee73..a5f4c709966 100644 --- a/Libraries/LibWeb/HTML/Navigable.cpp +++ b/Libraries/LibWeb/HTML/Navigable.cpp @@ -1349,6 +1349,12 @@ WebIDL::ExceptionOr Navigable::navigate(NavigateParams params) auto& active_document = *this->active_document(); auto& realm = active_document.realm(); + // AD-HOC: If we are not able to continue in this process, request a new process from the UI. + if (!active_document.page().client().is_url_suitable_for_same_process_navigation(active_document.url(), params.url)) { + active_document.page().client().request_new_process_for_navigation(params.url); + return {}; + } + // 2. Let sourceSnapshotParams be the result of snapshotting source snapshot params given sourceDocument. auto source_snapshot_params = source_document->snapshot_source_snapshot_params(); diff --git a/Libraries/LibWeb/Page/Page.h b/Libraries/LibWeb/Page/Page.h index 47b77e287fb..9704c71b046 100644 --- a/Libraries/LibWeb/Page/Page.h +++ b/Libraries/LibWeb/Page/Page.h @@ -321,6 +321,8 @@ public: virtual Page& page() = 0; virtual Page const& page() const = 0; virtual bool is_connection_open() const = 0; + virtual bool is_url_suitable_for_same_process_navigation([[maybe_unused]] URL::URL const& current_url, [[maybe_unused]] URL::URL const& target_url) const { return true; } + virtual void request_new_process_for_navigation(URL::URL const&) { } virtual Gfx::Palette palette() const = 0; virtual DevicePixelRect screen_rect() const = 0; virtual double device_pixels_per_css_pixel() const = 0; diff --git a/Libraries/LibWebView/CMakeLists.txt b/Libraries/LibWebView/CMakeLists.txt index bbab6874b47..acd6e5c8ac3 100644 --- a/Libraries/LibWebView/CMakeLists.txt +++ b/Libraries/LibWebView/CMakeLists.txt @@ -16,6 +16,7 @@ set(SOURCES ProcessHandle.cpp ProcessManager.cpp SearchEngine.cpp + SiteIsolation.cpp SourceHighlighter.cpp URL.cpp UserAgent.cpp diff --git a/Libraries/LibWebView/SiteIsolation.cpp b/Libraries/LibWebView/SiteIsolation.cpp new file mode 100644 index 00000000000..93584ca121b --- /dev/null +++ b/Libraries/LibWebView/SiteIsolation.cpp @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2025, Tim Flynn + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include +#include + +namespace WebView { + +bool is_url_suitable_for_same_process_navigation(URL::URL const& current_url, URL::URL const& target_url) +{ + // Allow navigating from about:blank to any site. + if (Web::HTML::url_matches_about_blank(current_url)) + return true; + + // Allow cross-scheme non-HTTP(S) navigation. Disallow cross-scheme HTTP(s) navigation. + auto current_url_is_http = Web::Fetch::Infrastructure::is_http_or_https_scheme(current_url.scheme()); + auto target_url_is_http = Web::Fetch::Infrastructure::is_http_or_https_scheme(target_url.scheme()); + + if (!current_url_is_http || !target_url_is_http) + return !current_url_is_http && !target_url_is_http; + + // Disallow cross-site HTTP(S) navigation. + return current_url.origin().is_same_site(target_url.origin()); +} + +} diff --git a/Libraries/LibWebView/SiteIsolation.h b/Libraries/LibWebView/SiteIsolation.h new file mode 100644 index 00000000000..c31c8c1bf78 --- /dev/null +++ b/Libraries/LibWebView/SiteIsolation.h @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2025, Tim Flynn + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include + +namespace WebView { + +[[nodiscard]] bool is_url_suitable_for_same_process_navigation(URL::URL const& current_url, URL::URL const& target_url); + +} diff --git a/Libraries/LibWebView/ViewImplementation.cpp b/Libraries/LibWebView/ViewImplementation.cpp index 271e334d5f3..3358847f5da 100644 --- a/Libraries/LibWebView/ViewImplementation.cpp +++ b/Libraries/LibWebView/ViewImplementation.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -89,6 +90,21 @@ u64 ViewImplementation::page_id() const return m_client_state.page_index; } +void ViewImplementation::create_new_process_for_cross_site_navigation(URL::URL const& url) +{ + if (m_client_state.client) + client().async_close_server(); + + initialize_client(); + VERIFY(m_client_state.client); + + // Don't keep a stale backup bitmap around. + m_backup_bitmap = nullptr; + handle_resize(); + + load(url); +} + void ViewImplementation::server_did_paint(Badge, i32 bitmap_id, Gfx::IntSize size) { if (m_client_state.back_bitmap.id == bitmap_id) { diff --git a/Libraries/LibWebView/ViewImplementation.h b/Libraries/LibWebView/ViewImplementation.h index 70dcb1eee26..c1f8ed73592 100644 --- a/Libraries/LibWebView/ViewImplementation.h +++ b/Libraries/LibWebView/ViewImplementation.h @@ -58,6 +58,8 @@ public: String const& handle() const { return m_client_state.client_handle; } + void create_new_process_for_cross_site_navigation(URL::URL const&); + void server_did_paint(Badge, i32 bitmap_id, Gfx::IntSize size); void set_window_position(Gfx::IntPoint); diff --git a/Libraries/LibWebView/WebContentClient.cpp b/Libraries/LibWebView/WebContentClient.cpp index f4cbf963e25..29d664096d9 100644 --- a/Libraries/LibWebView/WebContentClient.cpp +++ b/Libraries/LibWebView/WebContentClient.cpp @@ -62,6 +62,12 @@ void WebContentClient::did_paint(u64 page_id, Gfx::IntRect rect, i32 bitmap_id) view->server_did_paint({}, bitmap_id, rect.size()); } +void WebContentClient::did_request_new_process_for_navigation(u64 page_id, URL::URL url) +{ + if (auto view = view_for_page_id(page_id); view.has_value()) + view->create_new_process_for_cross_site_navigation(url); +} + void WebContentClient::did_start_loading(u64 page_id, URL::URL url, bool is_redirect) { if (auto process = WebView::Application::the().find_process(m_process_handle.pid); process.has_value()) diff --git a/Libraries/LibWebView/WebContentClient.h b/Libraries/LibWebView/WebContentClient.h index 06eec41a253..28dd0d71376 100644 --- a/Libraries/LibWebView/WebContentClient.h +++ b/Libraries/LibWebView/WebContentClient.h @@ -52,6 +52,7 @@ private: virtual void die() override; virtual void did_paint(u64 page_id, Gfx::IntRect, i32) override; + virtual void did_request_new_process_for_navigation(u64 page_id, URL::URL url) override; virtual void did_finish_loading(u64 page_id, URL::URL) override; virtual void did_request_refresh(u64 page_id) override; virtual void did_request_cursor_change(u64 page_id, Gfx::Cursor) override; diff --git a/Services/WebContent/PageClient.cpp b/Services/WebContent/PageClient.cpp index 1049fef6aa8..2e917bae179 100644 --- a/Services/WebContent/PageClient.cpp +++ b/Services/WebContent/PageClient.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -134,6 +135,16 @@ bool PageClient::is_connection_open() const return client().is_open(); } +bool PageClient::is_url_suitable_for_same_process_navigation(URL::URL const& current_url, URL::URL const& target_url) const +{ + return WebView::is_url_suitable_for_same_process_navigation(current_url, target_url); +} + +void PageClient::request_new_process_for_navigation(URL::URL const& url) +{ + client().async_did_request_new_process_for_navigation(m_id, url); +} + Gfx::Palette PageClient::palette() const { return Gfx::Palette(*m_palette_impl); diff --git a/Services/WebContent/PageClient.h b/Services/WebContent/PageClient.h index a7a5029a4a7..f3ea3df8a35 100644 --- a/Services/WebContent/PageClient.h +++ b/Services/WebContent/PageClient.h @@ -111,6 +111,8 @@ private: // ^PageClient virtual bool is_connection_open() const override; + virtual bool is_url_suitable_for_same_process_navigation(URL::URL const& current_url, URL::URL const& target_url) const override; + virtual void request_new_process_for_navigation(URL::URL const&) override; virtual Gfx::Palette palette() const override; virtual Web::DevicePixelRect screen_rect() const override { return m_screen_rect; } virtual Web::CSS::PreferredColorScheme preferred_color_scheme() const override { return m_preferred_color_scheme; } diff --git a/Services/WebContent/WebContentClient.ipc b/Services/WebContent/WebContentClient.ipc index 766a8dbb1e6..42e71257772 100644 --- a/Services/WebContent/WebContentClient.ipc +++ b/Services/WebContent/WebContentClient.ipc @@ -23,6 +23,7 @@ endpoint WebContentClient { + did_request_new_process_for_navigation(u64 page_id, URL::URL url) =| did_start_loading(u64 page_id, URL::URL url, bool is_redirect) =| did_finish_loading(u64 page_id, URL::URL url) =| did_request_refresh(u64 page_id) =|