Commit 575d8a02 authored by Robert Ogden's avatar Robert Ogden Committed by Commit Bot

Add PrefService integration to PrefetchProxyOriginDecider

Persists origin retry-after data to disk. Serialization of a base::Time
into a DictionaryValue was tricky, suggestions welcome.

Bug: 1146210
Change-Id: I57e356c44d014076fcfe3895d82cd7bd0fbdbdcf
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2531273Reviewed-by: default avatarChristian Dullweber <dullweber@chromium.org>
Reviewed-by: default avatarDominic Battré <battre@chromium.org>
Reviewed-by: default avatarRyan Sturm <ryansturm@chromium.org>
Commit-Queue: Robert Ogden <robertogden@chromium.org>
Cr-Commit-Position: refs/heads/master@{#827318}
parent 0b299f4a
...@@ -60,6 +60,9 @@ ...@@ -60,6 +60,9 @@
#include "chrome/browser/permissions/adaptive_quiet_notification_permission_ui_enabler.h" #include "chrome/browser/permissions/adaptive_quiet_notification_permission_ui_enabler.h"
#include "chrome/browser/permissions/permission_decision_auto_blocker_factory.h" #include "chrome/browser/permissions/permission_decision_auto_blocker_factory.h"
#include "chrome/browser/prefetch/no_state_prefetch/prerender_manager_factory.h" #include "chrome/browser/prefetch/no_state_prefetch/prerender_manager_factory.h"
#include "chrome/browser/prefetch/prefetch_proxy/prefetch_proxy_origin_decider.h"
#include "chrome/browser/prefetch/prefetch_proxy/prefetch_proxy_service.h"
#include "chrome/browser/prefetch/prefetch_proxy/prefetch_proxy_service_factory.h"
#include "chrome/browser/prefetch/search_prefetch/search_prefetch_service.h" #include "chrome/browser/prefetch/search_prefetch/search_prefetch_service.h"
#include "chrome/browser/prefetch/search_prefetch/search_prefetch_service_factory.h" #include "chrome/browser/prefetch/search_prefetch/search_prefetch_service_factory.h"
#include "chrome/browser/previews/previews_service.h" #include "chrome/browser/previews/previews_service.h"
...@@ -582,6 +585,12 @@ void ChromeBrowsingDataRemoverDelegate::RemoveEmbedderData( ...@@ -582,6 +585,12 @@ void ChromeBrowsingDataRemoverDelegate::RemoveEmbedderData(
if (lite_video_keyed_service) if (lite_video_keyed_service)
lite_video_keyed_service->ClearData(delete_begin_, delete_end_); lite_video_keyed_service->ClearData(delete_begin_, delete_end_);
PrefetchProxyService* prefetch_proxy_service =
PrefetchProxyServiceFactory::GetForProfile(profile_);
if (prefetch_proxy_service) {
prefetch_proxy_service->origin_decider()->OnBrowsingDataCleared();
}
#if defined(OS_ANDROID) #if defined(OS_ANDROID)
OomInterventionDecider* oom_intervention_decider = OomInterventionDecider* oom_intervention_decider =
OomInterventionDecider::GetForBrowserContext(profile_); OomInterventionDecider::GetForBrowserContext(profile_);
......
...@@ -4,21 +4,51 @@ ...@@ -4,21 +4,51 @@
#include "chrome/browser/prefetch/prefetch_proxy/prefetch_proxy_origin_decider.h" #include "chrome/browser/prefetch/prefetch_proxy/prefetch_proxy_origin_decider.h"
#include "base/time/default_clock.h" #include <memory>
#include <vector>
#include "base/util/values/values_util.h"
#include "chrome/browser/prefetch/prefetch_proxy/prefetch_proxy_params.h" #include "chrome/browser/prefetch/prefetch_proxy/prefetch_proxy_params.h"
#include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/pref_service.h"
PrefetchProxyOriginDecider::PrefetchProxyOriginDecider() namespace {
: clock_(base::DefaultClock::GetInstance()) {} // This pref contains a dictionary value whose keys are string representations
// of a url::Origin and values are a base::Time. The recorded base::Time is the
// time at which prefetch requests to the corresponding origin can resume, (any
// base::Time that is in the past can be removed). Entries to the dictionary are
// created when a prefetch request gets a 503 response with Retry-After header.
const char kRetryAfterPrefPath[] =
"chrome.prefetch_proxy.origin_decider.retry_after";
} // namespace
PrefetchProxyOriginDecider::~PrefetchProxyOriginDecider() = default; // static
void PrefetchProxyOriginDecider::RegisterPrefs(PrefRegistrySimple* registry) {
// Some loss in this pref (especially following a browser crash) is well
// tolerated and helps ensure the pref service isn't slammed.
registry->RegisterDictionaryPref(kRetryAfterPrefPath,
PrefRegistry::LOSSY_PREF);
}
PrefetchProxyOriginDecider::PrefetchProxyOriginDecider(
PrefService* pref_service,
base::Clock* clock)
: pref_service_(pref_service), clock_(clock) {
DCHECK(pref_service);
DCHECK(clock);
void PrefetchProxyOriginDecider::SetClockForTesting(const base::Clock* clock) { LoadFromPrefs();
clock_ = clock; if (ClearPastEntries()) {
SaveToPrefs();
}
} }
PrefetchProxyOriginDecider::~PrefetchProxyOriginDecider() = default;
void PrefetchProxyOriginDecider::OnBrowsingDataCleared() { void PrefetchProxyOriginDecider::OnBrowsingDataCleared() {
origin_retry_afters_.clear(); origin_retry_afters_.clear();
SaveToPrefs();
} }
bool PrefetchProxyOriginDecider::IsOriginOutsideRetryAfterWindow( bool PrefetchProxyOriginDecider::IsOriginOutsideRetryAfterWindow(
...@@ -48,4 +78,62 @@ void PrefetchProxyOriginDecider::ReportOriginRetryAfter( ...@@ -48,4 +78,62 @@ void PrefetchProxyOriginDecider::ReportOriginRetryAfter(
origin_retry_afters_.emplace(url::Origin::Create(url), origin_retry_afters_.emplace(url::Origin::Create(url),
clock_->Now() + retry_after); clock_->Now() + retry_after);
SaveToPrefs();
}
void PrefetchProxyOriginDecider::LoadFromPrefs() {
origin_retry_afters_.clear();
const base::DictionaryValue* dictionary =
pref_service_->GetDictionary(kRetryAfterPrefPath);
DCHECK(dictionary);
for (const auto& element : *dictionary) {
GURL url_origin(element.first);
if (!url_origin.is_valid()) {
// This may happen in the case of corrupted prefs, or otherwise. Handle
// gracefully.
NOTREACHED();
continue;
}
base::Optional<base::Time> retry_after = util::ValueToTime(*element.second);
if (!retry_after) {
// This may happen in the case of corrupted prefs, or otherwise. Handle
// gracefully.
NOTREACHED();
continue;
}
url::Origin origin = url::Origin::Create(url_origin);
origin_retry_afters_.emplace(origin, retry_after.value());
}
}
void PrefetchProxyOriginDecider::SaveToPrefs() const {
base::DictionaryValue dictionary;
for (const auto& element : origin_retry_afters_) {
std::string key = element.first.GetURL().spec();
base::Value value = util::TimeToValue(element.second);
dictionary.SetKey(std::move(key), std::move(value));
}
pref_service_->Set(kRetryAfterPrefPath, dictionary);
}
bool PrefetchProxyOriginDecider::ClearPastEntries() {
std::vector<url::Origin> to_remove;
for (const auto& entry : origin_retry_afters_) {
if (entry.second < clock_->Now()) {
to_remove.push_back(entry.first);
}
}
if (to_remove.empty()) {
return false;
}
for (const auto& rm : to_remove) {
origin_retry_afters_.erase(rm);
}
return true;
} }
...@@ -8,17 +8,27 @@ ...@@ -8,17 +8,27 @@
#include <map> #include <map>
#include "base/time/clock.h" #include "base/time/clock.h"
#include "base/time/default_clock.h"
#include "base/time/time.h" #include "base/time/time.h"
#include "url/gurl.h" #include "url/gurl.h"
#include "url/origin.h" #include "url/origin.h"
class PrefService;
class PrefRegistrySimple;
// A browser-scoped class that maintains persistent logic for when origins // A browser-scoped class that maintains persistent logic for when origins
// should not be prefetched. // should not be prefetched.
class PrefetchProxyOriginDecider { class PrefetchProxyOriginDecider {
public: public:
PrefetchProxyOriginDecider(); explicit PrefetchProxyOriginDecider(
PrefService* pref_service,
base::Clock* clock = base::DefaultClock::GetInstance());
~PrefetchProxyOriginDecider(); ~PrefetchProxyOriginDecider();
// Registers prefs. Should only be used for storing in a device-local registry
// (non-syncing).
static void RegisterPrefs(PrefRegistrySimple* registry);
// This should be called anytime browsing data is cleared by the user so that // This should be called anytime browsing data is cleared by the user so that
// the persistent data store can be cleared as well. // the persistent data store can be cleared as well.
void OnBrowsingDataCleared(); void OnBrowsingDataCleared();
...@@ -32,9 +42,23 @@ class PrefetchProxyOriginDecider { ...@@ -32,9 +42,23 @@ class PrefetchProxyOriginDecider {
// a maximum value provided by experiment params. // a maximum value provided by experiment params.
void ReportOriginRetryAfter(const GURL& url, base::TimeDelta retry_after); void ReportOriginRetryAfter(const GURL& url, base::TimeDelta retry_after);
void SetClockForTesting(const base::Clock* clock); PrefetchProxyOriginDecider(const PrefetchProxyOriginDecider&) = delete;
PrefetchProxyOriginDecider& operator=(const PrefetchProxyOriginDecider&) =
delete;
private: private:
// These methods serialize and deserialize |origin_retry_afters_| to
// |pref_service_| in a dictionary value.
void LoadFromPrefs();
void SaveToPrefs() const;
// Erases any expired entries in |origin_retry_afters_|, returning true iff
// any entries were removed.
bool ClearPastEntries();
// Not owned.
PrefService* pref_service_;
const base::Clock* clock_; const base::Clock* clock_;
// Maps origins to their last known retry_after time. // Maps origins to their last known retry_after time.
......
...@@ -7,57 +7,75 @@ ...@@ -7,57 +7,75 @@
#include "base/test/scoped_feature_list.h" #include "base/test/scoped_feature_list.h"
#include "base/test/simple_test_clock.h" #include "base/test/simple_test_clock.h"
#include "chrome/browser/prefetch/prefetch_proxy/prefetch_proxy_features.h" #include "chrome/browser/prefetch/prefetch_proxy/prefetch_proxy_features.h"
#include "components/prefs/testing_pref_service.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
TEST(PrefetchProxyOriginDeciderTest, DefaultEligible) { class PrefetchProxyOriginDeciderTest : public testing::Test {
PrefetchProxyOriginDecider decider; public:
EXPECT_TRUE(decider.IsOriginOutsideRetryAfterWindow(GURL("http://foo.com"))); void SetUp() override {
PrefetchProxyOriginDecider::RegisterPrefs(pref_service_.registry());
}
std::unique_ptr<PrefetchProxyOriginDecider> NewDecider() {
return std::make_unique<PrefetchProxyOriginDecider>(&pref_service_,
&clock_);
}
base::SimpleTestClock* clock() { return &clock_; }
private:
TestingPrefServiceSimple pref_service_;
base::SimpleTestClock clock_;
};
TEST_F(PrefetchProxyOriginDeciderTest, DefaultEligible) {
auto decider = NewDecider();
EXPECT_TRUE(decider->IsOriginOutsideRetryAfterWindow(GURL("http://foo.com")));
} }
TEST(PrefetchProxyOriginDeciderTest, NegativeIgnored) { TEST_F(PrefetchProxyOriginDeciderTest, NegativeIgnored) {
GURL url("http://foo.com"); GURL url("http://foo.com");
PrefetchProxyOriginDecider decider;
decider.ReportOriginRetryAfter(url, base::TimeDelta::FromSeconds(-1)); auto decider = NewDecider();
EXPECT_TRUE(decider.IsOriginOutsideRetryAfterWindow(url)); decider->ReportOriginRetryAfter(url, base::TimeDelta::FromSeconds(-1));
EXPECT_TRUE(decider->IsOriginOutsideRetryAfterWindow(url));
} }
TEST(PrefetchProxyOriginDeciderTest, MaxCap) { TEST_F(PrefetchProxyOriginDeciderTest, MaxCap) {
base::test::ScopedFeatureList scoped_feature_list; base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitAndEnableFeatureWithParameters( scoped_feature_list.InitAndEnableFeatureWithParameters(
features::kIsolatePrerenders, {{"max_retry_after_duration_secs", "10"}}); features::kIsolatePrerenders, {{"max_retry_after_duration_secs", "10"}});
GURL url("http://foo.com"); GURL url("http://foo.com");
PrefetchProxyOriginDecider decider;
base::SimpleTestClock clock;
decider.SetClockForTesting(&clock);
decider.ReportOriginRetryAfter(url, base::TimeDelta::FromSeconds(15)); auto decider = NewDecider();
EXPECT_FALSE(decider.IsOriginOutsideRetryAfterWindow(url));
decider->ReportOriginRetryAfter(url, base::TimeDelta::FromSeconds(15));
EXPECT_FALSE(decider->IsOriginOutsideRetryAfterWindow(url));
clock.Advance(base::TimeDelta::FromSeconds(11)); clock()->Advance(base::TimeDelta::FromSeconds(11));
EXPECT_TRUE(decider.IsOriginOutsideRetryAfterWindow(url)); EXPECT_TRUE(decider->IsOriginOutsideRetryAfterWindow(url));
} }
TEST(PrefetchProxyOriginDeciderTest, WaitsForDelta) { TEST_F(PrefetchProxyOriginDeciderTest, WaitsForDelta) {
GURL url("http://foo.com"); GURL url("http://foo.com");
PrefetchProxyOriginDecider decider;
base::SimpleTestClock clock;
decider.SetClockForTesting(&clock);
decider.ReportOriginRetryAfter(url, base::TimeDelta::FromSeconds(15)); auto decider = NewDecider();
decider->ReportOriginRetryAfter(url, base::TimeDelta::FromSeconds(15));
for (size_t i = 0; i <= 15; i++) { for (size_t i = 0; i <= 15; i++) {
EXPECT_FALSE(decider.IsOriginOutsideRetryAfterWindow(url)); EXPECT_FALSE(decider->IsOriginOutsideRetryAfterWindow(url));
clock.Advance(base::TimeDelta::FromSeconds(1)); clock()->Advance(base::TimeDelta::FromSeconds(1));
} }
EXPECT_TRUE(decider.IsOriginOutsideRetryAfterWindow(url)); EXPECT_TRUE(decider->IsOriginOutsideRetryAfterWindow(url));
} }
TEST(PrefetchProxyOriginDeciderTest, ByOrigin) { TEST_F(PrefetchProxyOriginDeciderTest, ByOrigin) {
PrefetchProxyOriginDecider decider; auto decider = NewDecider();
decider.ReportOriginRetryAfter(GURL("http://foo.com"), decider->ReportOriginRetryAfter(GURL("http://foo.com"),
base::TimeDelta::FromSeconds(1)); base::TimeDelta::FromSeconds(1));
// Any url for the origin should be ineligible. // Any url for the origin should be ineligible.
...@@ -67,7 +85,7 @@ TEST(PrefetchProxyOriginDeciderTest, ByOrigin) { ...@@ -67,7 +85,7 @@ TEST(PrefetchProxyOriginDeciderTest, ByOrigin) {
GURL("http://foo.com/?query=yes"), GURL("http://foo.com/?query=yes"),
}) { }) {
SCOPED_TRACE(url); SCOPED_TRACE(url);
EXPECT_FALSE(decider.IsOriginOutsideRetryAfterWindow(url)); EXPECT_FALSE(decider->IsOriginOutsideRetryAfterWindow(url));
} }
// Other origins are eligible. // Other origins are eligible.
...@@ -77,17 +95,40 @@ TEST(PrefetchProxyOriginDeciderTest, ByOrigin) { ...@@ -77,17 +95,40 @@ TEST(PrefetchProxyOriginDeciderTest, ByOrigin) {
GURL("http://test.com/"), GURL("http://test.com/"),
}) { }) {
SCOPED_TRACE(url); SCOPED_TRACE(url);
EXPECT_TRUE(decider.IsOriginOutsideRetryAfterWindow(url)); EXPECT_TRUE(decider->IsOriginOutsideRetryAfterWindow(url));
} }
} }
TEST(PrefetchProxyOriginDeciderTest, Clear) { TEST_F(PrefetchProxyOriginDeciderTest, Clear) {
GURL url("http://foo.com"); GURL url("http://foo.com");
PrefetchProxyOriginDecider decider;
decider.ReportOriginRetryAfter(url, base::TimeDelta::FromSeconds(1)); auto decider = NewDecider();
EXPECT_FALSE(decider.IsOriginOutsideRetryAfterWindow(url));
decider->ReportOriginRetryAfter(url, base::TimeDelta::FromSeconds(1));
EXPECT_FALSE(decider->IsOriginOutsideRetryAfterWindow(url));
decider.OnBrowsingDataCleared(); decider->OnBrowsingDataCleared();
EXPECT_TRUE(decider.IsOriginOutsideRetryAfterWindow(url)); EXPECT_TRUE(decider->IsOriginOutsideRetryAfterWindow(url));
}
TEST_F(PrefetchProxyOriginDeciderTest, PersistentPrefs) {
{
auto decider = NewDecider();
decider->ReportOriginRetryAfter(GURL("http://expired.com"),
base::TimeDelta::FromSeconds(1));
decider->ReportOriginRetryAfter(GURL("http://foo.com"),
base::TimeDelta::FromSeconds(3));
}
clock()->Advance(base::TimeDelta::FromSeconds(2));
{
auto decider = NewDecider();
EXPECT_TRUE(
decider->IsOriginOutsideRetryAfterWindow(GURL("http://expired.com")));
EXPECT_FALSE(
decider->IsOriginOutsideRetryAfterWindow(GURL("http://foo.com")));
}
} }
...@@ -22,7 +22,8 @@ PrefetchProxyService::PrefetchProxyService(Profile* profile) ...@@ -22,7 +22,8 @@ PrefetchProxyService::PrefetchProxyService(Profile* profile)
: profile_(profile), : profile_(profile),
proxy_configurator_(std::make_unique<PrefetchProxyProxyConfigurator>()), proxy_configurator_(std::make_unique<PrefetchProxyProxyConfigurator>()),
origin_prober_(std::make_unique<PrefetchProxyOriginProber>(profile)), origin_prober_(std::make_unique<PrefetchProxyOriginProber>(profile)),
origin_decider_(std::make_unique<PrefetchProxyOriginDecider>()) {} origin_decider_(
std::make_unique<PrefetchProxyOriginDecider>(profile->GetPrefs())) {}
PrefetchProxyService::~PrefetchProxyService() = default; PrefetchProxyService::~PrefetchProxyService() = default;
......
...@@ -52,6 +52,7 @@ ...@@ -52,6 +52,7 @@
#include "chrome/browser/permissions/quiet_notification_permission_ui_state.h" #include "chrome/browser/permissions/quiet_notification_permission_ui_state.h"
#include "chrome/browser/policy/developer_tools_policy_handler.h" #include "chrome/browser/policy/developer_tools_policy_handler.h"
#include "chrome/browser/policy/webusb_allow_devices_for_urls_policy_handler.h" #include "chrome/browser/policy/webusb_allow_devices_for_urls_policy_handler.h"
#include "chrome/browser/prefetch/prefetch_proxy/prefetch_proxy_origin_decider.h"
#include "chrome/browser/prefs/chrome_pref_service_factory.h" #include "chrome/browser/prefs/chrome_pref_service_factory.h"
#include "chrome/browser/prefs/incognito_mode_prefs.h" #include "chrome/browser/prefs/incognito_mode_prefs.h"
#include "chrome/browser/prefs/origin_trial_prefs.h" #include "chrome/browser/prefs/origin_trial_prefs.h"
...@@ -817,6 +818,7 @@ void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry, ...@@ -817,6 +818,7 @@ void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry,
policy::DeveloperToolsPolicyHandler::RegisterProfilePrefs(registry); policy::DeveloperToolsPolicyHandler::RegisterProfilePrefs(registry);
policy::URLBlocklistManager::RegisterProfilePrefs(registry); policy::URLBlocklistManager::RegisterProfilePrefs(registry);
PrefProxyConfigTrackerImpl::RegisterProfilePrefs(registry); PrefProxyConfigTrackerImpl::RegisterProfilePrefs(registry);
PrefetchProxyOriginDecider::RegisterPrefs(registry);
PrefsTabHelper::RegisterProfilePrefs(registry, locale); PrefsTabHelper::RegisterProfilePrefs(registry, locale);
PreviewsHTTPSNotificationInfoBarDecider::RegisterProfilePrefs(registry); PreviewsHTTPSNotificationInfoBarDecider::RegisterProfilePrefs(registry);
Profile::RegisterProfilePrefs(registry); Profile::RegisterProfilePrefs(registry);
......
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