1 #include "env.h"
2 #include "node_errors.h"
3 #include "node_external_reference.h"
4 #include "node_internals.h"
5 #include "node_options.h"
6 #include "node_report.h"
7 #include "util-inl.h"
8
9 #include "handle_wrap.h"
10 #include "node_buffer.h"
11 #include "stream_base-inl.h"
12 #include "stream_wrap.h"
13
14 #include <v8.h>
15 #include <atomic>
16 #include <sstream>
17
18 namespace node {
19 namespace report {
20 using v8::Context;
21 using v8::FunctionCallbackInfo;
22 using v8::HandleScope;
23 using v8::Isolate;
24 using v8::Local;
25 using v8::Object;
26 using v8::String;
27 using v8::Value;
28
WriteReport(const FunctionCallbackInfo<Value> & info)29 void WriteReport(const FunctionCallbackInfo<Value>& info) {
30 Environment* env = Environment::GetCurrent(info);
31 Isolate* isolate = env->isolate();
32 HandleScope scope(isolate);
33 std::string filename;
34 Local<Value> error;
35
36 CHECK_EQ(info.Length(), 4);
37 String::Utf8Value message(isolate, info[0].As<String>());
38 String::Utf8Value trigger(isolate, info[1].As<String>());
39
40 if (info[2]->IsString())
41 filename = *String::Utf8Value(isolate, info[2]);
42 if (!info[3].IsEmpty())
43 error = info[3];
44 else
45 error = Local<Value>();
46
47 filename = TriggerNodeReport(env, *message, *trigger, filename, error);
48 // Return value is the report filename
49 info.GetReturnValue().Set(
50 String::NewFromUtf8(isolate, filename.c_str()).ToLocalChecked());
51 }
52
53 // External JavaScript API for returning a report
GetReport(const FunctionCallbackInfo<Value> & info)54 void GetReport(const FunctionCallbackInfo<Value>& info) {
55 Environment* env = Environment::GetCurrent(info);
56 Isolate* isolate = env->isolate();
57 HandleScope scope(isolate);
58 Local<Object> error;
59 std::ostringstream out;
60
61 CHECK_EQ(info.Length(), 1);
62 if (!info[0].IsEmpty() && info[0]->IsObject())
63 error = info[0].As<Object>();
64 else
65 error = Local<Object>();
66
67 GetNodeReport(env, "JavaScript API", __func__, error, out);
68
69 // Return value is the contents of a report as a string.
70 info.GetReturnValue().Set(
71 String::NewFromUtf8(isolate, out.str().c_str()).ToLocalChecked());
72 }
73
GetCompact(const FunctionCallbackInfo<Value> & info)74 static void GetCompact(const FunctionCallbackInfo<Value>& info) {
75 Mutex::ScopedLock lock(per_process::cli_options_mutex);
76 info.GetReturnValue().Set(per_process::cli_options->report_compact);
77 }
78
SetCompact(const FunctionCallbackInfo<Value> & info)79 static void SetCompact(const FunctionCallbackInfo<Value>& info) {
80 Mutex::ScopedLock lock(per_process::cli_options_mutex);
81 Environment* env = Environment::GetCurrent(info);
82 Isolate* isolate = env->isolate();
83 bool compact = info[0]->ToBoolean(isolate)->Value();
84 per_process::cli_options->report_compact = compact;
85 }
86
GetDirectory(const FunctionCallbackInfo<Value> & info)87 static void GetDirectory(const FunctionCallbackInfo<Value>& info) {
88 Mutex::ScopedLock lock(per_process::cli_options_mutex);
89 Environment* env = Environment::GetCurrent(info);
90 std::string directory = per_process::cli_options->report_directory;
91 auto result = String::NewFromUtf8(env->isolate(), directory.c_str());
92 info.GetReturnValue().Set(result.ToLocalChecked());
93 }
94
SetDirectory(const FunctionCallbackInfo<Value> & info)95 static void SetDirectory(const FunctionCallbackInfo<Value>& info) {
96 Mutex::ScopedLock lock(per_process::cli_options_mutex);
97 Environment* env = Environment::GetCurrent(info);
98 CHECK(info[0]->IsString());
99 Utf8Value dir(env->isolate(), info[0].As<String>());
100 per_process::cli_options->report_directory = *dir;
101 }
102
GetFilename(const FunctionCallbackInfo<Value> & info)103 static void GetFilename(const FunctionCallbackInfo<Value>& info) {
104 Mutex::ScopedLock lock(per_process::cli_options_mutex);
105 Environment* env = Environment::GetCurrent(info);
106 std::string filename = per_process::cli_options->report_filename;
107 auto result = String::NewFromUtf8(env->isolate(), filename.c_str());
108 info.GetReturnValue().Set(result.ToLocalChecked());
109 }
110
SetFilename(const FunctionCallbackInfo<Value> & info)111 static void SetFilename(const FunctionCallbackInfo<Value>& info) {
112 Mutex::ScopedLock lock(per_process::cli_options_mutex);
113 Environment* env = Environment::GetCurrent(info);
114 CHECK(info[0]->IsString());
115 Utf8Value name(env->isolate(), info[0].As<String>());
116 per_process::cli_options->report_filename = *name;
117 }
118
GetSignal(const FunctionCallbackInfo<Value> & info)119 static void GetSignal(const FunctionCallbackInfo<Value>& info) {
120 Environment* env = Environment::GetCurrent(info);
121 std::string signal = env->isolate_data()->options()->report_signal;
122 auto result = String::NewFromUtf8(env->isolate(), signal.c_str());
123 info.GetReturnValue().Set(result.ToLocalChecked());
124 }
125
SetSignal(const FunctionCallbackInfo<Value> & info)126 static void SetSignal(const FunctionCallbackInfo<Value>& info) {
127 Environment* env = Environment::GetCurrent(info);
128 CHECK(info[0]->IsString());
129 Utf8Value signal(env->isolate(), info[0].As<String>());
130 env->isolate_data()->options()->report_signal = *signal;
131 }
132
ShouldReportOnFatalError(const FunctionCallbackInfo<Value> & info)133 static void ShouldReportOnFatalError(const FunctionCallbackInfo<Value>& info) {
134 Mutex::ScopedLock lock(per_process::cli_options_mutex);
135 info.GetReturnValue().Set(per_process::cli_options->report_on_fatalerror);
136 }
137
SetReportOnFatalError(const FunctionCallbackInfo<Value> & info)138 static void SetReportOnFatalError(const FunctionCallbackInfo<Value>& info) {
139 CHECK(info[0]->IsBoolean());
140 Mutex::ScopedLock lock(per_process::cli_options_mutex);
141 per_process::cli_options->report_on_fatalerror = info[0]->IsTrue();
142 }
143
ShouldReportOnSignal(const FunctionCallbackInfo<Value> & info)144 static void ShouldReportOnSignal(const FunctionCallbackInfo<Value>& info) {
145 Environment* env = Environment::GetCurrent(info);
146 info.GetReturnValue().Set(env->isolate_data()->options()->report_on_signal);
147 }
148
SetReportOnSignal(const FunctionCallbackInfo<Value> & info)149 static void SetReportOnSignal(const FunctionCallbackInfo<Value>& info) {
150 Environment* env = Environment::GetCurrent(info);
151 CHECK(info[0]->IsBoolean());
152 env->isolate_data()->options()->report_on_signal = info[0]->IsTrue();
153 }
154
ShouldReportOnUncaughtException(const FunctionCallbackInfo<Value> & info)155 static void ShouldReportOnUncaughtException(
156 const FunctionCallbackInfo<Value>& info) {
157 Environment* env = Environment::GetCurrent(info);
158 info.GetReturnValue().Set(
159 env->isolate_data()->options()->report_uncaught_exception);
160 }
161
SetReportOnUncaughtException(const FunctionCallbackInfo<Value> & info)162 static void SetReportOnUncaughtException(
163 const FunctionCallbackInfo<Value>& info) {
164 Environment* env = Environment::GetCurrent(info);
165 CHECK(info[0]->IsBoolean());
166 env->isolate_data()->options()->report_uncaught_exception = info[0]->IsTrue();
167 }
168
Initialize(Local<Object> exports,Local<Value> unused,Local<Context> context,void * priv)169 static void Initialize(Local<Object> exports,
170 Local<Value> unused,
171 Local<Context> context,
172 void* priv) {
173 SetMethod(context, exports, "writeReport", WriteReport);
174 SetMethod(context, exports, "getReport", GetReport);
175 SetMethod(context, exports, "getCompact", GetCompact);
176 SetMethod(context, exports, "setCompact", SetCompact);
177 SetMethod(context, exports, "getDirectory", GetDirectory);
178 SetMethod(context, exports, "setDirectory", SetDirectory);
179 SetMethod(context, exports, "getFilename", GetFilename);
180 SetMethod(context, exports, "setFilename", SetFilename);
181 SetMethod(context, exports, "getSignal", GetSignal);
182 SetMethod(context, exports, "setSignal", SetSignal);
183 SetMethod(
184 context, exports, "shouldReportOnFatalError", ShouldReportOnFatalError);
185 SetMethod(context, exports, "setReportOnFatalError", SetReportOnFatalError);
186 SetMethod(context, exports, "shouldReportOnSignal", ShouldReportOnSignal);
187 SetMethod(context, exports, "setReportOnSignal", SetReportOnSignal);
188 SetMethod(context,
189 exports,
190 "shouldReportOnUncaughtException",
191 ShouldReportOnUncaughtException);
192 SetMethod(context,
193 exports,
194 "setReportOnUncaughtException",
195 SetReportOnUncaughtException);
196 }
197
RegisterExternalReferences(ExternalReferenceRegistry * registry)198 void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
199 registry->Register(WriteReport);
200 registry->Register(GetReport);
201 registry->Register(GetCompact);
202 registry->Register(SetCompact);
203 registry->Register(GetDirectory);
204 registry->Register(SetDirectory);
205 registry->Register(GetFilename);
206 registry->Register(SetFilename);
207 registry->Register(GetSignal);
208 registry->Register(SetSignal);
209 registry->Register(ShouldReportOnFatalError);
210 registry->Register(SetReportOnFatalError);
211 registry->Register(ShouldReportOnSignal);
212 registry->Register(SetReportOnSignal);
213 registry->Register(ShouldReportOnUncaughtException);
214 registry->Register(SetReportOnUncaughtException);
215 }
216
217 } // namespace report
218 } // namespace node
219
220 NODE_BINDING_CONTEXT_AWARE_INTERNAL(report, node::report::Initialize)
221 NODE_BINDING_EXTERNAL_REFERENCE(report,
222 node::report::RegisterExternalReferences)
223