Index: extensions/renderer/bindings/exception_handler.cc |
diff --git a/extensions/renderer/bindings/exception_handler.cc b/extensions/renderer/bindings/exception_handler.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..f356d8474038582c5a0f633cd497b3f87aa0642a |
--- /dev/null |
+++ b/extensions/renderer/bindings/exception_handler.cc |
@@ -0,0 +1,81 @@ |
+// Copyright 2017 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "extensions/renderer/bindings/exception_handler.h" |
+ |
+#include "base/logging.h" |
+#include "base/strings/stringprintf.h" |
+#include "gin/converter.h" |
+ |
+namespace extensions { |
+ |
+ExceptionHandler::ExceptionHandler( |
+ const binding::AddConsoleError& add_console_error, |
+ const binding::RunJSFunction& run_js) |
+ : add_console_error_(add_console_error), run_js_(run_js) {} |
+ExceptionHandler::~ExceptionHandler() {} |
+ |
+void ExceptionHandler::HandleException(v8::Local<v8::Context> context, |
+ const std::string& message, |
+ const v8::TryCatch& try_catch) { |
jbroman
2017/06/30 18:35:31
Hmm. Minor question here: do we want to reset the
Devlin
2017/07/06 16:49:22
Good idea; done.
|
+ DCHECK(try_catch.HasCaught()); |
+ |
+ v8::Isolate* isolate = context->GetIsolate(); |
+ v8::HandleScope handle_scope(isolate); |
+ |
+ v8::Local<v8::Message> v8_message = try_catch.Message(); |
+ std::string full_message = |
+ !v8_message.IsEmpty() |
+ ? base::StringPrintf("%s: %s", message.c_str(), |
+ gin::V8ToString(v8_message->Get()).c_str()) |
+ : message; |
+ |
+ v8::Local<v8::Function> handler = GetCustomHandler(context); |
+ if (!handler.IsEmpty()) { |
+ v8::Local<v8::Value> arguments[] = { |
+ gin::StringToV8(isolate, full_message), try_catch.Exception(), |
+ }; |
+ v8::TryCatch try_catch(isolate); |
jbroman
2017/06/30 18:35:31
Is it desirable to have exceptions here be verbose
Devlin
2017/07/06 16:49:22
Done.
jbroman
2017/07/06 21:09:18
Ah, you're quite correct; I misremembered.
|
+ run_js_.Run(handler, context, arraysize(arguments), arguments); |
+ } else { |
+ add_console_error_.Run(context, full_message); |
+ } |
+} |
+ |
+void ExceptionHandler::SetHandlerForContext(v8::Local<v8::Context> context, |
+ v8::Local<v8::Function> handler) { |
+ v8::Isolate* isolate = context->GetIsolate(); |
+ for (auto& pair : custom_handlers_) { |
+ if (pair.first == context) { |
+ pair.second = v8::Global<v8::Function>(isolate, handler); |
+ return; |
+ } |
+ } |
+ custom_handlers_.emplace_back(v8::Global<v8::Context>(isolate, context), |
+ v8::Global<v8::Function>(isolate, handler)); |
+} |
+ |
+void ExceptionHandler::InvalidateContext(v8::Local<v8::Context> context) { |
+ for (auto iter = custom_handlers_.begin(); iter != custom_handlers_.end(); |
+ ++iter) { |
+ if (iter->first == context) { |
+ custom_handlers_.erase(iter); |
+ break; |
+ } |
+ } |
+ // We erase only the first match we see in the list because we should have at |
+ // most one handler per context; assert that there aren't any others. |
+ DCHECK(GetCustomHandler(context).IsEmpty()); |
+} |
+ |
+v8::Local<v8::Function> ExceptionHandler::GetCustomHandler( |
+ v8::Local<v8::Context> context) { |
+ for (auto& pair : custom_handlers_) { |
+ if (pair.first == context) |
+ return pair.second.Get(context->GetIsolate()); |
+ } |
+ return v8::Local<v8::Function>(); |
+} |
+ |
+} // namespace extensions |