open_with_browser.cc revision 58537e28ecd584eab876aee8be7156509866d23a
1// Copyright 2013 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/chromeos/file_manager/open_with_browser.h" 6 7#include "base/bind.h" 8#include "base/command_line.h" 9#include "base/logging.h" 10#include "base/path_service.h" 11#include "base/threading/sequenced_worker_pool.h" 12#include "chrome/browser/chromeos/drive/drive.pb.h" 13#include "chrome/browser/chromeos/drive/file_system.h" 14#include "chrome/browser/chromeos/drive/file_system_util.h" 15#include "chrome/browser/extensions/api/file_handlers/app_file_handler_util.h" 16#include "chrome/browser/extensions/crx_installer.h" 17#include "chrome/browser/extensions/extension_install_prompt.h" 18#include "chrome/browser/extensions/extension_service.h" 19#include "chrome/browser/extensions/extension_system.h" 20#include "chrome/browser/plugins/plugin_prefs.h" 21#include "chrome/browser/profiles/profile.h" 22#include "chrome/browser/profiles/profile_manager.h" 23#include "chrome/browser/ui/browser.h" 24#include "chrome/browser/ui/browser_finder.h" 25#include "chrome/browser/ui/browser_tabstrip.h" 26#include "chrome/browser/ui/browser_window.h" 27#include "chrome/browser/ui/simple_message_box.h" 28#include "chrome/common/chrome_paths.h" 29#include "chrome/common/chrome_switches.h" 30#include "chromeos/chromeos_switches.h" 31#include "content/public/browser/browser_thread.h" 32#include "content/public/browser/plugin_service.h" 33#include "content/public/common/pepper_plugin_info.h" 34#include "content/public/common/webplugininfo.h" 35#include "net/base/net_util.h" 36 37using content::BrowserThread; 38using content::PluginService; 39 40namespace file_manager { 41namespace util { 42namespace { 43 44const base::FilePath::CharType kCRXExtension[] = FILE_PATH_LITERAL(".crx"); 45const base::FilePath::CharType kPdfExtension[] = FILE_PATH_LITERAL(".pdf"); 46const base::FilePath::CharType kSwfExtension[] = FILE_PATH_LITERAL(".swf"); 47 48// List of file extensions viewable in the browser. 49const base::FilePath::CharType* kFileExtensionsViewableInBrowser[] = { 50#if defined(GOOGLE_CHROME_BUILD) 51 FILE_PATH_LITERAL(".pdf"), 52 FILE_PATH_LITERAL(".swf"), 53#endif 54 FILE_PATH_LITERAL(".bmp"), 55 FILE_PATH_LITERAL(".jpg"), 56 FILE_PATH_LITERAL(".jpeg"), 57 FILE_PATH_LITERAL(".png"), 58 FILE_PATH_LITERAL(".webp"), 59 FILE_PATH_LITERAL(".gif"), 60 FILE_PATH_LITERAL(".txt"), 61 FILE_PATH_LITERAL(".html"), 62 FILE_PATH_LITERAL(".htm"), 63 FILE_PATH_LITERAL(".mhtml"), 64 FILE_PATH_LITERAL(".mht"), 65 FILE_PATH_LITERAL(".svg"), 66}; 67 68// Returns true if |file_path| is viewable in the browser (ex. HTML file). 69bool IsViewableInBrowser(const base::FilePath& file_path) { 70 for (size_t i = 0; i < arraysize(kFileExtensionsViewableInBrowser); i++) { 71 if (file_path.MatchesExtension(kFileExtensionsViewableInBrowser[i])) 72 return true; 73 } 74 return false; 75} 76 77bool IsPepperPluginEnabled(Profile* profile, 78 const base::FilePath& plugin_path) { 79 DCHECK(profile); 80 81 content::PepperPluginInfo* pepper_info = 82 PluginService::GetInstance()->GetRegisteredPpapiPluginInfo(plugin_path); 83 if (!pepper_info) 84 return false; 85 86 scoped_refptr<PluginPrefs> plugin_prefs = PluginPrefs::GetForProfile(profile); 87 if (!plugin_prefs.get()) 88 return false; 89 90 return plugin_prefs->IsPluginEnabled(pepper_info->ToWebPluginInfo()); 91} 92 93bool IsPdfPluginEnabled(Profile* profile) { 94 DCHECK(profile); 95 96 base::FilePath plugin_path; 97 PathService::Get(chrome::FILE_PDF_PLUGIN, &plugin_path); 98 return IsPepperPluginEnabled(profile, plugin_path); 99} 100 101bool IsFlashPluginEnabled(Profile* profile) { 102 DCHECK(profile); 103 104 base::FilePath plugin_path( 105 CommandLine::ForCurrentProcess()->GetSwitchValueNative( 106 switches::kPpapiFlashPath)); 107 if (plugin_path.empty()) 108 PathService::Get(chrome::FILE_PEPPER_FLASH_PLUGIN, &plugin_path); 109 return IsPepperPluginEnabled(profile, plugin_path); 110} 111 112void OpenNewTab(Profile* profile, const GURL& url) { 113 DCHECK(profile); 114 115 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 116 Browser* browser = chrome::FindOrCreateTabbedBrowser( 117 profile, chrome::HOST_DESKTOP_TYPE_ASH); 118 chrome::AddSelectedTabWithURL(browser, url, content::PAGE_TRANSITION_LINK); 119 // If the current browser is not tabbed then the new tab will be created 120 // in a different browser. Make sure it is visible. 121 browser->window()->Show(); 122} 123 124void InstallCRX(Profile* profile, const base::FilePath& file_path) { 125 DCHECK(profile); 126 127 ExtensionService* service = 128 extensions::ExtensionSystem::Get(profile)->extension_service(); 129 CHECK(service); 130 131 scoped_refptr<extensions::CrxInstaller> installer( 132 extensions::CrxInstaller::Create( 133 service, 134 scoped_ptr<ExtensionInstallPrompt>(new ExtensionInstallPrompt( 135 profile, NULL, NULL)))); 136 installer->set_error_on_unsupported_requirements(true); 137 installer->set_is_gallery_install(false); 138 installer->set_allow_silent_install(false); 139 installer->InstallCrx(file_path); 140} 141 142// Called when a crx file on Drive was downloaded. 143void OnCRXDownloadCallback(Profile* profile, 144 drive::FileError error, 145 const base::FilePath& file, 146 scoped_ptr<drive::ResourceEntry> entry) { 147 DCHECK(profile); 148 149 if (error != drive::FILE_ERROR_OK) 150 return; 151 InstallCRX(profile, file); 152} 153 154// Reads the alternate URL from a GDoc file. When it fails, returns a file URL 155// for |file_path| as fallback. 156// Note that an alternate url is a URL to open a hosted document. 157GURL ReadUrlFromGDocOnBlockingPool(const base::FilePath& file_path) { 158 GURL url = drive::util::ReadUrlFromGDocFile(file_path); 159 if (url.is_empty()) 160 url = net::FilePathToFileURL(file_path); 161 return url; 162} 163 164} // namespace 165 166bool OpenFileWithBrowser(Profile* profile, const base::FilePath& file_path) { 167 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 168 DCHECK(profile); 169 170 // For things supported natively by the browser, we should open it 171 // in a tab. 172 if (IsViewableInBrowser(file_path) || 173 ShouldBeOpenedWithPlugin(profile, file_path.Extension())) { 174 GURL page_url = net::FilePathToFileURL(file_path); 175 // Override drive resource to point to internal handler instead of file URL. 176 if (drive::util::IsUnderDriveMountPoint(file_path)) { 177 page_url = drive::util::FilePathToDriveURL( 178 drive::util::ExtractDrivePath(file_path)); 179 } 180 OpenNewTab(profile, page_url); 181 return true; 182 } 183 184 if (drive::util::HasGDocFileExtension(file_path)) { 185 if (drive::util::IsUnderDriveMountPoint(file_path)) { 186 // The file is on Google Docs. Open with drive URL. 187 GURL url = drive::util::FilePathToDriveURL( 188 drive::util::ExtractDrivePath(file_path)); 189 OpenNewTab(profile, url); 190 } else { 191 // The file is local (downloaded from an attachment or otherwise copied). 192 // Parse the file to extract the Docs url and open this url. 193 base::PostTaskAndReplyWithResult( 194 BrowserThread::GetBlockingPool(), 195 FROM_HERE, 196 base::Bind(&ReadUrlFromGDocOnBlockingPool, file_path), 197 base::Bind(&OpenNewTab, static_cast<Profile*>(NULL))); 198 } 199 return true; 200 } 201 202 if (file_path.MatchesExtension(kCRXExtension)) { 203 if (drive::util::IsUnderDriveMountPoint(file_path)) { 204 drive::FileSystemInterface* file_system = 205 drive::util::GetFileSystemByProfile(profile); 206 if (!file_system) 207 return false; 208 file_system->GetFileByPath( 209 drive::util::ExtractDrivePath(file_path), 210 base::Bind(&OnCRXDownloadCallback, profile)); 211 } else { 212 InstallCRX(profile, file_path); 213 } 214 return true; 215 } 216 217 // Failed to open the file of unknown type. 218 LOG(WARNING) << "Unknown file type: " << file_path.value(); 219 return false; 220} 221 222// If a bundled plugin is enabled, we should open pdf/swf files in a tab. 223bool ShouldBeOpenedWithPlugin( 224 Profile* profile, 225 const base::FilePath::StringType& file_extension) { 226 DCHECK(profile); 227 228 const base::FilePath file_path = 229 base::FilePath::FromUTF8Unsafe("dummy").AddExtension(file_extension); 230 if (file_path.MatchesExtension(kPdfExtension)) 231 return IsPdfPluginEnabled(profile); 232 if (file_path.MatchesExtension(kSwfExtension)) 233 return IsFlashPluginEnabled(profile); 234 return false; 235} 236 237} // namespace util 238} // namespace file_manager 239