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/blob_storage_host.h"
21 #include "content/browser/fileapi/browser_file_system_helper.h"
22 #include "content/browser/fileapi/chrome_blob_storage_context.h"
23 #include "content/browser/streams/stream_registry.h"
24 #include "content/common/fileapi/file_system_messages.h"
25 #include "content/common/fileapi/webblob_messages.h"
26 #include "content/public/browser/user_metrics.h"
27 #include "ipc/ipc_platform_file.h"
28 #include "net/base/mime_util.h"
29 #include "net/url_request/url_request_context.h"
30 #include "net/url_request/url_request_context_getter.h"
32 #include "webkit/browser/blob/blob_storage_context.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/common/blob/blob_data.h"
38 #include "webkit/common/blob/shareable_file_reference.h"
39 #include "webkit/common/fileapi/directory_entry.h"
40 #include "webkit/common/fileapi/file_system_info.h"
41 #include "webkit/common/fileapi/file_system_types.h"
42 #include "webkit/common/fileapi/file_system_util.h"
44 using fileapi::FileSystemFileUtil;
45 using fileapi::FileSystemBackend;
46 using fileapi::FileSystemOperation;
47 using fileapi::FileSystemURL;
48 using webkit_blob::BlobData;
49 using webkit_blob::BlobStorageContext;
55 const uint32 kFilteredMessageClasses[] = {
60 void RevokeFilePermission(int child_id, const base::FilePath& path) {
61 ChildProcessSecurityPolicyImpl::GetInstance()->RevokeAllPermissionsForFile(
67 FileAPIMessageFilter::FileAPIMessageFilter(
69 net::URLRequestContextGetter* request_context_getter,
70 fileapi::FileSystemContext* file_system_context,
71 ChromeBlobStorageContext* blob_storage_context,
72 StreamContext* stream_context)
73 : BrowserMessageFilter(
74 kFilteredMessageClasses, arraysize(kFilteredMessageClasses)),
75 process_id_(process_id),
76 context_(file_system_context),
77 security_policy_(ChildProcessSecurityPolicyImpl::GetInstance()),
78 request_context_getter_(request_context_getter),
79 request_context_(NULL),
80 blob_storage_context_(blob_storage_context),
81 stream_context_(stream_context) {
83 DCHECK(request_context_getter_.get());
84 DCHECK(blob_storage_context);
85 DCHECK(stream_context);
88 FileAPIMessageFilter::FileAPIMessageFilter(
90 net::URLRequestContext* request_context,
91 fileapi::FileSystemContext* file_system_context,
92 ChromeBlobStorageContext* blob_storage_context,
93 StreamContext* stream_context)
94 : BrowserMessageFilter(
95 kFilteredMessageClasses, arraysize(kFilteredMessageClasses)),
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 operation_runner_.reset();
141 base::TaskRunner* FileAPIMessageFilter::OverrideTaskRunnerForMessage(
142 const IPC::Message& message) {
143 if (message.type() == FileSystemHostMsg_SyncGetPlatformPath::ID)
144 return context_->default_file_task_runner();
148 bool FileAPIMessageFilter::OnMessageReceived(
149 const IPC::Message& message, bool* message_was_ok) {
150 *message_was_ok = true;
152 IPC_BEGIN_MESSAGE_MAP_EX(FileAPIMessageFilter, message, *message_was_ok)
153 IPC_MESSAGE_HANDLER(FileSystemHostMsg_OpenFileSystem, OnOpenFileSystem)
154 IPC_MESSAGE_HANDLER(FileSystemHostMsg_ResolveURL, OnResolveURL)
155 IPC_MESSAGE_HANDLER(FileSystemHostMsg_DeleteFileSystem, OnDeleteFileSystem)
156 IPC_MESSAGE_HANDLER(FileSystemHostMsg_Move, OnMove)
157 IPC_MESSAGE_HANDLER(FileSystemHostMsg_Copy, OnCopy)
158 IPC_MESSAGE_HANDLER(FileSystemHostMsg_Remove, OnRemove)
159 IPC_MESSAGE_HANDLER(FileSystemHostMsg_ReadMetadata, OnReadMetadata)
160 IPC_MESSAGE_HANDLER(FileSystemHostMsg_Create, OnCreate)
161 IPC_MESSAGE_HANDLER(FileSystemHostMsg_Exists, OnExists)
162 IPC_MESSAGE_HANDLER(FileSystemHostMsg_ReadDirectory, OnReadDirectory)
163 IPC_MESSAGE_HANDLER(FileSystemHostMsg_Write, OnWrite)
164 IPC_MESSAGE_HANDLER(FileSystemHostMsg_Truncate, OnTruncate)
165 IPC_MESSAGE_HANDLER(FileSystemHostMsg_TouchFile, OnTouchFile)
166 IPC_MESSAGE_HANDLER(FileSystemHostMsg_CancelWrite, OnCancel)
167 IPC_MESSAGE_HANDLER(FileSystemHostMsg_CreateSnapshotFile,
168 OnCreateSnapshotFile)
169 IPC_MESSAGE_HANDLER(FileSystemHostMsg_DidReceiveSnapshotFile,
170 OnDidReceiveSnapshotFile)
171 IPC_MESSAGE_HANDLER(FileSystemHostMsg_SyncGetPlatformPath,
172 OnSyncGetPlatformPath)
173 IPC_MESSAGE_HANDLER(BlobHostMsg_StartBuilding, OnStartBuildingBlob)
174 IPC_MESSAGE_HANDLER(BlobHostMsg_AppendBlobDataItem,
175 OnAppendBlobDataItemToBlob)
176 IPC_MESSAGE_HANDLER(BlobHostMsg_SyncAppendSharedMemory,
177 OnAppendSharedMemoryToBlob)
178 IPC_MESSAGE_HANDLER(BlobHostMsg_FinishBuilding, OnFinishBuildingBlob)
179 IPC_MESSAGE_HANDLER(BlobHostMsg_IncrementRefCount,
180 OnIncrementBlobRefCount)
181 IPC_MESSAGE_HANDLER(BlobHostMsg_DecrementRefCount,
182 OnDecrementBlobRefCount)
183 IPC_MESSAGE_HANDLER(BlobHostMsg_RegisterPublicURL,
184 OnRegisterPublicBlobURL)
185 IPC_MESSAGE_HANDLER(BlobHostMsg_RevokePublicURL, OnRevokePublicBlobURL)
186 IPC_MESSAGE_HANDLER(StreamHostMsg_StartBuilding, OnStartBuildingStream)
187 IPC_MESSAGE_HANDLER(StreamHostMsg_AppendBlobDataItem,
188 OnAppendBlobDataItemToStream)
189 IPC_MESSAGE_HANDLER(StreamHostMsg_SyncAppendSharedMemory,
190 OnAppendSharedMemoryToStream)
191 IPC_MESSAGE_HANDLER(StreamHostMsg_FinishBuilding, OnFinishBuildingStream)
192 IPC_MESSAGE_HANDLER(StreamHostMsg_AbortBuilding, OnAbortBuildingStream)
193 IPC_MESSAGE_HANDLER(StreamHostMsg_Clone, OnCloneStream)
194 IPC_MESSAGE_HANDLER(StreamHostMsg_Remove, OnRemoveStream)
195 IPC_MESSAGE_UNHANDLED(handled = false)
196 IPC_END_MESSAGE_MAP_EX()
200 FileAPIMessageFilter::~FileAPIMessageFilter() {}
202 void FileAPIMessageFilter::BadMessageReceived() {
203 RecordAction(base::UserMetricsAction("BadMessageTerminate_FAMF"));
204 BrowserMessageFilter::BadMessageReceived();
207 void FileAPIMessageFilter::OnOpenFileSystem(int request_id,
208 const GURL& origin_url,
209 fileapi::FileSystemType type) {
210 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
211 if (type == fileapi::kFileSystemTypeTemporary) {
212 RecordAction(base::UserMetricsAction("OpenFileSystemTemporary"));
213 } else if (type == fileapi::kFileSystemTypePersistent) {
214 RecordAction(base::UserMetricsAction("OpenFileSystemPersistent"));
216 fileapi::OpenFileSystemMode mode =
217 fileapi::OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT;
218 context_->OpenFileSystem(origin_url, type, mode, base::Bind(
219 &FileAPIMessageFilter::DidOpenFileSystem, this, request_id));
222 void FileAPIMessageFilter::OnResolveURL(
224 const GURL& filesystem_url) {
225 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
226 FileSystemURL url(context_->CrackURL(filesystem_url));
227 if (!ValidateFileSystemURL(request_id, url))
229 if (!security_policy_->CanReadFileSystemFile(process_id_, url)) {
230 Send(new FileSystemMsg_DidFail(request_id,
231 base::File::FILE_ERROR_SECURITY));
235 context_->ResolveURL(url, base::Bind(
236 &FileAPIMessageFilter::DidResolveURL, this, request_id));
239 void FileAPIMessageFilter::OnDeleteFileSystem(
241 const GURL& origin_url,
242 fileapi::FileSystemType type) {
243 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
244 context_->DeleteFileSystem(origin_url, type, base::Bind(
245 &FileAPIMessageFilter::DidDeleteFileSystem, this, request_id));
248 void FileAPIMessageFilter::OnMove(
249 int request_id, const GURL& src_path, const GURL& dest_path) {
250 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
251 FileSystemURL src_url(context_->CrackURL(src_path));
252 FileSystemURL dest_url(context_->CrackURL(dest_path));
253 if (!ValidateFileSystemURL(request_id, src_url) ||
254 !ValidateFileSystemURL(request_id, dest_url)) {
257 if (!security_policy_->CanReadFileSystemFile(process_id_, src_url) ||
258 !security_policy_->CanDeleteFileSystemFile(process_id_, src_url) ||
259 !security_policy_->CanCreateFileSystemFile(process_id_, dest_url)) {
260 Send(new FileSystemMsg_DidFail(request_id,
261 base::File::FILE_ERROR_SECURITY));
265 operations_[request_id] = operation_runner()->Move(
267 fileapi::FileSystemOperation::OPTION_NONE,
268 base::Bind(&FileAPIMessageFilter::DidFinish, this, request_id));
271 void FileAPIMessageFilter::OnCopy(
272 int request_id, const GURL& src_path, const GURL& dest_path) {
273 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
274 FileSystemURL src_url(context_->CrackURL(src_path));
275 FileSystemURL dest_url(context_->CrackURL(dest_path));
276 if (!ValidateFileSystemURL(request_id, src_url) ||
277 !ValidateFileSystemURL(request_id, dest_url)) {
280 if (!security_policy_->CanReadFileSystemFile(process_id_, src_url) ||
281 !security_policy_->CanCopyIntoFileSystemFile(process_id_, dest_url)) {
282 Send(new FileSystemMsg_DidFail(request_id,
283 base::File::FILE_ERROR_SECURITY));
287 operations_[request_id] = operation_runner()->Copy(
289 fileapi::FileSystemOperation::OPTION_NONE,
290 fileapi::FileSystemOperationRunner::CopyProgressCallback(),
291 base::Bind(&FileAPIMessageFilter::DidFinish, this, request_id));
294 void FileAPIMessageFilter::OnRemove(
295 int request_id, const GURL& path, bool recursive) {
296 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
297 FileSystemURL url(context_->CrackURL(path));
298 if (!ValidateFileSystemURL(request_id, url))
300 if (!security_policy_->CanDeleteFileSystemFile(process_id_, url)) {
301 Send(new FileSystemMsg_DidFail(request_id,
302 base::File::FILE_ERROR_SECURITY));
306 operations_[request_id] = operation_runner()->Remove(
308 base::Bind(&FileAPIMessageFilter::DidFinish, this, request_id));
311 void FileAPIMessageFilter::OnReadMetadata(
312 int request_id, const GURL& path) {
313 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
314 FileSystemURL url(context_->CrackURL(path));
315 if (!ValidateFileSystemURL(request_id, url))
317 if (!security_policy_->CanReadFileSystemFile(process_id_, url)) {
318 Send(new FileSystemMsg_DidFail(request_id,
319 base::File::FILE_ERROR_SECURITY));
323 operations_[request_id] = operation_runner()->GetMetadata(
324 url, base::Bind(&FileAPIMessageFilter::DidGetMetadata, this, request_id));
327 void FileAPIMessageFilter::OnCreate(
328 int request_id, const GURL& path, bool exclusive,
329 bool is_directory, bool recursive) {
330 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
331 FileSystemURL url(context_->CrackURL(path));
332 if (!ValidateFileSystemURL(request_id, url))
334 if (!security_policy_->CanCreateFileSystemFile(process_id_, url)) {
335 Send(new FileSystemMsg_DidFail(request_id,
336 base::File::FILE_ERROR_SECURITY));
341 operations_[request_id] = operation_runner()->CreateDirectory(
342 url, exclusive, recursive,
343 base::Bind(&FileAPIMessageFilter::DidFinish, this, request_id));
345 operations_[request_id] = operation_runner()->CreateFile(
347 base::Bind(&FileAPIMessageFilter::DidFinish, this, request_id));
351 void FileAPIMessageFilter::OnExists(
352 int request_id, const GURL& path, bool is_directory) {
353 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
354 FileSystemURL url(context_->CrackURL(path));
355 if (!ValidateFileSystemURL(request_id, url))
357 if (!security_policy_->CanReadFileSystemFile(process_id_, url)) {
358 Send(new FileSystemMsg_DidFail(request_id,
359 base::File::FILE_ERROR_SECURITY));
364 operations_[request_id] = operation_runner()->DirectoryExists(
366 base::Bind(&FileAPIMessageFilter::DidFinish, this, request_id));
368 operations_[request_id] = operation_runner()->FileExists(
370 base::Bind(&FileAPIMessageFilter::DidFinish, this, request_id));
374 void FileAPIMessageFilter::OnReadDirectory(
375 int request_id, const GURL& path) {
376 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
377 FileSystemURL url(context_->CrackURL(path));
378 if (!ValidateFileSystemURL(request_id, url))
380 if (!security_policy_->CanReadFileSystemFile(process_id_, url)) {
381 Send(new FileSystemMsg_DidFail(request_id,
382 base::File::FILE_ERROR_SECURITY));
386 operations_[request_id] = operation_runner()->ReadDirectory(
387 url, base::Bind(&FileAPIMessageFilter::DidReadDirectory,
391 void FileAPIMessageFilter::OnWrite(
394 const std::string& blob_uuid,
396 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
397 if (!request_context_) {
398 // We can't write w/o a request context, trying to do so will crash.
403 FileSystemURL url(context_->CrackURL(path));
404 if (!ValidateFileSystemURL(request_id, url))
406 if (!security_policy_->CanWriteFileSystemFile(process_id_, url)) {
407 Send(new FileSystemMsg_DidFail(request_id,
408 base::File::FILE_ERROR_SECURITY));
412 scoped_ptr<webkit_blob::BlobDataHandle> blob =
413 blob_storage_context_->context()->GetBlobDataFromUUID(blob_uuid);
415 operations_[request_id] = operation_runner()->Write(
416 request_context_, url, blob.Pass(), offset,
417 base::Bind(&FileAPIMessageFilter::DidWrite, this, request_id));
420 void FileAPIMessageFilter::OnTruncate(
424 FileSystemURL url(context_->CrackURL(path));
425 if (!ValidateFileSystemURL(request_id, url))
427 if (!security_policy_->CanWriteFileSystemFile(process_id_, url)) {
428 Send(new FileSystemMsg_DidFail(request_id,
429 base::File::FILE_ERROR_SECURITY));
433 operations_[request_id] = operation_runner()->Truncate(
435 base::Bind(&FileAPIMessageFilter::DidFinish, this, request_id));
438 void FileAPIMessageFilter::OnTouchFile(
441 const base::Time& last_access_time,
442 const base::Time& last_modified_time) {
443 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
444 FileSystemURL url(context_->CrackURL(path));
445 if (!ValidateFileSystemURL(request_id, url))
447 if (!security_policy_->CanCreateFileSystemFile(process_id_, url)) {
448 Send(new FileSystemMsg_DidFail(request_id,
449 base::File::FILE_ERROR_SECURITY));
453 operations_[request_id] = operation_runner()->TouchFile(
454 url, last_access_time, last_modified_time,
455 base::Bind(&FileAPIMessageFilter::DidFinish, this, request_id));
458 void FileAPIMessageFilter::OnCancel(
460 int request_id_to_cancel) {
461 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
463 OperationsMap::iterator found = operations_.find(request_id_to_cancel);
464 if (found != operations_.end()) {
465 // The cancel will eventually send both the write failure and the cancel
467 operation_runner()->Cancel(
469 base::Bind(&FileAPIMessageFilter::DidFinish, this, request_id));
471 // The write already finished; report that we failed to stop it.
472 Send(new FileSystemMsg_DidFail(
473 request_id, base::File::FILE_ERROR_INVALID_OPERATION));
477 void FileAPIMessageFilter::OnSyncGetPlatformPath(
478 const GURL& path, base::FilePath* platform_path) {
479 SyncGetPlatformPath(context_, process_id_, path, platform_path);
482 void FileAPIMessageFilter::OnCreateSnapshotFile(
483 int request_id, const GURL& path) {
484 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
485 FileSystemURL url(context_->CrackURL(path));
487 // Make sure if this file can be read by the renderer as this is
488 // called when the renderer is about to create a new File object
489 // (for reading the file).
490 if (!ValidateFileSystemURL(request_id, url))
492 if (!security_policy_->CanReadFileSystemFile(process_id_, url)) {
493 Send(new FileSystemMsg_DidFail(request_id,
494 base::File::FILE_ERROR_SECURITY));
498 FileSystemBackend* backend = context_->GetFileSystemBackend(url.type());
499 if (backend->SupportsStreaming(url)) {
500 operations_[request_id] = operation_runner()->GetMetadata(
502 base::Bind(&FileAPIMessageFilter::DidGetMetadataForStreaming,
505 operations_[request_id] = operation_runner()->CreateSnapshotFile(
507 base::Bind(&FileAPIMessageFilter::DidCreateSnapshot,
508 this, request_id, url));
512 void FileAPIMessageFilter::OnDidReceiveSnapshotFile(int request_id) {
513 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
514 in_transit_snapshot_files_.erase(request_id);
517 void FileAPIMessageFilter::OnStartBuildingBlob(const std::string& uuid) {
518 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
519 ignore_result(blob_storage_host_->StartBuildingBlob(uuid));
522 void FileAPIMessageFilter::OnAppendBlobDataItemToBlob(
523 const std::string& uuid, const BlobData::Item& item) {
524 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
525 if (item.type() == BlobData::Item::TYPE_FILE_FILESYSTEM) {
526 FileSystemURL filesystem_url(context_->CrackURL(item.filesystem_url()));
527 if (!FileSystemURLIsValid(context_, filesystem_url) ||
528 !security_policy_->CanReadFileSystemFile(process_id_, filesystem_url)) {
529 ignore_result(blob_storage_host_->CancelBuildingBlob(uuid));
533 if (item.type() == BlobData::Item::TYPE_FILE &&
534 !security_policy_->CanReadFile(process_id_, item.path())) {
535 ignore_result(blob_storage_host_->CancelBuildingBlob(uuid));
538 if (item.length() == 0) {
539 BadMessageReceived();
542 ignore_result(blob_storage_host_->AppendBlobDataItem(uuid, item));
545 void FileAPIMessageFilter::OnAppendSharedMemoryToBlob(
546 const std::string& uuid,
547 base::SharedMemoryHandle handle,
548 size_t buffer_size) {
549 DCHECK(base::SharedMemory::IsHandleValid(handle));
551 BadMessageReceived();
555 base::SharedMemory shared_memory(handle, true, PeerHandle());
557 base::SharedMemory shared_memory(handle, true);
559 if (!shared_memory.Map(buffer_size)) {
560 ignore_result(blob_storage_host_->CancelBuildingBlob(uuid));
565 item.SetToSharedBytes(static_cast<char*>(shared_memory.memory()),
567 ignore_result(blob_storage_host_->AppendBlobDataItem(uuid, item));
570 void FileAPIMessageFilter::OnFinishBuildingBlob(
571 const std::string& uuid, const std::string& content_type) {
572 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
573 ignore_result(blob_storage_host_->FinishBuildingBlob(uuid, content_type));
574 // TODO(michaeln): check return values once blink has migrated, crbug/174200
577 void FileAPIMessageFilter::OnIncrementBlobRefCount(const std::string& uuid) {
578 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
579 ignore_result(blob_storage_host_->IncrementBlobRefCount(uuid));
582 void FileAPIMessageFilter::OnDecrementBlobRefCount(const std::string& uuid) {
583 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
584 ignore_result(blob_storage_host_->DecrementBlobRefCount(uuid));
587 void FileAPIMessageFilter::OnRegisterPublicBlobURL(
588 const GURL& public_url, const std::string& uuid) {
589 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
590 ignore_result(blob_storage_host_->RegisterPublicBlobURL(public_url, uuid));
593 void FileAPIMessageFilter::OnRevokePublicBlobURL(const GURL& public_url) {
594 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
595 ignore_result(blob_storage_host_->RevokePublicBlobURL(public_url));
598 void FileAPIMessageFilter::OnStartBuildingStream(
599 const GURL& url, const std::string& content_type) {
600 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
601 // Only an internal Blob URL is expected here. See the BlobURL of the Blink.
602 if (!StartsWithASCII(
603 url.path(), "blobinternal%3A///", true /* case_sensitive */)) {
604 NOTREACHED() << "Malformed Stream URL: " << url.spec();
605 BadMessageReceived();
608 // Use an empty security origin for now. Stream accepts a security origin
609 // but how it's handled is not fixed yet.
610 new Stream(stream_context_->registry(),
611 NULL /* write_observer */,
613 stream_urls_.insert(url.spec());
616 void FileAPIMessageFilter::OnAppendBlobDataItemToStream(
617 const GURL& url, const BlobData::Item& item) {
618 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
620 scoped_refptr<Stream> stream(GetStreamForURL(url));
621 // Stream instances may be deleted on error. Just abort if there's no Stream
622 // instance for |url| in the registry.
626 // Data for stream is delivered as TYPE_BYTES item.
627 if (item.type() != BlobData::Item::TYPE_BYTES) {
628 BadMessageReceived();
631 stream->AddData(item.bytes(), item.length());
634 void FileAPIMessageFilter::OnAppendSharedMemoryToStream(
635 const GURL& url, base::SharedMemoryHandle handle, size_t buffer_size) {
636 DCHECK(base::SharedMemory::IsHandleValid(handle));
638 BadMessageReceived();
642 base::SharedMemory shared_memory(handle, true, PeerHandle());
644 base::SharedMemory shared_memory(handle, true);
646 if (!shared_memory.Map(buffer_size)) {
651 scoped_refptr<Stream> stream(GetStreamForURL(url));
655 stream->AddData(static_cast<char*>(shared_memory.memory()), buffer_size);
658 void FileAPIMessageFilter::OnFinishBuildingStream(const GURL& url) {
659 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
660 scoped_refptr<Stream> stream(GetStreamForURL(url));
665 void FileAPIMessageFilter::OnAbortBuildingStream(const GURL& url) {
666 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
667 scoped_refptr<Stream> stream(GetStreamForURL(url));
672 void FileAPIMessageFilter::OnCloneStream(
673 const GURL& url, const GURL& src_url) {
674 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
675 // Abort if there's no Stream instance for |src_url| (source Stream which
676 // we're going to make |url| point to) in the registry.
677 if (!GetStreamForURL(src_url))
680 stream_context_->registry()->CloneStream(url, src_url);
681 stream_urls_.insert(url.spec());
684 void FileAPIMessageFilter::OnRemoveStream(const GURL& url) {
685 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
687 if (!GetStreamForURL(url).get())
690 stream_context_->registry()->UnregisterStream(url);
691 stream_urls_.erase(url.spec());
694 void FileAPIMessageFilter::DidFinish(int request_id,
695 base::File::Error result) {
696 if (result == base::File::FILE_OK)
697 Send(new FileSystemMsg_DidSucceed(request_id));
699 Send(new FileSystemMsg_DidFail(request_id, result));
700 operations_.erase(request_id);
703 void FileAPIMessageFilter::DidGetMetadata(
705 base::File::Error result,
706 const base::File::Info& info) {
707 if (result == base::File::FILE_OK)
708 Send(new FileSystemMsg_DidReadMetadata(request_id, info));
710 Send(new FileSystemMsg_DidFail(request_id, result));
711 operations_.erase(request_id);
714 void FileAPIMessageFilter::DidGetMetadataForStreaming(
716 base::File::Error result,
717 const base::File::Info& info) {
718 if (result == base::File::FILE_OK) {
719 // For now, streaming Blobs are implemented as a successful snapshot file
720 // creation with an empty path.
721 Send(new FileSystemMsg_DidCreateSnapshotFile(request_id, info,
724 Send(new FileSystemMsg_DidFail(request_id, result));
726 operations_.erase(request_id);
729 void FileAPIMessageFilter::DidReadDirectory(
731 base::File::Error result,
732 const std::vector<fileapi::DirectoryEntry>& entries,
734 if (result == base::File::FILE_OK) {
735 if (!entries.empty() || !has_more)
736 Send(new FileSystemMsg_DidReadDirectory(request_id, entries, has_more));
739 Send(new FileSystemMsg_DidFail(request_id, result));
742 operations_.erase(request_id);
745 void FileAPIMessageFilter::DidWrite(int request_id,
746 base::File::Error result,
749 if (result == base::File::FILE_OK) {
750 Send(new FileSystemMsg_DidWrite(request_id, bytes, complete));
752 operations_.erase(request_id);
754 Send(new FileSystemMsg_DidFail(request_id, result));
755 operations_.erase(request_id);
759 void FileAPIMessageFilter::DidOpenFileSystem(int request_id,
761 const std::string& filesystem_name,
762 base::File::Error result) {
763 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
764 if (result == base::File::FILE_OK) {
765 DCHECK(root.is_valid());
766 Send(new FileSystemMsg_DidOpenFileSystem(
767 request_id, filesystem_name, root));
769 Send(new FileSystemMsg_DidFail(request_id, result));
771 // For OpenFileSystem we do not create a new operation, so no unregister here.
774 void FileAPIMessageFilter::DidResolveURL(
776 base::File::Error result,
777 const fileapi::FileSystemInfo& info,
778 const base::FilePath& file_path,
779 fileapi::FileSystemContext::ResolvedEntryType type) {
780 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
781 if (result == base::File::FILE_OK &&
782 type == fileapi::FileSystemContext::RESOLVED_ENTRY_NOT_FOUND)
783 result = base::File::FILE_ERROR_NOT_FOUND;
785 if (result == base::File::FILE_OK) {
786 DCHECK(info.root_url.is_valid());
787 Send(new FileSystemMsg_DidResolveURL(
788 request_id, info, file_path,
789 type == fileapi::FileSystemContext::RESOLVED_ENTRY_DIRECTORY));
791 Send(new FileSystemMsg_DidFail(request_id, result));
793 // For ResolveURL we do not create a new operation, so no unregister here.
796 void FileAPIMessageFilter::DidDeleteFileSystem(
798 base::File::Error result) {
799 if (result == base::File::FILE_OK)
800 Send(new FileSystemMsg_DidSucceed(request_id));
802 Send(new FileSystemMsg_DidFail(request_id, result));
803 // For DeleteFileSystem we do not create a new operation,
804 // so no unregister here.
807 void FileAPIMessageFilter::DidCreateSnapshot(
809 const fileapi::FileSystemURL& url,
810 base::File::Error result,
811 const base::File::Info& info,
812 const base::FilePath& platform_path,
813 const scoped_refptr<webkit_blob::ShareableFileReference>& /* unused */) {
814 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
815 operations_.erase(request_id);
817 if (result != base::File::FILE_OK) {
818 Send(new FileSystemMsg_DidFail(request_id, result));
822 scoped_refptr<webkit_blob::ShareableFileReference> file_ref =
823 webkit_blob::ShareableFileReference::Get(platform_path);
824 if (!security_policy_->CanReadFile(process_id_, platform_path)) {
825 // Give per-file read permission to the snapshot file if it hasn't it yet.
826 // In order for the renderer to be able to read the file via File object,
827 // it must be granted per-file read permission for the file's platform
828 // path. By now, it has already been verified that the renderer has
829 // sufficient permissions to read the file, so giving per-file permission
830 // here must be safe.
831 security_policy_->GrantReadFile(process_id_, platform_path);
833 // Revoke all permissions for the file when the last ref of the file
835 if (!file_ref.get()) {
836 // Create a reference for temporary permission handling.
837 file_ref = webkit_blob::ShareableFileReference::GetOrCreate(
839 webkit_blob::ShareableFileReference::DONT_DELETE_ON_FINAL_RELEASE,
840 context_->default_file_task_runner());
842 file_ref->AddFinalReleaseCallback(
843 base::Bind(&RevokeFilePermission, process_id_));
846 if (file_ref.get()) {
847 // This ref is held until OnDidReceiveSnapshotFile is called.
848 in_transit_snapshot_files_[request_id] = file_ref;
851 // Return the file info and platform_path.
852 Send(new FileSystemMsg_DidCreateSnapshotFile(
853 request_id, info, platform_path));
856 bool FileAPIMessageFilter::ValidateFileSystemURL(
857 int request_id, const fileapi::FileSystemURL& url) {
858 if (!FileSystemURLIsValid(context_, url)) {
859 Send(new FileSystemMsg_DidFail(request_id,
860 base::File::FILE_ERROR_INVALID_URL));
864 // Deny access to files in PluginPrivate FileSystem from JavaScript.
865 // TODO(nhiroki): Move this filter somewhere else since this is not for
867 if (url.type() == fileapi::kFileSystemTypePluginPrivate) {
868 Send(new FileSystemMsg_DidFail(request_id,
869 base::File::FILE_ERROR_SECURITY));
876 scoped_refptr<Stream> FileAPIMessageFilter::GetStreamForURL(const GURL& url) {
877 return stream_context_->registry()->GetStream(url);
880 } // namespace content