Chromium Code Reviews| 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..99ce57b46dc9279e4fbb7324c54ceaf12e0cf531 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,121 @@ 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; |
| + |
| + 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. Must be called on the IO thread. |
|
Randy Smith (Not in Mondays)
2013/11/04 22:57:47
nit: The second sentence can be ambiguously read a
asanka
2013/11/05 21:31:39
Done. Reworded to explicitly state thread restrict
|
| +base::Callback<bool(Profile*)> GetSafePluginChecker( |
| + 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( |
| + GURL(), 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, mime_type_), |
| + base::Bind(&DownloadTargetDeterminer::DetermineIfHandledByBrowserDone, |
|
Randy Smith (Not in Mondays)
2013/11/04 22:57:47
Just confirming: I read this code as using the mim
asanka
2013/11/05 21:31:39
The flow for file:// URLs is:
//net:
- MIME type
|
| + 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 +618,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 +770,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. |