blob: 99a57ca8f444bf0a9c3a41a3036e34080d2577b6 [file] [log] [blame]
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/chrome_content_browser_client.h"
#include <list>
#include <map>
#include <memory>
#include "base/bind.h"
#include "base/command_line.h"
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/message_loop/message_loop.h"
#include "base/metrics/field_trial.h"
#include "base/run_loop.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
#include "chrome/browser/browsing_data/browsing_data_helper.h"
#include "chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.h"
#include "chrome/browser/search_engines/template_url_service_factory.h"
#include "chrome/test/base/testing_profile.h"
#include "components/content_settings/core/browser/host_content_settings_map.h"
#include "components/search_engines/template_url_service.h"
#include "components/variations/entropy_provider.h"
#include "components/variations/variations_associated_data.h"
#include "components/version_info/version_info.h"
#include "content/public/browser/browsing_data_filter_builder.h"
#include "content/public/browser/browsing_data_remover.h"
#include "content/public/browser/navigation_controller.h"
#include "content/public/browser/navigation_entry.h"
#include "content/public/browser/storage_partition.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/content_switches.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "media/media_features.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
#if !defined(OS_ANDROID)
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/base/browser_with_test_window_test.h"
#include "chrome/test/base/search_test_utils.h"
#endif
#if defined(OS_CHROMEOS)
#include "ash/public/interfaces/constants.mojom.h"
#include "content/public/common/service_names.mojom.h"
#include "services/ui/public/interfaces/constants.mojom.h"
#endif
using content::BrowsingDataFilterBuilder;
using testing::_;
using ChromeContentBrowserClientTest = testing::Test;
TEST_F(ChromeContentBrowserClientTest, ShouldAssignSiteForURL) {
ChromeContentBrowserClient client;
EXPECT_FALSE(client.ShouldAssignSiteForURL(GURL("chrome-native://test")));
EXPECT_TRUE(client.ShouldAssignSiteForURL(GURL("http://www.google.com")));
EXPECT_TRUE(client.ShouldAssignSiteForURL(GURL("https://www.google.com")));
}
// BrowserWithTestWindowTest doesn't work on Android.
#if !defined(OS_ANDROID)
using ChromeContentBrowserClientWindowTest = BrowserWithTestWindowTest;
static void DidOpenURLForWindowTest(content::WebContents** target_contents,
content::WebContents* opened_contents) {
DCHECK(target_contents);
*target_contents = opened_contents;
}
TEST_F(ChromeContentBrowserClientWindowTest, IsDataSaverEnabled) {
ChromeContentBrowserClient client;
content::BrowserContext* context = browser()->profile();
EXPECT_FALSE(client.IsDataSaverEnabled(context));
browser()->profile()->GetPrefs()->SetBoolean(prefs::kDataSaverEnabled, true);
EXPECT_TRUE(client.IsDataSaverEnabled(context));
}
// This test opens two URLs using ContentBrowserClient::OpenURL. It expects the
// URLs to be opened in new tabs and activated, changing the active tabs after
// each call and increasing the tab count by 2.
TEST_F(ChromeContentBrowserClientWindowTest, OpenURL) {
ChromeContentBrowserClient client;
int previous_count = browser()->tab_strip_model()->count();
GURL urls[] = { GURL("https://www.google.com"),
GURL("https://www.chromium.org") };
for (const GURL& url : urls) {
content::OpenURLParams params(url, content::Referrer(),
WindowOpenDisposition::NEW_FOREGROUND_TAB,
ui::PAGE_TRANSITION_AUTO_TOPLEVEL, false);
// TODO(peter): We should have more in-depth browser tests for the window
// opening functionality, which also covers Android. This test can currently
// only be ran on platforms where OpenURL is implemented synchronously.
// See https://crbug.com/457667.
content::WebContents* web_contents = nullptr;
client.OpenURL(browser()->profile(),
params,
base::Bind(&DidOpenURLForWindowTest, &web_contents));
EXPECT_TRUE(web_contents);
content::WebContents* active_contents = browser()->tab_strip_model()->
GetActiveWebContents();
EXPECT_EQ(web_contents, active_contents);
EXPECT_EQ(url, active_contents->GetVisibleURL());
}
EXPECT_EQ(previous_count + 2, browser()->tab_strip_model()->count());
}
#endif // !defined(OS_ANDROID)
#if BUILDFLAG(ENABLE_WEBRTC)
// NOTE: Any updates to the expectations in these tests should also be done in
// the browser test WebRtcDisableEncryptionFlagBrowserTest.
class DisableWebRtcEncryptionFlagTest : public testing::Test {
public:
DisableWebRtcEncryptionFlagTest()
: from_command_line_(base::CommandLine::NO_PROGRAM),
to_command_line_(base::CommandLine::NO_PROGRAM) {}
protected:
void SetUp() override {
from_command_line_.AppendSwitch(switches::kDisableWebRtcEncryption);
}
void MaybeCopyDisableWebRtcEncryptionSwitch(version_info::Channel channel) {
ChromeContentBrowserClient::MaybeCopyDisableWebRtcEncryptionSwitch(
&to_command_line_,
from_command_line_,
channel);
}
base::CommandLine from_command_line_;
base::CommandLine to_command_line_;
private:
DISALLOW_COPY_AND_ASSIGN(DisableWebRtcEncryptionFlagTest);
};
TEST_F(DisableWebRtcEncryptionFlagTest, UnknownChannel) {
MaybeCopyDisableWebRtcEncryptionSwitch(version_info::Channel::UNKNOWN);
EXPECT_TRUE(to_command_line_.HasSwitch(switches::kDisableWebRtcEncryption));
}
TEST_F(DisableWebRtcEncryptionFlagTest, CanaryChannel) {
MaybeCopyDisableWebRtcEncryptionSwitch(version_info::Channel::CANARY);
EXPECT_TRUE(to_command_line_.HasSwitch(switches::kDisableWebRtcEncryption));
}
TEST_F(DisableWebRtcEncryptionFlagTest, DevChannel) {
MaybeCopyDisableWebRtcEncryptionSwitch(version_info::Channel::DEV);
EXPECT_TRUE(to_command_line_.HasSwitch(switches::kDisableWebRtcEncryption));
}
TEST_F(DisableWebRtcEncryptionFlagTest, BetaChannel) {
MaybeCopyDisableWebRtcEncryptionSwitch(version_info::Channel::BETA);
#if defined(OS_ANDROID)
EXPECT_TRUE(to_command_line_.HasSwitch(switches::kDisableWebRtcEncryption));
#else
EXPECT_FALSE(to_command_line_.HasSwitch(switches::kDisableWebRtcEncryption));
#endif
}
TEST_F(DisableWebRtcEncryptionFlagTest, StableChannel) {
MaybeCopyDisableWebRtcEncryptionSwitch(version_info::Channel::STABLE);
EXPECT_FALSE(to_command_line_.HasSwitch(switches::kDisableWebRtcEncryption));
}
#endif // ENABLE_WEBRTC
class BlinkSettingsFieldTrialTest : public testing::Test {
public:
static const char kDisallowFetchFieldTrialName[];
static const char kCSSExternalScannerFieldTrialName[];
static const char kFakeGroupName[];
BlinkSettingsFieldTrialTest()
: trial_list_(NULL),
command_line_(base::CommandLine::NO_PROGRAM) {}
void SetUp() override {
command_line_.AppendSwitchASCII(
switches::kProcessType, switches::kRendererProcess);
}
void TearDown() override {
variations::testing::ClearAllVariationParams();
}
void CreateFieldTrial(const char* trial_name, const char* group_name) {
base::FieldTrialList::CreateFieldTrial(trial_name, group_name);
}
void CreateFieldTrialWithParams(
const char* trial_name,
const char* group_name,
const char* key1, const char* value1,
const char* key2, const char* value2) {
std::map<std::string, std::string> params;
params.insert(std::make_pair(key1, value1));
params.insert(std::make_pair(key2, value2));
CreateFieldTrial(trial_name, kFakeGroupName);
variations::AssociateVariationParams(trial_name, kFakeGroupName, params);
}
void AppendContentBrowserClientSwitches() {
client_.AppendExtraCommandLineSwitches(&command_line_, kFakeChildProcessId);
}
const base::CommandLine& command_line() const {
return command_line_;
}
void AppendBlinkSettingsSwitch(const char* value) {
command_line_.AppendSwitchASCII(switches::kBlinkSettings, value);
}
private:
static const int kFakeChildProcessId = 1;
ChromeContentBrowserClient client_;
base::FieldTrialList trial_list_;
base::CommandLine command_line_;
content::TestBrowserThreadBundle thread_bundle_;
};
const char BlinkSettingsFieldTrialTest::kDisallowFetchFieldTrialName[] =
"DisallowFetchForDocWrittenScriptsInMainFrame";
const char BlinkSettingsFieldTrialTest::kCSSExternalScannerFieldTrialName[] =
"CSSExternalScanner";
const char BlinkSettingsFieldTrialTest::kFakeGroupName[] = "FakeGroup";
TEST_F(BlinkSettingsFieldTrialTest, NoFieldTrial) {
AppendContentBrowserClientSwitches();
EXPECT_FALSE(command_line().HasSwitch(switches::kBlinkSettings));
}
TEST_F(BlinkSettingsFieldTrialTest, FieldTrialWithoutParams) {
CreateFieldTrial(kDisallowFetchFieldTrialName, kFakeGroupName);
AppendContentBrowserClientSwitches();
EXPECT_FALSE(command_line().HasSwitch(switches::kBlinkSettings));
}
TEST_F(BlinkSettingsFieldTrialTest, BlinkSettingsSwitchAlreadySpecified) {
AppendBlinkSettingsSwitch("foo");
CreateFieldTrialWithParams(kDisallowFetchFieldTrialName, kFakeGroupName,
"key1", "value1", "key2", "value2");
AppendContentBrowserClientSwitches();
EXPECT_TRUE(command_line().HasSwitch(switches::kBlinkSettings));
EXPECT_EQ("foo",
command_line().GetSwitchValueASCII(switches::kBlinkSettings));
}
TEST_F(BlinkSettingsFieldTrialTest, FieldTrialEnabled) {
CreateFieldTrialWithParams(kDisallowFetchFieldTrialName, kFakeGroupName,
"key1", "value1", "key2", "value2");
AppendContentBrowserClientSwitches();
EXPECT_TRUE(command_line().HasSwitch(switches::kBlinkSettings));
EXPECT_EQ("key1=value1,key2=value2",
command_line().GetSwitchValueASCII(switches::kBlinkSettings));
}
TEST_F(BlinkSettingsFieldTrialTest, MultipleFieldTrialsEnabled) {
CreateFieldTrialWithParams(kDisallowFetchFieldTrialName, kFakeGroupName,
"key1", "value1", "key2", "value2");
CreateFieldTrialWithParams(kCSSExternalScannerFieldTrialName, kFakeGroupName,
"keyA", "valueA", "keyB", "valueB");
AppendContentBrowserClientSwitches();
EXPECT_TRUE(command_line().HasSwitch(switches::kBlinkSettings));
EXPECT_EQ("key1=value1,key2=value2,keyA=valueA,keyB=valueB",
command_line().GetSwitchValueASCII(switches::kBlinkSettings));
}
TEST_F(BlinkSettingsFieldTrialTest, MultipleFieldTrialsDuplicateKeys) {
CreateFieldTrialWithParams(kDisallowFetchFieldTrialName, kFakeGroupName,
"key1", "value1", "key2", "value2");
CreateFieldTrialWithParams(kCSSExternalScannerFieldTrialName, kFakeGroupName,
"key2", "duplicate", "key3", "value3");
AppendContentBrowserClientSwitches();
EXPECT_TRUE(command_line().HasSwitch(switches::kBlinkSettings));
EXPECT_EQ("key1=value1,key2=value2,key2=duplicate,key3=value3",
command_line().GetSwitchValueASCII(switches::kBlinkSettings));
}
#if !defined(OS_ANDROID)
namespace content {
class InstantNTPURLRewriteTest : public BrowserWithTestWindowTest {
protected:
void SetUp() override {
BrowserWithTestWindowTest::SetUp();
field_trial_list_.reset(new base::FieldTrialList(
base::MakeUnique<variations::SHA1EntropyProvider>("42")));
}
void InstallTemplateURLWithNewTabPage(GURL new_tab_page_url) {
TemplateURLServiceFactory::GetInstance()->SetTestingFactoryAndUse(
profile(), &TemplateURLServiceFactory::BuildInstanceFor);
TemplateURLService* template_url_service =
TemplateURLServiceFactory::GetForProfile(browser()->profile());
search_test_utils::WaitForTemplateURLServiceToLoad(template_url_service);
TemplateURLData data;
data.SetShortName(base::ASCIIToUTF16("foo.com"));
data.SetURL("http://foo.com/url?bar={searchTerms}");
data.new_tab_url = new_tab_page_url.spec();
TemplateURL* template_url =
template_url_service->Add(base::MakeUnique<TemplateURL>(data));
template_url_service->SetUserSelectedDefaultSearchProvider(template_url);
}
std::unique_ptr<base::FieldTrialList> field_trial_list_;
};
TEST_F(InstantNTPURLRewriteTest, UberURLHandler_InstantExtendedNewTabPage) {
const GURL url_original("chrome://newtab");
const GURL url_rewritten("https://www.example.com/newtab");
InstallTemplateURLWithNewTabPage(url_rewritten);
ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial("InstantExtended",
"Group1 use_cacheable_ntp:1"));
AddTab(browser(), GURL("chrome://blank"));
NavigateAndCommitActiveTab(url_original);
NavigationEntry* entry = browser()->tab_strip_model()->
GetActiveWebContents()->GetController().GetLastCommittedEntry();
ASSERT_TRUE(entry != NULL);
EXPECT_EQ(url_rewritten, entry->GetURL());
EXPECT_EQ(url_original, entry->GetVirtualURL());
}
} // namespace content
#endif // !defined(OS_ANDROID)
class ChromeContentBrowserClientGetLoggingFileTest : public testing::Test {};
TEST_F(ChromeContentBrowserClientGetLoggingFileTest, GetLoggingFile) {
base::CommandLine cmd_line(base::CommandLine::NO_PROGRAM);
ChromeContentBrowserClient client;
base::FilePath log_file_name;
EXPECT_FALSE(client.GetLoggingFileName(cmd_line).empty());
}
TEST_F(ChromeContentBrowserClientGetLoggingFileTest,
GetLoggingFileFromCommandLine) {
base::CommandLine cmd_line(base::CommandLine::NO_PROGRAM);
cmd_line.AppendSwitchASCII(switches::kLogFile, "test_log.txt");
ChromeContentBrowserClient client;
base::FilePath log_file_name;
EXPECT_EQ(base::FilePath(FILE_PATH_LITERAL("test_log.txt")).value(),
client.GetLoggingFileName(cmd_line).value());
}
class TestChromeContentBrowserClient : public ChromeContentBrowserClient {
public:
using ChromeContentBrowserClient::HandleWebUI;
using ChromeContentBrowserClient::HandleWebUIReverse;
};
TEST(ChromeContentBrowserClientTest, HandleWebUI) {
TestChromeContentBrowserClient test_content_browser_client;
const GURL http_help("http://help/");
GURL should_not_redirect = http_help;
test_content_browser_client.HandleWebUI(&should_not_redirect, nullptr);
EXPECT_EQ(http_help, should_not_redirect);
const GURL chrome_help("chrome://help/");
GURL should_redirect = chrome_help;
test_content_browser_client.HandleWebUI(&should_redirect, nullptr);
EXPECT_NE(chrome_help, should_redirect);
}
TEST(ChromeContentBrowserClientTest, HandleWebUIReverse) {
TestChromeContentBrowserClient test_content_browser_client;
GURL http_settings("http://settings/");
EXPECT_FALSE(
test_content_browser_client.HandleWebUIReverse(&http_settings, nullptr));
GURL chrome_settings("chrome://settings/");
EXPECT_TRUE(test_content_browser_client.HandleWebUIReverse(&chrome_settings,
nullptr));
}
TEST(ChromeContentBrowserClientTest, GetMetricSuffixForURL) {
ChromeContentBrowserClient client;
// Search is detected.
EXPECT_EQ("search", client.GetMetricSuffixForURL(GURL(
"https://www.google.co.jp/search?q=whatsgoingon")));
// Not a Search host.
EXPECT_EQ("", client.GetMetricSuffixForURL(GURL(
"https://www.google.example.com/search?q=whatsgoingon")));
// For now, non-https is considered a Search host.
EXPECT_EQ("search", client.GetMetricSuffixForURL(
GURL("http://www.google.com/search?q=whatsgoingon")));
// Not a Search result page (no query).
EXPECT_EQ("", client.GetMetricSuffixForURL(
GURL("https://www.google.com/search?notaquery=nope")));
}
#if defined(OS_CHROMEOS)
// This behavior only matters on Chrome OS, which is why this isn't wrapped in
// ENABLE_MASH_PACKAGED_SERVICES (which is used for Linux Ozone).
TEST(ChromeContentBrowserClientTest, ShouldTerminateOnServiceQuit) {
const struct {
std::string service_name;
bool expect_terminate;
} kTestCases[] = {
// Don't terminate for invalid service names.
{"", false},
{"unknown-name", false},
// Don't terminate for some well-known browser services.
{content::mojom::kBrowserServiceName, false},
{content::mojom::kGpuServiceName, false},
{content::mojom::kRendererServiceName, false},
// Do terminate for some mash-specific cases.
{ui::mojom::kServiceName, true},
{ash::mojom::kServiceName, true},
};
ChromeContentBrowserClient client;
for (const auto& test : kTestCases) {
service_manager::Identity id(test.service_name);
EXPECT_EQ(test.expect_terminate, client.ShouldTerminateOnServiceQuit(id))
<< "for service name " << test.service_name;
}
}
#endif // defined(OS_CHROMEOS)