OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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/dhcp_proxy_script_adapter_fetcher_win.h" | 5 #include "net/proxy/dhcp_proxy_script_adapter_fetcher_win.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/bind_helpers.h" | 8 #include "base/bind_helpers.h" |
9 #include "base/logging.h" | 9 #include "base/logging.h" |
10 #include "base/message_loop/message_loop_proxy.h" | 10 #include "base/message_loop/message_loop_proxy.h" |
(...skipping 28 matching lines...) Expand all Loading... |
39 state_(STATE_START), | 39 state_(STATE_START), |
40 result_(ERR_IO_PENDING), | 40 result_(ERR_IO_PENDING), |
41 url_request_context_(url_request_context) { | 41 url_request_context_(url_request_context) { |
42 DCHECK(url_request_context_); | 42 DCHECK(url_request_context_); |
43 } | 43 } |
44 | 44 |
45 DhcpProxyScriptAdapterFetcher::~DhcpProxyScriptAdapterFetcher() { | 45 DhcpProxyScriptAdapterFetcher::~DhcpProxyScriptAdapterFetcher() { |
46 Cancel(); | 46 Cancel(); |
47 } | 47 } |
48 | 48 |
49 void DhcpProxyScriptAdapterFetcher::Fetch( | 49 void DhcpProxyScriptAdapterFetcher::Fetch(const std::string& adapter_name, |
50 const std::string& adapter_name, const CompletionCallback& callback) { | 50 const CompletionCallback& callback) { |
51 DCHECK(CalledOnValidThread()); | 51 DCHECK(CalledOnValidThread()); |
52 DCHECK_EQ(state_, STATE_START); | 52 DCHECK_EQ(state_, STATE_START); |
53 result_ = ERR_IO_PENDING; | 53 result_ = ERR_IO_PENDING; |
54 pac_script_ = base::string16(); | 54 pac_script_ = base::string16(); |
55 state_ = STATE_WAIT_DHCP; | 55 state_ = STATE_WAIT_DHCP; |
56 callback_ = callback; | 56 callback_ = callback; |
57 | 57 |
58 wait_timer_.Start(FROM_HERE, ImplGetTimeout(), | 58 wait_timer_.Start(FROM_HERE, |
59 this, &DhcpProxyScriptAdapterFetcher::OnTimeout); | 59 ImplGetTimeout(), |
| 60 this, |
| 61 &DhcpProxyScriptAdapterFetcher::OnTimeout); |
60 scoped_refptr<DhcpQuery> dhcp_query(ImplCreateDhcpQuery()); | 62 scoped_refptr<DhcpQuery> dhcp_query(ImplCreateDhcpQuery()); |
61 task_runner_->PostTaskAndReply( | 63 task_runner_->PostTaskAndReply( |
62 FROM_HERE, | 64 FROM_HERE, |
63 base::Bind( | 65 base::Bind(&DhcpProxyScriptAdapterFetcher::DhcpQuery::GetPacURLForAdapter, |
64 &DhcpProxyScriptAdapterFetcher::DhcpQuery::GetPacURLForAdapter, | 66 dhcp_query.get(), |
65 dhcp_query.get(), | 67 adapter_name), |
66 adapter_name), | 68 base::Bind(&DhcpProxyScriptAdapterFetcher::OnDhcpQueryDone, |
67 base::Bind( | 69 AsWeakPtr(), |
68 &DhcpProxyScriptAdapterFetcher::OnDhcpQueryDone, | 70 dhcp_query)); |
69 AsWeakPtr(), | |
70 dhcp_query)); | |
71 } | 71 } |
72 | 72 |
73 void DhcpProxyScriptAdapterFetcher::Cancel() { | 73 void DhcpProxyScriptAdapterFetcher::Cancel() { |
74 DCHECK(CalledOnValidThread()); | 74 DCHECK(CalledOnValidThread()); |
75 callback_.Reset(); | 75 callback_.Reset(); |
76 wait_timer_.Stop(); | 76 wait_timer_.Stop(); |
77 script_fetcher_.reset(); | 77 script_fetcher_.reset(); |
78 | 78 |
79 switch (state_) { | 79 switch (state_) { |
80 case STATE_WAIT_DHCP: | 80 case STATE_WAIT_DHCP: |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
123 | 123 |
124 void DhcpProxyScriptAdapterFetcher::DhcpQuery::GetPacURLForAdapter( | 124 void DhcpProxyScriptAdapterFetcher::DhcpQuery::GetPacURLForAdapter( |
125 const std::string& adapter_name) { | 125 const std::string& adapter_name) { |
126 url_ = ImplGetPacURLFromDhcp(adapter_name); | 126 url_ = ImplGetPacURLFromDhcp(adapter_name); |
127 } | 127 } |
128 | 128 |
129 const std::string& DhcpProxyScriptAdapterFetcher::DhcpQuery::url() const { | 129 const std::string& DhcpProxyScriptAdapterFetcher::DhcpQuery::url() const { |
130 return url_; | 130 return url_; |
131 } | 131 } |
132 | 132 |
133 std::string | 133 std::string DhcpProxyScriptAdapterFetcher::DhcpQuery::ImplGetPacURLFromDhcp( |
134 DhcpProxyScriptAdapterFetcher::DhcpQuery::ImplGetPacURLFromDhcp( | 134 const std::string& adapter_name) { |
135 const std::string& adapter_name) { | |
136 return DhcpProxyScriptAdapterFetcher::GetPacURLFromDhcp(adapter_name); | 135 return DhcpProxyScriptAdapterFetcher::GetPacURLFromDhcp(adapter_name); |
137 } | 136 } |
138 | 137 |
139 void DhcpProxyScriptAdapterFetcher::OnDhcpQueryDone( | 138 void DhcpProxyScriptAdapterFetcher::OnDhcpQueryDone( |
140 scoped_refptr<DhcpQuery> dhcp_query) { | 139 scoped_refptr<DhcpQuery> dhcp_query) { |
141 DCHECK(CalledOnValidThread()); | 140 DCHECK(CalledOnValidThread()); |
142 // Because we can't cancel the call to the Win32 API, we can expect | 141 // Because we can't cancel the call to the Win32 API, we can expect |
143 // it to finish while we are in a few different states. The expected | 142 // it to finish while we are in a few different states. The expected |
144 // one is WAIT_DHCP, but it could be in CANCEL if Cancel() was called, | 143 // one is WAIT_DHCP, but it could be in CANCEL if Cancel() was called, |
145 // or FINISH if timeout occurred. | 144 // or FINISH if timeout occurred. |
146 DCHECK(state_ == STATE_WAIT_DHCP || state_ == STATE_CANCEL || | 145 DCHECK(state_ == STATE_WAIT_DHCP || state_ == STATE_CANCEL || |
147 state_ == STATE_FINISH); | 146 state_ == STATE_FINISH); |
148 if (state_ != STATE_WAIT_DHCP) | 147 if (state_ != STATE_WAIT_DHCP) |
149 return; | 148 return; |
150 | 149 |
151 wait_timer_.Stop(); | 150 wait_timer_.Stop(); |
152 | 151 |
153 pac_url_ = GURL(dhcp_query->url()); | 152 pac_url_ = GURL(dhcp_query->url()); |
154 if (pac_url_.is_empty() || !pac_url_.is_valid()) { | 153 if (pac_url_.is_empty() || !pac_url_.is_valid()) { |
155 result_ = ERR_PAC_NOT_IN_DHCP; | 154 result_ = ERR_PAC_NOT_IN_DHCP; |
156 TransitionToFinish(); | 155 TransitionToFinish(); |
157 } else { | 156 } else { |
158 state_ = STATE_WAIT_URL; | 157 state_ = STATE_WAIT_URL; |
159 script_fetcher_.reset(ImplCreateScriptFetcher()); | 158 script_fetcher_.reset(ImplCreateScriptFetcher()); |
160 script_fetcher_->Fetch( | 159 script_fetcher_->Fetch( |
161 pac_url_, &pac_script_, | 160 pac_url_, |
| 161 &pac_script_, |
162 base::Bind(&DhcpProxyScriptAdapterFetcher::OnFetcherDone, | 162 base::Bind(&DhcpProxyScriptAdapterFetcher::OnFetcherDone, |
163 base::Unretained(this))); | 163 base::Unretained(this))); |
164 } | 164 } |
165 } | 165 } |
166 | 166 |
167 void DhcpProxyScriptAdapterFetcher::OnTimeout() { | 167 void DhcpProxyScriptAdapterFetcher::OnTimeout() { |
168 DCHECK_EQ(state_, STATE_WAIT_DHCP); | 168 DCHECK_EQ(state_, STATE_WAIT_DHCP); |
169 result_ = ERR_TIMED_OUT; | 169 result_ = ERR_TIMED_OUT; |
170 TransitionToFinish(); | 170 TransitionToFinish(); |
171 } | 171 } |
(...skipping 14 matching lines...) Expand all Loading... |
186 DCHECK(state_ == STATE_WAIT_DHCP || state_ == STATE_WAIT_URL); | 186 DCHECK(state_ == STATE_WAIT_DHCP || state_ == STATE_WAIT_URL); |
187 state_ = STATE_FINISH; | 187 state_ = STATE_FINISH; |
188 CompletionCallback callback = callback_; | 188 CompletionCallback callback = callback_; |
189 callback_.Reset(); | 189 callback_.Reset(); |
190 | 190 |
191 // Be careful not to touch any member state after this, as the client | 191 // Be careful not to touch any member state after this, as the client |
192 // may delete us during this callback. | 192 // may delete us during this callback. |
193 callback.Run(result_); | 193 callback.Run(result_); |
194 } | 194 } |
195 | 195 |
196 DhcpProxyScriptAdapterFetcher::State | 196 DhcpProxyScriptAdapterFetcher::State DhcpProxyScriptAdapterFetcher::state() |
197 DhcpProxyScriptAdapterFetcher::state() const { | 197 const { |
198 return state_; | 198 return state_; |
199 } | 199 } |
200 | 200 |
201 ProxyScriptFetcher* DhcpProxyScriptAdapterFetcher::ImplCreateScriptFetcher() { | 201 ProxyScriptFetcher* DhcpProxyScriptAdapterFetcher::ImplCreateScriptFetcher() { |
202 return new ProxyScriptFetcherImpl(url_request_context_); | 202 return new ProxyScriptFetcherImpl(url_request_context_); |
203 } | 203 } |
204 | 204 |
205 DhcpProxyScriptAdapterFetcher::DhcpQuery* | 205 DhcpProxyScriptAdapterFetcher::DhcpQuery* |
206 DhcpProxyScriptAdapterFetcher::ImplCreateDhcpQuery() { | 206 DhcpProxyScriptAdapterFetcher::ImplCreateDhcpQuery() { |
207 return new DhcpQuery(); | 207 return new DhcpQuery(); |
208 } | 208 } |
209 | 209 |
210 base::TimeDelta DhcpProxyScriptAdapterFetcher::ImplGetTimeout() const { | 210 base::TimeDelta DhcpProxyScriptAdapterFetcher::ImplGetTimeout() const { |
211 return base::TimeDelta::FromMilliseconds(kTimeoutMs); | 211 return base::TimeDelta::FromMilliseconds(kTimeoutMs); |
212 } | 212 } |
213 | 213 |
214 // static | 214 // static |
215 std::string DhcpProxyScriptAdapterFetcher::GetPacURLFromDhcp( | 215 std::string DhcpProxyScriptAdapterFetcher::GetPacURLFromDhcp( |
216 const std::string& adapter_name) { | 216 const std::string& adapter_name) { |
217 EnsureDhcpcsvcInit(); | 217 EnsureDhcpcsvcInit(); |
218 | 218 |
219 std::wstring adapter_name_wide = base::SysMultiByteToWide(adapter_name, | 219 std::wstring adapter_name_wide = |
220 CP_ACP); | 220 base::SysMultiByteToWide(adapter_name, CP_ACP); |
221 | 221 |
222 DHCPCAPI_PARAMS_ARRAY send_params = { 0, NULL }; | 222 DHCPCAPI_PARAMS_ARRAY send_params = {0, NULL}; |
223 | 223 |
224 BYTE option_data[] = { 1, 252 }; | 224 BYTE option_data[] = {1, 252}; |
225 DHCPCAPI_PARAMS wpad_params = { 0 }; | 225 DHCPCAPI_PARAMS wpad_params = {0}; |
226 wpad_params.OptionId = 252; | 226 wpad_params.OptionId = 252; |
227 wpad_params.IsVendor = FALSE; // Surprising, but intentional. | 227 wpad_params.IsVendor = FALSE; // Surprising, but intentional. |
228 | 228 |
229 DHCPCAPI_PARAMS_ARRAY request_params = { 0 }; | 229 DHCPCAPI_PARAMS_ARRAY request_params = {0}; |
230 request_params.nParams = 1; | 230 request_params.nParams = 1; |
231 request_params.Params = &wpad_params; | 231 request_params.Params = &wpad_params; |
232 | 232 |
233 // The maximum message size is typically 4096 bytes on Windows per | 233 // The maximum message size is typically 4096 bytes on Windows per |
234 // http://support.microsoft.com/kb/321592 | 234 // http://support.microsoft.com/kb/321592 |
235 DWORD result_buffer_size = 4096; | 235 DWORD result_buffer_size = 4096; |
236 scoped_ptr<BYTE, base::FreeDeleter> result_buffer; | 236 scoped_ptr<BYTE, base::FreeDeleter> result_buffer; |
237 int retry_count = 0; | 237 int retry_count = 0; |
238 DWORD res = NO_ERROR; | 238 DWORD res = NO_ERROR; |
239 do { | 239 do { |
240 result_buffer.reset(static_cast<BYTE*>(malloc(result_buffer_size))); | 240 result_buffer.reset(static_cast<BYTE*>(malloc(result_buffer_size))); |
241 | 241 |
242 // Note that while the DHCPCAPI_REQUEST_SYNCHRONOUS flag seems to indicate | 242 // Note that while the DHCPCAPI_REQUEST_SYNCHRONOUS flag seems to indicate |
243 // there might be an asynchronous mode, there seems to be (at least in | 243 // there might be an asynchronous mode, there seems to be (at least in |
244 // terms of well-documented use of this API) only a synchronous mode, with | 244 // terms of well-documented use of this API) only a synchronous mode, with |
245 // an optional "async notifications later if the option changes" mode. | 245 // an optional "async notifications later if the option changes" mode. |
246 // Even IE9, which we hope to emulate as IE is the most widely deployed | 246 // Even IE9, which we hope to emulate as IE is the most widely deployed |
247 // previous implementation of the DHCP aspect of WPAD and the only one | 247 // previous implementation of the DHCP aspect of WPAD and the only one |
248 // on Windows (Konqueror is the other, on Linux), uses this API with the | 248 // on Windows (Konqueror is the other, on Linux), uses this API with the |
249 // synchronous flag. There seem to be several Microsoft Knowledge Base | 249 // synchronous flag. There seem to be several Microsoft Knowledge Base |
250 // articles about calls to this function failing when other flags are used | 250 // articles about calls to this function failing when other flags are used |
251 // (e.g. http://support.microsoft.com/kb/885270) so we won't take any | 251 // (e.g. http://support.microsoft.com/kb/885270) so we won't take any |
252 // chances on non-standard, poorly documented usage. | 252 // chances on non-standard, poorly documented usage. |
253 res = ::DhcpRequestParams(DHCPCAPI_REQUEST_SYNCHRONOUS, | 253 res = ::DhcpRequestParams(DHCPCAPI_REQUEST_SYNCHRONOUS, |
254 NULL, | 254 NULL, |
255 const_cast<LPWSTR>(adapter_name_wide.c_str()), | 255 const_cast<LPWSTR>(adapter_name_wide.c_str()), |
256 NULL, | 256 NULL, |
257 send_params, request_params, | 257 send_params, |
258 result_buffer.get(), &result_buffer_size, | 258 request_params, |
| 259 result_buffer.get(), |
| 260 &result_buffer_size, |
259 NULL); | 261 NULL); |
260 ++retry_count; | 262 ++retry_count; |
261 } while (res == ERROR_MORE_DATA && retry_count <= 3); | 263 } while (res == ERROR_MORE_DATA && retry_count <= 3); |
262 | 264 |
263 if (res != NO_ERROR) { | 265 if (res != NO_ERROR) { |
264 LOG(WARNING) << "Error fetching PAC URL from DHCP: " << res; | 266 LOG(WARNING) << "Error fetching PAC URL from DHCP: " << res; |
265 UMA_HISTOGRAM_COUNTS("Net.DhcpWpadUnhandledDhcpError", 1); | 267 UMA_HISTOGRAM_COUNTS("Net.DhcpWpadUnhandledDhcpError", 1); |
266 } else if (wpad_params.nBytesData) { | 268 } else if (wpad_params.nBytesData) { |
267 return SanitizeDhcpApiString( | 269 return SanitizeDhcpApiString( |
268 reinterpret_cast<const char*>(wpad_params.Data), | 270 reinterpret_cast<const char*>(wpad_params.Data), |
269 wpad_params.nBytesData); | 271 wpad_params.nBytesData); |
270 } | 272 } |
271 | 273 |
272 return ""; | 274 return ""; |
273 } | 275 } |
274 | 276 |
275 // static | 277 // static |
276 std::string DhcpProxyScriptAdapterFetcher::SanitizeDhcpApiString( | 278 std::string DhcpProxyScriptAdapterFetcher::SanitizeDhcpApiString( |
277 const char* data, size_t count_bytes) { | 279 const char* data, |
| 280 size_t count_bytes) { |
278 // The result should be ASCII, not wide character. Some DHCP | 281 // The result should be ASCII, not wide character. Some DHCP |
279 // servers appear to count the trailing NULL in nBytesData, others | 282 // servers appear to count the trailing NULL in nBytesData, others |
280 // do not. A few (we've had one report, http://crbug.com/297810) | 283 // do not. A few (we've had one report, http://crbug.com/297810) |
281 // do not NULL-terminate but may \n-terminate. | 284 // do not NULL-terminate but may \n-terminate. |
282 // | 285 // |
283 // Belt and suspenders and elastic waistband: First, ensure we | 286 // Belt and suspenders and elastic waistband: First, ensure we |
284 // NULL-terminate after nBytesData; this is the inner constructor | 287 // NULL-terminate after nBytesData; this is the inner constructor |
285 // with nBytesData as a parameter. Then, return only up to the | 288 // with nBytesData as a parameter. Then, return only up to the |
286 // first null in case of embedded NULLs; this is the outer | 289 // first null in case of embedded NULLs; this is the outer |
287 // constructor that takes the result of c_str() on the inner. If | 290 // constructor that takes the result of c_str() on the inner. If |
288 // the server is giving us back a buffer with embedded NULLs, | 291 // the server is giving us back a buffer with embedded NULLs, |
289 // something is broken anyway. Finally, trim trailing whitespace. | 292 // something is broken anyway. Finally, trim trailing whitespace. |
290 std::string result(std::string(data, count_bytes).c_str()); | 293 std::string result(std::string(data, count_bytes).c_str()); |
291 base::TrimWhitespaceASCII(result, base::TRIM_TRAILING, &result); | 294 base::TrimWhitespaceASCII(result, base::TRIM_TRAILING, &result); |
292 return result; | 295 return result; |
293 } | 296 } |
294 | 297 |
295 } // namespace net | 298 } // namespace net |
OLD | NEW |