Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / download / chrome_download_manager_delegate.cc
index 0e32cdf..2c23826 100644 (file)
@@ -6,6 +6,7 @@
 
 #include <string>
 
+#include "base/basictypes.h"
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/callback.h"
 #include "base/rand_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/task_runner.h"
+#include "base/task_runner_util.h"
+#include "base/threading/sequenced_worker_pool.h"
 #include "base/time/time.h"
 #include "chrome/browser/browser_process.h"
-#include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/download/download_completion_blocker.h"
 #include "chrome/browser/download/download_crx_util.h"
 #include "chrome/browser/download/download_file_picker.h"
 #include "chrome/browser/download/download_history.h"
+#include "chrome/browser/download/download_item_model.h"
 #include "chrome/browser/download/download_path_reservation_tracker.h"
 #include "chrome/browser/download/download_prefs.h"
 #include "chrome/browser/download/download_service.h"
 #include "chrome/browser/download/download_service_factory.h"
+#include "chrome/browser/download/download_stats.h"
 #include "chrome/browser/download/download_target_determiner.h"
 #include "chrome/browser/download/save_package_file_picker.h"
-#include "chrome/browser/extensions/api/downloads/downloads_api.h"
-#include "chrome/browser/extensions/crx_installer.h"
 #include "chrome/browser/platform_util.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/safe_browsing/safe_browsing_service.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_finder.h"
+#include "chrome/browser/ui/scoped_tabbed_browser_displayer.h"
 #include "chrome/common/chrome_constants.h"
 #include "chrome/common/pref_names.h"
-#include "components/user_prefs/pref_registry_syncable.h"
+#include "components/pref_registry/pref_registry_syncable.h"
 #include "content/public/browser/download_item.h"
 #include "content/public/browser/download_manager.h"
 #include "content/public/browser/notification_source.h"
-#include "extensions/common/constants.h"
+#include "content/public/browser/page_navigator.h"
+#include "extensions/browser/notification_types.h"
+#include "net/base/filename_util.h"
+#include "net/base/mime_util.h"
 
 #if defined(OS_CHROMEOS)
 #include "chrome/browser/chromeos/drive/download_handler.h"
 #include "chrome/browser/chromeos/drive/file_system_util.h"
 #endif
 
+#if defined(ENABLE_EXTENSIONS)
+#include "chrome/browser/extensions/api/downloads/downloads_api.h"
+#include "chrome/browser/extensions/crx_installer.h"
+#include "chrome/browser/extensions/webstore_installer.h"
+#include "extensions/common/constants.h"
+#endif
+
 using content::BrowserThread;
 using content::DownloadItem;
 using content::DownloadManager;
@@ -161,15 +177,25 @@ void CheckDownloadUrlDone(
 
 #endif  // FULL_SAFE_BROWSING
 
+// Called on the blocking pool to determine the MIME type for |path|.
+std::string GetMimeType(const base::FilePath& path) {
+  std::string mime_type;
+  net::GetMimeTypeFromFile(path, &mime_type);
+  return mime_type;
+}
+
 }  // namespace
 
 ChromeDownloadManagerDelegate::ChromeDownloadManagerDelegate(Profile* profile)
     : profile_(profile),
       next_download_id_(content::DownloadItem::kInvalidId),
-      download_prefs_(new DownloadPrefs(profile)) {
+      download_prefs_(new DownloadPrefs(profile)),
+      weak_ptr_factory_(this) {
 }
 
 ChromeDownloadManagerDelegate::~ChromeDownloadManagerDelegate() {
+  // If a DownloadManager was set for this, Shutdown() must be called.
+  DCHECK(!download_manager_);
 }
 
 void ChromeDownloadManagerDelegate::SetDownloadManager(DownloadManager* dm) {
@@ -178,6 +204,14 @@ void ChromeDownloadManagerDelegate::SetDownloadManager(DownloadManager* dm) {
 
 void ChromeDownloadManagerDelegate::Shutdown() {
   download_prefs_.reset();
+  weak_ptr_factory_.InvalidateWeakPtrs();
+  download_manager_ = NULL;
+}
+
+content::DownloadIdCallback
+ChromeDownloadManagerDelegate::GetDownloadIdReceiverCallback() {
+  return base::Bind(&ChromeDownloadManagerDelegate::SetNextId,
+                    weak_ptr_factory_.GetWeakPtr());
 }
 
 void ChromeDownloadManagerDelegate::SetNextId(uint32 next_id) {
@@ -220,13 +254,17 @@ void ChromeDownloadManagerDelegate::ReturnNextId(
 bool ChromeDownloadManagerDelegate::DetermineDownloadTarget(
     DownloadItem* download,
     const content::DownloadTargetCallback& callback) {
+  DownloadTargetDeterminer::CompletionCallback target_determined_callback =
+      base::Bind(&ChromeDownloadManagerDelegate::OnDownloadTargetDetermined,
+                 weak_ptr_factory_.GetWeakPtr(),
+                 download->GetId(),
+                 callback);
   DownloadTargetDeterminer::Start(
       download,
-      GetPlatformDownloadPath(
-          profile_, download, PLATFORM_TARGET_PATH),
+      GetPlatformDownloadPath(profile_, download, PLATFORM_TARGET_PATH),
       download_prefs_.get(),
       this,
-      callback);
+      target_determined_callback);
   return true;
 }
 
@@ -235,11 +273,13 @@ bool ChromeDownloadManagerDelegate::ShouldOpenFileBasedOnExtension(
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   if (path.Extension().empty())
     return false;
+#if defined(ENABLE_EXTENSIONS)
   // TODO(asanka): This determination is done based on |path|, while
   // ShouldOpenDownload() detects extension downloads based on the
   // characteristics of the download. Reconcile this. http://crbug.com/167702
   if (path.MatchesExtension(extensions::kExtensionFileExtension))
     return false;
+#endif
   return download_prefs_->IsAutoOpenEnabledBasedOnExtension(path);
 }
 
@@ -277,7 +317,7 @@ bool ChromeDownloadManagerDelegate::IsDownloadReadyForCompletion(
           item,
           base::Bind(
               &ChromeDownloadManagerDelegate::CheckClientDownloadDone,
-              this,
+              weak_ptr_factory_.GetWeakPtr(),
               item->GetId()));
       return false;
     }
@@ -305,12 +345,14 @@ bool ChromeDownloadManagerDelegate::ShouldCompleteDownload(
     const base::Closure& user_complete_callback) {
   return IsDownloadReadyForCompletion(item, base::Bind(
       &ChromeDownloadManagerDelegate::ShouldCompleteDownloadInternal,
-      this, item->GetId(), user_complete_callback));
+      weak_ptr_factory_.GetWeakPtr(), item->GetId(), user_complete_callback));
 }
 
 bool ChromeDownloadManagerDelegate::ShouldOpenDownload(
     DownloadItem* item, const content::DownloadOpenDelayedCallback& callback) {
-  if (download_crx_util::IsExtensionDownload(*item)) {
+#if defined(ENABLE_EXTENSIONS)
+  if (download_crx_util::IsExtensionDownload(*item) &&
+      !extensions::WebstoreInstaller::GetAssociatedApproval(*item)) {
     scoped_refptr<extensions::CrxInstaller> crx_installer =
         download_crx_util::OpenChromeExtension(profile_, *item);
 
@@ -318,7 +360,7 @@ bool ChromeDownloadManagerDelegate::ShouldOpenDownload(
     // time, Observe() will call the passed callback.
     registrar_.Add(
         this,
-        chrome::NOTIFICATION_CRX_INSTALLER_DONE,
+        extensions::NOTIFICATION_CRX_INSTALLER_DONE,
         content::Source<extensions::CrxInstaller>(crx_installer.get()));
 
     crx_installers_[crx_installer.get()] = callback;
@@ -328,6 +370,7 @@ bool ChromeDownloadManagerDelegate::ShouldOpenDownload(
     item->UpdateObservers();
     return false;
   }
+#endif
 
   return true;
 }
@@ -371,14 +414,49 @@ void ChromeDownloadManagerDelegate::ChooseSavePath(
       callback);
 }
 
+void ChromeDownloadManagerDelegate::OpenDownloadUsingPlatformHandler(
+    DownloadItem* download) {
+  base::FilePath platform_path(
+      GetPlatformDownloadPath(profile_, download, PLATFORM_TARGET_PATH));
+  DCHECK(!platform_path.empty());
+  platform_util::OpenItem(profile_, platform_path);
+}
+
 void ChromeDownloadManagerDelegate::OpenDownload(DownloadItem* download) {
   DCHECK_EQ(DownloadItem::COMPLETE, download->GetState());
+  DCHECK(!download->GetTargetFilePath().empty());
   if (!download->CanOpenDownload())
     return;
-  base::FilePath platform_path(
-      GetPlatformDownloadPath(profile_, download, PLATFORM_TARGET_PATH));
-  DCHECK(!platform_path.empty());
-  platform_util::OpenItem(platform_path);
+
+  if (!DownloadItemModel(download).ShouldPreferOpeningInBrowser()) {
+    RecordDownloadOpenMethod(DOWNLOAD_OPEN_METHOD_DEFAULT_PLATFORM);
+    OpenDownloadUsingPlatformHandler(download);
+    return;
+  }
+
+#if !defined(OS_ANDROID)
+  content::WebContents* web_contents = download->GetWebContents();
+  Browser* browser =
+      web_contents ? chrome::FindBrowserWithWebContents(web_contents) : NULL;
+  scoped_ptr<chrome::ScopedTabbedBrowserDisplayer> browser_displayer;
+  if (!browser ||
+      !browser->CanSupportWindowFeature(Browser::FEATURE_TABSTRIP)) {
+    browser_displayer.reset(new chrome::ScopedTabbedBrowserDisplayer(
+        profile_, chrome::GetActiveDesktop()));
+    browser = browser_displayer->browser();
+  }
+  content::OpenURLParams params(
+      net::FilePathToFileURL(download->GetTargetFilePath()),
+      content::Referrer(),
+      NEW_FOREGROUND_TAB,
+      content::PAGE_TRANSITION_LINK,
+      false);
+  browser->OpenURL(params);
+  RecordDownloadOpenMethod(DOWNLOAD_OPEN_METHOD_DEFAULT_BROWSER);
+#else
+  // ShouldPreferOpeningInBrowser() should never be true on Android.
+  NOTREACHED();
+#endif
 }
 
 void ChromeDownloadManagerDelegate::ShowDownloadInShell(
@@ -388,7 +466,7 @@ void ChromeDownloadManagerDelegate::ShowDownloadInShell(
   base::FilePath platform_path(
       GetPlatformDownloadPath(profile_, download, PLATFORM_CURRENT_PATH));
   DCHECK(!platform_path.empty());
-  platform_util::ShowItemInFolder(platform_path);
+  platform_util::ShowItemInFolder(profile_, platform_path);
 }
 
 void ChromeDownloadManagerDelegate::CheckForFileExistence(
@@ -403,8 +481,15 @@ void ChromeDownloadManagerDelegate::CheckForFileExistence(
     return;
   }
 #endif
-  BrowserThread::PostTaskAndReplyWithResult(
-      BrowserThread::FILE, FROM_HERE,
+  static const char kSequenceToken[] = "ChromeDMD-FileExistenceChecker";
+  base::SequencedWorkerPool* worker_pool = BrowserThread::GetBlockingPool();
+  scoped_refptr<base::SequencedTaskRunner> task_runner =
+      worker_pool->GetSequencedTaskRunnerWithShutdownBehavior(
+          worker_pool->GetNamedSequenceToken(kSequenceToken),
+          base::SequencedWorkerPool::SKIP_ON_SHUTDOWN);
+  base::PostTaskAndReplyWithResult(
+      task_runner.get(),
+      FROM_HERE,
       base::Bind(&base::PathExists, download->GetTargetFilePath()),
       callback);
 }
@@ -432,10 +517,10 @@ void ChromeDownloadManagerDelegate::NotifyExtensions(
     const base::FilePath& virtual_path,
     const NotifyExtensionsCallback& callback) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-#if !defined(OS_ANDROID)
-  ExtensionDownloadsEventRouter* router =
-      DownloadServiceFactory::GetForBrowserContext(profile_)->
-      GetExtensionEventRouter();
+#if defined(ENABLE_EXTENSIONS)
+  extensions::ExtensionDownloadsEventRouter* router =
+      DownloadServiceFactory::GetForBrowserContext(profile_)
+          ->GetExtensionEventRouter();
   if (router) {
     base::Closure original_path_callback =
         base::Bind(callback, base::FilePath(),
@@ -523,6 +608,16 @@ void ChromeDownloadManagerDelegate::CheckDownloadUrl(
   callback.Run(content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS);
 }
 
+void ChromeDownloadManagerDelegate::GetFileMimeType(
+    const base::FilePath& path,
+    const GetFileMimeTypeCallback& callback) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  base::PostTaskAndReplyWithResult(BrowserThread::GetBlockingPool(),
+                                   FROM_HERE,
+                                   base::Bind(&GetMimeType, path),
+                                   callback);
+}
+
 #if defined(FULL_SAFE_BROWSING)
 void ChromeDownloadManagerDelegate::CheckClientDownloadDone(
     uint32 download_id,
@@ -573,11 +668,10 @@ void ChromeDownloadManagerDelegate::Observe(
     int type,
     const content::NotificationSource& source,
     const content::NotificationDetails& details) {
-  DCHECK(type == chrome::NOTIFICATION_CRX_INSTALLER_DONE);
+#if defined(ENABLE_EXTENSIONS)
+  DCHECK(type == extensions::NOTIFICATION_CRX_INSTALLER_DONE);
 
-  registrar_.Remove(this,
-                    chrome::NOTIFICATION_CRX_INSTALLER_DONE,
-                    source);
+  registrar_.Remove(this, extensions::NOTIFICATION_CRX_INSTALLER_DONE, source);
 
   scoped_refptr<extensions::CrxInstaller> installer =
       content::Source<extensions::CrxInstaller>(source).ptr();
@@ -585,4 +679,53 @@ void ChromeDownloadManagerDelegate::Observe(
       crx_installers_[installer.get()];
   crx_installers_.erase(installer.get());
   callback.Run(installer->did_handle_successfully());
+#endif
+}
+
+void ChromeDownloadManagerDelegate::OnDownloadTargetDetermined(
+    int32 download_id,
+    const content::DownloadTargetCallback& callback,
+    scoped_ptr<DownloadTargetInfo> target_info) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  DownloadItem* item = download_manager_->GetDownload(download_id);
+  if (!target_info->target_path.empty() && item &&
+      IsOpenInBrowserPreferreredForFile(target_info->target_path) &&
+      target_info->is_filetype_handled_safely)
+    DownloadItemModel(item).SetShouldPreferOpeningInBrowser(true);
+  callback.Run(target_info->target_path,
+               target_info->target_disposition,
+               target_info->danger_type,
+               target_info->intermediate_path);
+}
+
+bool ChromeDownloadManagerDelegate::IsOpenInBrowserPreferreredForFile(
+    const base::FilePath& path) {
+  // On Windows, PDFs should open in Acrobat Reader if the user chooses.
+#if defined(OS_WIN)
+  if (path.MatchesExtension(FILE_PATH_LITERAL(".pdf")) &&
+      DownloadTargetDeterminer::IsAdobeReaderUpToDate()) {
+    return !download_prefs_->ShouldOpenPdfInAdobeReader();
+  }
+#endif
+
+  // On Android, always prefer opening with an external app. On ChromeOS, there
+  // are no external apps so just allow all opens to be handled by the "System."
+#if !defined(OS_ANDROID) && !defined(OS_CHROMEOS) && defined(ENABLE_PLUGINS)
+  // TODO(asanka): Consider other file types and MIME types.
+  // http://crbug.com/323561
+  if (path.MatchesExtension(FILE_PATH_LITERAL(".pdf")) ||
+      path.MatchesExtension(FILE_PATH_LITERAL(".htm")) ||
+      path.MatchesExtension(FILE_PATH_LITERAL(".html")) ||
+      path.MatchesExtension(FILE_PATH_LITERAL(".shtm")) ||
+      path.MatchesExtension(FILE_PATH_LITERAL(".shtml")) ||
+      path.MatchesExtension(FILE_PATH_LITERAL(".svg")) ||
+      path.MatchesExtension(FILE_PATH_LITERAL(".xht")) ||
+      path.MatchesExtension(FILE_PATH_LITERAL(".xhtm")) ||
+      path.MatchesExtension(FILE_PATH_LITERAL(".xhtml")) ||
+      path.MatchesExtension(FILE_PATH_LITERAL(".xsl")) ||
+      path.MatchesExtension(FILE_PATH_LITERAL(".xslt"))) {
+    return true;
+  }
+#endif
+  return false;
 }