Make GetSecurityLevel available from the java ToolbarModel.
[chromium-blink-merge.git] / net / proxy / proxy_config_service_win.cc
blob32553db6acba0b26273ccbb05681fecaf910d9d9
1 // Copyright (c) 2012 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 "net/proxy/proxy_config_service_win.h"
7 #include <windows.h>
8 #include <winhttp.h>
10 #include "base/logging.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "base/profiler/scoped_profile.h"
13 #include "base/stl_util.h"
14 #include "base/strings/string_util.h"
15 #include "base/strings/string_tokenizer.h"
16 #include "base/strings/utf_string_conversions.h"
17 #include "base/threading/thread_restrictions.h"
18 #include "base/win/registry.h"
19 #include "net/base/net_errors.h"
20 #include "net/proxy/proxy_config.h"
22 #pragma comment(lib, "winhttp.lib")
24 namespace net {
26 namespace {
28 const int kPollIntervalSec = 10;
30 void FreeIEConfig(WINHTTP_CURRENT_USER_IE_PROXY_CONFIG* ie_config) {
31 if (ie_config->lpszAutoConfigUrl)
32 GlobalFree(ie_config->lpszAutoConfigUrl);
33 if (ie_config->lpszProxy)
34 GlobalFree(ie_config->lpszProxy);
35 if (ie_config->lpszProxyBypass)
36 GlobalFree(ie_config->lpszProxyBypass);
39 } // namespace
41 // RegKey and ObjectWatcher pair.
42 class ProxyConfigServiceWin::KeyEntry {
43 public:
44 bool StartWatching(base::win::ObjectWatcher::Delegate* delegate) {
45 // Try to create a watch event for the registry key (which watches the
46 // sibling tree as well).
47 if (key_.StartWatching() != ERROR_SUCCESS)
48 return false;
50 // Now setup an ObjectWatcher for this event, so we get OnObjectSignaled()
51 // invoked on this message loop once it is signalled.
52 if (!watcher_.StartWatching(key_.watch_event(), delegate))
53 return false;
55 return true;
58 bool CreateRegKey(HKEY rootkey, const wchar_t* subkey) {
59 return key_.Create(rootkey, subkey, KEY_NOTIFY) == ERROR_SUCCESS;
62 HANDLE watch_event() const {
63 return key_.watch_event();
66 private:
67 base::win::RegKey key_;
68 base::win::ObjectWatcher watcher_;
71 ProxyConfigServiceWin::ProxyConfigServiceWin()
72 : PollingProxyConfigService(
73 base::TimeDelta::FromSeconds(kPollIntervalSec),
74 &ProxyConfigServiceWin::GetCurrentProxyConfig) {
77 ProxyConfigServiceWin::~ProxyConfigServiceWin() {
78 // The registry functions below will end up going to disk. Do this on another
79 // thread to avoid slowing the IO thread. http://crbug.com/61453
80 base::ThreadRestrictions::ScopedAllowIO allow_io;
81 STLDeleteElements(&keys_to_watch_);
84 void ProxyConfigServiceWin::AddObserver(Observer* observer) {
85 // Lazily-initialize our registry watcher.
86 StartWatchingRegistryForChanges();
88 // Let the super-class do its work now.
89 PollingProxyConfigService::AddObserver(observer);
92 void ProxyConfigServiceWin::StartWatchingRegistryForChanges() {
93 if (!keys_to_watch_.empty())
94 return; // Already initialized.
96 // The registry functions below will end up going to disk. Do this on another
97 // thread to avoid slowing the IO thread. http://crbug.com/61453
98 base::ThreadRestrictions::ScopedAllowIO allow_io;
100 // There are a number of different places where proxy settings can live
101 // in the registry. In some cases it appears in a binary value, in other
102 // cases string values. Furthermore winhttp and wininet appear to have
103 // separate stores, and proxy settings can be configured per-machine
104 // or per-user.
106 // This function is probably not exhaustive in the registry locations it
107 // watches for changes, however it should catch the majority of the
108 // cases. In case we have missed some less common triggers (likely), we
109 // will catch them during the periodic (10 second) polling, so things
110 // will recover.
112 AddKeyToWatchList(
113 HKEY_CURRENT_USER,
114 L"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings");
116 AddKeyToWatchList(
117 HKEY_LOCAL_MACHINE,
118 L"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings");
120 AddKeyToWatchList(
121 HKEY_LOCAL_MACHINE,
122 L"SOFTWARE\\Policies\\Microsoft\\Windows\\CurrentVersion\\"
123 L"Internet Settings");
126 bool ProxyConfigServiceWin::AddKeyToWatchList(HKEY rootkey,
127 const wchar_t* subkey) {
128 scoped_ptr<KeyEntry> entry(new KeyEntry);
129 if (!entry->CreateRegKey(rootkey, subkey))
130 return false;
132 if (!entry->StartWatching(this))
133 return false;
135 keys_to_watch_.push_back(entry.release());
136 return true;
139 void ProxyConfigServiceWin::OnObjectSignaled(HANDLE object) {
140 // TODO(vadimt): Remove ScopedProfile below once crbug.com/418183 is fixed.
141 tracked_objects::ScopedProfile tracking_profile(
142 FROM_HERE_WITH_EXPLICIT_FUNCTION(
143 "ProxyConfigServiceWin_OnObjectSignaled"));
145 // Figure out which registry key signalled this change.
146 KeyEntryList::iterator it;
147 for (it = keys_to_watch_.begin(); it != keys_to_watch_.end(); ++it) {
148 if ((*it)->watch_event() == object)
149 break;
152 DCHECK(it != keys_to_watch_.end());
154 // Keep watching the registry key.
155 if (!(*it)->StartWatching(this))
156 keys_to_watch_.erase(it);
158 // Have the PollingProxyConfigService test for changes.
159 CheckForChangesNow();
162 // static
163 void ProxyConfigServiceWin::GetCurrentProxyConfig(ProxyConfig* config) {
164 WINHTTP_CURRENT_USER_IE_PROXY_CONFIG ie_config = {0};
165 if (!WinHttpGetIEProxyConfigForCurrentUser(&ie_config)) {
166 LOG(ERROR) << "WinHttpGetIEProxyConfigForCurrentUser failed: " <<
167 GetLastError();
168 *config = ProxyConfig::CreateDirect();
169 config->set_source(PROXY_CONFIG_SOURCE_SYSTEM_FAILED);
170 return;
172 SetFromIEConfig(config, ie_config);
173 FreeIEConfig(&ie_config);
176 // static
177 void ProxyConfigServiceWin::SetFromIEConfig(
178 ProxyConfig* config,
179 const WINHTTP_CURRENT_USER_IE_PROXY_CONFIG& ie_config) {
180 if (ie_config.fAutoDetect)
181 config->set_auto_detect(true);
182 if (ie_config.lpszProxy) {
183 // lpszProxy may be a single proxy, or a proxy per scheme. The format
184 // is compatible with ProxyConfig::ProxyRules's string format.
185 config->proxy_rules().ParseFromString(
186 base::UTF16ToASCII(ie_config.lpszProxy));
188 if (ie_config.lpszProxyBypass) {
189 std::string proxy_bypass = base::UTF16ToASCII(ie_config.lpszProxyBypass);
191 base::StringTokenizer proxy_server_bypass_list(proxy_bypass, ";, \t\n\r");
192 while (proxy_server_bypass_list.GetNext()) {
193 std::string bypass_url_domain = proxy_server_bypass_list.token();
194 config->proxy_rules().bypass_rules.AddRuleFromString(bypass_url_domain);
197 if (ie_config.lpszAutoConfigUrl)
198 config->set_pac_url(GURL(ie_config.lpszAutoConfigUrl));
199 config->set_source(PROXY_CONFIG_SOURCE_SYSTEM);
202 } // namespace net