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
),
37 from_incognito_(from_incognito
),
44 ExtensionError::~ExtensionError() {
47 scoped_ptr
<DictionaryValue
> ExtensionError::ToValue() const {
48 // TODO(rdevlin.cronin): Use ValueBuilder when it's moved from
49 // chrome/common/extensions.
50 scoped_ptr
<DictionaryValue
> value(new DictionaryValue
);
51 value
->SetInteger(kTypeKey
, static_cast<int>(type_
));
52 value
->SetString(kExtensionIdKey
, extension_id_
);
53 value
->SetBoolean(kFromIncognitoKey
, from_incognito_
);
54 value
->SetInteger(kLevelKey
, static_cast<int>(level_
));
55 value
->SetString(kSourceKey
, source_
);
56 value
->SetString(kMessageKey
, message_
);
61 std::string
ExtensionError::PrintForTest() const {
62 return std::string("Extension Error:") +
63 "\n OTR: " + std::string(from_incognito_
? "true" : "false") +
64 "\n Level: " + base::IntToString(static_cast<int>(level_
)) +
65 "\n Source: " + base::UTF16ToUTF8(source_
) +
66 "\n Message: " + base::UTF16ToUTF8(message_
) +
67 "\n ID: " + extension_id_
;
70 bool ExtensionError::IsEqual(const ExtensionError
* rhs
) const {
71 // We don't check |source_| or |level_| here, since they are constant for
72 // manifest errors. Check them in RuntimeError::IsEqualImpl() instead.
73 return type_
== rhs
->type_
&&
74 extension_id_
== rhs
->extension_id_
&&
75 message_
== rhs
->message_
&&
79 ////////////////////////////////////////////////////////////////////////////////
83 const char ManifestError::kManifestKeyKey
[] = "manifestKey";
84 const char ManifestError::kManifestSpecificKey
[] = "manifestSpecific";
86 ManifestError::ManifestError(const std::string
& extension_id
,
87 const base::string16
& message
,
88 const base::string16
& manifest_key
,
89 const base::string16
& manifest_specific
)
90 : ExtensionError(ExtensionError::MANIFEST_ERROR
,
92 false, // extensions can't be installed while incognito.
93 logging::LOG_WARNING
, // All manifest errors are warnings.
94 base::FilePath(kManifestFilename
).AsUTF16Unsafe(),
96 manifest_key_(manifest_key
),
97 manifest_specific_(manifest_specific
) {
100 ManifestError::~ManifestError() {
103 scoped_ptr
<DictionaryValue
> ManifestError::ToValue() const {
104 scoped_ptr
<DictionaryValue
> value
= ExtensionError::ToValue();
105 if (!manifest_key_
.empty())
106 value
->SetString(kManifestKeyKey
, manifest_key_
);
107 if (!manifest_specific_
.empty())
108 value
->SetString(kManifestSpecificKey
, manifest_specific_
);
112 std::string
ManifestError::PrintForTest() const {
113 return ExtensionError::PrintForTest() +
114 "\n Type: ManifestError";
117 bool ManifestError::IsEqualImpl(const ExtensionError
* rhs
) const {
118 // If two manifest errors have the same extension id and message (which are
119 // both checked in ExtensionError::IsEqual), then they are equal.
123 ////////////////////////////////////////////////////////////////////////////////
127 const char RuntimeError::kColumnNumberKey
[] = "columnNumber";
128 const char RuntimeError::kContextUrlKey
[] = "contextUrl";
129 const char RuntimeError::kFunctionNameKey
[] = "functionName";
130 const char RuntimeError::kLineNumberKey
[] = "lineNumber";
131 const char RuntimeError::kStackTraceKey
[] = "stackTrace";
132 const char RuntimeError::kUrlKey
[] = "url";
133 const char RuntimeError::kRenderProcessIdKey
[] = "renderProcessId";
134 const char RuntimeError::kRenderViewIdKey
[] = "renderViewId";
136 RuntimeError::RuntimeError(const std::string
& extension_id
,
138 const base::string16
& source
,
139 const base::string16
& message
,
140 const StackTrace
& stack_trace
,
141 const GURL
& context_url
,
142 logging::LogSeverity level
,
144 int render_process_id
)
145 : ExtensionError(ExtensionError::RUNTIME_ERROR
,
146 !extension_id
.empty() ? extension_id
: GURL(source
).host(),
151 context_url_(context_url
),
152 stack_trace_(stack_trace
),
153 render_view_id_(render_view_id
),
154 render_process_id_(render_process_id
) {
158 RuntimeError::~RuntimeError() {
161 scoped_ptr
<DictionaryValue
> RuntimeError::ToValue() const {
162 // The items which are to be written into value are also described in
163 // chrome/browser/resources/extensions/extension_error_overlay.js in @typedef
164 // for RuntimeError and StackTrace. Please update them whenever you add or
165 // remove any keys here.
166 scoped_ptr
<DictionaryValue
> value
= ExtensionError::ToValue();
167 value
->SetString(kContextUrlKey
, context_url_
.spec());
168 value
->SetInteger(kRenderViewIdKey
, render_view_id_
);
169 value
->SetInteger(kRenderProcessIdKey
, render_process_id_
);
171 base::ListValue
* trace_value
= new base::ListValue
;
172 for (StackTrace::const_iterator iter
= stack_trace_
.begin();
173 iter
!= stack_trace_
.end(); ++iter
) {
174 DictionaryValue
* frame_value
= new DictionaryValue
;
175 frame_value
->SetInteger(kLineNumberKey
, iter
->line_number
);
176 frame_value
->SetInteger(kColumnNumberKey
, iter
->column_number
);
177 frame_value
->SetString(kUrlKey
, iter
->source
);
178 frame_value
->SetString(kFunctionNameKey
, iter
->function
);
179 trace_value
->Append(frame_value
);
182 value
->Set(kStackTraceKey
, trace_value
);
187 std::string
RuntimeError::PrintForTest() const {
188 std::string result
= ExtensionError::PrintForTest() +
189 "\n Type: RuntimeError"
190 "\n Context: " + context_url_
.spec() +
192 for (StackTrace::const_iterator iter
= stack_trace_
.begin();
193 iter
!= stack_trace_
.end(); ++iter
) {
195 "\n Line: " + base::IntToString(iter
->line_number
) +
196 "\n Column: " + base::IntToString(iter
->column_number
) +
197 "\n URL: " + base::UTF16ToUTF8(iter
->source
) +
198 "\n Function: " + base::UTF16ToUTF8(iter
->function
) +
204 bool RuntimeError::IsEqualImpl(const ExtensionError
* rhs
) const {
205 const RuntimeError
* error
= static_cast<const RuntimeError
*>(rhs
);
207 // Only look at the first frame of a stack trace to save time and group
208 // nearly-identical errors. The most recent error is kept, so there's no risk
209 // of displaying an old and inaccurate stack trace.
210 return level_
== error
->level_
&&
211 source_
== error
->source_
&&
212 context_url_
== error
->context_url_
&&
213 stack_trace_
.size() == error
->stack_trace_
.size() &&
214 (stack_trace_
.empty() || stack_trace_
[0] == error
->stack_trace_
[0]);
217 void RuntimeError::CleanUpInit() {
218 // If the error came from a generated background page, the "context" is empty
219 // because there's no visible URL. We should set context to be the generated
220 // background page in this case.
221 GURL source_url
= GURL(source_
);
222 if (context_url_
.is_empty() &&
224 std::string("/") + kGeneratedBackgroundPageFilename
) {
225 context_url_
= source_url
;
228 // In some instances (due to the fact that we're reusing error reporting from
229 // other systems), the source won't match up with the final entry in the stack
230 // trace. (For instance, in a browser action error, the source is the page -
231 // sometimes the background page - but the error is thrown from the script.)
232 // Make the source match the stack trace, since that is more likely the cause
234 if (!stack_trace_
.empty() && source_
!= stack_trace_
[0].source
)
235 source_
= stack_trace_
[0].source
;
238 } // namespace extensions