Bumping manifests a=b2g-bump
[gecko.git] / dom / base / ScriptSettings.h
blob880023ebc7eef645ed2139b963819240d92a7a17
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 // vim: ft=cpp tw=78 sw=2 et ts=2
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/. */
7 /* Utilities for managing the script settings object stack defined in webapps */
9 #ifndef mozilla_dom_ScriptSettings_h
10 #define mozilla_dom_ScriptSettings_h
12 #include "MainThreadUtils.h"
13 #include "nsIGlobalObject.h"
14 #include "nsIPrincipal.h"
16 #include "mozilla/Maybe.h"
18 #include "jsapi.h"
20 class nsPIDOMWindow;
21 class nsGlobalWindow;
22 class nsIScriptContext;
23 class nsIDocument;
25 namespace mozilla {
26 namespace dom {
28 // For internal use only - use AutoJSAPI instead.
29 namespace danger {
31 /**
32 * Fundamental cx pushing class. All other cx pushing classes are implemented
33 * in terms of this class.
35 class MOZ_STACK_CLASS AutoCxPusher
37 public:
38 explicit AutoCxPusher(JSContext *aCx, bool aAllowNull = false);
39 ~AutoCxPusher();
41 nsIScriptContext* GetScriptContext() { return mScx; }
43 // Returns true if this AutoCxPusher performed the push that is currently at
44 // the top of the cx stack.
45 bool IsStackTop() const;
47 private:
48 mozilla::Maybe<JSAutoRequest> mAutoRequest;
49 nsCOMPtr<nsIScriptContext> mScx;
50 uint32_t mStackDepthAfterPush;
51 #ifdef DEBUG
52 JSContext* mPushedContext;
53 unsigned mCompartmentDepthOnEntry;
54 #endif
57 } /* namespace danger */
60 * System-wide setup/teardown routines. Init and Destroy should be invoked
61 * once each, at startup and shutdown (respectively).
63 void InitScriptSettings();
64 void DestroyScriptSettings();
66 // To implement a web-compatible browser, it is often necessary to obtain the
67 // global object that is "associated" with the currently-running code. This
68 // process is made more complicated by the fact that, historically, different
69 // algorithms have operated with different definitions of the "associated"
70 // global.
72 // HTML5 formalizes this into two concepts: the "incumbent global" and the
73 // "entry global". The incumbent global corresponds to the global of the
74 // current script being executed, whereas the entry global corresponds to the
75 // global of the script where the current JS execution began.
77 // There is also a potentially-distinct third global that is determined by the
78 // current compartment. This roughly corresponds with the notion of Realms in
79 // ECMAScript.
81 // Suppose some event triggers an event listener in window |A|, which invokes a
82 // scripted function in window |B|, which invokes the |window.location.href|
83 // setter in window |C|. The entry global would be |A|, the incumbent global
84 // would be |B|, and the current compartment would be that of |C|.
86 // In general, it's best to use to use the most-closely-associated global
87 // unless the spec says to do otherwise. In 95% of the cases, the global of
88 // the current compartment (GetCurrentGlobal()) is the right thing. For
89 // example, WebIDL constructors (new C.XMLHttpRequest()) are initialized with
90 // the global of the current compartment (i.e. |C|).
92 // The incumbent global is very similar, but differs in a few edge cases. For
93 // example, if window |B| does |C.location.href = "..."|, the incumbent global
94 // used for the navigation algorithm is B, because no script from |C| was ever run.
96 // The entry global is used for various things like computing base URIs, mostly
97 // for historical reasons.
99 // Note that all of these functions return bonafide global objects. This means
100 // that, for Windows, they always return the inner.
102 // Returns the global associated with the top-most Candidate Entry Point on
103 // the Script Settings Stack. See the HTML spec. This may be null.
104 nsIGlobalObject* GetEntryGlobal();
106 // If the entry global is a window, returns its extant document. Otherwise,
107 // returns null.
108 nsIDocument* GetEntryDocument();
110 // Returns the global associated with the top-most entry of the the Script
111 // Settings Stack. See the HTML spec. This may be null.
112 nsIGlobalObject* GetIncumbentGlobal();
114 // Returns the global associated with the current compartment. This may be null.
115 nsIGlobalObject* GetCurrentGlobal();
117 // JS-implemented WebIDL presents an interesting situation with respect to the
118 // subject principal. A regular C++-implemented API can simply examine the
119 // compartment of the most-recently-executed script, and use that to infer the
120 // responsible party. However, JS-implemented APIs are run with system
121 // principal, and thus clobber the subject principal of the script that
122 // invoked the API. So we have to do some extra work to keep track of this
123 // information.
125 // We therefore implement the following behavior:
126 // * Each Script Settings Object has an optional WebIDL Caller Principal field.
127 // This defaults to null.
128 // * When we push an Entry Point in preparation to run a JS-implemented WebIDL
129 // callback, we grab the subject principal at the time of invocation, and
130 // store that as the WebIDL Caller Principal.
131 // * When non-null, callers can query this principal from script via an API on
132 // Components.utils.
133 nsIPrincipal* GetWebIDLCallerPrincipal();
135 // This may be used by callers that know that their incumbent global is non-
136 // null (i.e. they know there have been no System Caller pushes since the
137 // inner-most script execution).
138 inline JSObject& IncumbentJSGlobal()
140 return *GetIncumbentGlobal()->GetGlobalJSObject();
143 class ScriptSettingsStack;
144 class ScriptSettingsStackEntry {
145 friend class ScriptSettingsStack;
147 public:
148 ~ScriptSettingsStackEntry();
150 bool NoJSAPI() { return !mGlobalObject; }
152 protected:
153 ScriptSettingsStackEntry(nsIGlobalObject *aGlobal, bool aCandidate);
155 nsCOMPtr<nsIGlobalObject> mGlobalObject;
156 bool mIsCandidateEntryPoint;
158 private:
159 // This constructor is only for use by AutoNoJSAPI.
160 friend class AutoNoJSAPI;
161 ScriptSettingsStackEntry();
163 ScriptSettingsStackEntry *mOlder;
167 * For any interaction with JSAPI, an AutoJSAPI (or one of its subclasses)
168 * must be on the stack.
170 * This base class should be instantiated as-is when the caller wants to use
171 * JSAPI but doesn't expect to run script. The caller must then call one of its
172 * Init functions before being able to access the JSContext through cx().
173 * Its current duties are as-follows (see individual Init comments for details):
175 * * Grabbing an appropriate JSContext, and, on the main thread, pushing it onto
176 * the JSContext stack.
177 * * Entering an initial (possibly null) compartment, to ensure that the
178 * previously entered compartment for that JSContext is not used by mistake.
180 * Additionally, the following duties are planned, but not yet implemented:
182 * * De-poisoning the JSRuntime to allow manipulation of JSAPI. We can't
183 * actually implement this poisoning until all the JSContext pushing in the
184 * system goes through AutoJSAPI (see bug 951991). For now, this de-poisoning
185 * effectively corresponds to having a non-null cx on the stack.
186 * * Reporting any exceptions left on the JSRuntime, unless the caller steals
187 * or silences them.
188 * * Entering a JSAutoRequest. At present, this is handled by the cx pushing
189 * on the main thread, and by other code on workers. Depending on the order
190 * in which various cleanup lands, this may never be necessary, because
191 * JSAutoRequests may go away.
193 * In situations where the consumer expects to run script, AutoEntryScript
194 * should be used, which does additional manipulation of the script settings
195 * stack. In bug 991758, we'll add hard invariants to SpiderMonkey, such that
196 * any attempt to run script without an AutoEntryScript on the stack will
197 * fail. This prevents system code from accidentally triggering script
198 * execution at inopportune moments via surreptitious getters and proxies.
200 class MOZ_STACK_CLASS AutoJSAPI {
201 public:
202 // Trivial constructor. One of the Init functions must be called before
203 // accessing the JSContext through cx().
204 AutoJSAPI();
206 // This uses the SafeJSContext (or worker equivalent), and enters a null
207 // compartment, so that the consumer is forced to select a compartment to
208 // enter before manipulating objects.
209 void Init();
211 // This uses the SafeJSContext (or worker equivalent), and enters the
212 // compartment of aGlobalObject.
213 // If aGlobalObject or its associated JS global are null then it returns
214 // false and use of cx() will cause an assertion.
215 bool Init(nsIGlobalObject* aGlobalObject);
217 // Unsurprisingly, this uses aCx and enters the compartment of aGlobalObject.
218 // If aGlobalObject or its associated JS global are null then it returns
219 // false and use of cx() will cause an assertion.
220 // If aCx is null it will cause an assertion.
221 bool Init(nsIGlobalObject* aGlobalObject, JSContext* aCx);
223 // This may only be used on the main thread.
224 // This attempts to use the JSContext associated with aGlobalObject, otherwise
225 // it uses the SafeJSContext. It then enters the compartment of aGlobalObject.
226 // This means that existing error reporting mechanisms that use the JSContext
227 // to find the JSErrorReporter should still work as before.
228 // We should be able to remove this around bug 981198.
229 // If aGlobalObject or its associated JS global are null then it returns
230 // false and use of cx() will cause an assertion.
231 bool InitWithLegacyErrorReporting(nsIGlobalObject* aGlobalObject);
233 // Convenience functions to take an nsPIDOMWindow* or nsGlobalWindow*,
234 // when it is more easily available than an nsIGlobalObject.
235 bool Init(nsPIDOMWindow* aWindow);
236 bool Init(nsPIDOMWindow* aWindow, JSContext* aCx);
238 bool Init(nsGlobalWindow* aWindow);
239 bool Init(nsGlobalWindow* aWindow, JSContext* aCx);
241 bool InitWithLegacyErrorReporting(nsPIDOMWindow* aWindow);
242 bool InitWithLegacyErrorReporting(nsGlobalWindow* aWindow);
244 JSContext* cx() const {
245 MOZ_ASSERT(mCx, "Must call Init before using an AutoJSAPI");
246 MOZ_ASSERT_IF(NS_IsMainThread(), CxPusherIsStackTop());
247 return mCx;
250 bool CxPusherIsStackTop() const { return mCxPusher->IsStackTop(); }
252 protected:
253 // Protected constructor, allowing subclasses to specify a particular cx to
254 // be used. This constructor initialises the AutoJSAPI, so Init must NOT be
255 // called on subclasses that use this.
256 // If aGlobalObject, its associated JS global or aCx are null this will cause
257 // an assertion, as will setting aIsMainThread incorrectly.
258 AutoJSAPI(nsIGlobalObject* aGlobalObject, bool aIsMainThread, JSContext* aCx);
260 private:
261 mozilla::Maybe<danger::AutoCxPusher> mCxPusher;
262 mozilla::Maybe<JSAutoNullableCompartment> mAutoNullableCompartment;
263 JSContext *mCx;
265 void InitInternal(JSObject* aGlobal, JSContext* aCx, bool aIsMainThread);
269 * A class that represents a new script entry point.
271 class AutoEntryScript : public AutoJSAPI,
272 protected ScriptSettingsStackEntry {
273 public:
274 explicit AutoEntryScript(nsIGlobalObject* aGlobalObject,
275 bool aIsMainThread = NS_IsMainThread(),
276 // Note: aCx is mandatory off-main-thread.
277 JSContext* aCx = nullptr);
279 ~AutoEntryScript();
281 void SetWebIDLCallerPrincipal(nsIPrincipal *aPrincipal) {
282 mWebIDLCallerPrincipal = aPrincipal;
285 private:
286 // It's safe to make this a weak pointer, since it's the subject principal
287 // when we go on the stack, so can't go away until after we're gone. In
288 // particular, this is only used from the CallSetup constructor, and only in
289 // the aIsJSImplementedWebIDL case. And in that case, the subject principal
290 // is the principal of the callee function that is part of the CallArgs just a
291 // bit up the stack, and which will outlive us. So we know the principal
292 // can't go away until then either.
293 nsIPrincipal* mWebIDLCallerPrincipal;
294 friend nsIPrincipal* GetWebIDLCallerPrincipal();
298 * A class that can be used to force a particular incumbent script on the stack.
300 class AutoIncumbentScript : protected ScriptSettingsStackEntry {
301 public:
302 explicit AutoIncumbentScript(nsIGlobalObject* aGlobalObject);
303 private:
304 JS::AutoHideScriptedCaller mCallerOverride;
308 * A class to put the JS engine in an unusable state. The subject principal
309 * will become System, the information on the script settings stack is
310 * rendered inaccessible, and JSAPI may not be manipulated until the class is
311 * either popped or an AutoJSAPI instance is subsequently pushed.
313 * This class may not be instantiated if an exception is pending.
315 class AutoNoJSAPI : protected ScriptSettingsStackEntry {
316 public:
317 explicit AutoNoJSAPI(bool aIsMainThread = NS_IsMainThread());
318 private:
319 mozilla::Maybe<danger::AutoCxPusher> mCxPusher;
322 } // namespace dom
325 * Use AutoJSContext when you need a JS context on the stack but don't have one
326 * passed as a parameter. AutoJSContext will take care of finding the most
327 * appropriate JS context and release it when leaving the stack.
329 class MOZ_STACK_CLASS AutoJSContext {
330 public:
331 explicit AutoJSContext(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM);
332 operator JSContext*() const;
334 protected:
335 explicit AutoJSContext(bool aSafe MOZ_GUARD_OBJECT_NOTIFIER_PARAM);
337 // We need this Init() method because we can't use delegating constructor for
338 // the moment. It is a C++11 feature and we do not require C++11 to be
339 // supported to be able to compile Gecko.
340 void Init(bool aSafe MOZ_GUARD_OBJECT_NOTIFIER_PARAM);
342 JSContext* mCx;
343 dom::AutoJSAPI mJSAPI;
344 MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
348 * Use ThreadsafeAutoJSContext when you want an AutoJSContext but might be
349 * running on a worker thread.
351 class MOZ_STACK_CLASS ThreadsafeAutoJSContext {
352 public:
353 explicit ThreadsafeAutoJSContext(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM);
354 operator JSContext*() const;
356 private:
357 JSContext* mCx; // Used on workers. Null means mainthread.
358 Maybe<JSAutoRequest> mRequest; // Used on workers.
359 Maybe<AutoJSContext> mAutoJSContext; // Used on main thread.
360 MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
364 * AutoSafeJSContext is similar to AutoJSContext but will only return the safe
365 * JS context. That means it will never call nsContentUtils::GetCurrentJSContext().
367 * Note - This is deprecated. Please use AutoJSAPI instead.
369 class MOZ_STACK_CLASS AutoSafeJSContext : public AutoJSContext {
370 public:
371 explicit AutoSafeJSContext(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM);
372 private:
373 JSAutoCompartment mAc;
377 * Like AutoSafeJSContext but can be used safely on worker threads.
379 class MOZ_STACK_CLASS ThreadsafeAutoSafeJSContext {
380 public:
381 explicit ThreadsafeAutoSafeJSContext(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM);
382 operator JSContext*() const;
384 private:
385 JSContext* mCx; // Used on workers. Null means mainthread.
386 Maybe<JSAutoRequest> mRequest; // Used on workers.
387 Maybe<AutoSafeJSContext> mAutoSafeJSContext; // Used on main thread.
388 MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
392 } // namespace mozilla
394 #endif // mozilla_dom_ScriptSettings_h