// 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 "extensions/browser/extension_error.h" #include "base/strings/string_number_conversions.h" #include "base/strings/utf_string_conversions.h" #include "extensions/common/constants.h" #include "url/gurl.h" namespace extensions { //////////////////////////////////////////////////////////////////////////////// // ExtensionError ExtensionError::ExtensionError(Type type, const std::string& extension_id, bool from_incognito, logging::LogSeverity level, const base::string16& source, const base::string16& message) : type_(type), extension_id_(extension_id), id_(0), from_incognito_(from_incognito), level_(level), source_(source), message_(message), occurrences_(1u) { } ExtensionError::~ExtensionError() { } std::string ExtensionError::GetDebugString() const { return std::string("Extension Error:") + "\n OTR: " + std::string(from_incognito_ ? "true" : "false") + "\n Level: " + base::IntToString(static_cast(level_)) + "\n Source: " + base::UTF16ToUTF8(source_) + "\n Message: " + base::UTF16ToUTF8(message_) + "\n ID: " + extension_id_; } bool ExtensionError::IsEqual(const ExtensionError* rhs) const { // We don't check |source_| or |level_| here, since they are constant for // manifest errors. Check them in RuntimeError::IsEqualImpl() instead. return type_ == rhs->type_ && extension_id_ == rhs->extension_id_ && message_ == rhs->message_ && IsEqualImpl(rhs); } //////////////////////////////////////////////////////////////////////////////// // ManifestError ManifestError::ManifestError(const std::string& extension_id, const base::string16& message, const base::string16& manifest_key, const base::string16& manifest_specific) : ExtensionError(ExtensionError::MANIFEST_ERROR, extension_id, false, // extensions can't be installed while incognito. logging::LOG_WARNING, // All manifest errors are warnings. base::FilePath(kManifestFilename).AsUTF16Unsafe(), message), manifest_key_(manifest_key), manifest_specific_(manifest_specific) { } ManifestError::~ManifestError() { } std::string ManifestError::GetDebugString() const { return ExtensionError::GetDebugString() + "\n Type: ManifestError"; } bool ManifestError::IsEqualImpl(const ExtensionError* rhs) const { // If two manifest errors have the same extension id and message (which are // both checked in ExtensionError::IsEqual), then they are equal. return true; } //////////////////////////////////////////////////////////////////////////////// // RuntimeError RuntimeError::RuntimeError(const std::string& extension_id, bool from_incognito, const base::string16& source, const base::string16& message, const StackTrace& stack_trace, const GURL& context_url, logging::LogSeverity level, int render_frame_id, int render_process_id) : ExtensionError(ExtensionError::RUNTIME_ERROR, !extension_id.empty() ? extension_id : GURL(source).host(), from_incognito, level, source, message), context_url_(context_url), stack_trace_(stack_trace), render_frame_id_(render_frame_id), render_process_id_(render_process_id) { CleanUpInit(); } RuntimeError::~RuntimeError() { } std::string RuntimeError::GetDebugString() const { std::string result = ExtensionError::GetDebugString() + "\n Type: RuntimeError" "\n Context: " + context_url_.spec() + "\n Stack Trace: "; for (StackTrace::const_iterator iter = stack_trace_.begin(); iter != stack_trace_.end(); ++iter) { // The "NL" comments are to force clang-format to choose the right layout. result += "\n {"; result += "\n Line: " + base::SizeTToString(iter->line_number) + // NL "\n Column: " + base::SizeTToString(iter->column_number) + // NL "\n URL: " + base::UTF16ToUTF8(iter->source) + // NL "\n Function: " + base::UTF16ToUTF8(iter->function) + // NL "\n }"; // NL } return result; } bool RuntimeError::IsEqualImpl(const ExtensionError* rhs) const { const RuntimeError* error = static_cast(rhs); // Only look at the first frame of a stack trace to save time and group // nearly-identical errors. The most recent error is kept, so there's no risk // of displaying an old and inaccurate stack trace. return level_ == error->level_ && source_ == error->source_ && context_url_ == error->context_url_ && stack_trace_.size() == error->stack_trace_.size() && (stack_trace_.empty() || stack_trace_[0] == error->stack_trace_[0]); } void RuntimeError::CleanUpInit() { // If the error came from a generated background page, the "context" is empty // because there's no visible URL. We should set context to be the generated // background page in this case. GURL source_url = GURL(source_); if (context_url_.is_empty() && source_url.path() == std::string("/") + kGeneratedBackgroundPageFilename) { context_url_ = source_url; } // In some instances (due to the fact that we're reusing error reporting from // other systems), the source won't match up with the final entry in the stack // trace. (For instance, in a browser action error, the source is the page - // sometimes the background page - but the error is thrown from the script.) // Make the source match the stack trace, since that is more likely the cause // of the error. if (!stack_trace_.empty() && source_ != stack_trace_[0].source) source_ = stack_trace_[0].source; } //////////////////////////////////////////////////////////////////////////////// // InternalError InternalError::InternalError(const std::string& extension_id, const base::string16& message, logging::LogSeverity level) : ExtensionError(ExtensionError::INTERNAL_ERROR, extension_id, false, // not incognito. level, base::string16(), message) { } InternalError::~InternalError() { } std::string InternalError::GetDebugString() const { return ExtensionError::GetDebugString() + "\n Type: InternalError"; } bool InternalError::IsEqualImpl(const ExtensionError* rhs) const { // ExtensionError logic is sufficient for comparison. return true; } } // namespace extensions