Commit a1e6a91f authored by Robert Ogden's avatar Robert Ogden Committed by Commit Bot

Add triggering logic to HTTPS Server Previews

This adds the basic triggering logic to the Previews Navigation Throttle
(not including loadshedding or bypassing which will come in the next
CL).
Also creates a NavigationThrottleManager interface to decouple the Nav
Throttle from the decider. The decider will keep all the state for the
Nav Throttle since the throttle's lifetime is so short.

Most of the triggering testing is done in browser tests for sake of
clarity and complexity.

Bug: 864651
Change-Id: I1d1772c25ddfa159051bd5b1064c53256ced39f3
Reviewed-on: https://chromium-review.googlesource.com/1152164
Commit-Queue: Robert Ogden <robertogden@chromium.org>
Reviewed-by: default avatarTarun Bansal <tbansal@chromium.org>
Reviewed-by: default avatarDoug Arnett <dougarnett@chromium.org>
Reviewed-by: default avatarRyan Sturm <ryansturm@chromium.org>
Cr-Commit-Position: refs/heads/master@{#582220}
parent 78aae16b
......@@ -1201,6 +1201,7 @@ jumbo_split_static_library("browser") {
"previews/previews_lite_page_decider.h",
"previews/previews_lite_page_navigation_throttle.cc",
"previews/previews_lite_page_navigation_throttle.h",
"previews/previews_lite_page_navigation_throttle_manager.h",
"previews/previews_service.cc",
"previews/previews_service.h",
"previews/previews_service_factory.cc",
......
......@@ -2,7 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <map>
#include <string>
#include "base/command_line.h"
#include "base/metrics/field_trial_param_associator.h"
#include "base/metrics/field_trial_params.h"
#include "base/run_loop.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
......@@ -61,6 +66,7 @@ class PreviewsBrowserTest : public InProcessBrowserTest {
void SetUpOnMainThread() override {
noscript_css_requested_ = false;
noscript_js_requested_ = false;
https_url_count_ = 0;
// Set up https server with resource monitor.
https_server_.reset(
......@@ -80,20 +86,28 @@ class PreviewsBrowserTest : public InProcessBrowserTest {
// Set up http server with resource monitor and redirect handler.
http_server_.reset(
new net::EmbeddedTestServer(net::EmbeddedTestServer::TYPE_HTTP));
http_server_->ServeFilesFromSourceDirectory("chrome/test/data/previews");
http_server_->ServeFilesFromSourceDirectory("chrome/test/data");
http_server_->RegisterRequestMonitor(base::BindRepeating(
&PreviewsBrowserTest::MonitorResourceRequest, base::Unretained(this)));
http_server_->RegisterRequestHandler(base::BindRepeating(
&PreviewsBrowserTest::HandleRedirectRequest, base::Unretained(this)));
ASSERT_TRUE(http_server_->Start());
http_url_ = http_server_->GetURL("/noscript_test.html");
http_url_ = http_server_->GetURL("/previews/noscript_test.html");
ASSERT_TRUE(http_url_.SchemeIs(url::kHttpScheme));
redirect_url_ = http_server_->GetURL("/redirect.html");
subframe_url_ = http_server_->GetURL("/iframe_blank.html");
ASSERT_TRUE(subframe_url_.SchemeIs(url::kHttpScheme));
redirect_url_ = http_server_->GetURL("/previews/redirect.html");
ASSERT_TRUE(redirect_url_.SchemeIs(url::kHttpScheme));
}
void ExecuteScript(const std::string& script) {
EXPECT_TRUE(content::ExecuteScript(
browser()->tab_strip_model()->GetActiveWebContents(), script));
}
void SetUpCommandLine(base::CommandLine* cmd) override {
cmd->AppendSwitch("enable-spdy-proxy-auth");
cmd->AppendSwitchASCII("force-effective-connection-type", "Slow-2G");
......@@ -103,12 +117,15 @@ class PreviewsBrowserTest : public InProcessBrowserTest {
const GURL& https_no_transform_url() const { return https_no_transform_url_; }
const GURL& http_url() const { return http_url_; }
const GURL& redirect_url() const { return redirect_url_; }
const GURL& subframe_url() const { return subframe_url_; }
bool noscript_css_requested() const { return noscript_css_requested_; }
bool noscript_js_requested() const { return noscript_js_requested_; }
int https_url_count() const { return https_url_count_; }
private:
// Called by |https_server_|.
void MonitorResourceRequest(const net::test_server::HttpRequest& request) {
https_url_count_++;
if (request.GetURL().spec().find("noscript_test.css") !=
std::string::npos) {
noscript_css_requested_ = true;
......@@ -135,8 +152,10 @@ class PreviewsBrowserTest : public InProcessBrowserTest {
GURL https_no_transform_url_;
GURL http_url_;
GURL redirect_url_;
GURL subframe_url_;
bool noscript_css_requested_;
bool noscript_js_requested_;
int https_url_count_;
};
// Loads a webpage that has both script and noscript tags and also requests
......@@ -329,6 +348,8 @@ IN_PROC_BROWSER_TEST_F(PreviewsOptimizationGuideBrowserTest,
EXPECT_FALSE(noscript_css_requested());
}
static const std::string kTestPreviewsServer = "https://litepages.test.com/";
// This test class enables LitePageServerPreviews.
class PreviewsLitePageServerBrowserTest : public PreviewsBrowserTest {
public:
......@@ -337,28 +358,113 @@ class PreviewsLitePageServerBrowserTest : public PreviewsBrowserTest {
~PreviewsLitePageServerBrowserTest() override {}
void SetUp() override {
scoped_feature_list_.InitWithFeatures(
{previews::features::kPreviews,
previews::features::kLitePageServerPreviews},
{});
std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList);
{
// The trial and group names are dummy values.
scoped_refptr<base::FieldTrial> trial =
base::FieldTrialList::CreateFieldTrial("TrialName1", "GroupName1");
std::map<std::string, std::string> feature_parameters = {
{"previews_host", kTestPreviewsServer}};
ASSERT_TRUE(base::FieldTrialParamAssociator::GetInstance()
->AssociateFieldTrialParams("TrialName1", "GroupName1",
feature_parameters));
feature_list->RegisterFieldTrialOverride(
previews::features::kLitePageServerPreviews.name,
base::FeatureList::OVERRIDE_ENABLE_FEATURE, trial.get());
}
{
// The trial and group names are dummy values.
scoped_refptr<base::FieldTrial> trial =
base::FieldTrialList::CreateFieldTrial("TrialName3", "GroupName3");
feature_list->RegisterFieldTrialOverride(
previews::features::kPreviews.name,
base::FeatureList::OVERRIDE_ENABLE_FEATURE, trial.get());
}
scoped_feature_list_.InitWithFeatureList(std::move(feature_list));
PreviewsBrowserTest::SetUp();
}
GURL NavigatedURL() {
return browser()->tab_strip_model()->GetActiveWebContents()->GetURL();
}
void VerifyPreviewLoaded() {
EXPECT_TRUE(NavigatedURL().DomainIs(GURL(kTestPreviewsServer).host()));
}
void VerifyPreviewNotLoaded() {
EXPECT_FALSE(NavigatedURL().DomainIs(GURL(kTestPreviewsServer).host()));
}
private:
base::test::ScopedFeatureList scoped_feature_list_;
};
// Previews InfoBar (which these tests triggers) does not work on Mac.
// Previews InfoBar (which these tests trigger) does not work on Mac.
// See crbug.com/782322 for detail.
// Also occasional flakes on win7 (crbug.com/789542).
#if defined(OS_ANDROID) || defined(OS_LINUX)
#define MAYBE_LitePagePreviewsEnabled LitePagePreviewsEnabled
#define MAYBE_LitePagePreviewsTriggering LitePagePreviewsTriggering
#else
#define MAYBE_LitePagePreviewsEnabled DISABLED_LitePagePreviewsEnabled
#define MAYBE_LitePagePreviewsTriggering DISABLED_LitePagePreviewsTriggering
#endif
// Makes sure that nothing crashes.
IN_PROC_BROWSER_TEST_F(PreviewsLitePageServerBrowserTest,
MAYBE_LitePagePreviewsEnabled) {
MAYBE_LitePagePreviewsTriggering) {
// Verify the preview is not triggered on HTTP pageloads.
ui_test_utils::NavigateToURL(browser(), http_url());
VerifyPreviewNotLoaded();
// Verify the preview is triggered on HTTPS pageloads.
ui_test_utils::NavigateToURL(browser(), https_url());
VerifyPreviewLoaded();
// Verify the preview is triggered when an HTTP page redirects to HTTPS.
ui_test_utils::NavigateToURL(browser(), redirect_url());
VerifyPreviewLoaded();
// Verify the preview is not triggered for POST navigations.
std::string post_data = "helloworld";
NavigateParams params(browser(), https_url(), ui::PAGE_TRANSITION_LINK);
params.window_action = NavigateParams::SHOW_WINDOW;
params.disposition = WindowOpenDisposition::NEW_FOREGROUND_TAB;
params.is_renderer_initiated = false;
params.uses_post = true;
params.post_data = network::ResourceRequestBody::CreateFromBytes(
post_data.data(), post_data.size());
ui_test_utils::NavigateToURL(&params);
VerifyPreviewNotLoaded();
// Verify the preview is not triggered when navigating to the previews server.
ui_test_utils::NavigateToURL(browser(), GURL(kTestPreviewsServer));
EXPECT_EQ(NavigatedURL(), GURL(kTestPreviewsServer));
// Verify a subframe navigation does not trigger a preview.
const int starting_https_url_count = https_url_count();
ui_test_utils::NavigateToURL(browser(), subframe_url());
ExecuteScript("window.open(\"" + https_url().spec() + "\", \"subframe\")");
EXPECT_EQ(https_url_count(), starting_https_url_count + 1);
}
class PreviewsLitePageServerDataSaverBrowserTest
: public PreviewsLitePageServerBrowserTest {
public:
PreviewsLitePageServerDataSaverBrowserTest() = default;
~PreviewsLitePageServerDataSaverBrowserTest() override = default;
// Overrides the cmd line in PreviewsBrowserTest and leave out the flag to
// enable DataSaver.
void SetUpCommandLine(base::CommandLine* cmd) override {
cmd->AppendSwitchASCII("force-effective-connection-type", "Slow-2G");
}
};
IN_PROC_BROWSER_TEST_F(PreviewsLitePageServerDataSaverBrowserTest,
MAYBE_LitePagePreviewsTriggering) {
// Verify the preview is not triggered on HTTPS pageloads without DataSaver.
ui_test_utils::NavigateToURL(browser(), https_url());
VerifyPreviewNotLoaded();
}
......@@ -48,17 +48,12 @@ PreviewsLitePageDecider::MaybeCreateThrottleFor(
previews::params::IsLitePageServerPreviewsEnabled();
if (drp_enabled && preview_enabled) {
return PreviewsLitePageNavigationThrottle::MaybeCreateThrottleFor(handle);
return std::make_unique<PreviewsLitePageNavigationThrottle>(handle,
decider);
}
return nullptr;
}
void PreviewsLitePageDecider::SetRetryAt(base::TimeTicks retry_at) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (retry_at > retry_at_)
retry_at_ = retry_at;
}
bool PreviewsLitePageDecider::IsDataSaverEnabled(
content::NavigationHandle* handle) const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
......@@ -73,6 +68,13 @@ bool PreviewsLitePageDecider::IsDataSaverEnabled(
return drp_settings->IsDataReductionProxyEnabled();
}
void PreviewsLitePageDecider::SetServerUnavailableUntil(
base::TimeTicks retry_at) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!retry_at_.has_value() || retry_at > retry_at_)
retry_at_ = retry_at;
}
bool PreviewsLitePageDecider::IsServerUnavailable(base::TimeTicks now) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!retry_at_.has_value())
......
......@@ -5,6 +5,7 @@
#ifndef CHROME_BROWSER_PREVIEWS_PREVIEWS_LITE_PAGE_DECIDER_H_
#define CHROME_BROWSER_PREVIEWS_PREVIEWS_LITE_PAGE_DECIDER_H_
#include <map>
#include <memory>
#include "base/gtest_prod_util.h"
......@@ -12,17 +13,18 @@
#include "base/optional.h"
#include "base/sequence_checker.h"
#include "base/time/time.h"
#include "chrome/browser/previews/previews_lite_page_navigation_throttle_manager.h"
namespace content {
class NavigationHandle;
class NavigationThrottle;
} // namespace content
// This class manages the state for triggering the Lite Page Server Preview.
// This class ensures that the feature is enabled and the
// current Profile is not incognito before handing off the real legwork of the
// triggering decision to |PreviewsLitePageNavigationThrottle|.
class PreviewsLitePageDecider {
class PreviewsLitePageDecider
: public PreviewsLitePageNavigationThrottleManager {
public:
PreviewsLitePageDecider();
virtual ~PreviewsLitePageDecider();
......@@ -33,10 +35,6 @@ class PreviewsLitePageDecider {
static std::unique_ptr<content::NavigationThrottle> MaybeCreateThrottleFor(
content::NavigationHandle* handle);
// Used to notify that the Previews Server should not be sent anymore requests
// until after the given time.
void SetRetryAt(base::TimeTicks retry_at);
protected:
// Virtual for testing.
virtual bool IsDataSaverEnabled(content::NavigationHandle* handle) const;
......@@ -44,9 +42,9 @@ class PreviewsLitePageDecider {
private:
FRIEND_TEST_ALL_PREFIXES(PreviewsLitePageDeciderTest, TestServerUnavailable);
// Returns true if a Preview should not be triggered because the server is
// unavailable.
bool IsServerUnavailable(base::TimeTicks now);
// PreviewsLitePageNavigationThrottleManager:
void SetServerUnavailableUntil(base::TimeTicks retry_at) override;
bool IsServerUnavailable(base::TimeTicks now) override;
// The time after which it is ok to send the server more preview requests.
base::Optional<base::TimeTicks> retry_at_;
......
......@@ -38,7 +38,7 @@ TEST_F(PreviewsLitePageDeciderTest, TestServerUnavailable) {
for (const TestCase& test_case : kTestCases) {
std::unique_ptr<PreviewsLitePageDecider> decider =
std::make_unique<PreviewsLitePageDecider>();
decider->SetRetryAt(test_case.retry_at);
decider->SetServerUnavailableUntil(test_case.retry_at);
EXPECT_EQ(decider->IsServerUnavailable(test_case.now),
test_case.want_is_unavailable);
}
......
......@@ -4,31 +4,144 @@
#include "chrome/browser/previews/previews_lite_page_navigation_throttle.h"
#include "base/memory/weak_ptr.h"
#include "base/strings/string_number_conversions.h"
#include "components/base32/base32.h"
#include "components/previews/core/previews_experiments.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/navigation_handle.h"
#include "content/public/browser/page_navigator.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_user_data.h"
#include "content/public/common/referrer.h"
#include "crypto/sha2.h"
#include "net/base/escape.h"
#include "url/gurl.h"
namespace {
bool IsPreviewsDomain(const GURL& url) {
GURL previews_host = previews::params::GetLitePagePreviewsDomainURL();
return url.DomainIs(previews_host.host()) &&
url.EffectiveIntPort() == previews_host.EffectiveIntPort();
}
} // namespace
class WebContentsLifetimeHelper
: public content::WebContentsUserData<WebContentsLifetimeHelper> {
public:
explicit WebContentsLifetimeHelper(content::WebContents* web_contents)
: web_contents_(web_contents), weak_factory_(this) {}
base::WeakPtr<WebContentsLifetimeHelper> GetWeakPtr() {
return weak_factory_.GetWeakPtr();
}
void PostNewNavigation(const content::OpenURLParams& url_params) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
DCHECK(url_params.url.is_valid());
DCHECK(url_params.url.SchemeIs(url::kHttpsScheme));
web_contents_->OpenURL(url_params);
}
private:
content::WebContents* web_contents_;
base::WeakPtrFactory<WebContentsLifetimeHelper> weak_factory_;
};
PreviewsLitePageNavigationThrottle::PreviewsLitePageNavigationThrottle(
content::NavigationHandle* handle)
: content::NavigationThrottle(handle) {
content::NavigationHandle* handle,
PreviewsLitePageNavigationThrottleManager* manager)
: content::NavigationThrottle(handle), manager_(manager) {
DCHECK(manager_);
DCHECK(handle);
DCHECK(handle->GetWebContents());
DCHECK(handle->GetWebContents()->GetBrowserContext());
}
PreviewsLitePageNavigationThrottle::~PreviewsLitePageNavigationThrottle() =
default;
// static
std::unique_ptr<content::NavigationThrottle>
PreviewsLitePageNavigationThrottle::MaybeCreateThrottleFor(
content::NavigationHandle* handle) {
DCHECK(handle);
return nullptr;
bool PreviewsLitePageNavigationThrottle::IsEligibleForPreview() const {
if (!navigation_handle()->GetURL().SchemeIs(url::kHttpsScheme))
return false;
if (navigation_handle()->IsPost())
return false;
if (!navigation_handle()->IsInMainFrame())
return false;
if (IsPreviewsDomain(navigation_handle()->GetURL()))
return false;
return true;
}
GURL PreviewsLitePageNavigationThrottle::GetPreviewsURL() const {
GURL original_url = navigation_handle()->GetURL();
DCHECK(original_url.is_valid());
DCHECK(!IsPreviewsDomain(original_url));
std::string origin_hash = base::ToLowerASCII(base32::Base32Encode(
crypto::SHA256HashString(
original_url.scheme() + "://" + original_url.host() + ":" +
base::IntToString(original_url.EffectiveIntPort())),
base32::Base32EncodePolicy::OMIT_PADDING));
GURL previews_host = previews::params::GetLitePagePreviewsDomainURL();
GURL previews_url = GURL(
previews_host.scheme() + "://" + origin_hash + "." +
previews_host.host() +
(previews_host.has_port() ? (":" + previews_host.port()) : "") + "/p?u=" +
net::EscapeQueryParamValue(original_url.spec(), true /* use_plus */));
DCHECK(previews_url.is_valid());
DCHECK(previews_url.SchemeIs(url::kHttpsScheme));
return previews_url;
}
content::NavigationThrottle::ThrottleCheckResult
PreviewsLitePageNavigationThrottle::MaybeNavigateToPreview() const {
if (!IsEligibleForPreview()) {
return content::NavigationThrottle::PROCEED;
}
content::OpenURLParams url_params(GetPreviewsURL(),
navigation_handle()->GetReferrer(),
WindowOpenDisposition::CURRENT_TAB,
navigation_handle()->GetPageTransition(),
navigation_handle()->IsRendererInitiated());
// TODO(crbug.com/864652): Add chrome-proxy headers.
url_params.redirect_chain = navigation_handle()->GetRedirectChain();
url_params.frame_tree_node_id = navigation_handle()->GetFrameTreeNodeId();
url_params.user_gesture = navigation_handle()->HasUserGesture();
url_params.started_from_context_menu =
navigation_handle()->WasStartedFromContextMenu();
// The helper class and its weak pointer protect against the WebContents
// dying in-between the PostTask and its execution, resulting in a use after
// free bug. Since the helper is a WebContentsUserData, it will be
// destroyed when the WebContents is and the task will not be executed.
content::WebContents* web_contents = navigation_handle()->GetWebContents();
WebContentsLifetimeHelper::CreateForWebContents(web_contents);
WebContentsLifetimeHelper* helper =
WebContentsLifetimeHelper::FromWebContents(web_contents);
content::BrowserThread::PostTask(
content::BrowserThread::UI, FROM_HERE,
base::BindOnce(&WebContentsLifetimeHelper::PostNewNavigation,
helper->GetWeakPtr(), url_params));
return content::NavigationThrottle::CANCEL;
}
content::NavigationThrottle::ThrottleCheckResult
PreviewsLitePageNavigationThrottle::WillStartRequest() {
return content::NavigationThrottle::PROCEED;
return MaybeNavigateToPreview();
}
content::NavigationThrottle::ThrottleCheckResult
PreviewsLitePageNavigationThrottle::WillRedirectRequest() {
return content::NavigationThrottle::PROCEED;
return MaybeNavigateToPreview();
}
content::NavigationThrottle::ThrottleCheckResult
......
......@@ -5,6 +5,8 @@
#ifndef CHROME_BROWSER_PREVIEWS_PREVIEWS_LITE_PAGE_NAVIGATION_THROTTLE_H_
#define CHROME_BROWSER_PREVIEWS_PREVIEWS_LITE_PAGE_NAVIGATION_THROTTLE_H_
#include "base/gtest_prod_util.h"
#include "chrome/browser/previews/previews_lite_page_navigation_throttle_manager.h"
#include "content/public/browser/navigation_handle.h"
#include "content/public/browser/navigation_throttle.h"
......@@ -14,17 +16,34 @@
// new one to the Previews Server.
class PreviewsLitePageNavigationThrottle : public content::NavigationThrottle {
public:
explicit PreviewsLitePageNavigationThrottle(
content::NavigationHandle* handle);
PreviewsLitePageNavigationThrottle(
content::NavigationHandle* handle,
PreviewsLitePageNavigationThrottleManager* manager);
~PreviewsLitePageNavigationThrottle() override;
// If a Preview is triggered, this method returns an instance of |this|.
// Otherwise it will return a nullptr.
static std::unique_ptr<content::NavigationThrottle> MaybeCreateThrottleFor(
content::NavigationHandle* handle);
private:
FRIEND_TEST_ALL_PREFIXES(PreviewsLitePageNavigationThrottleTest,
TestGetPreviewsURL);
// The current effective connection type;
net::EffectiveConnectionType GetECT() const;
// Returns true if the current URL is eligible for the preview. Does not check
// any blacklisting or single bypass.
bool IsEligibleForPreview() const;
// Returns the URL for a preview of the current URL given by the navigation
// handle.
GURL GetPreviewsURL() const;
// This method is called on every request and redirect. It checks all
// eligibility and blacklisting criteria for the current URL and will return
// CANCEL when the preview is triggered and post a new navigation, or will
// return PROCEED if the preview is not triggered.
content::NavigationThrottle::ThrottleCheckResult MaybeNavigateToPreview()
const;
// content::NavigationThrottle implementation:
content::NavigationThrottle::ThrottleCheckResult WillStartRequest() override;
content::NavigationThrottle::ThrottleCheckResult WillRedirectRequest()
......@@ -34,6 +53,10 @@ class PreviewsLitePageNavigationThrottle : public content::NavigationThrottle {
override;
const char* GetNameForLogging() override;
// The manager class to report state changes to and get state from. Outlives
// |this|.
PreviewsLitePageNavigationThrottleManager* manager_;
DISALLOW_COPY_AND_ASSIGN(PreviewsLitePageNavigationThrottle);
};
......
// 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.
#ifndef CHROME_BROWSER_PREVIEWS_PREVIEWS_LITE_PAGE_NAVIGATION_THROTTLE_MANAGER_H_
#define CHROME_BROWSER_PREVIEWS_PREVIEWS_LITE_PAGE_NAVIGATION_THROTTLE_MANAGER_H_
#include "base/time/time.h"
// This interface specifies the interaction that a
// |PreviewsLitePageNavigationThrottle| has with it's state manager. This class
// tracks the state of the Navigation Throttle since a single instance of the
// navigation throttle can be very short lived, and therefore is not aware of
// any actions taken by its predecessor.
class PreviewsLitePageNavigationThrottleManager {
public:
// Used to notify that the Previews Server should not be sent anymore requests
// until after the given time.
virtual void SetServerUnavailableUntil(base::TimeTicks retry_at) = 0;
// Returns true if a Preview should not be triggered because the server is
// unavailable.
virtual bool IsServerUnavailable(base::TimeTicks now) = 0;
};
#endif // CHROME_BROWSER_PREVIEWS_PREVIEWS_LITE_PAGE_NAVIGATION_THROTTLE_MANAGER_H_
// 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 "chrome/browser/previews/previews_lite_page_navigation_throttle.h"
#include <memory>
#include "base/memory/ptr_util.h"
#include "base/metrics/field_trial.h"
#include "base/metrics/field_trial_params.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/scoped_task_environment.h"
#include "chrome/browser/previews/previews_lite_page_decider.h"
#include "chrome/test/base/chrome_render_view_host_test_harness.h"
#include "components/previews/core/previews_features.h"
#include "content/public/browser/navigation_handle.h"
#include "net/http/http_util.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
namespace {
const char kTestUrl[] = "https://www.test.com/";
}
class PreviewsLitePageNavigationThrottleTest
: public ChromeRenderViewHostTestHarness {
protected:
PreviewsLitePageNavigationThrottleTest() = default;
void SetUp() override {
ChromeRenderViewHostTestHarness::SetUp();
test_handle_ = content::NavigationHandle::CreateNavigationHandleForTesting(
GURL(kTestUrl), main_rfh());
content::RenderFrameHostTester::For(main_rfh())
->InitializeRenderFrameIfNeeded();
}
void SimulateCommit() {
test_handle_->CallDidCommitNavigationForTesting(test_handle_->GetURL());
}
void SimulateWillProcessResponse() {
std::string headers("HTTP/1.1 200 OK\n\n");
test_handle_->CallWillProcessResponseForTesting(
main_rfh(),
net::HttpUtil::AssembleRawHeaders(headers.c_str(), headers.size()));
SimulateCommit();
}
void CallDidFinishNavigation() { test_handle_.reset(); }
content::NavigationHandle* handle() { return test_handle_.get(); }
content::NavigationHandle* handle_with_url(std::string url) {
test_handle_ = content::NavigationHandle::CreateNavigationHandleForTesting(
GURL(url), main_rfh());
return test_handle_.get();
}
private:
std::unique_ptr<content::NavigationHandle> test_handle_;
};
TEST_F(PreviewsLitePageNavigationThrottleTest, TestGetPreviewsURL) {
struct TestCase {
std::string previews_host;
std::string original_url;
std::string previews_url;
};
const TestCase kTestCases[]{
// Use https://play.golang.org/p/HUM2HxmUTOW to compute |previews_url|.
{
"https://previews.host.com",
"https://original.host.com/path/path/path?query=yes",
"https://shta44dh4bi7rc6fnpjnkrtytwlabygjhk53v2trlot2wddylwua."
"previews.host.com/p?u="
"https%3A%2F%2Foriginal.host.com%2Fpath%2Fpath%2Fpath%3Fquery%3Dyes",
},
{
"https://previews.host.com",
"http://original.host.com/path/path/path?query=yes",
"https://6p7dar4ju6r4ynz7x3pucmlcltuqsf7z5auhvckzln7voglkt56q."
"previews.host.com/p?u="
"http%3A%2F%2Foriginal.host.com%2Fpath%2Fpath%2Fpath%3Fquery%3Dyes",
},
{
"https://previews.host.com",
"https://original.host.com:1443/path/path/path?query=yes",
"https://mil6oxtqb4zpsbmutm4d7wrx5nlr6tzlxjp7y44u55zqhzsdzjpq."
"previews.host.com/p?u=https%3A%2F%2Foriginal.host.com%3A1443"
"%2Fpath%2Fpath%2Fpath%3Fquery%3Dyes",
},
{
"https://previews.host.com:1443",
"http://original.host.com/path/path/path?query=yes",
"https://6p7dar4ju6r4ynz7x3pucmlcltuqsf7z5auhvckzln7voglkt56q."
"previews.host.com:1443/p?u="
"http%3A%2F%2Foriginal.host.com%2Fpath%2Fpath%2Fpath%3Fquery%3Dyes",
},
{
"https://previews.host.com:1443",
"https://original.host.com:1443/path/path/path?query=yes",
"https://mil6oxtqb4zpsbmutm4d7wrx5nlr6tzlxjp7y44u55zqhzsdzjpq."
"previews.host.com:1443/p?u=https%3A%2F%2Foriginal.host.com%3A1443"
"%2Fpath%2Fpath%2Fpath%3Fquery%3Dyes",
},
{
"https://previews.host.com",
"https://original.host.com/path/path/path?query=yes#fragment",
"https://shta44dh4bi7rc6fnpjnkrtytwlabygjhk53v2trlot2wddylwua."
"previews.host.com/p?u="
"https%3A%2F%2Foriginal.host.com%2Fpath%2Fpath%2Fpath%3Fquery%3Dyes"
"%23fragment",
},
};
for (const TestCase& test_case : kTestCases) {
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitAndEnableFeatureWithParameters(
previews::features::kLitePageServerPreviews,
{{"previews_host", test_case.previews_host}});
std::unique_ptr<PreviewsLitePageDecider> decider =
std::make_unique<PreviewsLitePageDecider>();
std::unique_ptr<PreviewsLitePageNavigationThrottle> throttle =
std::make_unique<PreviewsLitePageNavigationThrottle>(
handle_with_url(test_case.original_url), decider.get());
EXPECT_EQ(throttle->GetPreviewsURL(), test_case.previews_url);
}
// Boilerplate navigation to keep the test harness happy.
SimulateWillProcessResponse();
CallDidFinishNavigation();
}
......@@ -2616,6 +2616,7 @@ test("unit_tests") {
"../browser/previews/previews_infobar_delegate_unittest.cc",
"../browser/previews/previews_infobar_tab_helper_unittest.cc",
"../browser/previews/previews_lite_page_decider_unittest.cc",
"../browser/previews/previews_lite_page_navigation_throttle_unittest.cc",
"../browser/previews/previews_service_unittest.cc",
"../browser/process_singleton_win_unittest.cc",
"../browser/profiles/gaia_info_update_service_unittest.cc",
......
......@@ -129,6 +129,18 @@ base::TimeDelta OfflinePreviewFreshnessDuration() {
"offline_preview_freshness_duration_in_days", 7));
}
GURL GetLitePagePreviewsDomainURL() {
std::string variable_host_str = GetFieldTrialParamValueByFeature(
features::kLitePageServerPreviews, "previews_host");
if (!variable_host_str.empty()) {
GURL variable_host(variable_host_str);
DCHECK(variable_host.is_valid());
DCHECK(variable_host.has_scheme());
return variable_host;
}
return GURL("https://litepages.googlezip.net/");
}
net::EffectiveConnectionType GetECTThresholdForPreview(
previews::PreviewsType type) {
switch (type) {
......
......@@ -11,6 +11,7 @@
#include "base/time/time.h"
#include "net/nqe/effective_connection_type.h"
#include "url/gurl.h"
namespace previews {
......@@ -88,6 +89,9 @@ base::TimeDelta SingleOptOutDuration();
// shown as a preview.
base::TimeDelta OfflinePreviewFreshnessDuration();
// The host for Lite Page server previews.
GURL GetLitePagePreviewsDomainURL();
// The threshold of EffectiveConnectionType above which preview |type| will be
// triggered.
net::EffectiveConnectionType GetECTThresholdForPreview(
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment