diff --git a/libcef/browser/browser_host_impl.cc b/libcef/browser/browser_host_impl.cc index e72eab769..ed8852f74 100644 --- a/libcef/browser/browser_host_impl.cc +++ b/libcef/browser/browser_host_impl.cc @@ -55,6 +55,7 @@ #include "content/public/browser/render_view_host.h" #include "content/public/browser/resource_request_info.h" #include "content/public/common/file_chooser_params.h" +#include "net/base/directory_lister.h" #include "third_party/WebKit/public/web/WebFindOptions.h" #include "ui/shell_dialogs/selected_file_info.h" @@ -263,6 +264,54 @@ void RunFileDialogDismissed( callback->OnFileDialogDismissed(selected_accept_filter, paths); } +class UploadFolderHelper : + public net::DirectoryLister::DirectoryListerDelegate { + public: + explicit UploadFolderHelper( + const CefBrowserHostImpl::RunFileChooserCallback& callback) + : callback_(callback) { + } + + ~UploadFolderHelper() override { + if (!callback_.is_null()) { + if (CEF_CURRENTLY_ON_UIT()) { + CancelNow(callback_); + } else { + CEF_POST_TASK(CEF_UIT, + base::Bind(&UploadFolderHelper::CancelNow, callback_)); + } + } + } + + void OnListFile( + const net::DirectoryLister::DirectoryListerData& data) override { + CEF_REQUIRE_UIT(); + if (!data.info.IsDirectory()) + select_files_.push_back(data.path); + } + + void OnListDone(int error) override { + CEF_REQUIRE_UIT(); + if (!callback_.is_null()) { + callback_.Run(0, select_files_); + callback_.Reset(); + } + } + + private: + static void CancelNow( + const CefBrowserHostImpl::RunFileChooserCallback& callback) { + CEF_REQUIRE_UIT(); + std::vector file_paths; + callback.Run(0, file_paths); + } + + CefBrowserHostImpl::RunFileChooserCallback callback_; + std::vector select_files_; + + DISALLOW_COPY_AND_ASSIGN(UploadFolderHelper); +}; + } // namespace @@ -2316,16 +2365,23 @@ void CefBrowserHostImpl::RunFileChooser( if (!render_view_host) return; + FileChooserParams cef_params; + static_cast(cef_params) = params; + + if (lister_) { + // Cancel the previous upload folder run. + lister_->Cancel(); + lister_.reset(); + } + if (params.mode == content::FileChooserParams::UploadFolder) { - // TODO(cef): Implement the logic necessary for the 'webkitdirectory' - // attribute. See CEF issue #958. - OnRunFileChooserDelegateCallback( - web_contents, params.mode, 0, std::vector()); + RunFileChooserOnUIThread(cef_params, + base::Bind( + &CefBrowserHostImpl::OnRunFileChooserUploadFolderDelegateCallback, + this, web_contents, params.mode)); return; } - FileChooserParams cef_params; - static_cast(cef_params) = params; RunFileChooserOnUIThread(cef_params, base::Bind(&CefBrowserHostImpl::OnRunFileChooserDelegateCallback, this, web_contents, params.mode)); @@ -3035,6 +3091,30 @@ void CefBrowserHostImpl::OnRunFileChooserCallback( base::Bind(callback, selected_accept_filter, file_paths)); } +void CefBrowserHostImpl::OnRunFileChooserUploadFolderDelegateCallback( + content::WebContents* web_contents, + const content::FileChooserParams::Mode mode, + int selected_accept_filter, + const std::vector& file_paths) { + CEF_REQUIRE_UIT(); + DCHECK (mode == content::FileChooserParams::UploadFolder); + + if (file_paths.size() == 0) { + // Client canceled the file chooser. + OnRunFileChooserDelegateCallback(web_contents, mode, + selected_accept_filter, file_paths); + } else { + lister_.reset(new net::DirectoryLister( + file_paths[0], + true, + net::DirectoryLister::NO_SORT, + new UploadFolderHelper( + base::Bind(&CefBrowserHostImpl::OnRunFileChooserDelegateCallback, + this, web_contents, mode)))); + lister_->Start(); + } +} + void CefBrowserHostImpl::OnRunFileChooserDelegateCallback( content::WebContents* web_contents, content::FileChooserParams::Mode mode, @@ -3042,6 +3122,9 @@ void CefBrowserHostImpl::OnRunFileChooserDelegateCallback( const std::vector& file_paths) { CEF_REQUIRE_UIT(); + if (lister_.get()) + lister_.reset(); + content::RenderViewHost* render_view_host = web_contents->GetRenderViewHost(); if (!render_view_host) return; diff --git a/libcef/browser/browser_host_impl.h b/libcef/browser/browser_host_impl.h index 374cff8bd..fb2b6868f 100644 --- a/libcef/browser/browser_host_impl.h +++ b/libcef/browser/browser_host_impl.h @@ -50,6 +50,7 @@ class WebInputEvent; } namespace net { +class DirectoryLister; class URLRequest; } @@ -580,6 +581,14 @@ class CefBrowserHostImpl : public CefBrowserHost, int selected_accept_filter, const std::vector& file_paths); + // Used with WebContentsDelegate::RunFileChooser when mode is + // content::FileChooserParams::UploadFolder. + void OnRunFileChooserUploadFolderDelegateCallback( + content::WebContents* web_contents, + const content::FileChooserParams::Mode mode, + int selected_accept_filter, + const std::vector& file_paths); + // Used with WebContentsDelegate::RunFileChooser to notify the WebContents. void OnRunFileChooserDelegateCallback( content::WebContents* web_contents, @@ -667,6 +676,9 @@ class CefBrowserHostImpl : public CefBrowserHost, // True if a file chooser is currently pending. bool file_chooser_pending_; + // Used for asynchronously listing directory contents. + scoped_ptr lister_; + #if defined(USE_AURA) // Widget hosting the web contents. It will be deleted automatically when the // associated root window is destroyed.