| Index: chrome/browser/download/download_target_determiner.cc
|
| diff --git a/chrome/browser/download/download_target_determiner.cc b/chrome/browser/download/download_target_determiner.cc
|
| index 7291336364e08ed85d6393a12df346948e3e32ae..6f34d40593808dade355ea991b35cf924e944498 100644
|
| --- a/chrome/browser/download/download_target_determiner.cc
|
| +++ b/chrome/browser/download/download_target_determiner.cc
|
| @@ -23,9 +23,16 @@
|
| #include "content/public/browser/download_interrupt_reasons.h"
|
| #include "extensions/common/constants.h"
|
| #include "grit/generated_resources.h"
|
| +#include "net/base/mime_util.h"
|
| #include "net/base/net_util.h"
|
| #include "ui/base/l10n/l10n_util.h"
|
|
|
| +#if defined(ENABLE_PLUGINS)
|
| +#include "chrome/browser/plugins/plugin_prefs.h"
|
| +#include "content/public/browser/plugin_service.h"
|
| +#include "content/public/common/webplugininfo.h"
|
| +#endif
|
| +
|
| using content::BrowserThread;
|
| using content::DownloadItem;
|
|
|
| @@ -51,6 +58,11 @@ void VisitCountsToVisitedBefore(
|
|
|
| } // namespace
|
|
|
| +DownloadTargetInfo::DownloadTargetInfo()
|
| + : is_filetype_handled_securely(false) {}
|
| +
|
| +DownloadTargetInfo::~DownloadTargetInfo() {}
|
| +
|
| DownloadTargetDeterminerDelegate::~DownloadTargetDeterminerDelegate() {
|
| }
|
|
|
| @@ -59,7 +71,7 @@ DownloadTargetDeterminer::DownloadTargetDeterminer(
|
| const base::FilePath& initial_virtual_path,
|
| DownloadPrefs* download_prefs,
|
| DownloadTargetDeterminerDelegate* delegate,
|
| - const content::DownloadTargetCallback& callback)
|
| + const CompletionCallback& callback)
|
| : next_state_(STATE_GENERATE_TARGET_PATH),
|
| should_prompt_(false),
|
| should_notify_extensions_(false),
|
| @@ -67,6 +79,7 @@ DownloadTargetDeterminer::DownloadTargetDeterminer(
|
| conflict_action_(DownloadPathReservationTracker::OVERWRITE),
|
| danger_type_(download->GetDangerType()),
|
| virtual_path_(initial_virtual_path),
|
| + is_filetype_handled_securely_(false),
|
| download_(download),
|
| is_resumption_(download_->GetLastReason() !=
|
| content::DOWNLOAD_INTERRUPT_REASON_NONE &&
|
| @@ -112,6 +125,12 @@ void DownloadTargetDeterminer::DoLoop() {
|
| case STATE_DETERMINE_LOCAL_PATH:
|
| result = DoDetermineLocalPath();
|
| break;
|
| + case STATE_DETERMINE_MIME_TYPE:
|
| + result = DoDetermineMimeType();
|
| + break;
|
| + case STATE_DETERMINE_IF_HANDLED_BY_BROWSER:
|
| + result = DoDetermineIfHandledByBrowser();
|
| + break;
|
| case STATE_CHECK_DOWNLOAD_URL:
|
| result = DoCheckDownloadUrl();
|
| break;
|
| @@ -305,7 +324,7 @@ DownloadTargetDeterminer::Result
|
| DCHECK(!virtual_path_.empty());
|
| DCHECK(local_path_.empty());
|
|
|
| - next_state_ = STATE_CHECK_DOWNLOAD_URL;
|
| + next_state_ = STATE_DETERMINE_MIME_TYPE;
|
|
|
| delegate_->DetermineLocalPath(
|
| download_,
|
| @@ -329,6 +348,126 @@ void DownloadTargetDeterminer::DetermineLocalPathDone(
|
| }
|
|
|
| DownloadTargetDeterminer::Result
|
| + DownloadTargetDeterminer::DoDetermineMimeType() {
|
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
| + DCHECK(!virtual_path_.empty());
|
| + DCHECK(!local_path_.empty());
|
| + DCHECK(mime_type_.empty());
|
| +
|
| + next_state_ = STATE_DETERMINE_IF_HANDLED_BY_BROWSER;
|
| +
|
| + if (virtual_path_ == local_path_) {
|
| + delegate_->GetFileMimeType(
|
| + local_path_,
|
| + base::Bind(&DownloadTargetDeterminer::DetermineMimeTypeDone,
|
| + weak_ptr_factory_.GetWeakPtr()));
|
| + return QUIT_DOLOOP;
|
| + }
|
| + return CONTINUE;
|
| +}
|
| +
|
| +void DownloadTargetDeterminer::DetermineMimeTypeDone(
|
| + const std::string& mime_type) {
|
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
| + DVLOG(20) << "MIME type: " << mime_type;
|
| + mime_type_ = mime_type;
|
| + DoLoop();
|
| +}
|
| +
|
| +#if defined(ENABLE_PLUGINS)
|
| +// The code below is used by DoDetermineIfHandledByBrowser to determine if the
|
| +// file type is handled by a sandboxed plugin.
|
| +namespace {
|
| +
|
| +typedef std::vector<content::WebPluginInfo> PluginVector;
|
| +
|
| +// Returns true if there is a plugin in |plugins| that is sandboxed and enabled
|
| +// for |profile|.
|
| +bool IsSafePluginAvailableForProfile(scoped_ptr<PluginVector> plugins,
|
| + Profile* profile) {
|
| + using content::WebPluginInfo;
|
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
| +
|
| + if (plugins->size() == 0)
|
| + return false;
|
| +
|
| + scoped_refptr<PluginPrefs> plugin_prefs = PluginPrefs::GetForProfile(profile);
|
| + if (!plugin_prefs)
|
| + return false;
|
| +
|
| + for (PluginVector::iterator plugin = plugins->begin();
|
| + plugin != plugins->end(); ++plugin) {
|
| + if (plugin_prefs->IsPluginEnabled(*plugin) &&
|
| + (plugin->type == WebPluginInfo::PLUGIN_TYPE_PEPPER_IN_PROCESS ||
|
| + plugin->type == WebPluginInfo::PLUGIN_TYPE_PEPPER_OUT_OF_PROCESS))
|
| + return true;
|
| + }
|
| + return false;
|
| +}
|
| +
|
| +// Returns a callback that determines if a sandboxed plugin is available to
|
| +// handle |mime_type| for a specific profile. The returned callback must be
|
| +// invoked on the UI thread, while this function should be called on the IO
|
| +// thread.
|
| +base::Callback<bool(Profile*)> GetSafePluginChecker(
|
| + const GURL& url,
|
| + const std::string& mime_type) {
|
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
|
| + DCHECK(!mime_type.empty());
|
| +
|
| + scoped_ptr<PluginVector> plugins(new PluginVector);
|
| + content::PluginService* plugin_service =
|
| + content::PluginService::GetInstance();
|
| + if (plugin_service)
|
| + plugin_service->GetPluginInfoArray(
|
| + url, mime_type, false, plugins.get(), NULL);
|
| + return base::Bind(&IsSafePluginAvailableForProfile, base::Passed(&plugins));
|
| +}
|
| +
|
| +} // namespace
|
| +#endif // ENABLE_PLUGINS
|
| +
|
| +DownloadTargetDeterminer::Result
|
| + DownloadTargetDeterminer::DoDetermineIfHandledByBrowser() {
|
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
| + DCHECK(!virtual_path_.empty());
|
| + DCHECK(!local_path_.empty());
|
| + DCHECK(!is_filetype_handled_securely_);
|
| +
|
| + next_state_ = STATE_CHECK_DOWNLOAD_URL;
|
| +
|
| + if (mime_type_.empty())
|
| + return CONTINUE;
|
| +
|
| + if (net::IsSupportedMimeType(mime_type_)) {
|
| + is_filetype_handled_securely_ = true;
|
| + return CONTINUE;
|
| + }
|
| +
|
| +#if defined(ENABLE_PLUGINS)
|
| + BrowserThread::PostTaskAndReplyWithResult(
|
| + BrowserThread::IO,
|
| + FROM_HERE,
|
| + base::Bind(&GetSafePluginChecker,
|
| + net::FilePathToFileURL(local_path_), mime_type_),
|
| + base::Bind(&DownloadTargetDeterminer::DetermineIfHandledByBrowserDone,
|
| + weak_ptr_factory_.GetWeakPtr()));
|
| + return QUIT_DOLOOP;
|
| +#else
|
| + return CONTINUE;
|
| +#endif
|
| +}
|
| +
|
| +void DownloadTargetDeterminer::DetermineIfHandledByBrowserDone(
|
| + const base::Callback<bool(Profile*)>& callback) {
|
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
| + is_filetype_handled_securely_ = callback.Run(GetProfile());
|
| + DVLOG(20) << "Is file type handled securely: "
|
| + << is_filetype_handled_securely_;
|
| + DoLoop();
|
| +}
|
| +
|
| +DownloadTargetDeterminer::Result
|
| DownloadTargetDeterminer::DoCheckDownloadUrl() {
|
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
| DCHECK(!virtual_path_.empty());
|
| @@ -484,15 +623,20 @@ void DownloadTargetDeterminer::ScheduleCallbackAndDeleteSelf() {
|
| << " Intermediate:" << intermediate_path_.AsUTF8Unsafe()
|
| << " Should prompt:" << should_prompt_
|
| << " Danger type:" << danger_type_;
|
| + scoped_ptr<DownloadTargetInfo> target_info(new DownloadTargetInfo);
|
| +
|
| + target_info->target_path = local_path_;
|
| + target_info->target_disposition =
|
| + (HasPromptedForPath() || should_prompt_
|
| + ? DownloadItem::TARGET_DISPOSITION_PROMPT
|
| + : DownloadItem::TARGET_DISPOSITION_OVERWRITE);
|
| + target_info->danger_type = danger_type_;
|
| + target_info->intermediate_path = intermediate_path_;
|
| + target_info->mime_type = mime_type_;
|
| + target_info->is_filetype_handled_securely = is_filetype_handled_securely_;
|
| +
|
| base::MessageLoop::current()->PostTask(
|
| - FROM_HERE,
|
| - base::Bind(completion_callback_,
|
| - local_path_,
|
| - (HasPromptedForPath() || should_prompt_
|
| - ? DownloadItem::TARGET_DISPOSITION_PROMPT
|
| - : DownloadItem::TARGET_DISPOSITION_OVERWRITE),
|
| - danger_type_,
|
| - intermediate_path_));
|
| + FROM_HERE, base::Bind(completion_callback_, base::Passed(&target_info)));
|
| completion_callback_.Reset();
|
| delete this;
|
| }
|
| @@ -631,12 +775,11 @@ void DownloadTargetDeterminer::OnDownloadDestroyed(
|
| }
|
|
|
| // static
|
| -void DownloadTargetDeterminer::Start(
|
| - content::DownloadItem* download,
|
| - const base::FilePath& initial_virtual_path,
|
| - DownloadPrefs* download_prefs,
|
| - DownloadTargetDeterminerDelegate* delegate,
|
| - const content::DownloadTargetCallback& callback) {
|
| +void DownloadTargetDeterminer::Start(content::DownloadItem* download,
|
| + const base::FilePath& initial_virtual_path,
|
| + DownloadPrefs* download_prefs,
|
| + DownloadTargetDeterminerDelegate* delegate,
|
| + const CompletionCallback& callback) {
|
| // DownloadTargetDeterminer owns itself and will self destruct when the job is
|
| // complete or the download item is destroyed. The callback is always invoked
|
| // asynchronously.
|
|
|