1 #include "env-inl.h"
2 #include "node_errors.h"
3 #include "node_external_reference.h"
4 #include "node_internals.h"
5 #include "node_metadata.h"
6 #include "node_options-inl.h"
7 #include "node_process-inl.h"
8 #include "node_realm-inl.h"
9 #include "node_revert.h"
10 #include "util-inl.h"
11
12 #include <climits> // PATH_MAX
13
14 namespace node {
15 using v8::Context;
16 using v8::DEFAULT;
17 using v8::EscapableHandleScope;
18 using v8::Function;
19 using v8::FunctionCallbackInfo;
20 using v8::FunctionTemplate;
21 using v8::Integer;
22 using v8::Isolate;
23 using v8::Local;
24 using v8::MaybeLocal;
25 using v8::Name;
26 using v8::NewStringType;
27 using v8::None;
28 using v8::Object;
29 using v8::PropertyCallbackInfo;
30 using v8::SideEffectType;
31 using v8::String;
32 using v8::Value;
33
ProcessTitleGetter(Local<Name> property,const PropertyCallbackInfo<Value> & info)34 static void ProcessTitleGetter(Local<Name> property,
35 const PropertyCallbackInfo<Value>& info) {
36 std::string title = GetProcessTitle("node");
37 info.GetReturnValue().Set(
38 String::NewFromUtf8(info.GetIsolate(), title.data(),
39 NewStringType::kNormal, title.size())
40 .ToLocalChecked());
41 }
42
ProcessTitleSetter(Local<Name> property,Local<Value> value,const PropertyCallbackInfo<void> & info)43 static void ProcessTitleSetter(Local<Name> property,
44 Local<Value> value,
45 const PropertyCallbackInfo<void>& info) {
46 node::Utf8Value title(info.GetIsolate(), value);
47 TRACE_EVENT_METADATA1(
48 "__metadata", "process_name", "name", TRACE_STR_COPY(*title));
49 uv_set_process_title(*title);
50 }
51
DebugPortGetter(Local<Name> property,const PropertyCallbackInfo<Value> & info)52 static void DebugPortGetter(Local<Name> property,
53 const PropertyCallbackInfo<Value>& info) {
54 Environment* env = Environment::GetCurrent(info);
55 ExclusiveAccess<HostPort>::Scoped host_port(env->inspector_host_port());
56 int port = host_port->port();
57 info.GetReturnValue().Set(port);
58 }
59
DebugPortSetter(Local<Name> property,Local<Value> value,const PropertyCallbackInfo<void> & info)60 static void DebugPortSetter(Local<Name> property,
61 Local<Value> value,
62 const PropertyCallbackInfo<void>& info) {
63 Environment* env = Environment::GetCurrent(info);
64 int32_t port = value->Int32Value(env->context()).FromMaybe(0);
65
66 if ((port != 0 && port < 1024) || port > 65535) {
67 return THROW_ERR_OUT_OF_RANGE(
68 env,
69 "process.debugPort must be 0 or in range 1024 to 65535");
70 }
71
72 ExclusiveAccess<HostPort>::Scoped host_port(env->inspector_host_port());
73 host_port->set_port(static_cast<int>(port));
74 }
75
GetParentProcessId(Local<Name> property,const PropertyCallbackInfo<Value> & info)76 static void GetParentProcessId(Local<Name> property,
77 const PropertyCallbackInfo<Value>& info) {
78 info.GetReturnValue().Set(uv_os_getppid());
79 }
80
CreateProcessObject(Realm * realm)81 MaybeLocal<Object> CreateProcessObject(Realm* realm) {
82 Isolate* isolate = realm->isolate();
83 EscapableHandleScope scope(isolate);
84 Local<Context> context = realm->context();
85
86 Local<FunctionTemplate> process_template = FunctionTemplate::New(isolate);
87 process_template->SetClassName(realm->env()->process_string());
88 Local<Function> process_ctor;
89 Local<Object> process;
90 if (!process_template->GetFunction(context).ToLocal(&process_ctor) ||
91 !process_ctor->NewInstance(context).ToLocal(&process)) {
92 return MaybeLocal<Object>();
93 }
94
95 // process[exiting_aliased_Uint32Array]
96 if (process
97 ->SetPrivate(context,
98 realm->env()->exiting_aliased_Uint32Array(),
99 realm->env()->exiting().GetJSArray())
100 .IsNothing()) {
101 return {};
102 }
103
104 // process.version
105 READONLY_PROPERTY(
106 process, "version", FIXED_ONE_BYTE_STRING(isolate, NODE_VERSION));
107
108 Local<Object> versions = Object::New(isolate);
109 // Node.js version is always on the top
110 READONLY_STRING_PROPERTY(
111 versions, "node", per_process::metadata.versions.node);
112
113 #define V(key) +1
114 std::pair<std::string_view, std::string_view>
115 versions_array[NODE_VERSIONS_KEYS(V)];
116 #undef V
117 auto* slot = &versions_array[0];
118
119 #define V(key) \
120 do { \
121 *slot++ = std::pair<std::string_view, std::string_view>( \
122 #key, per_process::metadata.versions.key); \
123 } while (0);
124 NODE_VERSIONS_KEYS(V)
125 #undef V
126
127 std::sort(&versions_array[0],
128 &versions_array[arraysize(versions_array)],
129 [](auto& a, auto& b) { return a.first < b.first; });
130
131 for (const auto& version : versions_array) {
132 versions
133 ->DefineOwnProperty(
134 context,
135 OneByteString(isolate, version.first.data(), version.first.size()),
136 OneByteString(
137 isolate, version.second.data(), version.second.size()),
138 v8::ReadOnly)
139 .Check();
140 }
141
142 // process.versions
143 READONLY_PROPERTY(process, "versions", versions);
144
145 // process.arch
146 READONLY_STRING_PROPERTY(process, "arch", per_process::metadata.arch);
147
148 // process.platform
149 READONLY_STRING_PROPERTY(process, "platform", per_process::metadata.platform);
150
151 // process.release
152 Local<Object> release = Object::New(isolate);
153 READONLY_PROPERTY(process, "release", release);
154 READONLY_STRING_PROPERTY(release, "name", per_process::metadata.release.name);
155 #if NODE_VERSION_IS_LTS
156 READONLY_STRING_PROPERTY(release, "lts", per_process::metadata.release.lts);
157 #endif // NODE_VERSION_IS_LTS
158
159 #ifdef NODE_HAS_RELEASE_URLS
160 READONLY_STRING_PROPERTY(
161 release, "sourceUrl", per_process::metadata.release.source_url);
162 READONLY_STRING_PROPERTY(
163 release, "headersUrl", per_process::metadata.release.headers_url);
164 #ifdef _WIN32
165 READONLY_STRING_PROPERTY(
166 release, "libUrl", per_process::metadata.release.lib_url);
167 #endif // _WIN32
168 #endif // NODE_HAS_RELEASE_URLS
169
170 // process._rawDebug: may be overwritten later in JS land, but should be
171 // available from the beginning for debugging purposes
172 SetMethod(context, process, "_rawDebug", RawDebug);
173
174 return scope.Escape(process);
175 }
176
PatchProcessObject(const FunctionCallbackInfo<Value> & args)177 void PatchProcessObject(const FunctionCallbackInfo<Value>& args) {
178 Isolate* isolate = args.GetIsolate();
179 Local<Context> context = isolate->GetCurrentContext();
180 Environment* env = Environment::GetCurrent(context);
181 CHECK(args[0]->IsObject());
182 Local<Object> process = args[0].As<Object>();
183
184 // process.title
185 CHECK(process
186 ->SetAccessor(
187 context,
188 FIXED_ONE_BYTE_STRING(isolate, "title"),
189 ProcessTitleGetter,
190 env->owns_process_state() ? ProcessTitleSetter : nullptr,
191 Local<Value>(),
192 DEFAULT,
193 None,
194 SideEffectType::kHasNoSideEffect)
195 .FromJust());
196
197 // process.argv
198 process->Set(context,
199 FIXED_ONE_BYTE_STRING(isolate, "argv"),
200 ToV8Value(context, env->argv()).ToLocalChecked()).Check();
201
202 // process.execArgv
203 process->Set(context,
204 FIXED_ONE_BYTE_STRING(isolate, "execArgv"),
205 ToV8Value(context, env->exec_argv())
206 .ToLocalChecked()).Check();
207
208 READONLY_PROPERTY(process, "pid",
209 Integer::New(isolate, uv_os_getpid()));
210
211 CHECK(process->SetAccessor(context,
212 FIXED_ONE_BYTE_STRING(isolate, "ppid"),
213 GetParentProcessId).FromJust());
214
215 // --security-revert flags
216 #define V(code, _, __) \
217 do { \
218 if (IsReverted(SECURITY_REVERT_ ## code)) { \
219 READONLY_PROPERTY(process, "REVERT_" #code, True(isolate)); \
220 } \
221 } while (0);
222 SECURITY_REVERSIONS(V)
223 #undef V
224
225 // process.execPath
226 process
227 ->Set(context,
228 FIXED_ONE_BYTE_STRING(isolate, "execPath"),
229 String::NewFromUtf8(isolate,
230 env->exec_path().c_str(),
231 NewStringType::kInternalized,
232 env->exec_path().size())
233 .ToLocalChecked())
234 .Check();
235
236 // process.debugPort
237 CHECK(process
238 ->SetAccessor(context,
239 FIXED_ONE_BYTE_STRING(isolate, "debugPort"),
240 DebugPortGetter,
241 env->owns_process_state() ? DebugPortSetter : nullptr,
242 Local<Value>())
243 .FromJust());
244 }
245
RegisterProcessExternalReferences(ExternalReferenceRegistry * registry)246 void RegisterProcessExternalReferences(ExternalReferenceRegistry* registry) {
247 registry->Register(RawDebug);
248 registry->Register(GetParentProcessId);
249 registry->Register(DebugPortSetter);
250 registry->Register(DebugPortGetter);
251 registry->Register(ProcessTitleSetter);
252 registry->Register(ProcessTitleGetter);
253 }
254
255 } // namespace node
256
257 NODE_BINDING_EXTERNAL_REFERENCE(process_object,
258 node::RegisterProcessExternalReferences)
259