1ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved. 2c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Use of this source code is governed by a BSD-style license that can be 3c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// found in the LICENSE file. 4c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 5c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/proxy/proxy_config_service_win.h" 6c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 7c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include <windows.h> 8c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include <winhttp.h> 9c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 10c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/logging.h" 11ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/memory/scoped_ptr.h" 12c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/string_tokenizer.h" 13c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/string_util.h" 143345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/stl_util-inl.h" 153f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#include "base/threading/thread_restrictions.h" 16731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include "base/win/registry.h" 17c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/base/net_errors.h" 18c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/proxy/proxy_config.h" 19c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 20c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#pragma comment(lib, "winhttp.lib") 21c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 22c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottnamespace net { 23c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 243345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merricknamespace { 253345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 263345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickconst int kPollIntervalSec = 10; 273345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 283345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid FreeIEConfig(WINHTTP_CURRENT_USER_IE_PROXY_CONFIG* ie_config) { 29c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (ie_config->lpszAutoConfigUrl) 30c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott GlobalFree(ie_config->lpszAutoConfigUrl); 31c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (ie_config->lpszProxy) 32c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott GlobalFree(ie_config->lpszProxy); 33c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (ie_config->lpszProxyBypass) 34c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott GlobalFree(ie_config->lpszProxyBypass); 35c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 36c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 373345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick} // namespace 383345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 393345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// RegKey and ObjectWatcher pair. 403345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickclass ProxyConfigServiceWin::KeyEntry { 413345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick public: 423f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen bool StartWatching(base::win::ObjectWatcher::Delegate* delegate) { 433345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Try to create a watch event for the registry key (which watches the 443345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // sibling tree as well). 4572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (key_.StartWatching() != ERROR_SUCCESS) 463345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return false; 473345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 483345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Now setup an ObjectWatcher for this event, so we get OnObjectSignaled() 493345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // invoked on this message loop once it is signalled. 503345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (!watcher_.StartWatching(key_.watch_event(), delegate)) 513345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return false; 523345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 533345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return true; 543345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick } 553345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 563345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick bool CreateRegKey(HKEY rootkey, const wchar_t* subkey) { 5772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return key_.Create(rootkey, subkey, KEY_NOTIFY) == ERROR_SUCCESS; 583345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick } 593345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 603345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick HANDLE watch_event() const { 613345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return key_.watch_event(); 623345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick } 633345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 643345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick private: 65731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick base::win::RegKey key_; 663f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen base::win::ObjectWatcher watcher_; 673345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}; 683345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 693345a6884c488ff3a535c2c9acdd33d74b37e311Iain MerrickProxyConfigServiceWin::ProxyConfigServiceWin() 703345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick : PollingProxyConfigService( 713345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick base::TimeDelta::FromSeconds(kPollIntervalSec), 723345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick &ProxyConfigServiceWin::GetCurrentProxyConfig) { 733345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick} 743345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 753345a6884c488ff3a535c2c9acdd33d74b37e311Iain MerrickProxyConfigServiceWin::~ProxyConfigServiceWin() { 76513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch // The registry functions below will end up going to disk. Do this on another 77513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch // thread to avoid slowing the IO thread. http://crbug.com/61453 78513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch base::ThreadRestrictions::ScopedAllowIO allow_io; 793345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick STLDeleteElements(&keys_to_watch_); 803345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick} 813345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 823345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid ProxyConfigServiceWin::AddObserver(Observer* observer) { 833345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Lazily-initialize our registry watcher. 843345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick StartWatchingRegistryForChanges(); 853345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 863345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Let the super-class do its work now. 873345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick PollingProxyConfigService::AddObserver(observer); 883345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick} 893345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 903345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid ProxyConfigServiceWin::StartWatchingRegistryForChanges() { 913345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (!keys_to_watch_.empty()) 923345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return; // Already initialized. 933345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 94513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch // The registry functions below will end up going to disk. Do this on another 95513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch // thread to avoid slowing the IO thread. http://crbug.com/61453 96513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch base::ThreadRestrictions::ScopedAllowIO allow_io; 97513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch 983345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // There are a number of different places where proxy settings can live 993345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // in the registry. In some cases it appears in a binary value, in other 1003345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // cases string values. Furthermore winhttp and wininet appear to have 1013345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // separate stores, and proxy settings can be configured per-machine 1023345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // or per-user. 1033345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // 1043345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // This function is probably not exhaustive in the registry locations it 1053345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // watches for changes, however it should catch the majority of the 1063345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // cases. In case we have missed some less common triggers (likely), we 1073345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // will catch them during the periodic (10 second) polling, so things 1083345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // will recover. 1093345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 1103345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick AddKeyToWatchList( 1113345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick HKEY_CURRENT_USER, 1123345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick L"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings"); 1133345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 1143345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick AddKeyToWatchList( 1153345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick HKEY_LOCAL_MACHINE, 1163345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick L"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings"); 1173345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 1183345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick AddKeyToWatchList( 1193345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick HKEY_LOCAL_MACHINE, 1203345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick L"SOFTWARE\\Policies\\Microsoft\\Windows\\CurrentVersion\\" 1213345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick L"Internet Settings"); 1223345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick} 1233345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 1243345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickbool ProxyConfigServiceWin::AddKeyToWatchList(HKEY rootkey, 1253345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick const wchar_t* subkey) { 1263345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick scoped_ptr<KeyEntry> entry(new KeyEntry); 1273345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (!entry->CreateRegKey(rootkey, subkey)) 1283345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return false; 1293345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 1303345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (!entry->StartWatching(this)) 1313345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return false; 1323345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 1333345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick keys_to_watch_.push_back(entry.release()); 1343345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return true; 1353345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick} 1363345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 1373345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid ProxyConfigServiceWin::OnObjectSignaled(HANDLE object) { 1383345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Figure out which registry key signalled this change. 1393345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick KeyEntryList::iterator it; 1403345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick for (it = keys_to_watch_.begin(); it != keys_to_watch_.end(); ++it) { 1413345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if ((*it)->watch_event() == object) 1423345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick break; 1433345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick } 1443345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 1453345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick DCHECK(it != keys_to_watch_.end()); 1463345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 1473345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Keep watching the registry key. 1483345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (!(*it)->StartWatching(this)) 1493345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick keys_to_watch_.erase(it); 1503345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 1513345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Have the PollingProxyConfigService test for changes. 1523345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick CheckForChangesNow(); 1533345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick} 1543345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 1553345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// static 1563345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid ProxyConfigServiceWin::GetCurrentProxyConfig(ProxyConfig* config) { 157c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott WINHTTP_CURRENT_USER_IE_PROXY_CONFIG ie_config = {0}; 158c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (!WinHttpGetIEProxyConfigForCurrentUser(&ie_config)) { 159c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott LOG(ERROR) << "WinHttpGetIEProxyConfigForCurrentUser failed: " << 160c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott GetLastError(); 1613345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick *config = ProxyConfig::CreateDirect(); 1623345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return; 163c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 164c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott SetFromIEConfig(config, ie_config); 165c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott FreeIEConfig(&ie_config); 166c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 167c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 168c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// static 169c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid ProxyConfigServiceWin::SetFromIEConfig( 170c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott ProxyConfig* config, 171c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott const WINHTTP_CURRENT_USER_IE_PROXY_CONFIG& ie_config) { 172c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (ie_config.fAutoDetect) 173c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch config->set_auto_detect(true); 174c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (ie_config.lpszProxy) { 175c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // lpszProxy may be a single proxy, or a proxy per scheme. The format 176c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // is compatible with ProxyConfig::ProxyRules's string format. 177c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch config->proxy_rules().ParseFromString(WideToASCII(ie_config.lpszProxy)); 178c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 179c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (ie_config.lpszProxyBypass) { 180c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott std::string proxy_bypass = WideToASCII(ie_config.lpszProxyBypass); 181c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 182ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen StringTokenizer proxy_server_bypass_list(proxy_bypass, ";, \t\n\r"); 183c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott while (proxy_server_bypass_list.GetNext()) { 184c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott std::string bypass_url_domain = proxy_server_bypass_list.token(); 185c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch config->proxy_rules().bypass_rules.AddRuleFromString(bypass_url_domain); 186c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 187c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 188c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (ie_config.lpszAutoConfigUrl) 189c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch config->set_pac_url(GURL(ie_config.lpszAutoConfigUrl)); 190c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 191c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 192c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} // namespace net 193