Chromium Code Reviews| Index: content/renderer/render_frame_impl.cc |
| diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc |
| index 13392d1784ee20bce387f8fdb3496debf9589912..8d285ccff6154a90b01f12d287e2f1d7e3a8578e 100644 |
| --- a/content/renderer/render_frame_impl.cc |
| +++ b/content/renderer/render_frame_impl.cc |
| @@ -69,6 +69,8 @@ |
| #include "content/public/common/content_features.h" |
| #include "content/public/common/content_switches.h" |
| #include "content/public/common/context_menu_params.h" |
| +#include "content/public/common/file_chooser_file_info.h" |
| +#include "content/public/common/file_chooser_params.h" |
| #include "content/public/common/isolated_world_ids.h" |
| #include "content/public/common/page_state.h" |
| #include "content/public/common/resource_response.h" |
| @@ -151,6 +153,7 @@ |
| #include "net/base/registry_controlled_domains/registry_controlled_domain.h" |
| #include "net/http/http_util.h" |
| #include "storage/common/data_element.h" |
| +#include "third_party/WebKit/public/platform/FilePathConversion.h" |
| #include "third_party/WebKit/public/platform/URLConversion.h" |
| #include "third_party/WebKit/public/platform/WebCachePolicy.h" |
| #include "third_party/WebKit/public/platform/WebData.h" |
| @@ -851,6 +854,14 @@ bool UseMojoCdm() { |
| } // namespace |
| +struct RenderFrameImpl::PendingFileChooser { |
| + PendingFileChooser(const FileChooserParams& p, |
| + blink::WebFileChooserCompletion* c) |
| + : params(p), completion(c) {} |
| + FileChooserParams params; |
| + blink::WebFileChooserCompletion* completion; // MAY BE NULL to skip callback. |
| +}; |
| + |
| // static |
| RenderFrameImpl* RenderFrameImpl::Create(RenderViewImpl* render_view, |
| int32_t routing_id) { |
| @@ -1114,6 +1125,15 @@ RenderFrameImpl::RenderFrameImpl(const CreateParams& params) |
| } |
| RenderFrameImpl::~RenderFrameImpl() { |
| + // If file chooser is still waiting for answer, dispatch empty answer. |
| + while (!file_chooser_completions_.empty()) { |
| + if (file_chooser_completions_.front()->completion) { |
| + file_chooser_completions_.front()->completion->didChooseFile( |
| + WebVector<WebString>()); |
| + } |
| + file_chooser_completions_.pop_front(); |
| + } |
| + |
| FOR_EACH_OBSERVER(RenderFrameObserver, observers_, RenderFrameGone()); |
| FOR_EACH_OBSERVER(RenderFrameObserver, observers_, OnDestruct()); |
| @@ -1505,6 +1525,7 @@ bool RenderFrameImpl::OnMessageReceived(const IPC::Message& msg) { |
| IPC_MESSAGE_HANDLER(FrameMsg_EnableViewSourceMode, OnEnableViewSourceMode) |
| IPC_MESSAGE_HANDLER(FrameMsg_SuppressFurtherDialogs, |
| OnSuppressFurtherDialogs) |
| + IPC_MESSAGE_HANDLER(FrameMsg_RunFileChooserResponse, OnFileChooserResponse) |
| #if defined(OS_ANDROID) |
| IPC_MESSAGE_HANDLER(FrameMsg_ActivateNearestFindResult, |
| OnActivateNearestFindResult) |
| @@ -2218,6 +2239,31 @@ bool RenderFrameImpl::RunJavaScriptMessage(JavaScriptMessageType type, |
| return success; |
| } |
| +bool RenderFrameImpl::ScheduleFileChooser( |
| + const FileChooserParams& params, |
| + blink::WebFileChooserCompletion* completion) { |
| + static const size_t kMaximumPendingFileChooseRequests = 4; |
| + if (file_chooser_completions_.size() > kMaximumPendingFileChooseRequests) { |
| + // This sanity check prevents too many file choose requests from getting |
| + // queued which could DoS the user. Getting these is most likely a |
| + // programming error (there are many ways to DoS the user so it's not |
| + // considered a "real" security check), either in JS requesting many file |
| + // choosers to pop up, or in a plugin. |
| + // |
| + // TODO(brettw) we might possibly want to require a user gesture to open |
|
Avi (use Gerrit)
2016/06/10 21:52:54
TODO(brettw): We ...
nasko
2016/06/10 22:07:50
Done.
|
| + // a file picker, which will address this issue in a better way. |
| + return false; |
| + } |
| + |
| + file_chooser_completions_.push_back( |
| + base::WrapUnique(new PendingFileChooser(params, completion))); |
| + if (file_chooser_completions_.size() == 1) { |
| + // Actually show the browse dialog when this is the first request. |
| + Send(new FrameHostMsg_RunFileChooser(routing_id_, params)); |
| + } |
| + return true; |
| +} |
| + |
| void RenderFrameImpl::LoadNavigationErrorPage( |
| const WebURLRequest& failed_request, |
| const WebURLError& error, |
| @@ -3744,6 +3790,37 @@ bool RenderFrameImpl::runModalBeforeUnloadDialog(bool is_reload) { |
| return success; |
| } |
| +bool RenderFrameImpl::runFileChooser( |
| + const blink::WebFileChooserParams& params, |
| + blink::WebFileChooserCompletion* chooser_completion) { |
| + // Do not open the file dialog in a hidden RenderView. |
| + if (render_view_->is_hidden()) |
| + return false; |
| + |
| + FileChooserParams ipc_params; |
| + if (params.directory) |
| + ipc_params.mode = FileChooserParams::UploadFolder; |
| + else if (params.multiSelect) |
| + ipc_params.mode = FileChooserParams::OpenMultiple; |
| + else if (params.saveAs) |
| + ipc_params.mode = FileChooserParams::Save; |
| + else |
| + ipc_params.mode = FileChooserParams::Open; |
| + ipc_params.title = params.title; |
| + ipc_params.default_file_name = |
| + blink::WebStringToFilePath(params.initialValue).BaseName(); |
| + ipc_params.accept_types.reserve(params.acceptTypes.size()); |
| + for (size_t i = 0; i < params.acceptTypes.size(); ++i) |
|
Avi (use Gerrit)
2016/06/10 21:52:54
for ( : )
nasko
2016/06/10 22:07:50
Done.
|
| + ipc_params.accept_types.push_back(params.acceptTypes[i]); |
| + ipc_params.need_local_path = params.needLocalPath; |
| +#if defined(OS_ANDROID) |
| + ipc_params.capture = params.useMediaCapture; |
| +#endif |
| + ipc_params.requestor = params.requestor; |
| + |
| + return ScheduleFileChooser(ipc_params, chooser_completion); |
| +} |
| + |
| void RenderFrameImpl::showContextMenu(const blink::WebContextMenuData& data) { |
| ContextMenuParams params = ContextMenuParamsBuilder::Build(data); |
| blink::WebRect position_in_window(params.x, params.y, 0, 0); |
| @@ -5129,6 +5206,43 @@ void RenderFrameImpl::OnSuppressFurtherDialogs() { |
| suppress_further_dialogs_ = true; |
| } |
| +void RenderFrameImpl::OnFileChooserResponse( |
| + const std::vector<content::FileChooserFileInfo>& files) { |
| + // This could happen if we navigated to a different page before the user |
| + // closed the chooser. |
| + if (file_chooser_completions_.empty()) |
| + return; |
| + |
| + // Convert Chrome's SelectedFileInfo list to WebKit's. |
| + WebVector<blink::WebFileChooserCompletion::SelectedFileInfo> selected_files( |
| + files.size()); |
| + for (size_t i = 0; i < files.size(); ++i) { |
|
Avi (use Gerrit)
2016/06/10 21:52:54
for ( : )
nasko
2016/06/10 22:07:49
This one uses i for the WebVector access, so I kep
|
| + blink::WebFileChooserCompletion::SelectedFileInfo selected_file; |
| + selected_file.path = files[i].file_path.AsUTF16Unsafe(); |
| + selected_file.displayName = |
| + base::FilePath(files[i].display_name).AsUTF16Unsafe(); |
| + if (files[i].file_system_url.is_valid()) { |
| + selected_file.fileSystemURL = files[i].file_system_url; |
| + selected_file.length = files[i].length; |
| + selected_file.modificationTime = files[i].modification_time.ToDoubleT(); |
| + selected_file.isDirectory = files[i].is_directory; |
| + } |
| + selected_files[i] = selected_file; |
| + } |
| + |
| + if (file_chooser_completions_.front()->completion) { |
| + file_chooser_completions_.front()->completion->didChooseFile( |
| + selected_files); |
| + } |
| + file_chooser_completions_.pop_front(); |
| + |
| + // If there are more pending file chooser requests, schedule one now. |
| + if (!file_chooser_completions_.empty()) { |
| + Send(new FrameHostMsg_RunFileChooser( |
| + routing_id_, file_chooser_completions_.front()->params)); |
| + } |
| +} |
| + |
| #if defined(OS_ANDROID) |
| void RenderFrameImpl::OnActivateNearestFindResult(int request_id, |
| float x, |