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/file_system_util.h" 14 #include "chrome/browser/chromeos/file_manager/filesystem_api_util.h" 15 #include "chrome/browser/chromeos/fileapi/external_file_url_util.h" 16 #include "chrome/browser/drive/drive_api_util.h" 17 #include "chrome/browser/plugins/plugin_prefs.h" 18 #include "chrome/browser/profiles/profile_manager.h" 19 #include "chrome/browser/ui/ash/multi_user/multi_user_util.h" 20 #include "chrome/browser/ui/browser.h" 21 #include "chrome/browser/ui/browser_tabstrip.h" 22 #include "chrome/browser/ui/browser_window.h" 23 #include "chrome/browser/ui/scoped_tabbed_browser_displayer.h" 24 #include "chrome/common/chrome_paths.h" 25 #include "chrome/common/chrome_switches.h" 26 #include "content/public/browser/browser_thread.h" 27 #include "content/public/browser/plugin_service.h" 28 #include "content/public/common/pepper_plugin_info.h" 29 #include "net/base/filename_util.h" 30 31 using content::BrowserThread; 32 using content::PluginService; 33 34 namespace file_manager { 35 namespace util { 36 namespace { 37 38 const base::FilePath::CharType kPdfExtension[] = FILE_PATH_LITERAL(".pdf"); 39 const base::FilePath::CharType kSwfExtension[] = FILE_PATH_LITERAL(".swf"); 40 41 // List of file extensions viewable in the browser. 42 const base::FilePath::CharType* kFileExtensionsViewableInBrowser[] = { 43 FILE_PATH_LITERAL(".bmp"), 44 FILE_PATH_LITERAL(".ico"), 45 FILE_PATH_LITERAL(".jpg"), 46 FILE_PATH_LITERAL(".jpeg"), 47 FILE_PATH_LITERAL(".png"), 48 FILE_PATH_LITERAL(".webp"), 49 FILE_PATH_LITERAL(".gif"), 50 FILE_PATH_LITERAL(".txt"), 51 FILE_PATH_LITERAL(".html"), 52 FILE_PATH_LITERAL(".htm"), 53 FILE_PATH_LITERAL(".mhtml"), 54 FILE_PATH_LITERAL(".mht"), 55 FILE_PATH_LITERAL(".svg"), 56 }; 57 58 // Returns true if |file_path| is viewable in the browser (ex. HTML file). 59 bool IsViewableInBrowser(const base::FilePath& file_path) { 60 for (size_t i = 0; i < arraysize(kFileExtensionsViewableInBrowser); i++) { 61 if (file_path.MatchesExtension(kFileExtensionsViewableInBrowser[i])) 62 return true; 63 } 64 return false; 65 } 66 67 bool IsPepperPluginEnabled(Profile* profile, 68 const base::FilePath& plugin_path) { 69 DCHECK(profile); 70 71 content::PepperPluginInfo* pepper_info = 72 PluginService::GetInstance()->GetRegisteredPpapiPluginInfo(plugin_path); 73 if (!pepper_info) 74 return false; 75 76 scoped_refptr<PluginPrefs> plugin_prefs = PluginPrefs::GetForProfile(profile); 77 if (!plugin_prefs.get()) 78 return false; 79 80 return plugin_prefs->IsPluginEnabled(pepper_info->ToWebPluginInfo()); 81 } 82 83 bool IsPdfPluginEnabled(Profile* profile) { 84 DCHECK(profile); 85 86 base::FilePath plugin_path; 87 PathService::Get(chrome::FILE_PDF_PLUGIN, &plugin_path); 88 return IsPepperPluginEnabled(profile, plugin_path); 89 } 90 91 bool IsFlashPluginEnabled(Profile* profile) { 92 DCHECK(profile); 93 94 base::FilePath plugin_path( 95 CommandLine::ForCurrentProcess()->GetSwitchValueNative( 96 switches::kPpapiFlashPath)); 97 if (plugin_path.empty()) 98 PathService::Get(chrome::FILE_PEPPER_FLASH_PLUGIN, &plugin_path); 99 return IsPepperPluginEnabled(profile, plugin_path); 100 } 101 102 void OpenNewTab(Profile* profile, const GURL& url) { 103 DCHECK_CURRENTLY_ON(BrowserThread::UI); 104 105 // Check the validity of the pointer so that the closure from 106 // base::Bind(&OpenNewTab, profile) can be passed between threads. 107 if (!g_browser_process->profile_manager()->IsValidProfile(profile)) 108 return; 109 110 chrome::ScopedTabbedBrowserDisplayer displayer( 111 profile, chrome::HOST_DESKTOP_TYPE_ASH); 112 chrome::AddSelectedTabWithURL(displayer.browser(), url, 113 ui::PAGE_TRANSITION_LINK); 114 115 // Since the ScopedTabbedBrowserDisplayer does not guarantee that the 116 // browser will be shown on the active desktop, we ensure the visibility. 117 multi_user_util::MoveWindowToCurrentDesktop( 118 displayer.browser()->window()->GetNativeWindow()); 119 } 120 121 // Reads the alternate URL from a GDoc file. When it fails, returns a file URL 122 // for |file_path| as fallback. 123 // Note that an alternate url is a URL to open a hosted document. 124 GURL ReadUrlFromGDocOnBlockingPool(const base::FilePath& file_path) { 125 GURL url = drive::util::ReadUrlFromGDocFile(file_path); 126 if (url.is_empty()) 127 url = net::FilePathToFileURL(file_path); 128 return url; 129 } 130 131 } // namespace 132 133 bool OpenFileWithBrowser(Profile* profile, 134 const storage::FileSystemURL& file_system_url) { 135 DCHECK_CURRENTLY_ON(BrowserThread::UI); 136 DCHECK(profile); 137 138 const base::FilePath file_path = file_system_url.path(); 139 140 // For things supported natively by the browser, we should open it 141 // in a tab. 142 if (IsViewableInBrowser(file_path) || 143 ShouldBeOpenedWithPlugin(profile, file_path.Extension())) { 144 // Use external file URL if it is provided for the file system. 145 GURL page_url = chromeos::FileSystemURLToExternalFileURL(file_system_url); 146 if (page_url.is_empty()) 147 page_url = net::FilePathToFileURL(file_path); 148 149 OpenNewTab(profile, page_url); 150 return true; 151 } 152 153 if (drive::util::HasHostedDocumentExtension(file_path)) { 154 if (file_manager::util::IsUnderNonNativeLocalPath(profile, file_path)) { 155 // The file is on a non-native volume. Use external file URL. If the file 156 // is on the drive volume, ExternalFileURLRequestJob redirects the URL to 157 // drive's web interface. Otherwise (e.g. MTP, FSP), the file is just 158 // downloaded in a browser tab. 159 const GURL url = 160 chromeos::FileSystemURLToExternalFileURL(file_system_url); 161 DCHECK(!url.is_empty()); 162 OpenNewTab(profile, url); 163 } else { 164 // The file is local (downloaded from an attachment or otherwise copied). 165 // Parse the file to extract the Docs url and open this url. 166 base::PostTaskAndReplyWithResult( 167 BrowserThread::GetBlockingPool(), 168 FROM_HERE, 169 base::Bind(&ReadUrlFromGDocOnBlockingPool, file_path), 170 base::Bind(&OpenNewTab, profile)); 171 } 172 return true; 173 } 174 175 // Failed to open the file of unknown type. 176 LOG(WARNING) << "Unknown file type: " << file_path.value(); 177 return false; 178 } 179 180 // If a bundled plugin is enabled, we should open pdf/swf files in a tab. 181 bool ShouldBeOpenedWithPlugin( 182 Profile* profile, 183 const base::FilePath::StringType& file_extension) { 184 DCHECK(profile); 185 186 const base::FilePath file_path = 187 base::FilePath::FromUTF8Unsafe("dummy").AddExtension(file_extension); 188 if (file_path.MatchesExtension(kPdfExtension)) 189 return IsPdfPluginEnabled(profile); 190 if (file_path.MatchesExtension(kSwfExtension)) 191 return IsFlashPluginEnabled(profile); 192 return false; 193 } 194 195 } // namespace util 196 } // namespace file_manager 197