Home | History | Annotate | Download | only in fileapi
      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/browser/fileapi/fileapi_message_filter.h"
      6 
      7 #include <string>
      8 #include <vector>
      9 
     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"
     41 #include "url/gurl.h"
     42 
     43 using storage::FileSystemFileUtil;
     44 using storage::FileSystemBackend;
     45 using storage::FileSystemOperation;
     46 using storage::FileSystemURL;
     47 using storage::BlobData;
     48 using storage::BlobStorageContext;
     49 
     50 namespace content {
     51 
     52 namespace {
     53 
     54 const uint32 kFilteredMessageClasses[] = {
     55   BlobMsgStart,
     56   FileSystemMsgStart,
     57 };
     58 
     59 void RevokeFilePermission(int child_id, const base::FilePath& path) {
     60   ChildProcessSecurityPolicyImpl::GetInstance()->RevokeAllPermissionsForFile(
     61     child_id, path);
     62 }
     63 
     64 }  // namespace
     65 
     66 FileAPIMessageFilter::FileAPIMessageFilter(
     67     int process_id,
     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) {
     81   DCHECK(context_);
     82   DCHECK(request_context_getter_.get());
     83   DCHECK(blob_storage_context);
     84   DCHECK(stream_context);
     85 }
     86 
     87 FileAPIMessageFilter::FileAPIMessageFilter(
     88     int process_id,
     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) {
    101   DCHECK(context_);
    102   DCHECK(request_context_);
    103   DCHECK(blob_storage_context);
    104   DCHECK(stream_context);
    105 }
    106 
    107 void FileAPIMessageFilter::OnChannelConnected(int32 peer_pid) {
    108   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    109 
    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_);
    115   }
    116 
    117   blob_storage_host_.reset(
    118       new BlobStorageHost(blob_storage_context_->context()));
    119 
    120   operation_runner_ = context_->CreateFileSystemOperationRunner();
    121 }
    122 
    123 void FileAPIMessageFilter::OnChannelClosing() {
    124   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    125 
    126   // Unregister all the blob and stream URLs that are previously registered in
    127   // this process.
    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));
    132   }
    133 
    134   in_transit_snapshot_files_.clear();
    135 
    136   operation_runner_.reset();
    137   operations_.clear();
    138 }
    139 
    140 base::TaskRunner* FileAPIMessageFilter::OverrideTaskRunnerForMessage(
    141     const IPC::Message& message) {
    142   if (message.type() == FileSystemHostMsg_SyncGetPlatformPath::ID)
    143     return context_->default_file_task_runner();
    144   return NULL;
    145 }
    146 
    147 bool FileAPIMessageFilter::OnMessageReceived(const IPC::Message& message) {
    148   bool handled = true;
    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()
    194   return handled;
    195 }
    196 
    197 FileAPIMessageFilter::~FileAPIMessageFilter() {}
    198 
    199 void FileAPIMessageFilter::BadMessageReceived() {
    200   RecordAction(base::UserMetricsAction("BadMessageTerminate_FAMF"));
    201   BrowserMessageFilter::BadMessageReceived();
    202 }
    203 
    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"));
    212   }
    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));
    217 }
    218 
    219 void FileAPIMessageFilter::OnResolveURL(
    220     int request_id,
    221     const GURL& filesystem_url) {
    222   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    223   FileSystemURL url(context_->CrackURL(filesystem_url));
    224   if (!ValidateFileSystemURL(request_id, url))
    225     return;
    226   if (!security_policy_->CanReadFileSystemFile(process_id_, url)) {
    227     Send(new FileSystemMsg_DidFail(request_id,
    228                                    base::File::FILE_ERROR_SECURITY));
    229     return;
    230   }
    231 
    232   context_->ResolveURL(url, base::Bind(
    233       &FileAPIMessageFilter::DidResolveURL, this, request_id));
    234 }
    235 
    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));
    242 }
    243 
    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)) {
    251     return;
    252   }
    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));
    258     return;
    259   }
    260 
    261   operations_[request_id] = operation_runner()->Move(
    262       src_url,
    263       dest_url,
    264       storage::FileSystemOperation::OPTION_NONE,
    265       base::Bind(&FileAPIMessageFilter::DidFinish, this, request_id));
    266 }
    267 
    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)) {
    275     return;
    276   }
    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));
    281     return;
    282   }
    283 
    284   operations_[request_id] = operation_runner()->Copy(
    285       src_url,
    286       dest_url,
    287       storage::FileSystemOperation::OPTION_NONE,
    288       storage::FileSystemOperationRunner::CopyProgressCallback(),
    289       base::Bind(&FileAPIMessageFilter::DidFinish, this, request_id));
    290 }
    291 
    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))
    297     return;
    298   if (!security_policy_->CanDeleteFileSystemFile(process_id_, url)) {
    299     Send(new FileSystemMsg_DidFail(request_id,
    300                                    base::File::FILE_ERROR_SECURITY));
    301     return;
    302   }
    303 
    304   operations_[request_id] = operation_runner()->Remove(
    305       url, recursive,
    306       base::Bind(&FileAPIMessageFilter::DidFinish, this, request_id));
    307 }
    308 
    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))
    314     return;
    315   if (!security_policy_->CanReadFileSystemFile(process_id_, url)) {
    316     Send(new FileSystemMsg_DidFail(request_id,
    317                                    base::File::FILE_ERROR_SECURITY));
    318     return;
    319   }
    320 
    321   operations_[request_id] = operation_runner()->GetMetadata(
    322       url, base::Bind(&FileAPIMessageFilter::DidGetMetadata, this, request_id));
    323 }
    324 
    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))
    331     return;
    332   if (!security_policy_->CanCreateFileSystemFile(process_id_, url)) {
    333     Send(new FileSystemMsg_DidFail(request_id,
    334                                    base::File::FILE_ERROR_SECURITY));
    335     return;
    336   }
    337 
    338   if (is_directory) {
    339     operations_[request_id] = operation_runner()->CreateDirectory(
    340         url, exclusive, recursive,
    341         base::Bind(&FileAPIMessageFilter::DidFinish, this, request_id));
    342   } else {
    343     operations_[request_id] = operation_runner()->CreateFile(
    344         url, exclusive,
    345         base::Bind(&FileAPIMessageFilter::DidFinish, this, request_id));
    346   }
    347 }
    348 
    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))
    354     return;
    355   if (!security_policy_->CanReadFileSystemFile(process_id_, url)) {
    356     Send(new FileSystemMsg_DidFail(request_id,
    357                                    base::File::FILE_ERROR_SECURITY));
    358     return;
    359   }
    360 
    361   if (is_directory) {
    362     operations_[request_id] = operation_runner()->DirectoryExists(
    363         url,
    364         base::Bind(&FileAPIMessageFilter::DidFinish, this, request_id));
    365   } else {
    366     operations_[request_id] = operation_runner()->FileExists(
    367         url,
    368         base::Bind(&FileAPIMessageFilter::DidFinish, this, request_id));
    369   }
    370 }
    371 
    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))
    377     return;
    378   if (!security_policy_->CanReadFileSystemFile(process_id_, url)) {
    379     Send(new FileSystemMsg_DidFail(request_id,
    380                                    base::File::FILE_ERROR_SECURITY));
    381     return;
    382   }
    383 
    384   operations_[request_id] = operation_runner()->ReadDirectory(
    385       url, base::Bind(&FileAPIMessageFilter::DidReadDirectory,
    386                       this, request_id));
    387 }
    388 
    389 void FileAPIMessageFilter::OnWrite(
    390     int request_id,
    391     const GURL& path,
    392     const std::string& blob_uuid,
    393     int64 offset) {
    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.
    397     NOTREACHED();
    398     return;
    399   }
    400 
    401   FileSystemURL url(context_->CrackURL(path));
    402   if (!ValidateFileSystemURL(request_id, url))
    403     return;
    404   if (!security_policy_->CanWriteFileSystemFile(process_id_, url)) {
    405     Send(new FileSystemMsg_DidFail(request_id,
    406                                    base::File::FILE_ERROR_SECURITY));
    407     return;
    408   }
    409 
    410   scoped_ptr<storage::BlobDataHandle> blob =
    411       blob_storage_context_->context()->GetBlobDataFromUUID(blob_uuid);
    412 
    413   operations_[request_id] = operation_runner()->Write(
    414       request_context_, url, blob.Pass(), offset,
    415       base::Bind(&FileAPIMessageFilter::DidWrite, this, request_id));
    416 }
    417 
    418 void FileAPIMessageFilter::OnTruncate(
    419     int request_id,
    420     const GURL& path,
    421     int64 length) {
    422   FileSystemURL url(context_->CrackURL(path));
    423   if (!ValidateFileSystemURL(request_id, url))
    424     return;
    425   if (!security_policy_->CanWriteFileSystemFile(process_id_, url)) {
    426     Send(new FileSystemMsg_DidFail(request_id,
    427                                    base::File::FILE_ERROR_SECURITY));
    428     return;
    429   }
    430 
    431   operations_[request_id] = operation_runner()->Truncate(
    432       url, length,
    433       base::Bind(&FileAPIMessageFilter::DidFinish, this, request_id));
    434 }
    435 
    436 void FileAPIMessageFilter::OnTouchFile(
    437     int request_id,
    438     const GURL& path,
    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))
    444     return;
    445   if (!security_policy_->CanCreateFileSystemFile(process_id_, url)) {
    446     Send(new FileSystemMsg_DidFail(request_id,
    447                                    base::File::FILE_ERROR_SECURITY));
    448     return;
    449   }
    450 
    451   operations_[request_id] = operation_runner()->TouchFile(
    452       url, last_access_time, last_modified_time,
    453       base::Bind(&FileAPIMessageFilter::DidFinish, this, request_id));
    454 }
    455 
    456 void FileAPIMessageFilter::OnCancel(
    457     int request_id,
    458     int request_id_to_cancel) {
    459   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    460 
    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
    464     // success.
    465     operation_runner()->Cancel(
    466         found->second,
    467         base::Bind(&FileAPIMessageFilter::DidFinish, this, request_id));
    468   } else {
    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));
    472   }
    473 }
    474 
    475 void FileAPIMessageFilter::OnSyncGetPlatformPath(
    476     const GURL& path, base::FilePath* platform_path) {
    477   SyncGetPlatformPath(context_, process_id_, path, platform_path);
    478 }
    479 
    480 void FileAPIMessageFilter::OnCreateSnapshotFile(
    481     int request_id, const GURL& path) {
    482   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    483   FileSystemURL url(context_->CrackURL(path));
    484 
    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))
    489     return;
    490   if (!security_policy_->CanReadFileSystemFile(process_id_, url)) {
    491     Send(new FileSystemMsg_DidFail(request_id,
    492                                    base::File::FILE_ERROR_SECURITY));
    493     return;
    494   }
    495 
    496   FileSystemBackend* backend = context_->GetFileSystemBackend(url.type());
    497   if (backend->SupportsStreaming(url)) {
    498     operations_[request_id] = operation_runner()->GetMetadata(
    499         url,
    500         base::Bind(&FileAPIMessageFilter::DidGetMetadataForStreaming,
    501                    this, request_id));
    502   } else {
    503     operations_[request_id] = operation_runner()->CreateSnapshotFile(
    504         url,
    505         base::Bind(&FileAPIMessageFilter::DidCreateSnapshot,
    506                    this, request_id, url));
    507   }
    508 }
    509 
    510 void FileAPIMessageFilter::OnDidReceiveSnapshotFile(int request_id) {
    511   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    512   in_transit_snapshot_files_.erase(request_id);
    513 }
    514 
    515 void FileAPIMessageFilter::OnStartBuildingBlob(const std::string& uuid) {
    516   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    517   ignore_result(blob_storage_host_->StartBuildingBlob(uuid));
    518 }
    519 
    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));
    528       return;
    529     }
    530   }
    531   if (item.type() == BlobData::Item::TYPE_FILE &&
    532       !security_policy_->CanReadFile(process_id_, item.path())) {
    533     ignore_result(blob_storage_host_->CancelBuildingBlob(uuid));
    534     return;
    535   }
    536   if (item.length() == 0) {
    537     BadMessageReceived();
    538     return;
    539   }
    540   ignore_result(blob_storage_host_->AppendBlobDataItem(uuid, item));
    541 }
    542 
    543 void FileAPIMessageFilter::OnAppendSharedMemoryToBlob(
    544     const std::string& uuid,
    545     base::SharedMemoryHandle handle,
    546     size_t buffer_size) {
    547   DCHECK(base::SharedMemory::IsHandleValid(handle));
    548   if (!buffer_size) {
    549     BadMessageReceived();
    550     return;
    551   }
    552 #if defined(OS_WIN)
    553   base::SharedMemory shared_memory(handle, true, PeerHandle());
    554 #else
    555   base::SharedMemory shared_memory(handle, true);
    556 #endif
    557   if (!shared_memory.Map(buffer_size)) {
    558     ignore_result(blob_storage_host_->CancelBuildingBlob(uuid));
    559     return;
    560   }
    561 
    562   BlobData::Item item;
    563   item.SetToSharedBytes(static_cast<char*>(shared_memory.memory()),
    564                         buffer_size);
    565   ignore_result(blob_storage_host_->AppendBlobDataItem(uuid, item));
    566 }
    567 
    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
    573 }
    574 
    575 void FileAPIMessageFilter::OnIncrementBlobRefCount(const std::string& uuid) {
    576   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    577   ignore_result(blob_storage_host_->IncrementBlobRefCount(uuid));
    578 }
    579 
    580 void FileAPIMessageFilter::OnDecrementBlobRefCount(const std::string& uuid) {
    581   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    582   ignore_result(blob_storage_host_->DecrementBlobRefCount(uuid));
    583 }
    584 
    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));
    589 }
    590 
    591 void FileAPIMessageFilter::OnRevokePublicBlobURL(const GURL& public_url) {
    592   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    593   ignore_result(blob_storage_host_->RevokePublicBlobURL(public_url));
    594 }
    595 
    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();
    604     return;
    605   }
    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 */,
    610              url);
    611   stream_urls_.insert(url.spec());
    612 }
    613 
    614 void FileAPIMessageFilter::OnAppendBlobDataItemToStream(
    615     const GURL& url, const BlobData::Item& item) {
    616   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    617 
    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.
    621   if (!stream.get())
    622     return;
    623 
    624   // Data for stream is delivered as TYPE_BYTES item.
    625   if (item.type() != BlobData::Item::TYPE_BYTES) {
    626     BadMessageReceived();
    627     return;
    628   }
    629   stream->AddData(item.bytes(), item.length());
    630 }
    631 
    632 void FileAPIMessageFilter::OnAppendSharedMemoryToStream(
    633     const GURL& url, base::SharedMemoryHandle handle, size_t buffer_size) {
    634   DCHECK(base::SharedMemory::IsHandleValid(handle));
    635   if (!buffer_size) {
    636     BadMessageReceived();
    637     return;
    638   }
    639 #if defined(OS_WIN)
    640   base::SharedMemory shared_memory(handle, true, PeerHandle());
    641 #else
    642   base::SharedMemory shared_memory(handle, true);
    643 #endif
    644   if (!shared_memory.Map(buffer_size)) {
    645     OnRemoveStream(url);
    646     return;
    647   }
    648 
    649   scoped_refptr<Stream> stream(GetStreamForURL(url));
    650   if (!stream.get())
    651     return;
    652 
    653   stream->AddData(static_cast<char*>(shared_memory.memory()), buffer_size);
    654 }
    655 
    656 void FileAPIMessageFilter::OnFinishBuildingStream(const GURL& url) {
    657   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    658   scoped_refptr<Stream> stream(GetStreamForURL(url));
    659   if (stream.get())
    660     stream->Finalize();
    661 }
    662 
    663 void FileAPIMessageFilter::OnAbortBuildingStream(const GURL& url) {
    664   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    665   scoped_refptr<Stream> stream(GetStreamForURL(url));
    666   if (stream.get())
    667     stream->Abort();
    668 }
    669 
    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())
    676     return;
    677 
    678   stream_context_->registry()->CloneStream(url, src_url);
    679   stream_urls_.insert(url.spec());
    680 }
    681 
    682 void FileAPIMessageFilter::OnRemoveStream(const GURL& url) {
    683   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    684 
    685   if (!GetStreamForURL(url).get())
    686     return;
    687 
    688   stream_context_->registry()->UnregisterStream(url);
    689   stream_urls_.erase(url.spec());
    690 }
    691 
    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));
    696   else
    697     Send(new FileSystemMsg_DidFail(request_id, result));
    698   operations_.erase(request_id);
    699 }
    700 
    701 void FileAPIMessageFilter::DidGetMetadata(
    702     int request_id,
    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));
    707   else
    708     Send(new FileSystemMsg_DidFail(request_id, result));
    709   operations_.erase(request_id);
    710 }
    711 
    712 void FileAPIMessageFilter::DidGetMetadataForStreaming(
    713     int request_id,
    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,
    720                                                  base::FilePath()));
    721   } else {
    722     Send(new FileSystemMsg_DidFail(request_id, result));
    723   }
    724   operations_.erase(request_id);
    725 }
    726 
    727 void FileAPIMessageFilter::DidReadDirectory(
    728     int request_id,
    729     base::File::Error result,
    730     const std::vector<storage::DirectoryEntry>& entries,
    731     bool has_more) {
    732   if (result == base::File::FILE_OK) {
    733     if (!entries.empty() || !has_more)
    734       Send(new FileSystemMsg_DidReadDirectory(request_id, entries, has_more));
    735   } else {
    736     DCHECK(!has_more);
    737     Send(new FileSystemMsg_DidFail(request_id, result));
    738   }
    739   if (!has_more)
    740     operations_.erase(request_id);
    741 }
    742 
    743 void FileAPIMessageFilter::DidWrite(int request_id,
    744                                     base::File::Error result,
    745                                     int64 bytes,
    746                                     bool complete) {
    747   if (result == base::File::FILE_OK) {
    748     Send(new FileSystemMsg_DidWrite(request_id, bytes, complete));
    749     if (complete)
    750       operations_.erase(request_id);
    751   } else {
    752     Send(new FileSystemMsg_DidFail(request_id, result));
    753     operations_.erase(request_id);
    754   }
    755 }
    756 
    757 void FileAPIMessageFilter::DidOpenFileSystem(int request_id,
    758                                              const GURL& root,
    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));
    766   } else {
    767     Send(new FileSystemMsg_DidFail(request_id, result));
    768   }
    769   // For OpenFileSystem we do not create a new operation, so no unregister here.
    770 }
    771 
    772 void FileAPIMessageFilter::DidResolveURL(
    773     int request_id,
    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;
    782 
    783   if (result == base::File::FILE_OK) {
    784     DCHECK(info.root_url.is_valid());
    785     Send(new FileSystemMsg_DidResolveURL(
    786         request_id,
    787         info,
    788         file_path,
    789         type == storage::FileSystemContext::RESOLVED_ENTRY_DIRECTORY));
    790   } else {
    791     Send(new FileSystemMsg_DidFail(request_id, result));
    792   }
    793   // For ResolveURL we do not create a new operation, so no unregister here.
    794 }
    795 
    796 void FileAPIMessageFilter::DidDeleteFileSystem(
    797     int request_id,
    798     base::File::Error result) {
    799   if (result == base::File::FILE_OK)
    800     Send(new FileSystemMsg_DidSucceed(request_id));
    801   else
    802     Send(new FileSystemMsg_DidFail(request_id, result));
    803   // For DeleteFileSystem we do not create a new operation,
    804   // so no unregister here.
    805 }
    806 
    807 void FileAPIMessageFilter::DidCreateSnapshot(
    808     int request_id,
    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);
    816 
    817   if (result != base::File::FILE_OK) {
    818     Send(new FileSystemMsg_DidFail(request_id, result));
    819     return;
    820   }
    821 
    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);
    832 
    833     // Revoke all permissions for the file when the last ref of the file
    834     // is dropped.
    835     if (!file_ref.get()) {
    836       // Create a reference for temporary permission handling.
    837       file_ref = storage::ShareableFileReference::GetOrCreate(
    838           platform_path,
    839           storage::ShareableFileReference::DONT_DELETE_ON_FINAL_RELEASE,
    840           context_->default_file_task_runner());
    841     }
    842     file_ref->AddFinalReleaseCallback(
    843         base::Bind(&RevokeFilePermission, process_id_));
    844   }
    845 
    846   if (file_ref.get()) {
    847     // This ref is held until OnDidReceiveSnapshotFile is called.
    848     in_transit_snapshot_files_[request_id] = file_ref;
    849   }
    850 
    851   // Return the file info and platform_path.
    852   Send(new FileSystemMsg_DidCreateSnapshotFile(
    853       request_id, info, platform_path));
    854 }
    855 
    856 bool FileAPIMessageFilter::ValidateFileSystemURL(
    857     int request_id,
    858     const storage::FileSystemURL& url) {
    859   if (!FileSystemURLIsValid(context_, url)) {
    860     Send(new FileSystemMsg_DidFail(request_id,
    861                                    base::File::FILE_ERROR_INVALID_URL));
    862     return false;
    863   }
    864 
    865   // Deny access to files in PluginPrivate FileSystem from JavaScript.
    866   // TODO(nhiroki): Move this filter somewhere else since this is not for
    867   // validation.
    868   if (url.type() == storage::kFileSystemTypePluginPrivate) {
    869     Send(new FileSystemMsg_DidFail(request_id,
    870                                    base::File::FILE_ERROR_SECURITY));
    871     return false;
    872   }
    873 
    874   return true;
    875 }
    876 
    877 scoped_refptr<Stream> FileAPIMessageFilter::GetStreamForURL(const GURL& url) {
    878   return stream_context_->registry()->GetStream(url);
    879 }
    880 
    881 }  // namespace content
    882