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

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

Powered by Google App Engine
This is Rietveld 408576698