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/prefs/pref_service.h"
10 #include "base/strings/string_util.h"
11 #include "components/google/core/browser/google_pref_names.h"
12 #include "components/google/core/browser/google_switches.h"
13 #include "components/google/core/browser/google_util.h"
14 #include "net/base/load_flags.h"
15 #include "net/url_request/url_fetcher.h"
16 #include "net/url_request/url_request_status.h"
19 const char GoogleURLTracker::kDefaultGoogleHomepage
[] =
20 "https://www.google.com/";
21 const char GoogleURLTracker::kSearchDomainCheckURL
[] =
22 "https://www.google.com/searchdomaincheck?format=domain&type=chrome";
24 GoogleURLTracker::GoogleURLTracker(scoped_ptr
<GoogleURLTrackerClient
> client
,
26 : client_(client
.Pass()),
27 google_url_(mode
== UNIT_TEST_MODE
?
28 kDefaultGoogleHomepage
:
29 client_
->GetPrefs()->GetString(prefs::kLastKnownGoogleURL
)),
31 in_startup_sleep_(true),
32 already_fetched_(false),
33 need_to_fetch_(false),
34 weak_ptr_factory_(this) {
35 net::NetworkChangeNotifier::AddNetworkChangeObserver(this);
36 client_
->set_google_url_tracker(this);
38 // Because this function can be called during startup, when kicking off a URL
39 // fetch can eat up 20 ms of time, we delay five seconds, which is hopefully
40 // long enough to be after startup, but still get results back quickly.
41 // Ideally, instead of this timer, we'd do something like "check if the
42 // browser is starting up, and if so, come back later", but there is currently
43 // no function to do this.
45 // In UNIT_TEST_MODE, where we want to explicitly control when the tracker
46 // "wakes up", we do nothing at all.
47 if (mode
== NORMAL_MODE
) {
48 static const int kStartFetchDelayMS
= 5000;
49 base::MessageLoop::current()->PostDelayedTask(FROM_HERE
,
50 base::Bind(&GoogleURLTracker::FinishSleep
,
51 weak_ptr_factory_
.GetWeakPtr()),
52 base::TimeDelta::FromMilliseconds(kStartFetchDelayMS
));
56 GoogleURLTracker::~GoogleURLTracker() {
59 void GoogleURLTracker::RequestServerCheck(bool force
) {
60 // If this instance already has a fetcher, SetNeedToFetch() is unnecessary,
61 // and changing |already_fetched_| is wrong.
64 already_fetched_
= false;
69 scoped_ptr
<GoogleURLTracker::Subscription
> GoogleURLTracker::RegisterCallback(
70 const OnGoogleURLUpdatedCallback
& cb
) {
71 return callback_list_
.Add(cb
);
74 void GoogleURLTracker::OnURLFetchComplete(const net::URLFetcher
* source
) {
75 // Delete the fetcher on this function's exit.
76 scoped_ptr
<net::URLFetcher
> clean_up_fetcher(fetcher_
.release());
78 // Don't update the URL if the request didn't succeed.
79 if (!source
->GetStatus().is_success() || (source
->GetResponseCode() != 200)) {
80 already_fetched_
= false;
84 // See if the response data was valid. It should be ".google.<TLD>".
86 source
->GetResponseAsString(&url_str
);
87 base::TrimWhitespace(url_str
, base::TRIM_ALL
, &url_str
);
88 if (!StartsWithASCII(url_str
, ".google.", false))
90 GURL
url("https://www" + url_str
);
91 if (!url
.is_valid() || (url
.path().length() > 1) || url
.has_query() ||
93 !google_util::IsGoogleDomainUrl(url
, google_util::DISALLOW_SUBDOMAIN
,
94 google_util::DISALLOW_NON_STANDARD_PORTS
))
97 if (url
!= google_url_
) {
99 client_
->GetPrefs()->SetString(prefs::kLastKnownGoogleURL
,
101 callback_list_
.Notify();
105 void GoogleURLTracker::OnNetworkChanged(
106 net::NetworkChangeNotifier::ConnectionType type
) {
107 // Ignore destructive signals.
108 if (type
== net::NetworkChangeNotifier::CONNECTION_NONE
)
110 already_fetched_
= false;
111 StartFetchIfDesirable();
114 void GoogleURLTracker::Shutdown() {
117 weak_ptr_factory_
.InvalidateWeakPtrs();
118 net::NetworkChangeNotifier::RemoveNetworkChangeObserver(this);
121 void GoogleURLTracker::SetNeedToFetch() {
122 need_to_fetch_
= true;
123 StartFetchIfDesirable();
126 void GoogleURLTracker::FinishSleep() {
127 in_startup_sleep_
= false;
128 StartFetchIfDesirable();
131 void GoogleURLTracker::StartFetchIfDesirable() {
132 // Bail if a fetch isn't appropriate right now. This function will be called
133 // again each time one of the preconditions changes, so we'll fetch
134 // immediately once all of them are met.
136 // See comments in header on the class, on RequestServerCheck(), and on the
137 // various members here for more detail on exactly what the conditions are.
138 if (in_startup_sleep_
|| already_fetched_
|| !need_to_fetch_
)
141 // Some switches should disable the Google URL tracker entirely. If we can't
142 // do background networking, we can't do the necessary fetch, and if the user
143 // specified a Google base URL manually, we shouldn't bother to look up any
144 // alternatives or offer to switch to them.
145 if (!client_
->IsBackgroundNetworkingEnabled() ||
146 base::CommandLine::ForCurrentProcess()->HasSwitch(
147 switches::kGoogleBaseURL
))
150 already_fetched_
= true;
151 fetcher_
.reset(net::URLFetcher::Create(
152 fetcher_id_
, GURL(kSearchDomainCheckURL
), net::URLFetcher::GET
, this));
154 // We don't want this fetch to set new entries in the cache or cookies, lest
155 // we alarm the user.
156 fetcher_
->SetLoadFlags(net::LOAD_DISABLE_CACHE
|
157 net::LOAD_DO_NOT_SAVE_COOKIES
);
158 fetcher_
->SetRequestContext(client_
->GetRequestContext());
160 // Configure to retry at most kMaxRetries times for 5xx errors.
161 static const int kMaxRetries
= 5;
162 fetcher_
->SetMaxRetriesOn5xx(kMaxRetries
);
164 // Also retry kMaxRetries times on network change errors. A network change can
165 // propagate through Chrome in various stages, so it's possible for this code
166 // to be reached via OnNetworkChanged(), and then have the fetch we kick off
167 // be canceled due to e.g. the DNS server changing at a later time. In general
168 // it's not possible to ensure that by the time we reach here any requests we
169 // start won't be canceled in this fashion, so retrying is the best we can do.
170 fetcher_
->SetAutomaticallyRetryOnNetworkChanges(kMaxRetries
);