chromium/chrome/browser/chrome_navigation_browsertest.cc

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

#include "base/command_line.h"
#include "base/feature_list.h"
#include "base/memory/raw_ptr.h"
#include "base/run_loop.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/task/single_thread_task_runner.h"
#include "base/test/bind.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/test_timeouts.h"
#include "build/build_config.h"
#include "chrome/app/chrome_command_ids.h"
#include "chrome/browser/devtools/protocol/devtools_protocol_test_support.h"
#include "chrome/browser/extensions/chrome_test_extension_loader.h"
#include "chrome/browser/login_detection/login_detection_util.h"
#include "chrome/browser/renderer_context_menu/render_view_context_menu_test_util.h"
#include "chrome/browser/tab_contents/navigation_metrics_recorder.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_commands.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/location_bar/location_bar.h"
#include "chrome/browser/ui/sad_tab_helper.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/browser/ui/toolbar/back_forward_menu_model.h"
#include "chrome/common/chrome_features.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/url_constants.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/ui_test_utils.h"
#include "components/network_session_configurator/common/network_switches.h"
#include "components/omnibox/browser/omnibox_view.h"
#include "components/prefs/pref_service.h"
#include "components/site_isolation/features.h"
#include "components/site_isolation/pref_names.h"
#include "components/ukm/test_ukm_recorder.h"
#include "components/url_formatter/url_formatter.h"
#include "components/variations/active_field_trials.h"
#include "components/variations/hashing.h"
#include "content/common/content_navigation_policy.h"
#include "content/public/browser/child_process_security_policy.h"
#include "content/public/browser/context_menu_params.h"
#include "content/public/browser/download_manager_delegate.h"
#include "content/public/browser/navigation_entry.h"
#include "content/public/browser/navigation_handle.h"
#include "content/public/browser/reload_type.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_widget_host_view.h"
#include "content/public/browser/site_isolation_policy.h"
#include "content/public/browser/storage_partition.h"
#include "content/public/browser/web_contents_observer.h"
#include "content/public/common/content_features.h"
#include "content/public/common/content_switches.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/download_test_observer.h"
#include "content/public/test/navigation_handle_observer.h"
#include "content/public/test/test_navigation_observer.h"
#include "content/public/test/url_loader_interceptor.h"
#include "extensions/test/extension_test_message_listener.h"
#include "extensions/test/test_extension_dir.h"
#include "google_apis/gaia/gaia_switches.h"
#include "net/dns/mock_host_resolver.h"
#include "pdf/buildflags.h"
#include "services/metrics/public/cpp/ukm_builders.h"
#include "services/network/public/cpp/features.h"
#include "services/network/public/cpp/network_switches.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "third_party/blink/public/common/features.h"
#include "third_party/blink/public/common/page_state/page_state.h"
#include "third_party/blink/public/mojom/context_menu/context_menu.mojom.h"
#include "third_party/blink/public/mojom/use_counter/metrics/web_feature.mojom-shared.h"

IsEmpty;
UnorderedElementsAre;

class ChromeNavigationBrowserTest : public InProcessBrowserTest {};

// Tests that viewing frame source on a local file:// page with an iframe
// with a remote URL shows the correct tab title.
IN_PROC_BROWSER_TEST_F(ChromeNavigationBrowserTest, TestViewFrameSource) {}

// Base class for ctrl+click tests, which contains all the common functionality
// independent from which process the navigation happens in. Each subclass
// defines its own expectations depending on the conditions of the test.
class CtrlClickProcessTest : public ChromeNavigationBrowserTest {};

// Tests that verify that ctrl-click results 1) open up in a new renderer
// process (https://crbug.com/23815) and 2) are in a new BrowsingInstance (e.g.
// cannot find the opener's window by name - https://crbug.com/658386).
class CtrlClickShouldEndUpInNewProcessTest : public CtrlClickProcessTest {};

IN_PROC_BROWSER_TEST_F(CtrlClickShouldEndUpInNewProcessTest, NoTarget) {}

IN_PROC_BROWSER_TEST_F(CtrlClickShouldEndUpInNewProcessTest, BlankTarget) {}

IN_PROC_BROWSER_TEST_F(CtrlClickShouldEndUpInNewProcessTest, SubframeTarget) {}

// Similar to the tests above, but verifies that the new WebContents ends up in
// the same process as the opener when it is exceeding the process limit.
// See https://crbug.com/774723.
class CtrlClickShouldEndUpInSameProcessTest : public CtrlClickProcessTest {};

IN_PROC_BROWSER_TEST_F(CtrlClickShouldEndUpInSameProcessTest, NoTarget) {}

IN_PROC_BROWSER_TEST_F(CtrlClickShouldEndUpInSameProcessTest, BlankTarget) {}

IN_PROC_BROWSER_TEST_F(CtrlClickShouldEndUpInSameProcessTest, SubframeTarget) {}

// Test to verify that spoofing a URL via a redirect from a slightly malformed
// URL doesn't work.  See also https://crbug.com/657720.
IN_PROC_BROWSER_TEST_F(ChromeNavigationBrowserTest,
                       ContextMenuNavigationToInvalidUrl) {}

// Ensure that URL transformations do not let a webpage populate the Omnibox
// with a javascript: URL.  See https://crbug.com/850824 and
// https://crbug.com/1116280.
IN_PROC_BROWSER_TEST_F(ChromeNavigationBrowserTest,
                       ClearInvalidPendingURLOnFail) {}

// A test performing two simultaneous navigations, to ensure code in chrome/,
// such as tab helpers, can handle those cases.
// This test starts a browser-initiated cross-process navigation, which is
// delayed. At the same time, the renderer does a synchronous navigation
// through pushState, which will create a separate navigation and associated
// NavigationHandle. Afterwards, the original cross-process navigation is
// resumed and confirmed to properly commit.
IN_PROC_BROWSER_TEST_F(ChromeNavigationBrowserTest,
                       SlowCrossProcessNavigationWithPushState) {}

// Check that if a page has an iframe that loads an error page, that error page
// does not inherit the Content Security Policy from the parent frame.  See
// https://crbug.com/703801.  This test is in chrome/ because error page
// behavior is only fully defined in chrome/.
IN_PROC_BROWSER_TEST_F(ChromeNavigationBrowserTest,
                       ErrorPageDoesNotInheritCSP) {}

// Test that web pages can't navigate to an error page URL, either directly or
// via a redirect, and that web pages can't embed error pages in iframes.
IN_PROC_BROWSER_TEST_F(ChromeNavigationBrowserTest,
                       NavigationToErrorURLIsDisallowed) {}

// This test ensures that navigating to a page that returns an error code and
// an empty document still shows Chrome's helpful error page instead of the
// empty document.
IN_PROC_BROWSER_TEST_F(ChromeNavigationBrowserTest,
                       EmptyDocumentWithErrorCode) {}

// Test for https://crbug.com/866549#c2. It verifies that about:blank does not
// commit in the error page process when it is redirected to.
IN_PROC_BROWSER_TEST_F(ChromeNavigationBrowserTest,
                       RedirectErrorPageReloadToAboutBlank) {}

// This test covers a navigation that:
// 1. is initiated by a cross-site initiator,
// 2. gets redirected via webRequest API to about:blank.
// This is a regression test for https://crbug.com/1026738.
IN_PROC_BROWSER_TEST_F(
    ChromeNavigationBrowserTest,
    NavigationInitiatedByCrossSiteSubframeRedirectedToAboutBlank) {}

// This test covers a navigation that:
// 1. is initiated by a cross-site initiator,
// 2. gets redirected via webRequest API to a data: URL
// This covers a scenario similar to the one that led to crashes in
// https://crbug.com/1026738.
IN_PROC_BROWSER_TEST_F(
    ChromeNavigationBrowserTest,
    NavigationInitiatedByCrossSiteSubframeRedirectedToDataUrl) {}

// This test covers a navigation that:
// 1. is initiated by a cross-site initiator,
// 2. is a history navigation,
// 3. gets redirected via webRequest API to a data: URL, but the original
// navigation (that created the history entry) didn't get redirected.
// This covers a scenario similar to the one that led to crashes in
// https://crbug.com/40065692.
IN_PROC_BROWSER_TEST_F(ChromeNavigationBrowserTest,
                       HistoryNavigationRedirectedToDataUrl) {}

// Same as above but the history navigation got redirected to about:blank
// instead.
// TODO(crbug.com/40266169): This is currently disabled because of
// a bug where we will reuse the previous SiteInstance on the about:blank
// navigation, even if the origins don't match, resulting in a CHECK failure
// during the redirect on step 4. See also the TODO with the same bug number in
// `SiteInstanceImpl::IsSameSite()`.
IN_PROC_BROWSER_TEST_F(ChromeNavigationBrowserTest,
                       DISABLED_HistoryNavigationRedirectedToAboutBlank) {}

// Same as above but the history navigation is same-site with the previous page,
// so the crash won't happen as the navigation is reusing the same SiteInstance.
IN_PROC_BROWSER_TEST_F(ChromeNavigationBrowserTest,
                       HistoryNavigationRedirectedToAboutBlank_SameSite) {}

// Tests scenario where a blank iframe inside a blank popup (a popup with only
// the initial navigation entry) does a same document navigation. This test was
// added as a regression test for crbug.com/1237874. The main purpose of this
// test is to ensure that WebContentsObservers and Chrome features don't crash.
IN_PROC_BROWSER_TEST_F(ChromeNavigationBrowserTest,
                       SameDocumentNavigationInIframeInBlankDocument) {}

// Test scenario where we attempt a synchronous renderer-initiated same-document
// navigation inside a blank popup (a popup with only the initial navigation
// entry). Regression test for crbug.com/1254238. The main purpose of this test
// is to ensure that WebContentsObservers and Chrome features don't crash.
IN_PROC_BROWSER_TEST_F(ChromeNavigationBrowserTest,
                       SameDocumentNavigationInBlankPopup) {}

class SignInIsolationBrowserTest : public ChromeNavigationBrowserTest {};

// This test ensures that the sign-in origin requires a dedicated process.  It
// only ensures that the sign-in origin is added as an isolated origin at
// chrome/ layer; IsolatedOriginTest provides the main test coverage of origins
// whitelisted for process isolation.  See https://crbug.com/739418.
IN_PROC_BROWSER_TEST_F(SignInIsolationBrowserTest, NavigateToSignInPage) {}

class WebstoreIsolationBrowserTest : public ChromeNavigationBrowserTest {};

// Tests that Chrome Web Store URL used by the hosted app in production
// (chrome.google.com/webstore/) is isolated from the rest of google.com and
// other chrome.google.com pages not in the /webstore/ path. See
// https://crbug.com/939108.
IN_PROC_BROWSER_TEST_F(WebstoreIsolationBrowserTest, WebstorePopupIsIsolated) {}

// Make sure that the new Chrome Web Store URL used in production
// (chromewebstore.google.com) is isolated from the rest of the google.com
// domain.
IN_PROC_BROWSER_TEST_F(WebstoreIsolationBrowserTest,
                       NewWebstorePopupIsIsolated) {}

class WebstoreOverrideIsolationBrowserTest
    : public WebstoreIsolationBrowserTest {};

// Make sure that Chrome Web Store origins are isolated from the rest of their
// site when overriding the URL from the command line. See
// https://crbug.com/939108.
IN_PROC_BROWSER_TEST_F(WebstoreOverrideIsolationBrowserTest,
                       WebstorePopupIsIsolated) {}

// Check that it's possible to navigate to a chrome scheme URL from a crashed
// tab. See https://crbug.com/764641.
IN_PROC_BROWSER_TEST_F(ChromeNavigationBrowserTest, ChromeSchemeNavFromSadTab) {}

// Check that a browser-initiated navigation to a cross-site URL that then
// redirects to a pdf hosted on another site works.
IN_PROC_BROWSER_TEST_F(ChromeNavigationBrowserTest, CrossSiteRedirectionToPDF) {}

ChromeNavigationBrowserTestWithMobileEmulation;

// Tests the behavior of navigating to a PDF when mobile emulation is enabled.
IN_PROC_BROWSER_TEST_F(ChromeNavigationBrowserTestWithMobileEmulation,
                       NavigateToPDFWithMobileEmulation) {}

// Tests the behavior of cross origin redirection to a PDF with mobile emulation
// is enabled.
IN_PROC_BROWSER_TEST_F(ChromeNavigationBrowserTestWithMobileEmulation,
                       CrossSiteRedirectionToPDFWithMobileEmulation) {}

// Check that clicking on a link doesn't carry the transient user activation
// from the original page to the navigated page (crbug.com/865243).
IN_PROC_BROWSER_TEST_F(ChromeNavigationBrowserTest,
                       WindowOpenBlockedAfterClickNavigation) {}

IN_PROC_BROWSER_TEST_F(ChromeNavigationBrowserTest,
                       OpenerNavigation_DownloadPolicy_Disallowed) {}

// Opener navigations from a same-origin popup should be allowed.
IN_PROC_BROWSER_TEST_F(ChromeNavigationBrowserTest,
                       OpenerNavigation_DownloadPolicy_Allowed) {}

// Test which verifies that a noopener link/window.open() properly focus the
// newly opened tab. See https://crbug.com/912348.
IN_PROC_BROWSER_TEST_F(ChromeNavigationBrowserTest,
                       NoopenerCorrectlyFocusesNewTab) {}

// Tests the ukm entry logged when the navigation entry is marked as skippable
// on back/forward button on doing a renderer initiated navigation without ever
// getting a user activation.
IN_PROC_BROWSER_TEST_F(ChromeNavigationBrowserTest,
                       NoUserActivationSetSkipOnBackForward) {}

// Same as above except the navigation is cross-site.
IN_PROC_BROWSER_TEST_F(ChromeNavigationBrowserTest,
                       NoUserActivationSetSkipOnBackForwardCrossSite) {}

// Ensure that starting a navigation out of a sad tab hides the sad tab right
// away, without waiting for the navigation to commit and restores it again
// after cancelling.
void ChromeNavigationBrowserTest::
    ExpectHideAndRestoreSadTabWhenNavigationCancels(bool cross_site) {}

// Ensure that starting a navigation out of a sad tab hides the sad tab right
// away, without waiting for the navigation to commit and restores it again
// after cancelling.
IN_PROC_BROWSER_TEST_F(ChromeNavigationBrowserTest,
                       RestoreSadTabWhenNavigationCancels_CrossSite) {}

// Same-site version of above.
IN_PROC_BROWSER_TEST_F(ChromeNavigationBrowserTest,
                       RestoreSadTabWhenNavigationCancels_SameSite) {}

// Ensure that completing a navigation from a sad tab will clear the sad tab.
void ChromeNavigationBrowserTest::ExpectHideSadTabWhenNavigationCompletes(
    bool cross_site) {}

// Flaky, see https://crbug.com/1223052 and https://crbug.com/1236500.
// Ensure that completing a navigation from a sad tab will clear the sad tab.
IN_PROC_BROWSER_TEST_F(ChromeNavigationBrowserTest,
                       DISABLED_ClearSadTabWhenNavigationCompletes_CrossSite) {}

// Same-site version of above.
IN_PROC_BROWSER_TEST_F(ChromeNavigationBrowserTest,
                       ClearSadTabWhenNavigationCompletes_SameSite) {}

// TODO(csharrison): These tests should become tentative WPT, once the feature
// is enabled by default.
NavigationConsumingTest;

// The fullscreen API is spec'd to require a user activation (aka user gesture),
// so use that API to test if navigation consumes the activation.
// https://fullscreen.spec.whatwg.org/#allowed-to-request-fullscreen
// https://crbug.com/1283289 Flaky on ChromeOS.
#if BUILDFLAG(IS_CHROMEOS)
#define MAYBE_NavigationConsumesUserGesture_Fullscreen
#else
#define MAYBE_NavigationConsumesUserGesture_Fullscreen
#endif
IN_PROC_BROWSER_TEST_F(NavigationConsumingTest,
                       MAYBE_NavigationConsumesUserGesture_Fullscreen) {}

// Similar to the fullscreen test above, but checks that popups are successfully
// blocked if spawned after a navigation.
IN_PROC_BROWSER_TEST_F(NavigationConsumingTest,
                       NavigationConsumesUserGesture_Popups) {}

// Regression test for https://crbug.com/856779, where a navigation to a
// top-level, same process frame in another tab fails to focus that tab.
IN_PROC_BROWSER_TEST_F(NavigationConsumingTest, TargetNavigationFocus) {}

HistoryManipulationInterventionBrowserTest;

// Tests that chrome::GoBack does nothing if all the previous entries are marked
// as skippable and the back button is disabled.
IN_PROC_BROWSER_TEST_F(HistoryManipulationInterventionBrowserTest,
                       AllEntriesSkippableBackButtonDisabled) {}

// Tests that chrome::GoBack is successful if there is at least one entry not
// marked as skippable and the back button should be enabled.
IN_PROC_BROWSER_TEST_F(HistoryManipulationInterventionBrowserTest,
                       AllEntriesNotSkippableBackButtonEnabled) {}

#if BUILDFLAG(ENABLE_PDF)
// Tests that a main frame hosting pdf does not get skipped because of history
// manipulation intervention if there was a user gesture.
// TODO(crbug.com/333829580): Flaky.
IN_PROC_BROWSER_TEST_F(HistoryManipulationInterventionBrowserTest,
                       DISABLED_PDFDoNotSkipOnBackForwardDueToUserGesture) {}

// Tests that a main frame hosting pdf gets skipped because of history
// manipulation intervention if there was no user gesture.
// TODO(crbug.com/333829580): Flaky.
IN_PROC_BROWSER_TEST_F(HistoryManipulationInterventionBrowserTest,
                       DISABLED_PDFSkipOnBackForwardNoUserGesture) {}
#endif  // BUILDFLAG(ENABLE_PDF)

// This test class turns on the mode where sites where the user enters a
// password are dynamically added to the list of sites requiring a dedicated
// process.  It also disables strict site isolation so that the effects of
// password isolation can be observed.
class SiteIsolationForPasswordSitesBrowserTest
    : public ChromeNavigationBrowserTest {};

// Verifies that a site gets process-isolated after a password is typed on a
// page from that site.
IN_PROC_BROWSER_TEST_F(SiteIsolationForPasswordSitesBrowserTest,
                       SiteIsIsolatedAfterEnteringPassword) {}

// Verifies that persistent isolated sites survive restarts.  Part 1.
IN_PROC_BROWSER_TEST_F(SiteIsolationForPasswordSitesBrowserTest,
                       PRE_IsolatedSitesPersistAcrossRestarts) {}

// Verifies that process-isolated sites persist across restarts.  Part 2.
// This runs after Part 1 above and in the same profile.  Part 1 has already
// added "saved.com" as a persisted isolated origin, so this part verifies that
// it requires a dedicated process after restart.
IN_PROC_BROWSER_TEST_F(SiteIsolationForPasswordSitesBrowserTest,
                       IsolatedSitesPersistAcrossRestarts) {}

// Verify that trying to isolate a site multiple times will only save it to
// disk once.
IN_PROC_BROWSER_TEST_F(SiteIsolationForPasswordSitesBrowserTest,
                       IsolatedSiteIsSavedOnlyOnce) {}

// Check that Incognito doesn't inherit saved isolated origins from its
// original profile, and that any isolated origins added in Incognito don't
// affect the original profile.
IN_PROC_BROWSER_TEST_F(SiteIsolationForPasswordSitesBrowserTest,
                       IncognitoWithIsolatedSites) {}

// Verify that serving a Clear-Site-Data header does not clear saved isolated
// sites.  Saved isolated sites should only be cleared by user-initiated
// actions. (Note: Clear-Site-Data is only available on HTTPS URLs.)
IN_PROC_BROWSER_TEST_F(SiteIsolationForPasswordSitesBrowserTest,
                       ClearSiteDataDoesNotClearSavedIsolatedSites) {}

// This test class turns on the feature to dynamically isolate sites where the
// user logs in via OAuth. This also requires enabling OAuth login detection
// (which is used by other features as well) and disabling strict site
// isolation (so that OAuth isolation can be observed on desktop platforms).
class SiteIsolationForOAuthSitesBrowserTest
    : public ChromeNavigationBrowserTest {};

// Simulate a popup-based OAuth login flow, where a client opens a popup to log
// in via OAuth.  Ensure that the client's site becomes isolated when the OAuth
// login completes.
IN_PROC_BROWSER_TEST_F(SiteIsolationForOAuthSitesBrowserTest, PopupFlow) {}

// Similar to previous test, but simulate a same-window OAuth login flow, where
// a client navigates directly to the OAuth provider, which will
// navigate/redirect back to the client when the login flow completes.
//
// Part 2 of this test also verifies that OAuth site isolation persists across
// restarts.
IN_PROC_BROWSER_TEST_F(SiteIsolationForOAuthSitesBrowserTest,
                       PRE_RedirectFlow) {}

// See part 1 of the test above.  This is part 2, which verifies that OAuth
// site isolation persists across restarts.
IN_PROC_BROWSER_TEST_F(SiteIsolationForOAuthSitesBrowserTest, RedirectFlow) {}

// This test class turns on the mode where sites served with
// Cross-Origin-Opener-Policy headers are site-isolated.  This complements
// COOPIsolationTest in content_browsertests and focuses on persistence of COOP
// sites in user prefs, which requires the //chrome layer.
class SiteIsolationForCOOPBrowserTest : public ChromeNavigationBrowserTest {};

// Verifies that sites isolated due to COOP headers are persisted across
// restarts.  Note that persistence requires both visiting the COOP site and
// interacting with it via a user activation.  Part 1/2.
IN_PROC_BROWSER_TEST_F(SiteIsolationForCOOPBrowserTest,
                       PRE_PersistAcrossRestarts) {}

// Verifies that sites isolated due to COOP headers with a user activation are
// persisted across restarts.  Part 2/2.
IN_PROC_BROWSER_TEST_F(SiteIsolationForCOOPBrowserTest, PersistAcrossRestarts) {}

// Check that COOP sites are not persisted in Incognito; the isolation should
// only persist for the duration of the Incognito session.
IN_PROC_BROWSER_TEST_F(SiteIsolationForCOOPBrowserTest, Incognito) {}

// Verify that when a COOP-isolated site is visited again, the timestamp in its
// stored pref entry is updated correctly and taken into consideration when
// trimming the list of stored COOP sites to its maximum size.
IN_PROC_BROWSER_TEST_F(SiteIsolationForCOOPBrowserTest,
                       TimestampUpdateOnSecondVisit) {}