summaryrefslogtreecommitdiffstats
path: root/content
diff options
context:
space:
mode:
authorjohnnyg@chromium.org <johnnyg@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-04-12 00:01:51 +0000
committerjohnnyg@chromium.org <johnnyg@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-04-12 00:01:51 +0000
commit600ea40f950f2c2a177428986b9a2d557e7a8c90 (patch)
treee1d602a1e424758b8c18aee583e4dbbef75427da /content
parent491af0cde7544b0f973296782dbb1daccbc3d603 (diff)
downloadchromium_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.cc16
-rw-r--r--content/browser/child_process_security_policy.h8
-rw-r--r--content/browser/child_process_security_policy_unittest.cc32
-rw-r--r--content/browser/renderer_host/render_view_host.cc18
-rw-r--r--content/browser/renderer_host/render_view_host.h4
-rw-r--r--content/common/view_messages.h13
-rw-r--r--content/renderer/render_view.cc27
-rw-r--r--content/renderer/render_view.h8
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_;