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