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/. */
10 #include "mozilla/Atomics.h"
11 #include "mozilla/Attributes.h"
12 #include "mozilla/DataMutex.h"
13 #include "mozilla/LinkedList.h"
14 #include "mozilla/Logging.h"
15 #include "mozilla/net/NeckoTargetHolder.h"
16 #include "mozilla/TimeStamp.h"
18 #include "nsIChannelEventSink.h"
19 #include "nsIInterfaceRequestor.h"
20 #include "nsIStreamLoader.h"
21 #include "nsThreadUtils.h"
24 #include "ProxyAutoConfig.h"
26 class nsISystemProxySettings
;
34 class WaitForThreadShutdown
;
37 * This class defines a callback interface used by AsyncGetProxyForURI.
39 class NS_NO_VTABLE nsPACManCallback
: public nsISupports
{
42 * This method is invoked on the same thread that called AsyncGetProxyForURI.
45 * This parameter indicates whether or not the PAC query succeeded.
47 * This parameter holds the value of the PAC string. It is empty when
48 * status is a failure code.
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.
54 virtual void OnQueryComplete(nsresult status
, const nsACString
& pacString
,
55 const nsACString
& newPACURL
) = 0;
58 class PendingPACQuery final
: public Runnable
,
59 public LinkedListElement
<PendingPACQuery
> {
61 PendingPACQuery(nsPACMan
* pacMan
, nsIURI
* uri
, nsPACManCallback
* callback
,
62 uint32_t flags
, bool mainThreadResponse
);
64 // can be called from either thread
65 void Complete(nsresult status
, const nsACString
& pacString
);
66 void UseAlternatePACFile(const nsACString
& pacURL
);
74 NS_IMETHOD
Run(void) override
; /* Runnable */
77 nsPACMan
* mPACMan
; // weak reference
80 RefPtr
<nsPACManCallback
> mCallback
;
81 bool mOnMainThreadOnly
;
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.
89 class nsPACMan final
: public nsIStreamLoaderObserver
,
90 public nsIInterfaceRequestor
,
91 public nsIChannelEventSink
,
92 public NeckoTargetHolder
{
94 NS_DECL_THREADSAFE_ISUPPORTS
96 explicit nsPACMan(nsISerialEventTarget
* mainThreadEventTarget
);
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.
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
114 * The callback to run once the PAC result is available.
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
121 nsresult
AsyncGetProxyForURI(nsIURI
* uri
, nsPACManCallback
* callback
,
122 uint32_t flags
, bool mainThreadResponse
);
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.
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.
133 nsresult
LoadPACFromURI(const nsACString
& aSpec
);
136 * Returns true if we are currently loading the PAC file.
139 auto loader
= mLoader
.Lock();
140 return loader
.ref() != nullptr;
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)
151 bool IsPACURI(const nsACString
& spec
) {
152 return mPACURISpec
.Equals(spec
) || mPACURIRedirectSpec
.Equals(spec
) ||
153 mNormalPACURISpec
.Equals(spec
);
156 bool IsPACURI(nsIURI
* uri
) {
157 if (mPACURISpec
.IsEmpty() && mPACURIRedirectSpec
.IsEmpty()) {
162 nsresult rv
= uri
->GetSpec(tmp
);
167 return IsPACURI(tmp
);
170 bool IsUsingWPAD() { return mAutoDetect
; }
172 nsresult
Init(nsISystemProxySettings
*);
173 static nsPACMan
* sInstance
;
175 // PAC thread operations only
176 void ProcessPendingQ();
177 void CancelPendingQ(nsresult
, bool aShutdown
);
179 void SetWPADOverDHCPEnabled(bool aValue
) { mWPADOverDHCPEnabled
= aValue
; }
182 NS_DECL_NSISTREAMLOADEROBSERVER
183 NS_DECL_NSIINTERFACEREQUESTOR
184 NS_DECL_NSICHANNELEVENTSINK
186 friend class PendingPACQuery
;
187 friend class PACLoadComplete
;
188 friend class ConfigureWPADComplete
;
189 friend class ExecutePACThreadAction
;
190 friend class WaitForThreadShutdown
;
191 friend class TestPACMan
;
196 * Cancel any existing load if any.
198 void CancelExistingLoad();
201 * Start loading the PAC file.
206 * Continue loading the PAC file.
208 void ContinueLoadingAfterPACUriKnown();
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.
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.
222 nsresult
LoadPACFromURI(const nsACString
& aSpec
, bool aResetLoadFailureCount
);
225 * Reload the PAC file if there is reason to.
227 void MaybeReloadPAC();
230 * Called when we fail to load the PAC file.
232 void OnLoadFailure();
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
239 nsresult
PostQuery(PendingPACQuery
* query
);
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
);
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
);
254 * Dispatches a runnable to the PAC processing thread. Handles lazy
255 * instantiation of the thread.
257 * @param aEvent The event to disptach.
258 * @param aSync Whether or not this should be synchronous dispatch.
260 nsresult
DispatchToPAC(already_AddRefed
<nsIRunnable
> aEvent
,
263 UniquePtr
<ProxyAutoConfigBase
> mPAC
;
264 nsCOMPtr
<nsIThread
> mPACThread
;
265 nsCOMPtr
<nsISystemProxySettings
> mSystemProxySettings
;
266 nsCOMPtr
<nsIDHCPClient
> mDHCPClient
;
268 LinkedList
<PendingPACQuery
> mPendingQ
; /* pac thread only */
270 // These specs are not nsIURI so that they can be used off the main thread.
271 // The non-normalized versions are directly from the configuration, the
272 // normalized version has been extracted from an nsIURI
273 nsCString mPACURISpec
;
274 nsCString mPACURIRedirectSpec
;
275 nsCString mNormalPACURISpec
;
277 DataMutex
<nsCOMPtr
<nsIStreamLoader
>> mLoader
;
279 Atomic
<bool, Relaxed
> mShutdown
;
280 TimeStamp mScheduledReload
;
281 Atomic
<uint32_t, Relaxed
> mLoadFailureCount
;
286 bool mWPADOverDHCPEnabled
;
287 int32_t mProxyConfigType
;
290 extern LazyLogModule gProxyLog
;
293 } // namespace mozilla
295 #endif // nsPACMan_h__