blob: d8733fe51dc0234222f57984b487615512137855 [file] [log] [blame]
[email protected]1b66fdb2013-07-26 09:57:281// Copyright 2013 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
[email protected]921237d062013-08-10 15:30:495#include "extensions/browser/extension_error.h"
[email protected]1b66fdb2013-07-26 09:57:286
[email protected]1b66fdb2013-07-26 09:57:287#include "base/strings/string_number_conversions.h"
8#include "base/strings/utf_string_conversions.h"
9#include "base/values.h"
[email protected]1b66fdb2013-07-26 09:57:2810#include "extensions/common/constants.h"
[email protected]921237d062013-08-10 15:30:4911#include "url/gurl.h"
[email protected]1b66fdb2013-07-26 09:57:2812
[email protected]fa5fed32013-09-05 21:56:2213using base::DictionaryValue;
[email protected]1b66fdb2013-07-26 09:57:2814
15namespace extensions {
16
[email protected]fa5fed32013-09-05 21:56:2217////////////////////////////////////////////////////////////////////////////////
18// ExtensionError
[email protected]1b66fdb2013-07-26 09:57:2819
[email protected]fa5fed32013-09-05 21:56:2220// Static JSON keys.
21const char ExtensionError::kExtensionIdKey[] = "extensionId";
22const char ExtensionError::kFromIncognitoKey[] = "fromIncognito";
23const char ExtensionError::kLevelKey[] = "level";
24const char ExtensionError::kMessageKey[] = "message";
25const char ExtensionError::kSourceKey[] = "source";
26const char ExtensionError::kTypeKey[] = "type";
[email protected]1b66fdb2013-07-26 09:57:2827
28ExtensionError::ExtensionError(Type type,
[email protected]921237d062013-08-10 15:30:4929 const std::string& extension_id,
[email protected]1b66fdb2013-07-26 09:57:2830 bool from_incognito,
[email protected]d466f782013-08-28 21:59:2331 logging::LogSeverity level,
[email protected]0d163dc2013-12-20 23:48:3632 const base::string16& source,
33 const base::string16& message)
[email protected]1b66fdb2013-07-26 09:57:2834 : type_(type),
[email protected]921237d062013-08-10 15:30:4935 extension_id_(extension_id),
[email protected]1b66fdb2013-07-26 09:57:2836 from_incognito_(from_incognito),
[email protected]d466f782013-08-28 21:59:2337 level_(level),
[email protected]1b66fdb2013-07-26 09:57:2838 source_(source),
[email protected]d466f782013-08-28 21:59:2339 message_(message),
40 occurrences_(1u) {
[email protected]1b66fdb2013-07-26 09:57:2841}
42
43ExtensionError::~ExtensionError() {
44}
45
[email protected]fa5fed32013-09-05 21:56:2246scoped_ptr<DictionaryValue> ExtensionError::ToValue() const {
47 // TODO(rdevlin.cronin): Use ValueBuilder when it's moved from
48 // chrome/common/extensions.
49 scoped_ptr<DictionaryValue> value(new DictionaryValue);
50 value->SetInteger(kTypeKey, static_cast<int>(type_));
51 value->SetString(kExtensionIdKey, extension_id_);
52 value->SetBoolean(kFromIncognitoKey, from_incognito_);
53 value->SetInteger(kLevelKey, static_cast<int>(level_));
54 value->SetString(kSourceKey, source_);
55 value->SetString(kMessageKey, message_);
56
57 return value.Pass();
58}
59
[email protected]1b66fdb2013-07-26 09:57:2860std::string ExtensionError::PrintForTest() const {
61 return std::string("Extension Error:") +
62 "\n OTR: " + std::string(from_incognito_ ? "true" : "false") +
[email protected]50af6082013-09-10 02:05:1963 "\n Level: " + base::IntToString(static_cast<int>(level_)) +
[email protected]1b66fdb2013-07-26 09:57:2864 "\n Source: " + base::UTF16ToUTF8(source_) +
65 "\n Message: " + base::UTF16ToUTF8(message_) +
66 "\n ID: " + extension_id_;
67}
68
[email protected]d466f782013-08-28 21:59:2369bool ExtensionError::IsEqual(const ExtensionError* rhs) const {
70 // We don't check |source_| or |level_| here, since they are constant for
71 // manifest errors. Check them in RuntimeError::IsEqualImpl() instead.
72 return type_ == rhs->type_ &&
73 extension_id_ == rhs->extension_id_ &&
74 message_ == rhs->message_ &&
75 IsEqualImpl(rhs);
76}
77
[email protected]fa5fed32013-09-05 21:56:2278////////////////////////////////////////////////////////////////////////////////
79// ManifestError
80
81// Static JSON keys.
82const char ManifestError::kManifestKeyKey[] = "manifestKey";
83const char ManifestError::kManifestSpecificKey[] = "manifestSpecific";
84
[email protected]d466f782013-08-28 21:59:2385ManifestError::ManifestError(const std::string& extension_id,
[email protected]0d163dc2013-12-20 23:48:3686 const base::string16& message,
87 const base::string16& manifest_key,
88 const base::string16& manifest_specific)
[email protected]d466f782013-08-28 21:59:2389 : ExtensionError(ExtensionError::MANIFEST_ERROR,
[email protected]921237d062013-08-10 15:30:4990 extension_id,
91 false, // extensions can't be installed while incognito.
[email protected]d466f782013-08-28 21:59:2392 logging::LOG_WARNING, // All manifest errors are warnings.
[email protected]921237d062013-08-10 15:30:4993 base::FilePath(kManifestFilename).AsUTF16Unsafe(),
[email protected]b191e2d32013-09-03 21:08:3094 message),
95 manifest_key_(manifest_key),
96 manifest_specific_(manifest_specific) {
[email protected]1b66fdb2013-07-26 09:57:2897}
98
[email protected]d466f782013-08-28 21:59:2399ManifestError::~ManifestError() {
[email protected]1b66fdb2013-07-26 09:57:28100}
101
[email protected]fa5fed32013-09-05 21:56:22102scoped_ptr<DictionaryValue> ManifestError::ToValue() const {
103 scoped_ptr<DictionaryValue> value = ExtensionError::ToValue();
104 if (!manifest_key_.empty())
105 value->SetString(kManifestKeyKey, manifest_key_);
106 if (!manifest_specific_.empty())
107 value->SetString(kManifestSpecificKey, manifest_specific_);
108 return value.Pass();
109}
110
[email protected]d466f782013-08-28 21:59:23111std::string ManifestError::PrintForTest() const {
[email protected]1b66fdb2013-07-26 09:57:28112 return ExtensionError::PrintForTest() +
[email protected]d466f782013-08-28 21:59:23113 "\n Type: ManifestError";
[email protected]1b66fdb2013-07-26 09:57:28114}
115
[email protected]d466f782013-08-28 21:59:23116bool ManifestError::IsEqualImpl(const ExtensionError* rhs) const {
117 // If two manifest errors have the same extension id and message (which are
118 // both checked in ExtensionError::IsEqual), then they are equal.
119 return true;
[email protected]1b66fdb2013-07-26 09:57:28120}
121
[email protected]2fb9bd22013-09-07 00:08:08122////////////////////////////////////////////////////////////////////////////////
123// RuntimeError
124
125// Static JSON keys.
126const char RuntimeError::kColumnNumberKey[] = "columnNumber";
127const char RuntimeError::kContextUrlKey[] = "contextUrl";
128const char RuntimeError::kFunctionNameKey[] = "functionName";
129const char RuntimeError::kLineNumberKey[] = "lineNumber";
130const char RuntimeError::kStackTraceKey[] = "stackTrace";
131const char RuntimeError::kUrlKey[] = "url";
[email protected]c934c382013-11-01 00:36:01132const char RuntimeError::kRenderProcessIdKey[] = "renderProcessId";
133const char RuntimeError::kRenderViewIdKey[] = "renderViewId";
[email protected]2fb9bd22013-09-07 00:08:08134
[email protected]a0ed2682013-09-06 08:41:07135RuntimeError::RuntimeError(const std::string& extension_id,
136 bool from_incognito,
[email protected]0d163dc2013-12-20 23:48:36137 const base::string16& source,
138 const base::string16& message,
[email protected]88b50b62013-09-01 23:05:06139 const StackTrace& stack_trace,
140 const GURL& context_url,
[email protected]c934c382013-11-01 00:36:01141 logging::LogSeverity level,
142 int render_view_id,
143 int render_process_id)
[email protected]d466f782013-08-28 21:59:23144 : ExtensionError(ExtensionError::RUNTIME_ERROR,
[email protected]a0ed2682013-09-06 08:41:07145 !extension_id.empty() ? extension_id : GURL(source).host(),
[email protected]1b66fdb2013-07-26 09:57:28146 from_incognito,
[email protected]d466f782013-08-28 21:59:23147 level,
[email protected]1b66fdb2013-07-26 09:57:28148 source,
[email protected]88b50b62013-09-01 23:05:06149 message),
150 context_url_(context_url),
[email protected]c934c382013-11-01 00:36:01151 stack_trace_(stack_trace),
152 render_view_id_(render_view_id),
153 render_process_id_(render_process_id) {
[email protected]88b50b62013-09-01 23:05:06154 CleanUpInit();
[email protected]1b66fdb2013-07-26 09:57:28155}
156
[email protected]d466f782013-08-28 21:59:23157RuntimeError::~RuntimeError() {
[email protected]1b66fdb2013-07-26 09:57:28158}
159
[email protected]2fb9bd22013-09-07 00:08:08160scoped_ptr<DictionaryValue> RuntimeError::ToValue() const {
161 scoped_ptr<DictionaryValue> value = ExtensionError::ToValue();
162 value->SetString(kContextUrlKey, context_url_.spec());
[email protected]c934c382013-11-01 00:36:01163 value->SetInteger(kRenderViewIdKey, render_view_id_);
164 value->SetInteger(kRenderProcessIdKey, render_process_id_);
[email protected]2fb9bd22013-09-07 00:08:08165
[email protected]c934c382013-11-01 00:36:01166 base::ListValue* trace_value = new base::ListValue;
[email protected]2fb9bd22013-09-07 00:08:08167 for (StackTrace::const_iterator iter = stack_trace_.begin();
168 iter != stack_trace_.end(); ++iter) {
169 DictionaryValue* frame_value = new DictionaryValue;
170 frame_value->SetInteger(kLineNumberKey, iter->line_number);
171 frame_value->SetInteger(kColumnNumberKey, iter->column_number);
172 frame_value->SetString(kUrlKey, iter->source);
173 frame_value->SetString(kFunctionNameKey, iter->function);
174 trace_value->Append(frame_value);
175 }
176
177 value->Set(kStackTraceKey, trace_value);
178
179 return value.Pass();
180}
181
[email protected]d466f782013-08-28 21:59:23182std::string RuntimeError::PrintForTest() const {
[email protected]1b66fdb2013-07-26 09:57:28183 std::string result = ExtensionError::PrintForTest() +
[email protected]d466f782013-08-28 21:59:23184 "\n Type: RuntimeError"
[email protected]88b50b62013-09-01 23:05:06185 "\n Context: " + context_url_.spec() +
[email protected]1b66fdb2013-07-26 09:57:28186 "\n Stack Trace: ";
187 for (StackTrace::const_iterator iter = stack_trace_.begin();
188 iter != stack_trace_.end(); ++iter) {
189 result += "\n {"
190 "\n Line: " + base::IntToString(iter->line_number) +
191 "\n Column: " + base::IntToString(iter->column_number) +
[email protected]88b50b62013-09-01 23:05:06192 "\n URL: " + base::UTF16ToUTF8(iter->source) +
[email protected]1b66fdb2013-07-26 09:57:28193 "\n Function: " + base::UTF16ToUTF8(iter->function) +
194 "\n }";
195 }
196 return result;
197}
198
[email protected]d466f782013-08-28 21:59:23199bool RuntimeError::IsEqualImpl(const ExtensionError* rhs) const {
200 const RuntimeError* error = static_cast<const RuntimeError*>(rhs);
201
202 // Only look at the first frame of a stack trace to save time and group
203 // nearly-identical errors. The most recent error is kept, so there's no risk
204 // of displaying an old and inaccurate stack trace.
[email protected]010ff5072013-09-10 08:36:50205 return level_ == error->level_ &&
206 source_ == error->source_ &&
[email protected]88b50b62013-09-01 23:05:06207 context_url_ == error->context_url_ &&
[email protected]d466f782013-08-28 21:59:23208 stack_trace_.size() == error->stack_trace_.size() &&
209 (stack_trace_.empty() || stack_trace_[0] == error->stack_trace_[0]);
210}
211
[email protected]88b50b62013-09-01 23:05:06212void RuntimeError::CleanUpInit() {
213 // If the error came from a generated background page, the "context" is empty
214 // because there's no visible URL. We should set context to be the generated
215 // background page in this case.
216 GURL source_url = GURL(source_);
217 if (context_url_.is_empty() &&
218 source_url.path() ==
219 std::string("/") + kGeneratedBackgroundPageFilename) {
220 context_url_ = source_url;
[email protected]1b66fdb2013-07-26 09:57:28221 }
222
[email protected]88b50b62013-09-01 23:05:06223 // In some instances (due to the fact that we're reusing error reporting from
224 // other systems), the source won't match up with the final entry in the stack
225 // trace. (For instance, in a browser action error, the source is the page -
226 // sometimes the background page - but the error is thrown from the script.)
227 // Make the source match the stack trace, since that is more likely the cause
228 // of the error.
229 if (!stack_trace_.empty() && source_ != stack_trace_[0].source)
230 source_ = stack_trace_[0].source;
[email protected]1b66fdb2013-07-26 09:57:28231}
232
233} // namespace extensions