Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
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 #ifndef nsFrameMessageManager_h__
8 #define nsFrameMessageManager_h__
10 #include "nsIMessageManager.h"
11 #include "nsIObserver.h"
12 #include "nsCOMPtr.h"
13 #include "nsAutoPtr.h"
14 #include "nsCOMArray.h"
15 #include "nsTArray.h"
16 #include "nsIAtom.h"
17 #include "nsCycleCollectionParticipant.h"
18 #include "nsTArray.h"
19 #include "nsIPrincipal.h"
20 #include "nsIXPConnect.h"
21 #include "nsDataHashtable.h"
22 #include "nsClassHashtable.h"
23 #include "mozilla/Services.h"
24 #include "nsIObserverService.h"
25 #include "nsThreadUtils.h"
26 #include "nsWeakPtr.h"
27 #include "mozilla/Attributes.h"
28 #include "js/RootingAPI.h"
29 #include "nsTObserverArray.h"
30 #include "mozilla/dom/StructuredCloneUtils.h"
32 namespace mozilla {
33 namespace dom {
35 class ContentParent;
36 class ContentChild;
37 class ClonedMessageData;
38 class MessageManagerReporter;
40 namespace ipc {
42 enum MessageManagerFlags {
43 MM_CHILD = 0,
44 MM_CHROME = 1,
45 MM_GLOBAL = 2,
46 MM_PROCESSMANAGER = 4,
47 MM_BROADCASTER = 8,
48 MM_OWNSCALLBACK = 16
49 };
51 class MessageManagerCallback
52 {
53 public:
54 virtual ~MessageManagerCallback() {}
56 virtual bool DoLoadFrameScript(const nsAString& aURL, bool aRunInGlobalScope)
57 {
58 return true;
59 }
61 virtual bool DoSendBlockingMessage(JSContext* aCx,
62 const nsAString& aMessage,
63 const StructuredCloneData& aData,
64 JS::Handle<JSObject*> aCpows,
65 nsIPrincipal* aPrincipal,
66 InfallibleTArray<nsString>* aJSONRetVal,
67 bool aIsSync)
68 {
69 return true;
70 }
72 virtual bool DoSendAsyncMessage(JSContext* aCx,
73 const nsAString& aMessage,
74 const StructuredCloneData& aData,
75 JS::Handle<JSObject*> aCpows,
76 nsIPrincipal* aPrincipal)
77 {
78 return true;
79 }
81 virtual bool CheckPermission(const nsAString& aPermission)
82 {
83 return false;
84 }
86 virtual bool CheckManifestURL(const nsAString& aManifestURL)
87 {
88 return false;
89 }
91 virtual bool CheckAppHasPermission(const nsAString& aPermission)
92 {
93 return false;
94 }
96 virtual bool CheckAppHasStatus(unsigned short aStatus)
97 {
98 return false;
99 }
101 protected:
102 bool BuildClonedMessageDataForParent(ContentParent* aParent,
103 const StructuredCloneData& aData,
104 ClonedMessageData& aClonedData);
105 bool BuildClonedMessageDataForChild(ContentChild* aChild,
106 const StructuredCloneData& aData,
107 ClonedMessageData& aClonedData);
108 };
110 StructuredCloneData UnpackClonedMessageDataForParent(const ClonedMessageData& aData);
111 StructuredCloneData UnpackClonedMessageDataForChild(const ClonedMessageData& aData);
113 } // namespace ipc
114 } // namespace dom
115 } // namespace mozilla
117 class nsAXPCNativeCallContext;
119 struct nsMessageListenerInfo
120 {
121 bool operator==(const nsMessageListenerInfo& aOther) const
122 {
123 return &aOther == this;
124 }
126 // Exactly one of mStrongListener and mWeakListener must be non-null.
127 nsCOMPtr<nsIMessageListener> mStrongListener;
128 nsWeakPtr mWeakListener;
129 };
131 class CpowHolder
132 {
133 public:
134 virtual bool ToObject(JSContext* cx, JS::MutableHandle<JSObject*> objp) = 0;
135 };
137 class MOZ_STACK_CLASS SameProcessCpowHolder : public CpowHolder
138 {
139 public:
140 SameProcessCpowHolder(JSRuntime *aRuntime, JS::Handle<JSObject*> aObj)
141 : mObj(aRuntime, aObj)
142 {
143 }
145 bool ToObject(JSContext* aCx, JS::MutableHandle<JSObject*> aObjp);
147 private:
148 JS::Rooted<JSObject*> mObj;
149 };
151 class nsFrameMessageManager MOZ_FINAL : public nsIContentFrameMessageManager,
152 public nsIMessageBroadcaster,
153 public nsIFrameScriptLoader,
154 public nsIProcessChecker
155 {
156 friend class mozilla::dom::MessageManagerReporter;
157 typedef mozilla::dom::StructuredCloneData StructuredCloneData;
158 public:
159 nsFrameMessageManager(mozilla::dom::ipc::MessageManagerCallback* aCallback,
160 nsFrameMessageManager* aParentManager,
161 /* mozilla::dom::ipc::MessageManagerFlags */ uint32_t aFlags)
162 : mChrome(!!(aFlags & mozilla::dom::ipc::MM_CHROME)),
163 mGlobal(!!(aFlags & mozilla::dom::ipc::MM_GLOBAL)),
164 mIsProcessManager(!!(aFlags & mozilla::dom::ipc::MM_PROCESSMANAGER)),
165 mIsBroadcaster(!!(aFlags & mozilla::dom::ipc::MM_BROADCASTER)),
166 mOwnsCallback(!!(aFlags & mozilla::dom::ipc::MM_OWNSCALLBACK)),
167 mHandlingMessage(false),
168 mDisconnected(false),
169 mCallback(aCallback),
170 mParentManager(aParentManager)
171 {
172 NS_ASSERTION(mChrome || !aParentManager, "Should not set parent manager!");
173 NS_ASSERTION(!mIsBroadcaster || !mCallback,
174 "Broadcasters cannot have callbacks!");
175 // This is a bit hackish. When parent manager is global, we want
176 // to attach the window message manager to it immediately.
177 // Is it just the frame message manager which waits until the
178 // content process is running.
179 if (mParentManager && (mCallback || IsWindowLevel())) {
180 mParentManager->AddChildManager(this);
181 }
182 if (mOwnsCallback) {
183 mOwnedCallback = aCallback;
184 }
185 }
187 ~nsFrameMessageManager()
188 {
189 for (int32_t i = mChildManagers.Count(); i > 0; --i) {
190 static_cast<nsFrameMessageManager*>(mChildManagers[i - 1])->
191 Disconnect(false);
192 }
193 if (mIsProcessManager) {
194 if (this == sParentProcessManager) {
195 sParentProcessManager = nullptr;
196 }
197 if (this == sChildProcessManager) {
198 sChildProcessManager = nullptr;
199 delete sPendingSameProcessAsyncMessages;
200 sPendingSameProcessAsyncMessages = nullptr;
201 }
202 if (this == sSameProcessParentManager) {
203 sSameProcessParentManager = nullptr;
204 }
205 }
206 }
208 NS_DECL_CYCLE_COLLECTING_ISUPPORTS
209 NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsFrameMessageManager,
210 nsIContentFrameMessageManager)
211 NS_DECL_NSIMESSAGELISTENERMANAGER
212 NS_DECL_NSIMESSAGESENDER
213 NS_DECL_NSIMESSAGEBROADCASTER
214 NS_DECL_NSISYNCMESSAGESENDER
215 NS_DECL_NSICONTENTFRAMEMESSAGEMANAGER
216 NS_DECL_NSIFRAMESCRIPTLOADER
217 NS_DECL_NSIPROCESSCHECKER
219 static nsFrameMessageManager*
220 NewProcessMessageManager(mozilla::dom::ContentParent* aProcess);
222 nsresult ReceiveMessage(nsISupports* aTarget, const nsAString& aMessage,
223 bool aIsSync, const StructuredCloneData* aCloneData,
224 CpowHolder* aCpows, nsIPrincipal* aPrincipal,
225 InfallibleTArray<nsString>* aJSONRetVal);
227 void AddChildManager(nsFrameMessageManager* aManager);
228 void RemoveChildManager(nsFrameMessageManager* aManager)
229 {
230 mChildManagers.RemoveObject(aManager);
231 }
232 void Disconnect(bool aRemoveFromParent = true);
234 void InitWithCallback(mozilla::dom::ipc::MessageManagerCallback* aCallback);
235 void SetCallback(mozilla::dom::ipc::MessageManagerCallback* aCallback);
236 mozilla::dom::ipc::MessageManagerCallback* GetCallback()
237 {
238 return mCallback;
239 }
241 nsresult DispatchAsyncMessage(const nsAString& aMessageName,
242 const JS::Value& aJSON,
243 const JS::Value& aObjects,
244 nsIPrincipal* aPrincipal,
245 JSContext* aCx,
246 uint8_t aArgc);
247 nsresult DispatchAsyncMessageInternal(JSContext* aCx,
248 const nsAString& aMessage,
249 const StructuredCloneData& aData,
250 JS::Handle<JSObject*> aCpows,
251 nsIPrincipal* aPrincipal);
252 void RemoveFromParent();
253 nsFrameMessageManager* GetParentManager() { return mParentManager; }
254 void SetParentManager(nsFrameMessageManager* aParent)
255 {
256 NS_ASSERTION(!mParentManager, "We have parent manager already!");
257 NS_ASSERTION(mChrome, "Should not set parent manager!");
258 mParentManager = aParent;
259 }
260 bool IsGlobal() { return mGlobal; }
261 bool IsWindowLevel() { return mParentManager && mParentManager->IsGlobal(); }
263 static nsFrameMessageManager* GetParentProcessManager()
264 {
265 return sParentProcessManager;
266 }
267 static nsFrameMessageManager* GetChildProcessManager()
268 {
269 return sChildProcessManager;
270 }
271 private:
272 nsresult SendMessage(const nsAString& aMessageName,
273 JS::Handle<JS::Value> aJSON,
274 JS::Handle<JS::Value> aObjects,
275 nsIPrincipal* aPrincipal,
276 JSContext* aCx,
277 uint8_t aArgc,
278 JS::MutableHandle<JS::Value> aRetval,
279 bool aIsSync);
280 protected:
281 friend class MMListenerRemover;
282 // We keep the message listeners as arrays in a hastable indexed by the
283 // message name. That gives us fast lookups in ReceiveMessage().
284 nsClassHashtable<nsStringHashKey,
285 nsAutoTObserverArray<nsMessageListenerInfo, 1>> mListeners;
286 nsCOMArray<nsIContentFrameMessageManager> mChildManagers;
287 bool mChrome; // true if we're in the chrome process
288 bool mGlobal; // true if we're the global frame message manager
289 bool mIsProcessManager; // true if the message manager belongs to the process realm
290 bool mIsBroadcaster; // true if the message manager is a broadcaster
291 bool mOwnsCallback;
292 bool mHandlingMessage;
293 bool mDisconnected;
294 mozilla::dom::ipc::MessageManagerCallback* mCallback;
295 nsAutoPtr<mozilla::dom::ipc::MessageManagerCallback> mOwnedCallback;
296 nsFrameMessageManager* mParentManager;
297 nsTArray<nsString> mPendingScripts;
298 nsTArray<bool> mPendingScriptsGlobalStates;
299 public:
300 static nsFrameMessageManager* sParentProcessManager;
301 static nsFrameMessageManager* sChildProcessManager;
302 static nsFrameMessageManager* sSameProcessParentManager;
303 static nsTArray<nsCOMPtr<nsIRunnable> >* sPendingSameProcessAsyncMessages;
304 private:
305 enum ProcessCheckerType {
306 PROCESS_CHECKER_PERMISSION,
307 PROCESS_CHECKER_MANIFEST_URL,
308 ASSERT_APP_HAS_PERMISSION
309 };
310 nsresult AssertProcessInternal(ProcessCheckerType aType,
311 const nsAString& aCapability,
312 bool* aValid);
313 };
315 /* A helper class for taking care of many details for async message sending
316 within a single process. Intended to be used like so:
318 class MyAsyncMessage : public nsSameProcessAsyncMessageBase, public nsRunnable
319 {
320 // Initialize nsSameProcessAsyncMessageBase...
322 NS_IMETHOD Run() {
323 ReceiveMessage(..., ...);
324 return NS_OK;
325 }
326 };
327 */
328 class nsSameProcessAsyncMessageBase
329 {
330 typedef mozilla::dom::StructuredCloneClosure StructuredCloneClosure;
332 public:
333 typedef mozilla::dom::StructuredCloneData StructuredCloneData;
335 nsSameProcessAsyncMessageBase(JSContext* aCx,
336 const nsAString& aMessage,
337 const StructuredCloneData& aData,
338 JS::Handle<JSObject*> aCpows,
339 nsIPrincipal* aPrincipal);
341 void ReceiveMessage(nsISupports* aTarget, nsFrameMessageManager* aManager);
343 private:
344 nsSameProcessAsyncMessageBase(const nsSameProcessAsyncMessageBase&);
346 JSRuntime* mRuntime;
347 nsString mMessage;
348 JSAutoStructuredCloneBuffer mData;
349 StructuredCloneClosure mClosure;
350 JS::PersistentRooted<JSObject*> mCpows;
351 nsCOMPtr<nsIPrincipal> mPrincipal;
352 };
354 class nsScriptCacheCleaner;
356 struct nsFrameScriptObjectExecutorHolder
357 {
358 nsFrameScriptObjectExecutorHolder(JSContext* aCx, JSScript* aScript)
359 : mScript(aCx, aScript), mFunction(aCx, nullptr)
360 { MOZ_COUNT_CTOR(nsFrameScriptObjectExecutorHolder); }
362 nsFrameScriptObjectExecutorHolder(JSContext* aCx, JSObject* aFunction)
363 : mScript(aCx, nullptr), mFunction(aCx, aFunction)
364 { MOZ_COUNT_CTOR(nsFrameScriptObjectExecutorHolder); }
366 ~nsFrameScriptObjectExecutorHolder()
367 { MOZ_COUNT_DTOR(nsFrameScriptObjectExecutorHolder); }
369 bool WillRunInGlobalScope() { return mScript; }
371 JS::PersistentRooted<JSScript*> mScript;
372 JS::PersistentRooted<JSObject*> mFunction;
373 };
375 class nsFrameScriptObjectExecutorStackHolder;
377 class nsFrameScriptExecutor
378 {
379 public:
380 static void Shutdown();
381 already_AddRefed<nsIXPConnectJSObjectHolder> GetGlobal()
382 {
383 nsCOMPtr<nsIXPConnectJSObjectHolder> ref = mGlobal;
384 return ref.forget();
385 }
386 protected:
387 friend class nsFrameScriptCx;
388 nsFrameScriptExecutor()
389 { MOZ_COUNT_CTOR(nsFrameScriptExecutor); }
390 ~nsFrameScriptExecutor()
391 { MOZ_COUNT_DTOR(nsFrameScriptExecutor); }
392 void DidCreateGlobal();
393 void LoadFrameScriptInternal(const nsAString& aURL, bool aRunInGlobalScope);
394 void TryCacheLoadAndCompileScript(const nsAString& aURL,
395 bool aRunInGlobalScope,
396 bool aShouldCache,
397 JS::MutableHandle<JSScript*> aScriptp,
398 JS::MutableHandle<JSObject*> aFunp);
399 void TryCacheLoadAndCompileScript(const nsAString& aURL,
400 bool aRunInGlobalScope);
401 bool InitTabChildGlobalInternal(nsISupports* aScope, const nsACString& aID);
402 nsCOMPtr<nsIXPConnectJSObjectHolder> mGlobal;
403 nsCOMPtr<nsIPrincipal> mPrincipal;
404 static nsDataHashtable<nsStringHashKey, nsFrameScriptObjectExecutorHolder*>* sCachedScripts;
405 static nsScriptCacheCleaner* sScriptCacheCleaner;
406 };
408 class nsScriptCacheCleaner MOZ_FINAL : public nsIObserver
409 {
410 NS_DECL_ISUPPORTS
412 nsScriptCacheCleaner()
413 {
414 nsCOMPtr<nsIObserverService> obsSvc = mozilla::services::GetObserverService();
415 if (obsSvc)
416 obsSvc->AddObserver(this, "xpcom-shutdown", false);
417 }
419 NS_IMETHODIMP Observe(nsISupports *aSubject,
420 const char *aTopic,
421 const char16_t *aData)
422 {
423 nsFrameScriptExecutor::Shutdown();
424 return NS_OK;
425 }
426 };
428 #endif