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