Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(929)

Side by Side Diff: content/renderer/pepper/pepper_file_io_host.cc

Issue 33053002: Pepper: Move FileIO host from renderer to browser. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rebased Created 7 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « content/renderer/pepper/pepper_file_io_host.h ('k') | content/renderer/pepper/quota_file_io.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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.
4
5 #include "content/renderer/pepper/pepper_file_io_host.h"
6
7 #include "base/bind.h"
8 #include "base/callback.h"
9 #include "base/callback_helpers.h"
10 #include "base/command_line.h"
11 #include "base/files/file_util_proxy.h"
12 #include "content/child/child_thread.h"
13 #include "content/child/fileapi/file_system_dispatcher.h"
14 #include "content/child/quota_dispatcher.h"
15 #include "content/common/fileapi/file_system_messages.h"
16 #include "content/common/view_messages.h"
17 #include "content/public/common/content_client.h"
18 #include "content/public/renderer/content_renderer_client.h"
19 #include "content/renderer/pepper/pepper_file_ref_renderer_host.h"
20 #include "content/renderer/pepper/quota_file_io.h"
21 #include "content/renderer/pepper/renderer_ppapi_host_impl.h"
22 #include "content/renderer/render_thread_impl.h"
23 #include "ppapi/c/pp_errors.h"
24 #include "ppapi/c/ppb_file_io.h"
25 #include "ppapi/host/dispatch_host_message.h"
26 #include "ppapi/host/ppapi_host.h"
27 #include "ppapi/proxy/ppapi_messages.h"
28 #include "ppapi/shared_impl/file_system_util.h"
29 #include "ppapi/shared_impl/file_type_conversion.h"
30 #include "ppapi/shared_impl/time_conversion.h"
31 #include "ppapi/thunk/enter.h"
32 #include "third_party/WebKit/public/web/WebPluginContainer.h"
33
34 namespace content {
35
36 using ppapi::FileIOStateManager;
37 using ppapi::PPTimeToTime;
38 using ppapi::host::ReplyMessageContext;
39 using ppapi::thunk::EnterResourceNoLock;
40
41 namespace {
42
43 typedef base::Callback<void (base::PlatformFileError)> PlatformGeneralCallback;
44
45 int32_t ErrorOrByteNumber(int32_t pp_error, int32_t byte_number) {
46 // On the plugin side, some callbacks expect a parameter that means different
47 // things depending on whether is negative or not. We translate for those
48 // callbacks here.
49 return pp_error == PP_OK ? byte_number : pp_error;
50 }
51
52 class QuotaCallbackTranslator : public QuotaDispatcher::Callback {
53 public:
54 typedef QuotaFileIO::Delegate::AvailableSpaceCallback PluginCallback;
55 explicit QuotaCallbackTranslator(const PluginCallback& cb) : callback_(cb) {}
56 virtual void DidQueryStorageUsageAndQuota(int64 usage, int64 quota) OVERRIDE {
57 callback_.Run(std::max(static_cast<int64>(0), quota - usage));
58 }
59 virtual void DidGrantStorageQuota(int64 granted_quota) OVERRIDE {
60 NOTREACHED();
61 }
62 virtual void DidFail(quota::QuotaStatusCode error) OVERRIDE {
63 callback_.Run(0);
64 }
65 private:
66 PluginCallback callback_;
67 };
68
69 class QuotaFileIODelegate : public QuotaFileIO::Delegate {
70 public:
71 QuotaFileIODelegate() {}
72 virtual ~QuotaFileIODelegate() {}
73
74 virtual void QueryAvailableSpace(
75 const GURL& origin,
76 quota::StorageType type,
77 const AvailableSpaceCallback& callback) OVERRIDE {
78 ChildThread::current()->quota_dispatcher()->QueryStorageUsageAndQuota(
79 origin, type, new QuotaCallbackTranslator(callback));
80 }
81 virtual void WillUpdateFile(const GURL& file_path) OVERRIDE {
82 ChildThread::current()->Send(new FileSystemHostMsg_WillUpdate(file_path));
83 }
84 virtual void DidUpdateFile(const GURL& file_path, int64_t delta) OVERRIDE {
85 ChildThread::current()->Send(new FileSystemHostMsg_DidUpdate(
86 file_path, delta));
87 }
88 virtual scoped_refptr<base::MessageLoopProxy>
89 GetFileThreadMessageLoopProxy() OVERRIDE {
90 return RenderThreadImpl::current()->GetFileThreadMessageLoopProxy();
91 }
92 };
93
94 typedef base::Callback<
95 void (base::PlatformFileError error,
96 base::PassPlatformFile file,
97 quota::QuotaLimitType quota_policy,
98 const PepperFileIOHost::NotifyCloseFileCallback& close_file_callback)>
99 AsyncOpenFileSystemURLCallback;
100
101 void DoNotifyCloseFile(int file_open_id, base::PlatformFileError error) {
102 ChildThread::current()->file_system_dispatcher()->NotifyCloseFile(
103 file_open_id);
104 }
105
106 void DidOpenFileSystemURL(const AsyncOpenFileSystemURLCallback& callback,
107 base::PlatformFile file,
108 int file_open_id,
109 quota::QuotaLimitType quota_policy) {
110 callback.Run(base::PLATFORM_FILE_OK,
111 base::PassPlatformFile(&file),
112 quota_policy,
113 base::Bind(&DoNotifyCloseFile, file_open_id));
114 // Make sure we won't leak file handle if the requester has died.
115 if (file != base::kInvalidPlatformFileValue) {
116 base::FileUtilProxy::Close(
117 RenderThreadImpl::current()->GetFileThreadMessageLoopProxy().get(),
118 file,
119 base::Bind(&DoNotifyCloseFile, file_open_id));
120 }
121 }
122
123 void DidFailOpenFileSystemURL(const AsyncOpenFileSystemURLCallback& callback,
124 base::PlatformFileError error_code) {
125 base::PlatformFile invalid_file = base::kInvalidPlatformFileValue;
126 callback.Run(error_code,
127 base::PassPlatformFile(&invalid_file),
128 quota::kQuotaLimitTypeUnknown,
129 PepperFileIOHost::NotifyCloseFileCallback());
130 }
131
132 } // namespace
133
134 PepperFileIOHost::PepperFileIOHost(RendererPpapiHost* host,
135 PP_Instance instance,
136 PP_Resource resource)
137 : ResourceHost(host->GetPpapiHost(), instance, resource),
138 renderer_ppapi_host_(host),
139 file_(base::kInvalidPlatformFileValue),
140 file_system_type_(PP_FILESYSTEMTYPE_INVALID),
141 quota_policy_(quota::kQuotaLimitTypeUnknown),
142 open_flags_(0),
143 routing_id_(RenderThreadImpl::current()->GenerateRoutingID()),
144 weak_factory_(this) {
145 ChildThread::current()->AddRoute(routing_id_, this);
146 }
147
148 PepperFileIOHost::~PepperFileIOHost() {
149 OnHostMsgClose(NULL);
150 ChildThread::current()->RemoveRoute(routing_id_);
151 }
152
153 int32_t PepperFileIOHost::OnResourceMessageReceived(
154 const IPC::Message& msg,
155 ppapi::host::HostMessageContext* context) {
156 IPC_BEGIN_MESSAGE_MAP(PepperFileIOHost, msg)
157 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_FileIO_Open,
158 OnHostMsgOpen)
159 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_FileIO_Touch,
160 OnHostMsgTouch)
161 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_FileIO_Write,
162 OnHostMsgWrite)
163 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_FileIO_SetLength,
164 OnHostMsgSetLength)
165 PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_FileIO_Flush,
166 OnHostMsgFlush)
167 PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_FileIO_Close,
168 OnHostMsgClose)
169 PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_FileIO_RequestOSFileHandle,
170 OnHostMsgRequestOSFileHandle)
171 IPC_END_MESSAGE_MAP()
172 return PP_ERROR_FAILED;
173 }
174
175 bool PepperFileIOHost::OnMessageReceived(const IPC::Message& msg) {
176 bool handled = true;
177 IPC_BEGIN_MESSAGE_MAP(PepperFileIOHost, msg)
178 IPC_MESSAGE_HANDLER(ViewMsg_AsyncOpenPepperFile_ACK, OnAsyncFileOpened)
179 IPC_MESSAGE_UNHANDLED(handled = false)
180 IPC_END_MESSAGE_MAP()
181 return handled;
182 }
183
184 void PepperFileIOHost::OnAsyncFileOpened(
185 base::PlatformFileError error_code,
186 IPC::PlatformFileForTransit file_for_transit) {
187 DCHECK(!pending_open_callback_.is_null());
188 base::PlatformFile file =
189 IPC::PlatformFileForTransitToPlatformFile(file_for_transit);
190 if (!pending_open_callback_.is_null())
191 pending_open_callback_.Run(error_code, base::PassPlatformFile(&file));
192
193 // Make sure we won't leak file handle if the requester has died.
194 if (file != base::kInvalidPlatformFileValue) {
195 base::FileUtilProxy::Close(
196 RenderThreadImpl::current()->GetFileThreadMessageLoopProxy().get(),
197 file,
198 base::FileUtilProxy::StatusCallback());
199 }
200 pending_open_callback_.Reset();
201 }
202
203 int32_t PepperFileIOHost::OnHostMsgOpen(
204 ppapi::host::HostMessageContext* context,
205 PP_Resource file_ref_resource,
206 int32_t open_flags) {
207 int32_t rv = state_manager_.CheckOperationState(
208 FileIOStateManager::OPERATION_EXCLUSIVE, false);
209 if (rv != PP_OK)
210 return rv;
211
212 if (!ppapi::PepperFileOpenFlagsToPlatformFileFlags(open_flags, NULL))
213 return PP_ERROR_BADARGUMENT;
214
215 ppapi::host::ResourceHost* resource_host =
216 renderer_ppapi_host_->GetPpapiHost()->GetResourceHost(file_ref_resource);
217 if (!resource_host || !resource_host->IsFileRefHost())
218 return PP_ERROR_BADRESOURCE;
219
220 PepperFileRefRendererHost* file_ref_host =
221 static_cast<PepperFileRefRendererHost*>(resource_host);
222 if (file_ref_host->GetFileSystemType() == PP_FILESYSTEMTYPE_INVALID)
223 return PP_ERROR_FAILED;
224
225 open_flags_ = open_flags;
226 file_system_type_ = file_ref_host->GetFileSystemType();
227
228 if (file_system_type_ != PP_FILESYSTEMTYPE_EXTERNAL) {
229 file_system_url_ = file_ref_host->GetFileSystemURL();
230 FileSystemDispatcher* file_system_dispatcher =
231 ChildThread::current()->file_system_dispatcher();
232
233 AsyncOpenFileSystemURLCallback callback = base::Bind(
234 &PepperFileIOHost::ExecutePlatformOpenFileSystemURLCallback,
235 weak_factory_.GetWeakPtr(),
236 context->MakeReplyMessageContext());
237 file_system_dispatcher->OpenPepperFile(
238 file_system_url_, open_flags,
239 base::Bind(&DidOpenFileSystemURL, callback),
240 base::Bind(&DidFailOpenFileSystemURL, callback));
241 } else {
242 pending_open_callback_ =
243 base::Bind(&PepperFileIOHost::ExecutePlatformOpenFileCallback,
244 weak_factory_.GetWeakPtr(),
245 context->MakeReplyMessageContext());
246 RenderThreadImpl::current()->Send(new ViewHostMsg_AsyncOpenPepperFile(
247 routing_id_,
248 file_ref_host->GetExternalFilePath(),
249 open_flags_));
250 }
251 state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE);
252 return PP_OK_COMPLETIONPENDING;
253 }
254
255 int32_t PepperFileIOHost::OnHostMsgTouch(
256 ppapi::host::HostMessageContext* context,
257 PP_Time last_access_time,
258 PP_Time last_modified_time) {
259 int32_t rv = state_manager_.CheckOperationState(
260 FileIOStateManager::OPERATION_EXCLUSIVE, true);
261 if (rv != PP_OK)
262 return rv;
263
264 if (file_system_type_ != PP_FILESYSTEMTYPE_EXTERNAL) {
265 FileSystemDispatcher* file_system_dispatcher =
266 ChildThread::current()->file_system_dispatcher();
267 file_system_dispatcher->TouchFile(
268 file_system_url_,
269 PPTimeToTime(last_access_time),
270 PPTimeToTime(last_modified_time),
271 base::Bind(&PepperFileIOHost::ExecutePlatformGeneralCallback,
272 weak_factory_.GetWeakPtr(),
273 context->MakeReplyMessageContext()));
274 state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE);
275 return PP_OK_COMPLETIONPENDING;
276 }
277
278 // TODO(nhiroki): fix a failure of FileIO.Touch for an external filesystem on
279 // Mac and Linux due to sandbox restrictions (http://crbug.com/101128).
280 if (!base::FileUtilProxy::Touch(
281 RenderThreadImpl::current()->GetFileThreadMessageLoopProxy().get(),
282 file_,
283 PPTimeToTime(last_access_time),
284 PPTimeToTime(last_modified_time),
285 base::Bind(&PepperFileIOHost::ExecutePlatformGeneralCallback,
286 weak_factory_.GetWeakPtr(),
287 context->MakeReplyMessageContext())))
288 return PP_ERROR_FAILED;
289
290 state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE);
291 return PP_OK_COMPLETIONPENDING;
292 }
293
294 int32_t PepperFileIOHost::OnHostMsgWrite(
295 ppapi::host::HostMessageContext* context,
296 int64_t offset,
297 const std::string& buffer) {
298 int32_t rv = state_manager_.CheckOperationState(
299 FileIOStateManager::OPERATION_WRITE, true);
300 if (rv != PP_OK)
301 return rv;
302
303 if (quota_file_io_) {
304 if (!quota_file_io_->Write(
305 offset, buffer.c_str(), buffer.size(),
306 base::Bind(&PepperFileIOHost::ExecutePlatformWriteCallback,
307 weak_factory_.GetWeakPtr(),
308 context->MakeReplyMessageContext())))
309 return PP_ERROR_FAILED;
310 } else {
311 if (!base::FileUtilProxy::Write(
312 RenderThreadImpl::current()->GetFileThreadMessageLoopProxy().get(),
313 file_,
314 offset,
315 buffer.c_str(),
316 buffer.size(),
317 base::Bind(&PepperFileIOHost::ExecutePlatformWriteCallback,
318 weak_factory_.GetWeakPtr(),
319 context->MakeReplyMessageContext())))
320 return PP_ERROR_FAILED;
321 }
322
323 state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_WRITE);
324 return PP_OK_COMPLETIONPENDING;
325 }
326
327 int32_t PepperFileIOHost::OnHostMsgSetLength(
328 ppapi::host::HostMessageContext* context,
329 int64_t length) {
330 int32_t rv = state_manager_.CheckOperationState(
331 FileIOStateManager::OPERATION_EXCLUSIVE, true);
332 if (rv != PP_OK)
333 return rv;
334
335 if (file_system_type_ != PP_FILESYSTEMTYPE_EXTERNAL) {
336 FileSystemDispatcher* file_system_dispatcher =
337 ChildThread::current()->file_system_dispatcher();
338 file_system_dispatcher->Truncate(
339 file_system_url_, length, NULL,
340 base::Bind(&PepperFileIOHost::ExecutePlatformGeneralCallback,
341 weak_factory_.GetWeakPtr(),
342 context->MakeReplyMessageContext()));
343 } else {
344 // TODO(nhiroki): fix a failure of FileIO.SetLength for an external
345 // filesystem on Mac due to sandbox restrictions (http://crbug.com/156077).
346 if (!base::FileUtilProxy::Truncate(
347 RenderThreadImpl::current()->GetFileThreadMessageLoopProxy().get(),
348 file_,
349 length,
350 base::Bind(&PepperFileIOHost::ExecutePlatformGeneralCallback,
351 weak_factory_.GetWeakPtr(),
352 context->MakeReplyMessageContext())))
353 return PP_ERROR_FAILED;
354 }
355
356 state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE);
357 return PP_OK_COMPLETIONPENDING;
358 }
359
360 int32_t PepperFileIOHost::OnHostMsgFlush(
361 ppapi::host::HostMessageContext* context) {
362 int32_t rv = state_manager_.CheckOperationState(
363 FileIOStateManager::OPERATION_EXCLUSIVE, true);
364 if (rv != PP_OK)
365 return rv;
366
367 if (!base::FileUtilProxy::Flush(
368 RenderThreadImpl::current()->GetFileThreadMessageLoopProxy().get(),
369 file_,
370 base::Bind(&PepperFileIOHost::ExecutePlatformGeneralCallback,
371 weak_factory_.GetWeakPtr(),
372 context->MakeReplyMessageContext())))
373 return PP_ERROR_FAILED;
374
375 state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE);
376 return PP_OK_COMPLETIONPENDING;
377 }
378
379 int32_t PepperFileIOHost::OnHostMsgClose(
380 ppapi::host::HostMessageContext* context) {
381 if (file_ != base::kInvalidPlatformFileValue) {
382 base::FileUtilProxy::Close(
383 RenderThreadImpl::current()->GetFileThreadMessageLoopProxy().get(),
384 file_,
385 base::ResetAndReturn(&notify_close_file_callback_));
386 file_ = base::kInvalidPlatformFileValue;
387 quota_file_io_.reset();
388 }
389 return PP_OK;
390 }
391
392 int32_t PepperFileIOHost::OnHostMsgRequestOSFileHandle(
393 ppapi::host::HostMessageContext* context) {
394 if (open_flags_ != PP_FILEOPENFLAG_READ &&
395 quota_policy_ != quota::kQuotaLimitTypeUnlimited)
396 return PP_ERROR_FAILED;
397
398 // Whitelist to make it privately accessible.
399 if (!host()->permissions().HasPermission(ppapi::PERMISSION_PRIVATE) &&
400 !GetContentClient()->renderer()->IsPluginAllowedToCallRequestOSFileHandle(
401 renderer_ppapi_host_->GetContainerForInstance(pp_instance())))
402 return PP_ERROR_NOACCESS;
403
404 IPC::PlatformFileForTransit file =
405 renderer_ppapi_host_->ShareHandleWithRemote(file_, false);
406 if (file == IPC::InvalidPlatformFileForTransit())
407 return PP_ERROR_FAILED;
408 ppapi::host::ReplyMessageContext reply_context =
409 context->MakeReplyMessageContext();
410 ppapi::proxy::SerializedHandle file_handle;
411 file_handle.set_file_handle(file, open_flags_);
412 reply_context.params.AppendHandle(file_handle);
413 host()->SendReply(reply_context,
414 PpapiPluginMsg_FileIO_RequestOSFileHandleReply());
415 return PP_OK_COMPLETIONPENDING;
416 }
417
418 void PepperFileIOHost::ExecutePlatformGeneralCallback(
419 ppapi::host::ReplyMessageContext reply_context,
420 base::PlatformFileError error_code) {
421 reply_context.params.set_result(
422 ppapi::PlatformFileErrorToPepperError(error_code));
423 host()->SendReply(reply_context, PpapiPluginMsg_FileIO_GeneralReply());
424 state_manager_.SetOperationFinished();
425 }
426
427 void PepperFileIOHost::ExecutePlatformOpenFileCallback(
428 ppapi::host::ReplyMessageContext reply_context,
429 base::PlatformFileError error_code,
430 base::PassPlatformFile file) {
431 int32_t pp_error = ppapi::PlatformFileErrorToPepperError(error_code);
432 if (pp_error == PP_OK)
433 state_manager_.SetOpenSucceed();
434
435 DCHECK(file_ == base::kInvalidPlatformFileValue);
436 file_ = file.ReleaseValue();
437
438 DCHECK(!quota_file_io_.get());
439 if (file_ != base::kInvalidPlatformFileValue) {
440 if (ppapi::FileSystemTypeHasQuota(file_system_type_)) {
441 quota_file_io_.reset(new QuotaFileIO(
442 new QuotaFileIODelegate, file_, file_system_url_, file_system_type_));
443 }
444
445 IPC::PlatformFileForTransit file_for_transit =
446 renderer_ppapi_host_->ShareHandleWithRemote(file_, false);
447 if (!(file_for_transit == IPC::InvalidPlatformFileForTransit())) {
448 // Send the file descriptor to the plugin process. This is used in the
449 // plugin for any file operations that can be done there.
450 int32_t flags_to_send = open_flags_;
451 if (!host()->permissions().HasPermission(ppapi::PERMISSION_DEV)) {
452 // IMPORTANT: Clear PP_FILEOPENFLAG_WRITE and PP_FILEOPENFLAG_APPEND so
453 // the plugin can't write and so bypass our quota checks.
454 flags_to_send =
455 open_flags_ & ~(PP_FILEOPENFLAG_WRITE | PP_FILEOPENFLAG_APPEND);
456 }
457 ppapi::proxy::SerializedHandle file_handle;
458 file_handle.set_file_handle(file_for_transit, flags_to_send);
459 reply_context.params.AppendHandle(file_handle);
460 }
461 }
462
463 reply_context.params.set_result(pp_error);
464 host()->SendReply(reply_context, PpapiPluginMsg_FileIO_OpenReply());
465 state_manager_.SetOperationFinished();
466 }
467
468 void PepperFileIOHost::ExecutePlatformOpenFileSystemURLCallback(
469 ppapi::host::ReplyMessageContext reply_context,
470 base::PlatformFileError error_code,
471 base::PassPlatformFile file,
472 quota::QuotaLimitType quota_policy,
473 const PepperFileIOHost::NotifyCloseFileCallback& callback) {
474 if (error_code == base::PLATFORM_FILE_OK)
475 notify_close_file_callback_ = callback;
476 quota_policy_ = quota_policy;
477 ExecutePlatformOpenFileCallback(reply_context, error_code, file);
478 }
479
480 void PepperFileIOHost::ExecutePlatformWriteCallback(
481 ppapi::host::ReplyMessageContext reply_context,
482 base::PlatformFileError error_code,
483 int bytes_written) {
484 // On the plugin side, the callback expects a parameter with different meaning
485 // depends on whether is negative or not. It is the result here. We translate
486 // for the callback.
487 int32_t pp_error = ppapi::PlatformFileErrorToPepperError(error_code);
488 reply_context.params.set_result(ErrorOrByteNumber(pp_error, bytes_written));
489 host()->SendReply(reply_context, PpapiPluginMsg_FileIO_GeneralReply());
490 state_manager_.SetOperationFinished();
491 }
492
493 } // namespace content
OLDNEW
« no previous file with comments | « content/renderer/pepper/pepper_file_io_host.h ('k') | content/renderer/pepper/quota_file_io.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698