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 |