[M120][Tizen][Onscreen] Fix build errors for TV profile
[platform/framework/web/chromium-efl.git] / chrome / browser / intranet_redirect_detector.cc
1 // Copyright 2012 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/intranet_redirect_detector.h"
6
7 #include <stddef.h>
8
9 #include <utility>
10
11 #include "base/command_line.h"
12 #include "base/feature_list.h"
13 #include "base/functional/bind.h"
14 #include "base/location.h"
15 #include "base/rand_util.h"
16 #include "base/strings/utf_string_conversions.h"
17 #include "base/task/single_thread_task_runner.h"
18 #include "chrome/browser/browser_process.h"
19 #include "chrome/browser/net/system_network_context_manager.h"
20 #include "chrome/browser/profiles/profile.h"
21 #include "chrome/common/chrome_switches.h"
22 #include "chrome/common/pref_names.h"
23 #include "components/omnibox/browser/intranet_redirector_state.h"
24 #include "components/omnibox/browser/omnibox_prefs.h"
25 #include "components/omnibox/common/omnibox_features.h"
26 #include "components/prefs/pref_registry_simple.h"
27 #include "components/prefs/pref_service.h"
28 #include "content/public/browser/browser_context.h"
29 #include "content/public/browser/browser_thread.h"
30 #include "content/public/browser/network_service_instance.h"
31 #include "content/public/browser/storage_partition.h"
32 #include "mojo/public/cpp/bindings/remote.h"
33 #include "net/base/load_flags.h"
34 #include "net/base/net_errors.h"
35 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
36 #include "net/traffic_annotation/network_traffic_annotation.h"
37 #include "services/network/public/cpp/resource_request.h"
38 #include "services/network/public/cpp/simple_url_loader.h"
39 #include "services/network/public/mojom/network_service.mojom.h"
40
41 // TODO(crbug.com/181671): Write test to verify we handle the policy toggling.
42 IntranetRedirectDetector::IntranetRedirectDetector()
43     : redirect_origin_(g_browser_process->local_state()->GetString(
44           prefs::kLastKnownIntranetRedirectOrigin)) {
45   // Because this function can be called during startup, when kicking off a URL
46   // fetch can eat up 20 ms of time, we delay seven seconds, which is hopefully
47   // long enough to be after startup, but still get results back quickly.
48   // Ideally, instead of this timer, we'd do something like "check if the
49   // browser is starting up, and if so, come back later", but there is currently
50   // no function to do this.
51   static constexpr base::TimeDelta kStartFetchDelay = base::Seconds(7);
52   base::SingleThreadTaskRunner::GetCurrentDefault()->PostDelayedTask(
53       FROM_HERE,
54       base::BindOnce(&IntranetRedirectDetector::FinishSleep,
55                      weak_ptr_factory_.GetWeakPtr()),
56       kStartFetchDelay);
57
58   content::GetNetworkConnectionTracker()->AddNetworkConnectionObserver(this);
59   SetupDnsConfigClient();
60 }
61
62 IntranetRedirectDetector::~IntranetRedirectDetector() {
63   content::GetNetworkConnectionTracker()->RemoveNetworkConnectionObserver(this);
64 }
65
66 // static
67 GURL IntranetRedirectDetector::RedirectOrigin() {
68   const IntranetRedirectDetector* const detector =
69       g_browser_process->intranet_redirect_detector();
70   return detector ? detector->redirect_origin_ : GURL();
71 }
72
73 // static
74 void IntranetRedirectDetector::RegisterPrefs(PrefRegistrySimple* registry) {
75   registry->RegisterStringPref(prefs::kLastKnownIntranetRedirectOrigin,
76                                std::string());
77   registry->RegisterBooleanPref(prefs::kDNSInterceptionChecksEnabled, true);
78   registry->RegisterIntegerPref(omnibox::kIntranetRedirectBehavior, 0);
79 }
80
81 void IntranetRedirectDetector::Restart() {
82   if (!IsEnabledByPolicy()) {
83     if (redirect_origin_.is_valid()) {
84       g_browser_process->local_state()->SetString(
85           prefs::kLastKnownIntranetRedirectOrigin, std::string());
86     }
87     redirect_origin_ = GURL();
88     return;
89   }
90   // If a request is already scheduled, do not scheduled yet another one.
91   if (in_sleep_)
92     return;
93
94   // Since presumably many programs open connections after network changes,
95   // delay this a little bit.
96   in_sleep_ = true;
97   static constexpr base::TimeDelta kRestartDelay = base::Seconds(1);
98   base::SingleThreadTaskRunner::GetCurrentDefault()->PostDelayedTask(
99       FROM_HERE,
100       base::BindOnce(&IntranetRedirectDetector::FinishSleep,
101                      weak_ptr_factory_.GetWeakPtr()),
102       kRestartDelay);
103 }
104
105 void IntranetRedirectDetector::FinishSleep() {
106   in_sleep_ = false;
107   if (!IsEnabledByPolicy()) {
108     if (redirect_origin_.is_valid()) {
109       g_browser_process->local_state()->SetString(
110           prefs::kLastKnownIntranetRedirectOrigin, std::string());
111     }
112     redirect_origin_ = GURL();
113     return;
114   }
115
116   // If another fetch operation is still running, cancel it.
117   simple_loaders_.clear();
118   resulting_origins_.clear();
119
120   const base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
121   if (cmd_line->HasSwitch(switches::kDisableBackgroundNetworking))
122     return;
123
124   DCHECK(simple_loaders_.empty() && resulting_origins_.empty());
125
126   // Create traffic annotation tag.
127   net::NetworkTrafficAnnotationTag traffic_annotation =
128       net::DefineNetworkTrafficAnnotation("intranet_redirect_detector", R"(
129         semantics {
130           sender: "Intranet Redirect Detector"
131           description:
132             "This component sends requests to three randomly generated, and "
133             "thus likely nonexistent, hostnames.  If at least two redirect to "
134             "the same hostname, this suggests the ISP is hijacking NXDOMAIN, "
135             "and the omnibox should treat similar redirected navigations as "
136             "'failed' when deciding whether to prompt the user with a 'did you "
137             "mean to navigate' infobar for certain search inputs."
138           trigger: "On startup and when IP address of the computer changes."
139           data: "None, this is just an empty request."
140           destination: OTHER
141         }
142         policy {
143           cookies_allowed: NO
144           setting: "This feature cannot be disabled by settings."
145           policy_exception_justification:
146               "Not implemented, considered not useful."
147         })");
148
149   // Start three loaders on random hostnames.
150   for (size_t i = 0; i < 3; ++i) {
151     std::string url_string("http://");
152     // We generate a random hostname with between 7 and 15 characters.
153     const int num_chars = base::RandInt(7, 15);
154     for (int j = 0; j < num_chars; ++j)
155       url_string += ('a' + base::RandInt(0, 'z' - 'a'));
156     GURL random_url(url_string + '/');
157
158     auto resource_request = std::make_unique<network::ResourceRequest>();
159     resource_request->url = random_url;
160     resource_request->method = "HEAD";
161     // We don't want these fetches to affect existing state in the profile.
162     resource_request->load_flags = net::LOAD_DISABLE_CACHE;
163     resource_request->credentials_mode = network::mojom::CredentialsMode::kOmit;
164     network::mojom::URLLoaderFactory* loader_factory =
165         g_browser_process->system_network_context_manager()
166             ->GetURLLoaderFactory();
167     std::unique_ptr<network::SimpleURLLoader> simple_loader =
168         network::SimpleURLLoader::Create(std::move(resource_request),
169                                          traffic_annotation);
170     network::SimpleURLLoader* simple_loader_ptr = simple_loader.get();
171     simple_loader->DownloadToString(
172         loader_factory,
173         base::BindOnce(&IntranetRedirectDetector::OnSimpleLoaderComplete,
174                        base::Unretained(this), simple_loader_ptr),
175         /*max_body_size=*/1);
176     simple_loaders_[simple_loader_ptr] = std::move(simple_loader);
177   }
178 }
179
180 void IntranetRedirectDetector::OnSimpleLoaderComplete(
181     network::SimpleURLLoader* source,
182     std::unique_ptr<std::string> response_body) {
183   // Delete the loader on this function's exit.
184   auto it = simple_loaders_.find(source);
185   DCHECK(it != simple_loaders_.end());
186   std::unique_ptr<network::SimpleURLLoader> simple_loader =
187       std::move(it->second);
188   simple_loaders_.erase(it);
189
190   // If any two loaders result in the same domain/host, we set the redirect
191   // origin to that; otherwise we set it to nothing.
192   if (response_body) {
193     DCHECK(source->GetFinalURL().is_valid());
194     GURL origin(source->GetFinalURL().DeprecatedGetOriginAsURL());
195     if (resulting_origins_.empty()) {
196       resulting_origins_.push_back(origin);
197       return;
198     }
199     if (net::registry_controlled_domains::SameDomainOrHost(
200         resulting_origins_.front(),
201         origin,
202         net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES)) {
203       redirect_origin_ = origin;
204       if (!simple_loaders_.empty()) {
205         // Cancel remaining loader, we don't need it.
206         DCHECK(simple_loaders_.size() == 1);
207         simple_loaders_.clear();
208       }
209     }
210     if (resulting_origins_.size() == 1) {
211       resulting_origins_.push_back(origin);
212       return;
213     }
214     DCHECK(resulting_origins_.size() == 2);
215     const bool same_domain_or_host =
216         net::registry_controlled_domains::SameDomainOrHost(
217             resulting_origins_.back(),
218             origin,
219             net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES);
220     redirect_origin_ = same_domain_or_host ? origin : GURL();
221   } else {
222     if (resulting_origins_.empty() || (resulting_origins_.size() == 1 &&
223                                        resulting_origins_.front().is_valid())) {
224       resulting_origins_.push_back(GURL());
225       return;
226     }
227     redirect_origin_ = GURL();
228   }
229
230   g_browser_process->local_state()->SetString(
231       prefs::kLastKnownIntranetRedirectOrigin, redirect_origin_.is_valid() ?
232           redirect_origin_.spec() : std::string());
233 }
234
235 void IntranetRedirectDetector::OnConnectionChanged(
236     network::mojom::ConnectionType type) {
237   if (type != network::mojom::ConnectionType::CONNECTION_NONE)
238     Restart();
239 }
240
241 void IntranetRedirectDetector::OnDnsConfigChanged() {
242   Restart();
243 }
244
245 void IntranetRedirectDetector::SetupDnsConfigClient() {
246   DCHECK(!dns_config_client_receiver_.is_bound());
247
248   mojo::Remote<network::mojom::DnsConfigChangeManager> manager_remote;
249   content::GetNetworkService()->GetDnsConfigChangeManager(
250       manager_remote.BindNewPipeAndPassReceiver());
251   manager_remote->RequestNotifications(
252       dns_config_client_receiver_.BindNewPipeAndPassRemote());
253   dns_config_client_receiver_.set_disconnect_handler(base::BindOnce(
254       &IntranetRedirectDetector::OnDnsConfigClientConnectionError,
255       base::Unretained(this)));
256 }
257
258 void IntranetRedirectDetector::OnDnsConfigClientConnectionError() {
259   dns_config_client_receiver_.reset();
260   SetupDnsConfigClient();
261 }
262
263 bool IntranetRedirectDetector::IsEnabledByPolicy() {
264   // The InterceptionChecksBehavior pref and the older
265   // DNSInterceptionChecksEnabled policy should each be able to disable
266   // interception checks. Therefore, we enable the redirect detector iff allowed
267   // by both policies.
268
269   // Check IntranetRedirectorBehavior pref.
270   auto behavior =
271       omnibox::GetInterceptionChecksBehavior(g_browser_process->local_state());
272   if (behavior == omnibox::IntranetRedirectorBehavior::DISABLE_FEATURE ||
273       behavior == omnibox::IntranetRedirectorBehavior::
274                       DISABLE_INTERCEPTION_CHECKS_ENABLE_INFOBARS) {
275     return false;
276   }
277
278   // Consult previous DNSInterceptionChecksEnabled policy.
279   if (!g_browser_process->local_state()->GetBoolean(
280           prefs::kDNSInterceptionChecksEnabled))
281     return false;
282
283   return true;
284 }