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