tor-browser

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

MessagePort.h (8052B)


      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 mozilla_dom_MessagePort_h
      8 #define mozilla_dom_MessagePort_h
      9 
     10 #include "mozilla/DOMEventTargetHelper.h"
     11 #include "mozilla/UniquePtr.h"
     12 #include "mozilla/dom/DOMTypes.h"
     13 #include "nsTArray.h"
     14 
     15 #ifdef XP_WIN
     16 #  undef PostMessage
     17 #endif
     18 
     19 class nsIGlobalObject;
     20 
     21 namespace mozilla::dom {
     22 
     23 class MessageData;
     24 class MessagePortChild;
     25 class PostMessageRunnable;
     26 class RefMessageBodyService;
     27 class SharedMessageBody;
     28 class StrongWorkerRef;
     29 struct StructuredSerializeOptions;
     30 
     31 // A class to hold a MessagePortIdentifier from
     32 // MessagePort::CloneAndDistentangle() and close if neither passed to
     33 // MessagePort::Create() nor release()ed to send via IPC.
     34 // When the `neutered` field of the MessagePortIdentifier is false, a close is
     35 // required.
     36 // This does not derive from MessagePortIdentifier because
     37 // MessagePortIdentifier is final and because use of UniqueMessagePortId as a
     38 // MessagePortIdentifier is intentionally prevented without release of
     39 // ownership.
     40 class UniqueMessagePortId final {
     41 public:
     42  UniqueMessagePortId() { mIdentifier.neutered() = true; }
     43  explicit UniqueMessagePortId(const MessagePortIdentifier& aIdentifier)
     44      : mIdentifier(aIdentifier) {}
     45  UniqueMessagePortId(UniqueMessagePortId&& aOther) noexcept
     46      : mIdentifier(aOther.mIdentifier) {
     47    aOther.mIdentifier.neutered() = true;
     48  }
     49  ~UniqueMessagePortId() { ForceClose(); };
     50  void ForceClose();
     51 
     52  [[nodiscard]] MessagePortIdentifier release() {
     53    MessagePortIdentifier id = mIdentifier;
     54    mIdentifier.neutered() = true;
     55    return id;
     56  }
     57  // const member accessors are not required because a const
     58  // UniqueMessagePortId is not useful.
     59  nsID& uuid() { return mIdentifier.uuid(); }
     60  nsID& destinationUuid() { return mIdentifier.destinationUuid(); }
     61  uint32_t& sequenceId() { return mIdentifier.sequenceId(); }
     62  bool& neutered() { return mIdentifier.neutered(); }
     63 
     64  UniqueMessagePortId(const UniqueMessagePortId& aOther) = delete;
     65  void operator=(const UniqueMessagePortId& aOther) = delete;
     66 
     67 private:
     68  MessagePortIdentifier mIdentifier;
     69 };
     70 
     71 class MessagePort final : public DOMEventTargetHelper {
     72  friend class PostMessageRunnable;
     73 
     74 public:
     75  NS_DECL_ISUPPORTS_INHERITED
     76  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(MessagePort, DOMEventTargetHelper)
     77 
     78  static already_AddRefed<MessagePort> Create(nsIGlobalObject* aGlobal,
     79                                              const nsID& aUUID,
     80                                              const nsID& aDestinationUUID,
     81                                              ErrorResult& aRv);
     82 
     83  static already_AddRefed<MessagePort> Create(nsIGlobalObject* aGlobal,
     84                                              UniqueMessagePortId& aIdentifier,
     85                                              ErrorResult& aRv);
     86 
     87  // For IPC.
     88  static void ForceClose(const MessagePortIdentifier& aIdentifier);
     89 
     90  virtual JSObject* WrapObject(JSContext* aCx,
     91                               JS::Handle<JSObject*> aGivenProto) override;
     92 
     93  void PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
     94                   const Sequence<JSObject*>& aTransferable, ErrorResult& aRv);
     95 
     96  void PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
     97                   const StructuredSerializeOptions& aOptions,
     98                   ErrorResult& aRv);
     99 
    100  void Start();
    101 
    102  void Close();
    103 
    104  EventHandlerNonNull* GetOnmessage();
    105 
    106  void SetOnmessage(EventHandlerNonNull* aCallback);
    107 
    108  IMPL_EVENT_HANDLER(messageerror)
    109 
    110  // Non WebIDL methods
    111 
    112  void UnshippedEntangle(RefPtr<MessagePort>& aEntangledPort);
    113 
    114  bool CanBeCloned() const { return !mHasBeenTransferredOrClosed; }
    115 
    116  void CloneAndDisentangle(UniqueMessagePortId& aIdentifier);
    117 
    118  void CloseForced();
    119 
    120  // These methods are useful for MessagePortChild
    121 
    122  void Entangled(nsTArray<MessageData>& aMessages);
    123  void MessagesReceived(nsTArray<MessageData>& aMessages);
    124  void StopSendingDataConfirmed();
    125  void Closed();
    126 
    127 private:
    128  enum State {
    129    // The plan is to be eStateUnshippedEntangled once we are told about our
    130    // unshipped entangled counterpart.
    131    eStateInitializingUnshippedEntangled,
    132 
    133    // When a port is created by a MessageChannel it is entangled with the
    134    // other. They both run on the same thread, same event loop and the
    135    // messages are added to the queues without using PBackground actors.
    136    // When one of the port is shipped, the state is changed to
    137    // StateEntangling.
    138    eStateUnshippedEntangled,
    139 
    140    // If the port is closed or cloned when we are in this state, we go in one
    141    // of the following 2 steps. EntanglingForClose or ForDisentangle.
    142    eStateEntangling,
    143 
    144    // We are not fully entangled yet but are already disentangled.
    145    eStateEntanglingForDisentangle,
    146 
    147    // We are not fully entangled yet but are already closed.
    148    eStateEntanglingForClose,
    149 
    150    // When entangled() is received we send all the messages in the
    151    // mMessagesForTheOtherPort to the actor and we change the state to
    152    // StateEntangled. At this point the port is entangled with the other. We
    153    // send and receive messages.
    154    // If the port queue is not enabled, the received messages are stored in
    155    // the mMessages.
    156    eStateEntangled,
    157 
    158    // When the port is cloned or disentangled we want to stop receiving
    159    // messages. We call 'SendStopSendingData' to the actor and we wait for an
    160    // answer. All the messages received between now and the
    161    // 'StopSendingDataComfirmed are queued in the mMessages but not
    162    // dispatched.
    163    eStateDisentangling,
    164 
    165    // When 'StopSendingDataConfirmed' is received, we can disentangle the port
    166    // calling SendDisentangle in the actor because we are 100% sure that we
    167    // don't receive any other message, so nothing will be lost.
    168    // Disentangling the port we send all the messages from the mMessages
    169    // though the actor.
    170    eStateDisentangled,
    171 
    172    // We are here if Close() has been called. We are disentangled but we can
    173    // still send pending messages.
    174    eStateDisentangledForClose
    175  };
    176 
    177  explicit MessagePort(nsIGlobalObject* aGlobal, State aState);
    178  ~MessagePort();
    179 
    180  void DisconnectFromOwner() override;
    181 
    182  void Initialize(const nsID& aUUID, const nsID& aDestinationUUID,
    183                  uint32_t aSequenceID, bool aNeutered, ErrorResult& aRv);
    184 
    185  bool ConnectToPBackground();
    186 
    187  // Dispatch events from the Message Queue using a nsRunnable.
    188  void Dispatch();
    189 
    190  void DispatchError();
    191 
    192  void StartDisentangling();
    193  void Disentangle();
    194 
    195  void RemoveDocFromBFCache();
    196 
    197  void CloseInternal(bool aSoftly);
    198 
    199  // This method is meant to keep alive the MessagePort when this object is
    200  // creating the actor and until the actor is entangled.
    201  // We release the object when the port is closed or disentangled.
    202  void UpdateMustKeepAlive();
    203 
    204  bool IsCertainlyAliveForCC() const override { return mIsKeptAlive; }
    205 
    206  RefPtr<StrongWorkerRef> mWorkerRef;
    207 
    208  RefPtr<PostMessageRunnable> mPostMessageRunnable;
    209 
    210  RefPtr<MessagePortChild> mActor;
    211 
    212  RefPtr<MessagePort> mUnshippedEntangledPort;
    213 
    214  RefPtr<RefMessageBodyService> mRefMessageBodyService;
    215 
    216  nsTArray<RefPtr<SharedMessageBody>> mMessages;
    217  nsTArray<RefPtr<SharedMessageBody>> mMessagesForTheOtherPort;
    218 
    219  UniquePtr<MessagePortIdentifier> mIdentifier;
    220 
    221  State mState;
    222 
    223  bool mMessageQueueEnabled;
    224 
    225  bool mIsKeptAlive;
    226 
    227  // mHasBeenTransferredOrClosed is used to know if this port has been manually
    228  // closed or transferred via postMessage. Note that if the entangled port is
    229  // closed, this port is closed as well (see mState) but, just because close()
    230  // has not been called directly, by spec, this port can still be transferred.
    231  bool mHasBeenTransferredOrClosed;
    232 };
    233 
    234 }  // namespace mozilla::dom
    235 
    236 #endif  // mozilla_dom_MessagePort_h