1 // Copyright (c) 2012 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.
5 #include "ppapi/proxy/ppb_file_io_proxy.h"
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/ppb_file_io_shared.h"
13 #include "ppapi/shared_impl/resource.h"
14 #include "ppapi/shared_impl/resource_tracker.h"
16 using ppapi::thunk::PPB_FileIO_API
;
17 using ppapi::thunk::PPB_FileRef_API
;
24 // The maximum size we'll support reading in one chunk. The renderer process
25 // must allocate a buffer sized according to the request of the plugin. To
26 // keep things from getting out of control, we cap the read size to this value.
27 // This should generally be OK since the API specifies that it may perform a
29 static const int32_t kMaxReadSize
= 33554432; // 32MB
32 typedef EnterHostFromHostResourceForceCallback
<PPB_FileIO_API
> EnterHostFileIO
;
34 typedef EnterPluginFromHostResource
<PPB_FileIO_API
> EnterPluginFileIO
;
36 class FileIO
: public PPB_FileIO_Shared
{
38 explicit FileIO(const HostResource
& host_resource
);
41 // PPB_FileIO_API implementation (not provided by FileIOImpl).
42 virtual void Close() OVERRIDE
;
43 virtual int32_t GetOSFileDescriptor() OVERRIDE
;
44 virtual int32_t WillWrite(int64_t offset
,
45 int32_t bytes_to_write
,
46 scoped_refptr
<TrackedCallback
> callback
) OVERRIDE
;
47 virtual int32_t WillSetLength(
49 scoped_refptr
<TrackedCallback
> callback
) OVERRIDE
;
52 // FileIOImpl overrides.
53 virtual int32_t OpenValidated(
54 PP_Resource file_ref_resource
,
55 PPB_FileRef_API
* file_ref_api
,
57 scoped_refptr
<TrackedCallback
> callback
) OVERRIDE
;
58 virtual int32_t QueryValidated(
60 scoped_refptr
<TrackedCallback
> callback
) OVERRIDE
;
61 virtual int32_t TouchValidated(
62 PP_Time last_access_time
,
63 PP_Time last_modified_time
,
64 scoped_refptr
<TrackedCallback
> callback
) OVERRIDE
;
65 virtual int32_t ReadValidated(
67 const PP_ArrayOutput
& output_array_buffer
,
68 int32_t max_read_length
,
69 scoped_refptr
< ::ppapi::TrackedCallback
> callback
) OVERRIDE
;
70 virtual int32_t WriteValidated(
73 int32_t bytes_to_write
,
74 scoped_refptr
<TrackedCallback
> callback
) OVERRIDE
;
75 virtual int32_t SetLengthValidated(
77 scoped_refptr
<TrackedCallback
> callback
) OVERRIDE
;
78 virtual int32_t FlushValidated(
79 scoped_refptr
<TrackedCallback
> callback
) OVERRIDE
;
81 PluginDispatcher
* GetDispatcher() const {
82 return PluginDispatcher::GetForResource(this);
85 static const ApiID kApiID
= API_ID_PPB_FILE_IO
;
87 DISALLOW_IMPLICIT_CONSTRUCTORS(FileIO
);
90 FileIO::FileIO(const HostResource
& host_resource
)
91 : PPB_FileIO_Shared(host_resource
) {
98 void FileIO::Close() {
100 GetDispatcher()->Send(new PpapiHostMsg_PPBFileIO_Close(kApiID
,
105 int32_t FileIO::GetOSFileDescriptor() {
109 int32_t FileIO::WillWrite(int64_t offset
,
110 int32_t bytes_to_write
,
111 scoped_refptr
<TrackedCallback
> callback
) {
112 GetDispatcher()->Send(new PpapiHostMsg_PPBFileIO_WillWrite(
113 kApiID
, host_resource(), offset
, bytes_to_write
));
114 RegisterCallback(OPERATION_EXCLUSIVE
, callback
, NULL
, NULL
);
115 return PP_OK_COMPLETIONPENDING
;
118 int32_t FileIO::WillSetLength(int64_t length
,
119 scoped_refptr
<TrackedCallback
> callback
) {
120 GetDispatcher()->Send(new PpapiHostMsg_PPBFileIO_WillSetLength(
121 kApiID
, host_resource(), length
));
122 RegisterCallback(OPERATION_EXCLUSIVE
, callback
, NULL
, NULL
);
123 return PP_OK_COMPLETIONPENDING
;
126 int32_t FileIO::OpenValidated(PP_Resource file_ref_resource
,
127 PPB_FileRef_API
* file_ref_api
,
129 scoped_refptr
<TrackedCallback
> callback
) {
130 Resource
* file_ref_object
=
131 PpapiGlobals::Get()->GetResourceTracker()->GetResource(file_ref_resource
);
133 GetDispatcher()->Send(new PpapiHostMsg_PPBFileIO_Open(
134 kApiID
, host_resource(), file_ref_object
->host_resource(), open_flags
));
135 RegisterCallback(OPERATION_EXCLUSIVE
, callback
, NULL
, NULL
);
136 return PP_OK_COMPLETIONPENDING
;
139 int32_t FileIO::QueryValidated(PP_FileInfo
* info
,
140 scoped_refptr
<TrackedCallback
> callback
) {
141 GetDispatcher()->Send(new PpapiHostMsg_PPBFileIO_Query(
142 kApiID
, host_resource()));
143 RegisterCallback(OPERATION_EXCLUSIVE
, callback
, NULL
, info
);
144 return PP_OK_COMPLETIONPENDING
;
147 int32_t FileIO::TouchValidated(PP_Time last_access_time
,
148 PP_Time last_modified_time
,
149 scoped_refptr
<TrackedCallback
> callback
) {
150 GetDispatcher()->Send(new PpapiHostMsg_PPBFileIO_Touch(
151 kApiID
, host_resource(), last_access_time
, last_modified_time
));
152 RegisterCallback(OPERATION_EXCLUSIVE
, callback
, NULL
, NULL
);
153 return PP_OK_COMPLETIONPENDING
;
156 int32_t FileIO::ReadValidated(int64_t offset
,
157 const PP_ArrayOutput
& output_array_buffer
,
158 int32_t max_read_length
,
159 scoped_refptr
<TrackedCallback
> callback
) {
160 GetDispatcher()->Send(new PpapiHostMsg_PPBFileIO_Read(
161 kApiID
, host_resource(), offset
, max_read_length
));
162 RegisterCallback(OPERATION_READ
, callback
, &output_array_buffer
, NULL
);
163 return PP_OK_COMPLETIONPENDING
;
166 int32_t FileIO::WriteValidated(int64_t offset
,
168 int32_t bytes_to_write
,
169 scoped_refptr
<TrackedCallback
> callback
) {
170 // TODO(brettw) it would be nice to use a shared memory buffer for large
171 // writes rather than having to copy to a string (which will involve a number
172 // of extra copies to serialize over IPC).
173 GetDispatcher()->Send(new PpapiHostMsg_PPBFileIO_Write(
174 kApiID
, host_resource(), offset
, std::string(buffer
, bytes_to_write
)));
175 RegisterCallback(OPERATION_WRITE
, callback
, NULL
, NULL
);
176 return PP_OK_COMPLETIONPENDING
;
179 int32_t FileIO::SetLengthValidated(int64_t length
,
180 scoped_refptr
<TrackedCallback
> callback
) {
181 GetDispatcher()->Send(new PpapiHostMsg_PPBFileIO_SetLength(
182 kApiID
, host_resource(), length
));
183 RegisterCallback(OPERATION_EXCLUSIVE
, callback
, NULL
, NULL
);
184 return PP_OK_COMPLETIONPENDING
;
187 int32_t FileIO::FlushValidated(scoped_refptr
<TrackedCallback
> callback
) {
188 GetDispatcher()->Send(new PpapiHostMsg_PPBFileIO_Flush(
189 kApiID
, host_resource()));
190 RegisterCallback(OPERATION_EXCLUSIVE
, callback
, NULL
, NULL
);
191 return PP_OK_COMPLETIONPENDING
;
196 // -----------------------------------------------------------------------------
198 PPB_FileIO_Proxy::PPB_FileIO_Proxy(Dispatcher
* dispatcher
)
199 : InterfaceProxy(dispatcher
),
200 callback_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {
203 PPB_FileIO_Proxy::~PPB_FileIO_Proxy() {
207 PP_Resource
PPB_FileIO_Proxy::CreateProxyResource(PP_Instance instance
) {
208 PluginDispatcher
* dispatcher
= PluginDispatcher::GetForInstance(instance
);
213 dispatcher
->Send(new PpapiHostMsg_PPBFileIO_Create(kApiID
, instance
,
215 if (result
.is_null())
217 return (new FileIO(result
))->GetReference();
220 bool PPB_FileIO_Proxy::OnMessageReceived(const IPC::Message
& msg
) {
222 IPC_BEGIN_MESSAGE_MAP(PPB_FileIO_Proxy
, msg
)
223 #if !defined(OS_NACL)
224 // Plugin -> host message.
225 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFileIO_Create
, OnHostMsgCreate
)
226 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFileIO_Open
, OnHostMsgOpen
)
227 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFileIO_Close
, OnHostMsgClose
)
228 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFileIO_Query
, OnHostMsgQuery
)
229 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFileIO_Touch
, OnHostMsgTouch
)
230 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFileIO_Read
, OnHostMsgRead
)
231 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFileIO_Write
, OnHostMsgWrite
)
232 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFileIO_SetLength
, OnHostMsgSetLength
)
233 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFileIO_Flush
, OnHostMsgFlush
)
234 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFileIO_WillWrite
, OnHostMsgWillWrite
)
235 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFileIO_WillSetLength
,
236 OnHostMsgWillSetLength
)
237 #endif // !defined(OS_NACL)
238 // Host -> plugin messages.
239 IPC_MESSAGE_HANDLER(PpapiMsg_PPBFileIO_GeneralComplete
,
240 OnPluginMsgGeneralComplete
)
241 IPC_MESSAGE_HANDLER(PpapiMsg_PPBFileIO_OpenFileComplete
,
242 OnPluginMsgOpenFileComplete
)
243 IPC_MESSAGE_HANDLER(PpapiMsg_PPBFileIO_QueryComplete
,
244 OnPluginMsgQueryComplete
)
245 IPC_MESSAGE_HANDLER(PpapiMsg_PPBFileIO_ReadComplete
,
246 OnPluginMsgReadComplete
)
247 IPC_MESSAGE_UNHANDLED(handled
= false)
248 IPC_END_MESSAGE_MAP()
252 #if !defined(OS_NACL)
253 void PPB_FileIO_Proxy::OnHostMsgCreate(PP_Instance instance
,
254 HostResource
* result
) {
255 thunk::EnterResourceCreation
enter(instance
);
256 if (enter
.succeeded()) {
257 result
->SetHostResource(instance
,
258 enter
.functions()->CreateFileIO(instance
));
262 void PPB_FileIO_Proxy::OnHostMsgOpen(const HostResource
& host_resource
,
263 const HostResource
& file_ref_resource
,
264 int32_t open_flags
) {
265 EnterHostFileIO
enter(host_resource
, callback_factory_
,
266 &PPB_FileIO_Proxy::OpenFileCallbackCompleteInHost
, host_resource
);
267 if (enter
.succeeded()) {
268 enter
.SetResult(enter
.object()->Open(
269 file_ref_resource
.host_resource(), open_flags
, enter
.callback()));
273 void PPB_FileIO_Proxy::OnHostMsgClose(const HostResource
& host_resource
) {
274 EnterHostFromHostResource
<PPB_FileIO_API
> enter(host_resource
);
275 if (enter
.succeeded())
276 enter
.object()->Close();
279 void PPB_FileIO_Proxy::OnHostMsgQuery(const HostResource
& host_resource
) {
280 // The callback will take charge of deleting the FileInfo. The contents must
281 // be defined so we don't send garbage to the plugin in the failure case.
282 PP_FileInfo
* info
= new PP_FileInfo
;
283 memset(info
, 0, sizeof(PP_FileInfo
));
284 EnterHostFileIO
enter(host_resource
, callback_factory_
,
285 &PPB_FileIO_Proxy::QueryCallbackCompleteInHost
,
286 host_resource
, info
);
287 if (enter
.succeeded())
288 enter
.SetResult(enter
.object()->Query(info
, enter
.callback()));
291 void PPB_FileIO_Proxy::OnHostMsgTouch(const HostResource
& host_resource
,
292 PP_Time last_access_time
,
293 PP_Time last_modified_time
) {
294 EnterHostFileIO
enter(host_resource
, callback_factory_
,
295 &PPB_FileIO_Proxy::GeneralCallbackCompleteInHost
,
297 if (enter
.succeeded()) {
298 enter
.SetResult(enter
.object()->Touch(last_access_time
, last_modified_time
,
303 void PPB_FileIO_Proxy::OnHostMsgRead(const HostResource
& host_resource
,
305 int32_t bytes_to_read
) {
306 // Validate bytes_to_read before allocating below. This value is coming from
307 // the untrusted plugin.
308 bytes_to_read
= std::min(bytes_to_read
, kMaxReadSize
);
309 if (bytes_to_read
< 0) {
310 ReadCallbackCompleteInHost(PP_ERROR_FAILED
, host_resource
,
315 // The callback will take charge of deleting the string.
316 std::string
* dest
= new std::string
;
317 dest
->resize(bytes_to_read
);
318 EnterHostFileIO
enter(host_resource
, callback_factory_
,
319 &PPB_FileIO_Proxy::ReadCallbackCompleteInHost
,
320 host_resource
, dest
);
321 if (enter
.succeeded()) {
322 enter
.SetResult(enter
.object()->Read(offset
,
323 bytes_to_read
> 0 ? &(*dest
)[0] : NULL
,
324 bytes_to_read
, enter
.callback()));
328 void PPB_FileIO_Proxy::OnHostMsgWrite(const HostResource
& host_resource
,
330 const std::string
& data
) {
331 EnterHostFileIO
enter(host_resource
, callback_factory_
,
332 &PPB_FileIO_Proxy::GeneralCallbackCompleteInHost
,
334 if (enter
.succeeded()) {
335 enter
.SetResult(enter
.object()->Write(offset
, data
.data(), data
.size(),
340 void PPB_FileIO_Proxy::OnHostMsgSetLength(const HostResource
& host_resource
,
342 EnterHostFileIO
enter(host_resource
, callback_factory_
,
343 &PPB_FileIO_Proxy::GeneralCallbackCompleteInHost
,
345 if (enter
.succeeded())
346 enter
.SetResult(enter
.object()->SetLength(length
, enter
.callback()));
349 void PPB_FileIO_Proxy::OnHostMsgFlush(const HostResource
& host_resource
) {
350 EnterHostFileIO
enter(host_resource
, callback_factory_
,
351 &PPB_FileIO_Proxy::GeneralCallbackCompleteInHost
,
353 if (enter
.succeeded())
354 enter
.SetResult(enter
.object()->Flush(enter
.callback()));
357 void PPB_FileIO_Proxy::OnHostMsgWillWrite(const HostResource
& host_resource
,
359 int32_t bytes_to_write
) {
360 EnterHostFileIO
enter(host_resource
, callback_factory_
,
361 &PPB_FileIO_Proxy::GeneralCallbackCompleteInHost
,
363 if (enter
.succeeded()) {
364 enter
.SetResult(enter
.object()->WillWrite(offset
, bytes_to_write
,
369 void PPB_FileIO_Proxy::OnHostMsgWillSetLength(const HostResource
& host_resource
,
371 EnterHostFileIO
enter(host_resource
, callback_factory_
,
372 &PPB_FileIO_Proxy::GeneralCallbackCompleteInHost
,
374 if (enter
.succeeded())
375 enter
.SetResult(enter
.object()->WillSetLength(length
, enter
.callback()));
377 #endif // !defined(OS_NACL)
379 void PPB_FileIO_Proxy::OnPluginMsgGeneralComplete(
380 const HostResource
& host_resource
,
382 EnterPluginFileIO
enter(host_resource
);
383 if (enter
.succeeded())
384 static_cast<FileIO
*>(enter
.object())->ExecuteGeneralCallback(result
);
387 void PPB_FileIO_Proxy::OnPluginMsgOpenFileComplete(
388 const HostResource
& host_resource
,
390 EnterPluginFileIO
enter(host_resource
);
391 if (enter
.succeeded())
392 static_cast<FileIO
*>(enter
.object())->ExecuteOpenFileCallback(result
);
395 void PPB_FileIO_Proxy::OnPluginMsgQueryComplete(
396 const HostResource
& host_resource
,
398 const PP_FileInfo
& info
) {
399 EnterPluginFileIO
enter(host_resource
);
400 if (enter
.succeeded())
401 static_cast<FileIO
*>(enter
.object())->ExecuteQueryCallback(result
, info
);
404 void PPB_FileIO_Proxy::OnPluginMsgReadComplete(
405 const HostResource
& host_resource
,
407 const std::string
& data
) {
408 EnterPluginFileIO
enter(host_resource
);
409 if (enter
.succeeded()) {
410 // The result code should contain the data size if it's positive.
411 DCHECK((result
< 0 && data
.size() == 0) ||
412 result
== static_cast<int32_t>(data
.size()));
413 static_cast<FileIO
*>(enter
.object())->ExecuteReadCallback(result
,
418 #if !defined(OS_NACL)
419 void PPB_FileIO_Proxy::GeneralCallbackCompleteInHost(
421 const HostResource
& host_resource
) {
422 Send(new PpapiMsg_PPBFileIO_GeneralComplete(kApiID
, host_resource
, pp_error
));
425 void PPB_FileIO_Proxy::OpenFileCallbackCompleteInHost(
427 const HostResource
& host_resource
) {
428 Send(new PpapiMsg_PPBFileIO_OpenFileComplete(kApiID
, host_resource
,
432 void PPB_FileIO_Proxy::QueryCallbackCompleteInHost(
434 const HostResource
& host_resource
,
436 Send(new PpapiMsg_PPBFileIO_QueryComplete(kApiID
, host_resource
, pp_error
,
441 void PPB_FileIO_Proxy::ReadCallbackCompleteInHost(
443 const HostResource
& host_resource
,
445 // Only send the amount of data in the string that was actually read.
447 DCHECK(pp_error
<= static_cast<int32_t>(data
->size()));
448 data
->resize(pp_error
);
450 Send(new PpapiMsg_PPBFileIO_ReadComplete(kApiID
, host_resource
, pp_error
,
454 #endif // !defined(OS_NACL)