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

Side by Side Diff: chrome/browser/extensions/extension_warning_set.cc

Issue 10407105: Improve error messaging of webRequest API in case of conflicts (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Merged with ToT Created 8 years, 2 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 | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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 "chrome/browser/extensions/extension_warning_set.h" 5 #include "chrome/browser/extensions/extension_warning_set.h"
6 6
7 #include "base/utf_string_conversions.h"
7 #include "chrome/browser/browser_process.h" 8 #include "chrome/browser/browser_process.h"
8 #include "chrome/browser/extensions/extension_global_error_badge.h"
9 #include "chrome/browser/extensions/extension_service.h" 9 #include "chrome/browser/extensions/extension_service.h"
10 #include "chrome/browser/extensions/extension_system.h"
10 #include "chrome/browser/profiles/profile.h" 11 #include "chrome/browser/profiles/profile.h"
11 #include "chrome/browser/profiles/profile_manager.h" 12 #include "chrome/browser/profiles/profile_manager.h"
12 #include "chrome/browser/ui/global_error/global_error_service.h"
13 #include "chrome/browser/ui/global_error/global_error_service_factory.h"
14 #include "chrome/common/chrome_notification_types.h" 13 #include "chrome/common/chrome_notification_types.h"
14 #include "chrome/common/extensions/extension.h"
15 #include "chrome/common/extensions/extension_set.h"
15 #include "content/public/browser/browser_thread.h" 16 #include "content/public/browser/browser_thread.h"
16 #include "content/public/browser/notification_service.h" 17 #include "content/public/browser/notification_service.h"
17 #include "grit/chromium_strings.h" 18 #include "grit/chromium_strings.h"
18 #include "grit/generated_resources.h" 19 #include "grit/generated_resources.h"
20 #include "net/base/escape.h"
19 #include "ui/base/l10n/l10n_util.h" 21 #include "ui/base/l10n/l10n_util.h"
20 22
21 using content::BrowserThread; 23 using content::BrowserThread;
22 24
23 // This class is used to represent warnings if extensions misbehave. 25 namespace {
24 class ExtensionWarning { 26 // Prefix for message parameters indicating that the parameter needs to
25 public: 27 // be translated from an extension id to the extension name.
26 // Default constructor for storing ExtensionServiceWarning in STL containers 28 const char kTranslate[] = "TO_TRANSLATE:";
27 // do not use. 29 const size_t kMaxNumberOfParameters = 4;
28 ExtensionWarning(); 30 }
29 31
30 // Constructs a warning of type |type| for extension |extension_id|. This 32 namespace extensions {
31 // could be for example the fact that an extension conflicted with others. 33
32 ExtensionWarning(ExtensionWarningSet::WarningType type, 34 //
33 const std::string& extension_id); 35 // ExtensionWarning
34 36 //
35 ~ExtensionWarning();
36
37 // Returns the specific warning type.
38 ExtensionWarningSet::WarningType warning_type() const { return type_; }
39
40 // Returns the id of the extension for which this warning is valid.
41 const std::string& extension_id() const { return extension_id_; }
42
43 private:
44 ExtensionWarningSet::WarningType type_;
45 std::string extension_id_;
46
47 // Allow implicit copy and assign operator.
48 };
49
50 ExtensionWarning::ExtensionWarning() : type_(ExtensionWarningSet::kInvalid) {
51 }
52 37
53 ExtensionWarning::ExtensionWarning( 38 ExtensionWarning::ExtensionWarning(
54 ExtensionWarningSet::WarningType type, 39 WarningType type,
55 const std::string& extension_id) 40 const std::string& extension_id,
56 : type_(type), extension_id_(extension_id) { 41 int message_id,
42 const std::vector<std::string>& message_parameters)
43 : type_(type),
44 extension_id_(extension_id),
45 message_id_(message_id),
46 message_parameters_(message_parameters) {
57 // These are invalid here because they do not have corresponding warning 47 // These are invalid here because they do not have corresponding warning
58 // messages in the UI. 48 // messages in the UI.
59 CHECK(type != ExtensionWarningSet::kInvalid); 49 CHECK_NE(type, kInvalid);
60 CHECK(type != ExtensionWarningSet::kMaxWarningType); 50 CHECK_NE(type, kMaxWarningType);
61 } 51 CHECK_LE(message_parameters.size(), kMaxNumberOfParameters);
52 }
53
54 ExtensionWarning::ExtensionWarning(const ExtensionWarning& other)
55 : type_(other.type_),
56 extension_id_(other.extension_id_),
57 message_id_(other.message_id_),
58 message_parameters_(other.message_parameters_) {}
62 59
63 ExtensionWarning::~ExtensionWarning() { 60 ExtensionWarning::~ExtensionWarning() {
64 } 61 }
65 62
63 ExtensionWarning& ExtensionWarning::operator=(const ExtensionWarning& other) {
64 type_ = other.type_;
65 extension_id_ = other.extension_id_;
66 message_id_ = other.message_id_;
67 message_parameters_ = other.message_parameters_;
68 return *this;
69 }
70
71 // static
72 ExtensionWarning ExtensionWarning::CreateNetworkDelayWarning(
73 const std::string& extension_id) {
74 std::vector<std::string> message_parameters;
75 message_parameters.push_back(l10n_util::GetStringUTF8(IDS_PRODUCT_NAME));
76 return ExtensionWarning(
77 kNetworkDelay,
78 extension_id,
79 IDS_EXTENSION_WARNINGS_NETWORK_DELAY,
80 message_parameters);
81 }
82
83 // static
84 ExtensionWarning ExtensionWarning::CreateNetworkConflictWarning(
85 const std::string& extension_id) {
86 std::vector<std::string> message_parameters;
87 return ExtensionWarning(
88 kNetworkConflict,
89 extension_id,
90 IDS_EXTENSION_WARNINGS_NETWORK_CONFLICT,
91 message_parameters);
92 }
93
94 // static
95 ExtensionWarning ExtensionWarning::CreateRedirectConflictWarning(
96 const std::string& extension_id,
97 const std::string& winning_extension_id,
98 const GURL& attempted_redirect_url,
99 const GURL& winning_redirect_url) {
100 std::vector<std::string> message_parameters;
101 message_parameters.push_back(attempted_redirect_url.spec());
102 message_parameters.push_back(kTranslate + winning_extension_id);
103 message_parameters.push_back(winning_redirect_url.spec());
104 return ExtensionWarning(
105 kRedirectConflict,
106 extension_id,
107 IDS_EXTENSION_WARNINGS_REDIRECT_CONFLICT,
108 message_parameters);
109 }
110
111 // static
112 ExtensionWarning ExtensionWarning::CreateRequestHeaderConflictWarning(
113 const std::string& extension_id,
114 const std::string& winning_extension_id,
115 const std::string& conflicting_header) {
116 std::vector<std::string> message_parameters;
117 message_parameters.push_back(conflicting_header);
118 message_parameters.push_back(kTranslate + winning_extension_id);
119 return ExtensionWarning(
120 kNetworkConflict,
121 extension_id,
122 IDS_EXTENSION_WARNINGS_REQUEST_HEADER_CONFLICT,
123 message_parameters);
124 }
125
126 // static
127 ExtensionWarning ExtensionWarning::CreateResponseHeaderConflictWarning(
128 const std::string& extension_id,
129 const std::string& winning_extension_id,
130 const std::string& conflicting_header) {
131 std::vector<std::string> message_parameters;
132 message_parameters.push_back(conflicting_header);
133 message_parameters.push_back(kTranslate + winning_extension_id);
134 return ExtensionWarning(
135 kNetworkConflict,
136 extension_id,
137 IDS_EXTENSION_WARNINGS_RESPONSE_HEADER_CONFLICT,
138 message_parameters);
139 }
140
141 // static
142 ExtensionWarning ExtensionWarning::CreateCredentialsConflictWarning(
143 const std::string& extension_id,
144 const std::string& winning_extension_id) {
145 std::vector<std::string> message_parameters;
146 message_parameters.push_back(kTranslate + winning_extension_id);
147 return ExtensionWarning(
148 kNetworkConflict,
149 extension_id,
150 IDS_EXTENSION_WARNINGS_CREDENTIALS_CONFLICT,
151 message_parameters);
152 }
153
154 // static
155 ExtensionWarning ExtensionWarning::CreateRepeatedCacheFlushesWarning(
156 const std::string& extension_id) {
157 std::vector<std::string> message_parameters;
158 message_parameters.push_back(l10n_util::GetStringUTF8(IDS_PRODUCT_NAME));
159 return ExtensionWarning(
160 kRepeatedCacheFlushes,
161 extension_id,
162 IDS_EXTENSION_WARNINGS_NETWORK_DELAY,
163 message_parameters);
164 }
165
166 const std::string ExtensionWarning::GetMessage(
167 const ExtensionSet* extensions) const {
168 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
169
170 // These parameters may be unsafe (URLs and Extension names) and need
171 // to be HTML-escaped before being embedded in the UI. Also extension IDs
172 // are translated to full extension names.
173 std::vector<string16> final_parameters;
174 for (size_t i = 0; i < message_parameters_.size(); ++i) {
175 std::string message = message_parameters_[i];
176 if (StartsWithASCII(message, kTranslate, true)) {
177 std::string extension_id = message.substr(sizeof(kTranslate) - 1);
178 const extensions::Extension* extension =
179 extensions->GetByID(extension_id);
180 message = extension ? extension->name() : extension_id;
181 }
182 final_parameters.push_back(UTF8ToUTF16(net::EscapeForHTML(message)));
183 }
184
185 COMPILE_ASSERT(kMaxNumberOfParameters == 4u, YouNeedToAddMoreCaseStatements);
186 switch (final_parameters.size()) {
187 case 0:
188 return l10n_util::GetStringUTF8(message_id_);
189 case 1:
190 return l10n_util::GetStringFUTF8(message_id_, final_parameters[0]);
191 case 2:
192 return l10n_util::GetStringFUTF8(message_id_, final_parameters[0],
193 final_parameters[1]);
194 case 3:
195 return l10n_util::GetStringFUTF8(message_id_, final_parameters[0],
196 final_parameters[1], final_parameters[2]);
197 case 4:
198 return l10n_util::GetStringFUTF8(message_id_, final_parameters[0],
199 final_parameters[1], final_parameters[2], final_parameters[3]);
200 default:
201 NOTREACHED();
202 return std::string();
203 }
204 }
205
66 bool operator<(const ExtensionWarning& a, const ExtensionWarning& b) { 206 bool operator<(const ExtensionWarning& a, const ExtensionWarning& b) {
67 if (a.warning_type() == b.warning_type()) 207 if (a.extension_id() != b.extension_id())
68 return a.extension_id() < b.extension_id(); 208 return a.extension_id() < b.extension_id();
69 return a.warning_type() < b.warning_type(); 209 return a.warning_type() < b.warning_type();
70 } 210 }
71 211
72 // Static 212 //
73 string16 ExtensionWarningSet::GetLocalizedWarning( 213 // ExtensionWarningSet
74 ExtensionWarningSet::WarningType warning_type) { 214 //
75 switch (warning_type) { 215
76 case kInvalid: 216 ExtensionWarningSet::ExtensionWarningSet(Profile* profile)
77 case kMaxWarningType: 217 : profile_(profile) {
78 NOTREACHED(); 218 DCHECK(CalledOnValidThread());
79 return string16(); 219 if (profile_) {
80 case kNetworkDelay: 220 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED,
Aaron Boodman 2012/10/16 06:06:05 Sigh, this isn't what I had in mind for a "dumb da
81 return l10n_util::GetStringFUTF16( 221 content::Source<Profile>(profile_->GetOriginalProfile()));
82 IDS_EXTENSION_WARNINGS_NETWORK_DELAY,
83 l10n_util::GetStringUTF16(IDS_PRODUCT_NAME));
84 case kNetworkConflict:
85 return l10n_util::GetStringUTF16(IDS_EXTENSION_WARNINGS_NETWORK_CONFLICT);
86 case kRepeatedCacheFlushes:
87 return l10n_util::GetStringFUTF16(
88 IDS_EXTENSION_WARNINGS_NETWORK_DELAY,
89 l10n_util::GetStringUTF16(IDS_PRODUCT_NAME));
90 } 222 }
91 NOTREACHED(); // Switch statement has no default branch. 223 }
92 return string16(); 224
93 } 225 ExtensionWarningSet::~ExtensionWarningSet() {}
94
95 ExtensionWarningSet::ExtensionWarningSet(Profile* profile) : profile_(profile) {
96 }
97
98 ExtensionWarningSet::~ExtensionWarningSet() {
99 }
100
101 void ExtensionWarningSet::SetWarning(ExtensionWarningSet::WarningType type,
102 const std::string& extension_id) {
103 ExtensionWarning warning(type, extension_id);
104 bool inserted = warnings_.insert(warning).second;
105 if (inserted) {
106 NotifyWarningsChanged();
107 UpdateWarningBadge();
108 }
109 }
110 226
111 void ExtensionWarningSet::ClearWarnings( 227 void ExtensionWarningSet::ClearWarnings(
112 const std::set<ExtensionWarningSet::WarningType>& types) { 228 const std::set<ExtensionWarning::WarningType>& types) {
229 DCHECK(CalledOnValidThread());
113 bool deleted_anything = false; 230 bool deleted_anything = false;
114 for (iterator i = warnings_.begin(); i != warnings_.end();) { 231 for (iterator i = warnings_.begin(); i != warnings_.end();) {
115 if (types.find(i->warning_type()) != types.end()) { 232 if (types.find(i->warning_type()) != types.end()) {
116 deleted_anything = true; 233 deleted_anything = true;
117 warnings_.erase(i++); 234 warnings_.erase(i++);
118 } else { 235 } else {
119 ++i; 236 ++i;
120 } 237 }
121 } 238 }
122 239
123 if (deleted_anything) { 240 if (deleted_anything)
124 NotifyWarningsChanged(); 241 NotifyWarningsChanged();
125 UpdateWarningBadge();
126 }
127 } 242 }
128 243
129 void ExtensionWarningSet::GetWarningsAffectingExtension( 244 void ExtensionWarningSet::GetWarningTypesAffectingExtension(
130 const std::string& extension_id, 245 const std::string& extension_id,
131 std::set<ExtensionWarningSet::WarningType>* result) const { 246 std::set<ExtensionWarning::WarningType>* result) const {
247 DCHECK(CalledOnValidThread());
132 result->clear(); 248 result->clear();
133 for (const_iterator i = warnings_.begin(); i != warnings_.end(); ++i) { 249 for (const_iterator i = warnings_.begin(); i != warnings_.end(); ++i) {
134 if (i->extension_id() == extension_id) 250 if (i->extension_id() == extension_id)
135 result->insert(i->warning_type()); 251 result->insert(i->warning_type());
136 } 252 }
137 } 253 }
138 254
255 void ExtensionWarningSet::GetWarningMessagesForExtension(
256 const std::string& extension_id,
257 std::vector<std::string>* result) const {
258 DCHECK(CalledOnValidThread());
259 result->clear();
260
261 const ExtensionService* extension_service =
262 ExtensionSystem::Get(profile_)->extension_service();
263
264 for (const_iterator i = warnings_.begin(); i != warnings_.end(); ++i) {
265 if (i->extension_id() == extension_id)
266 result->push_back(i->GetMessage(extension_service->extensions()));
267 }
268 }
269
270 void ExtensionWarningSet::AddWarnings(
271 const std::set<ExtensionWarning>& warnings) {
272 DCHECK(CalledOnValidThread());
273 size_t old_size = warnings_.size();
274
275 warnings_.insert(warnings.begin(), warnings.end());
276
277 if (old_size != warnings_.size())
278 NotifyWarningsChanged();
279 }
280
139 // static 281 // static
140 void ExtensionWarningSet::NotifyWarningsOnUI( 282 void ExtensionWarningSet::NotifyWarningsOnUI(
141 void* profile_id, 283 void* profile_id,
142 std::set<std::string> extension_ids, 284 std::set<ExtensionWarning> warnings) {
143 WarningType warning_type) { 285 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
144 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
145 Profile* profile = reinterpret_cast<Profile*>(profile_id); 286 Profile* profile = reinterpret_cast<Profile*>(profile_id);
146 if (!profile || 287 if (!profile ||
147 !g_browser_process->profile_manager() || 288 !g_browser_process->profile_manager() ||
148 !g_browser_process->profile_manager()->IsValidProfile(profile)) { 289 !g_browser_process->profile_manager()->IsValidProfile(profile)) {
149 return; 290 return;
150 } 291 }
151 292
152 ExtensionWarningSet* warnings = 293 extensions::ExtensionWarningSet* warning_set =
153 profile->GetExtensionService()->extension_warnings(); 294 extensions::ExtensionSystem::Get(profile)->warning_set();
154 295
155 for (std::set<std::string>::const_iterator i = extension_ids.begin(); 296 warning_set->AddWarnings(warnings);
156 i != extension_ids.end(); ++i) { 297 }
157 warnings->SetWarning(warning_type, *i); 298
299 void ExtensionWarningSet::AddObserver(Observer* observer) {
300 observer_list_.AddObserver(observer);
301 }
302
303 void ExtensionWarningSet::RemoveObserver(Observer* observer) {
304 observer_list_.RemoveObserver(observer);
305 }
306
307 void ExtensionWarningSet::NotifyWarningsChanged() {
308 DCHECK(CalledOnValidThread());
309 FOR_EACH_OBSERVER(Observer, observer_list_, ExtensionWarningsChanged());
310 }
311
312 void ExtensionWarningSet::Observe(
313 int type,
314 const content::NotificationSource& source,
315 const content::NotificationDetails& details) {
316 switch (type) {
317 case chrome::NOTIFICATION_EXTENSION_UNLOADED: {
318 const Extension* extension =
319 content::Details<extensions::UnloadedExtensionInfo>(details)->
320 extension;
321 // Unloading one extension might have solved the problems of others.
322 // Therefore, we clear warnings of this type for all extensions.
323 std::set<ExtensionWarning::WarningType> warning_types;
324 GetWarningTypesAffectingExtension(extension->id(), &warning_types);
325 ClearWarnings(warning_types);
326 break;
327 }
328 default:
329 NOTREACHED();
330 break;
158 } 331 }
159 } 332 }
160 333
161 void ExtensionWarningSet::SuppressBadgeForCurrentWarnings() { 334 } // namespace extensions
162 badge_suppressions_.insert(warnings_.begin(), warnings_.end());
163 UpdateWarningBadge();
164 }
165
166 void ExtensionWarningSet::NotifyWarningsChanged() {
167 content::NotificationService::current()->Notify(
168 chrome::NOTIFICATION_EXTENSION_WARNING_CHANGED,
169 content::Source<Profile>(profile_),
170 content::NotificationService::NoDetails());
171 }
172
173 void ExtensionWarningSet::UpdateWarningBadge() {
174 // We need a badge if a warning exists that has not been suppressed.
175 bool need_warning_badge = false;
176 for (const_iterator i = warnings_.begin(); i != warnings_.end(); ++i) {
177 if (badge_suppressions_.find(*i) == badge_suppressions_.end()) {
178 need_warning_badge = true;
179 break;
180 }
181 }
182
183 GlobalErrorService* service =
184 GlobalErrorServiceFactory::GetForProfile(profile_);
185 GlobalError* error = service->GetGlobalErrorByMenuItemCommandID(
186 ExtensionGlobalErrorBadge::GetMenuItemCommandID());
187
188 // Activate or hide the warning badge in case the current state is incorrect.
189 if (error && !need_warning_badge) {
190 service->RemoveGlobalError(error);
191 delete error;
192 } else if (!error && need_warning_badge) {
193 service->AddGlobalError(new ExtensionGlobalErrorBadge);
194 }
195 }
OLDNEW
« no previous file with comments | « chrome/browser/extensions/extension_warning_set.h ('k') | chrome/browser/extensions/extension_warning_set_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698