blob: 61a1d2f20f9ea005fba761d43cb4f96d29a56117 [file] [log] [blame]
license.botbf09a502008-08-24 00:55:551// 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
3// found in the LICENSE file.
initial.commit586acc5fe2008-07-26 22:42:524
[email protected]928fb582008-08-11 15:40:235#include "net/proxy/proxy_resolver_winhttp.h"
initial.commit586acc5fe2008-07-26 22:42:526
7#include <windows.h>
8#include <winhttp.h>
9
10#include "base/histogram.h"
11#include "net/base/net_errors.h"
12
13#pragma comment(lib, "winhttp.lib")
14
[email protected]e1acf6f2008-10-27 20:43:3315using base::TimeDelta;
16using base::TimeTicks;
17
initial.commit586acc5fe2008-07-26 22:42:5218namespace net {
19
20// A small wrapper for histogramming purposes ;-)
21static BOOL CallWinHttpGetProxyForUrl(HINTERNET session, LPCWSTR url,
22 WINHTTP_AUTOPROXY_OPTIONS* options,
23 WINHTTP_PROXY_INFO* results) {
24 TimeTicks time_start = TimeTicks::Now();
25 BOOL rv = WinHttpGetProxyForUrl(session, url, options, results);
26 TimeDelta time_delta = TimeTicks::Now() - time_start;
27 // Record separately success and failure times since they will have very
28 // different characteristics.
29 if (rv) {
30 UMA_HISTOGRAM_LONG_TIMES(L"Net.GetProxyForUrl_OK", time_delta);
31 } else {
32 UMA_HISTOGRAM_LONG_TIMES(L"Net.GetProxyForUrl_FAIL", time_delta);
33 }
34 return rv;
35}
36
initial.commit586acc5fe2008-07-26 22:42:5237static void FreeInfo(WINHTTP_PROXY_INFO* info) {
38 if (info->lpszProxy)
39 GlobalFree(info->lpszProxy);
40 if (info->lpszProxyBypass)
41 GlobalFree(info->lpszProxyBypass);
42}
43
[email protected]928fb582008-08-11 15:40:2344ProxyResolverWinHttp::ProxyResolverWinHttp()
initial.commit586acc5fe2008-07-26 22:42:5245 : session_handle_(NULL) {
46}
47
[email protected]928fb582008-08-11 15:40:2348ProxyResolverWinHttp::~ProxyResolverWinHttp() {
initial.commit586acc5fe2008-07-26 22:42:5249 CloseWinHttpSession();
50}
51
[email protected]96fbab42008-12-02 06:57:4452int ProxyResolverWinHttp::GetProxyForURL(const GURL& query_url,
53 const GURL& pac_url,
[email protected]928fb582008-08-11 15:40:2354 ProxyInfo* results) {
initial.commit586acc5fe2008-07-26 22:42:5255 // If we don't have a WinHTTP session, then create a new one.
56 if (!session_handle_ && !OpenWinHttpSession())
57 return ERR_FAILED;
58
59 // If we have been given an empty PAC url, then use auto-detection.
60 //
61 // NOTE: We just use DNS-based auto-detection here like Firefox. We do this
62 // to avoid WinHTTP's auto-detection code, which while more featureful (it
63 // supports DHCP based auto-detection) also appears to have issues.
64 //
65 WINHTTP_AUTOPROXY_OPTIONS options = {0};
[email protected]f9ad22f2008-09-09 20:35:4066 options.fAutoLogonIfChallenged = FALSE;
initial.commit586acc5fe2008-07-26 22:42:5267 options.dwFlags = WINHTTP_AUTOPROXY_CONFIG_URL;
[email protected]96fbab42008-12-02 06:57:4468 std::wstring pac_url_wide = ASCIIToWide(pac_url.spec());
initial.commit586acc5fe2008-07-26 22:42:5269 options.lpszAutoConfigUrl =
[email protected]61198eeb2008-09-09 04:43:0070 pac_url_wide.empty() ? L"http://wpad/wpad.dat" : pac_url_wide.c_str();
initial.commit586acc5fe2008-07-26 22:42:5271
72 WINHTTP_PROXY_INFO info = {0};
73 DCHECK(session_handle_);
initial.commit586acc5fe2008-07-26 22:42:5274
[email protected]f9ad22f2008-09-09 20:35:4075 // Per http://msdn.microsoft.com/en-us/library/aa383153(VS.85).aspx, it is
76 // necessary to first try resolving with fAutoLogonIfChallenged set to false.
77 // Otherwise, we fail over to trying it with a value of true. This way we
78 // get good performance in the case where WinHTTP uses an out-of-process
79 // resolver. This is important for Vista and Win2k3.
80 BOOL ok = CallWinHttpGetProxyForUrl(
[email protected]96fbab42008-12-02 06:57:4481 session_handle_, ASCIIToWide(query_url.spec()).c_str(), &options, &info);
[email protected]f9ad22f2008-09-09 20:35:4082 if (!ok) {
83 if (ERROR_WINHTTP_LOGIN_FAILURE == GetLastError()) {
84 options.fAutoLogonIfChallenged = TRUE;
85 ok = CallWinHttpGetProxyForUrl(
[email protected]96fbab42008-12-02 06:57:4486 session_handle_, ASCIIToWide(query_url.spec()).c_str(),
87 &options, &info);
initial.commit586acc5fe2008-07-26 22:42:5288 }
[email protected]f9ad22f2008-09-09 20:35:4089 if (!ok) {
90 DWORD error = GetLastError();
91 LOG(ERROR) << "WinHttpGetProxyForUrl failed: " << error;
92 // If we got here because of RPC timeout during out of process PAC
93 // resolution, no further requests on this session are going to work.
94 if (ERROR_WINHTTP_TIMEOUT == error ||
95 ERROR_WINHTTP_AUTO_PROXY_SERVICE_ERROR == error) {
96 CloseWinHttpSession();
97 }
98 return ERR_FAILED; // TODO(darin): Bug 1189288: translate error code.
99 }
initial.commit586acc5fe2008-07-26 22:42:52100 }
101
102 int rv = OK;
103
104 switch (info.dwAccessType) {
105 case WINHTTP_ACCESS_TYPE_NO_PROXY:
106 results->UseDirect();
107 break;
108 case WINHTTP_ACCESS_TYPE_NAMED_PROXY:
[email protected]f6fb2de2009-02-19 08:11:42109 // According to MSDN:
110 //
111 // The proxy server list contains one or more of the following strings
112 // separated by semicolons or whitespace.
113 //
114 // ([<scheme>=][<scheme>"://"]<server>[":"<port>])
115 //
116 // Based on this description, ProxyInfo::UseNamedProxy() isn't
117 // going to handle all the variations (in particular <scheme>=).
118 //
119 // However in practice, it seems that WinHTTP is simply returning
120 // things like "foopy1:80;foopy2:80". It strips out the non-HTTP
121 // proxy types, and stops the list when PAC encounters a "DIRECT".
122 // So UseNamedProxy() should work OK.
[email protected]82f954e2008-08-12 05:11:38123 results->UseNamedProxy(WideToASCII(info.lpszProxy));
initial.commit586acc5fe2008-07-26 22:42:52124 break;
125 default:
126 NOTREACHED();
127 rv = ERR_FAILED;
128 }
129
130 FreeInfo(&info);
131 return rv;
132}
133
[email protected]928fb582008-08-11 15:40:23134bool ProxyResolverWinHttp::OpenWinHttpSession() {
initial.commit586acc5fe2008-07-26 22:42:52135 DCHECK(!session_handle_);
136 session_handle_ = WinHttpOpen(NULL,
137 WINHTTP_ACCESS_TYPE_NO_PROXY,
138 WINHTTP_NO_PROXY_NAME,
139 WINHTTP_NO_PROXY_BYPASS,
140 0);
141 if (!session_handle_)
142 return false;
143
[email protected]928fb582008-08-11 15:40:23144 // Since this session handle will never be used for WinHTTP connections,
initial.commit586acc5fe2008-07-26 22:42:52145 // these timeouts don't really mean much individually. However, WinHTTP's
146 // out of process PAC resolution will use a combined (sum of all timeouts)
147 // value to wait for an RPC reply.
148 BOOL rv = WinHttpSetTimeouts(session_handle_, 10000, 10000, 5000, 5000);
149 DCHECK(rv);
150
151 return true;
152}
153
[email protected]928fb582008-08-11 15:40:23154void ProxyResolverWinHttp::CloseWinHttpSession() {
initial.commit586acc5fe2008-07-26 22:42:52155 if (session_handle_) {
156 WinHttpCloseHandle(session_handle_);
157 session_handle_ = NULL;
158 }
159}
160
161} // namespace net
license.botbf09a502008-08-24 00:55:55162