OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2011 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 "ppapi/proxy/ppb_file_io_proxy.h" |
| 6 |
| 7 #include "ppapi/c/pp_errors.h" |
| 8 #include "ppapi/proxy/enter_proxy.h" |
| 9 #include "ppapi/proxy/ppapi_messages.h" |
| 10 #include "ppapi/proxy/ppb_file_ref_proxy.h" |
| 11 #include "ppapi/shared_impl/ppapi_globals.h" |
| 12 #include "ppapi/shared_impl/resource.h" |
| 13 #include "ppapi/shared_impl/resource_tracker.h" |
| 14 |
| 15 using ppapi::thunk::PPB_FileIO_API; |
| 16 using ppapi::thunk::PPB_FileRef_API; |
| 17 |
| 18 namespace ppapi { |
| 19 namespace proxy { |
| 20 |
| 21 namespace { |
| 22 |
| 23 // The maximum size we'll support reading in one chunk. The renderer process |
| 24 // must allocate a buffer sized according to the request of the plugin. To |
| 25 // keep things from getting out of control, we cap the read size to this value. |
| 26 // This should generally be OK since the API specifies that it may perform a |
| 27 // partial read. |
| 28 static const int32_t kMaxReadSize = 33554432; // 32MB |
| 29 |
| 30 typedef EnterHostFromHostResourceForceCallback<PPB_FileIO_API> EnterHostFileIO; |
| 31 typedef EnterPluginFromHostResource<PPB_FileIO_API> EnterPluginFileIO; |
| 32 |
| 33 class FileIO : public FileIOImpl { |
| 34 public: |
| 35 explicit FileIO(const HostResource& host_resource); |
| 36 virtual ~FileIO(); |
| 37 |
| 38 // PPB_FileIO_API implementation (not provided by FileIOImpl). |
| 39 virtual void Close() OVERRIDE; |
| 40 virtual int32_t GetOSFileDescriptor() OVERRIDE; |
| 41 virtual int32_t WillWrite(int64_t offset, |
| 42 int32_t bytes_to_write, |
| 43 PP_CompletionCallback callback) OVERRIDE; |
| 44 virtual int32_t WillSetLength(int64_t length, |
| 45 PP_CompletionCallback callback) OVERRIDE; |
| 46 |
| 47 private: |
| 48 // FileIOImpl overrides. |
| 49 virtual int32_t OpenValidated(PP_Resource file_ref_resource, |
| 50 PPB_FileRef_API* file_ref_api, |
| 51 int32_t open_flags, |
| 52 PP_CompletionCallback callback) OVERRIDE; |
| 53 virtual int32_t QueryValidated(PP_FileInfo* info, |
| 54 PP_CompletionCallback callback) OVERRIDE; |
| 55 virtual int32_t TouchValidated(PP_Time last_access_time, |
| 56 PP_Time last_modified_time, |
| 57 PP_CompletionCallback callback) OVERRIDE; |
| 58 virtual int32_t ReadValidated(int64_t offset, |
| 59 char* buffer, |
| 60 int32_t bytes_to_read, |
| 61 PP_CompletionCallback callback) OVERRIDE; |
| 62 virtual int32_t WriteValidated(int64_t offset, |
| 63 const char* buffer, |
| 64 int32_t bytes_to_write, |
| 65 PP_CompletionCallback callback) OVERRIDE; |
| 66 virtual int32_t SetLengthValidated(int64_t length, |
| 67 PP_CompletionCallback callback) OVERRIDE; |
| 68 virtual int32_t FlushValidated(PP_CompletionCallback callback) OVERRIDE; |
| 69 |
| 70 PluginDispatcher* GetDispatcher() const { |
| 71 return PluginDispatcher::GetForResource(this); |
| 72 } |
| 73 |
| 74 static const ApiID kApiID = API_ID_PPB_FILE_IO; |
| 75 |
| 76 DISALLOW_IMPLICIT_CONSTRUCTORS(FileIO); |
| 77 }; |
| 78 |
| 79 FileIO::FileIO(const HostResource& host_resource) |
| 80 : FileIOImpl(host_resource) { |
| 81 } |
| 82 |
| 83 FileIO::~FileIO() { |
| 84 Close(); |
| 85 } |
| 86 |
| 87 void FileIO::Close() { |
| 88 if (file_open_) { |
| 89 GetDispatcher()->Send(new PpapiHostMsg_PPBFileIO_Close(kApiID, |
| 90 host_resource())); |
| 91 } |
| 92 } |
| 93 |
| 94 int32_t FileIO::GetOSFileDescriptor() { |
| 95 return -1; |
| 96 } |
| 97 |
| 98 int32_t FileIO::WillWrite(int64_t offset, |
| 99 int32_t bytes_to_write, |
| 100 PP_CompletionCallback callback) { |
| 101 GetDispatcher()->Send(new PpapiHostMsg_PPBFileIO_WillWrite( |
| 102 kApiID, host_resource(), offset, bytes_to_write)); |
| 103 RegisterCallback(OPERATION_EXCLUSIVE, callback, NULL, NULL); |
| 104 return PP_OK_COMPLETIONPENDING; |
| 105 } |
| 106 |
| 107 int32_t FileIO::WillSetLength(int64_t length, |
| 108 PP_CompletionCallback callback) { |
| 109 GetDispatcher()->Send(new PpapiHostMsg_PPBFileIO_WillSetLength( |
| 110 kApiID, host_resource(), length)); |
| 111 RegisterCallback(OPERATION_EXCLUSIVE, callback, NULL, NULL); |
| 112 return PP_OK_COMPLETIONPENDING; |
| 113 } |
| 114 |
| 115 int32_t FileIO::OpenValidated(PP_Resource file_ref_resource, |
| 116 PPB_FileRef_API* file_ref_api, |
| 117 int32_t open_flags, |
| 118 PP_CompletionCallback callback) { |
| 119 Resource* file_ref_object = |
| 120 PpapiGlobals::Get()->GetResourceTracker()->GetResource(file_ref_resource); |
| 121 |
| 122 GetDispatcher()->Send(new PpapiHostMsg_PPBFileIO_Open( |
| 123 kApiID, host_resource(), file_ref_object->host_resource(), open_flags)); |
| 124 RegisterCallback(OPERATION_EXCLUSIVE, callback, NULL, NULL); |
| 125 return PP_OK_COMPLETIONPENDING; |
| 126 } |
| 127 |
| 128 int32_t FileIO::QueryValidated(PP_FileInfo* info, |
| 129 PP_CompletionCallback callback) { |
| 130 GetDispatcher()->Send(new PpapiHostMsg_PPBFileIO_Query( |
| 131 kApiID, host_resource())); |
| 132 RegisterCallback(OPERATION_EXCLUSIVE, callback, NULL, info); |
| 133 return PP_OK_COMPLETIONPENDING; |
| 134 } |
| 135 |
| 136 int32_t FileIO::TouchValidated(PP_Time last_access_time, |
| 137 PP_Time last_modified_time, |
| 138 PP_CompletionCallback callback) { |
| 139 GetDispatcher()->Send(new PpapiHostMsg_PPBFileIO_Touch( |
| 140 kApiID, host_resource(), last_access_time, last_modified_time)); |
| 141 RegisterCallback(OPERATION_EXCLUSIVE, callback, NULL, NULL); |
| 142 return PP_OK_COMPLETIONPENDING; |
| 143 } |
| 144 |
| 145 int32_t FileIO::ReadValidated(int64_t offset, |
| 146 char* buffer, |
| 147 int32_t bytes_to_read, |
| 148 PP_CompletionCallback callback) { |
| 149 GetDispatcher()->Send(new PpapiHostMsg_PPBFileIO_Read( |
| 150 kApiID, host_resource(), offset, bytes_to_read)); |
| 151 RegisterCallback(OPERATION_READ, callback, buffer, NULL); |
| 152 return PP_OK_COMPLETIONPENDING; |
| 153 } |
| 154 |
| 155 int32_t FileIO::WriteValidated(int64_t offset, |
| 156 const char* buffer, |
| 157 int32_t bytes_to_write, |
| 158 PP_CompletionCallback callback) { |
| 159 // TODO(brettw) it would be nice to use a shared memory buffer for large |
| 160 // writes rather than having to copy to a string (which will involve a number |
| 161 // of extra copies to serialize over IPC). |
| 162 GetDispatcher()->Send(new PpapiHostMsg_PPBFileIO_Write( |
| 163 kApiID, host_resource(), offset, std::string(buffer, bytes_to_write))); |
| 164 RegisterCallback(OPERATION_WRITE, callback, NULL, NULL); |
| 165 return PP_OK_COMPLETIONPENDING; |
| 166 } |
| 167 |
| 168 int32_t FileIO::SetLengthValidated(int64_t length, |
| 169 PP_CompletionCallback callback) { |
| 170 GetDispatcher()->Send(new PpapiHostMsg_PPBFileIO_SetLength( |
| 171 kApiID, host_resource(), length)); |
| 172 RegisterCallback(OPERATION_EXCLUSIVE, callback, NULL, NULL); |
| 173 return PP_OK_COMPLETIONPENDING; |
| 174 } |
| 175 |
| 176 int32_t FileIO::FlushValidated(PP_CompletionCallback callback) { |
| 177 GetDispatcher()->Send(new PpapiHostMsg_PPBFileIO_Flush( |
| 178 kApiID, host_resource())); |
| 179 RegisterCallback(OPERATION_EXCLUSIVE, callback, NULL, NULL); |
| 180 return PP_OK_COMPLETIONPENDING; |
| 181 } |
| 182 |
| 183 } // namespace |
| 184 |
| 185 // ----------------------------------------------------------------------------- |
| 186 |
| 187 PPB_FileIO_Proxy::PPB_FileIO_Proxy(Dispatcher* dispatcher) |
| 188 : InterfaceProxy(dispatcher), |
| 189 callback_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) { |
| 190 } |
| 191 |
| 192 PPB_FileIO_Proxy::~PPB_FileIO_Proxy() { |
| 193 } |
| 194 |
| 195 // static |
| 196 PP_Resource PPB_FileIO_Proxy::CreateProxyResource(PP_Instance instance) { |
| 197 PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance); |
| 198 if (!dispatcher) |
| 199 return 0; |
| 200 |
| 201 HostResource result; |
| 202 dispatcher->Send(new PpapiHostMsg_PPBFileIO_Create(kApiID, instance, |
| 203 &result)); |
| 204 if (result.is_null()) |
| 205 return 0; |
| 206 return (new FileIO(result))->GetReference(); |
| 207 } |
| 208 |
| 209 bool PPB_FileIO_Proxy::OnMessageReceived(const IPC::Message& msg) { |
| 210 bool handled = true; |
| 211 IPC_BEGIN_MESSAGE_MAP(PPB_FileIO_Proxy, msg) |
| 212 // Plugin -> host message. |
| 213 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFileIO_Create, OnHostMsgCreate) |
| 214 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFileIO_Open, OnHostMsgOpen) |
| 215 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFileIO_Close, OnHostMsgClose) |
| 216 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFileIO_Query, OnHostMsgQuery) |
| 217 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFileIO_Touch, OnHostMsgTouch) |
| 218 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFileIO_Read, OnHostMsgRead) |
| 219 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFileIO_Write, OnHostMsgWrite) |
| 220 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFileIO_SetLength, OnHostMsgSetLength) |
| 221 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFileIO_Flush, OnHostMsgFlush) |
| 222 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFileIO_WillWrite, OnHostMsgWillWrite) |
| 223 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFileIO_WillSetLength, |
| 224 OnHostMsgWillSetLength) |
| 225 |
| 226 // Host -> plugin messages. |
| 227 IPC_MESSAGE_HANDLER(PpapiMsg_PPBFileIO_GeneralComplete, |
| 228 OnPluginMsgGeneralComplete) |
| 229 IPC_MESSAGE_HANDLER(PpapiMsg_PPBFileIO_OpenFileComplete, |
| 230 OnPluginMsgOpenFileComplete) |
| 231 IPC_MESSAGE_HANDLER(PpapiMsg_PPBFileIO_QueryComplete, |
| 232 OnPluginMsgQueryComplete) |
| 233 IPC_MESSAGE_HANDLER(PpapiMsg_PPBFileIO_ReadComplete, |
| 234 OnPluginMsgReadComplete) |
| 235 IPC_MESSAGE_UNHANDLED(handled = false) |
| 236 IPC_END_MESSAGE_MAP() |
| 237 return handled; |
| 238 } |
| 239 |
| 240 void PPB_FileIO_Proxy::OnHostMsgCreate(PP_Instance instance, |
| 241 HostResource* result) { |
| 242 thunk::EnterResourceCreation enter(instance); |
| 243 if (enter.succeeded()) { |
| 244 result->SetHostResource(instance, |
| 245 enter.functions()->CreateFileIO(instance)); |
| 246 } |
| 247 } |
| 248 |
| 249 void PPB_FileIO_Proxy::OnHostMsgOpen(const HostResource& host_resource, |
| 250 const HostResource& file_ref_resource, |
| 251 int32_t open_flags) { |
| 252 EnterHostFileIO enter(host_resource, callback_factory_, |
| 253 &PPB_FileIO_Proxy::OpenFileCallbackCompleteInHost, host_resource); |
| 254 if (enter.succeeded()) { |
| 255 enter.SetResult(enter.object()->Open( |
| 256 file_ref_resource.host_resource(), open_flags, enter.callback())); |
| 257 } |
| 258 } |
| 259 |
| 260 void PPB_FileIO_Proxy::OnHostMsgClose(const HostResource& host_resource) { |
| 261 EnterHostFromHostResource<PPB_FileIO_API> enter(host_resource); |
| 262 if (enter.succeeded()) |
| 263 enter.object()->Close(); |
| 264 } |
| 265 |
| 266 void PPB_FileIO_Proxy::OnHostMsgQuery(const HostResource& host_resource) { |
| 267 // The callback will take charge of deleting the FileInfo. The contents must |
| 268 // be defined so we don't send garbage to the plugin in the failure case. |
| 269 PP_FileInfo* info = new PP_FileInfo; |
| 270 memset(info, 0, sizeof(PP_FileInfo)); |
| 271 EnterHostFileIO enter(host_resource, callback_factory_, |
| 272 &PPB_FileIO_Proxy::QueryCallbackCompleteInHost, |
| 273 host_resource, info); |
| 274 if (enter.succeeded()) |
| 275 enter.SetResult(enter.object()->Query(info, enter.callback())); |
| 276 } |
| 277 |
| 278 void PPB_FileIO_Proxy::OnHostMsgTouch(const HostResource& host_resource, |
| 279 PP_Time last_access_time, |
| 280 PP_Time last_modified_time) { |
| 281 EnterHostFileIO enter(host_resource, callback_factory_, |
| 282 &PPB_FileIO_Proxy::GeneralCallbackCompleteInHost, |
| 283 host_resource); |
| 284 if (enter.succeeded()) { |
| 285 enter.SetResult(enter.object()->Touch(last_access_time, last_modified_time, |
| 286 enter.callback())); |
| 287 } |
| 288 } |
| 289 |
| 290 void PPB_FileIO_Proxy::OnHostMsgRead(const HostResource& host_resource, |
| 291 int64_t offset, |
| 292 int32_t bytes_to_read) { |
| 293 // Validate bytes_to_read before allocating below. This value is coming from |
| 294 // the untrusted plugin. |
| 295 bytes_to_read = std::min(bytes_to_read, kMaxReadSize); |
| 296 if (bytes_to_read < 0) { |
| 297 ReadCallbackCompleteInHost(PP_ERROR_FAILED, host_resource, |
| 298 new std::string()); |
| 299 return; |
| 300 } |
| 301 |
| 302 // The callback will take charge of deleting the string. |
| 303 std::string* dest = new std::string; |
| 304 dest->resize(bytes_to_read); |
| 305 EnterHostFileIO enter(host_resource, callback_factory_, |
| 306 &PPB_FileIO_Proxy::ReadCallbackCompleteInHost, |
| 307 host_resource, dest); |
| 308 if (enter.succeeded()) { |
| 309 enter.SetResult(enter.object()->Read(offset, |
| 310 bytes_to_read > 0 ? &(*dest)[0] : NULL, |
| 311 bytes_to_read, enter.callback())); |
| 312 } |
| 313 } |
| 314 |
| 315 void PPB_FileIO_Proxy::OnHostMsgWrite(const HostResource& host_resource, |
| 316 int64_t offset, |
| 317 const std::string& data) { |
| 318 EnterHostFileIO enter(host_resource, callback_factory_, |
| 319 &PPB_FileIO_Proxy::GeneralCallbackCompleteInHost, |
| 320 host_resource); |
| 321 if (enter.succeeded()) { |
| 322 enter.SetResult(enter.object()->Write(offset, data.data(), data.size(), |
| 323 enter.callback())); |
| 324 } |
| 325 } |
| 326 |
| 327 void PPB_FileIO_Proxy::OnHostMsgSetLength(const HostResource& host_resource, |
| 328 int64_t length) { |
| 329 EnterHostFileIO enter(host_resource, callback_factory_, |
| 330 &PPB_FileIO_Proxy::GeneralCallbackCompleteInHost, |
| 331 host_resource); |
| 332 if (enter.succeeded()) |
| 333 enter.SetResult(enter.object()->SetLength(length, enter.callback())); |
| 334 } |
| 335 |
| 336 void PPB_FileIO_Proxy::OnHostMsgFlush(const HostResource& host_resource) { |
| 337 EnterHostFileIO enter(host_resource, callback_factory_, |
| 338 &PPB_FileIO_Proxy::GeneralCallbackCompleteInHost, |
| 339 host_resource); |
| 340 if (enter.succeeded()) |
| 341 enter.SetResult(enter.object()->Flush(enter.callback())); |
| 342 } |
| 343 |
| 344 void PPB_FileIO_Proxy::OnHostMsgWillWrite(const HostResource& host_resource, |
| 345 int64_t offset, |
| 346 int32_t bytes_to_write) { |
| 347 EnterHostFileIO enter(host_resource, callback_factory_, |
| 348 &PPB_FileIO_Proxy::GeneralCallbackCompleteInHost, |
| 349 host_resource); |
| 350 if (enter.succeeded()) { |
| 351 enter.SetResult(enter.object()->WillWrite(offset, bytes_to_write, |
| 352 enter.callback())); |
| 353 } |
| 354 } |
| 355 |
| 356 void PPB_FileIO_Proxy::OnHostMsgWillSetLength(const HostResource& host_resource, |
| 357 int64_t length) { |
| 358 EnterHostFileIO enter(host_resource, callback_factory_, |
| 359 &PPB_FileIO_Proxy::GeneralCallbackCompleteInHost, |
| 360 host_resource); |
| 361 if (enter.succeeded()) |
| 362 enter.SetResult(enter.object()->WillSetLength(length, enter.callback())); |
| 363 } |
| 364 |
| 365 void PPB_FileIO_Proxy::OnPluginMsgGeneralComplete( |
| 366 const HostResource& host_resource, |
| 367 int32_t result) { |
| 368 EnterPluginFileIO enter(host_resource); |
| 369 if (enter.succeeded()) |
| 370 static_cast<FileIO*>(enter.object())->ExecuteGeneralCallback(result); |
| 371 } |
| 372 |
| 373 void PPB_FileIO_Proxy::OnPluginMsgOpenFileComplete( |
| 374 const HostResource& host_resource, |
| 375 int32_t result) { |
| 376 EnterPluginFileIO enter(host_resource); |
| 377 if (enter.succeeded()) |
| 378 static_cast<FileIO*>(enter.object())->ExecuteOpenFileCallback(result); |
| 379 } |
| 380 |
| 381 void PPB_FileIO_Proxy::OnPluginMsgQueryComplete( |
| 382 const HostResource& host_resource, |
| 383 int32_t result, |
| 384 const PP_FileInfo& info) { |
| 385 EnterPluginFileIO enter(host_resource); |
| 386 if (enter.succeeded()) |
| 387 static_cast<FileIO*>(enter.object())->ExecuteQueryCallback(result, info); |
| 388 } |
| 389 |
| 390 void PPB_FileIO_Proxy::OnPluginMsgReadComplete( |
| 391 const HostResource& host_resource, |
| 392 int32_t result, |
| 393 const std::string& data) { |
| 394 EnterPluginFileIO enter(host_resource); |
| 395 if (enter.succeeded()) { |
| 396 // The result code should contain the data size if it's positive. |
| 397 DCHECK((result < 0 && data.size() == 0) || |
| 398 result == static_cast<int32_t>(data.size())); |
| 399 static_cast<FileIO*>(enter.object())->ExecuteReadCallback(result, |
| 400 data.data()); |
| 401 } |
| 402 } |
| 403 |
| 404 void PPB_FileIO_Proxy::GeneralCallbackCompleteInHost( |
| 405 int32_t pp_error, |
| 406 const HostResource& host_resource) { |
| 407 Send(new PpapiMsg_PPBFileIO_GeneralComplete(kApiID, host_resource, pp_error)); |
| 408 } |
| 409 |
| 410 void PPB_FileIO_Proxy::OpenFileCallbackCompleteInHost( |
| 411 int32_t pp_error, |
| 412 const HostResource& host_resource) { |
| 413 Send(new PpapiMsg_PPBFileIO_OpenFileComplete(kApiID, host_resource, |
| 414 pp_error)); |
| 415 } |
| 416 |
| 417 void PPB_FileIO_Proxy::QueryCallbackCompleteInHost( |
| 418 int32_t pp_error, |
| 419 const HostResource& host_resource, |
| 420 PP_FileInfo* info) { |
| 421 Send(new PpapiMsg_PPBFileIO_QueryComplete(kApiID, host_resource, pp_error, |
| 422 *info)); |
| 423 delete info; |
| 424 } |
| 425 |
| 426 void PPB_FileIO_Proxy::ReadCallbackCompleteInHost( |
| 427 int32_t pp_error, |
| 428 const HostResource& host_resource, |
| 429 std::string* data) { |
| 430 // Only send the amount of data in the string that was actually read. |
| 431 if (pp_error >= 0) { |
| 432 DCHECK(pp_error <= static_cast<int32_t>(data->size())); |
| 433 data->resize(pp_error); |
| 434 } |
| 435 Send(new PpapiMsg_PPBFileIO_ReadComplete(kApiID, host_resource, pp_error, |
| 436 *data)); |
| 437 delete data; |
| 438 } |
| 439 |
| 440 } // namespace proxy |
| 441 } // namespace ppapi |
OLD | NEW |