blob: 736fd1929c4f8552366d22fc2a1684e53c089fce [file] [log] [blame]
// 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<int>(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 (auto iter = stack_trace_.cbegin(); iter != stack_trace_.cend(); ++iter) {
result += "\n {";
result += "\n Line: " + base::NumberToString(iter->line_number) +
"\n Column: " + base::NumberToString(iter->column_number) +
"\n URL: " + base::UTF16ToUTF8(iter->source) +
"\n Function: " + base::UTF16ToUTF8(iter->function) +
"\n }";
}
return result;
}
bool RuntimeError::IsEqualImpl(const ExtensionError* rhs) const {
const RuntimeError* error = static_cast<const RuntimeError*>(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_piece() ==
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