blob: 6fd057df630b9c79bfe7fa16152a11d27c674e01 [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
[email protected]835d7c82010-10-14 04:38:3810#include "base/metrics/histogram.h"
[email protected]7dc52f22009-03-02 22:37:1811#include "base/string_util.h"
[email protected]be1ce6a72010-08-03 14:35:2212#include "base/utf_string_conversions.h"
[email protected]7dc52f22009-03-02 22:37:1813#include "googleurl/src/gurl.h"
initial.commit586acc5fe2008-07-26 22:42:5214#include "net/base/net_errors.h"
[email protected]7dc52f22009-03-02 22:37:1815#include "net/proxy/proxy_info.h"
initial.commit586acc5fe2008-07-26 22:42:5216
17#pragma comment(lib, "winhttp.lib")
18
[email protected]e1acf6f2008-10-27 20:43:3319using base::TimeDelta;
20using base::TimeTicks;
21
initial.commit586acc5fe2008-07-26 22:42:5222namespace net {
23
initial.commit586acc5fe2008-07-26 22:42:5224static void FreeInfo(WINHTTP_PROXY_INFO* info) {
25 if (info->lpszProxy)
26 GlobalFree(info->lpszProxy);
27 if (info->lpszProxyBypass)
28 GlobalFree(info->lpszProxyBypass);
29}
30
[email protected]928fb582008-08-11 15:40:2331ProxyResolverWinHttp::ProxyResolverWinHttp()
[email protected]775fd9e2009-07-26 21:12:2032 : ProxyResolver(false /*expects_pac_bytes*/), session_handle_(NULL) {
initial.commit586acc5fe2008-07-26 22:42:5233}
34
[email protected]928fb582008-08-11 15:40:2335ProxyResolverWinHttp::~ProxyResolverWinHttp() {
initial.commit586acc5fe2008-07-26 22:42:5236 CloseWinHttpSession();
37}
38
[email protected]96fbab42008-12-02 06:57:4439int ProxyResolverWinHttp::GetProxyForURL(const GURL& query_url,
[email protected]775fd9e2009-07-26 21:12:2040 ProxyInfo* results,
41 CompletionCallback* /*callback*/,
[email protected]52ae80c2009-09-10 21:27:0042 RequestHandle* /*request*/,
[email protected]9e743cd2010-03-16 07:03:5343 const BoundNetLog& /*net_log*/) {
initial.commit586acc5fe2008-07-26 22:42:5244 // 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};
[email protected]f9ad22f2008-09-09 20:35:4055 options.fAutoLogonIfChallenged = FALSE;
initial.commit586acc5fe2008-07-26 22:42:5256 options.dwFlags = WINHTTP_AUTOPROXY_CONFIG_URL;
[email protected]775fd9e2009-07-26 21:12:2057 std::wstring pac_url_wide = ASCIIToWide(pac_url_.spec());
[email protected]620f5712009-08-04 22:43:1258 options.lpszAutoConfigUrl = pac_url_wide.c_str();
initial.commit586acc5fe2008-07-26 22:42:5259
60 WINHTTP_PROXY_INFO info = {0};
61 DCHECK(session_handle_);
initial.commit586acc5fe2008-07-26 22:42:5262
[email protected]f9ad22f2008-09-09 20:35:4063 // 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.
[email protected]95c971992010-12-03 22:02:4268 BOOL ok = WinHttpGetProxyForUrl(
[email protected]96fbab42008-12-02 06:57:4469 session_handle_, ASCIIToWide(query_url.spec()).c_str(), &options, &info);
[email protected]f9ad22f2008-09-09 20:35:4070 if (!ok) {
71 if (ERROR_WINHTTP_LOGIN_FAILURE == GetLastError()) {
72 options.fAutoLogonIfChallenged = TRUE;
[email protected]95c971992010-12-03 22:02:4273 ok = WinHttpGetProxyForUrl(
[email protected]96fbab42008-12-02 06:57:4474 session_handle_, ASCIIToWide(query_url.spec()).c_str(),
75 &options, &info);
initial.commit586acc5fe2008-07-26 22:42:5276 }
[email protected]f9ad22f2008-09-09 20:35:4077 if (!ok) {
78 DWORD error = GetLastError();
79 LOG(ERROR) << "WinHttpGetProxyForUrl failed: " << error;
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 }
initial.commit586acc5fe2008-07-26 22:42:5288 }
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:
[email protected]f6fb2de2009-02-19 08:11:4297 // 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.
[email protected]82f954e2008-08-12 05:11:38111 results->UseNamedProxy(WideToASCII(info.lpszProxy));
initial.commit586acc5fe2008-07-26 22:42:52112 break;
113 default:
114 NOTREACHED();
115 rv = ERR_FAILED;
116 }
117
118 FreeInfo(&info);
119 return rv;
120}
121
[email protected]775fd9e2009-07-26 21:12:20122void ProxyResolverWinHttp::CancelRequest(RequestHandle request) {
123 // This is a synchronous ProxyResolver; no possibility for async requests.
124 NOTREACHED();
125}
126
[email protected]24476402010-07-20 20:55:17127int ProxyResolverWinHttp::SetPacScript(
128 const scoped_refptr<ProxyResolverScriptData>& script_data,
129 CompletionCallback* /*callback*/) {
130 if (script_data->type() == ProxyResolverScriptData::TYPE_AUTO_DETECT) {
131 pac_url_ = GURL("http://wpad/wpad.dat");
132 } else {
133 pac_url_ = script_data->url();
134 }
[email protected]620f5712009-08-04 22:43:12135 return OK;
[email protected]775fd9e2009-07-26 21:12:20136}
137
[email protected]928fb582008-08-11 15:40:23138bool ProxyResolverWinHttp::OpenWinHttpSession() {
initial.commit586acc5fe2008-07-26 22:42:52139 DCHECK(!session_handle_);
140 session_handle_ = WinHttpOpen(NULL,
141 WINHTTP_ACCESS_TYPE_NO_PROXY,
142 WINHTTP_NO_PROXY_NAME,
143 WINHTTP_NO_PROXY_BYPASS,
144 0);
145 if (!session_handle_)
146 return false;
147
[email protected]928fb582008-08-11 15:40:23148 // Since this session handle will never be used for WinHTTP connections,
initial.commit586acc5fe2008-07-26 22:42:52149 // these timeouts don't really mean much individually. However, WinHTTP's
150 // out of process PAC resolution will use a combined (sum of all timeouts)
151 // value to wait for an RPC reply.
152 BOOL rv = WinHttpSetTimeouts(session_handle_, 10000, 10000, 5000, 5000);
153 DCHECK(rv);
154
155 return true;
156}
157
[email protected]928fb582008-08-11 15:40:23158void ProxyResolverWinHttp::CloseWinHttpSession() {
initial.commit586acc5fe2008-07-26 22:42:52159 if (session_handle_) {
160 WinHttpCloseHandle(session_handle_);
161 session_handle_ = NULL;
162 }
163}
164
165} // namespace net