OLD | NEW |
| (Empty) |
1 // Copyright (c) 2011 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_resolver_winhttp.h" | |
6 | |
7 #include <windows.h> | |
8 #include <winhttp.h> | |
9 | |
10 #include "base/metrics/histogram.h" | |
11 #include "base/strings/string_util.h" | |
12 #include "base/strings/utf_string_conversions.h" | |
13 #include "net/base/net_errors.h" | |
14 #include "net/proxy/proxy_info.h" | |
15 #include "url/gurl.h" | |
16 | |
17 #pragma comment(lib, "winhttp.lib") | |
18 | |
19 using base::TimeDelta; | |
20 using base::TimeTicks; | |
21 | |
22 namespace net { | |
23 | |
24 static void FreeInfo(WINHTTP_PROXY_INFO* info) { | |
25 if (info->lpszProxy) | |
26 GlobalFree(info->lpszProxy); | |
27 if (info->lpszProxyBypass) | |
28 GlobalFree(info->lpszProxyBypass); | |
29 } | |
30 | |
31 ProxyResolverWinHttp::ProxyResolverWinHttp() | |
32 : ProxyResolver(false /*expects_pac_bytes*/), session_handle_(NULL) { | |
33 } | |
34 | |
35 ProxyResolverWinHttp::~ProxyResolverWinHttp() { | |
36 CloseWinHttpSession(); | |
37 } | |
38 | |
39 int ProxyResolverWinHttp::GetProxyForURL(const GURL& query_url, | |
40 ProxyInfo* results, | |
41 const CompletionCallback& /*callback*/, | |
42 RequestHandle* /*request*/, | |
43 const BoundNetLog& /*net_log*/) { | |
44 // If we don't have a WinHTTP session, then create a new one. | |
45 if (!session_handle_ && !OpenWinHttpSession()) | |
46 return ERR_FAILED; | |
47 | |
48 // If we have been given an empty PAC url, then use auto-detection. | |
49 // | |
50 // NOTE: We just use DNS-based auto-detection here like Firefox. We do this | |
51 // to avoid WinHTTP's auto-detection code, which while more featureful (it | |
52 // supports DHCP based auto-detection) also appears to have issues. | |
53 // | |
54 WINHTTP_AUTOPROXY_OPTIONS options = {0}; | |
55 options.fAutoLogonIfChallenged = FALSE; | |
56 options.dwFlags = WINHTTP_AUTOPROXY_CONFIG_URL; | |
57 base::string16 pac_url16 = base::ASCIIToUTF16(pac_url_.spec()); | |
58 options.lpszAutoConfigUrl = pac_url16.c_str(); | |
59 | |
60 WINHTTP_PROXY_INFO info = {0}; | |
61 DCHECK(session_handle_); | |
62 | |
63 // Per http://msdn.microsoft.com/en-us/library/aa383153(VS.85).aspx, it is | |
64 // necessary to first try resolving with fAutoLogonIfChallenged set to false. | |
65 // Otherwise, we fail over to trying it with a value of true. This way we | |
66 // get good performance in the case where WinHTTP uses an out-of-process | |
67 // resolver. This is important for Vista and Win2k3. | |
68 BOOL ok = WinHttpGetProxyForUrl(session_handle_, | |
69 base::ASCIIToUTF16(query_url.spec()).c_str(), | |
70 &options, &info); | |
71 if (!ok) { | |
72 if (ERROR_WINHTTP_LOGIN_FAILURE == GetLastError()) { | |
73 options.fAutoLogonIfChallenged = TRUE; | |
74 ok = WinHttpGetProxyForUrl( | |
75 session_handle_, base::ASCIIToUTF16(query_url.spec()).c_str(), | |
76 &options, &info); | |
77 } | |
78 if (!ok) { | |
79 DWORD error = GetLastError(); | |
80 // If we got here because of RPC timeout during out of process PAC | |
81 // resolution, no further requests on this session are going to work. | |
82 if (ERROR_WINHTTP_TIMEOUT == error || | |
83 ERROR_WINHTTP_AUTO_PROXY_SERVICE_ERROR == error) { | |
84 CloseWinHttpSession(); | |
85 } | |
86 return ERR_FAILED; // TODO(darin): Bug 1189288: translate error code. | |
87 } | |
88 } | |
89 | |
90 int rv = OK; | |
91 | |
92 switch (info.dwAccessType) { | |
93 case WINHTTP_ACCESS_TYPE_NO_PROXY: | |
94 results->UseDirect(); | |
95 break; | |
96 case WINHTTP_ACCESS_TYPE_NAMED_PROXY: | |
97 // According to MSDN: | |
98 // | |
99 // The proxy server list contains one or more of the following strings | |
100 // separated by semicolons or whitespace. | |
101 // | |
102 // ([<scheme>=][<scheme>"://"]<server>[":"<port>]) | |
103 // | |
104 // Based on this description, ProxyInfo::UseNamedProxy() isn't | |
105 // going to handle all the variations (in particular <scheme>=). | |
106 // | |
107 // However in practice, it seems that WinHTTP is simply returning | |
108 // things like "foopy1:80;foopy2:80". It strips out the non-HTTP | |
109 // proxy types, and stops the list when PAC encounters a "DIRECT". | |
110 // So UseNamedProxy() should work OK. | |
111 results->UseNamedProxy(base::UTF16ToASCII(info.lpszProxy)); | |
112 break; | |
113 default: | |
114 NOTREACHED(); | |
115 rv = ERR_FAILED; | |
116 } | |
117 | |
118 FreeInfo(&info); | |
119 return rv; | |
120 } | |
121 | |
122 void ProxyResolverWinHttp::CancelRequest(RequestHandle request) { | |
123 // This is a synchronous ProxyResolver; no possibility for async requests. | |
124 NOTREACHED(); | |
125 } | |
126 | |
127 LoadState ProxyResolverWinHttp::GetLoadState(RequestHandle request) const { | |
128 NOTREACHED(); | |
129 return LOAD_STATE_IDLE; | |
130 } | |
131 | |
132 void ProxyResolverWinHttp::CancelSetPacScript() { | |
133 NOTREACHED(); | |
134 } | |
135 | |
136 int ProxyResolverWinHttp::SetPacScript( | |
137 const scoped_refptr<ProxyResolverScriptData>& script_data, | |
138 const CompletionCallback& /*callback*/) { | |
139 if (script_data->type() == ProxyResolverScriptData::TYPE_AUTO_DETECT) { | |
140 pac_url_ = GURL("http://wpad/wpad.dat"); | |
141 } else { | |
142 pac_url_ = script_data->url(); | |
143 } | |
144 return OK; | |
145 } | |
146 | |
147 bool ProxyResolverWinHttp::OpenWinHttpSession() { | |
148 DCHECK(!session_handle_); | |
149 session_handle_ = WinHttpOpen(NULL, | |
150 WINHTTP_ACCESS_TYPE_NO_PROXY, | |
151 WINHTTP_NO_PROXY_NAME, | |
152 WINHTTP_NO_PROXY_BYPASS, | |
153 0); | |
154 if (!session_handle_) | |
155 return false; | |
156 | |
157 // Since this session handle will never be used for WinHTTP connections, | |
158 // these timeouts don't really mean much individually. However, WinHTTP's | |
159 // out of process PAC resolution will use a combined (sum of all timeouts) | |
160 // value to wait for an RPC reply. | |
161 BOOL rv = WinHttpSetTimeouts(session_handle_, 10000, 10000, 5000, 5000); | |
162 DCHECK(rv); | |
163 | |
164 return true; | |
165 } | |
166 | |
167 void ProxyResolverWinHttp::CloseWinHttpSession() { | |
168 if (session_handle_) { | |
169 WinHttpCloseHandle(session_handle_); | |
170 session_handle_ = NULL; | |
171 } | |
172 } | |
173 | |
174 } // namespace net | |
OLD | NEW |