1 // 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.
5 #include "extensions/browser/extension_error.h"
7 #include "base/strings/string_number_conversions.h"
8 #include "base/strings/utf_string_conversions.h"
9 #include "base/values.h"
10 #include "extensions/common/constants.h"
13 using base::DictionaryValue
;
15 namespace extensions
{
17 ////////////////////////////////////////////////////////////////////////////////
21 const char ExtensionError::kExtensionIdKey
[] = "extensionId";
22 const char ExtensionError::kFromIncognitoKey
[] = "fromIncognito";
23 const char ExtensionError::kLevelKey
[] = "level";
24 const char ExtensionError::kMessageKey
[] = "message";
25 const char ExtensionError::kSourceKey
[] = "source";
26 const char ExtensionError::kTypeKey
[] = "type";
28 ExtensionError::ExtensionError(Type type
,
29 const std::string
& extension_id
,
31 logging::LogSeverity level
,
32 const base::string16
& source
,
33 const base::string16
& message
)
35 extension_id_(extension_id
),
36 from_incognito_(from_incognito
),
43 ExtensionError::~ExtensionError() {
46 scoped_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_
);
60 std::string
ExtensionError::PrintForTest() const {
61 return std::string("Extension Error:") +
62 "\n OTR: " + std::string(from_incognito_
? "true" : "false") +
63 "\n Level: " + base::IntToString(static_cast<int>(level_
)) +
64 "\n Source: " + base::UTF16ToUTF8(source_
) +
65 "\n Message: " + base::UTF16ToUTF8(message_
) +
66 "\n ID: " + extension_id_
;
69 bool 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_
&&
78 ////////////////////////////////////////////////////////////////////////////////
82 const char ManifestError::kManifestKeyKey
[] = "manifestKey";
83 const char ManifestError::kManifestSpecificKey
[] = "manifestSpecific";
85 ManifestError::ManifestError(const std::string
& extension_id
,
86 const base::string16
& message
,
87 const base::string16
& manifest_key
,
88 const base::string16
& manifest_specific
)
89 : ExtensionError(ExtensionError::MANIFEST_ERROR
,
91 false, // extensions can't be installed while incognito.
92 logging::LOG_WARNING
, // All manifest errors are warnings.
93 base::FilePath(kManifestFilename
).AsUTF16Unsafe(),
95 manifest_key_(manifest_key
),
96 manifest_specific_(manifest_specific
) {
99 ManifestError::~ManifestError() {
102 scoped_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_
);
111 std::string
ManifestError::PrintForTest() const {
112 return ExtensionError::PrintForTest() +
113 "\n Type: ManifestError";
116 bool 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.
122 ////////////////////////////////////////////////////////////////////////////////
126 const char RuntimeError::kColumnNumberKey
[] = "columnNumber";
127 const char RuntimeError::kContextUrlKey
[] = "contextUrl";
128 const char RuntimeError::kFunctionNameKey
[] = "functionName";
129 const char RuntimeError::kLineNumberKey
[] = "lineNumber";
130 const char RuntimeError::kStackTraceKey
[] = "stackTrace";
131 const char RuntimeError::kUrlKey
[] = "url";
132 const char RuntimeError::kRenderProcessIdKey
[] = "renderProcessId";
133 const char RuntimeError::kRenderViewIdKey
[] = "renderViewId";
135 RuntimeError::RuntimeError(const std::string
& extension_id
,
137 const base::string16
& source
,
138 const base::string16
& message
,
139 const StackTrace
& stack_trace
,
140 const GURL
& context_url
,
141 logging::LogSeverity level
,
143 int render_process_id
)
144 : ExtensionError(ExtensionError::RUNTIME_ERROR
,
145 !extension_id
.empty() ? extension_id
: GURL(source
).host(),
150 context_url_(context_url
),
151 stack_trace_(stack_trace
),
152 render_view_id_(render_view_id
),
153 render_process_id_(render_process_id
) {
157 RuntimeError::~RuntimeError() {
160 scoped_ptr
<DictionaryValue
> RuntimeError::ToValue() const {
161 // The items which are to be written into value are also described in
162 // chrome/browser/resources/extensions/extension_error_overlay.js in @typedef
163 // for RuntimeError and StackTrace. Please update them whenever you add or
164 // remove any keys here.
165 scoped_ptr
<DictionaryValue
> value
= ExtensionError::ToValue();
166 value
->SetString(kContextUrlKey
, context_url_
.spec());
167 value
->SetInteger(kRenderViewIdKey
, render_view_id_
);
168 value
->SetInteger(kRenderProcessIdKey
, render_process_id_
);
170 base::ListValue
* trace_value
= new base::ListValue
;
171 for (StackTrace::const_iterator iter
= stack_trace_
.begin();
172 iter
!= stack_trace_
.end(); ++iter
) {
173 DictionaryValue
* frame_value
= new DictionaryValue
;
174 frame_value
->SetInteger(kLineNumberKey
, iter
->line_number
);
175 frame_value
->SetInteger(kColumnNumberKey
, iter
->column_number
);
176 frame_value
->SetString(kUrlKey
, iter
->source
);
177 frame_value
->SetString(kFunctionNameKey
, iter
->function
);
178 trace_value
->Append(frame_value
);
181 value
->Set(kStackTraceKey
, trace_value
);
186 std::string
RuntimeError::PrintForTest() const {
187 std::string result
= ExtensionError::PrintForTest() +
188 "\n Type: RuntimeError"
189 "\n Context: " + context_url_
.spec() +
191 for (StackTrace::const_iterator iter
= stack_trace_
.begin();
192 iter
!= stack_trace_
.end(); ++iter
) {
194 "\n Line: " + base::IntToString(iter
->line_number
) +
195 "\n Column: " + base::IntToString(iter
->column_number
) +
196 "\n URL: " + base::UTF16ToUTF8(iter
->source
) +
197 "\n Function: " + base::UTF16ToUTF8(iter
->function
) +
203 bool RuntimeError::IsEqualImpl(const ExtensionError
* rhs
) const {
204 const RuntimeError
* error
= static_cast<const RuntimeError
*>(rhs
);
206 // Only look at the first frame of a stack trace to save time and group
207 // nearly-identical errors. The most recent error is kept, so there's no risk
208 // of displaying an old and inaccurate stack trace.
209 return level_
== error
->level_
&&
210 source_
== error
->source_
&&
211 context_url_
== error
->context_url_
&&
212 stack_trace_
.size() == error
->stack_trace_
.size() &&
213 (stack_trace_
.empty() || stack_trace_
[0] == error
->stack_trace_
[0]);
216 void RuntimeError::CleanUpInit() {
217 // If the error came from a generated background page, the "context" is empty
218 // because there's no visible URL. We should set context to be the generated
219 // background page in this case.
220 GURL source_url
= GURL(source_
);
221 if (context_url_
.is_empty() &&
223 std::string("/") + kGeneratedBackgroundPageFilename
) {
224 context_url_
= source_url
;
227 // In some instances (due to the fact that we're reusing error reporting from
228 // other systems), the source won't match up with the final entry in the stack
229 // trace. (For instance, in a browser action error, the source is the page -
230 // sometimes the background page - but the error is thrown from the script.)
231 // Make the source match the stack trace, since that is more likely the cause
233 if (!stack_trace_
.empty() && source_
!= stack_trace_
[0].source
)
234 source_
= stack_trace_
[0].source
;
237 } // namespace extensions