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

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

Issue 1543923002: [Extensions] Fix chrome url override settings (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Latest master Created 4 years, 11 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 (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_web_ui.h" 5 #include "chrome/browser/extensions/extension_web_ui.h"
6 6
7 #include <stddef.h> 7 #include <stddef.h>
8 8
9 #include <set> 9 #include <set>
10 #include <vector> 10 #include <vector>
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
42 #include "ui/gfx/codec/png_codec.h" 42 #include "ui/gfx/codec/png_codec.h"
43 #include "ui/gfx/favicon_size.h" 43 #include "ui/gfx/favicon_size.h"
44 #include "ui/gfx/image/image_skia.h" 44 #include "ui/gfx/image/image_skia.h"
45 45
46 using content::WebContents; 46 using content::WebContents;
47 using extensions::Extension; 47 using extensions::Extension;
48 using extensions::URLOverrides; 48 using extensions::URLOverrides;
49 49
50 namespace { 50 namespace {
51 51
52 // De-dupes the items in |list|. Assumes the values are strings. 52 // The key to the override value for a page.
53 void CleanUpDuplicates(base::ListValue* list) { 53 const char kEntry[] = "entry";
54 std::set<std::string> seen_values; 54 // The key to whether or not the override is active (i.e., can be used).
55 // Overrides may be inactive e.g. when an extension is disabled.
56 const char kActive[] = "active";
55 57
56 // Loop backwards as we may be removing items. 58 // Iterates over |list| and:
57 for (size_t i = list->GetSize() - 1; (i + 1) > 0; --i) { 59 // - Converts any entries of the form <entry> to
58 std::string value; 60 // { 'entry': <entry>, 'active': true }.
59 if (!list->GetString(i, &value)) { 61 // - Removes any duplicate entries.
62 // We do the conversion because we previously stored these values as strings
63 // rather than objects.
64 // TODO(devlin): Remove the conversion once everyone's updated.
65 void InitializeOverridesList(base::ListValue* list) {
66 base::ListValue migrated;
67 std::set<std::string> seen_entries;
68 for (base::Value* val : *list) {
69 scoped_ptr<base::DictionaryValue> new_dict(new base::DictionaryValue());
70 std::string entry_name;
71 base::DictionaryValue* existing_dict = nullptr;
72 if (val->GetAsDictionary(&existing_dict)) {
73 bool success = existing_dict->GetString(kEntry, &entry_name);
74 CHECK(success);
75 new_dict->Swap(existing_dict);
76 } else if (val->GetAsString(&entry_name)) {
77 new_dict->SetString(kEntry, entry_name);
78 new_dict->SetBoolean(kActive, true);
79 } else {
60 NOTREACHED(); 80 NOTREACHED();
61 continue; 81 continue;
62 } 82 }
63 83
64 if (seen_values.find(value) == seen_values.end()) 84 if (seen_entries.count(entry_name) == 0) {
65 seen_values.insert(value); 85 seen_entries.insert(entry_name);
66 else 86 migrated.Append(std::move(new_dict));
67 list->Remove(i, NULL); 87 }
68 } 88 }
89
90 list->Swap(&migrated);
91 }
92
93 // Adds |override| to |list|, or, if there's already an entry for the override,
94 // marks it as active.
95 void AddOverridesToList(base::ListValue* list,
96 const std::string& override) {
97 for (base::Value* val : *list) {
98 base::DictionaryValue* dict = nullptr;
99 std::string entry;
100 if (!val->GetAsDictionary(&dict) || !dict->GetString(kEntry, &entry)) {
101 NOTREACHED();
102 continue;
103 }
104 if (entry == override) {
105 dict->SetBoolean(kActive, true);
106 return; // All done!
107 }
108 }
109
110 scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
111 dict->SetString(kEntry, override);
112 dict->SetBoolean(kActive, true);
113 // Add the entry to the front of the list.
114 list->Insert(0, dict.release());
115 }
116
117 // Validates that each entry in |list| contains a valid url and points to an
118 // extension contained in |all_extensions| (and, if not, removes it).
119 void ValidateOverridesList(base::ListValue* list,
120 const extensions::ExtensionSet& all_extensions) {
121 base::ListValue migrated;
122 for (base::Value* val : *list) {
123 base::DictionaryValue* dict = nullptr;
124 std::string entry;
125 if (!val->GetAsDictionary(&dict) || !dict->GetString(kEntry, &entry)) {
126 NOTREACHED();
127 continue;
128 }
129 scoped_ptr<base::DictionaryValue> new_dict(new base::DictionaryValue());
130 new_dict->Swap(dict);
131 GURL override_url(entry);
132 if (!override_url.is_valid())
133 continue;
134
135 if (!all_extensions.GetByID(override_url.host()))
136 continue;
137
138 migrated.Append(std::move(new_dict));
139 }
140
141 list->Swap(&migrated);
69 } 142 }
70 143
71 // Reloads the page in |web_contents| if it uses the same profile as |profile| 144 // Reloads the page in |web_contents| if it uses the same profile as |profile|
72 // and if the current URL is a chrome URL. 145 // and if the current URL is a chrome URL.
73 void UnregisterAndReplaceOverrideForWebContents(const std::string& page, 146 void UnregisterAndReplaceOverrideForWebContents(const std::string& page,
74 Profile* profile, 147 Profile* profile,
75 WebContents* web_contents) { 148 WebContents* web_contents) {
76 if (Profile::FromBrowserContext(web_contents->GetBrowserContext()) != profile) 149 if (Profile::FromBrowserContext(web_contents->GetBrowserContext()) != profile)
77 return; 150 return;
78 151
79 GURL url = web_contents->GetURL(); 152 GURL url = web_contents->GetURL();
80 if (!url.SchemeIs(content::kChromeUIScheme) || url.host_piece() != page) 153 if (!url.SchemeIs(content::kChromeUIScheme) || url.host_piece() != page)
81 return; 154 return;
82 155
83 // Don't use Reload() since |url| isn't the same as the internal URL that 156 // Don't use Reload() since |url| isn't the same as the internal URL that
84 // NavigationController has. 157 // NavigationController has.
85 web_contents->GetController().LoadURL( 158 web_contents->GetController().LoadURL(
86 url, content::Referrer::SanitizeForRequest( 159 url, content::Referrer::SanitizeForRequest(
87 url, content::Referrer(url, blink::WebReferrerPolicyDefault)), 160 url, content::Referrer(url, blink::WebReferrerPolicyDefault)),
88 ui::PAGE_TRANSITION_RELOAD, std::string()); 161 ui::PAGE_TRANSITION_RELOAD, std::string());
89 } 162 }
90 163
164 enum UpdateBehavior {
165 UPDATE_DEACTIVATE, // Mark 'active' as false.
166 UPDATE_REMOVE, // Remove the entry from the list.
167 };
168
169 // Updates the entry (if any) for |override_url| in |overrides_list| according
170 // to |behavior|. Returns true if anything changed.
171 bool UpdateOverridesList(base::ListValue* overrides_list,
172 const std::string& override_url,
173 UpdateBehavior behavior) {
174 base::ListValue::iterator iter =
175 std::find_if(overrides_list->begin(), overrides_list->end(),
176 [&override_url](const base::Value* value) {
177 std::string entry;
178 const base::DictionaryValue* dict = nullptr;
179 return value->GetAsDictionary(&dict) &&
180 dict->GetString(kEntry, &entry) &&
181 entry == override_url;
182 });
183 if (iter != overrides_list->end()) {
184 switch (behavior) {
185 case UPDATE_DEACTIVATE: {
186 base::DictionaryValue* dict = nullptr;
187 bool success = (*iter)->GetAsDictionary(&dict);
188 CHECK(success);
189 dict->SetBoolean(kActive, false);
190 break;
191 }
192 case UPDATE_REMOVE:
193 overrides_list->Erase(iter, nullptr);
194 break;
195 }
196 return true;
197 }
198 return false;
199 }
200
201 // Updates each list referenced in |overrides| according to |behavior|.
202 void UpdateOverridesLists(Profile* profile,
203 const URLOverrides::URLOverrideMap& overrides,
204 UpdateBehavior behavior) {
205 if (overrides.empty())
206 return;
207 PrefService* prefs = profile->GetPrefs();
208 DictionaryPrefUpdate update(prefs, ExtensionWebUI::kExtensionURLOverrides);
209 base::DictionaryValue* all_overrides = update.Get();
210 for (const auto& page_override_pair : overrides) {
211 base::ListValue* page_overrides = nullptr;
212 // If it's being unregistered, it should already be in the list.
213 if (!all_overrides->GetList(page_override_pair.first, &page_overrides)) {
214 NOTREACHED();
215 continue;
216 }
217 if (UpdateOverridesList(page_overrides, page_override_pair.second.spec(),
218 behavior)) {
219 // This is the active override, so we need to find all existing
220 // tabs for this override and get them to reload the original URL.
221 base::Callback<void(WebContents*)> callback =
222 base::Bind(&UnregisterAndReplaceOverrideForWebContents,
223 page_override_pair.first, profile);
224 extensions::ExtensionTabUtil::ForEachTab(callback);
225 }
226 }
227 }
228
91 // Run favicon callbck with image result. If no favicon was available then 229 // Run favicon callbck with image result. If no favicon was available then
92 // |image| will be empty. 230 // |image| will be empty.
93 void RunFaviconCallbackAsync( 231 void RunFaviconCallbackAsync(
94 const favicon_base::FaviconResultsCallback& callback, 232 const favicon_base::FaviconResultsCallback& callback,
95 const gfx::Image& image) { 233 const gfx::Image& image) {
96 std::vector<favicon_base::FaviconRawBitmapResult>* favicon_bitmap_results = 234 std::vector<favicon_base::FaviconRawBitmapResult>* favicon_bitmap_results =
97 new std::vector<favicon_base::FaviconRawBitmapResult>(); 235 new std::vector<favicon_base::FaviconRawBitmapResult>();
98 236
99 const std::vector<gfx::ImageSkiaRep>& image_reps = 237 const std::vector<gfx::ImageSkiaRep>& image_reps =
100 image.AsImageSkia().image_reps(); 238 image.AsImageSkia().image_reps();
(...skipping 21 matching lines...) Expand all
122 FROM_HERE, 260 FROM_HERE,
123 base::Bind(&favicon::FaviconService::FaviconResultsCallbackRunner, 261 base::Bind(&favicon::FaviconService::FaviconResultsCallbackRunner,
124 callback, base::Owned(favicon_bitmap_results))); 262 callback, base::Owned(favicon_bitmap_results)));
125 } 263 }
126 264
127 bool ValidateOverrideURL(const base::Value* override_url_value, 265 bool ValidateOverrideURL(const base::Value* override_url_value,
128 const GURL& source_url, 266 const GURL& source_url,
129 const extensions::ExtensionSet& extensions, 267 const extensions::ExtensionSet& extensions,
130 GURL* override_url, 268 GURL* override_url,
131 const Extension** extension) { 269 const Extension** extension) {
270 const base::DictionaryValue* dict = nullptr;
132 std::string override; 271 std::string override;
133 if (!override_url_value || !override_url_value->GetAsString(&override)) { 272 bool is_active = false;
273 if (!override_url_value || !override_url_value->GetAsDictionary(&dict) ||
274 !dict->GetBoolean(kActive, &is_active) || !is_active ||
275 !dict->GetString(kEntry, &override)) {
134 return false; 276 return false;
135 } 277 }
136 if (!source_url.query().empty()) 278 if (!source_url.query().empty())
137 override += "?" + source_url.query(); 279 override += "?" + source_url.query();
138 if (!source_url.ref().empty()) 280 if (!source_url.ref().empty())
139 override += "#" + source_url.ref(); 281 override += "#" + source_url.ref();
140 *override_url = GURL(override); 282 *override_url = GURL(override);
141 if (!override_url->is_valid()) { 283 if (!override_url->is_valid()) {
142 return false; 284 return false;
143 } 285 }
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
219 // Iterate over the URL list looking for a suitable override. If a 361 // Iterate over the URL list looking for a suitable override. If a
220 // valid non-component override is encountered it is chosen immediately. 362 // valid non-component override is encountered it is chosen immediately.
221 for (size_t i = 0; i < url_list->GetSize(); ++i) { 363 for (size_t i = 0; i < url_list->GetSize(); ++i) {
222 const base::Value* val = NULL; 364 const base::Value* val = NULL;
223 url_list->Get(i, &val); 365 url_list->Get(i, &val);
224 366
225 GURL override_url; 367 GURL override_url;
226 const Extension* extension; 368 const Extension* extension;
227 if (!ValidateOverrideURL( 369 if (!ValidateOverrideURL(
228 val, *url, extensions, &override_url, &extension)) { 370 val, *url, extensions, &override_url, &extension)) {
229 LOG(WARNING) << "Invalid chrome URL override"; 371 // Invalid overrides are cleaned up on startup.
230 UnregisterChromeURLOverride(url_host, profile, val);
231 // The above Unregister call will remove this item from url_list.
232 --i;
233 continue; 372 continue;
234 } 373 }
235 374
236 // We can't handle chrome-extension URLs in incognito mode unless the 375 // We can't handle chrome-extension URLs in incognito mode unless the
237 // extension uses split mode. 376 // extension uses split mode.
238 bool incognito_override_allowed = 377 bool incognito_override_allowed =
239 extensions::IncognitoInfo::IsSplitMode(extension) && 378 extensions::IncognitoInfo::IsSplitMode(extension) &&
240 extensions::util::IsIncognitoEnabled(extension->id(), profile); 379 extensions::util::IsIncognitoEnabled(extension->id(), profile);
241 if (profile->IsOffTheRecord() && !incognito_override_allowed) { 380 if (profile->IsOffTheRecord() && !incognito_override_allowed) {
242 continue; 381 continue;
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
294 *url = original_url; 433 *url = original_url;
295 return true; 434 return true;
296 } 435 }
297 } 436 }
298 } 437 }
299 438
300 return false; 439 return false;
301 } 440 }
302 441
303 // static 442 // static
304 void ExtensionWebUI::RegisterChromeURLOverrides( 443 void ExtensionWebUI::InitializeChromeURLOverrides(Profile* profile) {
305 Profile* profile, const URLOverrides::URLOverrideMap& overrides) { 444 PrefService* prefs = profile->GetPrefs();
306 if (overrides.empty()) 445 DictionaryPrefUpdate update(prefs, kExtensionURLOverrides);
307 return; 446 base::DictionaryValue* all_overrides = update.Get();
447
448 // DictionaryValue::Iterator cannot be used to modify the list. Generate the
449 // set of keys instead.
450 std::vector<std::string> keys;
451 for (base::DictionaryValue::Iterator iter(*all_overrides);
452 !iter.IsAtEnd(); iter.Advance()) {
453 keys.push_back(iter.key());
454 }
455 for (const std::string& key : keys) {
456 base::ListValue* list = nullptr;
457 bool success = all_overrides->GetList(key, &list);
458 CHECK(success);
459 InitializeOverridesList(list);
460 }
461 }
462
463 // static
464 void ExtensionWebUI::ValidateChromeURLOverrides(Profile* profile) {
465 scoped_ptr<extensions::ExtensionSet> all_extensions =
466 extensions::ExtensionRegistry::Get(profile)->
467 GenerateInstalledExtensionsSet();
308 468
309 PrefService* prefs = profile->GetPrefs(); 469 PrefService* prefs = profile->GetPrefs();
310 DictionaryPrefUpdate update(prefs, kExtensionURLOverrides); 470 DictionaryPrefUpdate update(prefs, kExtensionURLOverrides);
311 base::DictionaryValue* all_overrides = update.Get(); 471 base::DictionaryValue* all_overrides = update.Get();
312 472
313 // For each override provided by the extension, add it to the front of 473 // DictionaryValue::Iterator cannot be used to modify the list. Generate the
314 // the override list if it's not already in the list. 474 // set of keys instead.
315 URLOverrides::URLOverrideMap::const_iterator iter = overrides.begin(); 475 std::vector<std::string> keys;
316 for (; iter != overrides.end(); ++iter) { 476 for (base::DictionaryValue::Iterator iter(*all_overrides);
317 const std::string& key = iter->first; 477 !iter.IsAtEnd(); iter.Advance()) {
318 base::ListValue* page_overrides = NULL; 478 keys.push_back(iter.key());
319 if (!all_overrides->GetList(key, &page_overrides)) { 479 }
320 page_overrides = new base::ListValue(); 480 for (const std::string& key : keys) {
321 all_overrides->Set(key, page_overrides); 481 base::ListValue* list = nullptr;
322 } else { 482 bool success = all_overrides->GetList(key, &list);
323 CleanUpDuplicates(page_overrides); 483 CHECK(success);
324 484 ValidateOverridesList(list, *all_extensions);
325 // Verify that the override isn't already in the list.
326 base::ListValue::iterator i = page_overrides->begin();
327 for (; i != page_overrides->end(); ++i) {
328 std::string override_val;
329 if (!(*i)->GetAsString(&override_val)) {
330 NOTREACHED();
331 continue;
332 }
333 if (override_val == iter->second.spec())
334 break;
335 }
336 // This value is already in the list, leave it alone.
337 if (i != page_overrides->end())
338 continue;
339 }
340 // Insert the override at the front of the list. Last registered override
341 // wins.
342 page_overrides->Insert(0, new base::StringValue(iter->second.spec()));
343 } 485 }
344 } 486 }
345 487
346 // static 488 // static
347 void ExtensionWebUI::UnregisterAndReplaceOverride(const std::string& page, 489 void ExtensionWebUI::RegisterOrActivateChromeURLOverrides(
348 Profile* profile, 490 Profile* profile,
349 base::ListValue* list, 491 const URLOverrides::URLOverrideMap& overrides) {
350 const base::Value* override) {
351 size_t index = 0;
352 bool found = list->Remove(*override, &index);
353 if (found && index == 0) {
354 // This is the active override, so we need to find all existing
355 // tabs for this override and get them to reload the original URL.
356 base::Callback<void(WebContents*)> callback =
357 base::Bind(&UnregisterAndReplaceOverrideForWebContents, page, profile);
358 extensions::ExtensionTabUtil::ForEachTab(callback);
359 }
360 }
361
362 // static
363 void ExtensionWebUI::UnregisterChromeURLOverride(const std::string& page,
364 Profile* profile,
365 const base::Value* override) {
366 if (!override)
367 return;
368 PrefService* prefs = profile->GetPrefs();
369 DictionaryPrefUpdate update(prefs, kExtensionURLOverrides);
370 base::DictionaryValue* all_overrides = update.Get();
371 base::ListValue* page_overrides = NULL;
372 if (!all_overrides->GetList(page, &page_overrides)) {
373 // If it's being unregistered, it should already be in the list.
374 NOTREACHED();
375 return;
376 } else {
377 UnregisterAndReplaceOverride(page, profile, page_overrides, override);
378 }
379 }
380
381 // static
382 void ExtensionWebUI::UnregisterChromeURLOverrides(
383 Profile* profile, const URLOverrides::URLOverrideMap& overrides) {
384 if (overrides.empty()) 492 if (overrides.empty())
385 return; 493 return;
386 PrefService* prefs = profile->GetPrefs(); 494 PrefService* prefs = profile->GetPrefs();
387 DictionaryPrefUpdate update(prefs, kExtensionURLOverrides); 495 DictionaryPrefUpdate update(prefs, kExtensionURLOverrides);
388 base::DictionaryValue* all_overrides = update.Get(); 496 base::DictionaryValue* all_overrides = update.Get();
389 URLOverrides::URLOverrideMap::const_iterator iter = overrides.begin(); 497 for (const auto& page_override_pair : overrides) {
390 for (; iter != overrides.end(); ++iter) { 498 base::ListValue* page_overrides = nullptr;
391 const std::string& page = iter->first; 499 if (!all_overrides->GetList(page_override_pair.first, &page_overrides)) {
392 base::ListValue* page_overrides = NULL; 500 page_overrides = new base::ListValue();
393 if (!all_overrides->GetList(page, &page_overrides)) { 501 all_overrides->Set(page_override_pair.first, page_overrides);
394 // If it's being unregistered, it should already be in the list.
395 NOTREACHED();
396 continue;
397 } else {
398 base::StringValue override(iter->second.spec());
399 UnregisterAndReplaceOverride(iter->first, profile,
400 page_overrides, &override);
401 } 502 }
503 AddOverridesToList(page_overrides, page_override_pair.second.spec());
402 } 504 }
403 } 505 }
404 506
405 // static 507 // static
508 void ExtensionWebUI::DeactivateChromeURLOverrides(
509 Profile* profile,
510 const URLOverrides::URLOverrideMap& overrides) {
511 UpdateOverridesLists(profile, overrides, UPDATE_DEACTIVATE);
512 }
513
514 // static
515 void ExtensionWebUI::UnregisterChromeURLOverrides(
516 Profile* profile,
517 const URLOverrides::URLOverrideMap& overrides) {
518 UpdateOverridesLists(profile, overrides, UPDATE_REMOVE);
519 }
520
521 // static
406 void ExtensionWebUI::GetFaviconForURL( 522 void ExtensionWebUI::GetFaviconForURL(
407 Profile* profile, 523 Profile* profile,
408 const GURL& page_url, 524 const GURL& page_url,
409 const favicon_base::FaviconResultsCallback& callback) { 525 const favicon_base::FaviconResultsCallback& callback) {
410 const Extension* extension = extensions::ExtensionRegistry::Get( 526 const Extension* extension = extensions::ExtensionRegistry::Get(
411 profile)->enabled_extensions().GetByID(page_url.host()); 527 profile)->enabled_extensions().GetByID(page_url.host());
412 if (!extension) { 528 if (!extension) {
413 RunFaviconCallbackAsync(callback, gfx::Image()); 529 RunFaviconCallbackAsync(callback, gfx::Image());
414 return; 530 return;
415 } 531 }
(...skipping 18 matching lines...) Expand all
434 extensions::ImageLoader::ImageRepresentation::ALWAYS_RESIZE, 550 extensions::ImageLoader::ImageRepresentation::ALWAYS_RESIZE,
435 gfx::Size(pixel_size, pixel_size), 551 gfx::Size(pixel_size, pixel_size),
436 resource_scale_factor)); 552 resource_scale_factor));
437 } 553 }
438 554
439 // LoadImagesAsync actually can run callback synchronously. We want to force 555 // LoadImagesAsync actually can run callback synchronously. We want to force
440 // async. 556 // async.
441 extensions::ImageLoader::Get(profile)->LoadImagesAsync( 557 extensions::ImageLoader::Get(profile)->LoadImagesAsync(
442 extension, info_list, base::Bind(&RunFaviconCallbackAsync, callback)); 558 extension, info_list, base::Bind(&RunFaviconCallbackAsync, callback));
443 } 559 }
OLDNEW
« no previous file with comments | « chrome/browser/extensions/extension_web_ui.h ('k') | chrome/browser/extensions/extension_web_ui_override_registrar.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698