Index: chrome/browser/renderer_host/file_utilities_dispatcher_host.cc |
diff --git a/chrome/browser/renderer_host/file_utilities_dispatcher_host.cc b/chrome/browser/renderer_host/file_utilities_dispatcher_host.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..ffbbc19f2e2243fce84c1b02e6c314dca8c922f1 |
--- /dev/null |
+++ b/chrome/browser/renderer_host/file_utilities_dispatcher_host.cc |
@@ -0,0 +1,201 @@ |
+// Copyright (c) 2010 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "chrome/browser/renderer_host/file_utilities_dispatcher_host.h" |
+ |
+#include "base/file_util.h" |
+#include "base/platform_file.h" |
+#include "chrome/browser/child_process_security_policy.h" |
+#include "chrome/browser/browser_thread.h" |
+#include "chrome/common/render_messages.h" |
+#include "chrome/common/render_messages_params.h" |
+ |
+namespace { |
+ |
+void WriteFileSize(IPC::Message* reply_msg, |
+ const base::PlatformFileInfo& file_info) { |
+ ViewHostMsg_GetFileSize::WriteReplyParams(reply_msg, file_info.size); |
+} |
+ |
+void WriteFileModificationTime(IPC::Message* reply_msg, |
+ const base::PlatformFileInfo& file_info) { |
+ ViewHostMsg_GetFileModificationTime::WriteReplyParams( |
+ reply_msg, file_info.last_modified); |
+} |
+ |
+} // namespace |
+ |
+FileUtilitiesDispatcherHost::FileUtilitiesDispatcherHost( |
+ IPC::Message::Sender* sender, int process_id) |
+ : message_sender_(sender), |
+ process_id_(process_id), |
+ process_handle_(0), |
+ shutdown_(false) { |
+ DCHECK(message_sender_); |
+} |
+ |
+FileUtilitiesDispatcherHost::~FileUtilitiesDispatcherHost() { |
+} |
+ |
+void FileUtilitiesDispatcherHost::Init(base::ProcessHandle process_handle) { |
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
+ DCHECK(!shutdown_); |
+ DCHECK(!process_handle_); |
+ DCHECK(process_handle); |
+ process_handle_ = process_handle; |
+} |
+ |
+void FileUtilitiesDispatcherHost::Shutdown() { |
+ message_sender_ = NULL; |
+ shutdown_ = true; |
+} |
+ |
+bool FileUtilitiesDispatcherHost::OnMessageReceived( |
+ const IPC::Message& message, bool* message_was_ok) { |
+ DCHECK(!shutdown_); |
+ *message_was_ok = true; |
+ bool handled = true; |
+ IPC_BEGIN_MESSAGE_MAP_EX(FileUtilitiesDispatcherHost, |
+ message, *message_was_ok) |
+ IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_GetFileSize, OnGetFileSize) |
+ IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_GetFileModificationTime, |
+ OnGetFileModificationTime) |
+ IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_OpenFile, OnOpenFile) |
+ IPC_MESSAGE_UNHANDLED((handled = false, msg_is_ok__ = true)) |
+ IPC_END_MESSAGE_MAP_EX() |
+ return handled; |
+} |
+ |
+void FileUtilitiesDispatcherHost::OnGetFileSize( |
+ const FilePath& path, IPC::Message* reply_msg) { |
+ // Get file size only when the child process has been granted permission to |
+ // upload the file. |
+ if (!ChildProcessSecurityPolicy::GetInstance()->CanReadFile( |
+ process_id_, path)) { |
+ ViewHostMsg_GetFileSize::WriteReplyParams( |
+ reply_msg, static_cast<int64>(-1)); |
+ Send(reply_msg); |
+ return; |
+ } |
+ |
+ // Getting file size could take long time if it lives on a network share, |
+ // so run it on FILE thread. |
+ BrowserThread::PostTask( |
+ BrowserThread::FILE, FROM_HERE, |
+ NewRunnableMethod( |
+ this, &FileUtilitiesDispatcherHost::OnGetFileInfoOnFileThread, path, |
+ reply_msg, &WriteFileSize)); |
+} |
+ |
+void FileUtilitiesDispatcherHost::OnGetFileModificationTime( |
+ const FilePath& path, IPC::Message* reply_msg) { |
+ // Get file modification time only when the child process has been granted |
+ // permission to upload the file. |
+ if (!ChildProcessSecurityPolicy::GetInstance()->CanReadFile( |
+ process_id_, path)) { |
+ ViewHostMsg_GetFileModificationTime::WriteReplyParams(reply_msg, |
+ base::Time()); |
+ Send(reply_msg); |
+ return; |
+ } |
+ |
+ // Getting file modification time could take a long time if it lives on a |
+ // network share, so run it on the FILE thread. |
+ BrowserThread::PostTask( |
+ BrowserThread::FILE, FROM_HERE, |
+ NewRunnableMethod( |
+ this, &FileUtilitiesDispatcherHost::OnGetFileInfoOnFileThread, |
+ path, reply_msg, &WriteFileModificationTime)); |
+} |
+ |
+void FileUtilitiesDispatcherHost::OnGetFileInfoOnFileThread( |
+ const FilePath& path, |
+ IPC::Message* reply_msg, |
+ FileInfoWriteFunc write_func) { |
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
+ |
+ base::PlatformFileInfo file_info; |
+ file_info.size = 0; |
+ file_util::GetFileInfo(path, &file_info); |
+ |
+ (*write_func)(reply_msg, file_info); |
+ |
+ BrowserThread::PostTask( |
+ BrowserThread::IO, FROM_HERE, |
+ NewRunnableMethod(this, &FileUtilitiesDispatcherHost::Send, reply_msg)); |
+} |
+ |
+void FileUtilitiesDispatcherHost::OnOpenFile( |
+ const FilePath& path, int mode, IPC::Message* reply_msg) { |
+ // Open the file only when the child process has been granted permission to |
+ // upload the file. |
+ // TODO(jianli): Do we need separate permission to control opening the file? |
+ if (!ChildProcessSecurityPolicy::GetInstance()->CanReadFile( |
+ process_id_, path)) { |
+ ViewHostMsg_OpenFile::WriteReplyParams( |
+ reply_msg, |
+#if defined(OS_WIN) |
+ base::kInvalidPlatformFileValue |
+#elif defined(OS_POSIX) |
+ base::FileDescriptor(base::kInvalidPlatformFileValue, true) |
+#endif |
+ ); |
+ Send(reply_msg); |
+ return; |
+ } |
+ |
+ // Opening the file could take a long time if it lives on a network share, |
+ // so run it on the FILE thread. |
+ BrowserThread::PostTask( |
+ BrowserThread::FILE, FROM_HERE, |
+ NewRunnableMethod( |
+ this, &FileUtilitiesDispatcherHost::OnOpenFileOnFileThread, |
+ path, mode, reply_msg)); |
+} |
+ |
+void FileUtilitiesDispatcherHost::OnOpenFileOnFileThread( |
+ const FilePath& path, int mode, IPC::Message* reply_msg) { |
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
+ |
+ base::PlatformFile file_handle = base::CreatePlatformFile( |
+ path, |
+ (mode == 0) ? (base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ) |
+ : (base::PLATFORM_FILE_CREATE_ALWAYS | |
+ base::PLATFORM_FILE_WRITE), |
+ NULL, NULL); |
+ |
+ base::PlatformFile target_file_handle; |
+#if defined(OS_WIN) |
+ // Duplicate the file handle so that the renderer process can access the file. |
+ if (!DuplicateHandle(GetCurrentProcess(), file_handle, |
+ process_handle_, &target_file_handle, 0, false, |
+ DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) { |
+ // file_handle is closed whether or not DuplicateHandle succeeds. |
+ target_file_handle = INVALID_HANDLE_VALUE; |
+ } |
+#else |
+ target_file_handle = file_handle; |
+#endif |
+ |
+ ViewHostMsg_OpenFile::WriteReplyParams( |
+ reply_msg, |
+#if defined(OS_WIN) |
+ target_file_handle |
+#elif defined(OS_POSIX) |
+ base::FileDescriptor(target_file_handle, true) |
+#endif |
+ ); |
+ |
+ BrowserThread::PostTask( |
+ BrowserThread::IO, FROM_HERE, |
+ NewRunnableMethod(this, &FileUtilitiesDispatcherHost::Send, reply_msg)); |
+} |
+ |
+void FileUtilitiesDispatcherHost::Send(IPC::Message* message) { |
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
+ if (!shutdown_ && message_sender_) |
+ message_sender_->Send(message); |
+ else |
+ delete message; |
+} |