Line data Source code
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 "nsIStreamLoader.h"
11 : #include "nsIInterfaceRequestor.h"
12 : #include "nsIChannelEventSink.h"
13 : #include "ProxyAutoConfig.h"
14 : #include "nsThreadUtils.h"
15 : #include "nsIURI.h"
16 : #include "nsCOMPtr.h"
17 : #include "nsString.h"
18 : #include "mozilla/Attributes.h"
19 : #include "mozilla/LinkedList.h"
20 : #include "nsAutoPtr.h"
21 : #include "mozilla/TimeStamp.h"
22 : #include "mozilla/Logging.h"
23 : #include "mozilla/Atomics.h"
24 : #include "mozilla/net/NeckoTargetHolder.h"
25 :
26 : class nsISystemProxySettings;
27 : class nsIThread;
28 :
29 : namespace mozilla {
30 : namespace net {
31 :
32 : class nsPACMan;
33 : class WaitForThreadShutdown;
34 :
35 : /**
36 : * This class defines a callback interface used by AsyncGetProxyForURI.
37 : */
38 6 : class NS_NO_VTABLE nsPACManCallback : public nsISupports
39 : {
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,
55 : const nsCString &pacString,
56 : const nsCString &newPACURL) = 0;
57 : };
58 :
59 0 : class PendingPACQuery final : public Runnable,
60 : public LinkedListElement<PendingPACQuery>
61 : {
62 : public:
63 : PendingPACQuery(nsPACMan *pacMan, nsIURI *uri,
64 : nsPACManCallback *callback,
65 : bool mainThreadResponse);
66 :
67 : // can be called from either thread
68 : void Complete(nsresult status, const nsCString &pacString);
69 : void UseAlternatePACFile(const nsCString &pacURL);
70 :
71 : nsCString mSpec;
72 : nsCString mScheme;
73 : nsCString mHost;
74 : int32_t mPort;
75 :
76 : NS_IMETHOD Run(void); /* Runnable */
77 :
78 : private:
79 : nsPACMan *mPACMan; // weak reference
80 :
81 : private:
82 : RefPtr<nsPACManCallback> mCallback;
83 : bool mOnMainThreadOnly;
84 : };
85 :
86 : /**
87 : * This class provides an abstraction layer above the PAC thread. The methods
88 : * defined on this class are intended to be called on the main thread only.
89 : */
90 :
91 : class nsPACMan final : public nsIStreamLoaderObserver
92 : , public nsIInterfaceRequestor
93 : , public nsIChannelEventSink
94 : , public NeckoTargetHolder
95 : {
96 : public:
97 : NS_DECL_THREADSAFE_ISUPPORTS
98 :
99 : explicit nsPACMan(nsIEventTarget *mainThreadEventTarget);
100 :
101 : /**
102 : * This method may be called to shutdown the PAC manager. Any async queries
103 : * that have not yet completed will either finish normally or be canceled by
104 : * the time this method returns.
105 : */
106 : void Shutdown();
107 :
108 : /**
109 : * This method queries a PAC result asynchronously. The callback runs on the
110 : * calling thread. If the PAC file has not yet been loaded, then this method
111 : * will queue up the request, and complete it once the PAC file has been
112 : * loaded.
113 : *
114 : * @param uri
115 : * The URI to query.
116 : * @param callback
117 : * The callback to run once the PAC result is available.
118 : * @param mustCallbackOnMainThread
119 : * If set to false the callback can be made from the PAC thread
120 : */
121 : nsresult AsyncGetProxyForURI(nsIURI *uri,
122 : nsPACManCallback *callback,
123 : bool mustCallbackOnMainThread);
124 :
125 : /**
126 : * This method may be called to reload the PAC file. While we are loading
127 : * the PAC file, any asynchronous PAC queries will be queued up to be
128 : * processed once the PAC file finishes loading.
129 : *
130 : * @param pacSpec
131 : * The non normalized uri spec of this URI used for comparison with
132 : * system proxy settings to determine if the PAC uri has changed.
133 : */
134 : nsresult LoadPACFromURI(const nsCString &pacSpec);
135 :
136 : /**
137 : * Returns true if we are currently loading the PAC file.
138 : */
139 0 : bool IsLoading() { return mLoader != nullptr; }
140 :
141 : /**
142 : * Returns true if the given URI matches the URI of our PAC file or the
143 : * URI it has been redirected to. In the case of a chain of redirections
144 : * only the current one being followed and the original are considered
145 : * becuase this information is used, respectively, to determine if we
146 : * should bypass the proxy (to fetch the pac file) or if the pac
147 : * configuration has changed (and we should reload the pac file)
148 : */
149 0 : bool IsPACURI(const nsACString &spec)
150 : {
151 0 : return mPACURISpec.Equals(spec) || mPACURIRedirectSpec.Equals(spec) ||
152 0 : mNormalPACURISpec.Equals(spec);
153 : }
154 :
155 6 : bool IsPACURI(nsIURI *uri) {
156 6 : if (mPACURISpec.IsEmpty() && mPACURIRedirectSpec.IsEmpty()) {
157 6 : return false;
158 : }
159 :
160 0 : nsAutoCString tmp;
161 0 : nsresult rv = uri->GetSpec(tmp);
162 0 : if (NS_FAILED(rv)) {
163 0 : return false;
164 : }
165 :
166 0 : return IsPACURI(tmp);
167 : }
168 :
169 : nsresult Init(nsISystemProxySettings *);
170 : static nsPACMan *sInstance;
171 :
172 : // PAC thread operations only
173 : void ProcessPendingQ();
174 : void CancelPendingQ(nsresult);
175 :
176 : private:
177 : NS_DECL_NSISTREAMLOADEROBSERVER
178 : NS_DECL_NSIINTERFACEREQUESTOR
179 : NS_DECL_NSICHANNELEVENTSINK
180 :
181 : friend class PendingPACQuery;
182 : friend class PACLoadComplete;
183 : friend class ExecutePACThreadAction;
184 : friend class WaitForThreadShutdown;
185 :
186 : ~nsPACMan();
187 :
188 : /**
189 : * Cancel any existing load if any.
190 : */
191 : void CancelExistingLoad();
192 :
193 : /**
194 : * Start loading the PAC file.
195 : */
196 : void StartLoading();
197 :
198 : /**
199 : * Reload the PAC file if there is reason to.
200 : */
201 : void MaybeReloadPAC();
202 :
203 : /**
204 : * Called when we fail to load the PAC file.
205 : */
206 : void OnLoadFailure();
207 :
208 : /**
209 : * PostQuery() only runs on the PAC thread and it is used to
210 : * place a pendingPACQuery into the queue and potentially
211 : * execute the queue if it was otherwise empty
212 : */
213 : nsresult PostQuery(PendingPACQuery *query);
214 :
215 : // PAC thread operations only
216 : void PostProcessPendingQ();
217 : void PostCancelPendingQ(nsresult);
218 : bool ProcessPending();
219 :
220 : private:
221 : ProxyAutoConfig mPAC;
222 : nsCOMPtr<nsIThread> mPACThread;
223 : nsCOMPtr<nsISystemProxySettings> mSystemProxySettings;
224 :
225 : LinkedList<PendingPACQuery> mPendingQ; /* pac thread only */
226 :
227 : // These specs are not nsIURI so that they can be used off the main thread.
228 : // The non-normalized versions are directly from the configuration, the
229 : // normalized version has been extracted from an nsIURI
230 : nsCString mPACURISpec;
231 : nsCString mPACURIRedirectSpec;
232 : nsCString mNormalPACURISpec;
233 :
234 : nsCOMPtr<nsIStreamLoader> mLoader;
235 : bool mLoadPending;
236 : Atomic<bool, Relaxed> mShutdown;
237 : TimeStamp mScheduledReload;
238 : uint32_t mLoadFailureCount;
239 :
240 : bool mInProgress;
241 : bool mIncludePath;
242 : };
243 :
244 : extern LazyLogModule gProxyLog;
245 :
246 : } // namespace net
247 : } // namespace mozilla
248 :
249 : #endif // nsPACMan_h__
|