1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "components/google/core/browser/google_url_tracker.h"
8 #include "base/command_line.h"
9 #include "base/location.h"
10 #include "base/prefs/pref_service.h"
11 #include "base/single_thread_task_runner.h"
12 #include "base/strings/string_util.h"
13 #include "base/thread_task_runner_handle.h"
14 #include "components/google/core/browser/google_pref_names.h"
15 #include "components/google/core/browser/google_switches.h"
16 #include "components/google/core/browser/google_util.h"
17 #include "components/pref_registry/pref_registry_syncable.h"
18 #include "net/base/load_flags.h"
19 #include "net/url_request/url_fetcher.h"
20 #include "net/url_request/url_request_status.h"
23 const char GoogleURLTracker::kDefaultGoogleHomepage
[] =
24 "https://www.google.com/";
25 const char GoogleURLTracker::kSearchDomainCheckURL
[] =
26 "https://www.google.com/searchdomaincheck?format=domain&type=chrome";
28 GoogleURLTracker::GoogleURLTracker(scoped_ptr
<GoogleURLTrackerClient
> client
,
30 : client_(client
.Pass()),
31 google_url_(mode
== UNIT_TEST_MODE
?
32 kDefaultGoogleHomepage
:
33 client_
->GetPrefs()->GetString(prefs::kLastKnownGoogleURL
)),
35 in_startup_sleep_(true),
36 already_fetched_(false),
37 need_to_fetch_(false),
38 weak_ptr_factory_(this) {
39 net::NetworkChangeNotifier::AddNetworkChangeObserver(this);
40 client_
->set_google_url_tracker(this);
42 // Because this function can be called during startup, when kicking off a URL
43 // fetch can eat up 20 ms of time, we delay five seconds, which is hopefully
44 // long enough to be after startup, but still get results back quickly.
45 // Ideally, instead of this timer, we'd do something like "check if the
46 // browser is starting up, and if so, come back later", but there is currently
47 // no function to do this.
49 // In UNIT_TEST_MODE, where we want to explicitly control when the tracker
50 // "wakes up", we do nothing at all.
51 if (mode
== NORMAL_MODE
) {
52 static const int kStartFetchDelayMS
= 5000;
53 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
54 FROM_HERE
, base::Bind(&GoogleURLTracker::FinishSleep
,
55 weak_ptr_factory_
.GetWeakPtr()),
56 base::TimeDelta::FromMilliseconds(kStartFetchDelayMS
));
60 GoogleURLTracker::~GoogleURLTracker() {
64 void GoogleURLTracker::RegisterProfilePrefs(
65 user_prefs::PrefRegistrySyncable
* registry
) {
66 registry
->RegisterStringPref(prefs::kLastKnownGoogleURL
,
67 GoogleURLTracker::kDefaultGoogleHomepage
);
68 registry
->RegisterStringPref(prefs::kLastPromptedGoogleURL
, std::string());
71 void GoogleURLTracker::RequestServerCheck(bool force
) {
72 // If this instance already has a fetcher, SetNeedToFetch() is unnecessary,
73 // and changing |already_fetched_| is wrong.
76 already_fetched_
= false;
81 scoped_ptr
<GoogleURLTracker::Subscription
> GoogleURLTracker::RegisterCallback(
82 const OnGoogleURLUpdatedCallback
& cb
) {
83 return callback_list_
.Add(cb
);
86 void GoogleURLTracker::OnURLFetchComplete(const net::URLFetcher
* source
) {
87 // Delete the fetcher on this function's exit.
88 scoped_ptr
<net::URLFetcher
> clean_up_fetcher(fetcher_
.release());
90 // Don't update the URL if the request didn't succeed.
91 if (!source
->GetStatus().is_success() || (source
->GetResponseCode() != 200)) {
92 already_fetched_
= false;
96 // See if the response data was valid. It should be ".google.<TLD>".
98 source
->GetResponseAsString(&url_str
);
99 base::TrimWhitespace(url_str
, base::TRIM_ALL
, &url_str
);
100 if (!base::StartsWith(url_str
, ".google.",
101 base::CompareCase::INSENSITIVE_ASCII
))
103 GURL
url("https://www" + url_str
);
104 if (!url
.is_valid() || (url
.path().length() > 1) || url
.has_query() ||
106 !google_util::IsGoogleDomainUrl(url
, google_util::DISALLOW_SUBDOMAIN
,
107 google_util::DISALLOW_NON_STANDARD_PORTS
))
110 if (url
!= google_url_
) {
112 client_
->GetPrefs()->SetString(prefs::kLastKnownGoogleURL
,
114 callback_list_
.Notify();
118 void GoogleURLTracker::OnNetworkChanged(
119 net::NetworkChangeNotifier::ConnectionType type
) {
120 // Ignore destructive signals.
121 if (type
== net::NetworkChangeNotifier::CONNECTION_NONE
)
123 already_fetched_
= false;
124 StartFetchIfDesirable();
127 void GoogleURLTracker::Shutdown() {
130 weak_ptr_factory_
.InvalidateWeakPtrs();
131 net::NetworkChangeNotifier::RemoveNetworkChangeObserver(this);
134 void GoogleURLTracker::SetNeedToFetch() {
135 need_to_fetch_
= true;
136 StartFetchIfDesirable();
139 void GoogleURLTracker::FinishSleep() {
140 in_startup_sleep_
= false;
141 StartFetchIfDesirable();
144 void GoogleURLTracker::StartFetchIfDesirable() {
145 // Bail if a fetch isn't appropriate right now. This function will be called
146 // again each time one of the preconditions changes, so we'll fetch
147 // immediately once all of them are met.
149 // See comments in header on the class, on RequestServerCheck(), and on the
150 // various members here for more detail on exactly what the conditions are.
151 if (in_startup_sleep_
|| already_fetched_
|| !need_to_fetch_
)
154 // Some switches should disable the Google URL tracker entirely. If we can't
155 // do background networking, we can't do the necessary fetch, and if the user
156 // specified a Google base URL manually, we shouldn't bother to look up any
157 // alternatives or offer to switch to them.
158 if (!client_
->IsBackgroundNetworkingEnabled() ||
159 base::CommandLine::ForCurrentProcess()->HasSwitch(
160 switches::kGoogleBaseURL
))
163 already_fetched_
= true;
164 fetcher_
= net::URLFetcher::Create(fetcher_id_
, GURL(kSearchDomainCheckURL
),
165 net::URLFetcher::GET
, this);
167 // We don't want this fetch to set new entries in the cache or cookies, lest
168 // we alarm the user.
169 fetcher_
->SetLoadFlags(net::LOAD_DISABLE_CACHE
|
170 net::LOAD_DO_NOT_SAVE_COOKIES
);
171 fetcher_
->SetRequestContext(client_
->GetRequestContext());
173 // Configure to retry at most kMaxRetries times for 5xx errors.
174 static const int kMaxRetries
= 5;
175 fetcher_
->SetMaxRetriesOn5xx(kMaxRetries
);
177 // Also retry kMaxRetries times on network change errors. A network change can
178 // propagate through Chrome in various stages, so it's possible for this code
179 // to be reached via OnNetworkChanged(), and then have the fetch we kick off
180 // be canceled due to e.g. the DNS server changing at a later time. In general
181 // it's not possible to ensure that by the time we reach here any requests we
182 // start won't be canceled in this fashion, so retrying is the best we can do.
183 fetcher_
->SetAutomaticallyRetryOnNetworkChanges(kMaxRetries
);