blob: bf7b23eeec47b5435fdfcfb4a90b17f77eb55b6f [file] [log] [blame]
// Copyright 2018 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 <memory>
#include <string>
#include "base/bind.h"
#include "base/files/file_path.h"
#include "base/metrics/field_trial_params.h"
#include "base/strings/stringprintf.h"
#include "base/test/scoped_feature_list.h"
#include "base/timer/elapsed_timer.h"
#include "chrome/browser/subresource_filter/subresource_filter_browser_test_harness.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/test/base/ui_test_utils.h"
#include "components/subresource_filter/content/common/ad_delay_throttle.h"
#include "components/subresource_filter/core/common/common_features.h"
#include "content/public/test/browser_test.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 "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
class AdDelayBrowserTest
: public subresource_filter::SubresourceFilterBrowserTest {
public:
AdDelayBrowserTest() : subresource_filter::SubresourceFilterBrowserTest() {}
~AdDelayBrowserTest() override {}
void SetUp() override {
secure_server_ = std::make_unique<net::EmbeddedTestServer>(
net::EmbeddedTestServer::TYPE_HTTPS);
secure_server_->AddDefaultHandlers(
base::FilePath(FILE_PATH_LITERAL("chrome/test/data")));
scoped_features_.InitAndEnableFeatureWithParameters(
subresource_filter::kDelayUnsafeAds,
{{subresource_filter::kInsecureDelayParam, DelayParamToUse()},
{subresource_filter::kNonIsolatedDelayParam, DelayParamToUse()}});
subresource_filter::SubresourceFilterBrowserTest::SetUp();
}
void SetUpOnMainThread() override {
ASSERT_TRUE(secure_server_->Start());
subresource_filter::SubresourceFilterBrowserTest::SetUpOnMainThread();
host_resolver()->ClearRules();
}
// Calls fetchResources on the page, which issues fetch()es for two resources.
//
// Returns the name of the file whose fetch complete event triggered the
// callback.
// - If |policy| is kBothFetches, the returned file will be the last file
// loaded.
// - If |policy| is kOneFetch, the returned file will be the first file
// loaded.
enum class WaitForPolicy { kOneFetch, kBothFetches };
std::string FetchResources(const content::ToRenderFrameHost& adapter,
WaitForPolicy policy) {
std::string ret;
EXPECT_TRUE(content::ExecuteScriptAndExtractString(
adapter,
base::StringPrintf(
"fetchResources(%s);",
policy == WaitForPolicy::kBothFetches ? "true" : "false"),
&ret));
return ret;
}
content::WebContents* GetWebContents() {
return browser()->tab_strip_model()->GetActiveWebContents();
}
content::RenderFrameHost* AppendFrameAndWait(
const content::ToRenderFrameHost& adapter,
const GURL& url) {
content::RenderFrameHost* rfh = adapter.render_frame_host();
const char kScript[] = R"(
var frame = document.createElement('iframe');
frame.src = "%s";
document.body.appendChild(frame);)";
std::string script = base::StringPrintf(kScript, url.spec().c_str());
content::TestNavigationObserver nav(GetWebContents(), 1);
EXPECT_TRUE(content::ExecuteScript(rfh, script));
nav.Wait();
EXPECT_TRUE(nav.last_navigation_succeeded()) << nav.last_net_error_code();
return content::FrameMatchingPredicate(
GetWebContents(),
base::BindRepeating(&content::FrameHasSourceUrl, url));
}
base::TimeDelta GetExpectedDelay() const {
return base::TimeDelta::FromMilliseconds(
base::GetFieldTrialParamByFeatureAsInt(
subresource_filter::kDelayUnsafeAds,
subresource_filter::kInsecureDelayParam,
subresource_filter::AdDelayThrottle::kDefaultDelay
.InMilliseconds()));
}
protected:
// 10 minutes.
virtual std::string DelayParamToUse() { return "600000"; }
std::unique_ptr<net::EmbeddedTestServer> secure_server_;
private:
base::test::ScopedFeatureList scoped_features_;
};
class MinimalAdDelayBrowserTest : public AdDelayBrowserTest {
std::string DelayParamToUse() override { return "100"; }
};
IN_PROC_BROWSER_TEST_F(AdDelayBrowserTest, NoAd_NoDelay) {
GURL url(embedded_test_server()->GetURL(
"/subresource_filter/frame_with_multiple_fetches.html"));
ui_test_utils::NavigateToURL(browser(), url);
base::ElapsedTimer timer;
FetchResources(GetWebContents(), WaitForPolicy::kBothFetches);
EXPECT_GT(GetExpectedDelay(), timer.Elapsed());
}
IN_PROC_BROWSER_TEST_F(AdDelayBrowserTest, InsecureAdRequest_IsDelayed) {
ASSERT_NO_FATAL_FAILURE(
SetRulesetToDisallowURLsWithPathSuffix("included_script.js"));
GURL url(embedded_test_server()->GetURL(
"/subresource_filter/frame_with_multiple_fetches.html"));
ui_test_utils::NavigateToURL(browser(), url);
// If the included_script.js is delayed, assert that the
// included_allowed_script will always load before it. Because the allowed
// script is fetched second, this is a reasonably strong statement.
base::ElapsedTimer timer;
std::string first_resource =
FetchResources(GetWebContents(), WaitForPolicy::kOneFetch);
EXPECT_GE(GetExpectedDelay(), timer.Elapsed());
EXPECT_EQ("included_allowed_script.js", first_resource);
}
IN_PROC_BROWSER_TEST_F(AdDelayBrowserTest, SecureAdRequest_NoDelay) {
ASSERT_NO_FATAL_FAILURE(
SetRulesetToDisallowURLsWithPathSuffix("included_script.js"));
GURL url(secure_server_->GetURL(
"/subresource_filter/frame_with_multiple_fetches.html"));
ui_test_utils::NavigateToURL(browser(), url);
base::ElapsedTimer timer;
std::string first_resource =
FetchResources(GetWebContents(), WaitForPolicy::kBothFetches);
EXPECT_GT(GetExpectedDelay(), timer.Elapsed());
}
IN_PROC_BROWSER_TEST_F(AdDelayBrowserTest, NonIsolatedAdRequest_IsDelayed) {
ASSERT_NO_FATAL_FAILURE(
SetRulesetToDisallowURLsWithPathSuffix("included_script.js"));
GURL url(secure_server_->GetURL("/title1.html"));
ui_test_utils::NavigateToURL(browser(), url);
content::RenderFrameHost* subframe = AppendFrameAndWait(
GetWebContents(),
secure_server_->GetURL(
"/subresource_filter/frame_with_multiple_fetches.html"));
ASSERT_TRUE(subframe);
base::ElapsedTimer timer;
std::string first_resource =
FetchResources(subframe, WaitForPolicy::kOneFetch);
EXPECT_GE(GetExpectedDelay(), timer.Elapsed());
EXPECT_EQ("included_allowed_script.js", first_resource);
}
IN_PROC_BROWSER_TEST_F(AdDelayBrowserTest, IsolatedAdRequest_NoDelay) {
ASSERT_NO_FATAL_FAILURE(
SetRulesetToDisallowURLsWithPathSuffix("included_script.js"));
GURL url(embedded_test_server()->GetURL("/title1.html"));
ui_test_utils::NavigateToURL(browser(), url);
content::RenderFrameHost* subframe = AppendFrameAndWait(
GetWebContents(),
secure_server_->GetURL(
"/subresource_filter/frame_with_multiple_fetches.html"));
ASSERT_TRUE(subframe);
base::ElapsedTimer timer;
FetchResources(subframe, WaitForPolicy::kBothFetches);
EXPECT_GT(GetExpectedDelay(), timer.Elapsed());
}
IN_PROC_BROWSER_TEST_F(MinimalAdDelayBrowserTest, AdRequest_IsNotBlackholed) {
ASSERT_NO_FATAL_FAILURE(
SetRulesetToDisallowURLsWithPathSuffix("included_script.js"));
GURL url(embedded_test_server()->GetURL(
"/subresource_filter/frame_with_multiple_fetches.html"));
ui_test_utils::NavigateToURL(browser(), url);
// The test succeeds if it does not time out.
base::ElapsedTimer timer;
FetchResources(GetWebContents(), WaitForPolicy::kBothFetches);
EXPECT_LE(GetExpectedDelay(), timer.Elapsed());
}
IN_PROC_BROWSER_TEST_F(MinimalAdDelayBrowserTest, SyncXHRAd) {
ASSERT_NO_FATAL_FAILURE(
SetRulesetToDisallowURLsWithPathSuffix("included_script.js"));
GURL url(embedded_test_server()->GetURL("/title1.html"));
ui_test_utils::NavigateToURL(browser(), url);
std::string script = R"(
var request = new XMLHttpRequest();
request.open('GET', '/subresource_filter/included_script.js', false);
request.send(null);
)";
base::ElapsedTimer timer;
EXPECT_TRUE(content::ExecuteScript(
browser()->tab_strip_model()->GetActiveWebContents(), script.c_str()));
subresource_filter::AdDelayThrottle::Factory factory;
EXPECT_LE(factory.insecure_delay(), timer.Elapsed());
}