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 #include "mozilla/dom/ProcessActor.h"
8 
9 #include "nsContentUtils.h"
10 #include "mozJSComponentLoader.h"
11 #include "mozilla/ContentBlockingAllowList.h"
12 #include "mozilla/Logging.h"
13 #include "mozilla/dom/JSActorService.h"
14 #include "mozilla/dom/JSProcessActorParent.h"
15 #include "mozilla/dom/JSProcessActorChild.h"
16 
17 namespace mozilla {
18 namespace dom {
19 
ConstructActor(const nsACString & aName,JS::MutableHandleObject aActor,ErrorResult & aRv)20 void ProcessActor::ConstructActor(const nsACString& aName,
21                                   JS::MutableHandleObject aActor,
22                                   ErrorResult& aRv) {
23   MOZ_ASSERT(nsContentUtils::IsSafeToRunScript());
24 
25   JSActor::Type actorType = GetSide();
26   MOZ_ASSERT_IF(actorType == JSActor::Type::Parent, XRE_IsParentProcess());
27 
28   // Constructing an actor requires a running script, so push an AutoEntryScript
29   // onto the stack.
30   AutoEntryScript aes(xpc::PrivilegedJunkScope(), "ProcessActor construction");
31   JSContext* cx = aes.cx();
32 
33   RefPtr<JSActorService> actorSvc = JSActorService::GetSingleton();
34   if (!actorSvc) {
35     aRv.ThrowInvalidStateError(
36         "While constructing JSProcessActor, could not acquire JSActorService.");
37     return;
38   }
39 
40   RefPtr<JSProcessActorProtocol> proto =
41       actorSvc->GetJSProcessActorProtocol(aName);
42   if (!proto) {
43     aRv.ThrowNotFoundError(nsPrintfCString("No such JSProcessActor '%s'",
44                                            PromiseFlatCString(aName).get()));
45     return;
46   }
47 
48   if (!proto->Matches(GetRemoteType())) {
49     aRv.ThrowTypeMismatchError(
50         nsPrintfCString("JSProcessActor '%s' does not match this process",
51                         PromiseFlatCString(aName).get()));
52     return;
53   }
54 
55   // Load the module using mozJSComponentLoader.
56   RefPtr<mozJSComponentLoader> loader = mozJSComponentLoader::Get();
57   MOZ_ASSERT(loader);
58 
59   JS::RootedObject global(cx);
60   JS::RootedObject exports(cx);
61 
62   const JSProcessActorProtocol::Sided* side;
63   if (actorType == JSActor::Type::Parent) {
64     side = &proto->Parent();
65   } else {
66     side = &proto->Child();
67   }
68 
69   // Support basic functionally such as SendAsyncMessage and SendQuery for
70   // unspecified moduleURI.
71   if (!side->mModuleURI) {
72     RefPtr<JSActor> actor;
73     if (actorType == JSActor::Type::Parent) {
74       actor = new JSProcessActorParent();
75     } else {
76       actor = new JSProcessActorChild();
77     }
78 
79     JS::Rooted<JS::Value> wrapper(cx);
80     if (!ToJSValue(cx, actor, &wrapper)) {
81       aRv.NoteJSContextException(cx);
82       return;
83     }
84 
85     MOZ_ASSERT(wrapper.isObject());
86     aActor.set(&wrapper.toObject());
87     return;
88   }
89 
90   aRv = loader->Import(cx, side->mModuleURI.ref(), &global, &exports);
91   if (aRv.Failed()) {
92     return;
93   }
94 
95   MOZ_ASSERT(exports, "null exports!");
96 
97   // Load the specific property from our module.
98   JS::RootedValue ctor(cx);
99   nsAutoCString ctorName(aName);
100   ctorName.Append(actorType == JSActor::Type::Parent
101                       ? NS_LITERAL_CSTRING("Parent")
102                       : NS_LITERAL_CSTRING("Child"));
103   if (!JS_GetProperty(cx, exports, ctorName.get(), &ctor)) {
104     aRv.NoteJSContextException(cx);
105     return;
106   }
107 
108   if (NS_WARN_IF(!ctor.isObject())) {
109     nsPrintfCString message("Could not find actor constructor '%s'",
110                             PromiseFlatCString(ctorName).get());
111     aRv.ThrowNotFoundError(message);
112     return;
113   }
114 
115   // Invoke the constructor loaded from the module.
116   if (!JS::Construct(cx, ctor, JS::HandleValueArray::empty(), aActor)) {
117     aRv.NoteJSContextException(cx);
118     return;
119   }
120 }
121 
122 }  // namespace dom
123 }  // namespace mozilla
124