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 "url/gurl.h"
     31 #include "webkit/browser/blob/blob_storage_context.h"
     32 #include "webkit/browser/fileapi/file_observers.h"
     33 #include "webkit/browser/fileapi/file_permission_policy.h"
     34 #include "webkit/browser/fileapi/file_system_context.h"
     35 #include "webkit/browser/fileapi/isolated_context.h"
     36 #include "webkit/common/blob/blob_data.h"
     37 #include "webkit/common/blob/shareable_file_reference.h"
     38 #include "webkit/common/fileapi/directory_entry.h"
     39 #include "webkit/common/fileapi/file_system_info.h"
     40 #include "webkit/common/fileapi/file_system_types.h"
     41 #include "webkit/common/fileapi/file_system_util.h"
     42 
     43 using fileapi::FileSystemFileUtil;
     44 using fileapi::FileSystemBackend;
     45 using fileapi::FileSystemOperation;
     46 using fileapi::FileSystemURL;
     47 using webkit_blob::BlobData;
     48 using webkit_blob::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     fileapi::FileSystemContext* file_system_context,
     70     ChromeBlobStorageContext* blob_storage_context,
     71     StreamContext* stream_context)
     72     : BrowserMessageFilter(
     73           kFilteredMessageClasses, 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     fileapi::FileSystemContext* file_system_context,
     91     ChromeBlobStorageContext* blob_storage_context,
     92     StreamContext* stream_context)
     93     : BrowserMessageFilter(
     94           kFilteredMessageClasses, 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                                             fileapi::FileSystemType type) {
    207   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    208   if (type == fileapi::kFileSystemTypeTemporary) {
    209     RecordAction(base::UserMetricsAction("OpenFileSystemTemporary"));
    210   } else if (type == fileapi::kFileSystemTypePersistent) {
    211     RecordAction(base::UserMetricsAction("OpenFileSystemPersistent"));
    212   }
    213   fileapi::OpenFileSystemMode mode =
    214       fileapi::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(
    237     int request_id,
    238     const GURL& origin_url,
    239     fileapi::FileSystemType type) {
    240   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    241   context_->DeleteFileSystem(origin_url, type, base::Bind(
    242       &FileAPIMessageFilter::DidDeleteFileSystem, this, request_id));
    243 }
    244 
    245 void FileAPIMessageFilter::OnMove(
    246     int request_id, const GURL& src_path, const GURL& dest_path) {
    247   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    248   FileSystemURL src_url(context_->CrackURL(src_path));
    249   FileSystemURL dest_url(context_->CrackURL(dest_path));
    250   if (!ValidateFileSystemURL(request_id, src_url) ||
    251       !ValidateFileSystemURL(request_id, dest_url)) {
    252     return;
    253   }
    254   if (!security_policy_->CanReadFileSystemFile(process_id_, src_url) ||
    255       !security_policy_->CanDeleteFileSystemFile(process_id_, src_url) ||
    256       !security_policy_->CanCreateFileSystemFile(process_id_, dest_url)) {
    257     Send(new FileSystemMsg_DidFail(request_id,
    258                                    base::File::FILE_ERROR_SECURITY));
    259     return;
    260   }
    261 
    262   operations_[request_id] = operation_runner()->Move(
    263       src_url, dest_url,
    264       fileapi::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, dest_url,
    286       fileapi::FileSystemOperation::OPTION_NONE,
    287       fileapi::FileSystemOperationRunner::CopyProgressCallback(),
    288       base::Bind(&FileAPIMessageFilter::DidFinish, this, request_id));
    289 }
    290 
    291 void FileAPIMessageFilter::OnRemove(
    292     int request_id, const GURL& path, bool recursive) {
    293   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    294   FileSystemURL url(context_->CrackURL(path));
    295   if (!ValidateFileSystemURL(request_id, url))
    296     return;
    297   if (!security_policy_->CanDeleteFileSystemFile(process_id_, url)) {
    298     Send(new FileSystemMsg_DidFail(request_id,
    299                                    base::File::FILE_ERROR_SECURITY));
    300     return;
    301   }
    302 
    303   operations_[request_id] = operation_runner()->Remove(
    304       url, recursive,
    305       base::Bind(&FileAPIMessageFilter::DidFinish, this, request_id));
    306 }
    307 
    308 void FileAPIMessageFilter::OnReadMetadata(
    309     int request_id, const GURL& path) {
    310   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    311   FileSystemURL url(context_->CrackURL(path));
    312   if (!ValidateFileSystemURL(request_id, url))
    313     return;
    314   if (!security_policy_->CanReadFileSystemFile(process_id_, url)) {
    315     Send(new FileSystemMsg_DidFail(request_id,
    316                                    base::File::FILE_ERROR_SECURITY));
    317     return;
    318   }
    319 
    320   operations_[request_id] = operation_runner()->GetMetadata(
    321       url, base::Bind(&FileAPIMessageFilter::DidGetMetadata, this, request_id));
    322 }
    323 
    324 void FileAPIMessageFilter::OnCreate(
    325     int request_id, const GURL& path, bool exclusive,
    326     bool is_directory, bool recursive) {
    327   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    328   FileSystemURL url(context_->CrackURL(path));
    329   if (!ValidateFileSystemURL(request_id, url))
    330     return;
    331   if (!security_policy_->CanCreateFileSystemFile(process_id_, url)) {
    332     Send(new FileSystemMsg_DidFail(request_id,
    333                                    base::File::FILE_ERROR_SECURITY));
    334     return;
    335   }
    336 
    337   if (is_directory) {
    338     operations_[request_id] = operation_runner()->CreateDirectory(
    339         url, exclusive, recursive,
    340         base::Bind(&FileAPIMessageFilter::DidFinish, this, request_id));
    341   } else {
    342     operations_[request_id] = operation_runner()->CreateFile(
    343         url, exclusive,
    344         base::Bind(&FileAPIMessageFilter::DidFinish, this, request_id));
    345   }
    346 }
    347 
    348 void FileAPIMessageFilter::OnExists(
    349     int request_id, const GURL& path, bool is_directory) {
    350   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    351   FileSystemURL url(context_->CrackURL(path));
    352   if (!ValidateFileSystemURL(request_id, url))
    353     return;
    354   if (!security_policy_->CanReadFileSystemFile(process_id_, url)) {
    355     Send(new FileSystemMsg_DidFail(request_id,
    356                                    base::File::FILE_ERROR_SECURITY));
    357     return;
    358   }
    359 
    360   if (is_directory) {
    361     operations_[request_id] = operation_runner()->DirectoryExists(
    362         url,
    363         base::Bind(&FileAPIMessageFilter::DidFinish, this, request_id));
    364   } else {
    365     operations_[request_id] = operation_runner()->FileExists(
    366         url,
    367         base::Bind(&FileAPIMessageFilter::DidFinish, this, request_id));
    368   }
    369 }
    370 
    371 void FileAPIMessageFilter::OnReadDirectory(
    372     int request_id, const GURL& path) {
    373   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    374   FileSystemURL url(context_->CrackURL(path));
    375   if (!ValidateFileSystemURL(request_id, url))
    376     return;
    377   if (!security_policy_->CanReadFileSystemFile(process_id_, url)) {
    378     Send(new FileSystemMsg_DidFail(request_id,
    379                                    base::File::FILE_ERROR_SECURITY));
    380     return;
    381   }
    382 
    383   operations_[request_id] = operation_runner()->ReadDirectory(
    384       url, base::Bind(&FileAPIMessageFilter::DidReadDirectory,
    385                       this, request_id));
    386 }
    387 
    388 void FileAPIMessageFilter::OnWrite(
    389     int request_id,
    390     const GURL& path,
    391     const std::string& blob_uuid,
    392     int64 offset) {
    393   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    394   if (!request_context_) {
    395     // We can't write w/o a request context, trying to do so will crash.
    396     NOTREACHED();
    397     return;
    398   }
    399 
    400   FileSystemURL url(context_->CrackURL(path));
    401   if (!ValidateFileSystemURL(request_id, url))
    402     return;
    403   if (!security_policy_->CanWriteFileSystemFile(process_id_, url)) {
    404     Send(new FileSystemMsg_DidFail(request_id,
    405                                    base::File::FILE_ERROR_SECURITY));
    406     return;
    407   }
    408 
    409   scoped_ptr<webkit_blob::BlobDataHandle> blob =
    410       blob_storage_context_->context()->GetBlobDataFromUUID(blob_uuid);
    411 
    412   operations_[request_id] = operation_runner()->Write(
    413       request_context_, url, blob.Pass(), offset,
    414       base::Bind(&FileAPIMessageFilter::DidWrite, this, request_id));
    415 }
    416 
    417 void FileAPIMessageFilter::OnTruncate(
    418     int request_id,
    419     const GURL& path,
    420     int64 length) {
    421   FileSystemURL url(context_->CrackURL(path));
    422   if (!ValidateFileSystemURL(request_id, url))
    423     return;
    424   if (!security_policy_->CanWriteFileSystemFile(process_id_, url)) {
    425     Send(new FileSystemMsg_DidFail(request_id,
    426                                    base::File::FILE_ERROR_SECURITY));
    427     return;
    428   }
    429 
    430   operations_[request_id] = operation_runner()->Truncate(
    431       url, length,
    432       base::Bind(&FileAPIMessageFilter::DidFinish, this, request_id));
    433 }
    434 
    435 void FileAPIMessageFilter::OnTouchFile(
    436     int request_id,
    437     const GURL& path,
    438     const base::Time& last_access_time,
    439     const base::Time& last_modified_time) {
    440   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    441   FileSystemURL url(context_->CrackURL(path));
    442   if (!ValidateFileSystemURL(request_id, url))
    443     return;
    444   if (!security_policy_->CanCreateFileSystemFile(process_id_, url)) {
    445     Send(new FileSystemMsg_DidFail(request_id,
    446                                    base::File::FILE_ERROR_SECURITY));
    447     return;
    448   }
    449 
    450   operations_[request_id] = operation_runner()->TouchFile(
    451       url, last_access_time, last_modified_time,
    452       base::Bind(&FileAPIMessageFilter::DidFinish, this, request_id));
    453 }
    454 
    455 void FileAPIMessageFilter::OnCancel(
    456     int request_id,
    457     int request_id_to_cancel) {
    458   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    459 
    460   OperationsMap::iterator found = operations_.find(request_id_to_cancel);
    461   if (found != operations_.end()) {
    462     // The cancel will eventually send both the write failure and the cancel
    463     // success.
    464     operation_runner()->Cancel(
    465         found->second,
    466         base::Bind(&FileAPIMessageFilter::DidFinish, this, request_id));
    467   } else {
    468     // The write already finished; report that we failed to stop it.
    469     Send(new FileSystemMsg_DidFail(
    470         request_id, base::File::FILE_ERROR_INVALID_OPERATION));
    471   }
    472 }
    473 
    474 void FileAPIMessageFilter::OnSyncGetPlatformPath(
    475     const GURL& path, base::FilePath* platform_path) {
    476   SyncGetPlatformPath(context_, process_id_, path, platform_path);
    477 }
    478 
    479 void FileAPIMessageFilter::OnCreateSnapshotFile(
    480     int request_id, const GURL& path) {
    481   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    482   FileSystemURL url(context_->CrackURL(path));
    483 
    484   // Make sure if this file can be read by the renderer as this is
    485   // called when the renderer is about to create a new File object
    486   // (for reading the file).
    487   if (!ValidateFileSystemURL(request_id, url))
    488     return;
    489   if (!security_policy_->CanReadFileSystemFile(process_id_, url)) {
    490     Send(new FileSystemMsg_DidFail(request_id,
    491                                    base::File::FILE_ERROR_SECURITY));
    492     return;
    493   }
    494 
    495   FileSystemBackend* backend = context_->GetFileSystemBackend(url.type());
    496   if (backend->SupportsStreaming(url)) {
    497     operations_[request_id] = operation_runner()->GetMetadata(
    498         url,
    499         base::Bind(&FileAPIMessageFilter::DidGetMetadataForStreaming,
    500                    this, request_id));
    501   } else {
    502     operations_[request_id] = operation_runner()->CreateSnapshotFile(
    503         url,
    504         base::Bind(&FileAPIMessageFilter::DidCreateSnapshot,
    505                    this, request_id, url));
    506   }
    507 }
    508 
    509 void FileAPIMessageFilter::OnDidReceiveSnapshotFile(int request_id) {
    510   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    511   in_transit_snapshot_files_.erase(request_id);
    512 }
    513 
    514 void FileAPIMessageFilter::OnStartBuildingBlob(const std::string& uuid) {
    515   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    516   ignore_result(blob_storage_host_->StartBuildingBlob(uuid));
    517 }
    518 
    519 void FileAPIMessageFilter::OnAppendBlobDataItemToBlob(
    520     const std::string& uuid, const BlobData::Item& item) {
    521   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    522   if (item.type() == BlobData::Item::TYPE_FILE_FILESYSTEM) {
    523     FileSystemURL filesystem_url(context_->CrackURL(item.filesystem_url()));
    524     if (!FileSystemURLIsValid(context_, filesystem_url) ||
    525         !security_policy_->CanReadFileSystemFile(process_id_, filesystem_url)) {
    526       ignore_result(blob_storage_host_->CancelBuildingBlob(uuid));
    527       return;
    528     }
    529   }
    530   if (item.type() == BlobData::Item::TYPE_FILE &&
    531       !security_policy_->CanReadFile(process_id_, item.path())) {
    532     ignore_result(blob_storage_host_->CancelBuildingBlob(uuid));
    533     return;
    534   }
    535   if (item.length() == 0) {
    536     BadMessageReceived();
    537     return;
    538   }
    539   ignore_result(blob_storage_host_->AppendBlobDataItem(uuid, item));
    540 }
    541 
    542 void FileAPIMessageFilter::OnAppendSharedMemoryToBlob(
    543     const std::string& uuid,
    544     base::SharedMemoryHandle handle,
    545     size_t buffer_size) {
    546   DCHECK(base::SharedMemory::IsHandleValid(handle));
    547   if (!buffer_size) {
    548     BadMessageReceived();
    549     return;
    550   }
    551 #if defined(OS_WIN)
    552   base::SharedMemory shared_memory(handle, true, PeerHandle());
    553 #else
    554   base::SharedMemory shared_memory(handle, true);
    555 #endif
    556   if (!shared_memory.Map(buffer_size)) {
    557     ignore_result(blob_storage_host_->CancelBuildingBlob(uuid));
    558     return;
    559   }
    560 
    561   BlobData::Item item;
    562   item.SetToSharedBytes(static_cast<char*>(shared_memory.memory()),
    563                         buffer_size);
    564   ignore_result(blob_storage_host_->AppendBlobDataItem(uuid, item));
    565 }
    566 
    567 void FileAPIMessageFilter::OnFinishBuildingBlob(
    568     const std::string& uuid, const std::string& content_type) {
    569   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    570   ignore_result(blob_storage_host_->FinishBuildingBlob(uuid, content_type));
    571   // TODO(michaeln): check return values once blink has migrated, crbug/174200
    572 }
    573 
    574 void FileAPIMessageFilter::OnIncrementBlobRefCount(const std::string& uuid) {
    575   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    576   ignore_result(blob_storage_host_->IncrementBlobRefCount(uuid));
    577 }
    578 
    579 void FileAPIMessageFilter::OnDecrementBlobRefCount(const std::string& uuid) {
    580   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    581   ignore_result(blob_storage_host_->DecrementBlobRefCount(uuid));
    582 }
    583 
    584 void FileAPIMessageFilter::OnRegisterPublicBlobURL(
    585     const GURL& public_url, const std::string& uuid) {
    586   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    587   ignore_result(blob_storage_host_->RegisterPublicBlobURL(public_url, uuid));
    588 }
    589 
    590 void FileAPIMessageFilter::OnRevokePublicBlobURL(const GURL& public_url) {
    591   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    592   ignore_result(blob_storage_host_->RevokePublicBlobURL(public_url));
    593 }
    594 
    595 void FileAPIMessageFilter::OnStartBuildingStream(
    596     const GURL& url, const std::string& content_type) {
    597   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    598   // Only an internal Blob URL is expected here. See the BlobURL of the Blink.
    599   if (!StartsWithASCII(
    600           url.path(), "blobinternal%3A///", true /* case_sensitive */)) {
    601     NOTREACHED() << "Malformed Stream URL: " << url.spec();
    602     BadMessageReceived();
    603     return;
    604   }
    605   // Use an empty security origin for now. Stream accepts a security origin
    606   // but how it's handled is not fixed yet.
    607   new Stream(stream_context_->registry(),
    608              NULL /* write_observer */,
    609              url);
    610   stream_urls_.insert(url.spec());
    611 }
    612 
    613 void FileAPIMessageFilter::OnAppendBlobDataItemToStream(
    614     const GURL& url, const BlobData::Item& item) {
    615   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    616 
    617   scoped_refptr<Stream> stream(GetStreamForURL(url));
    618   // Stream instances may be deleted on error. Just abort if there's no Stream
    619   // instance for |url| in the registry.
    620   if (!stream.get())
    621     return;
    622 
    623   // Data for stream is delivered as TYPE_BYTES item.
    624   if (item.type() != BlobData::Item::TYPE_BYTES) {
    625     BadMessageReceived();
    626     return;
    627   }
    628   stream->AddData(item.bytes(), item.length());
    629 }
    630 
    631 void FileAPIMessageFilter::OnAppendSharedMemoryToStream(
    632     const GURL& url, base::SharedMemoryHandle handle, size_t buffer_size) {
    633   DCHECK(base::SharedMemory::IsHandleValid(handle));
    634   if (!buffer_size) {
    635     BadMessageReceived();
    636     return;
    637   }
    638 #if defined(OS_WIN)
    639   base::SharedMemory shared_memory(handle, true, PeerHandle());
    640 #else
    641   base::SharedMemory shared_memory(handle, true);
    642 #endif
    643   if (!shared_memory.Map(buffer_size)) {
    644     OnRemoveStream(url);
    645     return;
    646   }
    647 
    648   scoped_refptr<Stream> stream(GetStreamForURL(url));
    649   if (!stream.get())
    650     return;
    651 
    652   stream->AddData(static_cast<char*>(shared_memory.memory()), buffer_size);
    653 }
    654 
    655 void FileAPIMessageFilter::OnFinishBuildingStream(const GURL& url) {
    656   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    657   scoped_refptr<Stream> stream(GetStreamForURL(url));
    658   if (stream.get())
    659     stream->Finalize();
    660 }
    661 
    662 void FileAPIMessageFilter::OnAbortBuildingStream(const GURL& url) {
    663   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    664   scoped_refptr<Stream> stream(GetStreamForURL(url));
    665   if (stream.get())
    666     stream->Abort();
    667 }
    668 
    669 void FileAPIMessageFilter::OnCloneStream(
    670     const GURL& url, const GURL& src_url) {
    671   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    672   // Abort if there's no Stream instance for |src_url| (source Stream which
    673   // we're going to make |url| point to) in the registry.
    674   if (!GetStreamForURL(src_url))
    675     return;
    676 
    677   stream_context_->registry()->CloneStream(url, src_url);
    678   stream_urls_.insert(url.spec());
    679 }
    680 
    681 void FileAPIMessageFilter::OnRemoveStream(const GURL& url) {
    682   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    683 
    684   if (!GetStreamForURL(url).get())
    685     return;
    686 
    687   stream_context_->registry()->UnregisterStream(url);
    688   stream_urls_.erase(url.spec());
    689 }
    690 
    691 void FileAPIMessageFilter::DidFinish(int request_id,
    692                                      base::File::Error result) {
    693   if (result == base::File::FILE_OK)
    694     Send(new FileSystemMsg_DidSucceed(request_id));
    695   else
    696     Send(new FileSystemMsg_DidFail(request_id, result));
    697   operations_.erase(request_id);
    698 }
    699 
    700 void FileAPIMessageFilter::DidGetMetadata(
    701     int request_id,
    702     base::File::Error result,
    703     const base::File::Info& info) {
    704   if (result == base::File::FILE_OK)
    705     Send(new FileSystemMsg_DidReadMetadata(request_id, info));
    706   else
    707     Send(new FileSystemMsg_DidFail(request_id, result));
    708   operations_.erase(request_id);
    709 }
    710 
    711 void FileAPIMessageFilter::DidGetMetadataForStreaming(
    712     int request_id,
    713     base::File::Error result,
    714     const base::File::Info& info) {
    715   if (result == base::File::FILE_OK) {
    716     // For now, streaming Blobs are implemented as a successful snapshot file
    717     // creation with an empty path.
    718     Send(new FileSystemMsg_DidCreateSnapshotFile(request_id, info,
    719                                                  base::FilePath()));
    720   } else {
    721     Send(new FileSystemMsg_DidFail(request_id, result));
    722   }
    723   operations_.erase(request_id);
    724 }
    725 
    726 void FileAPIMessageFilter::DidReadDirectory(
    727     int request_id,
    728     base::File::Error result,
    729     const std::vector<fileapi::DirectoryEntry>& entries,
    730     bool has_more) {
    731   if (result == base::File::FILE_OK) {
    732     if (!entries.empty() || !has_more)
    733       Send(new FileSystemMsg_DidReadDirectory(request_id, entries, has_more));
    734   } else {
    735     DCHECK(!has_more);
    736     Send(new FileSystemMsg_DidFail(request_id, result));
    737   }
    738   if (!has_more)
    739     operations_.erase(request_id);
    740 }
    741 
    742 void FileAPIMessageFilter::DidWrite(int request_id,
    743                                     base::File::Error result,
    744                                     int64 bytes,
    745                                     bool complete) {
    746   if (result == base::File::FILE_OK) {
    747     Send(new FileSystemMsg_DidWrite(request_id, bytes, complete));
    748     if (complete)
    749       operations_.erase(request_id);
    750   } else {
    751     Send(new FileSystemMsg_DidFail(request_id, result));
    752     operations_.erase(request_id);
    753   }
    754 }
    755 
    756 void FileAPIMessageFilter::DidOpenFileSystem(int request_id,
    757                                              const GURL& root,
    758                                              const std::string& filesystem_name,
    759                                              base::File::Error result) {
    760   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    761   if (result == base::File::FILE_OK) {
    762     DCHECK(root.is_valid());
    763     Send(new FileSystemMsg_DidOpenFileSystem(
    764         request_id, filesystem_name, root));
    765   } else {
    766     Send(new FileSystemMsg_DidFail(request_id, result));
    767   }
    768   // For OpenFileSystem we do not create a new operation, so no unregister here.
    769 }
    770 
    771 void FileAPIMessageFilter::DidResolveURL(
    772     int request_id,
    773     base::File::Error result,
    774     const fileapi::FileSystemInfo& info,
    775     const base::FilePath& file_path,
    776     fileapi::FileSystemContext::ResolvedEntryType type) {
    777   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    778   if (result == base::File::FILE_OK &&
    779       type == fileapi::FileSystemContext::RESOLVED_ENTRY_NOT_FOUND)
    780     result = base::File::FILE_ERROR_NOT_FOUND;
    781 
    782   if (result == base::File::FILE_OK) {
    783     DCHECK(info.root_url.is_valid());
    784     Send(new FileSystemMsg_DidResolveURL(
    785         request_id, info, file_path,
    786         type == fileapi::FileSystemContext::RESOLVED_ENTRY_DIRECTORY));
    787   } else {
    788     Send(new FileSystemMsg_DidFail(request_id, result));
    789   }
    790   // For ResolveURL we do not create a new operation, so no unregister here.
    791 }
    792 
    793 void FileAPIMessageFilter::DidDeleteFileSystem(
    794     int request_id,
    795     base::File::Error result) {
    796   if (result == base::File::FILE_OK)
    797     Send(new FileSystemMsg_DidSucceed(request_id));
    798   else
    799     Send(new FileSystemMsg_DidFail(request_id, result));
    800   // For DeleteFileSystem we do not create a new operation,
    801   // so no unregister here.
    802 }
    803 
    804 void FileAPIMessageFilter::DidCreateSnapshot(
    805     int request_id,
    806     const fileapi::FileSystemURL& url,
    807     base::File::Error result,
    808     const base::File::Info& info,
    809     const base::FilePath& platform_path,
    810     const scoped_refptr<webkit_blob::ShareableFileReference>& /* unused */) {
    811   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    812   operations_.erase(request_id);
    813 
    814   if (result != base::File::FILE_OK) {
    815     Send(new FileSystemMsg_DidFail(request_id, result));
    816     return;
    817   }
    818 
    819   scoped_refptr<webkit_blob::ShareableFileReference> file_ref =
    820       webkit_blob::ShareableFileReference::Get(platform_path);
    821   if (!security_policy_->CanReadFile(process_id_, platform_path)) {
    822     // Give per-file read permission to the snapshot file if it hasn't it yet.
    823     // In order for the renderer to be able to read the file via File object,
    824     // it must be granted per-file read permission for the file's platform
    825     // path. By now, it has already been verified that the renderer has
    826     // sufficient permissions to read the file, so giving per-file permission
    827     // here must be safe.
    828     security_policy_->GrantReadFile(process_id_, platform_path);
    829 
    830     // Revoke all permissions for the file when the last ref of the file
    831     // is dropped.
    832     if (!file_ref.get()) {
    833       // Create a reference for temporary permission handling.
    834       file_ref = webkit_blob::ShareableFileReference::GetOrCreate(
    835           platform_path,
    836           webkit_blob::ShareableFileReference::DONT_DELETE_ON_FINAL_RELEASE,
    837           context_->default_file_task_runner());
    838     }
    839     file_ref->AddFinalReleaseCallback(
    840         base::Bind(&RevokeFilePermission, process_id_));
    841   }
    842 
    843   if (file_ref.get()) {
    844     // This ref is held until OnDidReceiveSnapshotFile is called.
    845     in_transit_snapshot_files_[request_id] = file_ref;
    846   }
    847 
    848   // Return the file info and platform_path.
    849   Send(new FileSystemMsg_DidCreateSnapshotFile(
    850       request_id, info, platform_path));
    851 }
    852 
    853 bool FileAPIMessageFilter::ValidateFileSystemURL(
    854     int request_id, const fileapi::FileSystemURL& url) {
    855   if (!FileSystemURLIsValid(context_, url)) {
    856     Send(new FileSystemMsg_DidFail(request_id,
    857                                    base::File::FILE_ERROR_INVALID_URL));
    858     return false;
    859   }
    860 
    861   // Deny access to files in PluginPrivate FileSystem from JavaScript.
    862   // TODO(nhiroki): Move this filter somewhere else since this is not for
    863   // validation.
    864   if (url.type() == fileapi::kFileSystemTypePluginPrivate) {
    865     Send(new FileSystemMsg_DidFail(request_id,
    866                                    base::File::FILE_ERROR_SECURITY));
    867     return false;
    868   }
    869 
    870   return true;
    871 }
    872 
    873 scoped_refptr<Stream> FileAPIMessageFilter::GetStreamForURL(const GURL& url) {
    874   return stream_context_->registry()->GetStream(url);
    875 }
    876 
    877 }  // namespace content
    878