#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;
#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) {
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) {
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;
}
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);
}
item,
base::Bind(
&ChromeDownloadManagerDelegate::CheckClientDownloadDone,
- this,
+ weak_ptr_factory_.GetWeakPtr(),
item->GetId()));
return false;
}
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);
// 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;
item->UpdateObservers();
return false;
}
+#endif
return true;
}
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(
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(
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);
}
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(),
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,
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();
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;
}