tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

nsFrameMessageManager.h (12705B)


      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/. */
      6 
      7 #ifndef nsFrameMessageManager_h__
      8 #define nsFrameMessageManager_h__
      9 
     10 #include <string.h>
     11 
     12 #include "ErrorList.h"
     13 #include "js/TypeDecls.h"
     14 #include "js/Value.h"
     15 #include "js/experimental/JSStencil.h"
     16 #include "mozilla/AlreadyAddRefed.h"
     17 #include "mozilla/RefPtr.h"
     18 #include "mozilla/Services.h"
     19 #include "mozilla/StaticPtr.h"
     20 #include "mozilla/TypedEnumBits.h"
     21 #include "mozilla/UniquePtr.h"
     22 #include "mozilla/dom/ipc/StructuredCloneData.h"
     23 #include "nsCOMPtr.h"
     24 #include "nsClassHashtable.h"
     25 #include "nsCycleCollectionParticipant.h"
     26 #include "nsHashKeys.h"
     27 #include "nsIMessageManager.h"
     28 #include "nsIObserver.h"
     29 #include "nsIObserverService.h"
     30 #include "nsISupports.h"
     31 #include "nsIWeakReferenceUtils.h"
     32 #include "nsStringFwd.h"
     33 #include "nsTArray.h"
     34 #include "nsTHashMap.h"
     35 #include "nsTObserverArray.h"
     36 #include "nscore.h"
     37 
     38 class nsFrameLoader;
     39 class nsIRunnable;
     40 
     41 namespace mozilla {
     42 
     43 class ErrorResult;
     44 
     45 namespace dom {
     46 
     47 class ChildProcessMessageManager;
     48 class ChromeMessageBroadcaster;
     49 class ClonedMessageData;
     50 class MessageBroadcaster;
     51 class MessageListener;
     52 class MessageListenerManager;
     53 class MessageManagerReporter;
     54 class ParentProcessMessageManager;
     55 class ProcessMessageManager;
     56 
     57 namespace ipc {
     58 
     59 class MessageManagerCallback;
     60 class WritableSharedMap;
     61 
     62 enum class MessageManagerFlags {
     63  MM_NONE = 0,
     64  MM_CHROME = 1,
     65  MM_GLOBAL = 2,
     66  MM_PROCESSMANAGER = 4,
     67  MM_BROADCASTER = 8,
     68  MM_OWNSCALLBACK = 16
     69 };
     70 MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(MessageManagerFlags);
     71 
     72 void UnpackClonedMessageData(const ClonedMessageData& aClonedData,
     73                             StructuredCloneData& aData);
     74 
     75 }  // namespace ipc
     76 }  // namespace dom
     77 }  // namespace mozilla
     78 
     79 struct nsMessageListenerInfo {
     80  bool operator==(const nsMessageListenerInfo& aOther) const {
     81    return &aOther == this;
     82  }
     83 
     84  // If mWeakListener is null then mStrongListener holds a MessageListener.
     85  // If mWeakListener is non-null then mStrongListener contains null.
     86  RefPtr<mozilla::dom::MessageListener> mStrongListener;
     87  nsWeakPtr mWeakListener;
     88  bool mListenWhenClosed;
     89 };
     90 
     91 class nsFrameMessageManager : public nsIMessageSender {
     92  friend class mozilla::dom::MessageManagerReporter;
     93  using StructuredCloneData = mozilla::dom::ipc::StructuredCloneData;
     94 
     95 protected:
     96  using MessageManagerFlags = mozilla::dom::ipc::MessageManagerFlags;
     97 
     98  nsFrameMessageManager(mozilla::dom::ipc::MessageManagerCallback* aCallback,
     99                        MessageManagerFlags aFlags);
    100 
    101  virtual ~nsFrameMessageManager();
    102 
    103 public:
    104  explicit nsFrameMessageManager(
    105      mozilla::dom::ipc::MessageManagerCallback* aCallback)
    106      : nsFrameMessageManager(aCallback, MessageManagerFlags::MM_NONE) {}
    107 
    108  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
    109  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(nsFrameMessageManager)
    110 
    111  void MarkForCC();
    112 
    113  // MessageListenerManager
    114  void AddMessageListener(const nsAString& aMessageName,
    115                          mozilla::dom::MessageListener& aListener,
    116                          bool aListenWhenClosed, mozilla::ErrorResult& aError);
    117  void RemoveMessageListener(const nsAString& aMessageName,
    118                             mozilla::dom::MessageListener& aListener,
    119                             mozilla::ErrorResult& aError);
    120  void AddWeakMessageListener(const nsAString& aMessageName,
    121                              mozilla::dom::MessageListener& aListener,
    122                              mozilla::ErrorResult& aError);
    123  void RemoveWeakMessageListener(const nsAString& aMessageName,
    124                                 mozilla::dom::MessageListener& aListener,
    125                                 mozilla::ErrorResult& aError);
    126 
    127  // MessageSender
    128  void SendAsyncMessage(JSContext* aCx, const nsAString& aMessageName,
    129                        JS::Handle<JS::Value> aObj,
    130                        JS::Handle<JS::Value> aTransfers,
    131                        mozilla::ErrorResult& aError) {
    132    DispatchAsyncMessage(aCx, aMessageName, aObj, aTransfers, aError);
    133  }
    134  already_AddRefed<mozilla::dom::ProcessMessageManager>
    135  GetProcessMessageManager(mozilla::ErrorResult& aError);
    136  void GetRemoteType(nsACString& aRemoteType,
    137                     mozilla::ErrorResult& aError) const;
    138 
    139  // SyncMessageSender
    140  void SendSyncMessage(JSContext* aCx, const nsAString& aMessageName,
    141                       JS::Handle<JS::Value> aObj, nsTArray<JS::Value>& aResult,
    142                       mozilla::ErrorResult& aError);
    143 
    144  // GlobalProcessScriptLoader
    145  void GetInitialProcessData(JSContext* aCx,
    146                             JS::MutableHandle<JS::Value> aInitialProcessData,
    147                             mozilla::ErrorResult& aError);
    148 
    149  mozilla::dom::ipc::WritableSharedMap* SharedData();
    150 
    151  NS_DECL_NSIMESSAGESENDER
    152 
    153  static mozilla::dom::ProcessMessageManager* NewProcessMessageManager(
    154      bool aIsRemote);
    155 
    156  void ReceiveMessage(
    157      nsISupports* aTarget, nsFrameLoader* aTargetFrameLoader,
    158      const nsAString& aMessage, bool aIsSync, StructuredCloneData* aCloneData,
    159      nsTArray<mozilla::UniquePtr<StructuredCloneData>>* aRetVal,
    160      mozilla::ErrorResult& aError) {
    161    ReceiveMessage(aTarget, aTargetFrameLoader, mClosed, aMessage, aIsSync,
    162                   aCloneData, aRetVal, aError);
    163  }
    164 
    165  void Disconnect(bool aRemoveFromParent = true);
    166  void Close();
    167 
    168  void SetCallback(mozilla::dom::ipc::MessageManagerCallback* aCallback);
    169 
    170  mozilla::dom::ipc::MessageManagerCallback* GetCallback() { return mCallback; }
    171 
    172  nsresult DispatchAsyncMessageInternal(JSContext* aCx,
    173                                        const nsAString& aMessage,
    174                                        StructuredCloneData& aData);
    175  bool IsGlobal() { return mGlobal; }
    176  bool IsBroadcaster() { return mIsBroadcaster; }
    177  bool IsChrome() { return mChrome; }
    178 
    179  // GetGlobalMessageManager creates the global message manager if it hasn't
    180  // been yet.
    181  static already_AddRefed<mozilla::dom::ChromeMessageBroadcaster>
    182  GetGlobalMessageManager();
    183  static mozilla::dom::ParentProcessMessageManager* GetParentProcessManager() {
    184    return sParentProcessManager;
    185  }
    186  static mozilla::dom::ChildProcessMessageManager* GetChildProcessManager() {
    187    return sChildProcessManager;
    188  }
    189  static void SetChildProcessManager(
    190      mozilla::dom::ChildProcessMessageManager* aManager) {
    191    sChildProcessManager = aManager;
    192  }
    193 
    194  static bool GetParamsForMessage(JSContext* aCx, const JS::Value& aValue,
    195                                  const JS::Value& aTransfer,
    196                                  StructuredCloneData& aData);
    197 
    198  void SetInitialProcessData(JS::Handle<JS::Value> aInitialData);
    199 
    200  void LoadPendingScripts();
    201 
    202 protected:
    203  friend class MMListenerRemover;
    204 
    205  virtual mozilla::dom::MessageBroadcaster* GetParentManager() {
    206    return nullptr;
    207  }
    208  virtual void ClearParentManager(bool aRemove) {}
    209 
    210  void DispatchAsyncMessage(JSContext* aCx, const nsAString& aMessageName,
    211                            JS::Handle<JS::Value> aObj,
    212                            JS::Handle<JS::Value> aTransfers,
    213                            mozilla::ErrorResult& aError);
    214 
    215  void ReceiveMessage(
    216      nsISupports* aTarget, nsFrameLoader* aTargetFrameLoader,
    217      bool aTargetClosed, const nsAString& aMessage, bool aIsSync,
    218      StructuredCloneData* aCloneData,
    219      nsTArray<mozilla::UniquePtr<StructuredCloneData>>* aRetVal,
    220      mozilla::ErrorResult& aError);
    221 
    222  void LoadScript(const nsAString& aURL, bool aAllowDelayedLoad,
    223                  bool aRunInGlobalScope, mozilla::ErrorResult& aError);
    224  void RemoveDelayedScript(const nsAString& aURL);
    225  void GetDelayedScripts(JSContext* aCx, nsTArray<nsTArray<JS::Value>>& aList,
    226                         mozilla::ErrorResult& aError);
    227 
    228  // We keep the message listeners as arrays in a hastable indexed by the
    229  // message name. That gives us fast lookups in ReceiveMessage().
    230  nsClassHashtable<nsStringHashKey,
    231                   nsAutoTObserverArray<nsMessageListenerInfo, 1>>
    232      mListeners;
    233  nsTArray<RefPtr<mozilla::dom::MessageListenerManager>> mChildManagers;
    234  bool mChrome;            // true if we're in the chrome process
    235  bool mGlobal;            // true if we're the global frame message manager
    236  bool mIsProcessManager;  // true if the message manager belongs to the process
    237                           // realm
    238  bool mIsBroadcaster;     // true if the message manager is a broadcaster
    239  bool mOwnsCallback;
    240  bool mHandlingMessage;
    241  bool mClosed;  // true if we can no longer send messages
    242  bool mDisconnected;
    243  mozilla::dom::ipc::MessageManagerCallback* mCallback;
    244  mozilla::UniquePtr<mozilla::dom::ipc::MessageManagerCallback> mOwnedCallback;
    245  nsTArray<nsString> mPendingScripts;
    246  nsTArray<bool> mPendingScriptsGlobalStates;
    247  JS::Heap<JS::Value> mInitialProcessData;
    248  RefPtr<mozilla::dom::ipc::WritableSharedMap> mSharedData;
    249 
    250  void LoadPendingScripts(nsFrameMessageManager* aManager,
    251                          nsFrameMessageManager* aChildMM);
    252 
    253 public:
    254  static mozilla::dom::ParentProcessMessageManager* sParentProcessManager;
    255  static nsFrameMessageManager* sSameProcessParentManager;
    256  static nsTArray<nsCOMPtr<nsIRunnable>>* sPendingSameProcessAsyncMessages;
    257 
    258 private:
    259  static mozilla::dom::ChildProcessMessageManager* sChildProcessManager;
    260 };
    261 
    262 /* A helper class for taking care of many details for async message sending
    263   within a single process.  Intended to be used like so:
    264 
    265   class MyAsyncMessage : public nsSameProcessAsyncMessageBase, public Runnable
    266   {
    267     NS_IMETHOD Run() {
    268       ReceiveMessage(..., ...);
    269       return NS_OK;
    270     }
    271   };
    272 
    273 
    274   RefPtr<nsSameProcessAsyncMessageBase> ev = new MyAsyncMessage();
    275   nsresult rv = ev->Init(...);
    276   if (NS_SUCCEEDED(rv)) {
    277     NS_DispatchToMainThread(ev);
    278   }
    279 */
    280 class nsSameProcessAsyncMessageBase {
    281 public:
    282  using StructuredCloneData = mozilla::dom::ipc::StructuredCloneData;
    283 
    284  nsSameProcessAsyncMessageBase();
    285  nsresult Init(const nsAString& aMessage, StructuredCloneData& aData);
    286 
    287  void ReceiveMessage(nsISupports* aTarget, nsFrameLoader* aTargetFrameLoader,
    288                      nsFrameMessageManager* aManager);
    289 
    290 private:
    291  nsSameProcessAsyncMessageBase(const nsSameProcessAsyncMessageBase&);
    292 
    293  nsString mMessage;
    294  StructuredCloneData mData;
    295 #ifdef DEBUG
    296  bool mCalledInit;
    297 #endif
    298 };
    299 
    300 class nsScriptCacheCleaner;
    301 
    302 struct nsMessageManagerScriptHolder {
    303  explicit nsMessageManagerScriptHolder(JS::Stencil* aStencil)
    304      : mStencil(aStencil) {
    305    MOZ_COUNT_CTOR(nsMessageManagerScriptHolder);
    306  }
    307 
    308  MOZ_COUNTED_DTOR(nsMessageManagerScriptHolder)
    309 
    310  RefPtr<JS::Stencil> mStencil;
    311 };
    312 
    313 class nsMessageManagerScriptExecutor {
    314 public:
    315  static void PurgeCache();
    316  static void Shutdown();
    317 
    318  void MarkScopesForCC();
    319 
    320 protected:
    321  friend class nsMessageManagerScriptCx;
    322  nsMessageManagerScriptExecutor() {
    323    MOZ_COUNT_CTOR(nsMessageManagerScriptExecutor);
    324  }
    325  MOZ_COUNTED_DTOR(nsMessageManagerScriptExecutor)
    326 
    327  void DidCreateScriptLoader();
    328  void LoadScriptInternal(JS::Handle<JSObject*> aMessageManager,
    329                          const nsAString& aURL, bool aRunInUniqueScope);
    330  already_AddRefed<JS::Stencil> TryCacheLoadAndCompileScript(
    331      const nsAString& aURL, bool aRunInUniqueScope,
    332      JS::Handle<JSObject*> aMessageManager);
    333  bool Init();
    334  void Trace(const TraceCallbacks& aCallbacks, void* aClosure);
    335  void Unlink();
    336  AutoTArray<JS::Heap<JSObject*>, 2> mAnonymousGlobalScopes;
    337 
    338  // Returns true if this is a process message manager. There should only be a
    339  // single process message manager per session, so instances of this type will
    340  // optimize their script loading to avoid unnecessary duplication.
    341  virtual bool IsProcessScoped() const { return false; }
    342 
    343  static nsTHashMap<nsStringHashKey, nsMessageManagerScriptHolder*>*
    344      sCachedScripts;
    345  static mozilla::StaticRefPtr<nsScriptCacheCleaner> sScriptCacheCleaner;
    346 };
    347 
    348 class nsScriptCacheCleaner final : public nsIObserver {
    349  ~nsScriptCacheCleaner() = default;
    350 
    351  NS_DECL_ISUPPORTS
    352 
    353  nsScriptCacheCleaner() {
    354    nsCOMPtr<nsIObserverService> obsSvc =
    355        mozilla::services::GetObserverService();
    356    if (obsSvc) {
    357      obsSvc->AddObserver(this, "xpcom-shutdown", false);
    358    }
    359  }
    360 
    361  NS_IMETHOD Observe(nsISupports* aSubject, const char* aTopic,
    362                     const char16_t* aData) override {
    363    if (strcmp("xpcom-shutdown", aTopic) == 0) {
    364      nsMessageManagerScriptExecutor::Shutdown();
    365    }
    366    return NS_OK;
    367  }
    368 };
    369 
    370 #endif