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

Unified 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 5 years 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 side-by-side diff with in-line comments
Download patch
Index: chrome/browser/extensions/extension_web_ui.cc
diff --git a/chrome/browser/extensions/extension_web_ui.cc b/chrome/browser/extensions/extension_web_ui.cc
index d5667eef16abd62360d90bb2ad3ccf8d46117314..ad28ac771f875bfaab70dbdc96072dfbed7e0acc 100644
--- a/chrome/browser/extensions/extension_web_ui.cc
+++ b/chrome/browser/extensions/extension_web_ui.cc
@@ -49,23 +49,96 @@ using extensions::URLOverrides;
namespace {
-// De-dupes the items in |list|. Assumes the values are strings.
-void CleanUpDuplicates(base::ListValue* list) {
- std::set<std::string> seen_values;
-
- // Loop backwards as we may be removing items.
- for (size_t i = list->GetSize() - 1; (i + 1) > 0; --i) {
- std::string value;
- if (!list->GetString(i, &value)) {
+// The key to the override value for a page.
+const char kEntry[] = "entry";
+// The key to whether or not the override is active (i.e., can be used).
+// Overrides may be inactive e.g. when an extension is disabled.
+const char kActive[] = "active";
+
+// Iterates over |list| and:
+// - Converts any entries of the form <entry> to
+// { 'entry': <entry>, 'active': true }.
+// - Removes any duplicate entries.
+// We do the conversion because we previously stored these values as strings
+// rather than objects.
+// TODO(devlin): Remove the conversion once everyone's updated.
+void InitializeOverridesList(base::ListValue* list) {
+ base::ListValue migrated;
+ std::set<std::string> seen_entries;
+ for (base::Value* val : *list) {
+ scoped_ptr<base::DictionaryValue> new_dict(new base::DictionaryValue());
+ std::string entry_name;
+ base::DictionaryValue* existing_dict = nullptr;
+ if (val->GetAsDictionary(&existing_dict)) {
+ bool success = existing_dict->GetString(kEntry, &entry_name);
+ CHECK(success);
+ new_dict->Swap(existing_dict);
+ } else if (val->GetAsString(&entry_name)) {
+ new_dict->SetString(kEntry, entry_name);
+ new_dict->SetBoolean(kActive, true);
+ } else {
NOTREACHED();
continue;
}
- if (seen_values.find(value) == seen_values.end())
- seen_values.insert(value);
- else
- list->Remove(i, NULL);
+ if (seen_entries.count(entry_name) == 0) {
+ seen_entries.insert(entry_name);
+ migrated.Append(std::move(new_dict));
+ }
}
+
+ list->Swap(&migrated);
+}
+
+// Adds |override| to |list|, or, if there's already an entry for the override,
+// marks it as active.
+void AddOverridesToList(base::ListValue* list,
+ const std::string& override) {
+ for (base::Value* val : *list) {
+ base::DictionaryValue* dict = nullptr;
+ std::string entry;
+ if (!val->GetAsDictionary(&dict) || !dict->GetString(kEntry, &entry)) {
+ NOTREACHED();
+ continue;
+ }
+ if (entry == override) {
+ dict->SetBoolean(kActive, true);
+ return; // All done!
+ }
+ }
+
+ scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
+ dict->SetString(kEntry, override);
+ dict->SetBoolean(kActive, true);
+ // Add the entry to the front of the list.
+ list->Insert(0, dict.release());
+}
+
+// Validates that each entry in |list| contains a valid url and points to an
+// extension contained in |all_extensions| (and, if not, removes it).
+void ValidateOverridesList(base::ListValue* list,
+ const extensions::ExtensionSet& all_extensions) {
+ base::ListValue migrated;
+ for (base::Value* val : *list) {
+ base::DictionaryValue* dict = nullptr;
+ std::string entry;
+ if (!val->GetAsDictionary(&dict) || !dict->GetString(kEntry, &entry)) {
+ NOTREACHED();
+ continue;
+ }
+ scoped_ptr<base::DictionaryValue> new_dict(new base::DictionaryValue());
+ new_dict->Swap(dict);
+ GURL override_url(entry);
+ if (!override_url.is_valid())
+ continue;
+
+ if (!all_extensions.GetByID(override_url.host()))
+ continue;
+
+ migrated.Append(std::move(new_dict));
+ }
+
+ list->Swap(&migrated);
}
// Reloads the page in |web_contents| if it uses the same profile as |profile|
@@ -88,6 +161,71 @@ void UnregisterAndReplaceOverrideForWebContents(const std::string& page,
ui::PAGE_TRANSITION_RELOAD, std::string());
}
+enum UpdateBehavior {
+ UPDATE_DEACTIVATE, // Mark 'active' as false.
+ UPDATE_REMOVE, // Remove the entry from the list.
+};
+
+// Updates the entry (if any) for |override_url| in |overrides_list| according
+// to |behavior|. Returns true if anything changed.
+bool UpdateOverridesList(base::ListValue* overrides_list,
+ const std::string& override_url,
+ UpdateBehavior behavior) {
+ base::ListValue::iterator iter =
+ std::find_if(overrides_list->begin(), overrides_list->end(),
+ [&override_url](const base::Value* value) {
+ std::string entry;
+ const base::DictionaryValue* dict = nullptr;
+ return value->GetAsDictionary(&dict) &&
+ dict->GetString(kEntry, &entry) &&
+ entry == override_url;
+ });
+ if (iter != overrides_list->end()) {
+ switch (behavior) {
+ case UPDATE_DEACTIVATE: {
+ base::DictionaryValue* dict = nullptr;
+ bool success = (*iter)->GetAsDictionary(&dict);
+ CHECK(success);
+ dict->SetBoolean(kActive, false);
+ break;
+ }
+ case UPDATE_REMOVE:
+ overrides_list->Erase(iter, nullptr);
+ break;
+ }
+ return true;
+ }
+ return false;
+}
+
+// Updates each list referenced in |overrides| according to |behavior|.
+void UpdateOverridesLists(Profile* profile,
+ const URLOverrides::URLOverrideMap& overrides,
+ UpdateBehavior behavior) {
+ if (overrides.empty())
+ return;
+ PrefService* prefs = profile->GetPrefs();
+ DictionaryPrefUpdate update(prefs, ExtensionWebUI::kExtensionURLOverrides);
+ base::DictionaryValue* all_overrides = update.Get();
+ for (const auto& page_override_pair : overrides) {
+ base::ListValue* page_overrides = nullptr;
+ // If it's being unregistered, it should already be in the list.
+ if (!all_overrides->GetList(page_override_pair.first, &page_overrides)) {
+ NOTREACHED();
+ continue;
+ }
+ if (UpdateOverridesList(page_overrides, page_override_pair.second.spec(),
+ behavior)) {
+ // This is the active override, so we need to find all existing
+ // tabs for this override and get them to reload the original URL.
+ base::Callback<void(WebContents*)> callback =
+ base::Bind(&UnregisterAndReplaceOverrideForWebContents,
+ page_override_pair.first, profile);
+ extensions::ExtensionTabUtil::ForEachTab(callback);
+ }
+ }
+}
+
// Run favicon callbck with image result. If no favicon was available then
// |image| will be empty.
void RunFaviconCallbackAsync(
@@ -129,8 +267,12 @@ bool ValidateOverrideURL(const base::Value* override_url_value,
const extensions::ExtensionSet& extensions,
GURL* override_url,
const Extension** extension) {
+ const base::DictionaryValue* dict = nullptr;
std::string override;
- if (!override_url_value || !override_url_value->GetAsString(&override)) {
+ bool is_active = false;
+ if (!override_url_value || !override_url_value->GetAsDictionary(&dict) ||
+ !dict->GetBoolean(kActive, &is_active) || !is_active ||
+ !dict->GetString(kEntry, &override)) {
return false;
}
if (!source_url.query().empty())
@@ -226,10 +368,7 @@ bool ExtensionWebUI::HandleChromeURLOverride(
const Extension* extension;
if (!ValidateOverrideURL(
val, *url, extensions, &override_url, &extension)) {
- LOG(WARNING) << "Invalid chrome URL override";
- UnregisterChromeURLOverride(url_host, profile, val);
- // The above Unregister call will remove this item from url_list.
- --i;
+ // Invalid overrides are cleaned up on startup.
continue;
}
@@ -301,108 +440,85 @@ bool ExtensionWebUI::HandleChromeURLOverrideReverse(
}
// static
-void ExtensionWebUI::RegisterChromeURLOverrides(
- Profile* profile, const URLOverrides::URLOverrideMap& overrides) {
- if (overrides.empty())
- return;
-
+void ExtensionWebUI::InitializeChromeURLOverrides(Profile* profile) {
PrefService* prefs = profile->GetPrefs();
DictionaryPrefUpdate update(prefs, kExtensionURLOverrides);
base::DictionaryValue* all_overrides = update.Get();
- // For each override provided by the extension, add it to the front of
- // the override list if it's not already in the list.
- URLOverrides::URLOverrideMap::const_iterator iter = overrides.begin();
- for (; iter != overrides.end(); ++iter) {
- const std::string& key = iter->first;
- base::ListValue* page_overrides = NULL;
- if (!all_overrides->GetList(key, &page_overrides)) {
- page_overrides = new base::ListValue();
- all_overrides->Set(key, page_overrides);
- } else {
- CleanUpDuplicates(page_overrides);
-
- // Verify that the override isn't already in the list.
- base::ListValue::iterator i = page_overrides->begin();
- for (; i != page_overrides->end(); ++i) {
- std::string override_val;
- if (!(*i)->GetAsString(&override_val)) {
- NOTREACHED();
- continue;
- }
- if (override_val == iter->second.spec())
- break;
- }
- // This value is already in the list, leave it alone.
- if (i != page_overrides->end())
- continue;
- }
- // Insert the override at the front of the list. Last registered override
- // wins.
- page_overrides->Insert(0, new base::StringValue(iter->second.spec()));
+ // DictionaryValue::Iterator cannot be used to modify the list. Generate the
+ // set of keys instead.
+ std::vector<std::string> keys;
+ for (base::DictionaryValue::Iterator iter(*all_overrides);
+ !iter.IsAtEnd(); iter.Advance()) {
+ keys.push_back(iter.key());
}
-}
-
-// static
-void ExtensionWebUI::UnregisterAndReplaceOverride(const std::string& page,
- Profile* profile,
- base::ListValue* list,
- const base::Value* override) {
- size_t index = 0;
- bool found = list->Remove(*override, &index);
- if (found && index == 0) {
- // This is the active override, so we need to find all existing
- // tabs for this override and get them to reload the original URL.
- base::Callback<void(WebContents*)> callback =
- base::Bind(&UnregisterAndReplaceOverrideForWebContents, page, profile);
- extensions::ExtensionTabUtil::ForEachTab(callback);
+ for (const std::string& key : keys) {
+ base::ListValue* list = nullptr;
+ bool success = all_overrides->GetList(key, &list);
+ CHECK(success);
+ InitializeOverridesList(list);
}
}
// static
-void ExtensionWebUI::UnregisterChromeURLOverride(const std::string& page,
- Profile* profile,
- const base::Value* override) {
- if (!override)
- return;
+void ExtensionWebUI::ValidateChromeURLOverrides(Profile* profile) {
+ scoped_ptr<extensions::ExtensionSet> all_extensions =
+ extensions::ExtensionRegistry::Get(profile)->
+ GenerateInstalledExtensionsSet();
+
PrefService* prefs = profile->GetPrefs();
DictionaryPrefUpdate update(prefs, kExtensionURLOverrides);
base::DictionaryValue* all_overrides = update.Get();
- base::ListValue* page_overrides = NULL;
- if (!all_overrides->GetList(page, &page_overrides)) {
- // If it's being unregistered, it should already be in the list.
- NOTREACHED();
- return;
- } else {
- UnregisterAndReplaceOverride(page, profile, page_overrides, override);
+
+ // DictionaryValue::Iterator cannot be used to modify the list. Generate the
+ // set of keys instead.
+ std::vector<std::string> keys;
+ for (base::DictionaryValue::Iterator iter(*all_overrides);
+ !iter.IsAtEnd(); iter.Advance()) {
+ keys.push_back(iter.key());
+ }
+ for (const std::string& key : keys) {
+ base::ListValue* list = nullptr;
+ bool success = all_overrides->GetList(key, &list);
+ CHECK(success);
+ ValidateOverridesList(list, *all_extensions);
}
}
// static
-void ExtensionWebUI::UnregisterChromeURLOverrides(
- Profile* profile, const URLOverrides::URLOverrideMap& overrides) {
+void ExtensionWebUI::RegisterOrActivateChromeURLOverrides(
+ Profile* profile,
+ const URLOverrides::URLOverrideMap& overrides) {
if (overrides.empty())
return;
PrefService* prefs = profile->GetPrefs();
DictionaryPrefUpdate update(prefs, kExtensionURLOverrides);
base::DictionaryValue* all_overrides = update.Get();
- URLOverrides::URLOverrideMap::const_iterator iter = overrides.begin();
- for (; iter != overrides.end(); ++iter) {
- const std::string& page = iter->first;
- base::ListValue* page_overrides = NULL;
- if (!all_overrides->GetList(page, &page_overrides)) {
- // If it's being unregistered, it should already be in the list.
- NOTREACHED();
- continue;
- } else {
- base::StringValue override(iter->second.spec());
- UnregisterAndReplaceOverride(iter->first, profile,
- page_overrides, &override);
+ for (const auto& page_override_pair : overrides) {
+ base::ListValue* page_overrides = nullptr;
+ if (!all_overrides->GetList(page_override_pair.first, &page_overrides)) {
+ page_overrides = new base::ListValue();
+ all_overrides->Set(page_override_pair.first, page_overrides);
}
+ AddOverridesToList(page_overrides, page_override_pair.second.spec());
}
}
// static
+void ExtensionWebUI::DeactivateChromeURLOverrides(
+ Profile* profile,
+ const URLOverrides::URLOverrideMap& overrides) {
+ UpdateOverridesLists(profile, overrides, UPDATE_DEACTIVATE);
+}
+
+// static
+void ExtensionWebUI::UnregisterChromeURLOverrides(
+ Profile* profile,
+ const URLOverrides::URLOverrideMap& overrides) {
+ UpdateOverridesLists(profile, overrides, UPDATE_REMOVE);
+}
+
+// static
void ExtensionWebUI::GetFaviconForURL(
Profile* profile,
const GURL& page_url,
« 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