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