1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "extensions/renderer/console.h"
6
7 #include "base/compiler_specific.h"
8 #include "base/debug/alias.h"
9 #include "base/lazy_instance.h"
10 #include "base/macros.h"
11 #include "base/strings/string_util.h"
12 #include "base/strings/stringprintf.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "extensions/renderer/get_script_context.h"
15 #include "extensions/renderer/script_context.h"
16 #include "extensions/renderer/script_context_set.h"
17 #include "extensions/renderer/v8_helpers.h"
18 #include "extensions/renderer/worker_thread_dispatcher.h"
19 #include "gin/converter.h"
20 #include "gin/per_isolate_data.h"
21 #include "third_party/blink/public/web/web_console_message.h"
22
23 namespace extensions {
24 namespace console {
25
26 namespace {
27
28 // Writes |message| to stack to show up in minidump, then crashes.
CheckWithMinidump(const std::string & message)29 void CheckWithMinidump(const std::string& message) {
30 DEBUG_ALIAS_FOR_CSTR(minidump, message.c_str(), 1024);
31 CHECK(false) << message;
32 }
33
BoundLogMethodCallback(const v8::FunctionCallbackInfo<v8::Value> & info)34 void BoundLogMethodCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
35 std::string message;
36 for (int i = 0; i < info.Length(); ++i) {
37 if (i > 0)
38 message += " ";
39 message += *v8::String::Utf8Value(info.GetIsolate(), info[i]);
40 }
41
42 ScriptContext* script_context =
43 GetScriptContextFromV8Context(info.GetIsolate()->GetCurrentContext());
44
45 // TODO(devlin): Consider (D)CHECK(script_context)
46 const auto level = static_cast<blink::mojom::ConsoleMessageLevel>(
47 info.Data().As<v8::Int32>()->Value());
48 AddMessage(script_context, level, message);
49 }
50
51 gin::WrapperInfo kWrapperInfo = {gin::kEmbedderNativeGin};
52
53 } // namespace
54
Fatal(ScriptContext * context,const std::string & message)55 void Fatal(ScriptContext* context, const std::string& message) {
56 AddMessage(context, blink::mojom::ConsoleMessageLevel::kError, message);
57 CheckWithMinidump(message);
58 }
59
AddMessage(ScriptContext * script_context,blink::mojom::ConsoleMessageLevel level,const std::string & message)60 void AddMessage(ScriptContext* script_context,
61 blink::mojom::ConsoleMessageLevel level,
62 const std::string& message) {
63 if (!script_context) {
64 LOG(WARNING) << "Could not log \"" << message
65 << "\": no ScriptContext found";
66 return;
67 }
68
69 if (!script_context->is_valid()) {
70 LOG(WARNING) << "Could not log \"" << message
71 << "\": ScriptContext invalidated.";
72 return;
73 }
74
75 blink::WebConsoleMessage web_console_message(
76 level, blink::WebString::FromUTF8(message));
77 blink::WebConsoleMessage::LogWebConsoleMessage(script_context->v8_context(),
78 web_console_message);
79 }
80
AsV8Object(v8::Isolate * isolate)81 v8::Local<v8::Object> AsV8Object(v8::Isolate* isolate) {
82 v8::EscapableHandleScope handle_scope(isolate);
83 gin::PerIsolateData* data = gin::PerIsolateData::From(isolate);
84 v8::Local<v8::ObjectTemplate> templ = data->GetObjectTemplate(&kWrapperInfo);
85 if (templ.IsEmpty()) {
86 templ = v8::ObjectTemplate::New(isolate);
87 static const struct {
88 const char* name;
89 blink::mojom::ConsoleMessageLevel level;
90 } methods[] = {
91 {"debug", blink::mojom::ConsoleMessageLevel::kVerbose},
92 {"log", blink::mojom::ConsoleMessageLevel::kInfo},
93 {"warn", blink::mojom::ConsoleMessageLevel::kWarning},
94 {"error", blink::mojom::ConsoleMessageLevel::kError},
95 };
96 for (const auto& method : methods) {
97 v8::Local<v8::FunctionTemplate> function = v8::FunctionTemplate::New(
98 isolate, BoundLogMethodCallback,
99 v8::Integer::New(isolate, static_cast<int>(method.level)));
100 function->RemovePrototype();
101 templ->Set(gin::StringToSymbol(isolate, method.name), function);
102 }
103 data->SetObjectTemplate(&kWrapperInfo, templ);
104 }
105 return handle_scope.Escape(
106 templ->NewInstance(isolate->GetCurrentContext()).ToLocalChecked());
107 }
108
109 } // namespace console
110 } // namespace extensions
111