Index: chrome/browser/extensions/extension_dom_ui.cc |
diff --git a/chrome/browser/extensions/extension_dom_ui.cc b/chrome/browser/extensions/extension_dom_ui.cc |
index ed5abb9624c0cc6fd38f49477aa674addedbe2bd..044a28a714cdae1bfed224b4e98483457679696f 100644 |
--- a/chrome/browser/extensions/extension_dom_ui.cc |
+++ b/chrome/browser/extensions/extension_dom_ui.cc |
@@ -5,8 +5,16 @@ |
#include "chrome/browser/extensions/extension_dom_ui.h" |
#include "chrome/browser/browser.h" |
+#include "chrome/browser/browser_list.h" |
+#include "chrome/browser/profile.h" |
#include "chrome/browser/tab_contents/tab_contents.h" |
#include "chrome/common/bindings_policy.h" |
+#include "chrome/common/pref_service.h" |
+#include "chrome/common/url_constants.h" |
+ |
+namespace { |
+const wchar_t kExtensionURLOverrides[] = L"extensions.chrome_url_overrides"; |
+} |
ExtensionDOMUI::ExtensionDOMUI(TabContents* tab_contents) |
: DOMUI(tab_contents) { |
@@ -14,18 +22,35 @@ ExtensionDOMUI::ExtensionDOMUI(TabContents* tab_contents) |
hide_favicon_ = true; |
should_hide_url_ = true; |
bindings_ = BindingsPolicy::EXTENSION; |
+ |
+ // For chrome:// overrides, some of the defaults are a little different. |
+ GURL url = tab_contents->GetURL(); |
+ if (url.SchemeIs(chrome::kChromeUIScheme)) { |
+ if (url.host() == chrome::kChromeUINewTabHost) { |
+ focus_location_bar_by_default_ = true; |
+ } else { |
+ // Current behavior of other chrome:// pages is to display the URL. |
+ should_hide_url_ = false; |
+ } |
+ } |
} |
-void ExtensionDOMUI::RenderViewCreated(RenderViewHost* render_view_host) { |
+void ExtensionDOMUI::ResetExtensionFunctionDispatcher( |
+ RenderViewHost* render_view_host) { |
+ // Use the NavigationController to get the URL rather than the TabContents |
+ // since this is the real underlying URL (see HandleChromeURLOverride). |
+ NavigationController& controller = tab_contents()->controller(); |
+ const GURL& url = controller.pending_entry()->url(); |
extension_function_dispatcher_.reset( |
- new ExtensionFunctionDispatcher(render_view_host, this, |
- tab_contents()->GetURL())); |
+ new ExtensionFunctionDispatcher(render_view_host, this, url)); |
+} |
+ |
+void ExtensionDOMUI::RenderViewCreated(RenderViewHost* render_view_host) { |
+ ResetExtensionFunctionDispatcher(render_view_host); |
} |
void ExtensionDOMUI::RenderViewReused(RenderViewHost* render_view_host) { |
- extension_function_dispatcher_.reset( |
- new ExtensionFunctionDispatcher(render_view_host, this, |
- tab_contents()->GetURL())); |
+ ResetExtensionFunctionDispatcher(render_view_host); |
} |
void ExtensionDOMUI::ProcessDOMUIMessage(const std::string& message, |
@@ -39,3 +64,188 @@ void ExtensionDOMUI::ProcessDOMUIMessage(const std::string& message, |
Browser* ExtensionDOMUI::GetBrowser() { |
return static_cast<Browser*>(tab_contents()->delegate()); |
} |
+ |
+//////////////////////////////////////////////////////////////////////////////// |
+// chrome:// URL overrides |
+ |
+// static |
+void ExtensionDOMUI::RegisterUserPrefs(PrefService* prefs) { |
+ prefs->RegisterDictionaryPref(kExtensionURLOverrides); |
+} |
+ |
+// static |
+bool ExtensionDOMUI::HandleChromeURLOverride(GURL* url, Profile* profile) { |
+ if (!url->SchemeIs(chrome::kChromeUIScheme)) |
+ return false; |
+ |
+ // Even when the extensions service is enabled by default, it's still |
+ // disabled in incognito mode. |
+ ExtensionsService* service = profile->GetExtensionsService(); |
+ if (!service) |
+ return false; |
+ |
+ const DictionaryValue* overrides = |
+ profile->GetPrefs()->GetDictionary(kExtensionURLOverrides); |
+ std::string page = url->host(); |
+ ListValue* url_list; |
+ if (!overrides || !overrides->GetList(UTF8ToWide(page), &url_list)) |
+ return false; |
+ |
+ if (!service->is_ready()) { |
+ // TODO(erikkay) So far, it looks like extensions load before the new tab |
+ // page. I don't know if we have anything that enforces this, so add this |
+ // check for safety. |
+ NOTREACHED() << "Chrome URL override requested before extensions loaded"; |
+ return false; |
+ } |
+ |
+ while (url_list->GetSize()) { |
+ Value* val; |
+ url_list->Get(0, &val); |
+ |
+ // Verify that the override value is good. If not, unregister it and find |
+ // the next one. |
+ std::string override; |
+ if (!val->GetAsString(&override)) { |
+ NOTREACHED(); |
+ UnregisterChromeURLOverride(page, profile, val); |
+ continue; |
+ } |
+ GURL extension_url(override); |
+ if (!extension_url.is_valid()) { |
+ NOTREACHED(); |
+ UnregisterChromeURLOverride(page, profile, val); |
+ continue; |
+ } |
+ |
+ // Verify that the extension that's being referred to actually exists. |
+ Extension* extension = service->GetExtensionByURL(extension_url); |
+ if (!extension) { |
+ // This can currently happen if you use --load-extension one run, and |
+ // then don't use it the next. It could also happen if an extension |
+ // were deleted directly from the filesystem, etc. |
+ LOG(WARNING) << "chrome URL override present for non-existant extension"; |
+ UnregisterChromeURLOverride(page, profile, val); |
+ continue; |
+ } |
+ |
+ *url = extension_url; |
+ return true; |
+ } |
+ return false; |
+} |
+ |
+// static |
+void ExtensionDOMUI::RegisterChromeURLOverrides( |
+ Profile* profile, const DictionaryValue* new_overrides) { |
+ if (!new_overrides) |
+ return; |
+ |
+ PrefService* prefs = profile->GetPrefs(); |
+ DictionaryValue* all_overrides = |
+ prefs->GetMutableDictionary(kExtensionURLOverrides); |
+ |
+ // For each override provided by the extension, add it to the front of |
+ // the override list if it's not already in the list. |
+ DictionaryValue::key_iterator iter = new_overrides->begin_keys(); |
+ for (;iter != new_overrides->end_keys(); ++iter) { |
+ Value* val; |
+ new_overrides->Get(*iter, &val); |
+ std::string string_val; |
+ if (!val->GetAsString(&string_val)) { |
+ NOTREACHED(); |
+ continue; |
+ } |
+ ListValue* page_overrides; |
+ if (!all_overrides->GetList(*iter, &page_overrides)) { |
+ page_overrides = new ListValue(); |
+ all_overrides->Set(*iter, page_overrides); |
+ } else { |
+ // Verify that the override isn't already in the list. |
+ 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 == string_val) |
+ 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, val->DeepCopy()); |
+ } |
+} |
+ |
+// static |
+void ExtensionDOMUI::UnregisterAndReplaceOverride(const std::string& page, |
+ Profile* profile, ListValue* list, Value* override) { |
+ int index = list->Remove(*override); |
+ if (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. |
+ for (TabContentsIterator iterator; !iterator.done(); iterator++) { |
+ TabContents* tab = *iterator; |
+ if (tab->profile() != profile) |
+ continue; |
+ |
+ GURL url = tab->GetURL(); |
+ if (!url.SchemeIs(chrome::kChromeUIScheme) || url.host() != page) |
+ continue; |
+ |
+ // Don't use Reload() since |url| isn't the same as the internal URL |
+ // that NavigationController has. |
+ tab->controller().LoadURL(url, url, PageTransition::RELOAD); |
+ } |
+ } |
+} |
+ |
+// static |
+void ExtensionDOMUI::UnregisterChromeURLOverride(const std::string& page, |
+ Profile* profile, Value* override) { |
+ if (!override) |
+ return; |
+ PrefService* prefs = profile->GetPrefs(); |
+ DictionaryValue* all_overrides = |
+ prefs->GetMutableDictionary(kExtensionURLOverrides); |
+ ListValue* page_overrides; |
+ if (!all_overrides->GetList(UTF8ToWide(page), &page_overrides)) { |
+ // If it's being unregistered, it should already be in the list. |
+ NOTREACHED(); |
+ return; |
+ } else { |
+ UnregisterAndReplaceOverride(page, profile, page_overrides, override); |
+ } |
+} |
+ |
+// static |
+void ExtensionDOMUI::UnregisterChromeURLOverrides( |
+ Profile* profile, const DictionaryValue* new_overrides) { |
+ if (!new_overrides) |
+ return; |
+ PrefService* prefs = profile->GetPrefs(); |
+ DictionaryValue* all_overrides = |
+ prefs->GetMutableDictionary(kExtensionURLOverrides); |
+ DictionaryValue::key_iterator iter = new_overrides->begin_keys(); |
+ for (; iter != new_overrides->end_keys(); ++iter) { |
+ Value* val; |
+ if (!new_overrides->Get(*iter, &val)) { |
+ NOTREACHED(); |
+ return; |
+ } |
+ ListValue* page_overrides; |
+ if (!all_overrides->GetList(*iter, &page_overrides)) { |
+ // If it's being unregistered, it should already be in the list. |
+ NOTREACHED(); |
+ continue; |
+ } else { |
+ UnregisterAndReplaceOverride(WideToUTF8(*iter), profile, page_overrides, |
+ val); |
+ } |
+ } |
+} |