blob: cef6cdc7944e506c0100d43e561c98075bc05a2a [file] [log] [blame]
// Copyright 2019 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_REDIRECT_PREDICTOR_H_
#define CHROME_BROWSER_PREVIEWS_PREVIEWS_LITE_PAGE_REDIRECT_PREDICTOR_H_
#include <memory>
#include "base/callback.h"
#include "base/gtest_prod_util.h"
#include "base/macros.h"
#include "base/optional.h"
#include "base/sequence_checker.h"
#include "base/timer/timer.h"
#include "content/public/browser/web_contents_observer.h"
#include "content/public/browser/web_contents_user_data.h"
#include "net/nqe/effective_connection_type.h"
#include "services/network/public/cpp/network_quality_tracker.h"
#include "url/gurl.h"
namespace content {
class NavigationHandle;
} // namespace content
namespace data_reduction_proxy {
class DataReductionProxySettings;
}
namespace previews {
class PreviewsOptimizationGuide;
}
// Manages background preresolving or preconnecting for lite page redirect
// previews. When a set of conditions are met, this class causes the litepage
// version of the current committed page URL to be preresolved/preconnected in a
// loop so that the DNS entry for the litepage is always cached, or the origin
// URL to be preresolved/preconnected if the current page is a preview. This
// helps to mitigate the delay of loading a preview or the original page of the
// same origin.
//
// All of the following conditions must be met to preresolve/preconnect the
// litepages host on a background loop during a page load:
// * We allow preresolving/preconnecting by feature param.
// * A page is committed.
// * There is no ongoing navigation.
// * Lite mode is enabled for the user. - Note this change is not directly
// observed because we find that it seldom changes in practice.
// * The lite page redirect feature is enabled.
// * ECT is at or below the lite page redirect threshold.
// * The current page's host is not blacklisted by server hints.
// * The current page isn't a litepage preview already.
// * Chrome is in the foreground.
// * This' |web_contents| is in the foreground.
class PreviewsLitePageRedirectPredictor
: public network::NetworkQualityTracker::EffectiveConnectionTypeObserver,
public content::WebContentsObserver,
public content::WebContentsUserData<PreviewsLitePageRedirectPredictor> {
public:
~PreviewsLitePageRedirectPredictor() override;
// content::WebContentsObserver:
void DidFinishNavigation(content::NavigationHandle* handle) override;
void DidStartNavigation(content::NavigationHandle* handle) override;
void OnVisibilityChanged(content::Visibility visibility) override;
// network::NetworkQualityTracker::EffectiveConnectionTypeObserver:
void OnEffectiveConnectionTypeChanged(
net::EffectiveConnectionType ect) override;
protected:
explicit PreviewsLitePageRedirectPredictor(
content::WebContents* web_contents);
// Virtual for testing.
virtual bool DataSaverIsEnabled() const;
virtual bool ECTIsSlow() const;
virtual bool PageIsBlacklisted(
content::NavigationHandle* navigation_handle) const;
// Returns true when this |web_contents| is the active tab and Chrome is in
// the foreground. Virtual for testing.
virtual bool IsVisible() const;
private:
friend class content::WebContentsUserData<PreviewsLitePageRedirectPredictor>;
FRIEND_TEST_ALL_PREFIXES(PreviewsLitePageRedirectPredictorUnitTest,
AllConditionsMet_Origin);
FRIEND_TEST_ALL_PREFIXES(PreviewsLitePageRedirectPredictorUnitTest,
AllConditionsMet_Preview);
FRIEND_TEST_ALL_PREFIXES(PreviewsLitePageRedirectPredictorUnitTest,
FeatureDisabled);
FRIEND_TEST_ALL_PREFIXES(PreviewsLitePageRedirectPredictorUnitTest,
DataSaverDisabled);
FRIEND_TEST_ALL_PREFIXES(PreviewsLitePageRedirectPredictorUnitTest,
NoNavigation);
FRIEND_TEST_ALL_PREFIXES(PreviewsLitePageRedirectPredictorUnitTest,
ECTNotSlow);
FRIEND_TEST_ALL_PREFIXES(PreviewsLitePageRedirectPredictorUnitTest,
ECTNotSlowOnPreview);
FRIEND_TEST_ALL_PREFIXES(PreviewsLitePageRedirectPredictorUnitTest,
PageBlacklisted);
FRIEND_TEST_ALL_PREFIXES(PreviewsLitePageRedirectPredictorUnitTest,
NotVisible);
FRIEND_TEST_ALL_PREFIXES(PreviewsLitePageRedirectPredictorUnitTest,
InsecurePage);
FRIEND_TEST_ALL_PREFIXES(PreviewsLitePageRedirectPredictorUnitTest,
ToggleMultipleTimes_Navigations);
FRIEND_TEST_ALL_PREFIXES(PreviewsLitePageRedirectPredictorUnitTest,
ToggleMultipleTimes_ECT);
FRIEND_TEST_ALL_PREFIXES(PreviewsLitePageRedirectPredictorUnitTest,
ToggleMultipleTimes_Visibility);
// Returns the GURL that should be preresolved, if any.
base::Optional<GURL> ShouldActOnPage(
content::NavigationHandle* navigation_handle) const;
// Toggles preresolving to either start or stop as needed. This operates
// statelessly, but should be called every time a change potentially needs to
// be made. See observers below.
void MaybeToggleTimer(content::NavigationHandle* navigation_handle);
// Immediately causes |url_| to be preresolved/preconnected.
void PreresolveOrPreconnect() const;
// Set if the preview URL is actively being preresolved/preconnected.
std::unique_ptr<base::RepeatingTimer> timer_;
// The url that should be preresolved/preconnected, if any.
base::Optional<GURL> url_;
// A reference to the DRP Settings.
data_reduction_proxy::DataReductionProxySettings* drp_settings_;
// A reference to the PreviewsOptimizationGuide.
previews::PreviewsOptimizationGuide* opt_guide_;
WEB_CONTENTS_USER_DATA_KEY_DECL();
SEQUENCE_CHECKER(sequence_checker_);
DISALLOW_COPY_AND_ASSIGN(PreviewsLitePageRedirectPredictor);
};
#endif // CHROME_BROWSER_PREVIEWS_PREVIEWS_LITE_PAGE_REDIRECT_PREDICTOR_H_