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 3 // found in the LICENSE file. 4 5 #include "chrome/browser/ui/webui/uber/uber_ui.h" 6 7 #include "base/command_line.h" 8 #include "base/stl_util.h" 9 #include "base/strings/utf_string_conversions.h" 10 #include "chrome/browser/chrome_notification_types.h" 11 #include "chrome/browser/extensions/extension_service.h" 12 #include "chrome/browser/profiles/profile.h" 13 #include "chrome/browser/ui/webui/chrome_web_ui_controller_factory.h" 14 #include "chrome/browser/ui/webui/extensions/extensions_ui.h" 15 #include "chrome/browser/ui/webui/options/options_ui.h" 16 #include "chrome/common/chrome_switches.h" 17 #include "chrome/common/extensions/manifest_url_handler.h" 18 #include "chrome/common/url_constants.h" 19 #include "content/public/browser/navigation_controller.h" 20 #include "content/public/browser/navigation_entry.h" 21 #include "content/public/browser/notification_source.h" 22 #include "content/public/browser/web_contents.h" 23 #include "content/public/browser/web_ui.h" 24 #include "content/public/browser/web_ui_data_source.h" 25 #include "extensions/common/extension_set.h" 26 #include "grit/browser_resources.h" 27 #include "grit/chromium_strings.h" 28 #include "grit/generated_resources.h" 29 30 using base::ASCIIToUTF16; 31 using content::NavigationController; 32 using content::NavigationEntry; 33 using content::RenderViewHost; 34 using content::WebContents; 35 36 namespace { 37 38 content::WebUIDataSource* CreateUberHTMLSource() { 39 content::WebUIDataSource* source = 40 content::WebUIDataSource::Create(chrome::kChromeUIUberHost); 41 42 source->SetUseJsonJSFormatV2(); 43 source->SetJsonPath("strings.js"); 44 source->AddResourcePath("uber.js", IDR_UBER_JS); 45 source->AddResourcePath("uber_utils.js", IDR_UBER_UTILS_JS); 46 source->SetDefaultResource(IDR_UBER_HTML); 47 source->OverrideContentSecurityPolicyFrameSrc("frame-src chrome:;"); 48 49 // Hack alert: continue showing "Loading..." until a real title is set. 50 source->AddLocalizedString("pageTitle", IDS_TAB_LOADING_TITLE); 51 52 source->AddString("extensionsFrameURL", 53 ASCIIToUTF16(chrome::kChromeUIExtensionsFrameURL)); 54 source->AddString("extensionsHost", 55 ASCIIToUTF16(chrome::kChromeUIExtensionsHost)); 56 source->AddString("helpFrameURL", 57 ASCIIToUTF16(chrome::kChromeUIHelpFrameURL)); 58 source->AddString("helpHost", 59 ASCIIToUTF16(chrome::kChromeUIHelpHost)); 60 source->AddString("historyFrameURL", 61 ASCIIToUTF16(chrome::kChromeUIHistoryFrameURL)); 62 source->AddString("historyHost", 63 ASCIIToUTF16(chrome::kChromeUIHistoryHost)); 64 source->AddString("settingsFrameURL", 65 ASCIIToUTF16(chrome::kChromeUISettingsFrameURL)); 66 source->AddString("settingsHost", 67 ASCIIToUTF16(chrome::kChromeUISettingsHost)); 68 69 return source; 70 } 71 72 // Determines whether the user has an active extension of the given type. 73 bool HasExtensionType(Profile* profile, const char* extensionType) { 74 const extensions::ExtensionSet* extensionSet = 75 profile->GetExtensionService()->extensions(); 76 77 for (extensions::ExtensionSet::const_iterator iter = extensionSet->begin(); 78 iter != extensionSet->end(); ++iter) { 79 extensions::URLOverrides::URLOverrideMap map = 80 extensions::URLOverrides::GetChromeURLOverrides(iter->get()); 81 extensions::URLOverrides::URLOverrideMap::const_iterator result = 82 map.find(std::string(extensionType)); 83 84 if (result != map.end()) 85 return true; 86 } 87 88 return false; 89 } 90 91 content::WebUIDataSource* CreateUberFrameHTMLSource(Profile* profile) { 92 content::WebUIDataSource* source = 93 content::WebUIDataSource::Create(chrome::kChromeUIUberFrameHost); 94 95 source->SetUseJsonJSFormatV2(); 96 source->SetJsonPath("strings.js"); 97 source->AddResourcePath("uber_frame.js", IDR_UBER_FRAME_JS); 98 source->SetDefaultResource(IDR_UBER_FRAME_HTML); 99 100 // TODO(jhawkins): Attempt to get rid of IDS_SHORT_PRODUCT_OS_NAME. 101 #if defined(OS_CHROMEOS) 102 source->AddLocalizedString("shortProductName", IDS_SHORT_PRODUCT_OS_NAME); 103 #else 104 source->AddLocalizedString("shortProductName", IDS_SHORT_PRODUCT_NAME); 105 #endif // defined(OS_CHROMEOS) 106 107 // Group settings and help separately if settings in a window is enabled. 108 base::string16 settings_group(ASCIIToUTF16("settings_group")); 109 base::string16 other_group(ASCIIToUTF16( 110 ::switches::SettingsWindowEnabled() ? "other_group" : "settings_group")); 111 source->AddString("extensionsHost", 112 ASCIIToUTF16(chrome::kChromeUIExtensionsHost)); 113 source->AddLocalizedString("extensionsDisplayName", 114 IDS_MANAGE_EXTENSIONS_SETTING_WINDOWS_TITLE); 115 source->AddString("extensionsGroup", other_group); 116 source->AddString("helpHost", 117 ASCIIToUTF16(chrome::kChromeUIHelpHost)); 118 source->AddLocalizedString("helpDisplayName", IDS_ABOUT_TITLE); 119 source->AddString("helpGroup", settings_group); 120 source->AddString("historyHost", 121 ASCIIToUTF16(chrome::kChromeUIHistoryHost)); 122 source->AddLocalizedString("historyDisplayName", IDS_HISTORY_TITLE); 123 source->AddString("historyGroup", other_group); 124 source->AddString("settingsHost", 125 ASCIIToUTF16(chrome::kChromeUISettingsHost)); 126 source->AddLocalizedString("settingsDisplayName", IDS_SETTINGS_TITLE); 127 source->AddString("settingsGroup", settings_group); 128 bool overridesHistory = HasExtensionType(profile, 129 chrome::kChromeUIHistoryHost); 130 source->AddString("overridesHistory", 131 ASCIIToUTF16(overridesHistory ? "yes" : "no")); 132 source->DisableDenyXFrameOptions(); 133 source->OverrideContentSecurityPolicyFrameSrc("frame-src chrome:;"); 134 135 return source; 136 } 137 138 } // namespace 139 140 UberUI::UberUI(content::WebUI* web_ui) : WebUIController(web_ui) { 141 Profile* profile = Profile::FromWebUI(web_ui); 142 content::WebUIDataSource::Add(profile, CreateUberHTMLSource()); 143 144 RegisterSubpage(chrome::kChromeUIExtensionsFrameURL, 145 chrome::kChromeUIExtensionsHost); 146 RegisterSubpage(chrome::kChromeUIHelpFrameURL, 147 chrome::kChromeUIHelpHost); 148 RegisterSubpage(chrome::kChromeUIHistoryFrameURL, 149 chrome::kChromeUIHistoryHost); 150 RegisterSubpage(chrome::kChromeUISettingsFrameURL, 151 chrome::kChromeUISettingsHost); 152 RegisterSubpage(chrome::kChromeUIUberFrameURL, 153 chrome::kChromeUIUberHost); 154 } 155 156 UberUI::~UberUI() { 157 STLDeleteValues(&sub_uis_); 158 } 159 160 void UberUI::RegisterSubpage(const std::string& page_url, 161 const std::string& page_host) { 162 GURL page_gurl(page_url); 163 content::WebUI* webui = web_ui()->GetWebContents()->CreateWebUI(page_gurl); 164 165 webui->OverrideJavaScriptFrame(page_host); 166 sub_uis_[page_url] = webui; 167 } 168 169 content::WebUI* UberUI::GetSubpage(const std::string& page_url) { 170 if (!sub_uis_.count(page_url)) 171 return NULL; 172 return sub_uis_[page_url]; 173 } 174 175 void UberUI::RenderViewCreated(RenderViewHost* render_view_host) { 176 for (SubpageMap::iterator iter = sub_uis_.begin(); iter != sub_uis_.end(); 177 ++iter) { 178 iter->second->GetController()->RenderViewCreated(render_view_host); 179 } 180 } 181 182 void UberUI::RenderViewReused(RenderViewHost* render_view_host) { 183 for (SubpageMap::iterator iter = sub_uis_.begin(); iter != sub_uis_.end(); 184 ++iter) { 185 iter->second->GetController()->RenderViewReused(render_view_host); 186 } 187 } 188 189 bool UberUI::OverrideHandleWebUIMessage(const GURL& source_url, 190 const std::string& message, 191 const base::ListValue& args) { 192 // Find the appropriate subpage and forward the message. 193 SubpageMap::iterator subpage = sub_uis_.find(source_url.GetOrigin().spec()); 194 if (subpage == sub_uis_.end()) { 195 // The message was sent from the uber page itself. 196 DCHECK_EQ(std::string(chrome::kChromeUIUberHost), source_url.host()); 197 return false; 198 } 199 200 // The message was sent from a subpage. 201 // TODO(jam) fix this to use interface 202 // return subpage->second->GetController()->OverrideHandleWebUIMessage( 203 // source_url, message, args); 204 subpage->second->ProcessWebUIMessage(source_url, message, args); 205 return true; 206 } 207 208 // UberFrameUI 209 210 UberFrameUI::UberFrameUI(content::WebUI* web_ui) : WebUIController(web_ui) { 211 Profile* profile = Profile::FromWebUI(web_ui); 212 content::WebUIDataSource::Add(profile, CreateUberFrameHTMLSource(profile)); 213 214 // Register as an observer for when extensions are loaded and unloaded. 215 registrar_.Add(this, 216 chrome::NOTIFICATION_EXTENSION_LOADED_DEPRECATED, 217 content::Source<Profile>(profile)); 218 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED_DEPRECATED, 219 content::Source<Profile>(profile)); 220 } 221 222 UberFrameUI::~UberFrameUI() { 223 } 224 225 void UberFrameUI::Observe(int type, const content::NotificationSource& source, 226 const content::NotificationDetails& details) { 227 switch (type) { 228 // We listen for notifications that indicate an extension has been loaded 229 // (i.e., has been installed and/or enabled) or unloaded (i.e., has been 230 // uninstalled and/or disabled). If one of these events has occurred, then 231 // we must update the behavior of the History navigation element so that 232 // it opens the history extension if one is installed and enabled or 233 // opens the default history page if one is uninstalled or disabled. 234 case chrome::NOTIFICATION_EXTENSION_LOADED_DEPRECATED: 235 case chrome::NOTIFICATION_EXTENSION_UNLOADED_DEPRECATED: { 236 Profile* profile = Profile::FromWebUI(web_ui()); 237 bool overrides_history = 238 HasExtensionType(profile, chrome::kChromeUIHistoryHost); 239 web_ui()->CallJavascriptFunction( 240 "uber_frame.setNavigationOverride", 241 base::StringValue(chrome::kChromeUIHistoryHost), 242 base::StringValue(overrides_history ? "yes" : "no")); 243 break; 244 } 245 default: 246 NOTREACHED(); 247 } 248 } 249