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__