JSActor.h (6029B)
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim:set ts=2 sw=2 sts=2 et cindent: */ 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_JSActor_h 8 #define mozilla_dom_JSActor_h 9 10 #include "ipc/EnumSerializer.h" 11 #include "js/TypeDecls.h" 12 #include "mozilla/dom/JSIPCValue.h" 13 #include "mozilla/dom/PromiseNativeHandler.h" 14 #include "nsCycleCollectionParticipant.h" 15 #include "nsTHashMap.h" 16 #include "nsWrapperCache.h" 17 18 class nsIGlobalObject; 19 class nsQueryJSActor; 20 21 namespace mozilla { 22 class ErrorResult; 23 24 namespace dom { 25 26 namespace ipc { 27 class StructuredCloneData; 28 } 29 30 class JSActorManager; 31 class JSActorMessageMeta; 32 class QueryPromiseHandler; 33 34 enum class JSActorMessageKind { 35 Message, 36 Query, 37 QueryResolve, 38 QueryReject, 39 EndGuard_, 40 }; 41 42 // Common base class for JSWindowActor{Parent,Child}. 43 class JSActor : public nsISupports, public nsWrapperCache { 44 public: 45 NS_DECL_CYCLE_COLLECTING_ISUPPORTS 46 NS_DECL_CYCLE_COLLECTION_WRAPPERCACHE_CLASS(JSActor) 47 48 explicit JSActor(nsISupports* aGlobal = nullptr); 49 50 const nsCString& Name() const { return mName; } 51 void GetName(nsCString& aName) { aName = Name(); } 52 53 void SendAsyncMessage(JSContext* aCx, const nsAString& aMessageName, 54 JS::Handle<JS::Value> aObj, 55 JS::Handle<JS::Value> aTransfers, ErrorResult& aRv); 56 57 already_AddRefed<Promise> SendQuery(JSContext* aCx, 58 const nsAString& aMessageName, 59 JS::Handle<JS::Value> aObj, 60 ErrorResult& aRv); 61 62 nsIGlobalObject* GetParentObject() const { return mGlobal; }; 63 64 protected: 65 // Send the message described by the structured clone data |aData|, and the 66 // message metadata |aMetadata|. The underlying transport should call the 67 // |ReceiveMessage| method on the other side asynchronously. 68 virtual void SendRawMessage(const JSActorMessageMeta& aMetadata, 69 JSIPCValue&& aData, 70 UniquePtr<ipc::StructuredCloneData> aStack, 71 ErrorResult& aRv) = 0; 72 73 // Helper method to send an in-process raw message. 74 using OtherSideCallback = std::function<already_AddRefed<JSActorManager>()>; 75 static void SendRawMessageInProcess( 76 const JSActorMessageMeta& aMeta, JSIPCValue&& aData, 77 UniquePtr<ipc::StructuredCloneData> aStack, 78 OtherSideCallback&& aGetOtherSide); 79 80 virtual ~JSActor() = default; 81 82 void Init(const nsACString& aName, bool aSendTyped); 83 84 bool CanSend() const { return mCanSend; } 85 86 void ThrowStateErrorForGetter(const char* aName, ErrorResult& aRv) const; 87 88 void StartDestroy(); 89 void AfterDestroy(); 90 91 enum class CallbackFunction { DidDestroy, ActorCreated }; 92 void InvokeCallback(CallbackFunction callback); 93 94 virtual void ClearManager() = 0; 95 96 private: 97 friend class JSActorManager; 98 friend class ::nsQueryJSActor; // for QueryInterfaceActor 99 100 nsresult QueryInterfaceActor(const nsIID& aIID, void** aPtr); 101 102 // Called by JSActorManager when they receive raw message data destined for 103 // this actor. 104 void ReceiveMessage(JSContext* aCx, const JSActorMessageMeta& aMetadata, 105 JS::Handle<JS::Value> aData, ErrorResult& aRv); 106 void ReceiveQuery(JSContext* aCx, const JSActorMessageMeta& aMetadata, 107 JS::Handle<JS::Value> aData, ErrorResult& aRv); 108 void ReceiveQueryReply(JSContext* aCx, const JSActorMessageMeta& aMetadata, 109 JS::Handle<JS::Value> aData, ErrorResult& aRv); 110 111 // Call the actual `ReceiveMessage` method, and get the return value. 112 void CallReceiveMessage(JSContext* aCx, const JSActorMessageMeta& aMetadata, 113 JS::Handle<JS::Value> aData, 114 JS::MutableHandle<JS::Value> aRetVal, 115 ErrorResult& aRv); 116 117 // Helper object used while processing query messages to send the final reply 118 // message. 119 class QueryHandler final : public PromiseNativeHandler { 120 public: 121 NS_DECL_CYCLE_COLLECTING_ISUPPORTS_FINAL 122 NS_DECL_CYCLE_COLLECTION_CLASS(QueryHandler) 123 124 QueryHandler(JSActor* aActor, const JSActorMessageMeta& aMetadata, 125 Promise* aPromise); 126 127 void RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue, 128 ErrorResult& aRv) override; 129 130 void ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue, 131 ErrorResult& aRv) override; 132 133 private: 134 ~QueryHandler() = default; 135 136 void SendReply(JSContext* aCx, JSActorMessageKind aKind, 137 JSIPCValue&& aData); 138 139 RefPtr<JSActor> mActor; 140 RefPtr<Promise> mPromise; 141 nsString mMessageName; 142 uint64_t mQueryId; 143 }; 144 145 // A query which hasn't been resolved yet, along with metadata about what 146 // query the promise is for. 147 struct PendingQuery { 148 RefPtr<Promise> mPromise; 149 nsString mMessageName; 150 }; 151 152 nsCOMPtr<nsIGlobalObject> mGlobal; 153 nsCOMPtr<nsISupports> mWrappedJS; 154 nsCString mName; 155 nsTHashMap<nsUint64HashKey, PendingQuery> mPendingQueries; 156 uint64_t mNextQueryId = 0; 157 bool mCanSend = true; 158 159 // If this is false, the receiver won't be doing type checking, so 160 // use structured clone when sending. The security of the receiver does not 161 // depend on this value, because it will make its own independent judgment 162 // about whether the message needs to be typed. 163 bool mSendTyped = true; 164 }; 165 166 } // namespace dom 167 } // namespace mozilla 168 169 namespace IPC { 170 171 template <> 172 struct ParamTraits<mozilla::dom::JSActorMessageKind> 173 : public ContiguousEnumSerializer< 174 mozilla::dom::JSActorMessageKind, 175 mozilla::dom::JSActorMessageKind::Message, 176 mozilla::dom::JSActorMessageKind::EndGuard_> {}; 177 178 } // namespace IPC 179 180 #endif // !defined(mozilla_dom_JSActor_h)