blob: 262944cd8aae9ba1c09bf46ba89125923b08e679 [file] [log] [blame]
// Copyright 2014 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 <vector>
#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/metrics/histogram_tester.h"
#include "chrome/browser/content_settings/chrome_content_settings_utils.h"
#include "chrome/browser/content_settings/tab_specific_content_settings.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_content_setting_bubble_model_delegate.h"
#include "chrome/browser/ui/browser_finder.h"
#include "chrome/browser/ui/content_settings/content_setting_bubble_model.h"
#include "chrome/browser/ui/content_settings/fake_owner.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/ui_test_utils.h"
#include "components/content_settings/core/common/content_settings_types.h"
#include "components/network_session_configurator/common/network_switches.h"
#include "components/rappor/test_rappor_service.h"
#include "content/public/common/content_switches.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/test_navigation_observer.h"
#include "net/dns/mock_host_resolver.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
#include "net/test/embedded_test_server/request_handler_util.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/events/event_constants.h"
class ContentSettingBubbleModelMixedScriptTest : public InProcessBrowserTest {
protected:
void SetUpInProcessBrowserTestFixture() override {
https_server_.reset(
new net::EmbeddedTestServer(net::EmbeddedTestServer::TYPE_HTTPS));
https_server_->ServeFilesFromSourceDirectory(GetChromeTestDataDir());
ASSERT_TRUE(https_server_->Start());
}
TabSpecificContentSettings* GetActiveTabSpecificContentSettings() {
return TabSpecificContentSettings::FromWebContents(
browser()->tab_strip_model()->GetActiveWebContents());
}
std::unique_ptr<net::EmbeddedTestServer> https_server_;
};
// Tests that a MIXEDSCRIPT type ContentSettingBubbleModel sends appropriate
// IPCs to allow the renderer to load unsafe scripts and refresh the page
// automatically.
IN_PROC_BROWSER_TEST_F(ContentSettingBubbleModelMixedScriptTest, MainFrame) {
GURL url(https_server_->GetURL("/content_setting_bubble/mixed_script.html"));
// Load a page with mixed content and do quick verification by looking at
// the title string.
ui_test_utils::NavigateToURL(browser(), url);
EXPECT_TRUE(GetActiveTabSpecificContentSettings()->IsContentBlocked(
CONTENT_SETTINGS_TYPE_MIXEDSCRIPT));
// Emulate link clicking on the mixed script bubble.
std::unique_ptr<ContentSettingBubbleModel> model(
ContentSettingBubbleModel::CreateContentSettingBubbleModel(
browser()->content_setting_bubble_model_delegate(),
browser()->tab_strip_model()->GetActiveWebContents(),
CONTENT_SETTINGS_TYPE_MIXEDSCRIPT));
model->OnCustomLinkClicked();
// Wait for reload
content::TestNavigationObserver observer(
browser()->tab_strip_model()->GetActiveWebContents());
observer.Wait();
EXPECT_FALSE(GetActiveTabSpecificContentSettings()->IsContentBlocked(
CONTENT_SETTINGS_TYPE_MIXEDSCRIPT));
}
class ContentSettingsMixedScriptIgnoreCertErrorsTest
: public ContentSettingBubbleModelMixedScriptTest {
protected:
void SetUpCommandLine(base::CommandLine* command_line) override {
command_line->AppendSwitch(switches::kIgnoreCertificateErrors);
}
void SetUpOnMainThread() override {
ContentSettingBubbleModelMixedScriptTest::SetUpOnMainThread();
// Rappor treats local hostnames a little bit special (e.g. records
// "127.0.0.1" as "localhost"), so use a non-local hostname for
// convenience.
host_resolver()->AddRule("*", "127.0.0.1");
}
};
// Tests that a MIXEDSCRIPT type ContentSettingBubbleModel records UMA
// and Rappor metrics when the content is allowed to run.
//
// This test fixture sets up the browser to ignore certificate errors,
// so that a non-matching, non-local hostname can be used for the
// test. This is because Rappor treats local hostnames as slightly
// special, so it's a little nicer to test with a non-local hostname.
IN_PROC_BROWSER_TEST_F(ContentSettingsMixedScriptIgnoreCertErrorsTest,
MainFrameMetrics) {
GURL url(https_server_->GetURL("/content_setting_bubble/mixed_script.html"));
GURL::Replacements replace_host;
replace_host.SetHostStr("example.test");
url = url.ReplaceComponents(replace_host);
rappor::TestRapporServiceImpl rappor_service;
EXPECT_EQ(0, rappor_service.GetReportsCount());
base::HistogramTester histograms;
histograms.ExpectTotalCount("ContentSettings.MixedScript", 0);
// Load a page with mixed content and do quick verification by looking at
// the title string.
ui_test_utils::NavigateToURL(browser(), url);
EXPECT_TRUE(GetActiveTabSpecificContentSettings()->IsContentBlocked(
CONTENT_SETTINGS_TYPE_MIXEDSCRIPT));
// Emulate link clicking on the mixed script bubble.
std::unique_ptr<ContentSettingBubbleModel> model(
ContentSettingBubbleModel::CreateContentSettingBubbleModel(
browser()->content_setting_bubble_model_delegate(),
browser()->tab_strip_model()->GetActiveWebContents(),
CONTENT_SETTINGS_TYPE_MIXEDSCRIPT));
model->SetRapporServiceImplForTesting(&rappor_service);
model->OnCustomLinkClicked();
// Wait for reload
content::TestNavigationObserver observer(
browser()->tab_strip_model()->GetActiveWebContents());
observer.Wait();
EXPECT_FALSE(GetActiveTabSpecificContentSettings()->IsContentBlocked(
CONTENT_SETTINGS_TYPE_MIXEDSCRIPT));
// Check that the UMA and Rappor counts are as expected.
histograms.ExpectBucketCount(
"ContentSettings.MixedScript",
content_settings::MIXED_SCRIPT_ACTION_CLICKED_ALLOW, 1);
EXPECT_EQ(1, rappor_service.GetReportsCount());
std::string sample;
rappor::RapporType type;
EXPECT_TRUE(rappor_service.GetRecordedSampleForMetric(
"ContentSettings.MixedScript.UserClickedAllow", &sample, &type));
EXPECT_EQ(url.host(), sample);
EXPECT_EQ(rappor::ETLD_PLUS_ONE_RAPPOR_TYPE, type);
}
// Tests that a MIXEDSCRIPT type ContentSettingBubbleModel does not work
// for an iframe (mixed script in iframes is never allowed and the mixed
// content shield isn't shown for it).
IN_PROC_BROWSER_TEST_F(ContentSettingBubbleModelMixedScriptTest, Iframe) {
GURL url(https_server_->GetURL(
"/content_setting_bubble/mixed_script_in_iframe.html"));
ui_test_utils::NavigateToURL(browser(), url);
// Blink does not ask the browser to handle mixed content in the case
// of active subresources in an iframe, so the content type should not
// be marked as blocked.
EXPECT_FALSE(GetActiveTabSpecificContentSettings()->IsContentBlocked(
CONTENT_SETTINGS_TYPE_MIXEDSCRIPT));
}
class ContentSettingBubbleModelMediaStreamTest : public InProcessBrowserTest {
public:
void ManageMediaStreamSettings(
TabSpecificContentSettings::MicrophoneCameraState state) {
// Open a tab for which we will invoke the media bubble.
GURL url(ui_test_utils::GetTestUrl(
base::FilePath().AppendASCII("content_setting_bubble"),
base::FilePath().AppendASCII("mixed_script.html")));
ui_test_utils::NavigateToURL(browser(), url);
content::WebContents* original_tab = GetActiveTab();
// Create a bubble with the given camera and microphone access state.
TabSpecificContentSettings::FromWebContents(original_tab)->
OnMediaStreamPermissionSet(
original_tab->GetLastCommittedURL(),
state, std::string(), std::string(), std::string(), std::string());
std::unique_ptr<ContentSettingBubbleModel> bubble(
new ContentSettingMediaStreamBubbleModel(
browser()->content_setting_bubble_model_delegate(), original_tab));
// Click the manage button, which opens in a new tab or window. Wait until
// it loads.
bubble->OnManageButtonClicked();
ASSERT_NE(GetActiveTab(), original_tab);
content::TestNavigationObserver observer(GetActiveTab());
observer.Wait();
}
content::WebContents* GetActiveTab() {
// First, we need to find the active browser window. It should be at
// the same desktop as the browser in which we invoked the bubble.
Browser* active_browser = chrome::FindLastActive();
return active_browser->tab_strip_model()->GetActiveWebContents();
}
};
// Tests that clicking on the manage button in the media bubble opens the
// correct section of the settings UI. This test sometimes leaks memory,
// detected by linux_chromium_asan_rel_ng. See http://crbug/668693 for more
// info.
IN_PROC_BROWSER_TEST_F(ContentSettingBubbleModelMediaStreamTest,
DISABLED_ManageLink) {
// For each of the three options, we click the manage button and check if the
// active tab loads the correct internal url.
// The microphone bubble links to microphone exceptions.
ManageMediaStreamSettings(TabSpecificContentSettings::MICROPHONE_ACCESSED);
EXPECT_EQ(GURL("chrome://settings/contentExceptions#media-stream-mic"),
GetActiveTab()->GetLastCommittedURL());
// The bubble for both media devices links to the the first section of the
// default media content settings, which is the microphone section.
ManageMediaStreamSettings(TabSpecificContentSettings::MICROPHONE_ACCESSED |
TabSpecificContentSettings::CAMERA_ACCESSED);
EXPECT_EQ(GURL("chrome://settings/content#media-stream-mic"),
GetActiveTab()->GetLastCommittedURL());
// The camera bubble links to camera exceptions.
ManageMediaStreamSettings(TabSpecificContentSettings::CAMERA_ACCESSED);
EXPECT_EQ(GURL("chrome://settings/contentExceptions#media-stream-camera"),
GetActiveTab()->GetLastCommittedURL());
}
class ContentSettingBubbleModelPopupTest : public InProcessBrowserTest {
protected:
static constexpr int kDisallowButtonIndex = 1;
void SetUpInProcessBrowserTestFixture() override {
https_server_.reset(
new net::EmbeddedTestServer(net::EmbeddedTestServer::TYPE_HTTPS));
https_server_->ServeFilesFromSourceDirectory(GetChromeTestDataDir());
ASSERT_TRUE(https_server_->Start());
}
std::unique_ptr<net::EmbeddedTestServer> https_server_;
};
// Tests that each popup action is counted in the right bucket.
IN_PROC_BROWSER_TEST_F(ContentSettingBubbleModelPopupTest,
PopupsActionsCount){
GURL url(https_server_->GetURL("/popup_blocker/popup-many.html"));
base::HistogramTester histograms;
histograms.ExpectTotalCount("ContentSettings.Popups", 0);
ui_test_utils::NavigateToURL(browser(), url);
histograms.ExpectBucketCount(
"ContentSettings.Popups",
content_settings::POPUPS_ACTION_DISPLAYED_BLOCKED_ICON_IN_OMNIBOX, 1);
// Creates the ContentSettingPopupBubbleModel in order to emulate clicks.
std::unique_ptr<ContentSettingBubbleModel> model(
ContentSettingBubbleModel::CreateContentSettingBubbleModel(
browser()->content_setting_bubble_model_delegate(),
browser()->tab_strip_model()->GetActiveWebContents(),
CONTENT_SETTINGS_TYPE_POPUPS));
std::unique_ptr<FakeOwner> owner =
FakeOwner::Create(*model, kDisallowButtonIndex);
histograms.ExpectBucketCount(
"ContentSettings.Popups",
content_settings::POPUPS_ACTION_DISPLAYED_BUBBLE, 1);
model->OnListItemClicked(0, ui::EF_LEFT_MOUSE_BUTTON);
histograms.ExpectBucketCount(
"ContentSettings.Popups",
content_settings::POPUPS_ACTION_CLICKED_LIST_ITEM_CLICKED, 1);
model->OnManageButtonClicked();
histograms.ExpectBucketCount(
"ContentSettings.Popups",
content_settings::POPUPS_ACTION_CLICKED_MANAGE_POPUPS_BLOCKING, 1);
owner->SetSelectedRadioOptionAndCommit(model->kAllowButtonIndex);
histograms.ExpectBucketCount(
"ContentSettings.Popups",
content_settings::POPUPS_ACTION_SELECTED_ALWAYS_ALLOW_POPUPS_FROM, 1);
histograms.ExpectTotalCount("ContentSettings.Popups", 5);
}
class ContentSettingBubbleModelMixedScriptOopifTest
: public ContentSettingBubbleModelMixedScriptTest {
protected:
void SetUpCommandLine(base::CommandLine* command_line) override {
content::IsolateAllSitesForTesting(command_line);
}
void SetUpInProcessBrowserTestFixture() override {
ContentSettingBubbleModelMixedScriptTest::
SetUpInProcessBrowserTestFixture();
host_resolver()->AddRule("*", "127.0.0.1");
ASSERT_TRUE(embedded_test_server()->Start());
}
};
// Tests that a MIXEDSCRIPT type ContentSettingBubbleModel sends appropriate
// IPCs to allow the renderer to load unsafe scripts inside out-of-processs
// iframes.
IN_PROC_BROWSER_TEST_F(ContentSettingBubbleModelMixedScriptOopifTest,
MixedContentInCrossSiteIframe) {
// Create a URL for the mixed content document and append it as a query
// string to the main URL. This approach is taken because the test servers
// run on random ports each time and it is not possible to use a static
// URL in the HTML for the main frame. The main document will use JS to
// navigate the iframe to the URL specified in the query string, which is
// determined at runtime and is known to be correct.
GURL foo_url(embedded_test_server()->GetURL(
"foo.com", "/content_setting_bubble/mixed_script.html"));
GURL main_url(https_server_->GetURL(
"/content_setting_bubble/mixed_script_in_cross_site_iframe.html?" +
foo_url.spec()));
// Load a page with mixed content and verify that mixed content didn't get
// executed.
ui_test_utils::NavigateToURL(browser(), main_url);
EXPECT_TRUE(GetActiveTabSpecificContentSettings()->IsContentBlocked(
CONTENT_SETTINGS_TYPE_MIXEDSCRIPT));
std::string title;
content::WebContents* web_contents =
browser()->tab_strip_model()->GetActiveWebContents();
EXPECT_TRUE(content::ExecuteScriptAndExtractString(
ChildFrameAt(web_contents->GetMainFrame(), 0),
"domAutomationController.send(document.title)", &title));
EXPECT_EQ("", title);
// Emulate link clicking on the mixed script bubble.
content::TestNavigationObserver observer(web_contents);
std::unique_ptr<ContentSettingBubbleModel> model(
ContentSettingBubbleModel::CreateContentSettingBubbleModel(
browser()->content_setting_bubble_model_delegate(), web_contents,
CONTENT_SETTINGS_TYPE_MIXEDSCRIPT));
model->OnCustomLinkClicked();
// Wait for reload and verify that mixed content is allowed.
observer.Wait();
EXPECT_FALSE(GetActiveTabSpecificContentSettings()->IsContentBlocked(
CONTENT_SETTINGS_TYPE_MIXEDSCRIPT));
// Ensure that the script actually executed by checking the title of the
// document in the subframe.
EXPECT_TRUE(content::ExecuteScriptAndExtractString(
ChildFrameAt(web_contents->GetMainFrame(), 0),
"domAutomationController.send(document.title)", &title));
EXPECT_EQ("mixed_script_ran_successfully", title);
}