Home | History | Annotate | Download | only in proxy
      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 #ifndef NET_PROXY_MULTI_THREADED_PROXY_RESOLVER_H_
      6 #define NET_PROXY_MULTI_THREADED_PROXY_RESOLVER_H_
      7 #pragma once
      8 
      9 #include <deque>
     10 #include <vector>
     11 
     12 #include "base/basictypes.h"
     13 #include "base/memory/ref_counted.h"
     14 #include "base/memory/scoped_ptr.h"
     15 #include "base/threading/non_thread_safe.h"
     16 #include "net/proxy/proxy_resolver.h"
     17 
     18 namespace base {
     19 class Thread;
     20 }  // namespace base
     21 
     22 namespace net {
     23 
     24 // ProxyResolverFactory is an interface for creating ProxyResolver instances.
     25 class ProxyResolverFactory {
     26  public:
     27   explicit ProxyResolverFactory(bool resolvers_expect_pac_bytes)
     28       : resolvers_expect_pac_bytes_(resolvers_expect_pac_bytes) {}
     29 
     30   virtual ~ProxyResolverFactory() {}
     31 
     32   // Creates a new ProxyResolver. The caller is responsible for freeing this
     33   // object.
     34   virtual ProxyResolver* CreateProxyResolver() = 0;
     35 
     36   bool resolvers_expect_pac_bytes() const {
     37     return resolvers_expect_pac_bytes_;
     38   }
     39 
     40  private:
     41   bool resolvers_expect_pac_bytes_;
     42   DISALLOW_COPY_AND_ASSIGN(ProxyResolverFactory);
     43 };
     44 
     45 // MultiThreadedProxyResolver is a ProxyResolver implementation that runs
     46 // synchronous ProxyResolver implementations on worker threads.
     47 //
     48 // Threads are created lazily on demand, up to a maximum total. The advantage
     49 // of having a pool of threads, is faster performance. In particular, being
     50 // able to keep servicing PAC requests even if one blocks its execution.
     51 //
     52 // During initialization (SetPacScript), a single thread is spun up to test
     53 // the script. If this succeeds, we cache the input script, and will re-use
     54 // this to lazily provision any new threads as needed.
     55 //
     56 // For each new thread that we spawn, a corresponding new ProxyResolver is
     57 // created using ProxyResolverFactory.
     58 //
     59 // Because we are creating multiple ProxyResolver instances, this means we
     60 // are duplicating script contexts for what is ordinarily seen as being a
     61 // single script. This can affect compatibility on some classes of PAC
     62 // script:
     63 //
     64 // (a) Scripts whose initialization has external dependencies on network or
     65 //     time may end up successfully initializing on some threads, but not
     66 //     others. So depending on what thread services the request, the result
     67 //     may jump between several possibilities.
     68 //
     69 // (b) Scripts whose FindProxyForURL() depends on side-effects may now
     70 //     work differently. For example, a PAC script which was incrementing
     71 //     a global counter and using that to make a decision. In the
     72 //     multi-threaded model, each thread may have a different value for this
     73 //     counter, so it won't globally be seen as monotonically increasing!
     74 class MultiThreadedProxyResolver : public ProxyResolver,
     75                                    public base::NonThreadSafe {
     76  public:
     77   // Creates an asynchronous ProxyResolver that runs requests on up to
     78   // |max_num_threads|.
     79   //
     80   // For each thread that is created, an accompanying synchronous ProxyResolver
     81   // will be provisioned using |resolver_factory|. All methods on these
     82   // ProxyResolvers will be called on the one thread, with the exception of
     83   // ProxyResolver::Shutdown() which will be called from the origin thread
     84   // prior to destruction.
     85   //
     86   // The constructor takes ownership of |resolver_factory|.
     87   MultiThreadedProxyResolver(ProxyResolverFactory* resolver_factory,
     88                              size_t max_num_threads);
     89 
     90   virtual ~MultiThreadedProxyResolver();
     91 
     92   // ProxyResolver implementation:
     93   virtual int GetProxyForURL(const GURL& url,
     94                              ProxyInfo* results,
     95                              CompletionCallback* callback,
     96                              RequestHandle* request,
     97                              const BoundNetLog& net_log);
     98   virtual void CancelRequest(RequestHandle request);
     99   virtual void CancelSetPacScript();
    100   virtual void PurgeMemory();
    101   virtual int SetPacScript(
    102       const scoped_refptr<ProxyResolverScriptData>& script_data,
    103       CompletionCallback* callback);
    104 
    105  private:
    106   class Executor;
    107   class Job;
    108   class SetPacScriptJob;
    109   class GetProxyForURLJob;
    110   // FIFO queue of pending jobs waiting to be started.
    111   // TODO(eroman): Make this priority queue.
    112   typedef std::deque<scoped_refptr<Job> > PendingJobsQueue;
    113   typedef std::vector<scoped_refptr<Executor> > ExecutorList;
    114 
    115   // Asserts that there are no outstanding user-initiated jobs on any of the
    116   // worker threads.
    117   void CheckNoOutstandingUserRequests() const;
    118 
    119   // Stops and deletes all of the worker threads.
    120   void ReleaseAllExecutors();
    121 
    122   // Returns an idle worker thread which is ready to receive GetProxyForURL()
    123   // requests. If all threads are occupied, returns NULL.
    124   Executor* FindIdleExecutor();
    125 
    126   // Creates a new worker thread, and appends it to |executors_|.
    127   Executor* AddNewExecutor();
    128 
    129   // Starts the next job from |pending_jobs_| if possible.
    130   void OnExecutorReady(Executor* executor);
    131 
    132   const scoped_ptr<ProxyResolverFactory> resolver_factory_;
    133   const size_t max_num_threads_;
    134   PendingJobsQueue pending_jobs_;
    135   ExecutorList executors_;
    136   scoped_refptr<ProxyResolverScriptData> current_script_data_;
    137 };
    138 
    139 }  // namespace net
    140 
    141 #endif  // NET_PROXY_MULTI_THREADED_PROXY_RESOLVER_H_
    142