- add sources.
[platform/framework/web/crosswalk.git] / src / extensions / browser / extension_error.cc
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.
4
5 #include "extensions/browser/extension_error.h"
6
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"
11 #include "url/gurl.h"
12
13 using base::string16;
14 using base::DictionaryValue;
15
16 namespace extensions {
17
18 ////////////////////////////////////////////////////////////////////////////////
19 // ExtensionError
20
21 // Static JSON keys.
22 const char ExtensionError::kExtensionIdKey[] = "extensionId";
23 const char ExtensionError::kFromIncognitoKey[] = "fromIncognito";
24 const char ExtensionError::kLevelKey[] = "level";
25 const char ExtensionError::kMessageKey[] = "message";
26 const char ExtensionError::kSourceKey[] = "source";
27 const char ExtensionError::kTypeKey[] = "type";
28
29 ExtensionError::ExtensionError(Type type,
30                                const std::string& extension_id,
31                                bool from_incognito,
32                                logging::LogSeverity level,
33                                const string16& source,
34                                const string16& message)
35     : type_(type),
36       extension_id_(extension_id),
37       from_incognito_(from_incognito),
38       level_(level),
39       source_(source),
40       message_(message),
41       occurrences_(1u) {
42 }
43
44 ExtensionError::~ExtensionError() {
45 }
46
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_);
57
58   return value.Pass();
59 }
60
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_;
68 }
69
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_ &&
76          IsEqualImpl(rhs);
77 }
78
79 ////////////////////////////////////////////////////////////////////////////////
80 // ManifestError
81
82 // Static JSON keys.
83 const char ManifestError::kManifestKeyKey[] = "manifestKey";
84 const char ManifestError::kManifestSpecificKey[] = "manifestSpecific";
85
86 ManifestError::ManifestError(const std::string& extension_id,
87                              const string16& message,
88                              const string16& manifest_key,
89                              const string16& manifest_specific)
90     : ExtensionError(ExtensionError::MANIFEST_ERROR,
91                      extension_id,
92                      false,  // extensions can't be installed while incognito.
93                      logging::LOG_WARNING,  // All manifest errors are warnings.
94                      base::FilePath(kManifestFilename).AsUTF16Unsafe(),
95                      message),
96       manifest_key_(manifest_key),
97       manifest_specific_(manifest_specific) {
98 }
99
100 ManifestError::~ManifestError() {
101 }
102
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_);
109   return value.Pass();
110 }
111
112 std::string ManifestError::PrintForTest() const {
113   return ExtensionError::PrintForTest() +
114          "\n  Type:    ManifestError";
115 }
116
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.
120   return true;
121 }
122
123 ////////////////////////////////////////////////////////////////////////////////
124 // RuntimeError
125
126 // Static JSON keys.
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";
135
136 RuntimeError::RuntimeError(const std::string& extension_id,
137                            bool from_incognito,
138                            const string16& source,
139                            const string16& message,
140                            const StackTrace& stack_trace,
141                            const GURL& context_url,
142                            logging::LogSeverity level,
143                            int render_view_id,
144                            int render_process_id)
145     : ExtensionError(ExtensionError::RUNTIME_ERROR,
146                      !extension_id.empty() ? extension_id : GURL(source).host(),
147                      from_incognito,
148                      level,
149                      source,
150                      message),
151       context_url_(context_url),
152       stack_trace_(stack_trace),
153       render_view_id_(render_view_id),
154       render_process_id_(render_process_id) {
155   CleanUpInit();
156 }
157
158 RuntimeError::~RuntimeError() {
159 }
160
161 scoped_ptr<DictionaryValue> RuntimeError::ToValue() const {
162   scoped_ptr<DictionaryValue> value = ExtensionError::ToValue();
163   value->SetString(kContextUrlKey, context_url_.spec());
164   value->SetInteger(kRenderViewIdKey, render_view_id_);
165   value->SetInteger(kRenderProcessIdKey, render_process_id_);
166
167   base::ListValue* trace_value = new base::ListValue;
168   for (StackTrace::const_iterator iter = stack_trace_.begin();
169        iter != stack_trace_.end(); ++iter) {
170     DictionaryValue* frame_value = new DictionaryValue;
171     frame_value->SetInteger(kLineNumberKey, iter->line_number);
172     frame_value->SetInteger(kColumnNumberKey, iter->column_number);
173     frame_value->SetString(kUrlKey, iter->source);
174     frame_value->SetString(kFunctionNameKey, iter->function);
175     trace_value->Append(frame_value);
176   }
177
178   value->Set(kStackTraceKey, trace_value);
179
180   return value.Pass();
181 }
182
183 std::string RuntimeError::PrintForTest() const {
184   std::string result = ExtensionError::PrintForTest() +
185          "\n  Type:    RuntimeError"
186          "\n  Context: " + context_url_.spec() +
187          "\n  Stack Trace: ";
188   for (StackTrace::const_iterator iter = stack_trace_.begin();
189        iter != stack_trace_.end(); ++iter) {
190     result += "\n    {"
191               "\n      Line:     " + base::IntToString(iter->line_number) +
192               "\n      Column:   " + base::IntToString(iter->column_number) +
193               "\n      URL:      " + base::UTF16ToUTF8(iter->source) +
194               "\n      Function: " + base::UTF16ToUTF8(iter->function) +
195               "\n    }";
196   }
197   return result;
198 }
199
200 bool RuntimeError::IsEqualImpl(const ExtensionError* rhs) const {
201   const RuntimeError* error = static_cast<const RuntimeError*>(rhs);
202
203   // Only look at the first frame of a stack trace to save time and group
204   // nearly-identical errors. The most recent error is kept, so there's no risk
205   // of displaying an old and inaccurate stack trace.
206   return level_ == error->level_ &&
207          source_ == error->source_ &&
208          context_url_ == error->context_url_ &&
209          stack_trace_.size() == error->stack_trace_.size() &&
210          (stack_trace_.empty() || stack_trace_[0] == error->stack_trace_[0]);
211 }
212
213 void RuntimeError::CleanUpInit() {
214   // If the error came from a generated background page, the "context" is empty
215   // because there's no visible URL. We should set context to be the generated
216   // background page in this case.
217   GURL source_url = GURL(source_);
218   if (context_url_.is_empty() &&
219       source_url.path() ==
220           std::string("/") + kGeneratedBackgroundPageFilename) {
221     context_url_ = source_url;
222   }
223
224   // In some instances (due to the fact that we're reusing error reporting from
225   // other systems), the source won't match up with the final entry in the stack
226   // trace. (For instance, in a browser action error, the source is the page -
227   // sometimes the background page - but the error is thrown from the script.)
228   // Make the source match the stack trace, since that is more likely the cause
229   // of the error.
230   if (!stack_trace_.empty() && source_ != stack_trace_[0].source)
231     source_ = stack_trace_[0].source;
232 }
233
234 }  // namespace extensions