diff options
author | jyasskin@chromium.org <jyasskin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-08-08 02:35:53 +0000 |
---|---|---|
committer | jyasskin@chromium.org <jyasskin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-08-08 02:35:53 +0000 |
commit | f31d66db22527a49eaadf4e598f2e6976673bc48 (patch) | |
tree | 76b54bde1da74a9be6574996319dadd41a461bae /chrome | |
parent | 7d6c372945b66064e03c794cfa3d22599da25c7b (diff) | |
download | chromium_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')
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', |