chromium/content/browser/renderer_host/blocked_scheme_navigation_browsertest.cc

// Copyright 2017 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/base64.h"
#include "base/command_line.h"
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/memory/raw_ptr.h"
#include "base/path_service.h"
#include "base/run_loop.h"
#include "base/strings/escape.h"
#include "base/strings/pattern.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/scoped_feature_list.h"
#include "build/build_config.h"
#include "build/buildflag.h"
#include "content/browser/site_per_process_browsertest.h"
#include "content/common/features.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/navigation_entry.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/content_paths.h"
#include "content/public/common/content_switches.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/content_browser_test_utils.h"
#include "content/public/test/download_test_observer.h"
#include "content/public/test/test_navigation_observer.h"
#include "content/shell/browser/shell.h"
#include "content/shell/browser/shell_download_manager_delegate.h"
#include "net/dns/mock_host_resolver.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
#include "storage/browser/file_system/external_mount_points.h"
#include "storage/common/file_system/file_system_mount_option.h"
#include "storage/common/file_system/file_system_types.h"
#include "third_party/blink/public/common/features.h"

#if BUILDFLAG(ENABLE_PLUGINS)
#include "content/public/browser/plugin_service.h"
#include "content/public/common/webplugininfo.h"
#endif

namespace content {

namespace {

// The pattern to catch messages printed by the browser when navigation to a
// URL is blocked. Navigation to filesystem: URLs uses a slightly different
// message than other blocked schemes, so use a wildcard to match both.
const char kNavigationBlockedMessage[] =;

// The message printed by the data or filesystem URL when it successfully
// navigates.
const char kNavigationSuccessfulMessage[] =;

// A "Hello World" pdf.
const char kPDF[] =;

enum ExpectedNavigationStatus {};

// A wrapper around WebContentsConsoleObserver that watches for a success or
// failure message. This will add a failure if an unexpected message is seen.
class BlockedURLWarningConsoleObserver {};

#if BUILDFLAG(ENABLE_PLUGINS)
// Registers a fake PDF plugin handler so that navigations with a PDF
// mime type end up with a navigation and don't simply download the file.
void RegisterFakePlugin() {}

void UnregisterFakePlugin() {}
#endif  // BUILDFLAG(ENABLE_PLUGINS)

}  // namespace

class BlockedSchemeNavigationBrowserTest
    : public ContentBrowserTest,
      public testing::WithParamInterface<const char*> {};

INSTANTIATE_TEST_SUITE_P();

////////////////////////////////////////////////////////////////////////////////
// Blocked schemes with HTML mimetype
//
// Tests that a browser initiated navigation to a blocked scheme doesn't show a
// console warning and is not blocked.
IN_PROC_BROWSER_TEST_P(BlockedSchemeNavigationBrowserTest,
                       BrowserInitiated_Allow) {}

// Tests that a content initiated navigation to a blocked scheme is blocked.
IN_PROC_BROWSER_TEST_P(BlockedSchemeNavigationBrowserTest,
                       HTML_Navigation_Block) {}

class DataUrlNavigationBrowserTestWithFeatureFlag
    : public BlockedSchemeNavigationBrowserTest {};

// Tests that a content initiated navigation to a data URL is allowed if
// blocking is disabled with a feature flag.
IN_PROC_BROWSER_TEST_F(DataUrlNavigationBrowserTestWithFeatureFlag,
                       HTML_Navigation_Allow_FeatureFlag) {}

// Tests that a window.open to a blocked scheme with HTML mime type is blocked.
IN_PROC_BROWSER_TEST_P(BlockedSchemeNavigationBrowserTest,
                       HTML_WindowOpen_Block) {}

// Tests that a form post to a blocked scheme with HTML mime type is blocked.
IN_PROC_BROWSER_TEST_P(BlockedSchemeNavigationBrowserTest,
                       HTML_FormPost_Block) {}

// Tests that clicking <a download> link downloads the URL even with a blocked
// scheme.
IN_PROC_BROWSER_TEST_P(BlockedSchemeNavigationBrowserTest, HTML_Download) {}

// Tests that navigating the main frame to a blocked scheme with HTML mimetype
// from a subframe is blocked.
// TODO: crbug.com/40943572 - Fix and re-enable the flaky test.
#if BUILDFLAG(IS_FUCHSIA)
#define MAYBE_HTML_NavigationFromFrame_Block
#else
#define MAYBE_HTML_NavigationFromFrame_Block
#endif
IN_PROC_BROWSER_TEST_P(BlockedSchemeNavigationBrowserTest,
                       MAYBE_HTML_NavigationFromFrame_Block) {}

// Tests that opening a new window with a blocked scheme from a subframe is
// blocked.
// TODO: crbug.com/40943572 - Fix and re-enable the flaky test.
#if BUILDFLAG(IS_FUCHSIA)
#define MAYBE_HTML_WindowOpenFromFrame_Block
#else
#define MAYBE_HTML_WindowOpenFromFrame_Block
#endif
IN_PROC_BROWSER_TEST_P(BlockedSchemeNavigationBrowserTest,
                       MAYBE_HTML_WindowOpenFromFrame_Block) {}

// Tests that navigation to a blocked scheme is blocked even if the top frame is
// already has a blocked scheme.
IN_PROC_BROWSER_TEST_P(BlockedSchemeNavigationBrowserTest,
                       HTML_Navigation_SameScheme_Block) {}

// Tests that a form post to a blocked scheme with HTML mime type is blocked
// even if the top frame is already a blocked scheme.
IN_PROC_BROWSER_TEST_P(BlockedSchemeNavigationBrowserTest,
                       HTML_FormPost_SameScheme_Block) {}

// Tests that navigating the top frame to a blocked scheme with HTML mimetype is
// blocked even if the top frame already has a blocked scheme.
// TODO: crbug.com/40943572 - Fix and re-enable the flaky test.
#if BUILDFLAG(IS_FUCHSIA)
#define MAYBE_HTML_NavigationFromFrame_TopFrameHasBlockedScheme_Block
#else
#define MAYBE_HTML_NavigationFromFrame_TopFrameHasBlockedScheme_Block
#endif
IN_PROC_BROWSER_TEST_P(
    BlockedSchemeNavigationBrowserTest,
    MAYBE_HTML_NavigationFromFrame_TopFrameHasBlockedScheme_Block) {}

// Tests that opening a new window with a blocked scheme with HTML mimetype is
// blocked even if the top frame already has a blocked scheme.
IN_PROC_BROWSER_TEST_P(
    BlockedSchemeNavigationBrowserTest,
    HTML_WindowOpenFromFrame_TopFrameHasBlockedScheme_Block) {}

////////////////////////////////////////////////////////////////////////////////
// Blocked schemes with octet-stream mimetype (binary)
//
// Test direct navigations to a binary mime types.
IN_PROC_BROWSER_TEST_P(BlockedSchemeNavigationBrowserTest,
                       OctetStream_BrowserInitiated) {}

#if BUILDFLAG(IS_ANDROID)
// Flaky on android: https://crbug.com/734563
#define MAYBE_DataUrl_OctetStream_WindowOpen
#else
#define MAYBE_DataUrl_OctetStream_WindowOpen
#endif

// Test window.open to a data URL with binary mimetype.
IN_PROC_BROWSER_TEST_F(BlockedSchemeNavigationBrowserTest,
                       MAYBE_DataUrl_OctetStream_WindowOpen) {}

// Test window.open to a filesystem URL with binary mimetype.
IN_PROC_BROWSER_TEST_F(BlockedSchemeNavigationBrowserTest,
                       FilesystemUrl_OctetStream_WindowOpen) {}

// Test navigation to a data URL with binary mimetype.
IN_PROC_BROWSER_TEST_F(BlockedSchemeNavigationBrowserTest,
                       DataUrl_OctetStream_Navigation) {}

// Test navigation to a filesystem URL with binary mimetype.
IN_PROC_BROWSER_TEST_F(BlockedSchemeNavigationBrowserTest,
                       FilesystemUrl_OctetStream_Navigation) {}

// Test form post to a data URL with binary mimetype.
IN_PROC_BROWSER_TEST_F(BlockedSchemeNavigationBrowserTest,
                       DataUrl_OctetStream_FormPost) {}

// Test form post to a filesystem URL with binary mimetype.
IN_PROC_BROWSER_TEST_F(BlockedSchemeNavigationBrowserTest,
                       FilesystemUrl_OctetStream_FormPost) {}

// Tests navigation of the main frame to a data URL with a binary mimetype
// from a subframe. These navigations should end up as downloads.
IN_PROC_BROWSER_TEST_F(BlockedSchemeNavigationBrowserTest,
                       DataUrl_OctetStream_NavigationFromFrame) {}

// Tests navigation of the main frame to a filesystem URL with a binary mimetype
// from a subframe. Navigations to filesystem URLs never end up as downloads.
// TODO(crbug.com/40943572): Enable the flaky test.
#if BUILDFLAG(IS_FUCHSIA)
#define MAYBE_FilesystemUrl_OctetStream_NavigationFromFrame
#else
#define MAYBE_FilesystemUrl_OctetStream_NavigationFromFrame
#endif
IN_PROC_BROWSER_TEST_F(BlockedSchemeNavigationBrowserTest,
                       MAYBE_FilesystemUrl_OctetStream_NavigationFromFrame) {}

////////////////////////////////////////////////////////////////////////////////
// URLs with unknown mimetype
//
// Test direct navigation to an unknown mime type.
IN_PROC_BROWSER_TEST_P(BlockedSchemeNavigationBrowserTest,
                       UnknownMimeType_BrowserInitiated_Download) {}

#if BUILDFLAG(IS_ANDROID)
// Flaky on android: https://crbug.com/734563
#define MAYBE_UnknownMimeType_WindowOpen
#else
#define MAYBE_UnknownMimeType_WindowOpen
#endif

// Test window.open to a blocked scheme with an unknown mime type.
IN_PROC_BROWSER_TEST_P(BlockedSchemeNavigationBrowserTest,
                       MAYBE_UnknownMimeType_WindowOpen) {}

// Test navigation to a data URL with an unknown mime type.
IN_PROC_BROWSER_TEST_F(BlockedSchemeNavigationBrowserTest,
                       DataUrl_UnknownMimeType_Navigation) {}

// Test navigation to a filesystem URL with an unknown mime type.
IN_PROC_BROWSER_TEST_F(BlockedSchemeNavigationBrowserTest,
                       FilesystemUrl_UnknownMimeType_Navigation) {}

// Test form post to a data URL with an unknown mime type.
IN_PROC_BROWSER_TEST_F(BlockedSchemeNavigationBrowserTest,
                       DataUrl_UnknownMimeType_FormPost) {}

// Test form post to a filesystem URL with an unknown mime type.
IN_PROC_BROWSER_TEST_F(BlockedSchemeNavigationBrowserTest,
                       FilesystemUrl_UnknownMimeType_FormPost) {}

// Test navigation of the main frame to a data URL with an unknown mimetype from
// a subframe. These navigations should end up as downloads.
IN_PROC_BROWSER_TEST_F(BlockedSchemeNavigationBrowserTest,
                       DataUrl_UnknownMimeType_NavigationFromFrame) {}

// Test navigation of the main frame to a filesystem URL with an unknown
// mimetype from a subframe. Navigations to filesystem URLs don't end up as
// downloads.
// TODO(crbug.com/40943572): Enable the flaky test.
#if BUILDFLAG(IS_FUCHSIA)
#define MAYBE_FilesystemUrl_UnknownMimeType_NavigationFromFrame
#else
#define MAYBE_FilesystemUrl_UnknownMimeType_NavigationFromFrame
#endif
IN_PROC_BROWSER_TEST_F(
    BlockedSchemeNavigationBrowserTest,
    MAYBE_FilesystemUrl_UnknownMimeType_NavigationFromFrame) {}

////////////////////////////////////////////////////////////////////////////////
// URLs with PDF mimetype
//
// Tests that a browser initiated navigation to a blocked scheme URL with PDF
// mime type is allowed, or initiates a download on Android.
IN_PROC_BROWSER_TEST_P(BlockedSchemeNavigationBrowserTest,
                       PDF_BrowserInitiatedNavigation_Allow) {}

// Tests that a window.open to a blocked scheme is blocked if the URL has a
// mime type that will be handled by a plugin (PDF in this case).
IN_PROC_BROWSER_TEST_P(BlockedSchemeNavigationBrowserTest,
                       PDF_WindowOpen_Block) {}

// Test that a navigation to a blocked scheme URL is blocked if the URL has a
// mime type that will be handled by a plugin (PDF in this case).
IN_PROC_BROWSER_TEST_P(BlockedSchemeNavigationBrowserTest,
                       PDF_Navigation_Block) {}

// Test that a form post to a blocked scheme is blocked if the URL has a mime
// type that will be handled by a plugin (PDF in this case).
IN_PROC_BROWSER_TEST_P(BlockedSchemeNavigationBrowserTest, PDF_FormPost_Block) {}

// Tests that navigating the main frame to a blocked scheme with PDF mimetype
// from a subframe is blocked, or is downloaded on Android.
// TODO: crbug.com/40943572 - Fix and re-enable the flaky test.
#if BUILDFLAG(IS_FUCHSIA)
#define MAYBE_PDF_NavigationFromFrame_Block
#else
#define MAYBE_PDF_NavigationFromFrame_Block
#endif
IN_PROC_BROWSER_TEST_P(BlockedSchemeNavigationBrowserTest,
                       MAYBE_PDF_NavigationFromFrame_Block) {}

// Tests that opening a window with a blocked scheme with PDF mimetype from a
// subframe is blocked, or is downloaded on Android.
IN_PROC_BROWSER_TEST_P(BlockedSchemeNavigationBrowserTest,
                       PDF_WindowOpenFromFrame_Block) {}

// Tests that navigating the top frame to a blocked scheme with PDF mimetype
// from a subframe is blocked even if the top frame already has a blocked
// scheme.
IN_PROC_BROWSER_TEST_P(BlockedSchemeNavigationBrowserTest,
                       PDF_NavigationFromFrame_TopFrameHasBlockedScheme_Block) {}

// Tests that opening a window with a blocked scheme with PDF mimetype from a
// subframe is blocked even if the top frame already has a blocked scheme.
IN_PROC_BROWSER_TEST_P(BlockedSchemeNavigationBrowserTest,
                       PDF_WindowOpenFromFrame_TopFrameHasBlockedScheme_Block) {}

// Test case to verify that redirects to blocked schemes are properly
// disallowed, even when invoked through history navigations. See
// https://crbug.com/723796.
IN_PROC_BROWSER_TEST_P(BlockedSchemeNavigationBrowserTest,
                       WindowOpenRedirectAndBack) {}

class FilesystemUrlNavigationBrowserTest
    : public ContentBrowserTest,
      public testing::WithParamInterface<bool> {};

// Tests that navigation to external mounted filesystem: URLs are blocked
// unless FileSystemUrlNavigation feature flag is enabled (b/291526810).
IN_PROC_BROWSER_TEST_P(FilesystemUrlNavigationBrowserTest, External) {}

INSTANTIATE_TEST_SUITE_P();

}  // namespace content