tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

nsPACMan.h (9194B)


      1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim:set ts=2 sw=2 sts=2 et cindent: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #ifndef nsPACMan_h__
      8 #define nsPACMan_h__
      9 
     10 #include "mozilla/Atomics.h"
     11 #include "mozilla/DataMutex.h"
     12 #include "mozilla/Monitor.h"
     13 #include "mozilla/LinkedList.h"
     14 #include "mozilla/Logging.h"
     15 #include "mozilla/net/NeckoTargetHolder.h"
     16 #include "mozilla/TimeStamp.h"
     17 #include "nsCOMPtr.h"
     18 #include "nsIChannelEventSink.h"
     19 #include "nsIInterfaceRequestor.h"
     20 #include "nsIStreamLoader.h"
     21 #include "nsThreadUtils.h"
     22 #include "nsIURI.h"
     23 #include "nsString.h"
     24 #include "ProxyAutoConfig.h"
     25 
     26 class nsISystemProxySettings;
     27 class nsIDHCPClient;
     28 class nsIThread;
     29 
     30 namespace mozilla {
     31 namespace net {
     32 
     33 class nsPACMan;
     34 class WaitForThreadShutdown;
     35 
     36 /**
     37 * This class defines a callback interface used by AsyncGetProxyForURI.
     38 */
     39 class NS_NO_VTABLE nsPACManCallback : public nsISupports {
     40 public:
     41  /**
     42   * This method is invoked on the same thread that called AsyncGetProxyForURI.
     43   *
     44   * @param status
     45   *        This parameter indicates whether or not the PAC query succeeded.
     46   * @param pacString
     47   *        This parameter holds the value of the PAC string.  It is empty when
     48   *        status is a failure code.
     49   * @param newPACURL
     50   *        This parameter holds the URL of a new PAC file that should be loaded
     51   *        before the query is evaluated again. At least one of pacString and
     52   *        newPACURL should be 0 length.
     53   */
     54  virtual void OnQueryComplete(nsresult status, const nsACString& pacString,
     55                               const nsACString& newPACURL) = 0;
     56 };
     57 
     58 class PendingPACQuery final : public Runnable,
     59                              public LinkedListElement<PendingPACQuery> {
     60 public:
     61  PendingPACQuery(nsPACMan* pacMan, nsIURI* uri, nsPACManCallback* callback,
     62                  uint32_t flags, bool mainThreadResponse);
     63 
     64  // can be called from either thread
     65  void Complete(nsresult status, const nsACString& pacString);
     66  void UseAlternatePACFile(const nsACString& pacURL);
     67 
     68  nsCString mSpec;
     69  nsCString mScheme;
     70  nsCString mHost;
     71  int32_t mPort;
     72  uint32_t mFlags;
     73 
     74  NS_IMETHOD Run(void) override; /* Runnable */
     75 
     76 private:
     77  nsPACMan* mPACMan;  // weak reference
     78 
     79 private:
     80  RefPtr<nsPACManCallback> mCallback;
     81  bool mOnMainThreadOnly;
     82 };
     83 
     84 /**
     85 * This class provides an abstraction layer above the PAC thread.  The methods
     86 * defined on this class are intended to be called on the main thread only.
     87 */
     88 
     89 class nsPACMan final : public nsIStreamLoaderObserver,
     90                       public nsIInterfaceRequestor,
     91                       public nsIChannelEventSink,
     92                       public NeckoTargetHolder {
     93 public:
     94  NS_DECL_THREADSAFE_ISUPPORTS
     95 
     96  explicit nsPACMan(nsISerialEventTarget* mainThreadEventTarget);
     97 
     98  /**
     99   * This method may be called to shutdown the PAC manager.  Any async queries
    100   * that have not yet completed will either finish normally or be canceled by
    101   * the time this method returns.
    102   */
    103  void Shutdown();
    104 
    105  /**
    106   * This method queries a PAC result asynchronously.  The callback runs on the
    107   * calling thread.  If the PAC file has not yet been loaded, then this method
    108   * will queue up the request, and complete it once the PAC file has been
    109   * loaded.
    110   *
    111   * @param uri
    112   *        The URI to query.
    113   * @param callback
    114   *        The callback to run once the PAC result is available.
    115   * @param flags
    116   *        A bit-wise combination of the RESOLVE_ flags defined above.  Pass
    117   *        0 to specify the default behavior.
    118   * @param mustCallbackOnMainThread
    119   *        If set to false the callback can be made from the PAC thread
    120   */
    121  nsresult AsyncGetProxyForURI(nsIURI* uri, nsPACManCallback* callback,
    122                               uint32_t flags, bool mainThreadResponse);
    123 
    124  /**
    125   * This method may be called to reload the PAC file.  While we are loading
    126   * the PAC file, any asynchronous PAC queries will be queued up to be
    127   * processed once the PAC file finishes loading.
    128   *
    129   * @param aSpec
    130   *        The non normalized uri spec of this URI used for comparison with
    131   *        system proxy settings to determine if the PAC uri has changed.
    132   */
    133  nsresult LoadPACFromURI(const nsACString& aSpec);
    134 
    135  /**
    136   * Returns true if we are currently loading the PAC file.
    137   */
    138  bool IsLoading() {
    139    auto loader = mLoader.Lock();
    140    return loader.ref() != nullptr;
    141  }
    142 
    143  /**
    144   * Returns true if the given URI matches the URI of our PAC file or the
    145   * URI it has been redirected to. In the case of a chain of redirections
    146   * only the current one being followed and the original are considered
    147   * becuase this information is used, respectively, to determine if we
    148   * should bypass the proxy (to fetch the pac file) or if the pac
    149   * configuration has changed (and we should reload the pac file)
    150   */
    151  bool IsPACURI(const nsACString& spec) {
    152    return mPACURISpec.Equals(spec) || mPACURIRedirectSpec.Equals(spec) ||
    153           mNormalPACURISpec.Equals(spec);
    154  }
    155 
    156  bool IsPACURI(nsIURI* uri) {
    157    if (mPACURISpec.IsEmpty() && mPACURIRedirectSpec.IsEmpty()) {
    158      return false;
    159    }
    160 
    161    nsAutoCString tmp;
    162    nsresult rv = uri->GetSpec(tmp);
    163    if (NS_FAILED(rv)) {
    164      return false;
    165    }
    166 
    167    return IsPACURI(tmp);
    168  }
    169 
    170  bool IsUsingWPAD() { return mAutoDetect; }
    171 
    172  nsresult Init(nsISystemProxySettings*);
    173  static nsPACMan* sInstance;
    174 
    175  // PAC thread operations only
    176  void ProcessPendingQ();
    177  void CancelPendingQ(nsresult, bool aShutdown);
    178 
    179  void SetWPADOverDHCPEnabled(bool aValue) { mWPADOverDHCPEnabled = aValue; }
    180 
    181 private:
    182  NS_DECL_NSISTREAMLOADEROBSERVER
    183  NS_DECL_NSIINTERFACEREQUESTOR
    184  NS_DECL_NSICHANNELEVENTSINK
    185 
    186  friend class PendingPACQuery;
    187  friend class PACLoadComplete;
    188  friend class ConfigureWPADComplete;
    189  friend class ExecutePACThreadAction;
    190  friend class WaitForThreadShutdown;
    191  friend class TestPACMan;
    192 
    193  ~nsPACMan();
    194 
    195  /**
    196   * Cancel any existing load if any.
    197   */
    198  void CancelExistingLoad();
    199 
    200  /**
    201   * Start loading the PAC file.
    202   */
    203  void StartLoading();
    204 
    205  /**
    206   * Continue loading the PAC file.
    207   */
    208  void ContinueLoadingAfterPACUriKnown();
    209 
    210  /**
    211   * This method may be called to reload the PAC file.  While we are loading
    212   * the PAC file, any asynchronous PAC queries will be queued up to be
    213   * processed once the PAC file finishes loading.
    214   *
    215   * @param aSpec
    216   *        The non normalized uri spec of this URI used for comparison with
    217   *        system proxy settings to determine if the PAC uri has changed.
    218   * @param aResetLoadFailureCount
    219   *        A flag saying whether the exponential back-off for attempting to
    220   * reload the PAC should be reset.
    221   */
    222  nsresult LoadPACFromURI(const nsACString& aSpec, bool aResetLoadFailureCount);
    223 
    224  /**
    225   * Reload the PAC file if there is reason to.
    226   */
    227  void MaybeReloadPAC();
    228 
    229  /**
    230   * Called when we fail to load the PAC file.
    231   */
    232  void OnLoadFailure();
    233 
    234  /**
    235   * PostQuery() only runs on the PAC thread and it is used to
    236   * place a pendingPACQuery into the queue and potentially
    237   * execute the queue if it was otherwise empty
    238   */
    239  nsresult PostQuery(PendingPACQuery* query);
    240 
    241  // Having found the PAC URI on the PAC thread, copy it to a string which
    242  // can be altered on the main thread.
    243  void AssignPACURISpec(const nsACString& aSpec);
    244 
    245  // PAC thread operations only
    246  void PostProcessPendingQ();
    247  void PostCancelPendingQ(nsresult, bool aShutdown = false);
    248  bool ProcessPending();
    249  nsresult GetPACFromDHCP(nsACString& aSpec);
    250  nsresult ConfigureWPAD(nsACString& aSpec);
    251 
    252 private:
    253  /**
    254   * Dispatches a runnable to the PAC processing thread. Handles lazy
    255   * instantiation of the thread.
    256   *
    257   * @param aEvent The event to disptach.
    258   * @param aSync Whether or not this should be synchronous dispatch.
    259   */
    260  nsresult DispatchToPAC(already_AddRefed<nsIRunnable> aEvent,
    261                         bool aSync = false);
    262 
    263  UniquePtr<ProxyAutoConfigBase> mPAC;
    264  nsCOMPtr<nsIThread> mPACThread;
    265  nsCOMPtr<nsISystemProxySettings> mSystemProxySettings;
    266 
    267  nsCOMPtr<nsIDHCPClient> mDHCPClient;
    268  mozilla::Monitor mMonitor{"mDHCPMonitor"};
    269  nsCString mPACStringFromDHCP MOZ_GUARDED_BY(mMonitor);
    270 
    271  LinkedList<PendingPACQuery> mPendingQ; /* pac thread only */
    272 
    273  // These specs are not nsIURI so that they can be used off the main thread.
    274  // The non-normalized versions are directly from the configuration, the
    275  // normalized version has been extracted from an nsIURI
    276  nsCString mPACURISpec;
    277  nsCString mPACURIRedirectSpec;
    278  nsCString mNormalPACURISpec;
    279 
    280  DataMutex<nsCOMPtr<nsIStreamLoader>> mLoader;
    281  bool mLoadPending;
    282  Atomic<bool, Relaxed> mShutdown;
    283  TimeStamp mScheduledReload;
    284  Atomic<uint32_t, Relaxed> mLoadFailureCount;
    285 
    286  bool mInProgress;
    287  bool mIncludePath;
    288  bool mAutoDetect;
    289  bool mWPADOverDHCPEnabled;
    290  int32_t mProxyConfigType;
    291 };
    292 
    293 extern LazyLogModule gProxyLog;
    294 
    295 }  // namespace net
    296 }  // namespace mozilla
    297 
    298 #endif  // nsPACMan_h__