| Index: chrome/browser/file_select_helper.cc
|
| ===================================================================
|
| --- chrome/browser/file_select_helper.cc (revision 79702)
|
| +++ chrome/browser/file_select_helper.cc (working copy)
|
| @@ -12,6 +12,8 @@
|
| #include "base/utf_string_conversions.h"
|
| #include "chrome/browser/platform_util.h"
|
| #include "chrome/browser/profiles/profile.h"
|
| +#include "content/browser/child_process_security_policy.h"
|
| +#include "content/browser/renderer_host/render_process_host.h"
|
| #include "content/browser/renderer_host/render_view_host.h"
|
| #include "content/browser/renderer_host/render_widget_host_view.h"
|
| #include "content/browser/tab_contents/tab_contents.h"
|
| @@ -22,6 +24,14 @@
|
| #include "net/base/mime_util.h"
|
| #include "ui/base/l10n/l10n_util.h"
|
|
|
| +namespace {
|
| +
|
| +// There is only one file-selection happening at any given time,
|
| +// so we allocate an enumeration ID for that purpose. All IDs from
|
| +// the renderer must start at 0 and increase.
|
| +static const int kFileSelectEnumerationId = -1;
|
| +}
|
| +
|
| FileSelectHelper::FileSelectHelper(Profile* profile)
|
| : profile_(profile),
|
| render_view_host_(NULL),
|
| @@ -35,10 +45,17 @@
|
| if (select_file_dialog_.get())
|
| select_file_dialog_->ListenerDestroyed();
|
|
|
| - // Stop any pending directory enumeration and prevent a callback.
|
| - if (directory_lister_.get()) {
|
| - directory_lister_->set_delegate(NULL);
|
| - directory_lister_->Cancel();
|
| + // Stop any pending directory enumeration, prevent a callback, and free
|
| + // allocated memory.
|
| + std::map<int, ActiveDirectoryEnumeration*>::iterator iter;
|
| + for (iter = directory_enumerations_.begin();
|
| + iter != directory_enumerations_.end();
|
| + ++iter) {
|
| + if (iter->second->lister_.get()) {
|
| + iter->second->lister_->set_delegate(NULL);
|
| + iter->second->lister_->Cancel();
|
| + }
|
| + delete iter->second;
|
| }
|
| }
|
|
|
| @@ -50,7 +67,7 @@
|
| profile_->set_last_selected_directory(path.DirName());
|
|
|
| if (dialog_type_ == SelectFileDialog::SELECT_FOLDER) {
|
| - DirectorySelected(path);
|
| + StartNewEnumeration(path, kFileSelectEnumerationId, render_view_host_);
|
| return;
|
| }
|
|
|
| @@ -85,40 +102,55 @@
|
| render_view_host_ = NULL;
|
| }
|
|
|
| -void FileSelectHelper::DirectorySelected(const FilePath& path) {
|
| - directory_lister_ = new net::DirectoryLister(path,
|
| - true,
|
| - net::DirectoryLister::NO_SORT,
|
| - this);
|
| - if (!directory_lister_->Start())
|
| - FileSelectionCanceled(NULL);
|
| +void FileSelectHelper::StartNewEnumeration(const FilePath& path,
|
| + int request_id,
|
| + RenderViewHost* render_view_host) {
|
| + scoped_ptr<ActiveDirectoryEnumeration> entry(new ActiveDirectoryEnumeration);
|
| + entry->rvh_ = render_view_host;
|
| + entry->delegate_.reset(new DirectoryListerDispatchDelegate(this, request_id));
|
| + entry->lister_ = new net::DirectoryLister(path,
|
| + true,
|
| + net::DirectoryLister::NO_SORT,
|
| + entry->delegate_.get());
|
| + if (!entry->lister_->Start()) {
|
| + if (request_id == kFileSelectEnumerationId)
|
| + FileSelectionCanceled(NULL);
|
| + else
|
| + render_view_host->DirectoryEnumerationFinished(request_id,
|
| + entry->results_);
|
| + } else {
|
| + directory_enumerations_[request_id] = entry.release();
|
| + }
|
| }
|
|
|
| void FileSelectHelper::OnListFile(
|
| + int id,
|
| const net::DirectoryLister::DirectoryListerData& data) {
|
| + ActiveDirectoryEnumeration* entry = directory_enumerations_[id];
|
| +
|
| // Directory upload returns directories via a "." file, so that
|
| // empty directories are included. This util call just checks
|
| // the flags in the structure; there's no file I/O going on.
|
| if (file_util::FileEnumerator::IsDirectory(data.info))
|
| - directory_lister_results_.push_back(
|
| - data.path.Append(FILE_PATH_LITERAL(".")));
|
| + entry->results_.push_back(data.path.Append(FILE_PATH_LITERAL(".")));
|
| else
|
| - directory_lister_results_.push_back(data.path);
|
| + entry->results_.push_back(data.path);
|
| }
|
|
|
| -void FileSelectHelper::OnListDone(int error) {
|
| - if (!render_view_host_)
|
| +void FileSelectHelper::OnListDone(int id, int error) {
|
| + // This entry needs to be cleaned up when this function is done.
|
| + scoped_ptr<ActiveDirectoryEnumeration> entry(directory_enumerations_[id]);
|
| + directory_enumerations_.erase(id);
|
| + if (!entry->rvh_)
|
| return;
|
| -
|
| if (error) {
|
| FileSelectionCanceled(NULL);
|
| return;
|
| }
|
| -
|
| - render_view_host_->FilesSelectedInChooser(directory_lister_results_);
|
| - render_view_host_ = NULL;
|
| - directory_lister_ = NULL;
|
| - directory_lister_results_.clear();
|
| + if (id == kFileSelectEnumerationId)
|
| + entry->rvh_->FilesSelectedInChooser(entry->results_);
|
| + else
|
| + entry->rvh_->DirectoryEnumerationFinished(id, entry->results_);
|
| }
|
|
|
| SelectFileDialog::FileTypeInfo* FileSelectHelper::GetFileTypesFromAcceptType(
|
| @@ -239,6 +271,13 @@
|
| NULL);
|
| }
|
|
|
| +void FileSelectHelper::EnumerateDirectory(int request_id,
|
| + RenderViewHost* render_view_host,
|
| + const FilePath& path) {
|
| + DCHECK_NE(kFileSelectEnumerationId, request_id);
|
| + StartNewEnumeration(path, request_id, render_view_host);
|
| +}
|
| +
|
| void FileSelectHelper::Observe(NotificationType type,
|
| const NotificationSource& source,
|
| const NotificationDetails& details) {
|
| @@ -258,6 +297,7 @@
|
| bool handled = true;
|
| IPC_BEGIN_MESSAGE_MAP(FileSelectObserver, message)
|
| IPC_MESSAGE_HANDLER(ViewHostMsg_RunFileChooser, OnRunFileChooser)
|
| + IPC_MESSAGE_HANDLER(ViewHostMsg_EnumerateDirectory, OnEnumerateDirectory)
|
| IPC_MESSAGE_UNHANDLED(handled = false)
|
| IPC_END_MESSAGE_MAP()
|
|
|
| @@ -271,3 +311,20 @@
|
| file_select_helper_->RunFileChooser(tab_contents()->render_view_host(),
|
| params);
|
| }
|
| +
|
| +void FileSelectObserver::OnEnumerateDirectory(int request_id,
|
| + const FilePath& path) {
|
| + ChildProcessSecurityPolicy* policy =
|
| + ChildProcessSecurityPolicy::GetInstance();
|
| + if (!policy->CanReadDirectory(
|
| + tab_contents()->render_view_host()->process()->id(),
|
| + path)) {
|
| + return;
|
| + }
|
| +
|
| + if (!file_select_helper_.get())
|
| + file_select_helper_.reset(new FileSelectHelper(tab_contents()->profile()));
|
| + file_select_helper_->EnumerateDirectory(request_id,
|
| + tab_contents()->render_view_host(),
|
| + path);
|
| +}
|
|
|