• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2011 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.
4 
5 #include "net/proxy/proxy_service.h"
6 
7 #include <algorithm>
8 
9 #include "base/compiler_specific.h"
10 #include "base/logging.h"
11 #include "base/message_loop.h"
12 #include "base/string_util.h"
13 #include "base/values.h"
14 #include "googleurl/src/gurl.h"
15 #include "net/base/net_errors.h"
16 #include "net/base/net_log.h"
17 #include "net/base/net_util.h"
18 #include "net/proxy/init_proxy_resolver.h"
19 #include "net/proxy/multi_threaded_proxy_resolver.h"
20 #include "net/proxy/proxy_config_service_fixed.h"
21 #include "net/proxy/proxy_resolver.h"
22 #include "net/proxy/proxy_resolver_js_bindings.h"
23 #ifndef ANDROID
24 #include "net/proxy/proxy_resolver_v8.h"
25 #endif
26 #include "net/proxy/proxy_script_fetcher.h"
27 #include "net/proxy/sync_host_resolver_bridge.h"
28 #include "net/url_request/url_request_context.h"
29 
30 #if defined(OS_WIN)
31 #include "net/proxy/proxy_config_service_win.h"
32 #include "net/proxy/proxy_resolver_winhttp.h"
33 #elif defined(OS_MACOSX)
34 #include "net/proxy/proxy_config_service_mac.h"
35 #include "net/proxy/proxy_resolver_mac.h"
36 #elif defined(OS_LINUX) && !defined(OS_CHROMEOS)
37 #include "net/proxy/proxy_config_service_linux.h"
38 #endif
39 
40 using base::TimeDelta;
41 using base::TimeTicks;
42 
43 namespace net {
44 
45 namespace {
46 
47 const size_t kMaxNumNetLogEntries = 100;
48 const size_t kDefaultNumPacThreads = 4;
49 
50 // When the IP address changes we don't immediately re-run proxy auto-config.
51 // Instead, we  wait for |kNumMillisToStallAfterNetworkChanges| before
52 // attempting to re-valuate proxy auto-config.
53 //
54 // During this time window, any resolve requests sent to the ProxyService will
55 // be queued. Once we have waited the required amount of them, the proxy
56 // auto-config step will be run, and the queued requests resumed.
57 //
58 // The reason we play this game is that our signal for detecting network
59 // changes (NetworkChangeNotifier) may fire *before* the system's networking
60 // dependencies are fully configured. This is a problem since it means if
61 // we were to run proxy auto-config right away, it could fail due to spurious
62 // DNS failures. (see http://crbug.com/50779 for more details.)
63 //
64 // By adding the wait window, we give things a chance to get properly set up.
65 // Now by the time we run the proxy-autoconfig there is a lower chance of
66 // getting transient DNS / connect failures.
67 //
68 // Admitedly this is a hack. Ideally we would have NetworkChangeNotifier
69 // deliver a reliable signal indicating that the network has changed AND is
70 // ready for action... But until then, we can reduce the likelihood of users
71 // getting wedged because of proxy detection failures on network switch.
72 //
73 // The obvious downside to this strategy is it introduces an additional
74 // latency when switching networks. This delay shouldn't be too disruptive
75 // assuming network switches are infrequent and user initiated. However if
76 // NetworkChangeNotifier delivers network changes more frequently this could
77 // cause jankiness. (NetworkChangeNotifier broadcasts a change event when ANY
78 // interface goes up/down. So in theory if the non-primary interface were
79 // hopping on and off wireless networks our constant delayed reconfiguration
80 // could add noticeable jank.)
81 //
82 // The specific hard-coded wait time below is arbitrary.
83 // Basically I ran some experiments switching between wireless networks on
84 // a Linux Ubuntu (Lucid) laptop, and experimentally found this timeout fixes
85 // things. It is entirely possible that the value is insuficient for other
86 // setups.
87 const int64 kNumMillisToStallAfterNetworkChanges = 2000;
88 
89 // Config getter that always returns direct settings.
90 class ProxyConfigServiceDirect : public ProxyConfigService {
91  public:
92   // ProxyConfigService implementation:
AddObserver(Observer * observer)93   virtual void AddObserver(Observer* observer) {}
RemoveObserver(Observer * observer)94   virtual void RemoveObserver(Observer* observer) {}
GetLatestProxyConfig(ProxyConfig * config)95   virtual ConfigAvailability GetLatestProxyConfig(ProxyConfig* config) {
96     *config = ProxyConfig::CreateDirect();
97     return CONFIG_VALID;
98   }
99 };
100 
101 // Proxy resolver that fails every time.
102 class ProxyResolverNull : public ProxyResolver {
103  public:
ProxyResolverNull()104   ProxyResolverNull() : ProxyResolver(false /*expects_pac_bytes*/) {}
105 
106   // ProxyResolver implementation:
GetProxyForURL(const GURL & url,ProxyInfo * results,CompletionCallback * callback,RequestHandle * request,const BoundNetLog & net_log)107   virtual int GetProxyForURL(const GURL& url,
108                              ProxyInfo* results,
109                              CompletionCallback* callback,
110                              RequestHandle* request,
111                              const BoundNetLog& net_log) {
112     return ERR_NOT_IMPLEMENTED;
113   }
114 
CancelRequest(RequestHandle request)115   virtual void CancelRequest(RequestHandle request) {
116     NOTREACHED();
117   }
118 
CancelSetPacScript()119   virtual void CancelSetPacScript() {
120     NOTREACHED();
121   }
122 
SetPacScript(const scoped_refptr<ProxyResolverScriptData> &,CompletionCallback *)123   virtual int SetPacScript(
124       const scoped_refptr<ProxyResolverScriptData>& /*script_data*/,
125       CompletionCallback* /*callback*/) {
126     return ERR_NOT_IMPLEMENTED;
127   }
128 };
129 
130 // ProxyResolver that simulates a PAC script which returns
131 // |pac_string| for every single URL.
132 class ProxyResolverFromPacString : public ProxyResolver {
133  public:
ProxyResolverFromPacString(const std::string & pac_string)134   ProxyResolverFromPacString(const std::string& pac_string)
135       : ProxyResolver(false /*expects_pac_bytes*/),
136         pac_string_(pac_string) {}
137 
GetProxyForURL(const GURL & url,ProxyInfo * results,CompletionCallback * callback,RequestHandle * request,const BoundNetLog & net_log)138   virtual int GetProxyForURL(const GURL& url,
139                              ProxyInfo* results,
140                              CompletionCallback* callback,
141                              RequestHandle* request,
142                              const BoundNetLog& net_log) {
143     results->UsePacString(pac_string_);
144     return OK;
145   }
146 
CancelRequest(RequestHandle request)147   virtual void CancelRequest(RequestHandle request) {
148     NOTREACHED();
149   }
150 
CancelSetPacScript()151   virtual void CancelSetPacScript() {
152     NOTREACHED();
153   }
154 
SetPacScript(const scoped_refptr<ProxyResolverScriptData> & pac_script,CompletionCallback * callback)155   virtual int SetPacScript(
156       const scoped_refptr<ProxyResolverScriptData>& pac_script,
157       CompletionCallback* callback) {
158     return OK;
159   }
160 
161  private:
162   const std::string pac_string_;
163 };
164 
165 #ifndef ANDROID
166 // This factory creates V8ProxyResolvers with appropriate javascript bindings.
167 class ProxyResolverFactoryForV8 : public ProxyResolverFactory {
168  public:
169   // |async_host_resolver|, |io_loop| and |net_log| must remain
170   // valid for the duration of our lifetime.
171   // |async_host_resolver| will only be operated on |io_loop|.
ProxyResolverFactoryForV8(HostResolver * async_host_resolver,MessageLoop * io_loop,NetLog * net_log)172   ProxyResolverFactoryForV8(HostResolver* async_host_resolver,
173                             MessageLoop* io_loop,
174                             NetLog* net_log)
175       : ProxyResolverFactory(true /*expects_pac_bytes*/),
176         async_host_resolver_(async_host_resolver),
177         io_loop_(io_loop),
178         net_log_(net_log) {
179   }
180 
CreateProxyResolver()181   virtual ProxyResolver* CreateProxyResolver() {
182     // Create a synchronous host resolver wrapper that operates
183     // |async_host_resolver_| on |io_loop_|.
184     SyncHostResolverBridge* sync_host_resolver =
185         new SyncHostResolverBridge(async_host_resolver_, io_loop_);
186 
187     ProxyResolverJSBindings* js_bindings =
188         ProxyResolverJSBindings::CreateDefault(sync_host_resolver, net_log_);
189 
190     // ProxyResolverV8 takes ownership of |js_bindings|.
191     return new ProxyResolverV8(js_bindings);
192   }
193 
194  private:
195   HostResolver* const async_host_resolver_;
196   MessageLoop* io_loop_;
197   NetLog* net_log_;
198 };
199 #endif
200 
201 // Creates ProxyResolvers using a platform-specific implementation.
202 class ProxyResolverFactoryForSystem : public ProxyResolverFactory {
203  public:
ProxyResolverFactoryForSystem()204   ProxyResolverFactoryForSystem()
205       : ProxyResolverFactory(false /*expects_pac_bytes*/) {}
206 
CreateProxyResolver()207   virtual ProxyResolver* CreateProxyResolver() {
208     DCHECK(IsSupported());
209 #if defined(OS_WIN)
210     return new ProxyResolverWinHttp();
211 #elif defined(OS_MACOSX)
212     return new ProxyResolverMac();
213 #else
214     NOTREACHED();
215     return NULL;
216 #endif
217   }
218 
IsSupported()219   static bool IsSupported() {
220 #if defined(OS_WIN) || defined(OS_MACOSX)
221     return true;
222 #else
223     return false;
224 #endif
225   }
226 };
227 
228 // NetLog parameter to describe a proxy configuration change.
229 class ProxyConfigChangedNetLogParam : public NetLog::EventParameters {
230  public:
ProxyConfigChangedNetLogParam(const ProxyConfig & old_config,const ProxyConfig & new_config)231   ProxyConfigChangedNetLogParam(const ProxyConfig& old_config,
232                                 const ProxyConfig& new_config)
233       : old_config_(old_config),
234         new_config_(new_config) {
235   }
236 
ToValue() const237   virtual Value* ToValue() const {
238     DictionaryValue* dict = new DictionaryValue();
239     // The "old_config" is optional -- the first notification will not have
240     // any "previous" configuration.
241     if (old_config_.is_valid())
242       dict->Set("old_config", old_config_.ToValue());
243     dict->Set("new_config", new_config_.ToValue());
244     return dict;
245   }
246 
247  private:
248   const ProxyConfig old_config_;
249   const ProxyConfig new_config_;
250   DISALLOW_COPY_AND_ASSIGN(ProxyConfigChangedNetLogParam);
251 };
252 
253 }  // namespace
254 
255 // ProxyService::PacRequest ---------------------------------------------------
256 
257 class ProxyService::PacRequest
258     : public base::RefCounted<ProxyService::PacRequest> {
259  public:
PacRequest(ProxyService * service,const GURL & url,ProxyInfo * results,CompletionCallback * user_callback,const BoundNetLog & net_log)260   PacRequest(ProxyService* service,
261              const GURL& url,
262              ProxyInfo* results,
263              CompletionCallback* user_callback,
264              const BoundNetLog& net_log)
265       : service_(service),
266         user_callback_(user_callback),
267         ALLOW_THIS_IN_INITIALIZER_LIST(io_callback_(
268             this, &PacRequest::QueryComplete)),
269         results_(results),
270         url_(url),
271         resolve_job_(NULL),
272         config_id_(ProxyConfig::INVALID_ID),
273         net_log_(net_log) {
274     DCHECK(user_callback);
275   }
276 
277   // Starts the resolve proxy request.
Start()278   int Start() {
279     DCHECK(!was_cancelled());
280     DCHECK(!is_started());
281 
282     DCHECK(service_->config_.is_valid());
283 
284     config_id_ = service_->config_.id();
285 
286     return resolver()->GetProxyForURL(
287         url_, results_, &io_callback_, &resolve_job_, net_log_);
288   }
289 
is_started() const290   bool is_started() const {
291     // Note that !! casts to bool. (VS gives a warning otherwise).
292     return !!resolve_job_;
293   }
294 
StartAndCompleteCheckingForSynchronous()295   void StartAndCompleteCheckingForSynchronous() {
296     int rv = service_->TryToCompleteSynchronously(url_, results_);
297     if (rv == ERR_IO_PENDING)
298       rv = Start();
299     if (rv != ERR_IO_PENDING)
300       QueryComplete(rv);
301   }
302 
CancelResolveJob()303   void CancelResolveJob() {
304     DCHECK(is_started());
305     // The request may already be running in the resolver.
306     resolver()->CancelRequest(resolve_job_);
307     resolve_job_ = NULL;
308     DCHECK(!is_started());
309   }
310 
Cancel()311   void Cancel() {
312     net_log_.AddEvent(NetLog::TYPE_CANCELLED, NULL);
313 
314     if (is_started())
315       CancelResolveJob();
316 
317     // Mark as cancelled, to prevent accessing this again later.
318     service_ = NULL;
319     user_callback_ = NULL;
320     results_ = NULL;
321 
322     net_log_.EndEvent(NetLog::TYPE_PROXY_SERVICE, NULL);
323   }
324 
325   // Returns true if Cancel() has been called.
was_cancelled() const326   bool was_cancelled() const { return user_callback_ == NULL; }
327 
328   // Helper to call after ProxyResolver completion (both synchronous and
329   // asynchronous). Fixes up the result that is to be returned to user.
QueryDidComplete(int result_code)330   int QueryDidComplete(int result_code) {
331     DCHECK(!was_cancelled());
332 
333     // Make a note in the results which configuration was in use at the
334     // time of the resolve.
335     results_->config_id_ = config_id_;
336 
337     // Reset the state associated with in-progress-resolve.
338     resolve_job_ = NULL;
339     config_id_ = ProxyConfig::INVALID_ID;
340 
341     return service_->DidFinishResolvingProxy(results_, result_code, net_log_);
342   }
343 
net_log()344   BoundNetLog* net_log() { return &net_log_; }
345 
346  private:
347   friend class base::RefCounted<ProxyService::PacRequest>;
348 
~PacRequest()349   ~PacRequest() {}
350 
351   // Callback for when the ProxyResolver request has completed.
QueryComplete(int result_code)352   void QueryComplete(int result_code) {
353     result_code = QueryDidComplete(result_code);
354 
355     // Remove this completed PacRequest from the service's pending list.
356     /// (which will probably cause deletion of |this|).
357     CompletionCallback* callback = user_callback_;
358     service_->RemovePendingRequest(this);
359 
360     callback->Run(result_code);
361   }
362 
resolver() const363   ProxyResolver* resolver() const { return service_->resolver_.get(); }
364 
365   // Note that we don't hold a reference to the ProxyService. Outstanding
366   // requests are cancelled during ~ProxyService, so this is guaranteed
367   // to be valid throughout our lifetime.
368   ProxyService* service_;
369   CompletionCallback* user_callback_;
370   CompletionCallbackImpl<PacRequest> io_callback_;
371   ProxyInfo* results_;
372   GURL url_;
373   ProxyResolver::RequestHandle resolve_job_;
374   ProxyConfig::ID config_id_;  // The config id when the resolve was started.
375   BoundNetLog net_log_;
376 };
377 
378 // ProxyService ---------------------------------------------------------------
379 
ProxyService(ProxyConfigService * config_service,ProxyResolver * resolver,NetLog * net_log)380 ProxyService::ProxyService(ProxyConfigService* config_service,
381                            ProxyResolver* resolver,
382                            NetLog* net_log)
383     : resolver_(resolver),
384       next_config_id_(1),
385       ALLOW_THIS_IN_INITIALIZER_LIST(init_proxy_resolver_callback_(
386           this, &ProxyService::OnInitProxyResolverComplete)),
387       current_state_(STATE_NONE) ,
388       net_log_(net_log),
389       stall_proxy_auto_config_delay_(
390           base::TimeDelta::FromMilliseconds(
391               kNumMillisToStallAfterNetworkChanges)) {
392   NetworkChangeNotifier::AddIPAddressObserver(this);
393   ResetConfigService(config_service);
394 }
395 
396 #ifndef ANDROID
397 // static
CreateUsingV8ProxyResolver(ProxyConfigService * proxy_config_service,size_t num_pac_threads,ProxyScriptFetcher * proxy_script_fetcher,HostResolver * host_resolver,NetLog * net_log)398 ProxyService* ProxyService::CreateUsingV8ProxyResolver(
399     ProxyConfigService* proxy_config_service,
400     size_t num_pac_threads,
401     ProxyScriptFetcher* proxy_script_fetcher,
402     HostResolver* host_resolver,
403     NetLog* net_log) {
404   DCHECK(proxy_config_service);
405   DCHECK(proxy_script_fetcher);
406   DCHECK(host_resolver);
407 
408   if (num_pac_threads == 0)
409     num_pac_threads = kDefaultNumPacThreads;
410 
411   ProxyResolverFactory* sync_resolver_factory =
412       new ProxyResolverFactoryForV8(
413           host_resolver,
414           MessageLoop::current(),
415           net_log);
416 
417   ProxyResolver* proxy_resolver =
418       new MultiThreadedProxyResolver(sync_resolver_factory, num_pac_threads);
419 
420   ProxyService* proxy_service =
421       new ProxyService(proxy_config_service, proxy_resolver, net_log);
422 
423   // Configure PAC script downloads to be issued using |proxy_script_fetcher|.
424   proxy_service->SetProxyScriptFetcher(proxy_script_fetcher);
425 
426   return proxy_service;
427 }
428 #endif
429 
430 // static
CreateUsingSystemProxyResolver(ProxyConfigService * proxy_config_service,size_t num_pac_threads,NetLog * net_log)431 ProxyService* ProxyService::CreateUsingSystemProxyResolver(
432     ProxyConfigService* proxy_config_service,
433     size_t num_pac_threads,
434     NetLog* net_log) {
435   DCHECK(proxy_config_service);
436 
437   if (!ProxyResolverFactoryForSystem::IsSupported()) {
438     LOG(WARNING) << "PAC support disabled because there is no "
439                     "system implementation";
440     return CreateWithoutProxyResolver(proxy_config_service, net_log);
441   }
442 
443   if (num_pac_threads == 0)
444     num_pac_threads = kDefaultNumPacThreads;
445 
446   ProxyResolver* proxy_resolver = new MultiThreadedProxyResolver(
447       new ProxyResolverFactoryForSystem(), num_pac_threads);
448 
449   return new ProxyService(proxy_config_service, proxy_resolver, net_log);
450 }
451 
452 // static
CreateWithoutProxyResolver(ProxyConfigService * proxy_config_service,NetLog * net_log)453 ProxyService* ProxyService::CreateWithoutProxyResolver(
454     ProxyConfigService* proxy_config_service,
455     NetLog* net_log) {
456   return new ProxyService(proxy_config_service,
457                           new ProxyResolverNull(),
458                           net_log);
459 }
460 
461 // static
CreateFixed(const ProxyConfig & pc)462 ProxyService* ProxyService::CreateFixed(const ProxyConfig& pc) {
463   // TODO(eroman): This isn't quite right, won't work if |pc| specifies
464   //               a PAC script.
465   return CreateUsingSystemProxyResolver(new ProxyConfigServiceFixed(pc),
466                                         0, NULL);
467 }
468 
469 // static
CreateFixed(const std::string & proxy)470 ProxyService* ProxyService::CreateFixed(const std::string& proxy) {
471   net::ProxyConfig proxy_config;
472   proxy_config.proxy_rules().ParseFromString(proxy);
473   return ProxyService::CreateFixed(proxy_config);
474 }
475 
476 // static
CreateDirect()477 ProxyService* ProxyService::CreateDirect() {
478   return CreateDirectWithNetLog(NULL);
479 }
480 
CreateDirectWithNetLog(NetLog * net_log)481 ProxyService* ProxyService::CreateDirectWithNetLog(NetLog* net_log) {
482   // Use direct connections.
483   return new ProxyService(new ProxyConfigServiceDirect, new ProxyResolverNull,
484                           net_log);
485 }
486 
487 // static
CreateFixedFromPacResult(const std::string & pac_string)488 ProxyService* ProxyService::CreateFixedFromPacResult(
489     const std::string& pac_string) {
490 
491   // We need the settings to contain an "automatic" setting, otherwise the
492   // ProxyResolver dependency we give it will never be used.
493   scoped_ptr<ProxyConfigService> proxy_config_service(
494       new ProxyConfigServiceFixed(ProxyConfig::CreateAutoDetect()));
495 
496   scoped_ptr<ProxyResolver> proxy_resolver(
497       new ProxyResolverFromPacString(pac_string));
498 
499   return new ProxyService(proxy_config_service.release(),
500                           proxy_resolver.release(),
501                           NULL);
502 }
503 
ResolveProxy(const GURL & raw_url,ProxyInfo * result,CompletionCallback * callback,PacRequest ** pac_request,const BoundNetLog & net_log)504 int ProxyService::ResolveProxy(const GURL& raw_url,
505                                ProxyInfo* result,
506                                CompletionCallback* callback,
507                                PacRequest** pac_request,
508                                const BoundNetLog& net_log) {
509   DCHECK(CalledOnValidThread());
510   DCHECK(callback);
511 
512   net_log.BeginEvent(NetLog::TYPE_PROXY_SERVICE, NULL);
513 
514   config_service_->OnLazyPoll();
515   if (current_state_ == STATE_NONE)
516     ApplyProxyConfigIfAvailable();
517 
518   // Strip away any reference fragments and the username/password, as they
519   // are not relevant to proxy resolution.
520   GURL url = SimplifyUrlForRequest(raw_url);
521 
522   // Check if the request can be completed right away. (This is the case when
523   // using a direct connection for example).
524   int rv = TryToCompleteSynchronously(url, result);
525   if (rv != ERR_IO_PENDING)
526     return DidFinishResolvingProxy(result, rv, net_log);
527 
528   scoped_refptr<PacRequest> req(
529       new PacRequest(this, url, result, callback, net_log));
530 
531   if (current_state_ == STATE_READY) {
532     // Start the resolve request.
533     rv = req->Start();
534     if (rv != ERR_IO_PENDING)
535       return req->QueryDidComplete(rv);
536   } else {
537     req->net_log()->BeginEvent(NetLog::TYPE_PROXY_SERVICE_WAITING_FOR_INIT_PAC,
538                                NULL);
539   }
540 
541   DCHECK_EQ(ERR_IO_PENDING, rv);
542   DCHECK(!ContainsPendingRequest(req));
543   pending_requests_.push_back(req);
544 
545   // Completion will be notifed through |callback|, unless the caller cancels
546   // the request using |pac_request|.
547   if (pac_request)
548     *pac_request = req.get();
549   return rv;  // ERR_IO_PENDING
550 }
551 
TryToCompleteSynchronously(const GURL & url,ProxyInfo * result)552 int ProxyService::TryToCompleteSynchronously(const GURL& url,
553                                              ProxyInfo* result) {
554   DCHECK_NE(STATE_NONE, current_state_);
555 
556   if (current_state_ != STATE_READY)
557     return ERR_IO_PENDING;  // Still initializing.
558 
559   DCHECK_NE(config_.id(), ProxyConfig::INVALID_ID);
560 
561   if (config_.HasAutomaticSettings())
562     return ERR_IO_PENDING;  // Must submit the request to the proxy resolver.
563 
564   // Use the manual proxy settings.
565   config_.proxy_rules().Apply(url, result);
566   result->config_id_ = config_.id();
567   return OK;
568 }
569 
~ProxyService()570 ProxyService::~ProxyService() {
571   NetworkChangeNotifier::RemoveIPAddressObserver(this);
572   config_service_->RemoveObserver(this);
573 
574   // Cancel any inprogress requests.
575   for (PendingRequests::iterator it = pending_requests_.begin();
576        it != pending_requests_.end();
577        ++it) {
578     (*it)->Cancel();
579   }
580 }
581 
SuspendAllPendingRequests()582 void ProxyService::SuspendAllPendingRequests() {
583   for (PendingRequests::iterator it = pending_requests_.begin();
584        it != pending_requests_.end();
585        ++it) {
586     PacRequest* req = it->get();
587     if (req->is_started()) {
588       req->CancelResolveJob();
589 
590       req->net_log()->BeginEvent(
591           NetLog::TYPE_PROXY_SERVICE_WAITING_FOR_INIT_PAC, NULL);
592     }
593   }
594 }
595 
SetReady()596 void ProxyService::SetReady() {
597   DCHECK(!init_proxy_resolver_.get());
598   current_state_ = STATE_READY;
599 
600   // Make a copy in case |this| is deleted during the synchronous completion
601   // of one of the requests. If |this| is deleted then all of the PacRequest
602   // instances will be Cancel()-ed.
603   PendingRequests pending_copy = pending_requests_;
604 
605   for (PendingRequests::iterator it = pending_copy.begin();
606        it != pending_copy.end();
607        ++it) {
608     PacRequest* req = it->get();
609     if (!req->is_started() && !req->was_cancelled()) {
610       req->net_log()->EndEvent(NetLog::TYPE_PROXY_SERVICE_WAITING_FOR_INIT_PAC,
611                                NULL);
612 
613       // Note that we re-check for synchronous completion, in case we are
614       // no longer using a ProxyResolver (can happen if we fell-back to manual).
615       req->StartAndCompleteCheckingForSynchronous();
616     }
617   }
618 }
619 
ApplyProxyConfigIfAvailable()620 void ProxyService::ApplyProxyConfigIfAvailable() {
621   DCHECK_EQ(STATE_NONE, current_state_);
622 
623   config_service_->OnLazyPoll();
624 
625   // If we have already fetched the configuration, start applying it.
626   if (fetched_config_.is_valid()) {
627     InitializeUsingLastFetchedConfig();
628     return;
629   }
630 
631   // Otherwise we need to first fetch the configuration.
632   current_state_ = STATE_WAITING_FOR_PROXY_CONFIG;
633 
634   // Retrieve the current proxy configuration from the ProxyConfigService.
635   // If a configuration is not available yet, we will get called back later
636   // by our ProxyConfigService::Observer once it changes.
637   ProxyConfig config;
638   ProxyConfigService::ConfigAvailability availability =
639       config_service_->GetLatestProxyConfig(&config);
640   if (availability != ProxyConfigService::CONFIG_PENDING)
641     OnProxyConfigChanged(config, availability);
642 }
643 
OnInitProxyResolverComplete(int result)644 void ProxyService::OnInitProxyResolverComplete(int result) {
645   DCHECK_EQ(STATE_WAITING_FOR_INIT_PROXY_RESOLVER, current_state_);
646   DCHECK(init_proxy_resolver_.get());
647   DCHECK(fetched_config_.HasAutomaticSettings());
648   init_proxy_resolver_.reset();
649 
650   if (result != OK) {
651     VLOG(1) << "Failed configuring with PAC script, falling-back to manual "
652                "proxy servers.";
653     config_ = fetched_config_;
654     config_.ClearAutomaticSettings();
655   }
656 
657   config_.set_id(fetched_config_.id());
658 
659   // Resume any requests which we had to defer until the PAC script was
660   // downloaded.
661   SetReady();
662 }
663 
ReconsiderProxyAfterError(const GURL & url,ProxyInfo * result,CompletionCallback * callback,PacRequest ** pac_request,const BoundNetLog & net_log)664 int ProxyService::ReconsiderProxyAfterError(const GURL& url,
665                                             ProxyInfo* result,
666                                             CompletionCallback* callback,
667                                             PacRequest** pac_request,
668                                             const BoundNetLog& net_log) {
669   DCHECK(CalledOnValidThread());
670 
671   // Check to see if we have a new config since ResolveProxy was called.  We
672   // want to re-run ResolveProxy in two cases: 1) we have a new config, or 2) a
673   // direct connection failed and we never tried the current config.
674 
675   bool re_resolve = result->config_id_ != config_.id();
676 
677   if (re_resolve) {
678     // If we have a new config or the config was never tried, we delete the
679     // list of bad proxies and we try again.
680     proxy_retry_info_.clear();
681     return ResolveProxy(url, result, callback, pac_request, net_log);
682   }
683 
684   // We don't have new proxy settings to try, try to fallback to the next proxy
685   // in the list.
686   bool did_fallback = result->Fallback(&proxy_retry_info_);
687 
688   // Return synchronous failure if there is nothing left to fall-back to.
689   // TODO(eroman): This is a yucky API, clean it up.
690   return did_fallback ? OK : ERR_FAILED;
691 }
692 
CancelPacRequest(PacRequest * req)693 void ProxyService::CancelPacRequest(PacRequest* req) {
694   DCHECK(CalledOnValidThread());
695   DCHECK(req);
696   req->Cancel();
697   RemovePendingRequest(req);
698 }
699 
ContainsPendingRequest(PacRequest * req)700 bool ProxyService::ContainsPendingRequest(PacRequest* req) {
701   PendingRequests::iterator it = std::find(
702       pending_requests_.begin(), pending_requests_.end(), req);
703   return pending_requests_.end() != it;
704 }
705 
RemovePendingRequest(PacRequest * req)706 void ProxyService::RemovePendingRequest(PacRequest* req) {
707   DCHECK(ContainsPendingRequest(req));
708   PendingRequests::iterator it = std::find(
709       pending_requests_.begin(), pending_requests_.end(), req);
710   pending_requests_.erase(it);
711 }
712 
DidFinishResolvingProxy(ProxyInfo * result,int result_code,const BoundNetLog & net_log)713 int ProxyService::DidFinishResolvingProxy(ProxyInfo* result,
714                                           int result_code,
715                                           const BoundNetLog& net_log) {
716   // Log the result of the proxy resolution.
717   if (result_code == OK) {
718     // When logging all events is enabled, dump the proxy list.
719     if (net_log.IsLoggingAllEvents()) {
720       net_log.AddEvent(
721           NetLog::TYPE_PROXY_SERVICE_RESOLVED_PROXY_LIST,
722           make_scoped_refptr(new NetLogStringParameter(
723               "pac_string", result->ToPacString())));
724     }
725     result->DeprioritizeBadProxies(proxy_retry_info_);
726   } else {
727     net_log.AddEvent(
728         NetLog::TYPE_PROXY_SERVICE_RESOLVED_PROXY_LIST,
729         make_scoped_refptr(new NetLogIntegerParameter(
730             "net_error", result_code)));
731 
732     // Fall-back to direct when the proxy resolver fails. This corresponds
733     // with a javascript runtime error in the PAC script.
734     //
735     // This implicit fall-back to direct matches Firefox 3.5 and
736     // Internet Explorer 8. For more information, see:
737     //
738     // http://www.chromium.org/developers/design-documents/proxy-settings-fallback
739     result->UseDirect();
740     result_code = OK;
741   }
742 
743   net_log.EndEvent(NetLog::TYPE_PROXY_SERVICE, NULL);
744   return result_code;
745 }
746 
SetProxyScriptFetcher(ProxyScriptFetcher * proxy_script_fetcher)747 void ProxyService::SetProxyScriptFetcher(
748     ProxyScriptFetcher* proxy_script_fetcher) {
749   DCHECK(CalledOnValidThread());
750   State previous_state = ResetProxyConfig(false);
751   proxy_script_fetcher_.reset(proxy_script_fetcher);
752   if (previous_state != STATE_NONE)
753     ApplyProxyConfigIfAvailable();
754 }
755 
GetProxyScriptFetcher() const756 ProxyScriptFetcher* ProxyService::GetProxyScriptFetcher() const {
757   DCHECK(CalledOnValidThread());
758   return proxy_script_fetcher_.get();
759 }
760 
ResetProxyConfig(bool reset_fetched_config)761 ProxyService::State ProxyService::ResetProxyConfig(bool reset_fetched_config) {
762   DCHECK(CalledOnValidThread());
763   State previous_state = current_state_;
764 
765   proxy_retry_info_.clear();
766   init_proxy_resolver_.reset();
767   SuspendAllPendingRequests();
768   config_ = ProxyConfig();
769   if (reset_fetched_config)
770     fetched_config_ = ProxyConfig();
771   current_state_ = STATE_NONE;
772 
773   return previous_state;
774 }
775 
ResetConfigService(ProxyConfigService * new_proxy_config_service)776 void ProxyService::ResetConfigService(
777     ProxyConfigService* new_proxy_config_service) {
778   DCHECK(CalledOnValidThread());
779   State previous_state = ResetProxyConfig(true);
780 
781   // Release the old configuration service.
782   if (config_service_.get())
783     config_service_->RemoveObserver(this);
784 
785   // Set the new configuration service.
786   config_service_.reset(new_proxy_config_service);
787   config_service_->AddObserver(this);
788 
789   if (previous_state != STATE_NONE)
790     ApplyProxyConfigIfAvailable();
791 }
792 
PurgeMemory()793 void ProxyService::PurgeMemory() {
794   DCHECK(CalledOnValidThread());
795   if (resolver_.get())
796     resolver_->PurgeMemory();
797 }
798 
ForceReloadProxyConfig()799 void ProxyService::ForceReloadProxyConfig() {
800   DCHECK(CalledOnValidThread());
801   ResetProxyConfig(false);
802   ApplyProxyConfigIfAvailable();
803 }
804 
805 // static
CreateSystemProxyConfigService(MessageLoop * io_loop,MessageLoop * file_loop)806 ProxyConfigService* ProxyService::CreateSystemProxyConfigService(
807     MessageLoop* io_loop, MessageLoop* file_loop) {
808 #if defined(OS_WIN)
809   return new ProxyConfigServiceWin();
810 #elif defined(OS_MACOSX)
811   return new ProxyConfigServiceMac(io_loop);
812 #elif defined(OS_CHROMEOS)
813   NOTREACHED() << "ProxyConfigService for ChromeOS should be created in "
814                << "profile_io_data.cc::CreateProxyConfigService.";
815   return NULL;
816 #elif defined(ANDROID)
817   NOTREACHED() << "ProxyConfigService for Android should be created in "
818                << "WebCache.cpp: WebCache::WebCache";
819   return NULL;
820 #elif defined(OS_LINUX)
821   ProxyConfigServiceLinux* linux_config_service =
822       new ProxyConfigServiceLinux();
823 
824   // Assume we got called from the UI loop, which runs the default
825   // glib main loop, so the current thread is where we should be
826   // running gconf calls from.
827   MessageLoop* glib_default_loop = MessageLoopForUI::current();
828 
829   // The file loop should be a MessageLoopForIO on Linux.
830   DCHECK_EQ(MessageLoop::TYPE_IO, file_loop->type());
831 
832   // Synchronously fetch the current proxy config (since we are
833   // running on glib_default_loop). Additionally register for
834   // notifications (delivered in either |glib_default_loop| or
835   // |file_loop|) to keep us updated when the proxy config changes.
836   linux_config_service->SetupAndFetchInitialConfig(glib_default_loop, io_loop,
837       static_cast<MessageLoopForIO*>(file_loop));
838 
839   return linux_config_service;
840 #else
841   LOG(WARNING) << "Failed to choose a system proxy settings fetcher "
842                   "for this platform.";
843   return new ProxyConfigServiceNull();
844 #endif
845 }
846 
OnProxyConfigChanged(const ProxyConfig & config,ProxyConfigService::ConfigAvailability availability)847 void ProxyService::OnProxyConfigChanged(
848     const ProxyConfig& config,
849     ProxyConfigService::ConfigAvailability availability) {
850   // Retrieve the current proxy configuration from the ProxyConfigService.
851   // If a configuration is not available yet, we will get called back later
852   // by our ProxyConfigService::Observer once it changes.
853   ProxyConfig effective_config;
854   switch (availability) {
855     case ProxyConfigService::CONFIG_PENDING:
856       // ProxyConfigService implementors should never pass CONFIG_PENDING.
857       NOTREACHED() << "Proxy config change with CONFIG_PENDING availability!";
858       return;
859     case ProxyConfigService::CONFIG_VALID:
860       effective_config = config;
861       break;
862     case ProxyConfigService::CONFIG_UNSET:
863       effective_config = ProxyConfig::CreateDirect();
864       break;
865   }
866 
867   // Emit the proxy settings change to the NetLog stream.
868   if (net_log_) {
869     scoped_refptr<NetLog::EventParameters> params(
870         new ProxyConfigChangedNetLogParam(fetched_config_, effective_config));
871     net_log_->AddEntry(net::NetLog::TYPE_PROXY_CONFIG_CHANGED,
872                        base::TimeTicks::Now(),
873                        NetLog::Source(),
874                        NetLog::PHASE_NONE,
875                        params);
876   }
877 
878   // Set the new configuration as the most recently fetched one.
879   fetched_config_ = effective_config;
880   fetched_config_.set_id(1);  // Needed for a later DCHECK of is_valid().
881 
882   InitializeUsingLastFetchedConfig();
883 }
884 
InitializeUsingLastFetchedConfig()885 void ProxyService::InitializeUsingLastFetchedConfig() {
886   ResetProxyConfig(false);
887 
888   DCHECK(fetched_config_.is_valid());
889 
890   // Increment the ID to reflect that the config has changed.
891   fetched_config_.set_id(next_config_id_++);
892 
893   if (!fetched_config_.HasAutomaticSettings()) {
894     config_ = fetched_config_;
895     SetReady();
896     return;
897   }
898 
899   // Start downloading + testing the PAC scripts for this new configuration.
900   current_state_ = STATE_WAITING_FOR_INIT_PROXY_RESOLVER;
901 
902   init_proxy_resolver_.reset(
903       new InitProxyResolver(resolver_.get(), proxy_script_fetcher_.get(),
904                             net_log_));
905 
906   // If we changed networks recently, we should delay running proxy auto-config.
907   base::TimeDelta wait_delay =
908       stall_proxy_autoconfig_until_ - base::TimeTicks::Now();
909 
910   int rv = init_proxy_resolver_->Init(
911       fetched_config_, wait_delay, &config_, &init_proxy_resolver_callback_);
912 
913   if (rv != ERR_IO_PENDING)
914     OnInitProxyResolverComplete(rv);
915 }
916 
OnIPAddressChanged()917 void ProxyService::OnIPAddressChanged() {
918   // See the comment block by |kNumMillisToStallAfterNetworkChanges| for info.
919   stall_proxy_autoconfig_until_ =
920       base::TimeTicks::Now() + stall_proxy_auto_config_delay_;
921 
922   State previous_state = ResetProxyConfig(false);
923   if (previous_state != STATE_NONE)
924     ApplyProxyConfigIfAvailable();
925 }
926 
SyncProxyServiceHelper(MessageLoop * io_message_loop,ProxyService * proxy_service)927 SyncProxyServiceHelper::SyncProxyServiceHelper(MessageLoop* io_message_loop,
928                                                ProxyService* proxy_service)
929     : io_message_loop_(io_message_loop),
930       proxy_service_(proxy_service),
931       event_(false, false),
932       ALLOW_THIS_IN_INITIALIZER_LIST(callback_(
933           this, &SyncProxyServiceHelper::OnCompletion)) {
934   DCHECK(io_message_loop_ != MessageLoop::current());
935 }
936 
ResolveProxy(const GURL & url,ProxyInfo * proxy_info,const BoundNetLog & net_log)937 int SyncProxyServiceHelper::ResolveProxy(const GURL& url,
938                                          ProxyInfo* proxy_info,
939                                          const BoundNetLog& net_log) {
940   DCHECK(io_message_loop_ != MessageLoop::current());
941 
942   io_message_loop_->PostTask(FROM_HERE, NewRunnableMethod(
943       this, &SyncProxyServiceHelper::StartAsyncResolve, url, net_log));
944 
945   event_.Wait();
946 
947   if (result_ == net::OK) {
948     *proxy_info = proxy_info_;
949   }
950   return result_;
951 }
952 
ReconsiderProxyAfterError(const GURL & url,ProxyInfo * proxy_info,const BoundNetLog & net_log)953 int SyncProxyServiceHelper::ReconsiderProxyAfterError(
954     const GURL& url, ProxyInfo* proxy_info, const BoundNetLog& net_log) {
955   DCHECK(io_message_loop_ != MessageLoop::current());
956 
957   io_message_loop_->PostTask(FROM_HERE, NewRunnableMethod(
958       this, &SyncProxyServiceHelper::StartAsyncReconsider, url, net_log));
959 
960   event_.Wait();
961 
962   if (result_ == net::OK) {
963     *proxy_info = proxy_info_;
964   }
965   return result_;
966 }
967 
~SyncProxyServiceHelper()968 SyncProxyServiceHelper::~SyncProxyServiceHelper() {}
969 
StartAsyncResolve(const GURL & url,const BoundNetLog & net_log)970 void SyncProxyServiceHelper::StartAsyncResolve(const GURL& url,
971                                                const BoundNetLog& net_log) {
972   result_ = proxy_service_->ResolveProxy(
973       url, &proxy_info_, &callback_, NULL, net_log);
974   if (result_ != net::ERR_IO_PENDING) {
975     OnCompletion(result_);
976   }
977 }
978 
StartAsyncReconsider(const GURL & url,const BoundNetLog & net_log)979 void SyncProxyServiceHelper::StartAsyncReconsider(const GURL& url,
980                                                   const BoundNetLog& net_log) {
981   result_ = proxy_service_->ReconsiderProxyAfterError(
982       url, &proxy_info_, &callback_, NULL, net_log);
983   if (result_ != net::ERR_IO_PENDING) {
984     OnCompletion(result_);
985   }
986 }
987 
OnCompletion(int rv)988 void SyncProxyServiceHelper::OnCompletion(int rv) {
989   result_ = rv;
990   event_.Signal();
991 }
992 
993 }  // namespace net
994