| 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..2f4f7732843e83ed97c035b72262d9d126226cf0
|
| --- /dev/null
|
| +++ b/extensions/renderer/bindings/exception_handler.cc
|
| @@ -0,0 +1,95 @@
|
| +// 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/memory/ptr_util.h"
|
| +#include "base/strings/stringprintf.h"
|
| +#include "base/supports_user_data.h"
|
| +#include "gin/converter.h"
|
| +#include "gin/per_context_data.h"
|
| +
|
| +namespace extensions {
|
| +
|
| +namespace {
|
| +
|
| +const char kExtensionExceptionHandlerPerContextKey[] =
|
| + "extension_exception_handler";
|
| +
|
| +struct ExceptionHandlerPerContextData : public base::SupportsUserData::Data {
|
| + v8::Global<v8::Function> custom_handler;
|
| +};
|
| +
|
| +// TODO(devlin): Extract this to a utility method.
|
| +ExceptionHandlerPerContextData* GetContextData(v8::Local<v8::Context> context,
|
| + bool should_create) {
|
| + gin::PerContextData* per_context_data = gin::PerContextData::From(context);
|
| + if (!per_context_data)
|
| + return nullptr;
|
| + auto* data = static_cast<ExceptionHandlerPerContextData*>(
|
| + per_context_data->GetUserData(kExtensionExceptionHandlerPerContextKey));
|
| +
|
| + if (!data && should_create) {
|
| + auto api_data = base::MakeUnique<ExceptionHandlerPerContextData>();
|
| + data = api_data.get();
|
| + per_context_data->SetUserData(kExtensionExceptionHandlerPerContextKey,
|
| + std::move(api_data));
|
| + }
|
| +
|
| + return data;
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +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,
|
| + v8::TryCatch* try_catch) {
|
| + 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 handler_try_catch(isolate);
|
| + run_js_.Run(handler, context, arraysize(arguments), arguments);
|
| + } else {
|
| + add_console_error_.Run(context, full_message);
|
| + }
|
| +
|
| + try_catch->Reset(); // Reset() to avoid handling the error more than once.
|
| +}
|
| +
|
| +void ExceptionHandler::SetHandlerForContext(v8::Local<v8::Context> context,
|
| + v8::Local<v8::Function> handler) {
|
| + ExceptionHandlerPerContextData* data = GetContextData(context, true);
|
| + DCHECK(data);
|
| + data->custom_handler.Reset(context->GetIsolate(), handler);
|
| +}
|
| +
|
| +v8::Local<v8::Function> ExceptionHandler::GetCustomHandler(
|
| + v8::Local<v8::Context> context) {
|
| + ExceptionHandlerPerContextData* data = GetContextData(context, false);
|
| + return data ? data->custom_handler.Get(context->GetIsolate())
|
| + : v8::Local<v8::Function>();
|
| +}
|
| +
|
| +} // namespace extensions
|
|
|