Sat, 03 Jan 2015 20:18:00 +0100
Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.
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 "nsCxPusher.h"
13 #include "MainThreadUtils.h"
14 #include "nsIGlobalObject.h"
15 #include "nsIPrincipal.h"
17 #include "mozilla/Maybe.h"
19 class nsIGlobalObject;
21 namespace mozilla {
22 namespace dom {
24 /*
25 * System-wide setup/teardown routines. Init and Destroy should be invoked
26 * once each, at startup and shutdown (respectively).
27 */
28 void InitScriptSettings();
29 void DestroyScriptSettings();
31 // This mostly gets the entry global, but doesn't entirely match the spec in
32 // certain edge cases. It's good enough for some purposes, but not others. If
33 // you want to call this function, ping bholley and describe your use-case.
34 nsIGlobalObject* BrokenGetEntryGlobal();
36 // Note: We don't yet expose GetEntryGlobal, because in order for it to be
37 // correct, we first need to replace a bunch of explicit cx pushing in the
38 // browser with AutoEntryScript. But GetIncumbentGlobal is simpler, because it
39 // can mostly be inferred from the JS stack.
40 nsIGlobalObject* GetIncumbentGlobal();
42 // JS-implemented WebIDL presents an interesting situation with respect to the
43 // subject principal. A regular C++-implemented API can simply examine the
44 // compartment of the most-recently-executed script, and use that to infer the
45 // responsible party. However, JS-implemented APIs are run with system
46 // principal, and thus clobber the subject principal of the script that
47 // invoked the API. So we have to do some extra work to keep track of this
48 // information.
49 //
50 // We therefore implement the following behavior:
51 // * Each Script Settings Object has an optional WebIDL Caller Principal field.
52 // This defaults to null.
53 // * When we push an Entry Point in preparation to run a JS-implemented WebIDL
54 // callback, we grab the subject principal at the time of invocation, and
55 // store that as the WebIDL Caller Principal.
56 // * When non-null, callers can query this principal from script via an API on
57 // Components.utils.
58 nsIPrincipal* GetWebIDLCallerPrincipal();
60 // This may be used by callers that know that their incumbent global is non-
61 // null (i.e. they know there have been no System Caller pushes since the
62 // inner-most script execution).
63 inline JSObject& IncumbentJSGlobal()
64 {
65 return *GetIncumbentGlobal()->GetGlobalJSObject();
66 }
68 class ScriptSettingsStack;
69 struct ScriptSettingsStackEntry {
70 nsCOMPtr<nsIGlobalObject> mGlobalObject;
71 bool mIsCandidateEntryPoint;
73 ScriptSettingsStackEntry(nsIGlobalObject *aGlobal, bool aCandidate)
74 : mGlobalObject(aGlobal)
75 , mIsCandidateEntryPoint(aCandidate)
76 {
77 MOZ_ASSERT(mGlobalObject);
78 MOZ_ASSERT(mGlobalObject->GetGlobalJSObject(),
79 "Must have an actual JS global for the duration on the stack");
80 MOZ_ASSERT(JS_IsGlobalObject(mGlobalObject->GetGlobalJSObject()),
81 "No outer windows allowed");
82 }
84 ~ScriptSettingsStackEntry() {
85 // We must have an actual JS global for the entire time this is on the stack.
86 MOZ_ASSERT_IF(mGlobalObject, mGlobalObject->GetGlobalJSObject());
87 }
89 bool NoJSAPI() { return this == &NoJSAPISingleton; }
90 static ScriptSettingsStackEntry NoJSAPISingleton;
92 private:
93 ScriptSettingsStackEntry() : mGlobalObject(nullptr)
94 , mIsCandidateEntryPoint(true)
95 {}
96 };
98 /*
99 * For any interaction with JSAPI, an AutoJSAPI (or one of its subclasses)
100 * must be on the stack.
101 *
102 * This base class should be instantiated as-is when the caller wants to use
103 * JSAPI but doesn't expect to run script. Its current duties are as-follows:
104 *
105 * * Grabbing an appropriate JSContext, and, on the main thread, pushing it onto
106 * the JSContext stack.
107 * * Entering a null compartment, so that the consumer is forced to select a
108 * compartment to enter before manipulating objects.
109 *
110 * Additionally, the following duties are planned, but not yet implemented:
111 *
112 * * De-poisoning the JSRuntime to allow manipulation of JSAPI. We can't
113 * actually implement this poisoning until all the JSContext pushing in the
114 * system goes through AutoJSAPI (see bug 951991). For now, this de-poisoning
115 * effectively corresponds to having a non-null cx on the stack.
116 * * Reporting any exceptions left on the JSRuntime, unless the caller steals
117 * or silences them.
118 * * Entering a JSAutoRequest. At present, this is handled by the cx pushing
119 * on the main thread, and by other code on workers. Depending on the order
120 * in which various cleanup lands, this may never be necessary, because
121 * JSAutoRequests may go away.
122 *
123 * In situations where the consumer expects to run script, AutoEntryScript
124 * should be used, which does additional manipulation of the script settings
125 * stack. In bug 991758, we'll add hard invariants to SpiderMonkey, such that
126 * any attempt to run script without an AutoEntryScript on the stack will
127 * fail. This prevents system code from accidentally triggering script
128 * execution at inopportune moments via surreptitious getters and proxies.
129 */
130 class AutoJSAPI {
131 public:
132 // Public constructor for use when the base class is constructed as-is. It
133 // uses the SafeJSContext (or worker equivalent), and enters a null
134 // compartment.
135 AutoJSAPI();
136 JSContext* cx() const { return mCx; }
138 bool CxPusherIsStackTop() { return mCxPusher.ref().IsStackTop(); }
140 protected:
141 // Protected constructor, allowing subclasses to specify a particular cx to
142 // be used.
143 AutoJSAPI(JSContext *aCx, bool aIsMainThread, bool aSkipNullAC = false);
145 private:
146 mozilla::Maybe<AutoCxPusher> mCxPusher;
147 mozilla::Maybe<JSAutoNullCompartment> mNullAc;
148 JSContext *mCx;
149 };
151 // Note - the ideal way to implement this is with an accessor on AutoJSAPI
152 // that lets us select the error reporting target. But at present,
153 // implementing it that way would require us to destroy and reconstruct
154 // mCxPusher, which is pretty wasteful. So we do this for now, since it should
155 // be pretty easy to switch things over later.
156 //
157 // This should only be used on the main thread.
158 class AutoJSAPIWithErrorsReportedToWindow : public AutoJSAPI {
159 public:
160 AutoJSAPIWithErrorsReportedToWindow(nsIScriptContext* aScx);
161 // Equivalent to AutoJSAPI if aGlobal is not a Window.
162 AutoJSAPIWithErrorsReportedToWindow(nsIGlobalObject* aGlobalObject);
163 };
165 /*
166 * A class that represents a new script entry point.
167 */
168 class AutoEntryScript : public AutoJSAPI,
169 protected ScriptSettingsStackEntry {
170 public:
171 AutoEntryScript(nsIGlobalObject* aGlobalObject,
172 bool aIsMainThread = NS_IsMainThread(),
173 // Note: aCx is mandatory off-main-thread.
174 JSContext* aCx = nullptr);
175 ~AutoEntryScript();
177 void SetWebIDLCallerPrincipal(nsIPrincipal *aPrincipal) {
178 mWebIDLCallerPrincipal = aPrincipal;
179 }
181 private:
182 JSAutoCompartment mAc;
183 dom::ScriptSettingsStack& mStack;
184 nsCOMPtr<nsIPrincipal> mWebIDLCallerPrincipal;
185 friend nsIPrincipal* GetWebIDLCallerPrincipal();
186 };
188 /*
189 * A class that can be used to force a particular incumbent script on the stack.
190 */
191 class AutoIncumbentScript : protected ScriptSettingsStackEntry {
192 public:
193 AutoIncumbentScript(nsIGlobalObject* aGlobalObject);
194 ~AutoIncumbentScript();
195 private:
196 dom::ScriptSettingsStack& mStack;
197 JS::AutoHideScriptedCaller mCallerOverride;
198 };
200 /*
201 * A class to put the JS engine in an unusable state. The subject principal
202 * will become System, the information on the script settings stack is
203 * rendered inaccessible, and JSAPI may not be manipulated until the class is
204 * either popped or an AutoJSAPI instance is subsequently pushed.
205 *
206 * This class may not be instantiated if an exception is pending.
207 */
208 class AutoNoJSAPI {
209 public:
210 AutoNoJSAPI(bool aIsMainThread = NS_IsMainThread());
211 ~AutoNoJSAPI();
212 private:
213 dom::ScriptSettingsStack& mStack;
214 mozilla::Maybe<AutoCxPusher> mCxPusher;
215 };
217 } // namespace dom
218 } // namespace mozilla
220 #endif // mozilla_dom_ScriptSettings_h