diff options
Diffstat (limited to 'chrome/browser/extensions/extension_dom_ui.cc')
-rw-r--r-- | chrome/browser/extensions/extension_dom_ui.cc | 222 |
1 files changed, 216 insertions, 6 deletions
diff --git a/chrome/browser/extensions/extension_dom_ui.cc b/chrome/browser/extensions/extension_dom_ui.cc index ed5abb9..044a28a 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); + } + } +} |