Expand RuntimeErrors for ErrorConsole
Include two of our internal scripts (event_bindings and schemaUtil) as sources for runtime errors. Add tests for same. BUG=21734 Review URL: https://chromiumcodereview.appspot.com/23923003 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@221652 0039d316-1c4b-4281-b951-d872f2087c98
This commit is contained in:
chrome
browser
extensions
renderer
extensions
test
data
extensions
error_console
bad_api_arguments_runtime_error
bad_api_permissions_runtime_error
extensions
@ -20,6 +20,7 @@
|
||||
#include "extensions/browser/extension_error.h"
|
||||
#include "extensions/common/constants.h"
|
||||
#include "extensions/common/error_utils.h"
|
||||
#include "extensions/common/extension_urls.h"
|
||||
#include "extensions/common/manifest_constants.h"
|
||||
#include "net/test/embedded_test_server/embedded_test_server.h"
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
@ -420,7 +421,6 @@ IN_PROC_BROWSER_TEST_F(ErrorConsoleBrowserTest, BrowserActionRuntimeError) {
|
||||
ACTION_BROWSER_ACTION,
|
||||
&extension);
|
||||
|
||||
std::string event_bindings_str = "event_bindings";
|
||||
std::string script_url = extension->url().Resolve("browser_action.js").spec();
|
||||
|
||||
const ErrorConsole::ErrorList& errors =
|
||||
@ -444,10 +444,77 @@ IN_PROC_BROWSER_TEST_F(ErrorConsoleBrowserTest, BrowserActionRuntimeError) {
|
||||
"extensions::SafeBuiltins",
|
||||
std::string("Function.target.") + kAnonymousFunction);
|
||||
CheckStackFrame(
|
||||
stack_trace[2], event_bindings_str, "Event.dispatchToListener");
|
||||
CheckStackFrame(stack_trace[3], event_bindings_str, "Event.dispatch_");
|
||||
CheckStackFrame(stack_trace[4], event_bindings_str, "dispatchArgs");
|
||||
CheckStackFrame(stack_trace[5], event_bindings_str, "dispatchEvent");
|
||||
stack_trace[2], kEventBindings, "Event.dispatchToListener");
|
||||
CheckStackFrame(stack_trace[3], kEventBindings, "Event.dispatch_");
|
||||
CheckStackFrame(stack_trace[4], kEventBindings, "dispatchArgs");
|
||||
CheckStackFrame(stack_trace[5], kEventBindings, "dispatchEvent");
|
||||
}
|
||||
|
||||
// Test that we can catch an error for calling an API with improper arguments.
|
||||
IN_PROC_BROWSER_TEST_F(ErrorConsoleBrowserTest, BadAPIArgumentsRuntimeError) {
|
||||
const Extension* extension = NULL;
|
||||
LoadExtensionAndCheckErrors(
|
||||
"bad_api_arguments_runtime_error",
|
||||
kNoFlags,
|
||||
1, // One error: call an API with improper arguments.
|
||||
ACTION_NONE,
|
||||
&extension);
|
||||
|
||||
const ErrorConsole::ErrorList& errors =
|
||||
error_console()->GetErrorsForExtension(extension->id());
|
||||
|
||||
CheckRuntimeError(
|
||||
errors[0],
|
||||
extension->id(),
|
||||
kSchemaUtils, // API calls are checked in schemaUtils.js.
|
||||
false, // not incognito
|
||||
"Uncaught Error: Invocation of form "
|
||||
"tabs.get(string, function) doesn't match definition "
|
||||
"tabs.get(integer tabId, function callback)",
|
||||
logging::LOG_ERROR,
|
||||
extension->url().Resolve(kBackgroundPageName),
|
||||
1u);
|
||||
|
||||
const StackTrace& stack_trace = GetStackTraceFromError(errors[0]);
|
||||
ASSERT_EQ(1u, stack_trace.size());
|
||||
CheckStackFrame(stack_trace[0],
|
||||
kSchemaUtils,
|
||||
kAnonymousFunction);
|
||||
}
|
||||
|
||||
// Test that we catch an error when we try to call an API method without
|
||||
// permission.
|
||||
IN_PROC_BROWSER_TEST_F(ErrorConsoleBrowserTest, BadAPIPermissionsRuntimeError) {
|
||||
const Extension* extension = NULL;
|
||||
LoadExtensionAndCheckErrors(
|
||||
"bad_api_permissions_runtime_error",
|
||||
kNoFlags,
|
||||
1, // One error: we try to call addUrl() on chrome.history without
|
||||
// permission, which results in a TypeError.
|
||||
ACTION_NONE,
|
||||
&extension);
|
||||
|
||||
std::string script_url = extension->url().Resolve("background.js").spec();
|
||||
|
||||
const ErrorConsole::ErrorList& errors =
|
||||
error_console()->GetErrorsForExtension(extension->id());
|
||||
|
||||
CheckRuntimeError(
|
||||
errors[0],
|
||||
extension->id(),
|
||||
script_url,
|
||||
false, // not incognito
|
||||
"Uncaught TypeError: Cannot call method 'addUrl' of undefined",
|
||||
logging::LOG_ERROR,
|
||||
extension->url().Resolve(kBackgroundPageName),
|
||||
1u);
|
||||
|
||||
const StackTrace& stack_trace = GetStackTraceFromError(errors[0]);
|
||||
ASSERT_EQ(1u, stack_trace.size());
|
||||
CheckStackFrame(stack_trace[0],
|
||||
script_url,
|
||||
kAnonymousFunction,
|
||||
5u, 1u);
|
||||
}
|
||||
|
||||
} // namespace extensions
|
||||
|
@ -51,6 +51,7 @@ scoped_ptr<ExtensionError> CreateNewRuntimeError(
|
||||
const std::string& extension_id,
|
||||
const string16& message) {
|
||||
return scoped_ptr<ExtensionError>(new RuntimeError(
|
||||
extension_id,
|
||||
from_incognito,
|
||||
GetSourceForExtensionId(extension_id),
|
||||
message,
|
||||
|
@ -36,6 +36,7 @@
|
||||
#include "chrome/common/pref_names.h"
|
||||
#include "content/public/browser/notification_service.h"
|
||||
#include "content/public/browser/render_process_host.h"
|
||||
#include "extensions/common/extension_urls.h"
|
||||
|
||||
using base::DictionaryValue;
|
||||
using base::ListValue;
|
||||
@ -134,7 +135,7 @@ void EventRouter::DispatchExtensionMessage(IPC::Sender* ipc_sender,
|
||||
ipc_sender->Send(new ExtensionMsg_MessageInvoke(
|
||||
MSG_ROUTING_CONTROL,
|
||||
extension_id,
|
||||
"event_bindings",
|
||||
kEventBindings,
|
||||
"dispatchEvent",
|
||||
args,
|
||||
user_gesture == USER_GESTURE_ENABLED));
|
||||
|
@ -586,15 +586,20 @@ void ExtensionHost::OnDetailedConsoleMessageAdded(
|
||||
const StackTrace& stack_trace,
|
||||
int32 severity_level) {
|
||||
if (IsSourceFromAnExtension(source)) {
|
||||
GURL context_url;
|
||||
if (associated_web_contents_)
|
||||
context_url = associated_web_contents_->GetLastCommittedURL();
|
||||
else if (host_contents_.get())
|
||||
context_url = host_contents_->GetLastCommittedURL();
|
||||
|
||||
ErrorConsole::Get(profile_)->ReportError(
|
||||
scoped_ptr<ExtensionError>(new RuntimeError(
|
||||
extension_id_,
|
||||
profile_->IsOffTheRecord(),
|
||||
source,
|
||||
message,
|
||||
stack_trace,
|
||||
associated_web_contents_ ?
|
||||
associated_web_contents_->GetLastCommittedURL() :
|
||||
GURL::EmptyGURL(),
|
||||
context_url,
|
||||
static_cast<logging::LogSeverity>(severity_level))));
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include "chrome/browser/extensions/tab_helper.h"
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "base/strings/string_util.h"
|
||||
#include "chrome/browser/chrome_notification_types.h"
|
||||
#include "chrome/browser/extensions/activity_log/activity_log.h"
|
||||
#include "chrome/browser/extensions/api/declarative/rules_registry_service.h"
|
||||
@ -364,6 +365,7 @@ void TabHelper::OnDetailedConsoleMessageAdded(
|
||||
if (IsSourceFromAnExtension(source)) {
|
||||
ErrorConsole::Get(profile_)->ReportError(
|
||||
scoped_ptr<ExtensionError>(new RuntimeError(
|
||||
extension_app_ ? extension_app_->id() : EmptyString(),
|
||||
profile_->IsOffTheRecord(),
|
||||
source,
|
||||
message,
|
||||
|
@ -78,6 +78,7 @@
|
||||
#include "content/public/renderer/render_view.h"
|
||||
#include "content/public/renderer/v8_value_converter.h"
|
||||
#include "extensions/common/constants.h"
|
||||
#include "extensions/common/extension_urls.h"
|
||||
#include "extensions/common/features/feature.h"
|
||||
#include "extensions/common/features/feature_provider.h"
|
||||
#include "extensions/common/manifest.h"
|
||||
@ -118,7 +119,6 @@ namespace {
|
||||
|
||||
static const int64 kInitialExtensionIdleHandlerDelayMs = 5*1000;
|
||||
static const int64 kMaxExtensionIdleHandlerDelayMs = 5*60*1000;
|
||||
static const char kEventModule[] = "event_bindings";
|
||||
static const char kEventDispatchFunction[] = "dispatchEvent";
|
||||
|
||||
// Returns the global value for "chrome" from |context|. If one doesn't exist
|
||||
@ -905,12 +905,12 @@ void Dispatcher::PopulateSourceMap() {
|
||||
// Libraries.
|
||||
source_map_.RegisterSource("contentWatcher", IDR_CONTENT_WATCHER_JS);
|
||||
source_map_.RegisterSource("entryIdManager", IDR_ENTRY_ID_MANAGER);
|
||||
source_map_.RegisterSource(kEventModule, IDR_EVENT_BINDINGS_JS);
|
||||
source_map_.RegisterSource(kEventBindings, IDR_EVENT_BINDINGS_JS);
|
||||
source_map_.RegisterSource("imageUtil", IDR_IMAGE_UTIL_JS);
|
||||
source_map_.RegisterSource("json_schema", IDR_JSON_SCHEMA_JS);
|
||||
source_map_.RegisterSource("lastError", IDR_LAST_ERROR_JS);
|
||||
source_map_.RegisterSource("messaging", IDR_MESSAGING_JS);
|
||||
source_map_.RegisterSource("schemaUtils", IDR_SCHEMA_UTILS_JS);
|
||||
source_map_.RegisterSource(kSchemaUtils, IDR_SCHEMA_UTILS_JS);
|
||||
source_map_.RegisterSource("sendRequest", IDR_SEND_REQUEST_JS);
|
||||
source_map_.RegisterSource("setIcon", IDR_SET_ICON_JS);
|
||||
source_map_.RegisterSource("test", IDR_TEST_CUSTOM_BINDINGS_JS);
|
||||
@ -1091,7 +1091,7 @@ void Dispatcher::DidCreateScriptContext(
|
||||
if (context->extension()) {
|
||||
v8::Handle<v8::Object> chrome = AsObjectOrEmpty(GetOrCreateChrome(context));
|
||||
if (!chrome.IsEmpty())
|
||||
module_system->SetLazyField(chrome, "Event", kEventModule, "Event");
|
||||
module_system->SetLazyField(chrome, "Event", kEventBindings, "Event");
|
||||
}
|
||||
|
||||
AddOrRemoveBindingsForContext(context);
|
||||
@ -1521,11 +1521,14 @@ void Dispatcher::DispatchEvent(const std::string& extension_id,
|
||||
base::ListValue args;
|
||||
args.Set(0, new base::StringValue(event_name));
|
||||
args.Set(1, new base::ListValue());
|
||||
|
||||
// Needed for Windows compilation, since kEventBindings is declared extern.
|
||||
const char* local_event_bindings = kEventBindings;
|
||||
v8_context_set_.ForEach(
|
||||
extension_id,
|
||||
NULL, // all render views
|
||||
base::Bind(&CallModuleMethod,
|
||||
kEventModule,
|
||||
local_event_bindings,
|
||||
kEventDispatchFunction,
|
||||
&args));
|
||||
}
|
||||
@ -1557,7 +1560,7 @@ void Dispatcher::InvokeModuleSystemMethod(
|
||||
// background page active.
|
||||
const Extension* extension = extensions_.GetByID(extension_id);
|
||||
if (extension && BackgroundInfo::HasLazyBackgroundPage(extension) &&
|
||||
module_name == kEventModule &&
|
||||
module_name == kEventBindings &&
|
||||
function_name == kEventDispatchFunction) {
|
||||
RenderView* background_view =
|
||||
ExtensionHelper::GetBackgroundPage(extension_id);
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
#include "chrome/test/base/module_system_test.h"
|
||||
|
||||
#include "extensions/common/extension_urls.h"
|
||||
#include "grit/renderer_resources.h"
|
||||
|
||||
namespace extensions {
|
||||
@ -13,9 +14,9 @@ class EventUnittest : public ModuleSystemTest {
|
||||
virtual void SetUp() OVERRIDE {
|
||||
ModuleSystemTest::SetUp();
|
||||
|
||||
RegisterModule("event_bindings", IDR_EVENT_BINDINGS_JS);
|
||||
RegisterModule(kEventBindings, IDR_EVENT_BINDINGS_JS);
|
||||
RegisterModule("json_schema", IDR_JSON_SCHEMA_JS);
|
||||
RegisterModule("schemaUtils", IDR_SCHEMA_UTILS_JS);
|
||||
RegisterModule(kSchemaUtils, IDR_SCHEMA_UTILS_JS);
|
||||
RegisterModule("unload_event", IDR_UNLOAD_EVENT_JS);
|
||||
RegisterModule("utils", IDR_UTILS_JS);
|
||||
|
||||
|
5
chrome/test/data/extensions/error_console/bad_api_arguments_runtime_error/background.js
Normal file
5
chrome/test/data/extensions/error_console/bad_api_arguments_runtime_error/background.js
Normal file
@ -0,0 +1,5 @@
|
||||
// Copyright 2013 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.
|
||||
|
||||
chrome.tabs.get("ThisShouldBeAnInteger", function(tab) { });
|
12
chrome/test/data/extensions/error_console/bad_api_arguments_runtime_error/manifest.json
Normal file
12
chrome/test/data/extensions/error_console/bad_api_arguments_runtime_error/manifest.json
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"name": "Bad API Arguments Runtime Error",
|
||||
"description": "Try to call an API (tabs) with improper arguments, causing a runtime error.",
|
||||
"version": "1.0",
|
||||
"manifest_version": 2,
|
||||
"background": {
|
||||
"scripts": ["background.js"]
|
||||
},
|
||||
"permissions": [
|
||||
"tabs", "*://*/*"
|
||||
]
|
||||
}
|
5
chrome/test/data/extensions/error_console/bad_api_permissions_runtime_error/background.js
Normal file
5
chrome/test/data/extensions/error_console/bad_api_permissions_runtime_error/background.js
Normal file
@ -0,0 +1,5 @@
|
||||
// Copyright 2013 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.
|
||||
|
||||
chrome.history.addUrl({"url": "https://www.google.com/"});
|
12
chrome/test/data/extensions/error_console/bad_api_permissions_runtime_error/manifest.json
Normal file
12
chrome/test/data/extensions/error_console/bad_api_permissions_runtime_error/manifest.json
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"name": "Bad API Permissions Runtime Error",
|
||||
"description": "Try to call an API without permission, causing a runtime error.",
|
||||
"version": "1.0",
|
||||
"manifest_version": 2,
|
||||
"background": {
|
||||
"scripts": ["background.js"]
|
||||
},
|
||||
"permissions": [
|
||||
"tabs", "*://*/*"
|
||||
]
|
||||
}
|
@ -120,14 +120,15 @@ bool ManifestError::IsEqualImpl(const ExtensionError* rhs) const {
|
||||
return true;
|
||||
}
|
||||
|
||||
RuntimeError::RuntimeError(bool from_incognito,
|
||||
RuntimeError::RuntimeError(const std::string& extension_id,
|
||||
bool from_incognito,
|
||||
const string16& source,
|
||||
const string16& message,
|
||||
const StackTrace& stack_trace,
|
||||
const GURL& context_url,
|
||||
logging::LogSeverity level)
|
||||
: ExtensionError(ExtensionError::RUNTIME_ERROR,
|
||||
GURL(source).host(),
|
||||
!extension_id.empty() ? extension_id : GURL(source).host(),
|
||||
from_incognito,
|
||||
level,
|
||||
source,
|
||||
|
@ -120,7 +120,8 @@ class ManifestError : public ExtensionError {
|
||||
|
||||
class RuntimeError : public ExtensionError {
|
||||
public:
|
||||
RuntimeError(bool from_incognito,
|
||||
RuntimeError(const std::string& extension_id, // optional, sometimes unknown.
|
||||
bool from_incognito,
|
||||
const base::string16& source,
|
||||
const base::string16& message,
|
||||
const StackTrace& stack_trace,
|
||||
|
@ -4,13 +4,20 @@
|
||||
|
||||
#include "extensions/common/extension_urls.h"
|
||||
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "extensions/common/constants.h"
|
||||
#include "url/gurl.h"
|
||||
|
||||
namespace extensions {
|
||||
|
||||
const char kEventBindings[] = "event_bindings";
|
||||
|
||||
const char kSchemaUtils[] = "schemaUtils";
|
||||
|
||||
bool IsSourceFromAnExtension(const base::string16& source) {
|
||||
return GURL(source).SchemeIs(kExtensionScheme);
|
||||
return GURL(source).SchemeIs(kExtensionScheme) ||
|
||||
source == base::UTF8ToUTF16(kEventBindings) ||
|
||||
source == base::UTF8ToUTF16(kSchemaUtils);
|
||||
}
|
||||
|
||||
} // namespace extensions
|
||||
|
@ -9,6 +9,12 @@
|
||||
|
||||
namespace extensions {
|
||||
|
||||
// The name of the event_bindings module.
|
||||
extern const char kEventBindings[];
|
||||
|
||||
// The name of the schemaUtils module.
|
||||
extern const char kSchemaUtils[];
|
||||
|
||||
// Determine whether or not a source came from an extension. |source| can link
|
||||
// to a page or a script, and can be external (e.g., "http://www.google.com"),
|
||||
// extension-related (e.g., "chrome-extension://<extension_id>/background.js"),
|
||||
|
Reference in New Issue
Block a user