OLD | NEW |
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 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_dom_ui.h" | 5 #include "chrome/browser/extensions/extension_dom_ui.h" |
6 | 6 |
7 #include "chrome/browser/browser.h" | 7 #include "chrome/browser/browser.h" |
| 8 #include "chrome/browser/browser_list.h" |
| 9 #include "chrome/browser/profile.h" |
8 #include "chrome/browser/tab_contents/tab_contents.h" | 10 #include "chrome/browser/tab_contents/tab_contents.h" |
9 #include "chrome/common/bindings_policy.h" | 11 #include "chrome/common/bindings_policy.h" |
| 12 #include "chrome/common/pref_service.h" |
| 13 #include "chrome/common/url_constants.h" |
| 14 |
| 15 namespace { |
| 16 const wchar_t kExtensionURLOverrides[] = L"extensions.chrome_url_overrides"; |
| 17 } |
10 | 18 |
11 ExtensionDOMUI::ExtensionDOMUI(TabContents* tab_contents) | 19 ExtensionDOMUI::ExtensionDOMUI(TabContents* tab_contents) |
12 : DOMUI(tab_contents) { | 20 : DOMUI(tab_contents) { |
13 // TODO(aa): It would be cool to show the extension's icon in here. | 21 // TODO(aa): It would be cool to show the extension's icon in here. |
14 hide_favicon_ = true; | 22 hide_favicon_ = true; |
15 should_hide_url_ = true; | 23 should_hide_url_ = true; |
16 bindings_ = BindingsPolicy::EXTENSION; | 24 bindings_ = BindingsPolicy::EXTENSION; |
| 25 |
| 26 // For chrome:// overrides, some of the defaults are a little different. |
| 27 GURL url = tab_contents->GetURL(); |
| 28 if (url.SchemeIs(chrome::kChromeUIScheme)) { |
| 29 if (url.host() == chrome::kChromeUINewTabHost) { |
| 30 focus_location_bar_by_default_ = true; |
| 31 } else { |
| 32 // Current behavior of other chrome:// pages is to display the URL. |
| 33 should_hide_url_ = false; |
| 34 } |
| 35 } |
| 36 } |
| 37 |
| 38 void ExtensionDOMUI::ResetExtensionFunctionDispatcher( |
| 39 RenderViewHost* render_view_host) { |
| 40 // Use the NavigationController to get the URL rather than the TabContents |
| 41 // since this is the real underlying URL (see HandleChromeURLOverride). |
| 42 NavigationController& controller = tab_contents()->controller(); |
| 43 const GURL& url = controller.pending_entry()->url(); |
| 44 extension_function_dispatcher_.reset( |
| 45 new ExtensionFunctionDispatcher(render_view_host, this, url)); |
17 } | 46 } |
18 | 47 |
19 void ExtensionDOMUI::RenderViewCreated(RenderViewHost* render_view_host) { | 48 void ExtensionDOMUI::RenderViewCreated(RenderViewHost* render_view_host) { |
20 extension_function_dispatcher_.reset( | 49 ResetExtensionFunctionDispatcher(render_view_host); |
21 new ExtensionFunctionDispatcher(render_view_host, this, | |
22 tab_contents()->GetURL())); | |
23 } | 50 } |
24 | 51 |
25 void ExtensionDOMUI::RenderViewReused(RenderViewHost* render_view_host) { | 52 void ExtensionDOMUI::RenderViewReused(RenderViewHost* render_view_host) { |
26 extension_function_dispatcher_.reset( | 53 ResetExtensionFunctionDispatcher(render_view_host); |
27 new ExtensionFunctionDispatcher(render_view_host, this, | |
28 tab_contents()->GetURL())); | |
29 } | 54 } |
30 | 55 |
31 void ExtensionDOMUI::ProcessDOMUIMessage(const std::string& message, | 56 void ExtensionDOMUI::ProcessDOMUIMessage(const std::string& message, |
32 const std::string& content, | 57 const std::string& content, |
33 int request_id, | 58 int request_id, |
34 bool has_callback) { | 59 bool has_callback) { |
35 extension_function_dispatcher_->HandleRequest(message, content, request_id, | 60 extension_function_dispatcher_->HandleRequest(message, content, request_id, |
36 has_callback); | 61 has_callback); |
37 } | 62 } |
38 | 63 |
39 Browser* ExtensionDOMUI::GetBrowser() { | 64 Browser* ExtensionDOMUI::GetBrowser() { |
40 return static_cast<Browser*>(tab_contents()->delegate()); | 65 return static_cast<Browser*>(tab_contents()->delegate()); |
41 } | 66 } |
| 67 |
| 68 //////////////////////////////////////////////////////////////////////////////// |
| 69 // chrome:// URL overrides |
| 70 |
| 71 // static |
| 72 void ExtensionDOMUI::RegisterUserPrefs(PrefService* prefs) { |
| 73 prefs->RegisterDictionaryPref(kExtensionURLOverrides); |
| 74 } |
| 75 |
| 76 // static |
| 77 bool ExtensionDOMUI::HandleChromeURLOverride(GURL* url, Profile* profile) { |
| 78 if (!url->SchemeIs(chrome::kChromeUIScheme)) |
| 79 return false; |
| 80 |
| 81 // Even when the extensions service is enabled by default, it's still |
| 82 // disabled in incognito mode. |
| 83 ExtensionsService* service = profile->GetExtensionsService(); |
| 84 if (!service) |
| 85 return false; |
| 86 |
| 87 const DictionaryValue* overrides = |
| 88 profile->GetPrefs()->GetDictionary(kExtensionURLOverrides); |
| 89 std::string page = url->host(); |
| 90 ListValue* url_list; |
| 91 if (!overrides || !overrides->GetList(UTF8ToWide(page), &url_list)) |
| 92 return false; |
| 93 |
| 94 if (!service->is_ready()) { |
| 95 // TODO(erikkay) So far, it looks like extensions load before the new tab |
| 96 // page. I don't know if we have anything that enforces this, so add this |
| 97 // check for safety. |
| 98 NOTREACHED() << "Chrome URL override requested before extensions loaded"; |
| 99 return false; |
| 100 } |
| 101 |
| 102 while (url_list->GetSize()) { |
| 103 Value* val; |
| 104 url_list->Get(0, &val); |
| 105 |
| 106 // Verify that the override value is good. If not, unregister it and find |
| 107 // the next one. |
| 108 std::string override; |
| 109 if (!val->GetAsString(&override)) { |
| 110 NOTREACHED(); |
| 111 UnregisterChromeURLOverride(page, profile, val); |
| 112 continue; |
| 113 } |
| 114 GURL extension_url(override); |
| 115 if (!extension_url.is_valid()) { |
| 116 NOTREACHED(); |
| 117 UnregisterChromeURLOverride(page, profile, val); |
| 118 continue; |
| 119 } |
| 120 |
| 121 // Verify that the extension that's being referred to actually exists. |
| 122 Extension* extension = service->GetExtensionByURL(extension_url); |
| 123 if (!extension) { |
| 124 // This can currently happen if you use --load-extension one run, and |
| 125 // then don't use it the next. It could also happen if an extension |
| 126 // were deleted directly from the filesystem, etc. |
| 127 LOG(WARNING) << "chrome URL override present for non-existant extension"; |
| 128 UnregisterChromeURLOverride(page, profile, val); |
| 129 continue; |
| 130 } |
| 131 |
| 132 *url = extension_url; |
| 133 return true; |
| 134 } |
| 135 return false; |
| 136 } |
| 137 |
| 138 // static |
| 139 void ExtensionDOMUI::RegisterChromeURLOverrides( |
| 140 Profile* profile, const DictionaryValue* new_overrides) { |
| 141 if (!new_overrides) |
| 142 return; |
| 143 |
| 144 PrefService* prefs = profile->GetPrefs(); |
| 145 DictionaryValue* all_overrides = |
| 146 prefs->GetMutableDictionary(kExtensionURLOverrides); |
| 147 |
| 148 // For each override provided by the extension, add it to the front of |
| 149 // the override list if it's not already in the list. |
| 150 DictionaryValue::key_iterator iter = new_overrides->begin_keys(); |
| 151 for (;iter != new_overrides->end_keys(); ++iter) { |
| 152 Value* val; |
| 153 new_overrides->Get(*iter, &val); |
| 154 std::string string_val; |
| 155 if (!val->GetAsString(&string_val)) { |
| 156 NOTREACHED(); |
| 157 continue; |
| 158 } |
| 159 ListValue* page_overrides; |
| 160 if (!all_overrides->GetList(*iter, &page_overrides)) { |
| 161 page_overrides = new ListValue(); |
| 162 all_overrides->Set(*iter, page_overrides); |
| 163 } else { |
| 164 // Verify that the override isn't already in the list. |
| 165 ListValue::iterator i = page_overrides->begin(); |
| 166 for (; i != page_overrides->end(); ++i) { |
| 167 std::string override_val; |
| 168 if (!(*i)->GetAsString(&override_val)) { |
| 169 NOTREACHED(); |
| 170 continue; |
| 171 } |
| 172 if (override_val == string_val) |
| 173 break; |
| 174 } |
| 175 // This value is already in the list, leave it alone. |
| 176 if (i != page_overrides->end()) |
| 177 continue; |
| 178 } |
| 179 // Insert the override at the front of the list. Last registered override |
| 180 // wins. |
| 181 page_overrides->Insert(0, val->DeepCopy()); |
| 182 } |
| 183 } |
| 184 |
| 185 // static |
| 186 void ExtensionDOMUI::UnregisterAndReplaceOverride(const std::string& page, |
| 187 Profile* profile, ListValue* list, Value* override) { |
| 188 int index = list->Remove(*override); |
| 189 if (index == 0) { |
| 190 // This is the active override, so we need to find all existing |
| 191 // tabs for this override and get them to reload the original URL. |
| 192 for (TabContentsIterator iterator; !iterator.done(); iterator++) { |
| 193 TabContents* tab = *iterator; |
| 194 if (tab->profile() != profile) |
| 195 continue; |
| 196 |
| 197 GURL url = tab->GetURL(); |
| 198 if (!url.SchemeIs(chrome::kChromeUIScheme) || url.host() != page) |
| 199 continue; |
| 200 |
| 201 // Don't use Reload() since |url| isn't the same as the internal URL |
| 202 // that NavigationController has. |
| 203 tab->controller().LoadURL(url, url, PageTransition::RELOAD); |
| 204 } |
| 205 } |
| 206 } |
| 207 |
| 208 // static |
| 209 void ExtensionDOMUI::UnregisterChromeURLOverride(const std::string& page, |
| 210 Profile* profile, Value* override) { |
| 211 if (!override) |
| 212 return; |
| 213 PrefService* prefs = profile->GetPrefs(); |
| 214 DictionaryValue* all_overrides = |
| 215 prefs->GetMutableDictionary(kExtensionURLOverrides); |
| 216 ListValue* page_overrides; |
| 217 if (!all_overrides->GetList(UTF8ToWide(page), &page_overrides)) { |
| 218 // If it's being unregistered, it should already be in the list. |
| 219 NOTREACHED(); |
| 220 return; |
| 221 } else { |
| 222 UnregisterAndReplaceOverride(page, profile, page_overrides, override); |
| 223 } |
| 224 } |
| 225 |
| 226 // static |
| 227 void ExtensionDOMUI::UnregisterChromeURLOverrides( |
| 228 Profile* profile, const DictionaryValue* new_overrides) { |
| 229 if (!new_overrides) |
| 230 return; |
| 231 PrefService* prefs = profile->GetPrefs(); |
| 232 DictionaryValue* all_overrides = |
| 233 prefs->GetMutableDictionary(kExtensionURLOverrides); |
| 234 DictionaryValue::key_iterator iter = new_overrides->begin_keys(); |
| 235 for (; iter != new_overrides->end_keys(); ++iter) { |
| 236 Value* val; |
| 237 if (!new_overrides->Get(*iter, &val)) { |
| 238 NOTREACHED(); |
| 239 return; |
| 240 } |
| 241 ListValue* page_overrides; |
| 242 if (!all_overrides->GetList(*iter, &page_overrides)) { |
| 243 // If it's being unregistered, it should already be in the list. |
| 244 NOTREACHED(); |
| 245 continue; |
| 246 } else { |
| 247 UnregisterAndReplaceOverride(WideToUTF8(*iter), profile, page_overrides, |
| 248 val); |
| 249 } |
| 250 } |
| 251 } |
OLD | NEW |