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