1a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch// Copyright 2014 The Chromium Authors. All rights reserved.
22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file.
42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch#include "extensions/renderer/console.h"
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/compiler_specific.h"
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/debug/alias.h"
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/lazy_instance.h"
107d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "base/strings/string_util.h"
117d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "base/strings/stringprintf.h"
12868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/renderer/render_view.h"
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/renderer/render_view_visitor.h"
15010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "extensions/renderer/dispatcher.h"
16010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "extensions/renderer/extension_helper.h"
177d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "third_party/WebKit/public/web/WebConsoleMessage.h"
187d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "third_party/WebKit/public/web/WebFrame.h"
197d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "third_party/WebKit/public/web/WebView.h"
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace extensions {
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace console {
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace {
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Finds the RenderView associated with a context. Note: there will be multiple
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// contexts in each RenderView.
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class ByContextFinder : public content::RenderViewVisitor {
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public:
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  static content::RenderView* Find(v8::Handle<v8::Context> context) {
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ByContextFinder finder(context);
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    content::RenderView::ForEach(&finder);
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return finder.found_;
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private:
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  explicit ByContextFinder(v8::Handle<v8::Context> context)
38a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      : context_(context), found_(NULL) {}
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual bool Visit(content::RenderView* render_view) OVERRIDE {
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ExtensionHelper* helper = ExtensionHelper::Get(render_view);
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (helper &&
430529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        helper->dispatcher()->script_context_set().GetByV8Context(context_)) {
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      found_ = render_view;
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return !found_;
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  v8::Handle<v8::Context> context_;
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  content::RenderView* found_;
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(ByContextFinder);
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Writes |message| to stack to show up in minidump, then crashes.
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void CheckWithMinidump(const std::string& message) {
577dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  char minidump[1024];
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::debug::Alias(&minidump);
59a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  base::snprintf(
60a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      minidump, arraysize(minidump), "e::console: %s", message.c_str());
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  CHECK(false) << message;
622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
64a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)typedef void (*LogMethod)(v8::Handle<v8::Context> context,
65a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)                          const std::string& message);
66a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
67a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)void BoundLogMethodCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
68a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  LogMethod log_method =
69a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      reinterpret_cast<LogMethod>(info.Data().As<v8::External>()->Value());
70a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  std::string message;
71a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  for (int i = 0; i < info.Length(); ++i) {
72a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    if (i > 0)
73a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      message += " ";
74a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    message += *v8::String::Utf8Value(info[i]);
75a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  }
76a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  (*log_method)(info.GetIsolate()->GetCallingContext(), message);
77a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)}
78a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
79f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void BindLogMethod(v8::Isolate* isolate,
80f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                   v8::Local<v8::Object> target,
81a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)                   const std::string& name,
82a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)                   LogMethod log_method) {
83a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  v8::Local<v8::FunctionTemplate> tmpl = v8::FunctionTemplate::New(
84a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      isolate,
85a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      &BoundLogMethodCallback,
86f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      v8::External::New(isolate, reinterpret_cast<void*>(log_method)));
87a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  target->Set(v8::String::NewFromUtf8(isolate, name.c_str()),
88a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)              tmpl->GetFunction());
89a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)}
90a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void Debug(content::RenderView* render_view, const std::string& message) {
942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  AddMessage(render_view, content::CONSOLE_MESSAGE_LEVEL_DEBUG, message);
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void Log(content::RenderView* render_view, const std::string& message) {
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  AddMessage(render_view, content::CONSOLE_MESSAGE_LEVEL_LOG, message);
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void Warn(content::RenderView* render_view, const std::string& message) {
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  AddMessage(render_view, content::CONSOLE_MESSAGE_LEVEL_WARNING, message);
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void Error(content::RenderView* render_view, const std::string& message) {
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  AddMessage(render_view, content::CONSOLE_MESSAGE_LEVEL_ERROR, message);
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void Fatal(content::RenderView* render_view, const std::string& message) {
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Error(render_view, message);
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  CheckWithMinidump(message);
1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AddMessage(content::RenderView* render_view,
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                content::ConsoleMessageLevel level,
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                const std::string& message) {
117f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  blink::WebView* web_view = render_view->GetWebView();
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!web_view || !web_view->mainFrame())
1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
120f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  blink::WebConsoleMessage::Level target_level =
121f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      blink::WebConsoleMessage::LevelLog;
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  switch (level) {
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case content::CONSOLE_MESSAGE_LEVEL_DEBUG:
124f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      target_level = blink::WebConsoleMessage::LevelDebug;
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      break;
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case content::CONSOLE_MESSAGE_LEVEL_LOG:
127f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      target_level = blink::WebConsoleMessage::LevelLog;
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      break;
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case content::CONSOLE_MESSAGE_LEVEL_WARNING:
130f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      target_level = blink::WebConsoleMessage::LevelWarning;
1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      break;
1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case content::CONSOLE_MESSAGE_LEVEL_ERROR:
133f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      target_level = blink::WebConsoleMessage::LevelError;
1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      break;
1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  web_view->mainFrame()->addMessageToConsole(
1375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      blink::WebConsoleMessage(target_level, base::UTF8ToUTF16(message)));
1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void Debug(v8::Handle<v8::Context> context, const std::string& message) {
1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  AddMessage(context, content::CONSOLE_MESSAGE_LEVEL_DEBUG, message);
1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void Log(v8::Handle<v8::Context> context, const std::string& message) {
1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  AddMessage(context, content::CONSOLE_MESSAGE_LEVEL_LOG, message);
1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void Warn(v8::Handle<v8::Context> context, const std::string& message) {
1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  AddMessage(context, content::CONSOLE_MESSAGE_LEVEL_WARNING, message);
1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void Error(v8::Handle<v8::Context> context, const std::string& message) {
1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  AddMessage(context, content::CONSOLE_MESSAGE_LEVEL_ERROR, message);
1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void Fatal(v8::Handle<v8::Context> context, const std::string& message) {
1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Error(context, message);
1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  CheckWithMinidump(message);
1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AddMessage(v8::Handle<v8::Context> context,
1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                content::ConsoleMessageLevel level,
1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                const std::string& message) {
1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (context.IsEmpty()) {
1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    LOG(WARNING) << "Could not log \"" << message << "\": no context given";
1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  content::RenderView* render_view = ByContextFinder::Find(context);
1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!render_view) {
1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    LOG(WARNING) << "Could not log \"" << message << "\": no render view found";
1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  AddMessage(render_view, level, message);
1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
176a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)v8::Local<v8::Object> AsV8Object() {
177f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  v8::Isolate* isolate = v8::Isolate::GetCurrent();
178a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  v8::EscapableHandleScope handle_scope(isolate);
1795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  v8::Local<v8::Object> console_object = v8::Object::New(isolate);
180f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  BindLogMethod(isolate, console_object, "debug", &Debug);
181f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  BindLogMethod(isolate, console_object, "log", &Log);
182f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  BindLogMethod(isolate, console_object, "warn", &Warn);
183f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  BindLogMethod(isolate, console_object, "error", &Error);
184a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  return handle_scope.Escape(console_object);
185a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)}
186a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace console
1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace extensions
189