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 "content/browser/fileapi/fileapi_message_filter.h"
10 #include "base/bind.h"
11 #include "base/files/file_path.h"
12 #include "base/logging.h"
13 #include "base/memory/scoped_ptr.h"
14 #include "base/platform_file.h"
15 #include "base/sequenced_task_runner.h"
16 #include "base/strings/string_util.h"
17 #include "base/threading/thread.h"
18 #include "base/time/time.h"
19 #include "content/browser/child_process_security_policy_impl.h"
20 #include "content/browser/fileapi/browser_file_system_helper.h"
21 #include "content/browser/fileapi/chrome_blob_storage_context.h"
22 #include "content/browser/streams/stream_registry.h"
23 #include "content/common/fileapi/file_system_messages.h"
24 #include "content/common/fileapi/webblob_messages.h"
25 #include "content/public/browser/user_metrics.h"
26 #include "ipc/ipc_platform_file.h"
27 #include "net/base/mime_util.h"
28 #include "net/url_request/url_request_context.h"
29 #include "net/url_request/url_request_context_getter.h"
31 #include "webkit/browser/blob/blob_storage_context.h"
32 #include "webkit/browser/blob/blob_storage_host.h"
33 #include "webkit/browser/fileapi/file_observers.h"
34 #include "webkit/browser/fileapi/file_permission_policy.h"
35 #include "webkit/browser/fileapi/file_system_context.h"
36 #include "webkit/browser/fileapi/isolated_context.h"
37 #include "webkit/browser/quota/quota_manager.h"
38 #include "webkit/common/blob/blob_data.h"
39 #include "webkit/common/blob/shareable_file_reference.h"
40 #include "webkit/common/fileapi/directory_entry.h"
41 #include "webkit/common/fileapi/file_system_info.h"
42 #include "webkit/common/fileapi/file_system_types.h"
43 #include "webkit/common/fileapi/file_system_util.h"
45 #if defined(ENABLE_PLUGINS)
46 #include "content/browser/renderer_host/pepper/pepper_security_helper.h"
47 #include "ppapi/shared_impl/file_type_conversion.h"
48 #endif // defined(ENABLE_PLUGINS)
50 using fileapi::FileSystemFileUtil;
51 using fileapi::FileSystemBackend;
52 using fileapi::FileSystemOperation;
53 using fileapi::FileSystemURL;
54 using fileapi::FileUpdateObserver;
55 using fileapi::UpdateObserverList;
56 using webkit_blob::BlobData;
57 using webkit_blob::BlobStorageContext;
58 using webkit_blob::BlobStorageHost;
64 void RevokeFilePermission(int child_id, const base::FilePath& path) {
65 ChildProcessSecurityPolicyImpl::GetInstance()->RevokeAllPermissionsForFile(
71 FileAPIMessageFilter::FileAPIMessageFilter(
73 net::URLRequestContextGetter* request_context_getter,
74 fileapi::FileSystemContext* file_system_context,
75 ChromeBlobStorageContext* blob_storage_context,
76 StreamContext* stream_context)
77 : process_id_(process_id),
78 context_(file_system_context),
79 security_policy_(ChildProcessSecurityPolicyImpl::GetInstance()),
80 request_context_getter_(request_context_getter),
81 request_context_(NULL),
82 blob_storage_context_(blob_storage_context),
83 stream_context_(stream_context) {
85 DCHECK(request_context_getter_.get());
86 DCHECK(blob_storage_context);
87 DCHECK(stream_context);
90 FileAPIMessageFilter::FileAPIMessageFilter(
92 net::URLRequestContext* request_context,
93 fileapi::FileSystemContext* file_system_context,
94 ChromeBlobStorageContext* blob_storage_context,
95 StreamContext* stream_context)
96 : process_id_(process_id),
97 context_(file_system_context),
98 security_policy_(ChildProcessSecurityPolicyImpl::GetInstance()),
99 request_context_(request_context),
100 blob_storage_context_(blob_storage_context),
101 stream_context_(stream_context) {
103 DCHECK(request_context_);
104 DCHECK(blob_storage_context);
105 DCHECK(stream_context);
108 void FileAPIMessageFilter::OnChannelConnected(int32 peer_pid) {
109 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
111 if (request_context_getter_.get()) {
112 DCHECK(!request_context_);
113 request_context_ = request_context_getter_->GetURLRequestContext();
114 request_context_getter_ = NULL;
115 DCHECK(request_context_);
118 blob_storage_host_.reset(
119 new BlobStorageHost(blob_storage_context_->context()));
121 operation_runner_ = context_->CreateFileSystemOperationRunner();
124 void FileAPIMessageFilter::OnChannelClosing() {
125 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
127 // Unregister all the blob and stream URLs that are previously registered in
129 blob_storage_host_.reset();
130 for (base::hash_set<std::string>::const_iterator iter = stream_urls_.begin();
131 iter != stream_urls_.end(); ++iter) {
132 stream_context_->registry()->UnregisterStream(GURL(*iter));
135 in_transit_snapshot_files_.clear();
137 // Close all files that are previously OpenFile()'ed in this process.
138 if (!on_close_callbacks_.IsEmpty()) {
140 << "File API: Renderer process shut down before NotifyCloseFile"
141 << " for " << on_close_callbacks_.size() << " files opened in PPAPI";
144 for (OnCloseCallbackMap::iterator itr(&on_close_callbacks_);
145 !itr.IsAtEnd(); itr.Advance()) {
146 const base::Closure* callback = itr.GetCurrentValue();
148 if (!callback->is_null())
152 on_close_callbacks_.Clear();
153 operation_runner_.reset();
157 base::TaskRunner* FileAPIMessageFilter::OverrideTaskRunnerForMessage(
158 const IPC::Message& message) {
159 if (message.type() == FileSystemHostMsg_SyncGetPlatformPath::ID)
160 return context_->default_file_task_runner();
164 bool FileAPIMessageFilter::OnMessageReceived(
165 const IPC::Message& message, bool* message_was_ok) {
166 *message_was_ok = true;
168 IPC_BEGIN_MESSAGE_MAP_EX(FileAPIMessageFilter, message, *message_was_ok)
169 IPC_MESSAGE_HANDLER(FileSystemHostMsg_OpenFileSystem, OnOpenFileSystem)
170 IPC_MESSAGE_HANDLER(FileSystemHostMsg_ResolveURL, OnResolveURL)
171 IPC_MESSAGE_HANDLER(FileSystemHostMsg_DeleteFileSystem, OnDeleteFileSystem)
172 IPC_MESSAGE_HANDLER(FileSystemHostMsg_Move, OnMove)
173 IPC_MESSAGE_HANDLER(FileSystemHostMsg_Copy, OnCopy)
174 IPC_MESSAGE_HANDLER(FileSystemHostMsg_Remove, OnRemove)
175 IPC_MESSAGE_HANDLER(FileSystemHostMsg_ReadMetadata, OnReadMetadata)
176 IPC_MESSAGE_HANDLER(FileSystemHostMsg_Create, OnCreate)
177 IPC_MESSAGE_HANDLER(FileSystemHostMsg_Exists, OnExists)
178 IPC_MESSAGE_HANDLER(FileSystemHostMsg_ReadDirectory, OnReadDirectory)
179 IPC_MESSAGE_HANDLER(FileSystemHostMsg_Write, OnWrite)
180 IPC_MESSAGE_HANDLER(FileSystemHostMsg_Truncate, OnTruncate)
181 IPC_MESSAGE_HANDLER(FileSystemHostMsg_TouchFile, OnTouchFile)
182 IPC_MESSAGE_HANDLER(FileSystemHostMsg_CancelWrite, OnCancel)
183 #if defined(ENABLE_PLUGINS)
184 IPC_MESSAGE_HANDLER(FileSystemHostMsg_OpenPepperFile, OnOpenPepperFile)
185 #endif // defined(ENABLE_PLUGINS)
186 IPC_MESSAGE_HANDLER(FileSystemHostMsg_NotifyCloseFile, OnNotifyCloseFile)
187 IPC_MESSAGE_HANDLER(FileSystemHostMsg_CreateSnapshotFile,
188 OnCreateSnapshotFile)
189 IPC_MESSAGE_HANDLER(FileSystemHostMsg_DidReceiveSnapshotFile,
190 OnDidReceiveSnapshotFile)
191 IPC_MESSAGE_HANDLER(FileSystemHostMsg_WillUpdate, OnWillUpdate)
192 IPC_MESSAGE_HANDLER(FileSystemHostMsg_DidUpdate, OnDidUpdate)
193 IPC_MESSAGE_HANDLER(FileSystemHostMsg_SyncGetPlatformPath,
194 OnSyncGetPlatformPath)
195 IPC_MESSAGE_HANDLER(BlobHostMsg_StartBuilding, OnStartBuildingBlob)
196 IPC_MESSAGE_HANDLER(BlobHostMsg_AppendBlobDataItem,
197 OnAppendBlobDataItemToBlob)
198 IPC_MESSAGE_HANDLER(BlobHostMsg_SyncAppendSharedMemory,
199 OnAppendSharedMemoryToBlob)
200 IPC_MESSAGE_HANDLER(BlobHostMsg_FinishBuilding, OnFinishBuildingBlob)
201 IPC_MESSAGE_HANDLER(BlobHostMsg_IncrementRefCount,
202 OnIncrementBlobRefCount)
203 IPC_MESSAGE_HANDLER(BlobHostMsg_DecrementRefCount,
204 OnDecrementBlobRefCount)
205 IPC_MESSAGE_HANDLER(BlobHostMsg_RegisterPublicURL,
206 OnRegisterPublicBlobURL)
207 IPC_MESSAGE_HANDLER(BlobHostMsg_RevokePublicURL, OnRevokePublicBlobURL)
208 IPC_MESSAGE_HANDLER(StreamHostMsg_StartBuilding, OnStartBuildingStream)
209 IPC_MESSAGE_HANDLER(StreamHostMsg_AppendBlobDataItem,
210 OnAppendBlobDataItemToStream)
211 IPC_MESSAGE_HANDLER(StreamHostMsg_SyncAppendSharedMemory,
212 OnAppendSharedMemoryToStream)
213 IPC_MESSAGE_HANDLER(StreamHostMsg_FinishBuilding, OnFinishBuildingStream)
214 IPC_MESSAGE_HANDLER(StreamHostMsg_AbortBuilding, OnAbortBuildingStream)
215 IPC_MESSAGE_HANDLER(StreamHostMsg_Clone, OnCloneStream)
216 IPC_MESSAGE_HANDLER(StreamHostMsg_Remove, OnRemoveStream)
217 IPC_MESSAGE_UNHANDLED(handled = false)
218 IPC_END_MESSAGE_MAP_EX()
222 FileAPIMessageFilter::~FileAPIMessageFilter() {}
224 void FileAPIMessageFilter::BadMessageReceived() {
225 RecordAction(UserMetricsAction("BadMessageTerminate_FAMF"));
226 BrowserMessageFilter::BadMessageReceived();
229 void FileAPIMessageFilter::OnOpenFileSystem(int request_id,
230 const GURL& origin_url,
231 fileapi::FileSystemType type) {
232 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
233 if (type == fileapi::kFileSystemTypeTemporary) {
234 RecordAction(UserMetricsAction("OpenFileSystemTemporary"));
235 } else if (type == fileapi::kFileSystemTypePersistent) {
236 RecordAction(UserMetricsAction("OpenFileSystemPersistent"));
238 fileapi::OpenFileSystemMode mode =
239 fileapi::OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT;
240 context_->OpenFileSystem(origin_url, type, mode, base::Bind(
241 &FileAPIMessageFilter::DidOpenFileSystem, this, request_id));
244 void FileAPIMessageFilter::OnResolveURL(
246 const GURL& filesystem_url) {
247 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
248 FileSystemURL url(context_->CrackURL(filesystem_url));
249 if (!ValidateFileSystemURL(request_id, url))
251 if (!security_policy_->CanReadFileSystemFile(process_id_, url)) {
252 Send(new FileSystemMsg_DidFail(request_id,
253 base::PLATFORM_FILE_ERROR_SECURITY));
257 context_->ResolveURL(url, base::Bind(
258 &FileAPIMessageFilter::DidResolveURL, this, request_id));
261 void FileAPIMessageFilter::OnDeleteFileSystem(
263 const GURL& origin_url,
264 fileapi::FileSystemType type) {
265 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
266 context_->DeleteFileSystem(origin_url, type, base::Bind(
267 &FileAPIMessageFilter::DidDeleteFileSystem, this, request_id));
270 void FileAPIMessageFilter::OnMove(
271 int request_id, const GURL& src_path, const GURL& dest_path) {
272 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
273 FileSystemURL src_url(context_->CrackURL(src_path));
274 FileSystemURL dest_url(context_->CrackURL(dest_path));
275 if (!ValidateFileSystemURL(request_id, src_url) ||
276 !ValidateFileSystemURL(request_id, dest_url)) {
279 if (!security_policy_->CanReadFileSystemFile(process_id_, src_url) ||
280 !security_policy_->CanDeleteFileSystemFile(process_id_, src_url) ||
281 !security_policy_->CanCreateFileSystemFile(process_id_, dest_url)) {
282 Send(new FileSystemMsg_DidFail(request_id,
283 base::PLATFORM_FILE_ERROR_SECURITY));
287 operations_[request_id] = operation_runner()->Move(
289 fileapi::FileSystemOperation::OPTION_NONE,
290 base::Bind(&FileAPIMessageFilter::DidFinish, this, request_id));
293 void FileAPIMessageFilter::OnCopy(
294 int request_id, const GURL& src_path, const GURL& dest_path) {
295 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
296 FileSystemURL src_url(context_->CrackURL(src_path));
297 FileSystemURL dest_url(context_->CrackURL(dest_path));
298 if (!ValidateFileSystemURL(request_id, src_url) ||
299 !ValidateFileSystemURL(request_id, dest_url)) {
302 if (!security_policy_->CanReadFileSystemFile(process_id_, src_url) ||
303 !security_policy_->CanCopyIntoFileSystemFile(process_id_, dest_url)) {
304 Send(new FileSystemMsg_DidFail(request_id,
305 base::PLATFORM_FILE_ERROR_SECURITY));
309 operations_[request_id] = operation_runner()->Copy(
311 fileapi::FileSystemOperation::OPTION_NONE,
312 fileapi::FileSystemOperationRunner::CopyProgressCallback(),
313 base::Bind(&FileAPIMessageFilter::DidFinish, this, request_id));
316 void FileAPIMessageFilter::OnRemove(
317 int request_id, const GURL& path, bool recursive) {
318 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
319 FileSystemURL url(context_->CrackURL(path));
320 if (!ValidateFileSystemURL(request_id, url))
322 if (!security_policy_->CanDeleteFileSystemFile(process_id_, url)) {
323 Send(new FileSystemMsg_DidFail(request_id,
324 base::PLATFORM_FILE_ERROR_SECURITY));
328 operations_[request_id] = operation_runner()->Remove(
330 base::Bind(&FileAPIMessageFilter::DidFinish, this, request_id));
333 void FileAPIMessageFilter::OnReadMetadata(
334 int request_id, const GURL& path) {
335 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
336 FileSystemURL url(context_->CrackURL(path));
337 if (!ValidateFileSystemURL(request_id, url))
339 if (!security_policy_->CanReadFileSystemFile(process_id_, url)) {
340 Send(new FileSystemMsg_DidFail(request_id,
341 base::PLATFORM_FILE_ERROR_SECURITY));
345 operations_[request_id] = operation_runner()->GetMetadata(
346 url, base::Bind(&FileAPIMessageFilter::DidGetMetadata, this, request_id));
349 void FileAPIMessageFilter::OnCreate(
350 int request_id, const GURL& path, bool exclusive,
351 bool is_directory, bool recursive) {
352 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
353 FileSystemURL url(context_->CrackURL(path));
354 if (!ValidateFileSystemURL(request_id, url))
356 if (!security_policy_->CanCreateFileSystemFile(process_id_, url)) {
357 Send(new FileSystemMsg_DidFail(request_id,
358 base::PLATFORM_FILE_ERROR_SECURITY));
363 operations_[request_id] = operation_runner()->CreateDirectory(
364 url, exclusive, recursive,
365 base::Bind(&FileAPIMessageFilter::DidFinish, this, request_id));
367 operations_[request_id] = operation_runner()->CreateFile(
369 base::Bind(&FileAPIMessageFilter::DidFinish, this, request_id));
373 void FileAPIMessageFilter::OnExists(
374 int request_id, const GURL& path, bool is_directory) {
375 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
376 FileSystemURL url(context_->CrackURL(path));
377 if (!ValidateFileSystemURL(request_id, url))
379 if (!security_policy_->CanReadFileSystemFile(process_id_, url)) {
380 Send(new FileSystemMsg_DidFail(request_id,
381 base::PLATFORM_FILE_ERROR_SECURITY));
386 operations_[request_id] = operation_runner()->DirectoryExists(
388 base::Bind(&FileAPIMessageFilter::DidFinish, this, request_id));
390 operations_[request_id] = operation_runner()->FileExists(
392 base::Bind(&FileAPIMessageFilter::DidFinish, this, request_id));
396 void FileAPIMessageFilter::OnReadDirectory(
397 int request_id, const GURL& path) {
398 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
399 FileSystemURL url(context_->CrackURL(path));
400 if (!ValidateFileSystemURL(request_id, url))
402 if (!security_policy_->CanReadFileSystemFile(process_id_, url)) {
403 Send(new FileSystemMsg_DidFail(request_id,
404 base::PLATFORM_FILE_ERROR_SECURITY));
408 operations_[request_id] = operation_runner()->ReadDirectory(
409 url, base::Bind(&FileAPIMessageFilter::DidReadDirectory,
413 void FileAPIMessageFilter::OnWrite(
416 const std::string& blob_uuid,
418 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
419 if (!request_context_) {
420 // We can't write w/o a request context, trying to do so will crash.
425 FileSystemURL url(context_->CrackURL(path));
426 if (!ValidateFileSystemURL(request_id, url))
428 if (!security_policy_->CanWriteFileSystemFile(process_id_, url)) {
429 Send(new FileSystemMsg_DidFail(request_id,
430 base::PLATFORM_FILE_ERROR_SECURITY));
434 scoped_ptr<webkit_blob::BlobDataHandle> blob =
435 blob_storage_context_->context()->GetBlobDataFromUUID(blob_uuid);
437 operations_[request_id] = operation_runner()->Write(
438 request_context_, url, blob.Pass(), offset,
439 base::Bind(&FileAPIMessageFilter::DidWrite, this, request_id));
442 void FileAPIMessageFilter::OnTruncate(
446 FileSystemURL url(context_->CrackURL(path));
447 if (!ValidateFileSystemURL(request_id, url))
449 if (!security_policy_->CanWriteFileSystemFile(process_id_, url)) {
450 Send(new FileSystemMsg_DidFail(request_id,
451 base::PLATFORM_FILE_ERROR_SECURITY));
455 operations_[request_id] = operation_runner()->Truncate(
457 base::Bind(&FileAPIMessageFilter::DidFinish, this, request_id));
460 void FileAPIMessageFilter::OnTouchFile(
463 const base::Time& last_access_time,
464 const base::Time& last_modified_time) {
465 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
466 FileSystemURL url(context_->CrackURL(path));
467 if (!ValidateFileSystemURL(request_id, url))
469 if (!security_policy_->CanCreateFileSystemFile(process_id_, url)) {
470 Send(new FileSystemMsg_DidFail(request_id,
471 base::PLATFORM_FILE_ERROR_SECURITY));
475 operations_[request_id] = operation_runner()->TouchFile(
476 url, last_access_time, last_modified_time,
477 base::Bind(&FileAPIMessageFilter::DidFinish, this, request_id));
480 void FileAPIMessageFilter::OnCancel(
482 int request_id_to_cancel) {
483 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
485 OperationsMap::iterator found = operations_.find(request_id_to_cancel);
486 if (found != operations_.end()) {
487 // The cancel will eventually send both the write failure and the cancel
489 operation_runner()->Cancel(
491 base::Bind(&FileAPIMessageFilter::DidFinish, this, request_id));
493 // The write already finished; report that we failed to stop it.
494 Send(new FileSystemMsg_DidFail(
495 request_id, base::PLATFORM_FILE_ERROR_INVALID_OPERATION));
499 #if defined(ENABLE_PLUGINS)
500 void FileAPIMessageFilter::OnOpenPepperFile(
501 int request_id, const GURL& path, int pp_open_flags) {
502 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
503 FileSystemURL url(context_->CrackURL(path));
504 if (!ValidateFileSystemURL(request_id, url))
506 if (!CanOpenFileSystemURLWithPepperFlags(pp_open_flags, process_id_, url)) {
507 Send(new FileSystemMsg_DidFail(
508 request_id, base::PLATFORM_FILE_ERROR_SECURITY));
512 quota::QuotaLimitType quota_policy = quota::kQuotaLimitTypeUnknown;
513 quota::QuotaManagerProxy* quota_manager_proxy =
514 context_->quota_manager_proxy();
515 CHECK(quota_manager_proxy);
516 CHECK(quota_manager_proxy->quota_manager());
518 if (quota_manager_proxy->quota_manager()->IsStorageUnlimited(
519 url.origin(), FileSystemTypeToQuotaStorageType(url.type()))) {
520 quota_policy = quota::kQuotaLimitTypeUnlimited;
522 quota_policy = quota::kQuotaLimitTypeLimited;
525 int platform_file_flags = 0;
526 if (!ppapi::PepperFileOpenFlagsToPlatformFileFlags(pp_open_flags,
527 &platform_file_flags)) {
528 // |pp_open_flags| should have already been checked in PepperFileIOHost.
529 NOTREACHED() << "Open file request with invalid pp_open_flags ignored.";
532 operations_[request_id] = operation_runner()->OpenFile(
533 url, platform_file_flags, PeerHandle(),
534 base::Bind(&FileAPIMessageFilter::DidOpenFile, this, request_id,
537 #endif // defined(ENABLE_PLUGINS)
539 void FileAPIMessageFilter::OnNotifyCloseFile(int file_open_id) {
540 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
542 // Remove |file_open_id| from the map of |on_close_callback|s.
543 // It must only be called for a ID that is successfully opened and enrolled in
545 base::Closure* on_close_callback = on_close_callbacks_.Lookup(file_open_id);
546 if (on_close_callback && !on_close_callback->is_null()) {
547 on_close_callback->Run();
548 on_close_callbacks_.Remove(file_open_id);
552 void FileAPIMessageFilter::OnWillUpdate(const GURL& path) {
553 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
554 FileSystemURL url(context_->CrackURL(path));
557 const UpdateObserverList* observers =
558 context_->GetUpdateObservers(url.type());
561 observers->Notify(&FileUpdateObserver::OnStartUpdate, MakeTuple(url));
564 void FileAPIMessageFilter::OnDidUpdate(const GURL& path, int64 delta) {
565 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
566 FileSystemURL url(context_->CrackURL(path));
569 const UpdateObserverList* observers =
570 context_->GetUpdateObservers(url.type());
573 observers->Notify(&FileUpdateObserver::OnUpdate, MakeTuple(url, delta));
574 observers->Notify(&FileUpdateObserver::OnEndUpdate, MakeTuple(url));
577 void FileAPIMessageFilter::OnSyncGetPlatformPath(
578 const GURL& path, base::FilePath* platform_path) {
579 SyncGetPlatformPath(context_, process_id_, path, platform_path);
582 void FileAPIMessageFilter::OnCreateSnapshotFile(
583 int request_id, const GURL& path) {
584 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
585 FileSystemURL url(context_->CrackURL(path));
587 // Make sure if this file can be read by the renderer as this is
588 // called when the renderer is about to create a new File object
589 // (for reading the file).
590 if (!ValidateFileSystemURL(request_id, url))
592 if (!security_policy_->CanReadFileSystemFile(process_id_, url)) {
593 Send(new FileSystemMsg_DidFail(request_id,
594 base::PLATFORM_FILE_ERROR_SECURITY));
598 operations_[request_id] = operation_runner()->CreateSnapshotFile(
600 base::Bind(&FileAPIMessageFilter::DidCreateSnapshot,
601 this, request_id, url));
604 void FileAPIMessageFilter::OnDidReceiveSnapshotFile(int request_id) {
605 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
606 in_transit_snapshot_files_.erase(request_id);
609 void FileAPIMessageFilter::OnStartBuildingBlob(const std::string& uuid) {
610 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
611 ignore_result(blob_storage_host_->StartBuildingBlob(uuid));
614 void FileAPIMessageFilter::OnAppendBlobDataItemToBlob(
615 const std::string& uuid, const BlobData::Item& item) {
616 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
617 if (item.type() == BlobData::Item::TYPE_FILE_FILESYSTEM) {
618 FileSystemURL filesystem_url(context_->CrackURL(item.filesystem_url()));
619 if (!FileSystemURLIsValid(context_, filesystem_url) ||
620 !security_policy_->CanReadFileSystemFile(process_id_, filesystem_url)) {
621 ignore_result(blob_storage_host_->CancelBuildingBlob(uuid));
625 if (item.type() == BlobData::Item::TYPE_FILE &&
626 !security_policy_->CanReadFile(process_id_, item.path())) {
627 ignore_result(blob_storage_host_->CancelBuildingBlob(uuid));
630 if (item.length() == 0) {
631 BadMessageReceived();
634 ignore_result(blob_storage_host_->AppendBlobDataItem(uuid, item));
637 void FileAPIMessageFilter::OnAppendSharedMemoryToBlob(
638 const std::string& uuid,
639 base::SharedMemoryHandle handle,
640 size_t buffer_size) {
641 DCHECK(base::SharedMemory::IsHandleValid(handle));
643 BadMessageReceived();
647 base::SharedMemory shared_memory(handle, true, PeerHandle());
649 base::SharedMemory shared_memory(handle, true);
651 if (!shared_memory.Map(buffer_size)) {
652 ignore_result(blob_storage_host_->CancelBuildingBlob(uuid));
657 item.SetToSharedBytes(static_cast<char*>(shared_memory.memory()),
659 ignore_result(blob_storage_host_->AppendBlobDataItem(uuid, item));
662 void FileAPIMessageFilter::OnFinishBuildingBlob(
663 const std::string& uuid, const std::string& content_type) {
664 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
665 ignore_result(blob_storage_host_->FinishBuildingBlob(uuid, content_type));
666 // TODO(michaeln): check return values once blink has migrated, crbug/174200
669 void FileAPIMessageFilter::OnIncrementBlobRefCount(const std::string& uuid) {
670 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
671 ignore_result(blob_storage_host_->IncrementBlobRefCount(uuid));
674 void FileAPIMessageFilter::OnDecrementBlobRefCount(const std::string& uuid) {
675 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
676 ignore_result(blob_storage_host_->DecrementBlobRefCount(uuid));
679 void FileAPIMessageFilter::OnRegisterPublicBlobURL(
680 const GURL& public_url, const std::string& uuid) {
681 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
682 ignore_result(blob_storage_host_->RegisterPublicBlobURL(public_url, uuid));
685 void FileAPIMessageFilter::OnRevokePublicBlobURL(const GURL& public_url) {
686 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
687 ignore_result(blob_storage_host_->RevokePublicBlobURL(public_url));
690 void FileAPIMessageFilter::OnStartBuildingStream(
691 const GURL& url, const std::string& content_type) {
692 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
693 // Only an internal Blob URL is expected here. See the BlobURL of the Blink.
694 if (!StartsWithASCII(
695 url.path(), "blobinternal%3A///", true /* case_sensitive */)) {
696 NOTREACHED() << "Malformed Stream URL: " << url.spec();
697 BadMessageReceived();
700 // Use an empty security origin for now. Stream accepts a security origin
701 // but how it's handled is not fixed yet.
702 new Stream(stream_context_->registry(),
703 NULL /* write_observer */,
705 stream_urls_.insert(url.spec());
708 void FileAPIMessageFilter::OnAppendBlobDataItemToStream(
709 const GURL& url, const BlobData::Item& item) {
710 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
712 scoped_refptr<Stream> stream(GetStreamForURL(url));
713 // Stream instances may be deleted on error. Just abort if there's no Stream
714 // instance for |url| in the registry.
718 // Data for stream is delivered as TYPE_BYTES item.
719 if (item.type() != BlobData::Item::TYPE_BYTES) {
720 BadMessageReceived();
723 stream->AddData(item.bytes(), item.length());
726 void FileAPIMessageFilter::OnAppendSharedMemoryToStream(
727 const GURL& url, base::SharedMemoryHandle handle, size_t buffer_size) {
728 DCHECK(base::SharedMemory::IsHandleValid(handle));
730 BadMessageReceived();
734 base::SharedMemory shared_memory(handle, true, PeerHandle());
736 base::SharedMemory shared_memory(handle, true);
738 if (!shared_memory.Map(buffer_size)) {
743 scoped_refptr<Stream> stream(GetStreamForURL(url));
747 stream->AddData(static_cast<char*>(shared_memory.memory()), buffer_size);
750 void FileAPIMessageFilter::OnFinishBuildingStream(const GURL& url) {
751 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
752 scoped_refptr<Stream> stream(GetStreamForURL(url));
757 void FileAPIMessageFilter::OnAbortBuildingStream(const GURL& url) {
758 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
759 scoped_refptr<Stream> stream(GetStreamForURL(url));
764 void FileAPIMessageFilter::OnCloneStream(
765 const GURL& url, const GURL& src_url) {
766 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
767 // Abort if there's no Stream instance for |src_url| (source Stream which
768 // we're going to make |url| point to) in the registry.
769 if (!GetStreamForURL(src_url))
772 stream_context_->registry()->CloneStream(url, src_url);
773 stream_urls_.insert(url.spec());
776 void FileAPIMessageFilter::OnRemoveStream(const GURL& url) {
777 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
779 if (!GetStreamForURL(url).get())
782 stream_context_->registry()->UnregisterStream(url);
783 stream_urls_.erase(url.spec());
786 void FileAPIMessageFilter::DidFinish(int request_id,
787 base::PlatformFileError result) {
788 if (result == base::PLATFORM_FILE_OK)
789 Send(new FileSystemMsg_DidSucceed(request_id));
791 Send(new FileSystemMsg_DidFail(request_id, result));
792 operations_.erase(request_id);
795 void FileAPIMessageFilter::DidGetMetadata(
797 base::PlatformFileError result,
798 const base::PlatformFileInfo& info) {
799 if (result == base::PLATFORM_FILE_OK)
800 Send(new FileSystemMsg_DidReadMetadata(request_id, info));
802 Send(new FileSystemMsg_DidFail(request_id, result));
803 operations_.erase(request_id);
806 void FileAPIMessageFilter::DidReadDirectory(
808 base::PlatformFileError result,
809 const std::vector<fileapi::DirectoryEntry>& entries,
811 if (result == base::PLATFORM_FILE_OK)
812 Send(new FileSystemMsg_DidReadDirectory(request_id, entries, has_more));
814 Send(new FileSystemMsg_DidFail(request_id, result));
815 operations_.erase(request_id);
818 void FileAPIMessageFilter::DidOpenFile(int request_id,
819 quota::QuotaLimitType quota_policy,
820 base::PlatformFileError result,
821 base::PlatformFile file,
822 const base::Closure& on_close_callback,
823 base::ProcessHandle peer_handle) {
824 if (result == base::PLATFORM_FILE_OK) {
825 IPC::PlatformFileForTransit file_for_transit =
826 file != base::kInvalidPlatformFileValue ?
827 IPC::GetFileHandleForProcess(file, peer_handle, true) :
828 IPC::InvalidPlatformFileForTransit();
829 int file_open_id = on_close_callbacks_.Add(
830 new base::Closure(on_close_callback));
832 Send(new FileSystemMsg_DidOpenFile(request_id,
837 Send(new FileSystemMsg_DidFail(request_id,
840 operations_.erase(request_id);
843 void FileAPIMessageFilter::DidWrite(int request_id,
844 base::PlatformFileError result,
847 if (result == base::PLATFORM_FILE_OK) {
848 Send(new FileSystemMsg_DidWrite(request_id, bytes, complete));
850 operations_.erase(request_id);
852 Send(new FileSystemMsg_DidFail(request_id, result));
853 operations_.erase(request_id);
857 void FileAPIMessageFilter::DidOpenFileSystem(int request_id,
859 const std::string& filesystem_name,
860 base::PlatformFileError result) {
861 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
862 if (result == base::PLATFORM_FILE_OK) {
863 DCHECK(root.is_valid());
864 Send(new FileSystemMsg_DidOpenFileSystem(
865 request_id, filesystem_name, root));
867 Send(new FileSystemMsg_DidFail(request_id, result));
869 // For OpenFileSystem we do not create a new operation, so no unregister here.
872 void FileAPIMessageFilter::DidResolveURL(int request_id,
873 base::PlatformFileError result,
874 const fileapi::FileSystemInfo& info,
875 const base::FilePath& file_path,
877 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
878 if (result == base::PLATFORM_FILE_OK) {
879 DCHECK(info.root_url.is_valid());
880 Send(new FileSystemMsg_DidResolveURL(
881 request_id, info, file_path, is_directory));
883 Send(new FileSystemMsg_DidFail(request_id, result));
885 // For ResolveURL we do not create a new operation, so no unregister here.
888 void FileAPIMessageFilter::DidDeleteFileSystem(
890 base::PlatformFileError result) {
891 if (result == base::PLATFORM_FILE_OK)
892 Send(new FileSystemMsg_DidSucceed(request_id));
894 Send(new FileSystemMsg_DidFail(request_id, result));
895 // For DeleteFileSystem we do not create a new operation,
896 // so no unregister here.
899 void FileAPIMessageFilter::DidCreateSnapshot(
901 const fileapi::FileSystemURL& url,
902 base::PlatformFileError result,
903 const base::PlatformFileInfo& info,
904 const base::FilePath& platform_path,
905 const scoped_refptr<webkit_blob::ShareableFileReference>& /* unused */) {
906 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
907 operations_.erase(request_id);
909 if (result != base::PLATFORM_FILE_OK) {
910 Send(new FileSystemMsg_DidFail(request_id, result));
914 scoped_refptr<webkit_blob::ShareableFileReference> file_ref =
915 webkit_blob::ShareableFileReference::Get(platform_path);
916 if (!security_policy_->CanReadFile(process_id_, platform_path)) {
917 // Give per-file read permission to the snapshot file if it hasn't it yet.
918 // In order for the renderer to be able to read the file via File object,
919 // it must be granted per-file read permission for the file's platform
920 // path. By now, it has already been verified that the renderer has
921 // sufficient permissions to read the file, so giving per-file permission
922 // here must be safe.
923 security_policy_->GrantReadFile(process_id_, platform_path);
925 // Revoke all permissions for the file when the last ref of the file
927 if (!file_ref.get()) {
928 // Create a reference for temporary permission handling.
929 file_ref = webkit_blob::ShareableFileReference::GetOrCreate(
931 webkit_blob::ShareableFileReference::DONT_DELETE_ON_FINAL_RELEASE,
932 context_->default_file_task_runner());
934 file_ref->AddFinalReleaseCallback(
935 base::Bind(&RevokeFilePermission, process_id_));
938 if (file_ref.get()) {
939 // This ref is held until OnDidReceiveSnapshotFile is called.
940 in_transit_snapshot_files_[request_id] = file_ref;
943 // Return the file info and platform_path.
944 Send(new FileSystemMsg_DidCreateSnapshotFile(
945 request_id, info, platform_path));
948 bool FileAPIMessageFilter::ValidateFileSystemURL(
949 int request_id, const fileapi::FileSystemURL& url) {
950 if (FileSystemURLIsValid(context_, url))
952 Send(new FileSystemMsg_DidFail(request_id,
953 base::PLATFORM_FILE_ERROR_INVALID_URL));
957 scoped_refptr<Stream> FileAPIMessageFilter::GetStreamForURL(const GURL& url) {
958 return stream_context_->registry()->GetStream(url);
961 } // namespace content