Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(75)

Side by Side Diff: extensions/browser/extension_error.cc

Issue 22938005: Add ErrorConsole UI for Extension Install Warnings (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@dc_ec_install_warnings
Patch Set: Dan's Created 7 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "extensions/browser/extension_error.h" 5 #include "extensions/browser/extension_error.h"
6 6
7 #include "base/json/json_reader.h" 7 #include "base/json/json_reader.h"
8 #include "base/strings/string_number_conversions.h" 8 #include "base/strings/string_number_conversions.h"
9 #include "base/strings/utf_string_conversions.h" 9 #include "base/strings/utf_string_conversions.h"
10 #include "base/values.h" 10 #include "base/values.h"
11 #include "extensions/common/constants.h" 11 #include "extensions/common/constants.h"
12 #include "url/gurl.h" 12 #include "url/gurl.h"
13 13
14 using base::string16; 14 using base::string16;
15 using base::DictionaryValue;
15 16
16 namespace extensions { 17 namespace extensions {
17 18
18 namespace { 19 namespace {
19 20
21 const char kTypeKey[] = "type";
22 const char kSourceKey[] = "source";
23 const char kMessageKey[] = "message";
24 const char kExtensionIdKey[] = "extensionId";
25 const char kFromIncognitoKey[] = "fromIncognito";
26 const char kManifestKeyKey[] = "manifestKey";
27 const char kManifestSpecificKey[] = "manifestSpecific";
28 const char kLevelKey[] = "level";
20 const char kLineNumberKey[] = "lineNumber"; 29 const char kLineNumberKey[] = "lineNumber";
21 const char kColumnNumberKey[] = "columnNumber"; 30 const char kColumnNumberKey[] = "columnNumber";
22 const char kURLKey[] = "url"; 31 const char kURLKey[] = "url";
23 const char kFunctionNameKey[] = "functionName"; 32 const char kFunctionNameKey[] = "functionName";
24 const char kExecutionContextURLKey[] = "executionContextURL"; 33 const char kExecutionContextURLKey[] = "executionContextURL";
25 const char kStackTraceKey[] = "stackTrace"; 34 const char kStackTraceKey[] = "stackTrace";
26 35
27 // Try to retrieve an extension ID from a |url|. On success, returns true and 36 // Try to retrieve an extension ID from a |url|. On success, returns true and
28 // populates |extension_id| with the ID. On failure, returns false and leaves 37 // populates |extension_id| with the ID. On failure, returns false and leaves
29 // extension_id untouched. 38 // extension_id untouched.
30 bool GetExtensionIDFromGURL(const GURL& url, std::string* extension_id) { 39 bool GetExtensionIdFromGURL(const GURL& url, std::string* extension_id) {
31 if (url.SchemeIs(kExtensionScheme)) { 40 if (url.SchemeIs(kExtensionScheme)) {
32 *extension_id = url.host(); 41 *extension_id = url.host();
33 return true; 42 return true;
34 } 43 }
35 return false; 44 return false;
36 } 45 }
37 46
38 } // namespace 47 } // namespace
39 48
40 ExtensionError::ExtensionError(Type type, 49 ExtensionError::ExtensionError(Type type,
41 const std::string& extension_id, 50 const std::string& extension_id,
42 bool from_incognito, 51 bool from_incognito,
43 const string16& source, 52 const string16& source,
44 const string16& message) 53 const string16& message)
45 : type_(type), 54 : type_(type),
46 extension_id_(extension_id), 55 extension_id_(extension_id),
47 from_incognito_(from_incognito), 56 from_incognito_(from_incognito),
48 source_(source), 57 source_(source),
49 message_(message) { 58 message_(message) {
50 } 59 }
51 60
52 ExtensionError::~ExtensionError() { 61 ExtensionError::~ExtensionError() {
53 } 62 }
54 63
64 scoped_ptr<DictionaryValue> ExtensionError::ToValue() const {
65 scoped_ptr<DictionaryValue> value(new DictionaryValue);
66 value->SetInteger(kTypeKey, static_cast<int>(type_));
67 value->SetString(kExtensionIdKey, extension_id_);
68 value->SetBoolean(kFromIncognitoKey, from_incognito_);
69 value->SetString(kSourceKey, source_);
70 value->SetString(kMessageKey, message_);
71
72 return value.Pass();
73 }
74
55 std::string ExtensionError::PrintForTest() const { 75 std::string ExtensionError::PrintForTest() const {
56 return std::string("Extension Error:") + 76 return std::string("Extension Error:") +
57 "\n OTR: " + std::string(from_incognito_ ? "true" : "false") + 77 "\n OTR: " + std::string(from_incognito_ ? "true" : "false") +
58 "\n Source: " + base::UTF16ToUTF8(source_) + 78 "\n Source: " + base::UTF16ToUTF8(source_) +
59 "\n Message: " + base::UTF16ToUTF8(message_) + 79 "\n Message: " + base::UTF16ToUTF8(message_) +
60 "\n ID: " + extension_id_; 80 "\n ID: " + extension_id_;
61 } 81 }
62 82
63 ManifestParsingError::ManifestParsingError(const std::string& extension_id, 83 bool ExtensionError::IsEqual(const ExtensionError* rhs) const {
64 const string16& message) 84 return type_ == rhs->type_ &&
65 : ExtensionError(ExtensionError::MANIFEST_PARSING_ERROR, 85 extension_id_ == rhs->extension_id_ &&
86 source_ == rhs->source_ &&
87 message_ == rhs->message_ &&
88 IsEqualImpl(rhs);
89 }
90
91 ManifestError::ManifestError(const std::string& extension_id,
92 const string16& message,
93 const string16& manifest_key,
94 const string16& manifest_specific)
95 : ExtensionError(ExtensionError::MANIFEST_ERROR,
66 extension_id, 96 extension_id,
67 false, // extensions can't be installed while incognito. 97 false, // extensions can't be installed while incognito.
68 base::FilePath(kManifestFilename).AsUTF16Unsafe(), 98 base::FilePath(kManifestFilename).AsUTF16Unsafe(),
69 message) { 99 message),
100 manifest_key_(manifest_key),
101 manifest_specific_(manifest_specific) {
70 } 102 }
71 103
72 ManifestParsingError::~ManifestParsingError() { 104 ManifestError::~ManifestError() {
73 } 105 }
74 106
75 std::string ManifestParsingError::PrintForTest() const { 107 scoped_ptr<DictionaryValue> ManifestError::ToValue() const {
76 return ExtensionError::PrintForTest() + 108 scoped_ptr<DictionaryValue> value = ExtensionError::ToValue();
77 "\n Type: ManifestParsingError"; 109 // All manifest errors are warnings - if it was a fatal error, we wouldn't
110 // get far enough to add an error for the extension.
111 value->SetInteger(kLevelKey, logging::LOG_WARNING);
112 if (!manifest_key_.empty())
113 value->SetString(kManifestKeyKey, manifest_key_);
114 if (!manifest_specific_.empty())
115 value->SetString(kManifestSpecificKey, manifest_specific_);
116 return value.Pass();
78 } 117 }
79 118
80 JavascriptRuntimeError::StackFrame::StackFrame() : line_number(-1), 119 std::string ManifestError::PrintForTest() const {
81 column_number(-1) { 120 return ExtensionError::PrintForTest() +
121 "\n Type: ManifestError";
82 } 122 }
83 123
84 JavascriptRuntimeError::StackFrame::StackFrame(size_t frame_line, 124 bool ManifestError::IsEqualImpl(const ExtensionError* rhs) const {
85 size_t frame_column, 125 // If two manifest errors have the same extension id and message (which are
86 const string16& frame_url, 126 // both checked in ExtensionError::IsEqual), then they are equal.
87 const string16& frame_function) 127 return true;
128 }
129
130 RuntimeError::StackFrame::StackFrame() : line_number(-1),
131 column_number(-1) {
132 }
133
134 RuntimeError::StackFrame::StackFrame(size_t frame_line,
135 size_t frame_column,
136 const string16& frame_url,
137 const string16& frame_function)
88 : line_number(frame_line), 138 : line_number(frame_line),
89 column_number(frame_column), 139 column_number(frame_column),
90 url(frame_url), 140 url(frame_url),
91 function(frame_function) { 141 function(frame_function) {
92 } 142 }
93 143
94 JavascriptRuntimeError::StackFrame::~StackFrame() { 144 RuntimeError::StackFrame::~StackFrame() {
95 } 145 }
96 146
97 JavascriptRuntimeError::JavascriptRuntimeError(bool from_incognito, 147 bool RuntimeError::StackFrame::operator==(
98 const string16& source, 148 const RuntimeError::StackFrame& rhs) const {
99 const string16& message, 149 return line_number == rhs.line_number &&
100 logging::LogSeverity level, 150 column_number == rhs.column_number &&
101 const string16& details) 151 url == rhs.url &&
102 : ExtensionError(ExtensionError::JAVASCRIPT_RUNTIME_ERROR, 152 function == rhs.function;
153 }
154 RuntimeError::RuntimeError(bool from_incognito,
155 const string16& source,
156 const string16& message,
157 logging::LogSeverity level,
158 const string16& details)
159 : ExtensionError(ExtensionError::RUNTIME_ERROR,
103 std::string(), // We don't know the id yet. 160 std::string(), // We don't know the id yet.
104 from_incognito, 161 from_incognito,
105 source, 162 source,
106 message), 163 message),
107 level_(level) { 164 level_(level) {
108 ParseDetails(details); 165 ParseDetails(details);
109 DetermineExtensionID(); 166 DetermineExtensionId();
110 } 167 }
111 168
112 JavascriptRuntimeError::~JavascriptRuntimeError() { 169 RuntimeError::~RuntimeError() {
113 } 170 }
114 171
115 std::string JavascriptRuntimeError::PrintForTest() const { 172 std::string RuntimeError::PrintForTest() const {
116 std::string result = ExtensionError::PrintForTest() + 173 std::string result = ExtensionError::PrintForTest() +
117 "\n Type: JavascriptRuntimeError" 174 "\n Type: RuntimeError"
118 "\n Context: " + base::UTF16ToUTF8(execution_context_url_) + 175 "\n Context: " + base::UTF16ToUTF8(execution_context_url_) +
119 "\n Stack Trace: "; 176 "\n Stack Trace: ";
120 for (StackTrace::const_iterator iter = stack_trace_.begin(); 177 for (StackTrace::const_iterator iter = stack_trace_.begin();
121 iter != stack_trace_.end(); ++iter) { 178 iter != stack_trace_.end(); ++iter) {
122 result += "\n {" 179 result += "\n {"
123 "\n Line: " + base::IntToString(iter->line_number) + 180 "\n Line: " + base::IntToString(iter->line_number) +
124 "\n Column: " + base::IntToString(iter->column_number) + 181 "\n Column: " + base::IntToString(iter->column_number) +
125 "\n URL: " + base::UTF16ToUTF8(iter->url) + 182 "\n URL: " + base::UTF16ToUTF8(iter->url) +
126 "\n Function: " + base::UTF16ToUTF8(iter->function) + 183 "\n Function: " + base::UTF16ToUTF8(iter->function) +
127 "\n }"; 184 "\n }";
128 } 185 }
129 return result; 186 return result;
130 } 187 }
131 188
132 void JavascriptRuntimeError::ParseDetails(const string16& details) { 189 bool RuntimeError::IsEqualImpl(const ExtensionError* rhs) const {
190 const RuntimeError* error = static_cast<const RuntimeError*>(rhs);
191
192 // We don't look at the full stack trace, because if the first frame is
193 // the same, it's close enough to heuristically count as a duplicate (after
194 // all, the same line caused the error).
195 // If the stack trace is empty, just compare the context.
196 return execution_context_url_ == error->execution_context_url_ &&
197 stack_trace_.size() == error->stack_trace_.size() &&
198 (stack_trace_.empty() || stack_trace_[0] == error->stack_trace_[0]);
199 }
200
201 void RuntimeError::ParseDetails(const string16& details) {
133 scoped_ptr<base::Value> value( 202 scoped_ptr<base::Value> value(
134 base::JSONReader::Read(base::UTF16ToUTF8(details))); 203 base::JSONReader::Read(base::UTF16ToUTF8(details)));
135 const base::DictionaryValue* details_value; 204 const DictionaryValue* details_value;
136 const base::ListValue* trace_value = NULL; 205 const base::ListValue* trace_value = NULL;
137 206
138 // The |details| value should contain an execution context url and a stack 207 // The |details| value should contain an execution context url and a stack
139 // trace. 208 // trace.
140 if (!value.get() || 209 if (!value.get() ||
141 !value->GetAsDictionary(&details_value) || 210 !value->GetAsDictionary(&details_value) ||
142 !details_value->GetString(kExecutionContextURLKey, 211 !details_value->GetString(kExecutionContextURLKey,
143 &execution_context_url_) || 212 &execution_context_url_) ||
144 !details_value->GetList(kStackTraceKey, &trace_value)) { 213 !details_value->GetList(kStackTraceKey, &trace_value)) {
145 NOTREACHED(); 214 NOTREACHED();
146 return; 215 return;
147 } 216 }
148 217
149 int line = 0; 218 int line = 0;
150 int column = 0; 219 int column = 0;
151 string16 url; 220 string16 url;
152 221
153 for (size_t i = 0; i < trace_value->GetSize(); ++i) { 222 for (size_t i = 0; i < trace_value->GetSize(); ++i) {
154 const base::DictionaryValue* frame_value = NULL; 223 const DictionaryValue* frame_value = NULL;
155 CHECK(trace_value->GetDictionary(i, &frame_value)); 224 CHECK(trace_value->GetDictionary(i, &frame_value));
156 225
157 frame_value->GetInteger(kLineNumberKey, &line); 226 frame_value->GetInteger(kLineNumberKey, &line);
158 frame_value->GetInteger(kColumnNumberKey, &column); 227 frame_value->GetInteger(kColumnNumberKey, &column);
159 frame_value->GetString(kURLKey, &url); 228 frame_value->GetString(kURLKey, &url);
160 229
161 string16 function; 230 string16 function;
162 frame_value->GetString(kFunctionNameKey, &function); // This can be empty. 231 frame_value->GetString(kFunctionNameKey, &function); // This can be empty.
163 stack_trace_.push_back(StackFrame(line, column, url, function)); 232 stack_trace_.push_back(StackFrame(line, column, url, function));
164 } 233 }
165 } 234 }
166 235
167 void JavascriptRuntimeError::DetermineExtensionID() { 236 void RuntimeError::DetermineExtensionId() {
168 if (!GetExtensionIDFromGURL(GURL(source_), &extension_id_)) 237 if (!GetExtensionIdFromGURL(GURL(source_), &extension_id_))
169 GetExtensionIDFromGURL(GURL(execution_context_url_), &extension_id_); 238 GetExtensionIdFromGURL(GURL(execution_context_url_), &extension_id_);
170 } 239 }
171 240
172 } // namespace extensions 241 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698