1 // Copyright 2017 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.
4 
5 #include "chrome/browser/net/proxy_config_monitor.h"
6 
7 #include <utility>
8 
9 #include "base/strings/utf_string_conversions.h"
10 #include "build/build_config.h"
11 #include "chrome/browser/browser_process.h"
12 #include "chrome/browser/net/proxy_service_factory.h"
13 #include "chrome/browser/profiles/profile.h"
14 #include "components/proxy_config/pref_proxy_config_tracker_impl.h"
15 #include "content/public/browser/browser_thread.h"
16 #include "mojo/public/cpp/bindings/pending_remote.h"
17 #include "services/network/public/mojom/network_context.mojom.h"
18 
19 #if defined(OS_CHROMEOS)
20 #include "chrome/browser/chromeos/profiles/profile_helper.h"
21 #endif  // defined(OS_CHROMEOS)
22 
23 #if BUILDFLAG(ENABLE_EXTENSIONS)
24 #include "chrome/browser/extensions/api/proxy/proxy_api.h"
25 #endif
26 
27 using content::BrowserThread;
28 
ProxyConfigMonitor(Profile * profile)29 ProxyConfigMonitor::ProxyConfigMonitor(Profile* profile) {
30   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
31   DCHECK(profile);
32 
33 #if BUILDFLAG(ENABLE_EXTENSIONS)
34   profile_ = profile;
35 #endif
36 
37 // If this is the ChromeOS sign-in profile, just create the tracker from global
38 // state.
39 #if defined(OS_CHROMEOS)
40   if (chromeos::ProfileHelper::IsSigninProfile(profile)) {
41     pref_proxy_config_tracker_ =
42         ProxyServiceFactory::CreatePrefProxyConfigTrackerOfLocalState(
43             g_browser_process->local_state());
44   }
45 #endif  // defined(OS_CHROMEOS)
46 
47   if (!pref_proxy_config_tracker_) {
48     pref_proxy_config_tracker_ =
49         ProxyServiceFactory::CreatePrefProxyConfigTrackerOfProfile(
50             profile->GetPrefs(), g_browser_process->local_state());
51   }
52 
53   proxy_config_service_ = ProxyServiceFactory::CreateProxyConfigService(
54       pref_proxy_config_tracker_.get());
55 
56   proxy_config_service_->AddObserver(this);
57 }
58 
ProxyConfigMonitor(PrefService * local_state)59 ProxyConfigMonitor::ProxyConfigMonitor(PrefService* local_state) {
60   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI) ||
61          !BrowserThread::IsThreadInitialized(BrowserThread::UI));
62 
63   pref_proxy_config_tracker_ =
64       ProxyServiceFactory::CreatePrefProxyConfigTrackerOfLocalState(
65           local_state);
66 
67   proxy_config_service_ = ProxyServiceFactory::CreateProxyConfigService(
68       pref_proxy_config_tracker_.get());
69 
70   proxy_config_service_->AddObserver(this);
71 }
72 
~ProxyConfigMonitor()73 ProxyConfigMonitor::~ProxyConfigMonitor() {
74   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI) ||
75          !BrowserThread::IsThreadInitialized(BrowserThread::UI));
76   proxy_config_service_->RemoveObserver(this);
77   pref_proxy_config_tracker_->DetachFromPrefService();
78 }
79 
AddToNetworkContextParams(network::mojom::NetworkContextParams * network_context_params)80 void ProxyConfigMonitor::AddToNetworkContextParams(
81     network::mojom::NetworkContextParams* network_context_params) {
82   mojo::PendingRemote<network::mojom::ProxyConfigClient> proxy_config_client;
83   network_context_params->proxy_config_client_receiver =
84       proxy_config_client.InitWithNewPipeAndPassReceiver();
85   proxy_config_client_set_.Add(std::move(proxy_config_client));
86 
87   poller_receiver_set_.Add(this,
88                            network_context_params->proxy_config_poller_client
89                                .InitWithNewPipeAndPassReceiver());
90 
91 #if BUILDFLAG(ENABLE_EXTENSIONS)
92   error_receiver_set_.Add(this, network_context_params->proxy_error_client
93                                     .InitWithNewPipeAndPassReceiver());
94 #endif
95 
96   net::ProxyConfigWithAnnotation proxy_config;
97   net::ProxyConfigService::ConfigAvailability availability =
98       proxy_config_service_->GetLatestProxyConfig(&proxy_config);
99   if (availability != net::ProxyConfigService::CONFIG_PENDING)
100     network_context_params->initial_proxy_config = proxy_config;
101 }
102 
FlushForTesting()103 void ProxyConfigMonitor::FlushForTesting() {
104   proxy_config_client_set_.FlushForTesting();
105 }
106 
OnProxyConfigChanged(const net::ProxyConfigWithAnnotation & config,net::ProxyConfigService::ConfigAvailability availability)107 void ProxyConfigMonitor::OnProxyConfigChanged(
108     const net::ProxyConfigWithAnnotation& config,
109     net::ProxyConfigService::ConfigAvailability availability) {
110   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI) ||
111          !BrowserThread::IsThreadInitialized(BrowserThread::UI));
112   for (const auto& proxy_config_client : proxy_config_client_set_) {
113     switch (availability) {
114       case net::ProxyConfigService::CONFIG_VALID:
115         proxy_config_client->OnProxyConfigUpdated(config);
116         break;
117       case net::ProxyConfigService::CONFIG_UNSET:
118         proxy_config_client->OnProxyConfigUpdated(
119             net::ProxyConfigWithAnnotation::CreateDirect());
120         break;
121       case net::ProxyConfigService::CONFIG_PENDING:
122         NOTREACHED();
123         break;
124     }
125   }
126 }
127 
OnLazyProxyConfigPoll()128 void ProxyConfigMonitor::OnLazyProxyConfigPoll() {
129   proxy_config_service_->OnLazyPoll();
130 }
131 
132 #if BUILDFLAG(ENABLE_EXTENSIONS)
OnPACScriptError(int32_t line_number,const std::string & details)133 void ProxyConfigMonitor::OnPACScriptError(int32_t line_number,
134                                           const std::string& details) {
135   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
136   extensions::ProxyEventRouter::GetInstance()->OnPACScriptError(
137       g_browser_process->extension_event_router_forwarder(), profile_,
138       line_number, base::UTF8ToUTF16(details));
139 }
140 
OnRequestMaybeFailedDueToProxySettings(int32_t net_error)141 void ProxyConfigMonitor::OnRequestMaybeFailedDueToProxySettings(
142     int32_t net_error) {
143   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI) ||
144          !BrowserThread::IsThreadInitialized(BrowserThread::UI));
145 
146   if (net_error >= 0) {
147     // If the error is obviously wrong, don't dispatch it to extensions. If the
148     // PAC executor process is compromised, then |net_error| could be attacker
149     // controlled.
150     return;
151   }
152 
153   extensions::ProxyEventRouter::GetInstance()->OnProxyError(
154       g_browser_process->extension_event_router_forwarder(), profile_,
155       net_error);
156 }
157 #endif
158