• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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::DictionaryValue;
14 
15 namespace extensions {
16 
17 ////////////////////////////////////////////////////////////////////////////////
18 // ExtensionError
19 
20 // Static JSON keys.
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";
27 
ExtensionError(Type type,const std::string & extension_id,bool from_incognito,logging::LogSeverity level,const base::string16 & source,const base::string16 & message)28 ExtensionError::ExtensionError(Type type,
29                                const std::string& extension_id,
30                                bool from_incognito,
31                                logging::LogSeverity level,
32                                const base::string16& source,
33                                const base::string16& message)
34     : type_(type),
35       extension_id_(extension_id),
36       from_incognito_(from_incognito),
37       level_(level),
38       source_(source),
39       message_(message),
40       occurrences_(1u) {
41 }
42 
~ExtensionError()43 ExtensionError::~ExtensionError() {
44 }
45 
ToValue() const46 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_);
56 
57   return value.Pass();
58 }
59 
PrintForTest() const60 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_;
67 }
68 
IsEqual(const ExtensionError * rhs) const69 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_ &&
75          IsEqualImpl(rhs);
76 }
77 
78 ////////////////////////////////////////////////////////////////////////////////
79 // ManifestError
80 
81 // Static JSON keys.
82 const char ManifestError::kManifestKeyKey[] = "manifestKey";
83 const char ManifestError::kManifestSpecificKey[] = "manifestSpecific";
84 
ManifestError(const std::string & extension_id,const base::string16 & message,const base::string16 & manifest_key,const base::string16 & manifest_specific)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,
90                      extension_id,
91                      false,  // extensions can't be installed while incognito.
92                      logging::LOG_WARNING,  // All manifest errors are warnings.
93                      base::FilePath(kManifestFilename).AsUTF16Unsafe(),
94                      message),
95       manifest_key_(manifest_key),
96       manifest_specific_(manifest_specific) {
97 }
98 
~ManifestError()99 ManifestError::~ManifestError() {
100 }
101 
ToValue() const102 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_);
108   return value.Pass();
109 }
110 
PrintForTest() const111 std::string ManifestError::PrintForTest() const {
112   return ExtensionError::PrintForTest() +
113          "\n  Type:    ManifestError";
114 }
115 
IsEqualImpl(const ExtensionError * rhs) const116 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.
119   return true;
120 }
121 
122 ////////////////////////////////////////////////////////////////////////////////
123 // RuntimeError
124 
125 // Static JSON keys.
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";
134 
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_view_id,int render_process_id)135 RuntimeError::RuntimeError(const std::string& extension_id,
136                            bool from_incognito,
137                            const base::string16& source,
138                            const base::string16& message,
139                            const StackTrace& stack_trace,
140                            const GURL& context_url,
141                            logging::LogSeverity level,
142                            int render_view_id,
143                            int render_process_id)
144     : ExtensionError(ExtensionError::RUNTIME_ERROR,
145                      !extension_id.empty() ? extension_id : GURL(source).host(),
146                      from_incognito,
147                      level,
148                      source,
149                      message),
150       context_url_(context_url),
151       stack_trace_(stack_trace),
152       render_view_id_(render_view_id),
153       render_process_id_(render_process_id) {
154   CleanUpInit();
155 }
156 
~RuntimeError()157 RuntimeError::~RuntimeError() {
158 }
159 
ToValue() const160 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_);
169 
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);
179   }
180 
181   value->Set(kStackTraceKey, trace_value);
182 
183   return value.Pass();
184 }
185 
PrintForTest() const186 std::string RuntimeError::PrintForTest() const {
187   std::string result = ExtensionError::PrintForTest() +
188          "\n  Type:    RuntimeError"
189          "\n  Context: " + context_url_.spec() +
190          "\n  Stack Trace: ";
191   for (StackTrace::const_iterator iter = stack_trace_.begin();
192        iter != stack_trace_.end(); ++iter) {
193     result += "\n    {"
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) +
198               "\n    }";
199   }
200   return result;
201 }
202 
IsEqualImpl(const ExtensionError * rhs) const203 bool RuntimeError::IsEqualImpl(const ExtensionError* rhs) const {
204   const RuntimeError* error = static_cast<const RuntimeError*>(rhs);
205 
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]);
214 }
215 
CleanUpInit()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() &&
222       source_url.path() ==
223           std::string("/") + kGeneratedBackgroundPageFilename) {
224     context_url_ = source_url;
225   }
226 
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
232   // of the error.
233   if (!stack_trace_.empty() && source_ != stack_trace_[0].source)
234     source_ = stack_trace_[0].source;
235 }
236 
237 }  // namespace extensions
238