/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim:set ts=2 sw=2 sts=2 et cindent: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef nsPACMan_h__ #define nsPACMan_h__ #include "nsIStreamLoader.h" #include "nsIInterfaceRequestor.h" #include "nsIChannelEventSink.h" #include "ProxyAutoConfig.h" #include "nsThreadUtils.h" #include "nsIURI.h" #include "nsCOMPtr.h" #include "nsString.h" #include "mozilla/Attributes.h" #include "mozilla/LinkedList.h" #include "nsAutoPtr.h" #include "mozilla/TimeStamp.h" #include "mozilla/Logging.h" #include "mozilla/Atomics.h" class nsISystemProxySettings; class nsIThread; namespace mozilla { namespace net { class nsPACMan; class WaitForThreadShutdown; /** * This class defines a callback interface used by AsyncGetProxyForURI. */ class NS_NO_VTABLE nsPACManCallback : public nsISupports { public: /** * This method is invoked on the same thread that called AsyncGetProxyForURI. * * @param status * This parameter indicates whether or not the PAC query succeeded. * @param pacString * This parameter holds the value of the PAC string. It is empty when * status is a failure code. * @param newPACURL * This parameter holds the URL of a new PAC file that should be loaded * before the query is evaluated again. At least one of pacString and * newPACURL should be 0 length. */ virtual void OnQueryComplete(nsresult status, const nsCString &pacString, const nsCString &newPACURL) = 0; }; class PendingPACQuery final : public Runnable, public LinkedListElement<PendingPACQuery> { public: PendingPACQuery(nsPACMan *pacMan, nsIURI *uri, nsPACManCallback *callback, bool mainThreadResponse); // can be called from either thread void Complete(nsresult status, const nsCString &pacString); void UseAlternatePACFile(const nsCString &pacURL); nsCString mSpec; nsCString mScheme; nsCString mHost; int32_t mPort; NS_IMETHOD Run(void); /* Runnable */ private: nsPACMan *mPACMan; // weak reference private: RefPtr<nsPACManCallback> mCallback; bool mOnMainThreadOnly; }; /** * This class provides an abstraction layer above the PAC thread. The methods * defined on this class are intended to be called on the main thread only. */ class nsPACMan final : public nsIStreamLoaderObserver , public nsIInterfaceRequestor , public nsIChannelEventSink { public: NS_DECL_THREADSAFE_ISUPPORTS nsPACMan(); /** * This method may be called to shutdown the PAC manager. Any async queries * that have not yet completed will either finish normally or be canceled by * the time this method returns. */ void Shutdown(); /** * This method queries a PAC result asynchronously. The callback runs on the * calling thread. If the PAC file has not yet been loaded, then this method * will queue up the request, and complete it once the PAC file has been * loaded. * * @param uri * The URI to query. * @param callback * The callback to run once the PAC result is available. * @param mustCallbackOnMainThread * If set to false the callback can be made from the PAC thread */ nsresult AsyncGetProxyForURI(nsIURI *uri, nsPACManCallback *callback, bool mustCallbackOnMainThread); /** * This method may be called to reload the PAC file. While we are loading * the PAC file, any asynchronous PAC queries will be queued up to be * processed once the PAC file finishes loading. * * @param pacSpec * The non normalized uri spec of this URI used for comparison with * system proxy settings to determine if the PAC uri has changed. */ nsresult LoadPACFromURI(const nsCString &pacSpec); /** * Returns true if we are currently loading the PAC file. */ bool IsLoading() { return mLoader != nullptr; } /** * Returns true if the given URI matches the URI of our PAC file or the * URI it has been redirected to. In the case of a chain of redirections * only the current one being followed and the original are considered * becuase this information is used, respectively, to determine if we * should bypass the proxy (to fetch the pac file) or if the pac * configuration has changed (and we should reload the pac file) */ bool IsPACURI(const nsACString &spec) { return mPACURISpec.Equals(spec) || mPACURIRedirectSpec.Equals(spec) || mNormalPACURISpec.Equals(spec); } bool IsPACURI(nsIURI *uri) { if (mPACURISpec.IsEmpty() && mPACURIRedirectSpec.IsEmpty()) { return false; } nsAutoCString tmp; nsresult rv = uri->GetSpec(tmp); if (NS_FAILED(rv)) { return false; } return IsPACURI(tmp); } nsresult Init(nsISystemProxySettings *); static nsPACMan *sInstance; // PAC thread operations only void ProcessPendingQ(); void CancelPendingQ(nsresult); private: NS_DECL_NSISTREAMLOADEROBSERVER NS_DECL_NSIINTERFACEREQUESTOR NS_DECL_NSICHANNELEVENTSINK friend class PendingPACQuery; friend class PACLoadComplete; friend class ExecutePACThreadAction; friend class WaitForThreadShutdown; ~nsPACMan(); /** * Cancel any existing load if any. */ void CancelExistingLoad(); /** * Start loading the PAC file. */ void StartLoading(); /** * Reload the PAC file if there is reason to. */ void MaybeReloadPAC(); /** * Called when we fail to load the PAC file. */ void OnLoadFailure(); /** * PostQuery() only runs on the PAC thread and it is used to * place a pendingPACQuery into the queue and potentially * execute the queue if it was otherwise empty */ nsresult PostQuery(PendingPACQuery *query); // PAC thread operations only void PostProcessPendingQ(); void PostCancelPendingQ(nsresult); bool ProcessPending(); void NamePACThread(); private: ProxyAutoConfig mPAC; nsCOMPtr<nsIThread> mPACThread; nsCOMPtr<nsISystemProxySettings> mSystemProxySettings; LinkedList<PendingPACQuery> mPendingQ; /* pac thread only */ // These specs are not nsIURI so that they can be used off the main thread. // The non-normalized versions are directly from the configuration, the // normalized version has been extracted from an nsIURI nsCString mPACURISpec; nsCString mPACURIRedirectSpec; nsCString mNormalPACURISpec; nsCOMPtr<nsIStreamLoader> mLoader; bool mLoadPending; Atomic<bool, Relaxed> mShutdown; TimeStamp mScheduledReload; uint32_t mLoadFailureCount; bool mInProgress; bool mIncludePath; }; extern LazyLogModule gProxyLog; } // namespace net } // namespace mozilla #endif // nsPACMan_h__