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_service.h" | 5 #include "net/proxy/proxy_service.h" |
6 | 6 |
7 #if defined(OS_WIN) | 7 #if defined(OS_WIN) |
8 #include <windows.h> | 8 #include <windows.h> |
9 #include <winhttp.h> | 9 #include <winhttp.h> |
10 #endif | 10 #endif |
11 | 11 |
12 #include <algorithm> | 12 #include <algorithm> |
13 | 13 |
| 14 #include "base/compiler_specific.h" |
14 #include "base/logging.h" | 15 #include "base/logging.h" |
15 #include "base/message_loop.h" | 16 #include "base/message_loop.h" |
16 #include "base/string_tokenizer.h" | 17 #include "base/string_tokenizer.h" |
17 #include "base/string_util.h" | 18 #include "base/string_util.h" |
18 #include "googleurl/src/gurl.h" | 19 #include "googleurl/src/gurl.h" |
19 #include "net/base/net_errors.h" | 20 #include "net/base/net_errors.h" |
20 #include "net/proxy/proxy_config_service_fixed.h" | 21 #include "net/proxy/proxy_config_service_fixed.h" |
21 #if defined(OS_WIN) | 22 #if defined(OS_WIN) |
22 #include "net/proxy/proxy_config_service_win.h" | 23 #include "net/proxy/proxy_config_service_win.h" |
23 #include "net/proxy/proxy_resolver_winhttp.h" | 24 #include "net/proxy/proxy_resolver_winhttp.h" |
(...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
158 } | 159 } |
159 | 160 |
160 void ProxyInfo::UseDirect() { | 161 void ProxyInfo::UseDirect() { |
161 proxy_list_.Set(std::string()); | 162 proxy_list_.Set(std::string()); |
162 } | 163 } |
163 | 164 |
164 void ProxyInfo::UseNamedProxy(const std::string& proxy_server) { | 165 void ProxyInfo::UseNamedProxy(const std::string& proxy_server) { |
165 proxy_list_.Set(proxy_server); | 166 proxy_list_.Set(proxy_server); |
166 } | 167 } |
167 | 168 |
168 #if defined(OS_WIN) | |
169 void ProxyInfo::Apply(HINTERNET request_handle) { | |
170 WINHTTP_PROXY_INFO pi; | |
171 std::wstring proxy; // We need to declare this variable here because | |
172 // lpszProxy needs to be valid in WinHttpSetOption. | |
173 if (is_direct()) { | |
174 pi.dwAccessType = WINHTTP_ACCESS_TYPE_NO_PROXY; | |
175 pi.lpszProxy = WINHTTP_NO_PROXY_NAME; | |
176 pi.lpszProxyBypass = WINHTTP_NO_PROXY_BYPASS; | |
177 } else { | |
178 proxy = ASCIIToWide(proxy_list_.Get()); | |
179 pi.dwAccessType = WINHTTP_ACCESS_TYPE_NAMED_PROXY; | |
180 pi.lpszProxy = const_cast<LPWSTR>(proxy.c_str()); | |
181 // NOTE: Specifying a bypass list here would serve no purpose. | |
182 pi.lpszProxyBypass = WINHTTP_NO_PROXY_BYPASS; | |
183 } | |
184 WinHttpSetOption(request_handle, WINHTTP_OPTION_PROXY, &pi, sizeof(pi)); | |
185 } | |
186 #endif | |
187 | |
188 std::string ProxyInfo::GetAnnotatedProxyList() { | 169 std::string ProxyInfo::GetAnnotatedProxyList() { |
189 return is_direct() ? "DIRECT" : proxy_list_.GetAnnotatedList(); | 170 return is_direct() ? "DIRECT" : proxy_list_.GetAnnotatedList(); |
190 } | 171 } |
191 | 172 |
192 // ProxyService::PacRequest --------------------------------------------------- | 173 // ProxyService::PacRequest --------------------------------------------------- |
193 | 174 |
194 // We rely on the fact that the origin thread (and its message loop) will not | 175 // We rely on the fact that the origin thread (and its message loop) will not |
195 // be destroyed until after the PAC thread is destroyed. | 176 // be destroyed until after the PAC thread is destroyed. |
196 | 177 |
197 class ProxyService::PacRequest : | 178 class ProxyService::PacRequest : |
198 public base::RefCountedThreadSafe<ProxyService::PacRequest> { | 179 public base::RefCountedThreadSafe<ProxyService::PacRequest> { |
199 public: | 180 public: |
200 PacRequest(ProxyService* service, | 181 PacRequest(ProxyService* service, |
201 const GURL& pac_url, | 182 const GURL& pac_url, |
202 CompletionCallback* callback) | 183 CompletionCallback* callback) |
203 : service_(service), | 184 : service_(service), |
204 callback_(callback), | 185 callback_(callback), |
205 results_(NULL), | 186 results_(NULL), |
206 config_id_(service->config_id()), | 187 config_id_(service->config_id()), |
207 pac_url_(pac_url), | 188 pac_url_(pac_url), |
208 origin_loop_(NULL) { | 189 origin_loop_(MessageLoop::current()) { |
209 // We need to remember original loop if only in case of asynchronous call | 190 DCHECK(callback); |
210 if (callback_) | |
211 origin_loop_ = MessageLoop::current(); | |
212 } | 191 } |
213 | 192 |
214 void Query(const GURL& url, ProxyInfo* results) { | 193 void Query(const GURL& url, ProxyInfo* results) { |
215 results_ = results; | 194 results_ = results; |
216 // If we have a valid callback then execute Query asynchronously | 195 // Execute Query asynchronously |
217 if (callback_) { | 196 AddRef(); // balanced in QueryComplete |
218 AddRef(); // balanced in QueryComplete | 197 service_->pac_thread()->message_loop()->PostTask(FROM_HERE, |
219 service_->pac_thread()->message_loop()->PostTask(FROM_HERE, | 198 NewRunnableMethod(this, &ProxyService::PacRequest::DoQuery, |
220 NewRunnableMethod(this, &ProxyService::PacRequest::DoQuery, | 199 service_->resolver(), url, pac_url_)); |
221 service_->resolver(), url, pac_url_)); | |
222 } else { | |
223 DoQuery(service_->resolver(), url, pac_url_); | |
224 } | |
225 } | 200 } |
226 | 201 |
227 void Cancel() { | 202 void Cancel() { |
228 // Clear these to inform QueryComplete that it should not try to | 203 // Clear these to inform QueryComplete that it should not try to |
229 // access them. | 204 // access them. |
230 service_ = NULL; | 205 service_ = NULL; |
231 callback_ = NULL; | 206 callback_ = NULL; |
232 results_ = NULL; | 207 results_ = NULL; |
233 } | 208 } |
234 | 209 |
235 private: | 210 private: |
236 // Runs on the PAC thread if a valid callback is provided. | 211 // Runs on the PAC thread. |
237 void DoQuery(ProxyResolver* resolver, | 212 void DoQuery(ProxyResolver* resolver, |
238 const GURL& query_url, | 213 const GURL& query_url, |
239 const GURL& pac_url) { | 214 const GURL& pac_url) { |
240 int rv = resolver->GetProxyForURL(query_url, pac_url, &results_buf_); | 215 int rv = resolver->GetProxyForURL(query_url, pac_url, &results_buf_); |
241 if (origin_loop_) { | 216 origin_loop_->PostTask(FROM_HERE, |
242 origin_loop_->PostTask(FROM_HERE, | 217 NewRunnableMethod(this, &PacRequest::QueryComplete, rv)); |
243 NewRunnableMethod(this, &PacRequest::QueryComplete, rv)); | |
244 } else { | |
245 QueryComplete(rv); | |
246 } | |
247 } | 218 } |
248 | 219 |
249 // If a valid callback is provided, this runs on the origin thread to | 220 // Runs the completion callback on the origin thread. |
250 // indicate that the completion callback should be run. | |
251 void QueryComplete(int result_code) { | 221 void QueryComplete(int result_code) { |
252 if (service_) | 222 // The PacRequest may have been cancelled after it was started. If it was |
| 223 // cancelled then |callback_|, |service_|, and |results_| will be NULL. |
| 224 bool was_cancelled = callback_ == NULL; |
| 225 |
| 226 if (!was_cancelled) { |
253 service_->DidCompletePacRequest(config_id_, result_code); | 227 service_->DidCompletePacRequest(config_id_, result_code); |
254 | 228 |
255 if (result_code == OK && results_) { | 229 if (result_code == OK) { |
256 results_->Use(results_buf_); | 230 results_->Use(results_buf_); |
257 results_->RemoveBadProxies(service_->proxy_retry_info_); | 231 results_->RemoveBadProxies(service_->proxy_retry_info_); |
| 232 } |
| 233 callback_->Run(result_code); |
258 } | 234 } |
259 | 235 |
260 if (callback_) | 236 Release(); // balances the AddRef in Query. we may get deleted after |
261 callback_->Run(result_code); | 237 // we return. |
262 | |
263 if (origin_loop_) { | |
264 Release(); // balances the AddRef in Query. we may get deleted after | |
265 // we return. | |
266 } | |
267 } | 238 } |
268 | 239 |
269 // Must only be used on the "origin" thread. | 240 // Must only be used on the "origin" thread. |
270 ProxyService* service_; | 241 ProxyService* service_; |
271 CompletionCallback* callback_; | 242 CompletionCallback* callback_; |
272 ProxyInfo* results_; | 243 ProxyInfo* results_; |
273 ProxyConfig::ID config_id_; | 244 ProxyConfig::ID config_id_; |
274 | 245 |
275 // Usable from within DoQuery on the PAC thread. | 246 // Usable from within DoQuery on the PAC thread. |
276 ProxyInfo results_buf_; | 247 ProxyInfo results_buf_; |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
314 // static | 285 // static |
315 ProxyService* ProxyService::CreateNull() { | 286 ProxyService* ProxyService::CreateNull() { |
316 // The ProxyResolver is set to NULL, since it should never be called | 287 // The ProxyResolver is set to NULL, since it should never be called |
317 // (because the configuration will never require PAC). | 288 // (because the configuration will never require PAC). |
318 return new ProxyService(new ProxyConfigServiceNull, NULL); | 289 return new ProxyService(new ProxyConfigServiceNull, NULL); |
319 } | 290 } |
320 | 291 |
321 int ProxyService::ResolveProxy(const GURL& url, ProxyInfo* result, | 292 int ProxyService::ResolveProxy(const GURL& url, ProxyInfo* result, |
322 CompletionCallback* callback, | 293 CompletionCallback* callback, |
323 PacRequest** pac_request) { | 294 PacRequest** pac_request) { |
| 295 DCHECK(callback); |
324 // The overhead of calling ProxyConfigService::GetProxyConfig is very low. | 296 // The overhead of calling ProxyConfigService::GetProxyConfig is very low. |
325 const TimeDelta kProxyConfigMaxAge = TimeDelta::FromSeconds(5); | 297 const TimeDelta kProxyConfigMaxAge = TimeDelta::FromSeconds(5); |
326 | 298 |
327 // Periodically check for a new config. | 299 // Periodically check for a new config. |
328 if (!config_has_been_updated_ || | 300 if (!config_has_been_updated_ || |
329 (TimeTicks::Now() - config_last_update_time_) > kProxyConfigMaxAge) | 301 (TimeTicks::Now() - config_last_update_time_) > kProxyConfigMaxAge) |
330 UpdateConfig(); | 302 UpdateConfig(); |
331 result->config_id_ = config_.id(); | 303 result->config_id_ = config_.id(); |
332 | 304 |
333 // Fallback to a "direct" (no proxy) connection if the current configuration | 305 // Fallback to a "direct" (no proxy) connection if the current configuration |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
374 } | 346 } |
375 } | 347 } |
376 // We failed to find a matching proxy server for the current URL | 348 // We failed to find a matching proxy server for the current URL |
377 // scheme. Default to direct. | 349 // scheme. Default to direct. |
378 result->UseDirect(); | 350 result->UseDirect(); |
379 } | 351 } |
380 return OK; | 352 return OK; |
381 } | 353 } |
382 | 354 |
383 if (config_.pac_url.is_valid() || config_.auto_detect) { | 355 if (config_.pac_url.is_valid() || config_.auto_detect) { |
384 if (callback) { | 356 if (!pac_thread_.get()) { |
385 // Create PAC thread for asynchronous mode. | 357 pac_thread_.reset(new base::Thread("pac-thread")); |
386 if (!pac_thread_.get()) { | 358 pac_thread_->Start(); |
387 pac_thread_.reset(new base::Thread("pac-thread")); | |
388 pac_thread_->Start(); | |
389 } | |
390 } else { | |
391 // If this request is synchronous, then there's no point | |
392 // in returning PacRequest instance | |
393 DCHECK(!pac_request); | |
394 } | 359 } |
395 | 360 |
396 scoped_refptr<PacRequest> req = | 361 scoped_refptr<PacRequest> req = |
397 new PacRequest(this, config_.pac_url, callback); | 362 new PacRequest(this, config_.pac_url, callback); |
398 | 363 |
399 // Strip away any reference fragments and the username/password, as they | 364 // Strip away any reference fragments and the username/password, as they |
400 // are not relevant to proxy resolution. | 365 // are not relevant to proxy resolution. |
401 GURL sanitized_url; | 366 GURL sanitized_url; |
402 { // TODO(eroman): The following duplicates logic from | 367 { // TODO(eroman): The following duplicates logic from |
403 // HttpUtil::SpecForRequest. Should probably live in net_util.h | 368 // HttpUtil::SpecForRequest. Should probably live in net_util.h |
404 GURL::Replacements replacements; | 369 GURL::Replacements replacements; |
405 replacements.ClearUsername(); | 370 replacements.ClearUsername(); |
406 replacements.ClearPassword(); | 371 replacements.ClearPassword(); |
407 replacements.ClearRef(); | 372 replacements.ClearRef(); |
408 sanitized_url = url.ReplaceComponents(replacements); | 373 sanitized_url = url.ReplaceComponents(replacements); |
409 } | 374 } |
410 | 375 |
411 req->Query(sanitized_url, result); | 376 req->Query(sanitized_url, result); |
412 | 377 |
413 if (callback) { | 378 if (pac_request) |
414 if (pac_request) | 379 *pac_request = req; |
415 *pac_request = req; | 380 |
416 return ERR_IO_PENDING; // Wait for callback. | 381 return ERR_IO_PENDING; // Wait for callback. |
417 } | |
418 return OK; | |
419 } | 382 } |
420 } | 383 } |
421 | 384 |
422 // otherwise, we have no proxy config | 385 // otherwise, we have no proxy config |
423 result->UseDirect(); | 386 result->UseDirect(); |
424 return OK; | 387 return OK; |
425 } | 388 } |
426 | 389 |
427 int ProxyService::ReconsiderProxyAfterError(const GURL& url, | 390 int ProxyService::ReconsiderProxyAfterError(const GURL& url, |
428 ProxyInfo* result, | 391 ProxyInfo* result, |
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
547 // Some systems (the Mac, for example) allow CIDR-style specification of | 510 // Some systems (the Mac, for example) allow CIDR-style specification of |
548 // proxy bypass for IP-specified hosts (e.g. "10.0.0.0/8"; see | 511 // proxy bypass for IP-specified hosts (e.g. "10.0.0.0/8"; see |
549 // http://www.tcd.ie/iss/internet/osx_proxy.php for a real-world example). | 512 // http://www.tcd.ie/iss/internet/osx_proxy.php for a real-world example). |
550 // That's kinda cool so we'll provide that for everyone. | 513 // That's kinda cool so we'll provide that for everyone. |
551 // TODO(avi): implement here | 514 // TODO(avi): implement here |
552 } | 515 } |
553 | 516 |
554 return false; | 517 return false; |
555 } | 518 } |
556 | 519 |
| 520 SyncProxyServiceHelper::SyncProxyServiceHelper(MessageLoop* io_message_loop, |
| 521 ProxyService* proxy_service) |
| 522 : io_message_loop_(io_message_loop), |
| 523 proxy_service_(proxy_service), |
| 524 event_(false, false), |
| 525 ALLOW_THIS_IN_INITIALIZER_LIST(callback_( |
| 526 this, &SyncProxyServiceHelper::OnCompletion)) { |
| 527 DCHECK(io_message_loop_ != MessageLoop::current()); |
| 528 } |
| 529 |
| 530 int SyncProxyServiceHelper::ResolveProxy(const GURL& url, |
| 531 ProxyInfo* proxy_info) { |
| 532 DCHECK(io_message_loop_ != MessageLoop::current()); |
| 533 |
| 534 io_message_loop_->PostTask(FROM_HERE, NewRunnableMethod( |
| 535 this, &SyncProxyServiceHelper::StartAsyncResolve, url)); |
| 536 |
| 537 event_.Wait(); |
| 538 |
| 539 if (result_ == net::OK) { |
| 540 *proxy_info = proxy_info_; |
| 541 } |
| 542 return result_; |
| 543 } |
| 544 |
| 545 int SyncProxyServiceHelper::ReconsiderProxyAfterError(const GURL& url, |
| 546 ProxyInfo* proxy_info) { |
| 547 DCHECK(io_message_loop_ != MessageLoop::current()); |
| 548 |
| 549 io_message_loop_->PostTask(FROM_HERE, NewRunnableMethod( |
| 550 this, &SyncProxyServiceHelper::StartAsyncReconsider, url)); |
| 551 |
| 552 event_.Wait(); |
| 553 |
| 554 if (result_ == net::OK) { |
| 555 *proxy_info = proxy_info_; |
| 556 } |
| 557 return result_; |
| 558 } |
| 559 |
| 560 void SyncProxyServiceHelper::StartAsyncResolve(const GURL& url) { |
| 561 result_ = proxy_service_->ResolveProxy(url, &proxy_info_, &callback_, NULL); |
| 562 if (result_ != net::ERR_IO_PENDING) { |
| 563 OnCompletion(result_); |
| 564 } |
| 565 } |
| 566 |
| 567 void SyncProxyServiceHelper::StartAsyncReconsider(const GURL& url) { |
| 568 result_ = proxy_service_->ReconsiderProxyAfterError( |
| 569 url, &proxy_info_, &callback_, NULL); |
| 570 if (result_ != net::ERR_IO_PENDING) { |
| 571 OnCompletion(result_); |
| 572 } |
| 573 } |
| 574 |
| 575 void SyncProxyServiceHelper::OnCompletion(int rv) { |
| 576 result_ = rv; |
| 577 event_.Signal(); |
| 578 } |
| 579 |
557 } // namespace net | 580 } // namespace net |
558 | 581 |
OLD | NEW |