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(), v8::NewStringType::kNormal)
53 .ToLocalChecked());
54 }
55
56 // External JavaScript API for returning a report
GetReport(const FunctionCallbackInfo<Value> & info)57 void GetReport(const FunctionCallbackInfo<Value>& info) {
58 Environment* env = Environment::GetCurrent(info);
59 Isolate* isolate = env->isolate();
60 HandleScope scope(isolate);
61 Local<Object> error;
62 std::ostringstream out;
63
64 CHECK_EQ(info.Length(), 1);
65 if (!info[0].IsEmpty() && info[0]->IsObject())
66 error = info[0].As<Object>();
67 else
68 error = Local<Object>();
69
70 GetNodeReport(
71 isolate, env, "JavaScript API", __func__, error, out);
72
73 // Return value is the contents of a report as a string.
74 info.GetReturnValue().Set(String::NewFromUtf8(isolate,
75 out.str().c_str(),
76 v8::NewStringType::kNormal)
77 .ToLocalChecked());
78 }
79
GetCompact(const FunctionCallbackInfo<Value> & info)80 static void GetCompact(const FunctionCallbackInfo<Value>& info) {
81 node::Mutex::ScopedLock lock(node::per_process::cli_options_mutex);
82 info.GetReturnValue().Set(node::per_process::cli_options->report_compact);
83 }
84
SetCompact(const FunctionCallbackInfo<Value> & info)85 static void SetCompact(const FunctionCallbackInfo<Value>& info) {
86 node::Mutex::ScopedLock lock(node::per_process::cli_options_mutex);
87 Environment* env = Environment::GetCurrent(info);
88 Isolate* isolate = env->isolate();
89 bool compact = info[0]->ToBoolean(isolate)->Value();
90 node::per_process::cli_options->report_compact = compact;
91 }
92
GetDirectory(const FunctionCallbackInfo<Value> & info)93 static void GetDirectory(const FunctionCallbackInfo<Value>& info) {
94 node::Mutex::ScopedLock lock(node::per_process::cli_options_mutex);
95 Environment* env = Environment::GetCurrent(info);
96 std::string directory = node::per_process::cli_options->report_directory;
97 auto result = String::NewFromUtf8(env->isolate(),
98 directory.c_str(),
99 v8::NewStringType::kNormal);
100 info.GetReturnValue().Set(result.ToLocalChecked());
101 }
102
SetDirectory(const FunctionCallbackInfo<Value> & info)103 static void SetDirectory(const FunctionCallbackInfo<Value>& info) {
104 node::Mutex::ScopedLock lock(node::per_process::cli_options_mutex);
105 Environment* env = Environment::GetCurrent(info);
106 CHECK(info[0]->IsString());
107 Utf8Value dir(env->isolate(), info[0].As<String>());
108 node::per_process::cli_options->report_directory = *dir;
109 }
110
GetFilename(const FunctionCallbackInfo<Value> & info)111 static void GetFilename(const FunctionCallbackInfo<Value>& info) {
112 node::Mutex::ScopedLock lock(node::per_process::cli_options_mutex);
113 Environment* env = Environment::GetCurrent(info);
114 std::string filename = node::per_process::cli_options->report_filename;
115 auto result = String::NewFromUtf8(env->isolate(),
116 filename.c_str(),
117 v8::NewStringType::kNormal);
118 info.GetReturnValue().Set(result.ToLocalChecked());
119 }
120
SetFilename(const FunctionCallbackInfo<Value> & info)121 static void SetFilename(const FunctionCallbackInfo<Value>& info) {
122 node::Mutex::ScopedLock lock(node::per_process::cli_options_mutex);
123 Environment* env = Environment::GetCurrent(info);
124 CHECK(info[0]->IsString());
125 Utf8Value name(env->isolate(), info[0].As<String>());
126 node::per_process::cli_options->report_filename = *name;
127 }
128
GetSignal(const FunctionCallbackInfo<Value> & info)129 static void GetSignal(const FunctionCallbackInfo<Value>& info) {
130 Environment* env = Environment::GetCurrent(info);
131 std::string signal = env->isolate_data()->options()->report_signal;
132 auto result = String::NewFromUtf8(env->isolate(),
133 signal.c_str(),
134 v8::NewStringType::kNormal);
135 info.GetReturnValue().Set(result.ToLocalChecked());
136 }
137
SetSignal(const FunctionCallbackInfo<Value> & info)138 static void SetSignal(const FunctionCallbackInfo<Value>& info) {
139 Environment* env = Environment::GetCurrent(info);
140 CHECK(info[0]->IsString());
141 Utf8Value signal(env->isolate(), info[0].As<String>());
142 env->isolate_data()->options()->report_signal = *signal;
143 }
144
ShouldReportOnFatalError(const FunctionCallbackInfo<Value> & info)145 static void ShouldReportOnFatalError(const FunctionCallbackInfo<Value>& info) {
146 Mutex::ScopedLock lock(node::per_process::cli_options_mutex);
147 info.GetReturnValue().Set(
148 node::per_process::cli_options->report_on_fatalerror);
149 }
150
SetReportOnFatalError(const FunctionCallbackInfo<Value> & info)151 static void SetReportOnFatalError(const FunctionCallbackInfo<Value>& info) {
152 CHECK(info[0]->IsBoolean());
153 Mutex::ScopedLock lock(node::per_process::cli_options_mutex);
154 node::per_process::cli_options->report_on_fatalerror = info[0]->IsTrue();
155 }
156
ShouldReportOnSignal(const FunctionCallbackInfo<Value> & info)157 static void ShouldReportOnSignal(const FunctionCallbackInfo<Value>& info) {
158 Environment* env = Environment::GetCurrent(info);
159 info.GetReturnValue().Set(env->isolate_data()->options()->report_on_signal);
160 }
161
SetReportOnSignal(const FunctionCallbackInfo<Value> & info)162 static void SetReportOnSignal(const FunctionCallbackInfo<Value>& info) {
163 Environment* env = Environment::GetCurrent(info);
164 CHECK(info[0]->IsBoolean());
165 env->isolate_data()->options()->report_on_signal = info[0]->IsTrue();
166 }
167
ShouldReportOnUncaughtException(const FunctionCallbackInfo<Value> & info)168 static void ShouldReportOnUncaughtException(
169 const FunctionCallbackInfo<Value>& info) {
170 Environment* env = Environment::GetCurrent(info);
171 info.GetReturnValue().Set(
172 env->isolate_data()->options()->report_uncaught_exception);
173 }
174
SetReportOnUncaughtException(const FunctionCallbackInfo<Value> & info)175 static void SetReportOnUncaughtException(
176 const FunctionCallbackInfo<Value>& info) {
177 Environment* env = Environment::GetCurrent(info);
178 CHECK(info[0]->IsBoolean());
179 env->isolate_data()->options()->report_uncaught_exception = info[0]->IsTrue();
180 }
181
Initialize(Local<Object> exports,Local<Value> unused,Local<Context> context,void * priv)182 static void Initialize(Local<Object> exports,
183 Local<Value> unused,
184 Local<Context> context,
185 void* priv) {
186 Environment* env = Environment::GetCurrent(context);
187
188 env->SetMethod(exports, "writeReport", WriteReport);
189 env->SetMethod(exports, "getReport", GetReport);
190 env->SetMethod(exports, "getCompact", GetCompact);
191 env->SetMethod(exports, "setCompact", SetCompact);
192 env->SetMethod(exports, "getDirectory", GetDirectory);
193 env->SetMethod(exports, "setDirectory", SetDirectory);
194 env->SetMethod(exports, "getFilename", GetFilename);
195 env->SetMethod(exports, "setFilename", SetFilename);
196 env->SetMethod(exports, "getSignal", GetSignal);
197 env->SetMethod(exports, "setSignal", SetSignal);
198 env->SetMethod(exports, "shouldReportOnFatalError", ShouldReportOnFatalError);
199 env->SetMethod(exports, "setReportOnFatalError", SetReportOnFatalError);
200 env->SetMethod(exports, "shouldReportOnSignal", ShouldReportOnSignal);
201 env->SetMethod(exports, "setReportOnSignal", SetReportOnSignal);
202 env->SetMethod(exports, "shouldReportOnUncaughtException",
203 ShouldReportOnUncaughtException);
204 env->SetMethod(exports, "setReportOnUncaughtException",
205 SetReportOnUncaughtException);
206 }
207
208 } // namespace report
209
210 NODE_MODULE_CONTEXT_AWARE_INTERNAL(report, report::Initialize)
211