diff options
author | johnnyg@chromium.org <johnnyg@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-04-12 00:01:51 +0000 |
---|---|---|
committer | johnnyg@chromium.org <johnnyg@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-04-12 00:01:51 +0000 |
commit | 600ea40f950f2c2a177428986b9a2d557e7a8c90 (patch) | |
tree | e1d602a1e424758b8c18aee583e4dbbef75427da /content | |
parent | 491af0cde7544b0f973296782dbb1daccbc3d603 (diff) | |
download | chromium_src-600ea40f950f2c2a177428986b9a2d557e7a8c90.zip chromium_src-600ea40f950f2c2a177428986b9a2d557e7a8c90.tar.gz chromium_src-600ea40f950f2c2a177428986b9a2d557e7a8c90.tar.bz2 |
Add a path for a web page to request the enumeration of a directory. This, together with a WebKit change, will allow a drag-and-drop on a Directory Upload control (<input type=file webkitdirectory>) which provides only the path to the renderer, to correctly populate the control as if the user had selected that directory in a file picker.
BUG=58977
TEST=drag-and-drop on directory upload control (with upstream change)
Review URL: http://codereview.chromium.org/6623015
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@81183 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'content')
-rw-r--r-- | content/browser/child_process_security_policy.cc | 16 | ||||
-rw-r--r-- | content/browser/child_process_security_policy.h | 8 | ||||
-rw-r--r-- | content/browser/child_process_security_policy_unittest.cc | 32 | ||||
-rw-r--r-- | content/browser/renderer_host/render_view_host.cc | 18 | ||||
-rw-r--r-- | content/browser/renderer_host/render_view_host.h | 4 | ||||
-rw-r--r-- | content/common/view_messages.h | 13 | ||||
-rw-r--r-- | content/renderer/render_view.cc | 27 | ||||
-rw-r--r-- | content/renderer/render_view.h | 8 |
8 files changed, 126 insertions, 0 deletions
diff --git a/content/browser/child_process_security_policy.cc b/content/browser/child_process_security_policy.cc index 33cf5e0..81eca77 100644 --- a/content/browser/child_process_security_policy.cc +++ b/content/browser/child_process_security_policy.cc @@ -20,6 +20,10 @@ static const int kReadFilePermissions = base::PLATFORM_FILE_EXCLUSIVE_READ | base::PLATFORM_FILE_ASYNC; +static const int kEnumerateDirectoryPermissions = + kReadFilePermissions | + base::PLATFORM_FILE_ENUMERATE; + // The SecurityState class is used to maintain per-child process security state // information. class ChildProcessSecurityPolicy::SecurityState { @@ -241,6 +245,11 @@ void ChildProcessSecurityPolicy::GrantReadFile(int child_id, GrantPermissionsForFile(child_id, file, kReadFilePermissions); } +void ChildProcessSecurityPolicy::GrantReadDirectory(int child_id, + const FilePath& directory) { + GrantPermissionsForFile(child_id, directory, kEnumerateDirectoryPermissions); +} + void ChildProcessSecurityPolicy::GrantPermissionsForFile( int child_id, const FilePath& file, int permissions) { base::AutoLock lock(lock_); @@ -372,6 +381,13 @@ bool ChildProcessSecurityPolicy::CanReadFile(int child_id, return HasPermissionsForFile(child_id, file, kReadFilePermissions); } +bool ChildProcessSecurityPolicy::CanReadDirectory(int child_id, + const FilePath& directory) { + return HasPermissionsForFile(child_id, + directory, + kEnumerateDirectoryPermissions); +} + bool ChildProcessSecurityPolicy::HasPermissionsForFile( int child_id, const FilePath& file, int permissions) { base::AutoLock lock(lock_); diff --git a/content/browser/child_process_security_policy.h b/content/browser/child_process_security_policy.h index aa53e9d..ec540f1 100644 --- a/content/browser/child_process_security_policy.h +++ b/content/browser/child_process_security_policy.h @@ -71,6 +71,10 @@ class ChildProcessSecurityPolicy { // to upload the file to the web. void GrantReadFile(int child_id, const FilePath& file); + // Grants the child process permission to enumerate all the files in + // this directory and read those files. + void GrantReadDirectory(int child_id, const FilePath& directory); + // Grants certain permissions to a file. |permissions| must be a bit-set of // base::PlatformFileFlags. void GrantPermissionsForFile(int child_id, @@ -106,6 +110,10 @@ class ChildProcessSecurityPolicy { // capability to upload the requested file. bool CanReadFile(int child_id, const FilePath& file); + // Before servicing a child process's request to enumerate a directory + // the browser should call this method to check for the capability. + bool CanReadDirectory(int child_id, const FilePath& directory); + // Determines if certain permissions were granted for a file. |permissions| // must be a bit-set of base::PlatformFileFlags. bool HasPermissionsForFile(int child_id, diff --git a/content/browser/child_process_security_policy_unittest.cc b/content/browser/child_process_security_policy_unittest.cc index 8ad4ad4..e20178e 100644 --- a/content/browser/child_process_security_policy_unittest.cc +++ b/content/browser/child_process_security_policy_unittest.cc @@ -215,6 +215,38 @@ TEST_F(ChildProcessSecurityPolicyTest, CanReadFiles) { p->Remove(kRendererID); } +TEST_F(ChildProcessSecurityPolicyTest, CanReadDirectories) { + ChildProcessSecurityPolicy* p = ChildProcessSecurityPolicy::GetInstance(); + + p->Add(kRendererID); + + EXPECT_FALSE(p->CanReadDirectory(kRendererID, + FilePath(FILE_PATH_LITERAL("/etc/")))); + p->GrantReadDirectory(kRendererID, FilePath(FILE_PATH_LITERAL("/etc/"))); + EXPECT_TRUE(p->CanReadDirectory(kRendererID, + FilePath(FILE_PATH_LITERAL("/etc/")))); + EXPECT_TRUE(p->CanReadFile(kRendererID, + FilePath(FILE_PATH_LITERAL("/etc/passwd")))); + + p->Remove(kRendererID); + p->Add(kRendererID); + + EXPECT_FALSE(p->CanReadDirectory(kRendererID, + FilePath(FILE_PATH_LITERAL("/etc/")))); + EXPECT_FALSE(p->CanReadFile(kRendererID, + FilePath(FILE_PATH_LITERAL("/etc/passwd")))); + + // Just granting read permission as a file doesn't imply reading as a + // directory. + p->GrantReadFile(kRendererID, FilePath(FILE_PATH_LITERAL("/etc/"))); + EXPECT_TRUE(p->CanReadFile(kRendererID, + FilePath(FILE_PATH_LITERAL("/etc/passwd")))); + EXPECT_FALSE(p->CanReadDirectory(kRendererID, + FilePath(FILE_PATH_LITERAL("/etc/")))); + + p->Remove(kRendererID); +} + TEST_F(ChildProcessSecurityPolicyTest, FilePermissions) { ChildProcessSecurityPolicy* p = ChildProcessSecurityPolicy::GetInstance(); diff --git a/content/browser/renderer_host/render_view_host.cc b/content/browser/renderer_host/render_view_host.cc index 1f35dc3..b9e1f52 100644 --- a/content/browser/renderer_host/render_view_host.cc +++ b/content/browser/renderer_host/render_view_host.cc @@ -465,6 +465,10 @@ void RenderViewHost::DragTargetDragEnter( policy->GrantRequestURL(process()->id(), net::FilePathToFileURL(path)); policy->GrantReadFile(process()->id(), path); + + // Allow dragged directories to be enumerated by the child process. + // Note that we can't tell a file from a directory at this point. + policy->GrantReadDirectory(process()->id(), path); } Send(new DragMsg_TargetDragEnter(routing_id(), drop_data, client_pt, screen_pt, operations_allowed)); @@ -683,6 +687,20 @@ void RenderViewHost::FilesSelectedInChooser( Send(new ViewMsg_RunFileChooserResponse(routing_id(), files)); } +void RenderViewHost::DirectoryEnumerationFinished( + int request_id, + const std::vector<FilePath>& files) { + // Grant the security access requested to the given files. + for (std::vector<FilePath>::const_iterator file = files.begin(); + file != files.end(); ++file) { + ChildProcessSecurityPolicy::GetInstance()->GrantReadFile( + process()->id(), *file); + } + Send(new ViewMsg_EnumerateDirectoryResponse(routing_id(), + request_id, + files)); +} + void RenderViewHost::LoadStateChanged(const GURL& url, net::LoadState load_state, uint64 upload_position, diff --git a/content/browser/renderer_host/render_view_host.h b/content/browser/renderer_host/render_view_host.h index 72920cb..75846ab 100644 --- a/content/browser/renderer_host/render_view_host.h +++ b/content/browser/renderer_host/render_view_host.h @@ -385,6 +385,10 @@ class RenderViewHost : public RenderWidgetHost { // from an Open File dialog for the form. void FilesSelectedInChooser(const std::vector<FilePath>& files); + // Notifies the listener that a directory enumeration is complete. + void DirectoryEnumerationFinished(int request_id, + const std::vector<FilePath>& files); + // Notifies the RenderViewHost that its load state changed. void LoadStateChanged(const GURL& url, net::LoadState load_state, uint64 upload_position, uint64 upload_size); diff --git a/content/common/view_messages.h b/content/common/view_messages.h index 3abb27d..ae921bd 100644 --- a/content/common/view_messages.h +++ b/content/common/view_messages.h @@ -1030,6 +1030,11 @@ IPC_MESSAGE_ROUTED1(ViewMsg_SetAltErrorPageURL, IPC_MESSAGE_ROUTED1(ViewMsg_RunFileChooserResponse, std::vector<FilePath> /* selected files */) +// Provides the results of directory enumeration. +IPC_MESSAGE_ROUTED2(ViewMsg_EnumerateDirectoryResponse, + int /* request_id */, + std::vector<FilePath> /* files_in_directory */) + // When a renderer sends a ViewHostMsg_Focus to the browser process, // the browser has the option of sending a ViewMsg_CantFocus back to // the renderer. @@ -1642,6 +1647,14 @@ IPC_MESSAGE_ROUTED1(ViewHostMsg_SelectionChanged, IPC_MESSAGE_ROUTED1(ViewHostMsg_RunFileChooser, ViewHostMsg_RunFileChooser_Params) +// Asks the browser to enumerate a directory. This is equivalent to running +// the file chooser in directory-enumeration mode and having the user select +// the given directory. The result is returned in a +// ViewMsg_EnumerateDirectoryResponse message. +IPC_MESSAGE_ROUTED2(ViewHostMsg_EnumerateDirectory, + int /* request_id */, + FilePath /* file_path */) + // Tells the browser to move the focus to the next (previous if reverse is // true) focusable element. IPC_MESSAGE_ROUTED1(ViewHostMsg_TakeFocus, diff --git a/content/renderer/render_view.cc b/content/renderer/render_view.cc index 6052063..c916155 100644 --- a/content/renderer/render_view.cc +++ b/content/renderer/render_view.cc @@ -935,6 +935,8 @@ bool RenderView::OnMessageReceived(const IPC::Message& message) { IPC_MESSAGE_HANDLER(ViewMsg_InstallMissingPlugin, OnInstallMissingPlugin) IPC_MESSAGE_HANDLER(ViewMsg_DisplayPrerenderedPage, OnDisplayPrerenderedPage) + IPC_MESSAGE_HANDLER(ViewMsg_EnumerateDirectoryResponse, + OnEnumerateDirectoryResponse) IPC_MESSAGE_HANDLER(ViewMsg_RunFileChooserResponse, OnFileChooserResponse) IPC_MESSAGE_HANDLER(ViewMsg_EnableViewSourceMode, OnEnableViewSourceMode) IPC_MESSAGE_HANDLER(ViewMsg_GetAllSavableResourceLinksForCurrentPage, @@ -2159,6 +2161,17 @@ bool RenderView::runFileChooser( return ScheduleFileChooser(ipc_params, chooser_completion); } +bool RenderView::enumerateDirectory( + const WebString& path, + WebFileChooserCompletion* chooser_completion) { + int id = enumeration_completion_id_++; + enumeration_completions_[id] = chooser_completion; + return Send(new ViewHostMsg_EnumerateDirectory( + routing_id_, + id, + webkit_glue::WebStringToFilePath(path))); +} + void RenderView::runModalAlertDialog( WebFrame* frame, const WebString& message) { RunJavaScriptMessage(ui::MessageBoxFlags::kIsJavascriptAlert, @@ -4237,6 +4250,20 @@ void RenderView::OnDisplayPrerenderedPage() { } } +void RenderView::OnEnumerateDirectoryResponse( + int id, + const std::vector<FilePath>& paths) { + if (!enumeration_completions_[id]) + return; + + WebVector<WebString> ws_file_names(paths.size()); + for (size_t i = 0; i < paths.size(); ++i) + ws_file_names[i] = webkit_glue::FilePathToWebString(paths[i]); + + enumeration_completions_[id]->didChooseFile(ws_file_names); + enumeration_completions_.erase(id); +} + void RenderView::OnFileChooserResponse(const std::vector<FilePath>& paths) { // This could happen if we navigated to a different page before the user // closed the chooser. diff --git a/content/renderer/render_view.h b/content/renderer/render_view.h index 347d761..6542966 100644 --- a/content/renderer/render_view.h +++ b/content/renderer/render_view.h @@ -391,6 +391,9 @@ class RenderView : public RenderWidget, virtual bool runFileChooser( const WebKit::WebFileChooserParams& params, WebKit::WebFileChooserCompletion* chooser_completion); + virtual bool enumerateDirectory( + const WebKit::WebString& path, + WebKit::WebFileChooserCompletion* chooser_completion); virtual void runModalAlertDialog(WebKit::WebFrame* frame, const WebKit::WebString& message); virtual bool runModalConfirmDialog(WebKit::WebFrame* frame, @@ -804,6 +807,7 @@ class RenderView : public RenderWidget, WebKit::WebDragOperationsMask operations_allowed); void OnEnablePreferredSizeChangedMode(int flags); void OnEnableViewSourceMode(); + void OnEnumerateDirectoryResponse(int id, const std::vector<FilePath>& paths); void OnExecuteEditCommand(const std::string& name, const std::string& value); void OnFileChooserResponse(const std::vector<FilePath>& paths); void OnFind(int request_id, const string16&, const WebKit::WebFindOptions&); @@ -1259,6 +1263,10 @@ class RenderView : public RenderWidget, struct PendingFileChooser; std::deque< linked_ptr<PendingFileChooser> > file_chooser_completions_; + // The current directory enumeration callback + std::map<int, WebKit::WebFileChooserCompletion*> enumeration_completions_; + int enumeration_completion_id_; + // ImageResourceFetchers schedule via DownloadImage. ImageResourceFetcherList image_fetchers_; |