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/sequenced_task_runner.h"
15 #include "base/strings/string_util.h"
16 #include "base/threading/thread.h"
17 #include "base/time/time.h"
18 #include "content/browser/child_process_security_policy_impl.h"
19 #include "content/browser/fileapi/blob_storage_host.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"
30 #include "storage/browser/blob/blob_storage_context.h"
31 #include "storage/browser/fileapi/file_observers.h"
32 #include "storage/browser/fileapi/file_permission_policy.h"
33 #include "storage/browser/fileapi/file_system_context.h"
34 #include "storage/browser/fileapi/isolated_context.h"
35 #include "storage/common/blob/blob_data.h"
36 #include "storage/common/blob/shareable_file_reference.h"
37 #include "storage/common/fileapi/directory_entry.h"
38 #include "storage/common/fileapi/file_system_info.h"
39 #include "storage/common/fileapi/file_system_types.h"
40 #include "storage/common/fileapi/file_system_util.h"
43 using storage::FileSystemFileUtil;
44 using storage::FileSystemBackend;
45 using storage::FileSystemOperation;
46 using storage::FileSystemURL;
47 using storage::BlobData;
48 using storage::BlobStorageContext;
54 const uint32 kFilteredMessageClasses[] = {
59 void RevokeFilePermission(int child_id, const base::FilePath& path) {
60 ChildProcessSecurityPolicyImpl::GetInstance()->RevokeAllPermissionsForFile(
66 FileAPIMessageFilter::FileAPIMessageFilter(
68 net::URLRequestContextGetter* request_context_getter,
69 storage::FileSystemContext* file_system_context,
70 ChromeBlobStorageContext* blob_storage_context,
71 StreamContext* stream_context)
72 : BrowserMessageFilter(kFilteredMessageClasses,
73 arraysize(kFilteredMessageClasses)),
74 process_id_(process_id),
75 context_(file_system_context),
76 security_policy_(ChildProcessSecurityPolicyImpl::GetInstance()),
77 request_context_getter_(request_context_getter),
78 request_context_(NULL),
79 blob_storage_context_(blob_storage_context),
80 stream_context_(stream_context) {
82 DCHECK(request_context_getter_.get());
83 DCHECK(blob_storage_context);
84 DCHECK(stream_context);
87 FileAPIMessageFilter::FileAPIMessageFilter(
89 net::URLRequestContext* request_context,
90 storage::FileSystemContext* file_system_context,
91 ChromeBlobStorageContext* blob_storage_context,
92 StreamContext* stream_context)
93 : BrowserMessageFilter(kFilteredMessageClasses,
94 arraysize(kFilteredMessageClasses)),
95 process_id_(process_id),
96 context_(file_system_context),
97 security_policy_(ChildProcessSecurityPolicyImpl::GetInstance()),
98 request_context_(request_context),
99 blob_storage_context_(blob_storage_context),
100 stream_context_(stream_context) {
102 DCHECK(request_context_);
103 DCHECK(blob_storage_context);
104 DCHECK(stream_context);
107 void FileAPIMessageFilter::OnChannelConnected(int32 peer_pid) {
108 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
110 if (request_context_getter_.get()) {
111 DCHECK(!request_context_);
112 request_context_ = request_context_getter_->GetURLRequestContext();
113 request_context_getter_ = NULL;
114 DCHECK(request_context_);
117 blob_storage_host_.reset(
118 new BlobStorageHost(blob_storage_context_->context()));
120 operation_runner_ = context_->CreateFileSystemOperationRunner();
123 void FileAPIMessageFilter::OnChannelClosing() {
124 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
126 // Unregister all the blob and stream URLs that are previously registered in
128 blob_storage_host_.reset();
129 for (base::hash_set<std::string>::const_iterator iter = stream_urls_.begin();
130 iter != stream_urls_.end(); ++iter) {
131 stream_context_->registry()->UnregisterStream(GURL(*iter));
134 in_transit_snapshot_files_.clear();
136 operation_runner_.reset();
140 base::TaskRunner* FileAPIMessageFilter::OverrideTaskRunnerForMessage(
141 const IPC::Message& message) {
142 if (message.type() == FileSystemHostMsg_SyncGetPlatformPath::ID)
143 return context_->default_file_task_runner();
147 bool FileAPIMessageFilter::OnMessageReceived(const IPC::Message& message) {
149 IPC_BEGIN_MESSAGE_MAP(FileAPIMessageFilter, message)
150 IPC_MESSAGE_HANDLER(FileSystemHostMsg_OpenFileSystem, OnOpenFileSystem)
151 IPC_MESSAGE_HANDLER(FileSystemHostMsg_ResolveURL, OnResolveURL)
152 IPC_MESSAGE_HANDLER(FileSystemHostMsg_DeleteFileSystem, OnDeleteFileSystem)
153 IPC_MESSAGE_HANDLER(FileSystemHostMsg_Move, OnMove)
154 IPC_MESSAGE_HANDLER(FileSystemHostMsg_Copy, OnCopy)
155 IPC_MESSAGE_HANDLER(FileSystemHostMsg_Remove, OnRemove)
156 IPC_MESSAGE_HANDLER(FileSystemHostMsg_ReadMetadata, OnReadMetadata)
157 IPC_MESSAGE_HANDLER(FileSystemHostMsg_Create, OnCreate)
158 IPC_MESSAGE_HANDLER(FileSystemHostMsg_Exists, OnExists)
159 IPC_MESSAGE_HANDLER(FileSystemHostMsg_ReadDirectory, OnReadDirectory)
160 IPC_MESSAGE_HANDLER(FileSystemHostMsg_Write, OnWrite)
161 IPC_MESSAGE_HANDLER(FileSystemHostMsg_Truncate, OnTruncate)
162 IPC_MESSAGE_HANDLER(FileSystemHostMsg_TouchFile, OnTouchFile)
163 IPC_MESSAGE_HANDLER(FileSystemHostMsg_CancelWrite, OnCancel)
164 IPC_MESSAGE_HANDLER(FileSystemHostMsg_CreateSnapshotFile,
165 OnCreateSnapshotFile)
166 IPC_MESSAGE_HANDLER(FileSystemHostMsg_DidReceiveSnapshotFile,
167 OnDidReceiveSnapshotFile)
168 IPC_MESSAGE_HANDLER(FileSystemHostMsg_SyncGetPlatformPath,
169 OnSyncGetPlatformPath)
170 IPC_MESSAGE_HANDLER(BlobHostMsg_StartBuilding, OnStartBuildingBlob)
171 IPC_MESSAGE_HANDLER(BlobHostMsg_AppendBlobDataItem,
172 OnAppendBlobDataItemToBlob)
173 IPC_MESSAGE_HANDLER(BlobHostMsg_SyncAppendSharedMemory,
174 OnAppendSharedMemoryToBlob)
175 IPC_MESSAGE_HANDLER(BlobHostMsg_FinishBuilding, OnFinishBuildingBlob)
176 IPC_MESSAGE_HANDLER(BlobHostMsg_IncrementRefCount,
177 OnIncrementBlobRefCount)
178 IPC_MESSAGE_HANDLER(BlobHostMsg_DecrementRefCount,
179 OnDecrementBlobRefCount)
180 IPC_MESSAGE_HANDLER(BlobHostMsg_RegisterPublicURL,
181 OnRegisterPublicBlobURL)
182 IPC_MESSAGE_HANDLER(BlobHostMsg_RevokePublicURL, OnRevokePublicBlobURL)
183 IPC_MESSAGE_HANDLER(StreamHostMsg_StartBuilding, OnStartBuildingStream)
184 IPC_MESSAGE_HANDLER(StreamHostMsg_AppendBlobDataItem,
185 OnAppendBlobDataItemToStream)
186 IPC_MESSAGE_HANDLER(StreamHostMsg_SyncAppendSharedMemory,
187 OnAppendSharedMemoryToStream)
188 IPC_MESSAGE_HANDLER(StreamHostMsg_FinishBuilding, OnFinishBuildingStream)
189 IPC_MESSAGE_HANDLER(StreamHostMsg_AbortBuilding, OnAbortBuildingStream)
190 IPC_MESSAGE_HANDLER(StreamHostMsg_Clone, OnCloneStream)
191 IPC_MESSAGE_HANDLER(StreamHostMsg_Remove, OnRemoveStream)
192 IPC_MESSAGE_UNHANDLED(handled = false)
193 IPC_END_MESSAGE_MAP()
197 FileAPIMessageFilter::~FileAPIMessageFilter() {}
199 void FileAPIMessageFilter::BadMessageReceived() {
200 RecordAction(base::UserMetricsAction("BadMessageTerminate_FAMF"));
201 BrowserMessageFilter::BadMessageReceived();
204 void FileAPIMessageFilter::OnOpenFileSystem(int request_id,
205 const GURL& origin_url,
206 storage::FileSystemType type) {
207 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
208 if (type == storage::kFileSystemTypeTemporary) {
209 RecordAction(base::UserMetricsAction("OpenFileSystemTemporary"));
210 } else if (type == storage::kFileSystemTypePersistent) {
211 RecordAction(base::UserMetricsAction("OpenFileSystemPersistent"));
213 storage::OpenFileSystemMode mode =
214 storage::OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT;
215 context_->OpenFileSystem(origin_url, type, mode, base::Bind(
216 &FileAPIMessageFilter::DidOpenFileSystem, this, request_id));
219 void FileAPIMessageFilter::OnResolveURL(
221 const GURL& filesystem_url) {
222 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
223 FileSystemURL url(context_->CrackURL(filesystem_url));
224 if (!ValidateFileSystemURL(request_id, url))
226 if (!security_policy_->CanReadFileSystemFile(process_id_, url)) {
227 Send(new FileSystemMsg_DidFail(request_id,
228 base::File::FILE_ERROR_SECURITY));
232 context_->ResolveURL(url, base::Bind(
233 &FileAPIMessageFilter::DidResolveURL, this, request_id));
236 void FileAPIMessageFilter::OnDeleteFileSystem(int request_id,
237 const GURL& origin_url,
238 storage::FileSystemType type) {
239 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
240 context_->DeleteFileSystem(origin_url, type, base::Bind(
241 &FileAPIMessageFilter::DidDeleteFileSystem, this, request_id));
244 void FileAPIMessageFilter::OnMove(
245 int request_id, const GURL& src_path, const GURL& dest_path) {
246 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
247 FileSystemURL src_url(context_->CrackURL(src_path));
248 FileSystemURL dest_url(context_->CrackURL(dest_path));
249 if (!ValidateFileSystemURL(request_id, src_url) ||
250 !ValidateFileSystemURL(request_id, dest_url)) {
253 if (!security_policy_->CanReadFileSystemFile(process_id_, src_url) ||
254 !security_policy_->CanDeleteFileSystemFile(process_id_, src_url) ||
255 !security_policy_->CanCreateFileSystemFile(process_id_, dest_url)) {
256 Send(new FileSystemMsg_DidFail(request_id,
257 base::File::FILE_ERROR_SECURITY));
261 operations_[request_id] = operation_runner()->Move(
264 storage::FileSystemOperation::OPTION_NONE,
265 base::Bind(&FileAPIMessageFilter::DidFinish, this, request_id));
268 void FileAPIMessageFilter::OnCopy(
269 int request_id, const GURL& src_path, const GURL& dest_path) {
270 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
271 FileSystemURL src_url(context_->CrackURL(src_path));
272 FileSystemURL dest_url(context_->CrackURL(dest_path));
273 if (!ValidateFileSystemURL(request_id, src_url) ||
274 !ValidateFileSystemURL(request_id, dest_url)) {
277 if (!security_policy_->CanReadFileSystemFile(process_id_, src_url) ||
278 !security_policy_->CanCopyIntoFileSystemFile(process_id_, dest_url)) {
279 Send(new FileSystemMsg_DidFail(request_id,
280 base::File::FILE_ERROR_SECURITY));
284 operations_[request_id] = operation_runner()->Copy(
287 storage::FileSystemOperation::OPTION_NONE,
288 storage::FileSystemOperationRunner::CopyProgressCallback(),
289 base::Bind(&FileAPIMessageFilter::DidFinish, this, request_id));
292 void FileAPIMessageFilter::OnRemove(
293 int request_id, const GURL& path, bool recursive) {
294 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
295 FileSystemURL url(context_->CrackURL(path));
296 if (!ValidateFileSystemURL(request_id, url))
298 if (!security_policy_->CanDeleteFileSystemFile(process_id_, url)) {
299 Send(new FileSystemMsg_DidFail(request_id,
300 base::File::FILE_ERROR_SECURITY));
304 operations_[request_id] = operation_runner()->Remove(
306 base::Bind(&FileAPIMessageFilter::DidFinish, this, request_id));
309 void FileAPIMessageFilter::OnReadMetadata(
310 int request_id, const GURL& path) {
311 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
312 FileSystemURL url(context_->CrackURL(path));
313 if (!ValidateFileSystemURL(request_id, url))
315 if (!security_policy_->CanReadFileSystemFile(process_id_, url)) {
316 Send(new FileSystemMsg_DidFail(request_id,
317 base::File::FILE_ERROR_SECURITY));
321 operations_[request_id] = operation_runner()->GetMetadata(
322 url, base::Bind(&FileAPIMessageFilter::DidGetMetadata, this, request_id));
325 void FileAPIMessageFilter::OnCreate(
326 int request_id, const GURL& path, bool exclusive,
327 bool is_directory, bool recursive) {
328 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
329 FileSystemURL url(context_->CrackURL(path));
330 if (!ValidateFileSystemURL(request_id, url))
332 if (!security_policy_->CanCreateFileSystemFile(process_id_, url)) {
333 Send(new FileSystemMsg_DidFail(request_id,
334 base::File::FILE_ERROR_SECURITY));
339 operations_[request_id] = operation_runner()->CreateDirectory(
340 url, exclusive, recursive,
341 base::Bind(&FileAPIMessageFilter::DidFinish, this, request_id));
343 operations_[request_id] = operation_runner()->CreateFile(
345 base::Bind(&FileAPIMessageFilter::DidFinish, this, request_id));
349 void FileAPIMessageFilter::OnExists(
350 int request_id, const GURL& path, bool is_directory) {
351 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
352 FileSystemURL url(context_->CrackURL(path));
353 if (!ValidateFileSystemURL(request_id, url))
355 if (!security_policy_->CanReadFileSystemFile(process_id_, url)) {
356 Send(new FileSystemMsg_DidFail(request_id,
357 base::File::FILE_ERROR_SECURITY));
362 operations_[request_id] = operation_runner()->DirectoryExists(
364 base::Bind(&FileAPIMessageFilter::DidFinish, this, request_id));
366 operations_[request_id] = operation_runner()->FileExists(
368 base::Bind(&FileAPIMessageFilter::DidFinish, this, request_id));
372 void FileAPIMessageFilter::OnReadDirectory(
373 int request_id, const GURL& path) {
374 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
375 FileSystemURL url(context_->CrackURL(path));
376 if (!ValidateFileSystemURL(request_id, url))
378 if (!security_policy_->CanReadFileSystemFile(process_id_, url)) {
379 Send(new FileSystemMsg_DidFail(request_id,
380 base::File::FILE_ERROR_SECURITY));
384 operations_[request_id] = operation_runner()->ReadDirectory(
385 url, base::Bind(&FileAPIMessageFilter::DidReadDirectory,
389 void FileAPIMessageFilter::OnWrite(
392 const std::string& blob_uuid,
394 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
395 if (!request_context_) {
396 // We can't write w/o a request context, trying to do so will crash.
401 FileSystemURL url(context_->CrackURL(path));
402 if (!ValidateFileSystemURL(request_id, url))
404 if (!security_policy_->CanWriteFileSystemFile(process_id_, url)) {
405 Send(new FileSystemMsg_DidFail(request_id,
406 base::File::FILE_ERROR_SECURITY));
410 scoped_ptr<storage::BlobDataHandle> blob =
411 blob_storage_context_->context()->GetBlobDataFromUUID(blob_uuid);
413 operations_[request_id] = operation_runner()->Write(
414 request_context_, url, blob.Pass(), offset,
415 base::Bind(&FileAPIMessageFilter::DidWrite, this, request_id));
418 void FileAPIMessageFilter::OnTruncate(
422 FileSystemURL url(context_->CrackURL(path));
423 if (!ValidateFileSystemURL(request_id, url))
425 if (!security_policy_->CanWriteFileSystemFile(process_id_, url)) {
426 Send(new FileSystemMsg_DidFail(request_id,
427 base::File::FILE_ERROR_SECURITY));
431 operations_[request_id] = operation_runner()->Truncate(
433 base::Bind(&FileAPIMessageFilter::DidFinish, this, request_id));
436 void FileAPIMessageFilter::OnTouchFile(
439 const base::Time& last_access_time,
440 const base::Time& last_modified_time) {
441 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
442 FileSystemURL url(context_->CrackURL(path));
443 if (!ValidateFileSystemURL(request_id, url))
445 if (!security_policy_->CanCreateFileSystemFile(process_id_, url)) {
446 Send(new FileSystemMsg_DidFail(request_id,
447 base::File::FILE_ERROR_SECURITY));
451 operations_[request_id] = operation_runner()->TouchFile(
452 url, last_access_time, last_modified_time,
453 base::Bind(&FileAPIMessageFilter::DidFinish, this, request_id));
456 void FileAPIMessageFilter::OnCancel(
458 int request_id_to_cancel) {
459 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
461 OperationsMap::iterator found = operations_.find(request_id_to_cancel);
462 if (found != operations_.end()) {
463 // The cancel will eventually send both the write failure and the cancel
465 operation_runner()->Cancel(
467 base::Bind(&FileAPIMessageFilter::DidFinish, this, request_id));
469 // The write already finished; report that we failed to stop it.
470 Send(new FileSystemMsg_DidFail(
471 request_id, base::File::FILE_ERROR_INVALID_OPERATION));
475 void FileAPIMessageFilter::OnSyncGetPlatformPath(
476 const GURL& path, base::FilePath* platform_path) {
477 SyncGetPlatformPath(context_, process_id_, path, platform_path);
480 void FileAPIMessageFilter::OnCreateSnapshotFile(
481 int request_id, const GURL& path) {
482 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
483 FileSystemURL url(context_->CrackURL(path));
485 // Make sure if this file can be read by the renderer as this is
486 // called when the renderer is about to create a new File object
487 // (for reading the file).
488 if (!ValidateFileSystemURL(request_id, url))
490 if (!security_policy_->CanReadFileSystemFile(process_id_, url)) {
491 Send(new FileSystemMsg_DidFail(request_id,
492 base::File::FILE_ERROR_SECURITY));
496 FileSystemBackend* backend = context_->GetFileSystemBackend(url.type());
497 if (backend->SupportsStreaming(url)) {
498 operations_[request_id] = operation_runner()->GetMetadata(
500 base::Bind(&FileAPIMessageFilter::DidGetMetadataForStreaming,
503 operations_[request_id] = operation_runner()->CreateSnapshotFile(
505 base::Bind(&FileAPIMessageFilter::DidCreateSnapshot,
506 this, request_id, url));
510 void FileAPIMessageFilter::OnDidReceiveSnapshotFile(int request_id) {
511 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
512 in_transit_snapshot_files_.erase(request_id);
515 void FileAPIMessageFilter::OnStartBuildingBlob(const std::string& uuid) {
516 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
517 ignore_result(blob_storage_host_->StartBuildingBlob(uuid));
520 void FileAPIMessageFilter::OnAppendBlobDataItemToBlob(
521 const std::string& uuid, const BlobData::Item& item) {
522 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
523 if (item.type() == BlobData::Item::TYPE_FILE_FILESYSTEM) {
524 FileSystemURL filesystem_url(context_->CrackURL(item.filesystem_url()));
525 if (!FileSystemURLIsValid(context_, filesystem_url) ||
526 !security_policy_->CanReadFileSystemFile(process_id_, filesystem_url)) {
527 ignore_result(blob_storage_host_->CancelBuildingBlob(uuid));
531 if (item.type() == BlobData::Item::TYPE_FILE &&
532 !security_policy_->CanReadFile(process_id_, item.path())) {
533 ignore_result(blob_storage_host_->CancelBuildingBlob(uuid));
536 if (item.length() == 0) {
537 BadMessageReceived();
540 ignore_result(blob_storage_host_->AppendBlobDataItem(uuid, item));
543 void FileAPIMessageFilter::OnAppendSharedMemoryToBlob(
544 const std::string& uuid,
545 base::SharedMemoryHandle handle,
546 size_t buffer_size) {
547 DCHECK(base::SharedMemory::IsHandleValid(handle));
549 BadMessageReceived();
553 base::SharedMemory shared_memory(handle, true, PeerHandle());
555 base::SharedMemory shared_memory(handle, true);
557 if (!shared_memory.Map(buffer_size)) {
558 ignore_result(blob_storage_host_->CancelBuildingBlob(uuid));
563 item.SetToSharedBytes(static_cast<char*>(shared_memory.memory()),
565 ignore_result(blob_storage_host_->AppendBlobDataItem(uuid, item));
568 void FileAPIMessageFilter::OnFinishBuildingBlob(
569 const std::string& uuid, const std::string& content_type) {
570 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
571 ignore_result(blob_storage_host_->FinishBuildingBlob(uuid, content_type));
572 // TODO(michaeln): check return values once blink has migrated, crbug/174200
575 void FileAPIMessageFilter::OnIncrementBlobRefCount(const std::string& uuid) {
576 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
577 ignore_result(blob_storage_host_->IncrementBlobRefCount(uuid));
580 void FileAPIMessageFilter::OnDecrementBlobRefCount(const std::string& uuid) {
581 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
582 ignore_result(blob_storage_host_->DecrementBlobRefCount(uuid));
585 void FileAPIMessageFilter::OnRegisterPublicBlobURL(
586 const GURL& public_url, const std::string& uuid) {
587 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
588 ignore_result(blob_storage_host_->RegisterPublicBlobURL(public_url, uuid));
591 void FileAPIMessageFilter::OnRevokePublicBlobURL(const GURL& public_url) {
592 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
593 ignore_result(blob_storage_host_->RevokePublicBlobURL(public_url));
596 void FileAPIMessageFilter::OnStartBuildingStream(
597 const GURL& url, const std::string& content_type) {
598 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
599 // Only an internal Blob URL is expected here. See the BlobURL of the Blink.
600 if (!StartsWithASCII(
601 url.path(), "blobinternal%3A///", true /* case_sensitive */)) {
602 NOTREACHED() << "Malformed Stream URL: " << url.spec();
603 BadMessageReceived();
606 // Use an empty security origin for now. Stream accepts a security origin
607 // but how it's handled is not fixed yet.
608 new Stream(stream_context_->registry(),
609 NULL /* write_observer */,
611 stream_urls_.insert(url.spec());
614 void FileAPIMessageFilter::OnAppendBlobDataItemToStream(
615 const GURL& url, const BlobData::Item& item) {
616 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
618 scoped_refptr<Stream> stream(GetStreamForURL(url));
619 // Stream instances may be deleted on error. Just abort if there's no Stream
620 // instance for |url| in the registry.
624 // Data for stream is delivered as TYPE_BYTES item.
625 if (item.type() != BlobData::Item::TYPE_BYTES) {
626 BadMessageReceived();
629 stream->AddData(item.bytes(), item.length());
632 void FileAPIMessageFilter::OnAppendSharedMemoryToStream(
633 const GURL& url, base::SharedMemoryHandle handle, size_t buffer_size) {
634 DCHECK(base::SharedMemory::IsHandleValid(handle));
636 BadMessageReceived();
640 base::SharedMemory shared_memory(handle, true, PeerHandle());
642 base::SharedMemory shared_memory(handle, true);
644 if (!shared_memory.Map(buffer_size)) {
649 scoped_refptr<Stream> stream(GetStreamForURL(url));
653 stream->AddData(static_cast<char*>(shared_memory.memory()), buffer_size);
656 void FileAPIMessageFilter::OnFinishBuildingStream(const GURL& url) {
657 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
658 scoped_refptr<Stream> stream(GetStreamForURL(url));
663 void FileAPIMessageFilter::OnAbortBuildingStream(const GURL& url) {
664 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
665 scoped_refptr<Stream> stream(GetStreamForURL(url));
670 void FileAPIMessageFilter::OnCloneStream(
671 const GURL& url, const GURL& src_url) {
672 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
673 // Abort if there's no Stream instance for |src_url| (source Stream which
674 // we're going to make |url| point to) in the registry.
675 if (!GetStreamForURL(src_url).get())
678 stream_context_->registry()->CloneStream(url, src_url);
679 stream_urls_.insert(url.spec());
682 void FileAPIMessageFilter::OnRemoveStream(const GURL& url) {
683 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
685 if (!GetStreamForURL(url).get())
688 stream_context_->registry()->UnregisterStream(url);
689 stream_urls_.erase(url.spec());
692 void FileAPIMessageFilter::DidFinish(int request_id,
693 base::File::Error result) {
694 if (result == base::File::FILE_OK)
695 Send(new FileSystemMsg_DidSucceed(request_id));
697 Send(new FileSystemMsg_DidFail(request_id, result));
698 operations_.erase(request_id);
701 void FileAPIMessageFilter::DidGetMetadata(
703 base::File::Error result,
704 const base::File::Info& info) {
705 if (result == base::File::FILE_OK)
706 Send(new FileSystemMsg_DidReadMetadata(request_id, info));
708 Send(new FileSystemMsg_DidFail(request_id, result));
709 operations_.erase(request_id);
712 void FileAPIMessageFilter::DidGetMetadataForStreaming(
714 base::File::Error result,
715 const base::File::Info& info) {
716 if (result == base::File::FILE_OK) {
717 // For now, streaming Blobs are implemented as a successful snapshot file
718 // creation with an empty path.
719 Send(new FileSystemMsg_DidCreateSnapshotFile(request_id, info,
722 Send(new FileSystemMsg_DidFail(request_id, result));
724 operations_.erase(request_id);
727 void FileAPIMessageFilter::DidReadDirectory(
729 base::File::Error result,
730 const std::vector<storage::DirectoryEntry>& entries,
732 if (result == base::File::FILE_OK) {
733 if (!entries.empty() || !has_more)
734 Send(new FileSystemMsg_DidReadDirectory(request_id, entries, has_more));
737 Send(new FileSystemMsg_DidFail(request_id, result));
740 operations_.erase(request_id);
743 void FileAPIMessageFilter::DidWrite(int request_id,
744 base::File::Error result,
747 if (result == base::File::FILE_OK) {
748 Send(new FileSystemMsg_DidWrite(request_id, bytes, complete));
750 operations_.erase(request_id);
752 Send(new FileSystemMsg_DidFail(request_id, result));
753 operations_.erase(request_id);
757 void FileAPIMessageFilter::DidOpenFileSystem(int request_id,
759 const std::string& filesystem_name,
760 base::File::Error result) {
761 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
762 if (result == base::File::FILE_OK) {
763 DCHECK(root.is_valid());
764 Send(new FileSystemMsg_DidOpenFileSystem(
765 request_id, filesystem_name, root));
767 Send(new FileSystemMsg_DidFail(request_id, result));
769 // For OpenFileSystem we do not create a new operation, so no unregister here.
772 void FileAPIMessageFilter::DidResolveURL(
774 base::File::Error result,
775 const storage::FileSystemInfo& info,
776 const base::FilePath& file_path,
777 storage::FileSystemContext::ResolvedEntryType type) {
778 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
779 if (result == base::File::FILE_OK &&
780 type == storage::FileSystemContext::RESOLVED_ENTRY_NOT_FOUND)
781 result = base::File::FILE_ERROR_NOT_FOUND;
783 if (result == base::File::FILE_OK) {
784 DCHECK(info.root_url.is_valid());
785 Send(new FileSystemMsg_DidResolveURL(
789 type == storage::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 storage::FileSystemURL& url,
810 base::File::Error result,
811 const base::File::Info& info,
812 const base::FilePath& platform_path,
813 const scoped_refptr<storage::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<storage::ShareableFileReference> file_ref =
823 storage::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 = storage::ShareableFileReference::GetOrCreate(
839 storage::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(
858 const storage::FileSystemURL& url) {
859 if (!FileSystemURLIsValid(context_, url)) {
860 Send(new FileSystemMsg_DidFail(request_id,
861 base::File::FILE_ERROR_INVALID_URL));
865 // Deny access to files in PluginPrivate FileSystem from JavaScript.
866 // TODO(nhiroki): Move this filter somewhere else since this is not for
868 if (url.type() == storage::kFileSystemTypePluginPrivate) {
869 Send(new FileSystemMsg_DidFail(request_id,
870 base::File::FILE_ERROR_SECURITY));
877 scoped_refptr<Stream> FileAPIMessageFilter::GetStreamForURL(const GURL& url) {
878 return stream_context_->registry()->GetStream(url);
881 } // namespace content