chromium/content/browser/webui/web_ui_browsertest.cc

// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <memory>
#include <utility>

#include "base/command_line.h"
#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/functional/callback_helpers.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/ref_counted_memory.h"
#include "base/memory/weak_ptr.h"
#include "base/run_loop.h"
#include "base/strings/strcat.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/bind.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/simple_test_tick_clock.h"
#include "base/time/time.h"
#include "build/build_config.h"
#include "content/browser/fenced_frame/fenced_frame.h"
#include "content/browser/renderer_host/navigation_controller_impl.h"
#include "content/browser/renderer_host/navigation_entry_impl.h"
#include "content/browser/renderer_host/navigation_entry_restore_context_impl.h"
#include "content/browser/renderer_host/render_frame_host_impl.h"
#include "content/browser/web_contents/web_contents_impl.h"
#include "content/browser/webui/web_ui_controller_factory_registry.h"
#include "content/browser/webui/web_ui_impl.h"
#include "content/common/content_navigation_policy.h"
#include "content/public/browser/child_process_security_policy.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_ui_controller.h"
#include "content/public/browser/web_ui_data_source.h"
#include "content/public/browser/web_ui_message_handler.h"
#include "content/public/browser/webui_config_map.h"
#include "content/public/common/content_switches.h"
#include "content/public/common/isolated_world_ids.h"
#include "content/public/common/url_constants.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/content_browser_test.h"
#include "content/public/test/fenced_frame_test_util.h"
#include "content/public/test/scoped_web_ui_controller_factory_registration.h"
#include "content/public/test/test_frame_navigation_observer.h"
#include "content/public/test/test_navigation_observer.h"
#include "content/public/test/test_utils.h"
#include "content/public/test/web_ui_browsertest_util.h"
#include "content/shell/browser/shell.h"
#include "content/test/content_browser_test_utils_internal.h"
#include "testing/gmock/include/gmock/gmock-matchers.h"
#include "third_party/blink/public/common/features.h"
#include "third_party/blink/public/common/input/web_mouse_event.h"
#include "third_party/blink/public/common/input/web_mouse_wheel_event.h"
#include "ui/events/base_event_utils.h"
#include "ui/webui/untrusted_web_ui_browsertest_util.h"

namespace content {

namespace {

WebUIImplBrowserTest;

// TODO(crbug.com/40290702): Shared workers are not available on Android.
#if !BUILDFLAG(IS_ANDROID)
const char kLoadSharedWorkerScript[] =;
#endif  // !BUILDFLAG(IS_ANDROID)

const char kLoadDedicatedWorkerScript[] =;

class TestWebUIMessageHandler : public WebUIMessageHandler {};

class WebUIRequiringGestureBrowserTest : public ContentBrowserTest {};

}  // namespace

// Tests that navigating between WebUIs of different types results in
// SiteInstance swap when running in process-per-tab process model.
IN_PROC_BROWSER_TEST_F(WebUIImplBrowserTest, ForceSwapOnDifferenteWebUITypes) {}

// Tests that a WebUI page will stay in the initial RenderFrameHost and its
// SiteInstance when we navigate to it from the initial blank page.
//
// While WebUI navigations require a BrowsingInstance swap and hence typically
// force a RenderFrameHost swap, the initial RenderFrameHost is in an unused
// process and unassigned SiteInstance, and so it effectively satisfies the
// BrowsingInstance swap requirement. So, it should be reused without requiring
// an extra RenderFrameHost swap.
IN_PROC_BROWSER_TEST_F(WebUIImplBrowserTest,
                       ReuseInitialRenderFrameHostOnFirstNavigation) {}

// Check that starting a WebUI navigation while an about:blank navigation in an
// initial RenderFrameHost is pending commit does not crash.  See
// https://crbug.com/1492076.
IN_PROC_BROWSER_TEST_F(WebUIImplBrowserTest,
                       StartWebUINavigationWhileAboutBlankIsPendingCommit) {}

// Check that navigating to a WebUI page from a crashed about:blank page will
// work correctly, properly granting WebUI bindings and avoiding the reuse of
// the initial SiteInstance and process.
IN_PROC_BROWSER_TEST_F(WebUIImplBrowserTest, NavigateFromCrashedAboutBlank) {}

// Check that when over the process limit, a WebUI navigation in one tab does
// not reuse an initial RFH's unused process in another unrelated tab.
IN_PROC_BROWSER_TEST_F(WebUIImplBrowserTest,
                       DoNotReuseInitialRenderFrameHostForDifferentTab) {}

// Check that if two initial RenderFrameHosts in different tabs share a
// process, and that process becomes locked to a normal web site after a
// navigation in the first tab, then that process should not be reused for a
// WebUI navigation in the second tab, even though it's still the initial
// RFH's process in that tab.
IN_PROC_BROWSER_TEST_F(WebUIImplBrowserTest,
                       DoNotReuseInitialRenderFrameHostWithUsedProcess) {}

// Check that if two initial RenderFrameHosts in different tabs share a
// process, then that process can be reused for a WebUI navigation in one of
// these tabs.
IN_PROC_BROWSER_TEST_F(WebUIImplBrowserTest,
                       ReuseInitialProcessSharedByMultipleTabs) {}

// Check that when a tab with a WebUI page is cloned, the new tab reuses the old
// tab's SiteInstance and process when it loads its copy of the WebUI page.
IN_PROC_BROWSER_TEST_F(WebUIImplBrowserTest, ReuseProcessInClonedTab) {}

// Check that doing a session restore of a WebUI NavigationEntry in a new tab
// can reuse the new tab's initial RFH.
IN_PROC_BROWSER_TEST_F(WebUIImplBrowserTest, ReuseInitialRFHInRestoredTab) {}

// Tests that navigating from chrome:// to chrome-untrusted:// results in
// SiteInstance swap.
IN_PROC_BROWSER_TEST_F(WebUIImplBrowserTest, ForceSwapOnFromChromeToUntrusted) {}

// Tests that navigating from chrome-untrusted:// to chrome:// results in
// SiteInstance swap.
IN_PROC_BROWSER_TEST_F(WebUIImplBrowserTest, ForceSwapOnFromUntrustedToChrome) {}

IN_PROC_BROWSER_TEST_F(WebUIImplBrowserTest, SameDocumentNavigationsAndReload) {}

// A WebUI message that should require a user gesture is ignored if there is no
// recent input event.
IN_PROC_BROWSER_TEST_F(WebUIRequiringGestureBrowserTest,
                       MessageRequiringGestureIgnoredIfNoGesture) {}

IN_PROC_BROWSER_TEST_F(WebUIRequiringGestureBrowserTest,
                       MessageRequiringGestureIgnoresRendererOnlyGesture) {}

IN_PROC_BROWSER_TEST_F(WebUIRequiringGestureBrowserTest,
                       MessageRequiringGestureIgnoresNonInteractiveEvents) {}

IN_PROC_BROWSER_TEST_F(
    WebUIRequiringGestureBrowserTest,
    // TODO(crbug.com/40851657): Re-enable this test
    DISABLED_MessageRequiringGestureAllowedWithInteractiveEvent) {}

// Verify that we can successfully navigate to a chrome-untrusted:// URL.
IN_PROC_BROWSER_TEST_F(WebUIImplBrowserTest, UntrustedSchemeLoads) {}

// Verify that we can successfully navigate to a chrome-untrusted:// URL
// without a crash while WebUI::Send is being performed.
// TODO(crbug.com/40773523): Enable this test once a root cause is identified.
IN_PROC_BROWSER_TEST_F(WebUIImplBrowserTest, DISABLED_NavigateWhileWebUISend) {}

IN_PROC_BROWSER_TEST_F(WebUIImplBrowserTest, CoopCoepPolicies) {}

// Regression test for: https://crbug.com/1308391
// Check content/ supports its embedders closing WebContent during WebUI
// destruction, after the RenderFrameHost owning it has unloaded.
IN_PROC_BROWSER_TEST_F(WebUIImplBrowserTest,
                       SynchronousWebContentDeletionInUnload) {}

class WebUIRequestSchemesTest : public ContentBrowserTest {};

// Verify that by default WebUI's child process security policy can request
// default schemes such as chrome.
//
// ChildProcessSecurityPolicy::CanRequestURL() always returns true for the
// following schemes, but in practice there are other checks that stop WebUIs
// from accessing these schemes.
IN_PROC_BROWSER_TEST_F(WebUIRequestSchemesTest, DefaultSchemesCanBeRequested) {}

// Verify that we can successfully allow non-default URL schemes to
// be requested by the WebUI's child process security policy.
IN_PROC_BROWSER_TEST_F(WebUIRequestSchemesTest,
                       AllowAdditionalSchemesToBeRequested) {}

class WebUIWorkerTest : public ContentBrowserTest {};

class WebUIDedicatedWorkerTest : public WebUIWorkerTest,
                                 public testing::WithParamInterface<bool> {};

INSTANTIATE_TEST_SUITE_P();

// TODO(crbug.com/40290702): Shared workers are not available on Android.
#if !BUILDFLAG(IS_ANDROID)
// Verify that we can create SharedWorker with scheme "chrome://" under
// WebUI page.
IN_PROC_BROWSER_TEST_F(WebUIWorkerTest, CanCreateWebUISharedWorkerForWebUI) {}

// Verify that pages with scheme other than "chrome://" cannot create
// SharedWorker with scheme "chrome://".
IN_PROC_BROWSER_TEST_F(WebUIWorkerTest,
                       CannotCreateWebUISharedWorkerForNonWebUI) {}

// Test that we can start a Shared Worker from a chrome-untrusted:// iframe.
IN_PROC_BROWSER_TEST_F(WebUIWorkerTest,
                       CanCreateSharedWorkerFromUntrustedIframe) {}

// Test that we can create a shared worker from a chrome-untrusted:// main
// frame.
IN_PROC_BROWSER_TEST_F(WebUIWorkerTest,
                       CanCreateUntrustedWebUISharedWorkerForUntrustedWebUI) {}

// Verify that chrome:// pages cannot create a SharedWorker with scheme
// "chrome-untrusted://".
IN_PROC_BROWSER_TEST_F(WebUIWorkerTest,
                       CannotCreateUntrustedWebUISharedWorkerFromTrustedWebUI) {}

// Verify that pages with scheme other than "chrome-untrusted://" cannot create
// a SharedWorker with scheme "chrome-untrusted://".
IN_PROC_BROWSER_TEST_F(WebUIWorkerTest,
                       CannotCreateUntrustedWebUISharedWorkerForWebURL) {}

// Verify that pages with scheme "chrome-untrusted://" cannot create a
// SharedWorker with scheme "chrome://".
IN_PROC_BROWSER_TEST_F(WebUIWorkerTest,
                       CannotCreateWebUISharedWorkerForUntrustedPage) {}

#endif  // !BUILDFLAG(IS_ANDROID)

// Verify that we can create a Worker with scheme "chrome://" under WebUI page.
IN_PROC_BROWSER_TEST_P(WebUIDedicatedWorkerTest,
                       CanCreateWebUIDedicatedWorkerForWebUI) {}

// Verify that pages with scheme other than "chrome://" cannot create a Worker
// with scheme "chrome://".
IN_PROC_BROWSER_TEST_P(WebUIDedicatedWorkerTest,
                       CannotCreateWebUIDedicatedWorkerForNonWebUI) {}

// Test that we can start a Worker from a chrome-untrusted:// iframe.
IN_PROC_BROWSER_TEST_P(WebUIDedicatedWorkerTest,
                       CanCreateDedicatedWorkerFromUntrustedIframe) {}

// Test that we can create a Worker from a chrome-untrusted:// main frame.
IN_PROC_BROWSER_TEST_P(
    WebUIDedicatedWorkerTest,
    CanCreateUntrustedWebUIDedicatedWorkerForUntrustedWebUI) {}

// Verify that chrome:// pages cannot create a Worker with scheme
// "chrome-untrusted://".
IN_PROC_BROWSER_TEST_P(
    WebUIDedicatedWorkerTest,
    CannotCreateUntrustedWebUIDedicatedWorkerFromTrustedWebUI) {}

// Verify that pages with scheme other than "chrome-untrusted://" cannot create
// a Worker with scheme "chrome-untrusted://".
IN_PROC_BROWSER_TEST_P(WebUIDedicatedWorkerTest,
                       CannotCreateUntrustedWebUIDedicatedWorkerForWebURL) {}

// Verify that pages with scheme "chrome-untrusted://" cannot create a Worker
// with scheme "chrome://".
IN_PROC_BROWSER_TEST_P(WebUIDedicatedWorkerTest,
                       CannotCreateWebUIDedicatedWorkerForUntrustedPage) {}

}  // namespace content