Home | History | Annotate | Download | only in file_manager
      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