| OLD | NEW |
| 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "net/proxy/proxy_resolver_winhttp.h" | 5 #include "net/proxy/proxy_config_service_win.h" |
| 6 | 6 |
| 7 #include <windows.h> | 7 #include <windows.h> |
| 8 #include <winhttp.h> | 8 #include <winhttp.h> |
| 9 | 9 |
| 10 #include "base/histogram.h" | |
| 11 #include "base/string_tokenizer.h" | 10 #include "base/string_tokenizer.h" |
| 12 #include "net/base/net_errors.h" | 11 #include "net/base/net_errors.h" |
| 13 | 12 |
| 14 #pragma comment(lib, "winhttp.lib") | 13 #pragma comment(lib, "winhttp.lib") |
| 15 | 14 |
| 16 using base::TimeDelta; | |
| 17 using base::TimeTicks; | |
| 18 | |
| 19 namespace net { | 15 namespace net { |
| 20 | 16 |
| 21 // A small wrapper for histogramming purposes ;-) | |
| 22 static BOOL CallWinHttpGetProxyForUrl(HINTERNET session, LPCWSTR url, | |
| 23 WINHTTP_AUTOPROXY_OPTIONS* options, | |
| 24 WINHTTP_PROXY_INFO* results) { | |
| 25 TimeTicks time_start = TimeTicks::Now(); | |
| 26 BOOL rv = WinHttpGetProxyForUrl(session, url, options, results); | |
| 27 TimeDelta time_delta = TimeTicks::Now() - time_start; | |
| 28 // Record separately success and failure times since they will have very | |
| 29 // different characteristics. | |
| 30 if (rv) { | |
| 31 UMA_HISTOGRAM_LONG_TIMES(L"Net.GetProxyForUrl_OK", time_delta); | |
| 32 } else { | |
| 33 UMA_HISTOGRAM_LONG_TIMES(L"Net.GetProxyForUrl_FAIL", time_delta); | |
| 34 } | |
| 35 return rv; | |
| 36 } | |
| 37 | |
| 38 static void FreeConfig(WINHTTP_CURRENT_USER_IE_PROXY_CONFIG* config) { | 17 static void FreeConfig(WINHTTP_CURRENT_USER_IE_PROXY_CONFIG* config) { |
| 39 if (config->lpszAutoConfigUrl) | 18 if (config->lpszAutoConfigUrl) |
| 40 GlobalFree(config->lpszAutoConfigUrl); | 19 GlobalFree(config->lpszAutoConfigUrl); |
| 41 if (config->lpszProxy) | 20 if (config->lpszProxy) |
| 42 GlobalFree(config->lpszProxy); | 21 GlobalFree(config->lpszProxy); |
| 43 if (config->lpszProxyBypass) | 22 if (config->lpszProxyBypass) |
| 44 GlobalFree(config->lpszProxyBypass); | 23 GlobalFree(config->lpszProxyBypass); |
| 45 } | 24 } |
| 46 | 25 |
| 47 static void FreeInfo(WINHTTP_PROXY_INFO* info) { | 26 int ProxyConfigServiceWin::GetProxyConfig(ProxyConfig* config) { |
| 48 if (info->lpszProxy) | |
| 49 GlobalFree(info->lpszProxy); | |
| 50 if (info->lpszProxyBypass) | |
| 51 GlobalFree(info->lpszProxyBypass); | |
| 52 } | |
| 53 | |
| 54 ProxyResolverWinHttp::ProxyResolverWinHttp() | |
| 55 : session_handle_(NULL) { | |
| 56 } | |
| 57 | |
| 58 ProxyResolverWinHttp::~ProxyResolverWinHttp() { | |
| 59 CloseWinHttpSession(); | |
| 60 } | |
| 61 | |
| 62 int ProxyResolverWinHttp::GetProxyConfig(ProxyConfig* config) { | |
| 63 WINHTTP_CURRENT_USER_IE_PROXY_CONFIG ie_config = {0}; | 27 WINHTTP_CURRENT_USER_IE_PROXY_CONFIG ie_config = {0}; |
| 64 if (!WinHttpGetIEProxyConfigForCurrentUser(&ie_config)) { | 28 if (!WinHttpGetIEProxyConfigForCurrentUser(&ie_config)) { |
| 65 LOG(ERROR) << "WinHttpGetIEProxyConfigForCurrentUser failed: " << | 29 LOG(ERROR) << "WinHttpGetIEProxyConfigForCurrentUser failed: " << |
| 66 GetLastError(); | 30 GetLastError(); |
| 67 return ERR_FAILED; // TODO(darin): Bug 1189288: translate error code. | 31 return ERR_FAILED; // TODO(darin): Bug 1189288: translate error code. |
| 68 } | 32 } |
| 69 | 33 |
| 70 if (ie_config.fAutoDetect) | 34 if (ie_config.fAutoDetect) |
| 71 config->auto_detect = true; | 35 config->auto_detect = true; |
| 72 if (ie_config.lpszProxy) | 36 if (ie_config.lpszProxy) |
| (...skipping 10 matching lines...) Expand all Loading... |
| 83 config->proxy_bypass.push_back(bypass_url_domain); | 47 config->proxy_bypass.push_back(bypass_url_domain); |
| 84 } | 48 } |
| 85 } | 49 } |
| 86 if (ie_config.lpszAutoConfigUrl) | 50 if (ie_config.lpszAutoConfigUrl) |
| 87 config->pac_url = GURL(ie_config.lpszAutoConfigUrl); | 51 config->pac_url = GURL(ie_config.lpszAutoConfigUrl); |
| 88 | 52 |
| 89 FreeConfig(&ie_config); | 53 FreeConfig(&ie_config); |
| 90 return OK; | 54 return OK; |
| 91 } | 55 } |
| 92 | 56 |
| 93 int ProxyResolverWinHttp::GetProxyForURL(const GURL& query_url, | |
| 94 const GURL& pac_url, | |
| 95 ProxyInfo* results) { | |
| 96 // If we don't have a WinHTTP session, then create a new one. | |
| 97 if (!session_handle_ && !OpenWinHttpSession()) | |
| 98 return ERR_FAILED; | |
| 99 | |
| 100 // If we have been given an empty PAC url, then use auto-detection. | |
| 101 // | |
| 102 // NOTE: We just use DNS-based auto-detection here like Firefox. We do this | |
| 103 // to avoid WinHTTP's auto-detection code, which while more featureful (it | |
| 104 // supports DHCP based auto-detection) also appears to have issues. | |
| 105 // | |
| 106 WINHTTP_AUTOPROXY_OPTIONS options = {0}; | |
| 107 options.fAutoLogonIfChallenged = FALSE; | |
| 108 options.dwFlags = WINHTTP_AUTOPROXY_CONFIG_URL; | |
| 109 std::wstring pac_url_wide = ASCIIToWide(pac_url.spec()); | |
| 110 options.lpszAutoConfigUrl = | |
| 111 pac_url_wide.empty() ? L"http://wpad/wpad.dat" : pac_url_wide.c_str(); | |
| 112 | |
| 113 WINHTTP_PROXY_INFO info = {0}; | |
| 114 DCHECK(session_handle_); | |
| 115 | |
| 116 // Per http://msdn.microsoft.com/en-us/library/aa383153(VS.85).aspx, it is | |
| 117 // necessary to first try resolving with fAutoLogonIfChallenged set to false. | |
| 118 // Otherwise, we fail over to trying it with a value of true. This way we | |
| 119 // get good performance in the case where WinHTTP uses an out-of-process | |
| 120 // resolver. This is important for Vista and Win2k3. | |
| 121 BOOL ok = CallWinHttpGetProxyForUrl( | |
| 122 session_handle_, ASCIIToWide(query_url.spec()).c_str(), &options, &info); | |
| 123 if (!ok) { | |
| 124 if (ERROR_WINHTTP_LOGIN_FAILURE == GetLastError()) { | |
| 125 options.fAutoLogonIfChallenged = TRUE; | |
| 126 ok = CallWinHttpGetProxyForUrl( | |
| 127 session_handle_, ASCIIToWide(query_url.spec()).c_str(), | |
| 128 &options, &info); | |
| 129 } | |
| 130 if (!ok) { | |
| 131 DWORD error = GetLastError(); | |
| 132 LOG(ERROR) << "WinHttpGetProxyForUrl failed: " << error; | |
| 133 // If we got here because of RPC timeout during out of process PAC | |
| 134 // resolution, no further requests on this session are going to work. | |
| 135 if (ERROR_WINHTTP_TIMEOUT == error || | |
| 136 ERROR_WINHTTP_AUTO_PROXY_SERVICE_ERROR == error) { | |
| 137 CloseWinHttpSession(); | |
| 138 } | |
| 139 return ERR_FAILED; // TODO(darin): Bug 1189288: translate error code. | |
| 140 } | |
| 141 } | |
| 142 | |
| 143 int rv = OK; | |
| 144 | |
| 145 switch (info.dwAccessType) { | |
| 146 case WINHTTP_ACCESS_TYPE_NO_PROXY: | |
| 147 results->UseDirect(); | |
| 148 break; | |
| 149 case WINHTTP_ACCESS_TYPE_NAMED_PROXY: | |
| 150 results->UseNamedProxy(WideToASCII(info.lpszProxy)); | |
| 151 break; | |
| 152 default: | |
| 153 NOTREACHED(); | |
| 154 rv = ERR_FAILED; | |
| 155 } | |
| 156 | |
| 157 FreeInfo(&info); | |
| 158 return rv; | |
| 159 } | |
| 160 | |
| 161 bool ProxyResolverWinHttp::OpenWinHttpSession() { | |
| 162 DCHECK(!session_handle_); | |
| 163 session_handle_ = WinHttpOpen(NULL, | |
| 164 WINHTTP_ACCESS_TYPE_NO_PROXY, | |
| 165 WINHTTP_NO_PROXY_NAME, | |
| 166 WINHTTP_NO_PROXY_BYPASS, | |
| 167 0); | |
| 168 if (!session_handle_) | |
| 169 return false; | |
| 170 | |
| 171 // Since this session handle will never be used for WinHTTP connections, | |
| 172 // these timeouts don't really mean much individually. However, WinHTTP's | |
| 173 // out of process PAC resolution will use a combined (sum of all timeouts) | |
| 174 // value to wait for an RPC reply. | |
| 175 BOOL rv = WinHttpSetTimeouts(session_handle_, 10000, 10000, 5000, 5000); | |
| 176 DCHECK(rv); | |
| 177 | |
| 178 return true; | |
| 179 } | |
| 180 | |
| 181 void ProxyResolverWinHttp::CloseWinHttpSession() { | |
| 182 if (session_handle_) { | |
| 183 WinHttpCloseHandle(session_handle_); | |
| 184 session_handle_ = NULL; | |
| 185 } | |
| 186 } | |
| 187 | |
| 188 } // namespace net | 57 } // namespace net |
| 189 | 58 |
| OLD | NEW |