Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / net / proxy / proxy_config_service_win.cc
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.
4
5 #include "net/proxy/proxy_config_service_win.h"
6
7 #include <windows.h>
8 #include <winhttp.h>
9
10 #include "base/bind.h"
11 #include "base/bind_helpers.h"
12 #include "base/logging.h"
13 #include "base/memory/scoped_ptr.h"
14 #include "base/profiler/scoped_tracker.h"
15 #include "base/stl_util.h"
16 #include "base/strings/string_util.h"
17 #include "base/strings/string_tokenizer.h"
18 #include "base/strings/utf_string_conversions.h"
19 #include "base/threading/thread_restrictions.h"
20 #include "base/win/registry.h"
21 #include "base/win/scoped_handle.h"
22 #include "net/base/net_errors.h"
23 #include "net/proxy/proxy_config.h"
24
25 #pragma comment(lib, "winhttp.lib")
26
27 namespace net {
28
29 namespace {
30
31 const int kPollIntervalSec = 10;
32
33 void FreeIEConfig(WINHTTP_CURRENT_USER_IE_PROXY_CONFIG* ie_config) {
34   if (ie_config->lpszAutoConfigUrl)
35     GlobalFree(ie_config->lpszAutoConfigUrl);
36   if (ie_config->lpszProxy)
37     GlobalFree(ie_config->lpszProxy);
38   if (ie_config->lpszProxyBypass)
39     GlobalFree(ie_config->lpszProxyBypass);
40 }
41
42 }  // namespace
43
44 ProxyConfigServiceWin::ProxyConfigServiceWin()
45     : PollingProxyConfigService(
46           base::TimeDelta::FromSeconds(kPollIntervalSec),
47           &ProxyConfigServiceWin::GetCurrentProxyConfig) {
48 }
49
50 ProxyConfigServiceWin::~ProxyConfigServiceWin() {
51   // The registry functions below will end up going to disk.  Do this on another
52   // thread to avoid slowing the IO thread.  http://crbug.com/61453
53   base::ThreadRestrictions::ScopedAllowIO allow_io;
54   STLDeleteElements(&keys_to_watch_);
55 }
56
57 void ProxyConfigServiceWin::AddObserver(Observer* observer) {
58   // Lazily-initialize our registry watcher.
59   StartWatchingRegistryForChanges();
60
61   // Let the super-class do its work now.
62   PollingProxyConfigService::AddObserver(observer);
63 }
64
65 void ProxyConfigServiceWin::StartWatchingRegistryForChanges() {
66   if (!keys_to_watch_.empty())
67     return;  // Already initialized.
68
69   // The registry functions below will end up going to disk.  Do this on another
70   // thread to avoid slowing the IO thread.  http://crbug.com/61453
71   base::ThreadRestrictions::ScopedAllowIO allow_io;
72
73   // There are a number of different places where proxy settings can live
74   // in the registry. In some cases it appears in a binary value, in other
75   // cases string values. Furthermore winhttp and wininet appear to have
76   // separate stores, and proxy settings can be configured per-machine
77   // or per-user.
78   //
79   // This function is probably not exhaustive in the registry locations it
80   // watches for changes, however it should catch the majority of the
81   // cases. In case we have missed some less common triggers (likely), we
82   // will catch them during the periodic (10 second) polling, so things
83   // will recover.
84
85   AddKeyToWatchList(
86       HKEY_CURRENT_USER,
87       L"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings");
88
89   AddKeyToWatchList(
90       HKEY_LOCAL_MACHINE,
91       L"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings");
92
93   AddKeyToWatchList(
94       HKEY_LOCAL_MACHINE,
95       L"SOFTWARE\\Policies\\Microsoft\\Windows\\CurrentVersion\\"
96       L"Internet Settings");
97 }
98
99 bool ProxyConfigServiceWin::AddKeyToWatchList(HKEY rootkey,
100                                               const wchar_t* subkey) {
101   scoped_ptr<base::win::RegKey> key(new base::win::RegKey);
102   if (key->Create(rootkey, subkey, KEY_NOTIFY) != ERROR_SUCCESS)
103     return false;
104
105   if (!key->StartWatching(base::Bind(&ProxyConfigServiceWin::OnObjectSignaled,
106                                      base::Unretained(this),
107                                      base::Unretained(key.get())))) {
108     return false;
109   }
110
111   keys_to_watch_.push_back(key.release());
112   return true;
113 }
114
115 void ProxyConfigServiceWin::OnObjectSignaled(base::win::RegKey* key) {
116   // TODO(vadimt): Remove ScopedTracker below once crbug.com/418183 is fixed.
117   tracked_objects::ScopedTracker tracking_profile(
118       FROM_HERE_WITH_EXPLICIT_FUNCTION(
119           "ProxyConfigServiceWin_OnObjectSignaled"));
120
121   // Figure out which registry key signalled this change.
122   RegKeyList::iterator it =
123       std::find(keys_to_watch_.begin(), keys_to_watch_.end(), key);
124   DCHECK(it != keys_to_watch_.end());
125
126   // Keep watching the registry key.
127   if (!key->StartWatching(base::Bind(&ProxyConfigServiceWin::OnObjectSignaled,
128                                      base::Unretained(this),
129                                      base::Unretained(key)))) {
130     delete *it;
131     keys_to_watch_.erase(it);
132   }
133
134   // Have the PollingProxyConfigService test for changes.
135   CheckForChangesNow();
136 }
137
138 // static
139 void ProxyConfigServiceWin::GetCurrentProxyConfig(ProxyConfig* config) {
140   WINHTTP_CURRENT_USER_IE_PROXY_CONFIG ie_config = {0};
141   if (!WinHttpGetIEProxyConfigForCurrentUser(&ie_config)) {
142     LOG(ERROR) << "WinHttpGetIEProxyConfigForCurrentUser failed: " <<
143         GetLastError();
144     *config = ProxyConfig::CreateDirect();
145     config->set_source(PROXY_CONFIG_SOURCE_SYSTEM_FAILED);
146     return;
147   }
148   SetFromIEConfig(config, ie_config);
149   FreeIEConfig(&ie_config);
150 }
151
152 // static
153 void ProxyConfigServiceWin::SetFromIEConfig(
154     ProxyConfig* config,
155     const WINHTTP_CURRENT_USER_IE_PROXY_CONFIG& ie_config) {
156   if (ie_config.fAutoDetect)
157     config->set_auto_detect(true);
158   if (ie_config.lpszProxy) {
159     // lpszProxy may be a single proxy, or a proxy per scheme. The format
160     // is compatible with ProxyConfig::ProxyRules's string format.
161     config->proxy_rules().ParseFromString(
162         base::UTF16ToASCII(ie_config.lpszProxy));
163   }
164   if (ie_config.lpszProxyBypass) {
165     std::string proxy_bypass = base::UTF16ToASCII(ie_config.lpszProxyBypass);
166
167     base::StringTokenizer proxy_server_bypass_list(proxy_bypass, ";, \t\n\r");
168     while (proxy_server_bypass_list.GetNext()) {
169       std::string bypass_url_domain = proxy_server_bypass_list.token();
170       config->proxy_rules().bypass_rules.AddRuleFromString(bypass_url_domain);
171     }
172   }
173   if (ie_config.lpszAutoConfigUrl)
174     config->set_pac_url(GURL(ie_config.lpszAutoConfigUrl));
175   config->set_source(PROXY_CONFIG_SOURCE_SYSTEM);
176 }
177
178 }  // namespace net