OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "chrome/browser/renderer_host/file_utilities_dispatcher_host.h" |
| 6 |
| 7 #include "base/file_util.h" |
| 8 #include "base/platform_file.h" |
| 9 #include "chrome/browser/child_process_security_policy.h" |
| 10 #include "chrome/browser/browser_thread.h" |
| 11 #include "chrome/common/render_messages.h" |
| 12 #include "chrome/common/render_messages_params.h" |
| 13 |
| 14 namespace { |
| 15 |
| 16 void WriteFileSize(IPC::Message* reply_msg, |
| 17 const base::PlatformFileInfo& file_info) { |
| 18 ViewHostMsg_GetFileSize::WriteReplyParams(reply_msg, file_info.size); |
| 19 } |
| 20 |
| 21 void WriteFileModificationTime(IPC::Message* reply_msg, |
| 22 const base::PlatformFileInfo& file_info) { |
| 23 ViewHostMsg_GetFileModificationTime::WriteReplyParams( |
| 24 reply_msg, file_info.last_modified); |
| 25 } |
| 26 |
| 27 } // namespace |
| 28 |
| 29 FileUtilitiesDispatcherHost::FileUtilitiesDispatcherHost( |
| 30 IPC::Message::Sender* sender, int process_id) |
| 31 : message_sender_(sender), |
| 32 process_id_(process_id), |
| 33 process_handle_(0), |
| 34 shutdown_(false) { |
| 35 DCHECK(message_sender_); |
| 36 } |
| 37 |
| 38 FileUtilitiesDispatcherHost::~FileUtilitiesDispatcherHost() { |
| 39 } |
| 40 |
| 41 void FileUtilitiesDispatcherHost::Init(base::ProcessHandle process_handle) { |
| 42 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 43 DCHECK(!shutdown_); |
| 44 DCHECK(!process_handle_); |
| 45 DCHECK(process_handle); |
| 46 process_handle_ = process_handle; |
| 47 } |
| 48 |
| 49 void FileUtilitiesDispatcherHost::Shutdown() { |
| 50 message_sender_ = NULL; |
| 51 shutdown_ = true; |
| 52 } |
| 53 |
| 54 bool FileUtilitiesDispatcherHost::OnMessageReceived( |
| 55 const IPC::Message& message, bool* message_was_ok) { |
| 56 DCHECK(!shutdown_); |
| 57 *message_was_ok = true; |
| 58 bool handled = true; |
| 59 IPC_BEGIN_MESSAGE_MAP_EX(FileUtilitiesDispatcherHost, |
| 60 message, *message_was_ok) |
| 61 IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_GetFileSize, OnGetFileSize) |
| 62 IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_GetFileModificationTime, |
| 63 OnGetFileModificationTime) |
| 64 IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_OpenFile, OnOpenFile) |
| 65 IPC_MESSAGE_UNHANDLED((handled = false, msg_is_ok__ = true)) |
| 66 IPC_END_MESSAGE_MAP_EX() |
| 67 return handled; |
| 68 } |
| 69 |
| 70 void FileUtilitiesDispatcherHost::OnGetFileSize( |
| 71 const FilePath& path, IPC::Message* reply_msg) { |
| 72 // Get file size only when the child process has been granted permission to |
| 73 // upload the file. |
| 74 if (!ChildProcessSecurityPolicy::GetInstance()->CanReadFile( |
| 75 process_id_, path)) { |
| 76 ViewHostMsg_GetFileSize::WriteReplyParams( |
| 77 reply_msg, static_cast<int64>(-1)); |
| 78 Send(reply_msg); |
| 79 return; |
| 80 } |
| 81 |
| 82 // Getting file size could take long time if it lives on a network share, |
| 83 // so run it on FILE thread. |
| 84 BrowserThread::PostTask( |
| 85 BrowserThread::FILE, FROM_HERE, |
| 86 NewRunnableMethod( |
| 87 this, &FileUtilitiesDispatcherHost::OnGetFileInfoOnFileThread, path, |
| 88 reply_msg, &WriteFileSize)); |
| 89 } |
| 90 |
| 91 void FileUtilitiesDispatcherHost::OnGetFileModificationTime( |
| 92 const FilePath& path, IPC::Message* reply_msg) { |
| 93 // Get file modification time only when the child process has been granted |
| 94 // permission to upload the file. |
| 95 if (!ChildProcessSecurityPolicy::GetInstance()->CanReadFile( |
| 96 process_id_, path)) { |
| 97 ViewHostMsg_GetFileModificationTime::WriteReplyParams(reply_msg, |
| 98 base::Time()); |
| 99 Send(reply_msg); |
| 100 return; |
| 101 } |
| 102 |
| 103 // Getting file modification time could take a long time if it lives on a |
| 104 // network share, so run it on the FILE thread. |
| 105 BrowserThread::PostTask( |
| 106 BrowserThread::FILE, FROM_HERE, |
| 107 NewRunnableMethod( |
| 108 this, &FileUtilitiesDispatcherHost::OnGetFileInfoOnFileThread, |
| 109 path, reply_msg, &WriteFileModificationTime)); |
| 110 } |
| 111 |
| 112 void FileUtilitiesDispatcherHost::OnGetFileInfoOnFileThread( |
| 113 const FilePath& path, |
| 114 IPC::Message* reply_msg, |
| 115 FileInfoWriteFunc write_func) { |
| 116 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
| 117 |
| 118 base::PlatformFileInfo file_info; |
| 119 file_info.size = 0; |
| 120 file_util::GetFileInfo(path, &file_info); |
| 121 |
| 122 (*write_func)(reply_msg, file_info); |
| 123 |
| 124 BrowserThread::PostTask( |
| 125 BrowserThread::IO, FROM_HERE, |
| 126 NewRunnableMethod(this, &FileUtilitiesDispatcherHost::Send, reply_msg)); |
| 127 } |
| 128 |
| 129 void FileUtilitiesDispatcherHost::OnOpenFile( |
| 130 const FilePath& path, int mode, IPC::Message* reply_msg) { |
| 131 // Open the file only when the child process has been granted permission to |
| 132 // upload the file. |
| 133 // TODO(jianli): Do we need separate permission to control opening the file? |
| 134 if (!ChildProcessSecurityPolicy::GetInstance()->CanReadFile( |
| 135 process_id_, path)) { |
| 136 ViewHostMsg_OpenFile::WriteReplyParams( |
| 137 reply_msg, |
| 138 #if defined(OS_WIN) |
| 139 base::kInvalidPlatformFileValue |
| 140 #elif defined(OS_POSIX) |
| 141 base::FileDescriptor(base::kInvalidPlatformFileValue, true) |
| 142 #endif |
| 143 ); |
| 144 Send(reply_msg); |
| 145 return; |
| 146 } |
| 147 |
| 148 // Opening the file could take a long time if it lives on a network share, |
| 149 // so run it on the FILE thread. |
| 150 BrowserThread::PostTask( |
| 151 BrowserThread::FILE, FROM_HERE, |
| 152 NewRunnableMethod( |
| 153 this, &FileUtilitiesDispatcherHost::OnOpenFileOnFileThread, |
| 154 path, mode, reply_msg)); |
| 155 } |
| 156 |
| 157 void FileUtilitiesDispatcherHost::OnOpenFileOnFileThread( |
| 158 const FilePath& path, int mode, IPC::Message* reply_msg) { |
| 159 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
| 160 |
| 161 base::PlatformFile file_handle = base::CreatePlatformFile( |
| 162 path, |
| 163 (mode == 0) ? (base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ) |
| 164 : (base::PLATFORM_FILE_CREATE_ALWAYS | |
| 165 base::PLATFORM_FILE_WRITE), |
| 166 NULL, NULL); |
| 167 |
| 168 base::PlatformFile target_file_handle; |
| 169 #if defined(OS_WIN) |
| 170 // Duplicate the file handle so that the renderer process can access the file. |
| 171 if (!DuplicateHandle(GetCurrentProcess(), file_handle, |
| 172 process_handle_, &target_file_handle, 0, false, |
| 173 DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) { |
| 174 // file_handle is closed whether or not DuplicateHandle succeeds. |
| 175 target_file_handle = INVALID_HANDLE_VALUE; |
| 176 } |
| 177 #else |
| 178 target_file_handle = file_handle; |
| 179 #endif |
| 180 |
| 181 ViewHostMsg_OpenFile::WriteReplyParams( |
| 182 reply_msg, |
| 183 #if defined(OS_WIN) |
| 184 target_file_handle |
| 185 #elif defined(OS_POSIX) |
| 186 base::FileDescriptor(target_file_handle, true) |
| 187 #endif |
| 188 ); |
| 189 |
| 190 BrowserThread::PostTask( |
| 191 BrowserThread::IO, FROM_HERE, |
| 192 NewRunnableMethod(this, &FileUtilitiesDispatcherHost::Send, reply_msg)); |
| 193 } |
| 194 |
| 195 void FileUtilitiesDispatcherHost::Send(IPC::Message* message) { |
| 196 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 197 if (!shutdown_ && message_sender_) |
| 198 message_sender_->Send(message); |
| 199 else |
| 200 delete message; |
| 201 } |
OLD | NEW |