summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
authorjyasskin@chromium.org <jyasskin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-08-08 02:35:53 +0000
committerjyasskin@chromium.org <jyasskin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-08-08 02:35:53 +0000
commitf31d66db22527a49eaadf4e598f2e6976673bc48 (patch)
tree76b54bde1da74a9be6574996319dadd41a461bae /chrome
parent7d6c372945b66064e03c794cfa3d22599da25c7b (diff)
downloadchromium_src-f31d66db22527a49eaadf4e598f2e6976673bc48.zip
chromium_src-f31d66db22527a49eaadf4e598f2e6976673bc48.tar.gz
chromium_src-f31d66db22527a49eaadf4e598f2e6976673bc48.tar.bz2
Revert 216345 "Move ExtensionError to extensions/, add error limits"
It leaks memory: http://build.chromium.org/p/chromium.memory.fyi/builders/Linux%20Tests%20%28valgrind%29%284%29/builds/24926/steps/memory%20test%3A%20unit/logs/stdio Leak_DefinitelyLost 663 (264 direct, 399 indirect) bytes in 3 blocks are definitely lost in loss record 33,024 of 38,445 operator new(unsigned long) (m_replacemalloc/vg_replace_malloc.c:1140) extensions::(anonymous namespace)::CreateNewRuntimeError(bool, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::basic_string<unsigned short, base::string16_char_traits, std::allocator<unsigned short> > const&) (chrome/browser/extensions/error_console/error_console_unittest.cc:51) extensions::ErrorConsoleUnitTest_AddAndRemoveErrors_Test::TestBody() (chrome/browser/extensions/error_console/error_console_unittest.cc:80) > Move ExtensionError to extensions/, add error limits > > Move ExtensionError class to extensions/browser/, since it doesn't need to be in chrome/. > Limit the number of errors stored per extension to 100. > Store errors in a map, keyed by Extension ID, since that is how we will likely be accessing them. > > BUG=21734 > > Review URL: https://chromiumcodereview.appspot.com/21609003 TBR=rdevlin.cronin@chromium.org Review URL: https://codereview.chromium.org/22585003 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@216355 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r--chrome/browser/extensions/error_console/error_console.cc93
-rw-r--r--chrome/browser/extensions/error_console/error_console.h32
-rw-r--r--chrome/browser/extensions/error_console/error_console_unittest.cc119
-rw-r--r--chrome/browser/extensions/error_console/extension_error.cc172
-rw-r--r--chrome/browser/extensions/error_console/extension_error.h127
-rw-r--r--chrome/chrome_browser_extensions.gypi4
6 files changed, 365 insertions, 182 deletions
diff --git a/chrome/browser/extensions/error_console/error_console.cc b/chrome/browser/extensions/error_console/error_console.cc
index 35e297b..94eedd8 100644
--- a/chrome/browser/extensions/error_console/error_console.cc
+++ b/chrome/browser/extensions/error_console/error_console.cc
@@ -4,14 +4,12 @@
#include "chrome/browser/extensions/error_console/error_console.h"
-#include <list>
+#include <algorithm>
-#include "base/lazy_instance.h"
-#include "base/stl_util.h"
#include "chrome/browser/chrome_notification_types.h"
+#include "chrome/browser/extensions/error_console/extension_error.h"
#include "chrome/browser/extensions/extension_system.h"
#include "chrome/browser/profiles/profile.h"
-#include "chrome/common/extensions/extension.h"
#include "content/public/browser/notification_details.h"
#include "content/public/browser/notification_service.h"
#include "content/public/browser/notification_source.h"
@@ -19,27 +17,6 @@
namespace extensions {
-namespace {
-
-const size_t kMaxErrorsPerExtension = 100;
-
-// Iterate through an error list and remove and delete all errors which were
-// from an incognito context.
-void DeleteIncognitoErrorsFromList(ErrorConsole::ErrorList* list) {
- ErrorConsole::ErrorList::iterator iter = list->begin();
- while (iter != list->end()) {
- if ((*iter)->from_incognito())
- iter = list->erase(iter);
- else
- ++iter;
- }
-}
-
-base::LazyInstance<ErrorConsole::ErrorList> g_empty_error_list =
- LAZY_INSTANCE_INITIALIZER;
-
-} // namespace
-
void ErrorConsole::Observer::OnErrorConsoleDestroyed() {
}
@@ -47,14 +24,10 @@ ErrorConsole::ErrorConsole(Profile* profile) : profile_(profile) {
registrar_.Add(this,
chrome::NOTIFICATION_PROFILE_DESTROYED,
content::NotificationService::AllBrowserContextsAndSources());
- registrar_.Add(this,
- chrome::NOTIFICATION_EXTENSION_UNINSTALLED,
- content::Source<Profile>(profile_));
}
ErrorConsole::~ErrorConsole() {
FOR_EACH_OBSERVER(Observer, observers_, OnErrorConsoleDestroyed());
- RemoveAllErrors();
}
// static
@@ -62,28 +35,31 @@ ErrorConsole* ErrorConsole::Get(Profile* profile) {
return ExtensionSystem::Get(profile)->error_console();
}
-void ErrorConsole::ReportError(scoped_ptr<const ExtensionError> scoped_error) {
+void ErrorConsole::ReportError(scoped_ptr<ExtensionError> error) {
DCHECK(thread_checker_.CalledOnValidThread());
+ errors_.push_back(error.release());
+ FOR_EACH_OBSERVER(Observer, observers_, OnErrorAdded(errors_.back()));
+}
- const ExtensionError* error = scoped_error.release();
- // If there are too many errors for an extension already, limit ourselves to
- // the most recent ones.
- ErrorList* error_list = &errors_[error->extension_id()];
- if (error_list->size() >= kMaxErrorsPerExtension) {
- delete error_list->front();
- error_list->pop_front();
+ErrorConsole::WeakErrorList ErrorConsole::GetErrorsForExtension(
+ const std::string& extension_id) const {
+ WeakErrorList result;
+ for (ErrorList::const_iterator iter = errors_.begin();
+ iter != errors_.end(); ++iter) {
+ if ((*iter)->extension_id() == extension_id)
+ result.push_back(*iter);
}
- error_list->push_back(error);
+ return result;
+}
- FOR_EACH_OBSERVER(Observer, observers_, OnErrorAdded(error));
+void ErrorConsole::RemoveError(const ExtensionError* error) {
+ ErrorList::iterator iter = std::find(errors_.begin(), errors_.end(), error);
+ CHECK(iter != errors_.end());
+ errors_.erase(iter);
}
-const ErrorConsole::ErrorList& ErrorConsole::GetErrorsForExtension(
- const std::string& extension_id) const {
- ErrorMap::const_iterator iter = errors_.find(extension_id);
- if (iter != errors_.end())
- return iter->second;
- return g_empty_error_list.Get();
+void ErrorConsole::RemoveAllErrors() {
+ errors_.clear();
}
void ErrorConsole::AddObserver(Observer* observer) {
@@ -97,26 +73,19 @@ void ErrorConsole::RemoveObserver(Observer* observer) {
}
void ErrorConsole::RemoveIncognitoErrors() {
- for (ErrorMap::iterator iter = errors_.begin();
+ WeakErrorList to_remove;
+ for (ErrorList::const_iterator iter = errors_.begin();
iter != errors_.end(); ++iter) {
- DeleteIncognitoErrorsFromList(&(iter->second));
+ if ((*iter)->from_incognito())
+ to_remove.push_back(*iter);
}
-}
-void ErrorConsole::RemoveErrorsForExtension(const std::string& extension_id) {
- ErrorMap::iterator iter = errors_.find(extension_id);
- if (iter != errors_.end()) {
- STLDeleteContainerPointers(iter->second.begin(), iter->second.end());
- errors_.erase(iter);
+ for (WeakErrorList::const_iterator iter = to_remove.begin();
+ iter != to_remove.end(); ++iter) {
+ RemoveError(*iter);
}
}
-void ErrorConsole::RemoveAllErrors() {
- for (ErrorMap::iterator iter = errors_.begin(); iter != errors_.end(); ++iter)
- STLDeleteContainerPointers(iter->second.begin(), iter->second.end());
- errors_.clear();
-}
-
void ErrorConsole::Observe(int type,
const content::NotificationSource& source,
const content::NotificationDetails& details) {
@@ -129,12 +98,6 @@ void ErrorConsole::Observe(int type,
RemoveIncognitoErrors();
break;
}
- case chrome::NOTIFICATION_EXTENSION_UNINSTALLED:
- // No need to check the profile here, since we registered to only receive
- // notifications from our own.
- RemoveErrorsForExtension(
- content::Details<Extension>(details).ptr()->id());
- break;
default:
NOTREACHED();
}
diff --git a/chrome/browser/extensions/error_console/error_console.h b/chrome/browser/extensions/error_console/error_console.h
index c60bda9..80b2f96 100644
--- a/chrome/browser/extensions/error_console/error_console.h
+++ b/chrome/browser/extensions/error_console/error_console.h
@@ -5,17 +5,16 @@
#ifndef CHROME_BROWSER_EXTENSIONS_ERROR_CONSOLE_ERROR_CONSOLE_H_
#define CHROME_BROWSER_EXTENSIONS_ERROR_CONSOLE_ERROR_CONSOLE_H_
-#include <deque>
-#include <map>
+#include <vector>
#include "base/gtest_prod_util.h"
#include "base/memory/scoped_ptr.h"
+#include "base/memory/scoped_vector.h"
#include "base/observer_list.h"
#include "base/strings/string16.h"
#include "base/threading/thread_checker.h"
#include "content/public/browser/notification_observer.h"
#include "content/public/browser/notification_registrar.h"
-#include "extensions/browser/extension_error.h"
namespace content {
class NotificationDetails;
@@ -27,16 +26,17 @@ class Profile;
namespace extensions {
class ErrorConsoleUnitTest;
+class ExtensionError;
// The ErrorConsole is a central object to which all extension errors are
// reported. This includes errors detected in extensions core, as well as
// runtime Javascript errors.
// This class is owned by ExtensionSystem, making it, in effect, a
// BrowserContext-keyed service.
-class ErrorConsole : public content::NotificationObserver {
+class ErrorConsole : content::NotificationObserver {
public:
- typedef std::deque<const ExtensionError*> ErrorList;
- typedef std::map<std::string, ErrorList> ErrorMap;
+ typedef ScopedVector<ExtensionError> ErrorList;
+ typedef std::vector<const ExtensionError*> WeakErrorList;
class Observer {
public:
@@ -55,18 +55,24 @@ class ErrorConsole : public content::NotificationObserver {
static ErrorConsole* Get(Profile* profile);
// Report an extension error, and add it to the list.
- void ReportError(scoped_ptr<const ExtensionError> error);
+ void ReportError(scoped_ptr<ExtensionError> error);
// Get a collection of weak pointers to all errors relating to the extension
// with the given |extension_id|.
- const ErrorList& GetErrorsForExtension(const std::string& extension_id) const;
+ WeakErrorList GetErrorsForExtension(const std::string& extension_id) const;
+
+ // Remove an error from the list of observed errors.
+ void RemoveError(const ExtensionError* error);
+
+ // Remove all errors from the list of observed errors.
+ void RemoveAllErrors();
// Add or remove observers of the ErrorConsole to be notified of any errors
// added.
void AddObserver(Observer* observer);
void RemoveObserver(Observer* observer);
- const ErrorMap& errors() { return errors_; }
+ const ErrorList& errors() { return errors_; }
private:
FRIEND_TEST_ALL_PREFIXES(ErrorConsoleUnitTest, AddAndRemoveErrors);
@@ -75,12 +81,6 @@ class ErrorConsole : public content::NotificationObserver {
// the incognito profile is destroyed.
void RemoveIncognitoErrors();
- // Remove all errors relating to a particular |extension_id|.
- void RemoveErrorsForExtension(const std::string& extension_id);
-
- // Remove all errors for all extensions.
- void RemoveAllErrors();
-
// content::NotificationObserver implementation.
virtual void Observe(int type,
const content::NotificationSource& source,
@@ -93,7 +93,7 @@ class ErrorConsole : public content::NotificationObserver {
ObserverList<Observer> observers_;
// The errors which we have received so far.
- ErrorMap errors_;
+ ErrorList errors_;
// The profile with which the ErrorConsole is associated. Only collect errors
// from extensions and RenderViews associated with this Profile (and it's
diff --git a/chrome/browser/extensions/error_console/error_console_unittest.cc b/chrome/browser/extensions/error_console/error_console_unittest.cc
index 62b5320..0d27ff2 100644
--- a/chrome/browser/extensions/error_console/error_console_unittest.cc
+++ b/chrome/browser/extensions/error_console/error_console_unittest.cc
@@ -4,16 +4,12 @@
#include "chrome/browser/extensions/error_console/error_console.h"
-#include "base/json/json_writer.h"
-#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/strings/string16.h"
-#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/extensions/error_console/extension_error.h"
#include "chrome/test/base/testing_profile.h"
-#include "content/public/common/url_constants.h"
-#include "extensions/browser/extension_error.h"
-#include "extensions/common/constants.h"
+#include "extensions/common/id_util.h"
#include "testing/gtest/include/gtest/gtest.h"
using base::string16;
@@ -23,32 +19,12 @@ namespace extensions {
namespace {
-const char kExecutionContextURLKey[] = "executionContextURL";
-const char kStackTraceKey[] = "stackTrace";
-
-string16 CreateErrorDetails(const std::string& extension_id) {
- base::DictionaryValue value;
- value.SetString(
- kExecutionContextURLKey,
- std::string(kExtensionScheme) +
- content::kStandardSchemeSeparator +
- extension_id);
- value.Set(kStackTraceKey, new ListValue);
- std::string json_utf8;
- base::JSONWriter::Write(&value, &json_utf8);
- return UTF8ToUTF16(json_utf8);
-}
-
-scoped_ptr<const ExtensionError> CreateNewRuntimeError(
- bool from_incognito,
- const std::string& extension_id,
- const string16& message) {
- return scoped_ptr<const ExtensionError>(new JavascriptRuntimeError(
- from_incognito,
- UTF8ToUTF16("source"),
- message,
- logging::LOG_INFO,
- CreateErrorDetails(extension_id)));
+scoped_ptr<ExtensionError> CreateNewManifestError(bool from_incognito) {
+ return scoped_ptr<ExtensionError>(
+ new ManifestParsingError(from_incognito,
+ UTF8ToUTF16("source"),
+ UTF8ToUTF16("message"),
+ 0u /* line number */ ));
}
} // namespace
@@ -73,81 +49,26 @@ TEST_F(ErrorConsoleUnitTest, AddAndRemoveErrors) {
const size_t kNumTotalErrors = 6;
const size_t kNumNonIncognitoErrors = 3;
- const char kId[] = "id";
// Populate with both incognito and non-incognito errors (evenly distributed).
- for (size_t i = 0; i < kNumTotalErrors; ++i) {
- error_console_->ReportError(
- CreateNewRuntimeError(i % 2 == 0, kId, string16()));
- }
-
- // There should only be one entry in the map, since errors are stored in lists
- // keyed by extension id.
- ASSERT_EQ(1u, error_console_->errors().size());
+ for (size_t i = 0; i < kNumTotalErrors; ++i)
+ error_console_->ReportError(CreateNewManifestError(i % 2 == 0));
- ASSERT_EQ(kNumTotalErrors, error_console_->GetErrorsForExtension(kId).size());
+ ASSERT_EQ(kNumTotalErrors, error_console_->errors().size());
// Remove the incognito errors; three errors should remain, and all should
// be from non-incognito contexts.
error_console_->RemoveIncognitoErrors();
- const ErrorConsole::ErrorList& errors =
- error_console_->GetErrorsForExtension(kId);
- ASSERT_EQ(kNumNonIncognitoErrors, errors.size());
- for (size_t i = 0; i < errors.size(); ++i)
- ASSERT_FALSE(errors[i]->from_incognito());
-
- // Add another error for a different extension id.
- const char kSecondId[] = "id2";
- error_console_->ReportError(
- CreateNewRuntimeError(false, kSecondId, string16()));
-
- // There should be two entries now, one for each id, and there should be one
- // error for the second extension.
- ASSERT_EQ(2u, error_console_->errors().size());
- ASSERT_EQ(1u, error_console_->GetErrorsForExtension(kSecondId).size());
-
- // Remove all errors for the second id.
- error_console_->RemoveErrorsForExtension(kSecondId);
- ASSERT_EQ(1u, error_console_->errors().size());
- ASSERT_EQ(0u, error_console_->GetErrorsForExtension(kSecondId).size());
- // First extension should be unaffected.
- ASSERT_EQ(kNumNonIncognitoErrors,
- error_console_->GetErrorsForExtension(kId).size());
-
- // Remove remaining errors.
- error_console_->RemoveAllErrors();
- ASSERT_EQ(0u, error_console_->errors().size());
- ASSERT_EQ(0u, error_console_->GetErrorsForExtension(kId).size());
-}
+ ASSERT_EQ(kNumNonIncognitoErrors, error_console_->errors().size());
+ for (size_t i = 0; i < error_console_->errors().size(); ++i)
+ ASSERT_FALSE(error_console_->errors()[i]->from_incognito());
-// Test that if we add enough errors, only the most recent
-// kMaxErrorsPerExtension are kept.
-TEST_F(ErrorConsoleUnitTest, ExcessiveErrorsGetCropped) {
- ASSERT_EQ(0u, error_console_->errors().size());
+ // Remove an error by address.
+ error_console_->RemoveError(error_console_->errors()[1]);
+ ASSERT_EQ(kNumNonIncognitoErrors - 1, error_console_->errors().size());
- // This constant matches one of the same name in error_console.cc.
- const size_t kMaxErrorsPerExtension = 100;
- const size_t kNumExtraErrors = 5;
- const char kId[] = "id";
-
- // Add new errors, with each error's message set to its number.
- for (size_t i = 0; i < kMaxErrorsPerExtension + kNumExtraErrors; ++i) {
- error_console_->ReportError(
- CreateNewRuntimeError(false, kId, base::UintToString16(i)));
- }
-
- ASSERT_EQ(1u, error_console_->errors().size());
-
- const ErrorConsole::ErrorList& errors =
- error_console_->GetErrorsForExtension(kId);
- ASSERT_EQ(kMaxErrorsPerExtension, errors.size());
-
- // We should have popped off errors in the order they arrived, so the
- // first stored error should be the 6th reported (zero-based)...
- ASSERT_EQ(errors.front()->message(),
- base::UintToString16(kNumExtraErrors));
- // ..and the last stored should be the 105th reported.
- ASSERT_EQ(errors.back()->message(),
- base::UintToString16(kMaxErrorsPerExtension + kNumExtraErrors - 1));
+ // Remove all remaining errors.
+ error_console_->RemoveAllErrors();
+ ASSERT_EQ(0u, error_console_->errors().size());
}
} // namespace extensions
diff --git a/chrome/browser/extensions/error_console/extension_error.cc b/chrome/browser/extensions/error_console/extension_error.cc
new file mode 100644
index 0000000..9d8944c
--- /dev/null
+++ b/chrome/browser/extensions/error_console/extension_error.cc
@@ -0,0 +1,172 @@
+// 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.
+
+#include "chrome/browser/extensions/error_console/extension_error.h"
+
+#include "base/json/json_reader.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/values.h"
+#include "chrome/common/extensions/extension.h"
+#include "extensions/common/constants.h"
+
+using base::string16;
+
+namespace extensions {
+
+namespace {
+
+const char kLineNumberKey[] = "lineNumber";
+const char kColumnNumberKey[] = "columnNumber";
+const char kURLKey[] = "url";
+const char kFunctionNameKey[] = "functionName";
+const char kExecutionContextURLKey[] = "executionContextURL";
+const char kStackTraceKey[] = "stackTrace";
+
+// Try to retrieve an extension ID from a |url|. On success, returns true and
+// populates |extension_id| with the ID. On failure, returns false and leaves
+// extension_id untouched.
+bool GetExtensionIDFromGURL(const GURL& url, std::string* extension_id) {
+ if (url.SchemeIs(extensions::kExtensionScheme)) {
+ *extension_id = url.host();
+ return true;
+ }
+ return false;
+}
+
+} // namespace
+
+ExtensionError::ExtensionError(Type type,
+ bool from_incognito,
+ const string16& source,
+ const string16& message)
+ : type_(type),
+ from_incognito_(from_incognito),
+ source_(source),
+ message_(message) {
+}
+
+ExtensionError::~ExtensionError() {
+}
+
+std::string ExtensionError::PrintForTest() const {
+ return std::string("Extension Error:") +
+ "\n OTR: " + std::string(from_incognito_ ? "true" : "false") +
+ "\n Source: " + base::UTF16ToUTF8(source_) +
+ "\n Message: " + base::UTF16ToUTF8(message_) +
+ "\n ID: " + extension_id_;
+}
+
+ManifestParsingError::ManifestParsingError(bool from_incognito,
+ const string16& source,
+ const string16& message,
+ size_t line_number)
+ : ExtensionError(ExtensionError::MANIFEST_PARSING_ERROR,
+ from_incognito,
+ source,
+ message),
+ line_number_(line_number) {
+}
+
+ManifestParsingError::~ManifestParsingError() {
+}
+
+std::string ManifestParsingError::PrintForTest() const {
+ return ExtensionError::PrintForTest() +
+ "\n Type: ManifestParsingError" +
+ "\n Line: " + base::IntToString(line_number_);
+}
+
+JavascriptRuntimeError::StackFrame::StackFrame() : line_number(-1),
+ column_number(-1) {
+}
+
+JavascriptRuntimeError::StackFrame::StackFrame(size_t frame_line,
+ size_t frame_column,
+ const string16& frame_url,
+ const string16& frame_function)
+ : line_number(frame_line),
+ column_number(frame_column),
+ url(frame_url),
+ function(frame_function) {
+}
+
+JavascriptRuntimeError::StackFrame::~StackFrame() {
+}
+
+JavascriptRuntimeError::JavascriptRuntimeError(bool from_incognito,
+ const string16& source,
+ const string16& message,
+ logging::LogSeverity level,
+ const string16& details)
+ : ExtensionError(ExtensionError::JAVASCRIPT_RUNTIME_ERROR,
+ from_incognito,
+ source,
+ message),
+ level_(level) {
+ ParseDetails(details);
+ DetermineExtensionID();
+}
+
+JavascriptRuntimeError::~JavascriptRuntimeError() {
+}
+
+std::string JavascriptRuntimeError::PrintForTest() const {
+ std::string result = ExtensionError::PrintForTest() +
+ "\n Type: JavascriptRuntimeError"
+ "\n Context: " + base::UTF16ToUTF8(execution_context_url_) +
+ "\n Stack Trace: ";
+ for (StackTrace::const_iterator iter = stack_trace_.begin();
+ iter != stack_trace_.end(); ++iter) {
+ result += "\n {"
+ "\n Line: " + base::IntToString(iter->line_number) +
+ "\n Column: " + base::IntToString(iter->column_number) +
+ "\n URL: " + base::UTF16ToUTF8(iter->url) +
+ "\n Function: " + base::UTF16ToUTF8(iter->function) +
+ "\n }";
+ }
+ return result;
+}
+
+void JavascriptRuntimeError::ParseDetails(const string16& details) {
+ scoped_ptr<base::Value> value(
+ base::JSONReader::Read(base::UTF16ToUTF8(details)));
+ const base::DictionaryValue* details_value;
+ const base::ListValue* trace_value = NULL;
+
+ // The |details| value should contain an execution context url and a stack
+ // trace.
+ if (!value.get() ||
+ !value->GetAsDictionary(&details_value) ||
+ !details_value->GetString(kExecutionContextURLKey,
+ &execution_context_url_) ||
+ !details_value->GetList(kStackTraceKey, &trace_value)) {
+ NOTREACHED();
+ return;
+ }
+
+ int line = 0;
+ int column = 0;
+ string16 url;
+
+ for (size_t i = 0; i < trace_value->GetSize(); ++i) {
+ const base::DictionaryValue* frame_value = NULL;
+ CHECK(trace_value->GetDictionary(i, &frame_value));
+
+ frame_value->GetInteger(kLineNumberKey, &line);
+ frame_value->GetInteger(kColumnNumberKey, &column);
+ frame_value->GetString(kURLKey, &url);
+
+ string16 function;
+ frame_value->GetString(kFunctionNameKey, &function); // This can be empty.
+ stack_trace_.push_back(StackFrame(line, column, url, function));
+ }
+}
+
+void JavascriptRuntimeError::DetermineExtensionID() {
+ if (!GetExtensionIDFromGURL(GURL(source_), &extension_id_))
+ GetExtensionIDFromGURL(GURL(execution_context_url_), &extension_id_);
+}
+
+} // namespace extensions
diff --git a/chrome/browser/extensions/error_console/extension_error.h b/chrome/browser/extensions/error_console/extension_error.h
new file mode 100644
index 0000000..e462d91
--- /dev/null
+++ b/chrome/browser/extensions/error_console/extension_error.h
@@ -0,0 +1,127 @@
+// 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.
+
+#ifndef CHROME_BROWSER_EXTENSIONS_ERROR_CONSOLE_EXTENSION_ERROR_H_
+#define CHROME_BROWSER_EXTENSIONS_ERROR_CONSOLE_EXTENSION_ERROR_H_
+
+#include <string>
+#include <vector>
+
+#include "base/compiler_specific.h"
+#include "base/logging.h"
+#include "base/strings/string16.h"
+
+namespace extensions {
+
+class ExtensionError {
+ public:
+ enum Type {
+ MANIFEST_PARSING_ERROR,
+ JAVASCRIPT_RUNTIME_ERROR
+ };
+
+ virtual ~ExtensionError();
+
+ virtual std::string PrintForTest() const;
+
+ Type type() const { return type_; }
+ const base::string16& source() const { return source_; }
+ const base::string16& message() const { return message_; }
+ const std::string& extension_id() const { return extension_id_; }
+ bool from_incognito() const { return from_incognito_; }
+
+ protected:
+ ExtensionError(Type type,
+ bool from_incognito,
+ const base::string16& source,
+ const base::string16& message);
+
+ // Which type of error this is.
+ Type type_;
+ // Whether or not the error was caused while incognito.
+ bool from_incognito_;
+ // The source for the error; this can be a script, web page, or manifest file.
+ // This is stored as a string (rather than a url) since it can be a Chrome
+ // script file (e.g., event_bindings.js).
+ base::string16 source_;
+ // The error message itself.
+ base::string16 message_;
+ // The ID of the extension which caused the error. This may be absent, since
+ // we can't always know the id (such as when a manifest fails to parse).
+ std::string extension_id_;
+
+ DISALLOW_COPY_AND_ASSIGN(ExtensionError);
+};
+
+class ManifestParsingError : public ExtensionError {
+ public:
+ ManifestParsingError(bool from_incognito,
+ const base::string16& source,
+ const base::string16& message,
+ size_t line_number);
+ virtual ~ManifestParsingError();
+
+ virtual std::string PrintForTest() const OVERRIDE;
+
+ size_t line_number() const { return line_number_; }
+ private:
+ size_t line_number_;
+
+ DISALLOW_COPY_AND_ASSIGN(ManifestParsingError);
+};
+
+class JavascriptRuntimeError : public ExtensionError {
+ public:
+ struct StackFrame {
+ size_t line_number;
+ size_t column_number;
+ // This is stored as a string (rather than a url) since it can be a
+ // Chrome script file (e.g., event_bindings.js).
+ base::string16 url;
+ base::string16 function; // optional
+
+ // STL-Required constructor
+ StackFrame();
+
+ StackFrame(size_t frame_line,
+ size_t frame_column,
+ const base::string16& frame_url,
+ const base::string16& frame_function /* can be empty */);
+
+ ~StackFrame();
+ };
+ typedef std::vector<StackFrame> StackTrace;
+
+ JavascriptRuntimeError(bool from_incognito,
+ const base::string16& source,
+ const base::string16& message,
+ logging::LogSeverity level,
+ const base::string16& details);
+ virtual ~JavascriptRuntimeError();
+
+ virtual std::string PrintForTest() const OVERRIDE;
+
+ logging::LogSeverity level() const { return level_; }
+ const base::string16& execution_context_url() const {
+ return execution_context_url_;
+ }
+ const StackTrace& stack_trace() const { return stack_trace_; }
+ private:
+ // Parse the JSON |details| passed to the error. This includes a stack trace
+ // and an execution context url.
+ void ParseDetails(const base::string16& details);
+ // Try to determine the ID of the extension. This may be obtained through the
+ // reported source, or through the execution context url.
+ void DetermineExtensionID();
+
+ logging::LogSeverity level_;
+ base::string16 execution_context_url_;
+ StackTrace stack_trace_;
+
+ DISALLOW_COPY_AND_ASSIGN(JavascriptRuntimeError);
+};
+
+} // namespace extensions
+
+#endif // CHROME_BROWSER_EXTENSIONS_ERROR_CONSOLE_EXTENSION_ERROR_H_
diff --git a/chrome/chrome_browser_extensions.gypi b/chrome/chrome_browser_extensions.gypi
index 4ee3d38..6f7425d 100644
--- a/chrome/chrome_browser_extensions.gypi
+++ b/chrome/chrome_browser_extensions.gypi
@@ -54,8 +54,6 @@
# All .cc, .h, .m, and .mm files under browser/extensions except for
# tests and mocks.
'../extensions/browser/extension_prefs_scope.h',
- '../extensions/browser/extension_error.cc',
- '../extensions/browser/extension_error.h',
'../extensions/browser/file_reader.cc',
'../extensions/browser/file_reader.h',
'../extensions/browser/pref_names.cc',
@@ -575,6 +573,8 @@
'browser/extensions/default_apps.h',
'browser/extensions/error_console/error_console.cc',
'browser/extensions/error_console/error_console.h',
+ 'browser/extensions/error_console/extension_error.cc',
+ 'browser/extensions/error_console/extension_error.h',
'browser/extensions/event_listener_map.cc',
'browser/extensions/event_listener_map.h',
'browser/extensions/event_names.cc',