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 #include <algorithm> | 7 #include <algorithm> |
8 | 8 |
9 #include "base/compiler_specific.h" | 9 #include "base/compiler_specific.h" |
10 #include "base/logging.h" | 10 #include "base/logging.h" |
11 #include "base/message_loop.h" | 11 #include "base/message_loop.h" |
12 #include "base/string_util.h" | 12 #include "base/string_util.h" |
13 #include "googleurl/src/gurl.h" | 13 #include "googleurl/src/gurl.h" |
14 #include "net/base/net_errors.h" | 14 #include "net/base/net_errors.h" |
15 #include "net/base/net_util.h" | 15 #include "net/base/net_util.h" |
| 16 #include "net/proxy/init_proxy_resolver.h" |
16 #include "net/proxy/proxy_config_service_fixed.h" | 17 #include "net/proxy/proxy_config_service_fixed.h" |
17 #include "net/proxy/proxy_script_fetcher.h" | 18 #include "net/proxy/proxy_script_fetcher.h" |
18 #if defined(OS_WIN) | 19 #if defined(OS_WIN) |
19 #include "net/proxy/proxy_config_service_win.h" | 20 #include "net/proxy/proxy_config_service_win.h" |
20 #include "net/proxy/proxy_resolver_winhttp.h" | 21 #include "net/proxy/proxy_resolver_winhttp.h" |
21 #elif defined(OS_MACOSX) | 22 #elif defined(OS_MACOSX) |
22 #include "net/proxy/proxy_resolver_mac.h" | 23 #include "net/proxy/proxy_resolver_mac.h" |
23 #elif defined(OS_LINUX) | 24 #elif defined(OS_LINUX) |
24 #include "net/proxy/proxy_config_service_linux.h" | 25 #include "net/proxy/proxy_config_service_linux.h" |
25 #endif | 26 #endif |
(...skipping 28 matching lines...) Expand all Loading... |
54 CompletionCallback* callback, | 55 CompletionCallback* callback, |
55 RequestHandle* request) { | 56 RequestHandle* request) { |
56 return ERR_NOT_IMPLEMENTED; | 57 return ERR_NOT_IMPLEMENTED; |
57 } | 58 } |
58 | 59 |
59 virtual void CancelRequest(RequestHandle request) { | 60 virtual void CancelRequest(RequestHandle request) { |
60 NOTREACHED(); | 61 NOTREACHED(); |
61 } | 62 } |
62 | 63 |
63 private: | 64 private: |
64 virtual void SetPacScriptByUrlInternal(const GURL& pac_url) {} | 65 virtual int SetPacScript(const GURL& /*pac_url*/, |
| 66 const std::string& /*pac_bytes*/, |
| 67 CompletionCallback* /*callback*/) { |
| 68 return ERR_NOT_IMPLEMENTED; |
| 69 } |
65 }; | 70 }; |
66 | 71 |
67 // ProxyService::PacRequest --------------------------------------------------- | 72 // ProxyService::PacRequest --------------------------------------------------- |
68 | 73 |
69 class ProxyService::PacRequest | 74 class ProxyService::PacRequest |
70 : public base::RefCounted<ProxyService::PacRequest> { | 75 : public base::RefCounted<ProxyService::PacRequest> { |
71 public: | 76 public: |
72 PacRequest(ProxyService* service, | 77 PacRequest(ProxyService* service, |
73 const GURL& url, | 78 const GURL& url, |
74 ProxyInfo* results, | 79 ProxyInfo* results, |
(...skipping 18 matching lines...) Expand all Loading... |
93 | 98 |
94 return resolver()->GetProxyForURL( | 99 return resolver()->GetProxyForURL( |
95 url_, results_, &io_callback_, &resolve_job_); | 100 url_, results_, &io_callback_, &resolve_job_); |
96 } | 101 } |
97 | 102 |
98 bool is_started() const { | 103 bool is_started() const { |
99 // Note that !! casts to bool. (VS gives a warning otherwise). | 104 // Note that !! casts to bool. (VS gives a warning otherwise). |
100 return !!resolve_job_; | 105 return !!resolve_job_; |
101 } | 106 } |
102 | 107 |
103 void StartAndComplete() { | 108 void StartAndCompleteCheckingForSynchronous() { |
104 int rv = Start(); | 109 int rv = service_->TryToCompleteSynchronously(url_, results_); |
| 110 if (rv == ERR_IO_PENDING) |
| 111 rv = Start(); |
105 if (rv != ERR_IO_PENDING) | 112 if (rv != ERR_IO_PENDING) |
106 QueryComplete(rv); | 113 QueryComplete(rv); |
107 } | 114 } |
108 | 115 |
109 void Cancel() { | 116 void CancelResolveJob() { |
110 // The request may already be running in the resolver. | 117 // The request may already be running in the resolver. |
111 if (is_started()) { | 118 if (is_started()) { |
112 resolver()->CancelRequest(resolve_job_); | 119 resolver()->CancelRequest(resolve_job_); |
113 resolve_job_ = NULL; | 120 resolve_job_ = NULL; |
114 } | 121 } |
| 122 DCHECK(!is_started()); |
| 123 } |
| 124 |
| 125 void Cancel() { |
| 126 CancelResolveJob(); |
115 | 127 |
116 // Mark as cancelled, to prevent accessing this again later. | 128 // Mark as cancelled, to prevent accessing this again later. |
117 service_ = NULL; | 129 service_ = NULL; |
118 user_callback_ = NULL; | 130 user_callback_ = NULL; |
119 results_ = NULL; | 131 results_ = NULL; |
120 } | 132 } |
121 | 133 |
122 // Returns true if Cancel() has been called. | 134 // Returns true if Cancel() has been called. |
123 bool was_cancelled() const { return user_callback_ == NULL; } | 135 bool was_cancelled() const { return user_callback_ == NULL; } |
124 | 136 |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
170 }; | 182 }; |
171 | 183 |
172 // ProxyService --------------------------------------------------------------- | 184 // ProxyService --------------------------------------------------------------- |
173 | 185 |
174 ProxyService::ProxyService(ProxyConfigService* config_service, | 186 ProxyService::ProxyService(ProxyConfigService* config_service, |
175 ProxyResolver* resolver) | 187 ProxyResolver* resolver) |
176 : config_service_(config_service), | 188 : config_service_(config_service), |
177 resolver_(resolver), | 189 resolver_(resolver), |
178 next_config_id_(1), | 190 next_config_id_(1), |
179 config_is_bad_(false), | 191 config_is_bad_(false), |
180 ALLOW_THIS_IN_INITIALIZER_LIST(proxy_script_fetcher_callback_( | 192 ALLOW_THIS_IN_INITIALIZER_LIST(init_proxy_resolver_callback_( |
181 this, &ProxyService::OnScriptFetchCompletion)), | 193 this, &ProxyService::OnInitProxyResolverComplete)) { |
182 fetched_pac_config_id_(ProxyConfig::INVALID_ID), | |
183 fetched_pac_error_(OK), | |
184 in_progress_fetch_config_id_(ProxyConfig::INVALID_ID) { | |
185 } | 194 } |
186 | 195 |
187 // static | 196 // static |
188 ProxyService* ProxyService::Create( | 197 ProxyService* ProxyService::Create( |
189 const ProxyConfig* pc, | 198 const ProxyConfig* pc, |
190 bool use_v8_resolver, | 199 bool use_v8_resolver, |
191 URLRequestContext* url_request_context, | 200 URLRequestContext* url_request_context, |
192 MessageLoop* io_loop) { | 201 MessageLoop* io_loop) { |
193 // Choose the system configuration service appropriate for each platform. | 202 // Choose the system configuration service appropriate for each platform. |
194 ProxyConfigService* proxy_config_service = pc ? | 203 ProxyConfigService* proxy_config_service = pc ? |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
247 | 256 |
248 // Check if the request can be completed right away. This is the case when | 257 // Check if the request can be completed right away. This is the case when |
249 // using a direct connection, or when the config is bad. | 258 // using a direct connection, or when the config is bad. |
250 UpdateConfigIfOld(); | 259 UpdateConfigIfOld(); |
251 int rv = TryToCompleteSynchronously(url, result); | 260 int rv = TryToCompleteSynchronously(url, result); |
252 if (rv != ERR_IO_PENDING) | 261 if (rv != ERR_IO_PENDING) |
253 return rv; | 262 return rv; |
254 | 263 |
255 scoped_refptr<PacRequest> req = new PacRequest(this, url, result, callback); | 264 scoped_refptr<PacRequest> req = new PacRequest(this, url, result, callback); |
256 | 265 |
257 bool resolver_is_ready = PrepareResolverForRequests(); | 266 bool resolver_is_ready = !IsInitializingProxyResolver(); |
258 | 267 |
259 if (resolver_is_ready) { | 268 if (resolver_is_ready) { |
260 // Start the resolve request. | 269 // Start the resolve request. |
261 rv = req->Start(); | 270 rv = req->Start(); |
262 if (rv != ERR_IO_PENDING) | 271 if (rv != ERR_IO_PENDING) |
263 return req->QueryDidComplete(rv); | 272 return req->QueryDidComplete(rv); |
264 } | 273 } |
265 | 274 |
266 DCHECK_EQ(ERR_IO_PENDING, rv); | 275 DCHECK_EQ(ERR_IO_PENDING, rv); |
267 DCHECK(!ContainsPendingRequest(req)); | 276 DCHECK(!ContainsPendingRequest(req)); |
(...skipping 15 matching lines...) Expand all Loading... |
283 // Fallback to a "direct" (no proxy) connection if the current configuration | 292 // Fallback to a "direct" (no proxy) connection if the current configuration |
284 // is known to be bad. | 293 // is known to be bad. |
285 if (config_is_bad_) { | 294 if (config_is_bad_) { |
286 // Reset this flag to false in case the ProxyInfo object is being | 295 // Reset this flag to false in case the ProxyInfo object is being |
287 // re-used by the caller. | 296 // re-used by the caller. |
288 result->config_was_tried_ = false; | 297 result->config_was_tried_ = false; |
289 } else { | 298 } else { |
290 // Remember that we are trying to use the current proxy configuration. | 299 // Remember that we are trying to use the current proxy configuration. |
291 result->config_was_tried_ = true; | 300 result->config_was_tried_ = true; |
292 | 301 |
| 302 if (config_.MayRequirePACResolver()) { |
| 303 // Need to go through ProxyResolver for this. |
| 304 return ERR_IO_PENDING; |
| 305 } |
| 306 |
293 if (!config_.proxy_rules.empty()) { | 307 if (!config_.proxy_rules.empty()) { |
294 ApplyProxyRules(url, config_.proxy_rules, result); | 308 ApplyProxyRules(url, config_.proxy_rules, result); |
295 return OK; | 309 return OK; |
296 } | 310 } |
297 | |
298 if (config_.pac_url.is_valid() || config_.auto_detect) { | |
299 // If we failed to download the PAC script, return the network error | |
300 // from the failed download. This is only going to happen for the first | |
301 // request after the failed download -- after that |config_is_bad_| will | |
302 // be set to true, so we short-cuircuit sooner. | |
303 if (fetched_pac_error_ != OK && !IsFetchingPacScript()) { | |
304 DidCompletePacRequest(fetched_pac_config_id_, fetched_pac_error_); | |
305 return fetched_pac_error_; | |
306 } | |
307 return ERR_IO_PENDING; | |
308 } | |
309 } | 311 } |
310 | 312 |
311 // otherwise, we have no proxy config | 313 // otherwise, we have no proxy config |
312 result->UseDirect(); | 314 result->UseDirect(); |
313 return OK; | 315 return OK; |
314 } | 316 } |
315 | 317 |
316 void ProxyService::ApplyProxyRules(const GURL& url, | 318 void ProxyService::ApplyProxyRules(const GURL& url, |
317 const ProxyConfig::ProxyRules& proxy_rules, | 319 const ProxyConfig::ProxyRules& proxy_rules, |
318 ProxyInfo* result) { | 320 ProxyInfo* result) { |
(...skipping 28 matching lines...) Expand all Loading... |
347 | 349 |
348 ProxyService::~ProxyService() { | 350 ProxyService::~ProxyService() { |
349 // Cancel any inprogress requests. | 351 // Cancel any inprogress requests. |
350 for (PendingRequests::iterator it = pending_requests_.begin(); | 352 for (PendingRequests::iterator it = pending_requests_.begin(); |
351 it != pending_requests_.end(); | 353 it != pending_requests_.end(); |
352 ++it) { | 354 ++it) { |
353 (*it)->Cancel(); | 355 (*it)->Cancel(); |
354 } | 356 } |
355 } | 357 } |
356 | 358 |
| 359 void ProxyService::SuspendAllPendingRequests() { |
| 360 for (PendingRequests::iterator it = pending_requests_.begin(); |
| 361 it != pending_requests_.end(); |
| 362 ++it) { |
| 363 it->get()->CancelResolveJob(); |
| 364 } |
| 365 } |
| 366 |
357 void ProxyService::ResumeAllPendingRequests() { | 367 void ProxyService::ResumeAllPendingRequests() { |
| 368 DCHECK(!IsInitializingProxyResolver()); |
| 369 |
358 // Make a copy in case |this| is deleted during the synchronous completion | 370 // Make a copy in case |this| is deleted during the synchronous completion |
359 // of one of the requests. If |this| is deleted then all of the PacRequest | 371 // of one of the requests. If |this| is deleted then all of the PacRequest |
360 // instances will be Cancel()-ed. | 372 // instances will be Cancel()-ed. |
361 PendingRequests pending_copy = pending_requests_; | 373 PendingRequests pending_copy = pending_requests_; |
362 | 374 |
363 for (PendingRequests::iterator it = pending_copy.begin(); | 375 for (PendingRequests::iterator it = pending_copy.begin(); |
364 it != pending_copy.end(); | 376 it != pending_copy.end(); |
365 ++it) { | 377 ++it) { |
366 PacRequest* req = it->get(); | 378 PacRequest* req = it->get(); |
367 if (!req->is_started() && !req->was_cancelled()) | 379 if (!req->is_started() && !req->was_cancelled()) { |
368 req->StartAndComplete(); | 380 // Note that we re-check for synchronous completion, in case we are |
| 381 // no longer using a ProxyResolver (can happen if we fell-back to manual). |
| 382 req->StartAndCompleteCheckingForSynchronous(); |
| 383 } |
369 } | 384 } |
370 } | 385 } |
371 | 386 |
372 bool ProxyService::PrepareResolverForRequests() { | 387 void ProxyService::OnInitProxyResolverComplete(int result) { |
373 // While the PAC script is being downloaded, block requests. | 388 DCHECK(init_proxy_resolver_.get()); |
374 if (IsFetchingPacScript()) | 389 DCHECK(config_.MayRequirePACResolver()); |
375 return false; | 390 init_proxy_resolver_.reset(); |
376 | 391 |
377 // Check if a new PAC script needs to be downloaded. | 392 if (result != OK) { |
378 DCHECK(config_.id() != ProxyConfig::INVALID_ID); | 393 LOG(INFO) << "Failed configuring with PAC script, falling-back to manual " |
379 if (resolver_->expects_pac_bytes() && | 394 "proxy servers."; |
380 config_.id() != fetched_pac_config_id_) { | 395 config_.auto_detect = false; |
381 // For auto-detect we use the well known WPAD url. | 396 config_.pac_url = GURL(); |
382 GURL pac_url = config_.auto_detect ? | 397 DCHECK(!config_.MayRequirePACResolver()); |
383 GURL("http://wpad/wpad.dat") : config_.pac_url; | |
384 | |
385 in_progress_fetch_config_id_ = config_.id(); | |
386 | |
387 LOG(INFO) << "Starting fetch of PAC script " << pac_url | |
388 << " for config_id=" << in_progress_fetch_config_id_; | |
389 | |
390 proxy_script_fetcher_->Fetch( | |
391 pac_url, &in_progress_fetch_bytes_, &proxy_script_fetcher_callback_); | |
392 return false; | |
393 } | 398 } |
394 | 399 |
395 // We are good to go. | |
396 return true; | |
397 } | |
398 | |
399 void ProxyService::OnScriptFetchCompletion(int result) { | |
400 DCHECK(IsFetchingPacScript()); | |
401 DCHECK(resolver_->expects_pac_bytes()); | |
402 | |
403 LOG(INFO) << "Completed PAC script fetch for config_id=" | |
404 << in_progress_fetch_config_id_ | |
405 << " with error " << ErrorToString(result) | |
406 << ". Fetched a total of " << in_progress_fetch_bytes_.size() | |
407 << " bytes"; | |
408 | |
409 // Notify the ProxyResolver of the new script data (will be empty string if | |
410 // result != OK). | |
411 resolver_->SetPacScriptByData(in_progress_fetch_bytes_); | |
412 | |
413 fetched_pac_config_id_ = in_progress_fetch_config_id_; | |
414 fetched_pac_error_ = result; | |
415 in_progress_fetch_config_id_ = ProxyConfig::INVALID_ID; | |
416 in_progress_fetch_bytes_.clear(); | |
417 | |
418 // Resume any requests which we had to defer until the PAC script was | 400 // Resume any requests which we had to defer until the PAC script was |
419 // downloaded. | 401 // downloaded. |
420 ResumeAllPendingRequests(); | 402 ResumeAllPendingRequests(); |
421 } | 403 } |
422 | 404 |
423 int ProxyService::ReconsiderProxyAfterError(const GURL& url, | 405 int ProxyService::ReconsiderProxyAfterError(const GURL& url, |
424 ProxyInfo* result, | 406 ProxyInfo* result, |
425 CompletionCallback* callback, | 407 CompletionCallback* callback, |
426 PacRequest** pac_request) { | 408 PacRequest** pac_request) { |
427 // Check to see if we have a new config since ResolveProxy was called. We | 409 // Check to see if we have a new config since ResolveProxy was called. We |
(...skipping 20 matching lines...) Expand all Loading... |
448 proxy_retry_info_.clear(); | 430 proxy_retry_info_.clear(); |
449 return ResolveProxy(url, result, callback, pac_request); | 431 return ResolveProxy(url, result, callback, pac_request); |
450 } | 432 } |
451 | 433 |
452 // We don't have new proxy settings to try, fallback to the next proxy | 434 // We don't have new proxy settings to try, fallback to the next proxy |
453 // in the list. | 435 // in the list. |
454 bool was_direct = result->is_direct(); | 436 bool was_direct = result->is_direct(); |
455 if (!was_direct && result->Fallback(&proxy_retry_info_)) | 437 if (!was_direct && result->Fallback(&proxy_retry_info_)) |
456 return OK; | 438 return OK; |
457 | 439 |
| 440 // TODO(eroman): Hmm, this doesn't seem right. For starters just because |
| 441 // auto_detect is true doesn't mean we are actually using it. |
458 if (!config_.auto_detect && !config_.proxy_rules.empty()) { | 442 if (!config_.auto_detect && !config_.proxy_rules.empty()) { |
459 // If auto detect is on, then we should try a DIRECT connection | 443 // If auto detect is on, then we should try a DIRECT connection |
460 // as the attempt to reach the proxy failed. | 444 // as the attempt to reach the proxy failed. |
461 return ERR_FAILED; | 445 return ERR_FAILED; |
462 } | 446 } |
463 | 447 |
464 // If we already tried a direct connection, then just give up. | 448 // If we already tried a direct connection, then just give up. |
465 if (was_direct) | 449 if (was_direct) |
466 return ERR_FAILED; | 450 return ERR_FAILED; |
467 | 451 |
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
580 | 564 |
581 // Increment the ID to reflect that the config has changed. | 565 // Increment the ID to reflect that the config has changed. |
582 config_.set_id(next_config_id_++); | 566 config_.set_id(next_config_id_++); |
583 | 567 |
584 LOG(INFO) << "New proxy configuration was loaded:\n" << config_; | 568 LOG(INFO) << "New proxy configuration was loaded:\n" << config_; |
585 | 569 |
586 // Reset state associated with latest config. | 570 // Reset state associated with latest config. |
587 config_is_bad_ = false; | 571 config_is_bad_ = false; |
588 proxy_retry_info_.clear(); | 572 proxy_retry_info_.clear(); |
589 | 573 |
590 // Tell the resolver to use the new PAC URL (for resolvers that fetch the | 574 // Cancel any PAC fetching / ProxyResolver::SetPacScript() which was |
591 // PAC script internally). | 575 // in progress for the previous configuration. |
592 // TODO(eroman): this isn't quite right. See http://crbug.com/9985 | 576 init_proxy_resolver_.reset(); |
593 if ((config_.pac_url.is_valid() || config_.auto_detect) && | 577 |
594 !resolver_->expects_pac_bytes()) { | 578 // Start downloading + testing the PAC scripts for this new configuration. |
595 const GURL pac_url = config_.auto_detect ? GURL() : config_.pac_url; | 579 if (config_.MayRequirePACResolver()) { |
596 resolver_->SetPacScriptByUrl(pac_url); | 580 // Since InitProxyResolver will be playing around with the proxy resolver |
| 581 // as it tests the parsing of various PAC scripts, make sure there is |
| 582 // nothing in-flight in |resolver_|. These paused requests are resumed by |
| 583 // OnInitProxyResolverComplete(). |
| 584 SuspendAllPendingRequests(); |
| 585 |
| 586 init_proxy_resolver_.reset( |
| 587 new InitProxyResolver(resolver_.get(), proxy_script_fetcher_.get())); |
| 588 int rv = init_proxy_resolver_->Init( |
| 589 config_, &init_proxy_resolver_callback_); |
| 590 if (rv != ERR_IO_PENDING) |
| 591 OnInitProxyResolverComplete(rv); |
597 } | 592 } |
598 } | 593 } |
599 | 594 |
600 void ProxyService::UpdateConfigIfOld() { | 595 void ProxyService::UpdateConfigIfOld() { |
601 // The overhead of calling ProxyConfigService::GetProxyConfig is very low. | 596 // The overhead of calling ProxyConfigService::GetProxyConfig is very low. |
602 const TimeDelta kProxyConfigMaxAge = TimeDelta::FromSeconds(5); | 597 const TimeDelta kProxyConfigMaxAge = TimeDelta::FromSeconds(5); |
603 | 598 |
604 // Periodically check for a new config. | 599 // Periodically check for a new config. |
605 if (!config_has_been_initialized() || | 600 if (!config_has_been_initialized() || |
606 (TimeTicks::Now() - config_last_update_time_) > kProxyConfigMaxAge) | 601 (TimeTicks::Now() - config_last_update_time_) > kProxyConfigMaxAge) |
(...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
746 OnCompletion(result_); | 741 OnCompletion(result_); |
747 } | 742 } |
748 } | 743 } |
749 | 744 |
750 void SyncProxyServiceHelper::OnCompletion(int rv) { | 745 void SyncProxyServiceHelper::OnCompletion(int rv) { |
751 result_ = rv; | 746 result_ = rv; |
752 event_.Signal(); | 747 event_.Signal(); |
753 } | 748 } |
754 | 749 |
755 } // namespace net | 750 } // namespace net |
OLD | NEW |