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/platform_file.h"
     15 #include "base/sequenced_task_runner.h"
     16 #include "base/strings/string_util.h"
     17 #include "base/threading/thread.h"
     18 #include "base/time/time.h"
     19 #include "content/browser/child_process_security_policy_impl.h"
     20 #include "content/browser/fileapi/browser_file_system_helper.h"
     21 #include "content/browser/fileapi/chrome_blob_storage_context.h"
     22 #include "content/browser/streams/stream_registry.h"
     23 #include "content/common/fileapi/file_system_messages.h"
     24 #include "content/common/fileapi/webblob_messages.h"
     25 #include "content/public/browser/user_metrics.h"
     26 #include "ipc/ipc_platform_file.h"
     27 #include "net/base/mime_util.h"
     28 #include "net/url_request/url_request_context.h"
     29 #include "net/url_request/url_request_context_getter.h"
     30 #include "url/gurl.h"
     31 #include "webkit/browser/blob/blob_storage_controller.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/browser/quota/quota_manager.h"
     37 #include "webkit/common/blob/blob_data.h"
     38 #include "webkit/common/blob/shareable_file_reference.h"
     39 #include "webkit/common/fileapi/directory_entry.h"
     40 #include "webkit/common/fileapi/file_system_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 fileapi::FileUpdateObserver;
     48 using fileapi::UpdateObserverList;
     49 using webkit_blob::BlobData;
     50 using webkit_blob::BlobStorageController;
     51 
     52 namespace content {
     53 
     54 namespace {
     55 
     56 void RevokeFilePermission(int child_id, const base::FilePath& path) {
     57   ChildProcessSecurityPolicyImpl::GetInstance()->RevokeAllPermissionsForFile(
     58     child_id, path);
     59 }
     60 
     61 }  // namespace
     62 
     63 FileAPIMessageFilter::FileAPIMessageFilter(
     64     int process_id,
     65     net::URLRequestContextGetter* request_context_getter,
     66     fileapi::FileSystemContext* file_system_context,
     67     ChromeBlobStorageContext* blob_storage_context,
     68     StreamContext* stream_context)
     69     : process_id_(process_id),
     70       context_(file_system_context),
     71       request_context_getter_(request_context_getter),
     72       request_context_(NULL),
     73       blob_storage_context_(blob_storage_context),
     74       stream_context_(stream_context) {
     75   DCHECK(context_);
     76   DCHECK(request_context_getter_.get());
     77   DCHECK(blob_storage_context);
     78   DCHECK(stream_context);
     79 }
     80 
     81 FileAPIMessageFilter::FileAPIMessageFilter(
     82     int process_id,
     83     net::URLRequestContext* request_context,
     84     fileapi::FileSystemContext* file_system_context,
     85     ChromeBlobStorageContext* blob_storage_context,
     86     StreamContext* stream_context)
     87     : process_id_(process_id),
     88       context_(file_system_context),
     89       request_context_(request_context),
     90       blob_storage_context_(blob_storage_context),
     91       stream_context_(stream_context) {
     92   DCHECK(context_);
     93   DCHECK(request_context_);
     94   DCHECK(blob_storage_context);
     95   DCHECK(stream_context);
     96 }
     97 
     98 void FileAPIMessageFilter::OnChannelConnected(int32 peer_pid) {
     99   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    100   BrowserMessageFilter::OnChannelConnected(peer_pid);
    101 
    102   if (request_context_getter_.get()) {
    103     DCHECK(!request_context_);
    104     request_context_ = request_context_getter_->GetURLRequestContext();
    105     request_context_getter_ = NULL;
    106     DCHECK(request_context_);
    107   }
    108 
    109   operation_runner_ = context_->CreateFileSystemOperationRunner();
    110 }
    111 
    112 void FileAPIMessageFilter::OnChannelClosing() {
    113   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    114   BrowserMessageFilter::OnChannelClosing();
    115 
    116   // Unregister all the blob and stream URLs that are previously registered in
    117   // this process.
    118   for (base::hash_set<std::string>::const_iterator iter = blob_urls_.begin();
    119        iter != blob_urls_.end(); ++iter) {
    120     blob_storage_context_->controller()->RemoveBlob(GURL(*iter));
    121   }
    122   for (base::hash_set<std::string>::const_iterator iter = stream_urls_.begin();
    123        iter != stream_urls_.end(); ++iter) {
    124     stream_context_->registry()->UnregisterStream(GURL(*iter));
    125   }
    126 
    127   in_transit_snapshot_files_.clear();
    128 
    129   // Close all files that are previously OpenFile()'ed in this process.
    130   if (!on_close_callbacks_.IsEmpty()) {
    131     DLOG(INFO)
    132         << "File API: Renderer process shut down before NotifyCloseFile"
    133         << " for " << on_close_callbacks_.size() << " files opened in PPAPI";
    134   }
    135 
    136   for (OnCloseCallbackMap::iterator itr(&on_close_callbacks_);
    137        !itr.IsAtEnd(); itr.Advance()) {
    138     const base::Closure* callback = itr.GetCurrentValue();
    139     DCHECK(callback);
    140     if (!callback->is_null())
    141       callback->Run();
    142   }
    143 
    144   on_close_callbacks_.Clear();
    145   operation_runner_.reset();
    146   operations_.clear();
    147 }
    148 
    149 base::TaskRunner* FileAPIMessageFilter::OverrideTaskRunnerForMessage(
    150     const IPC::Message& message) {
    151   if (message.type() == FileSystemHostMsg_SyncGetPlatformPath::ID)
    152     return context_->default_file_task_runner();
    153   return NULL;
    154 }
    155 
    156 bool FileAPIMessageFilter::OnMessageReceived(
    157     const IPC::Message& message, bool* message_was_ok) {
    158   *message_was_ok = true;
    159   bool handled = true;
    160   IPC_BEGIN_MESSAGE_MAP_EX(FileAPIMessageFilter, message, *message_was_ok)
    161     IPC_MESSAGE_HANDLER(FileSystemHostMsg_Open, OnOpen)
    162     IPC_MESSAGE_HANDLER(FileSystemHostMsg_DeleteFileSystem, OnDeleteFileSystem)
    163     IPC_MESSAGE_HANDLER(FileSystemHostMsg_Move, OnMove)
    164     IPC_MESSAGE_HANDLER(FileSystemHostMsg_Copy, OnCopy)
    165     IPC_MESSAGE_HANDLER(FileSystemMsg_Remove, OnRemove)
    166     IPC_MESSAGE_HANDLER(FileSystemHostMsg_ReadMetadata, OnReadMetadata)
    167     IPC_MESSAGE_HANDLER(FileSystemHostMsg_Create, OnCreate)
    168     IPC_MESSAGE_HANDLER(FileSystemHostMsg_Exists, OnExists)
    169     IPC_MESSAGE_HANDLER(FileSystemHostMsg_ReadDirectory, OnReadDirectory)
    170     IPC_MESSAGE_HANDLER(FileSystemHostMsg_Write, OnWrite)
    171     IPC_MESSAGE_HANDLER(FileSystemHostMsg_Truncate, OnTruncate)
    172     IPC_MESSAGE_HANDLER(FileSystemHostMsg_TouchFile, OnTouchFile)
    173     IPC_MESSAGE_HANDLER(FileSystemHostMsg_CancelWrite, OnCancel)
    174     IPC_MESSAGE_HANDLER(FileSystemHostMsg_OpenFile, OnOpenFile)
    175     IPC_MESSAGE_HANDLER(FileSystemHostMsg_NotifyCloseFile, OnNotifyCloseFile)
    176     IPC_MESSAGE_HANDLER(FileSystemHostMsg_CreateSnapshotFile,
    177                         OnCreateSnapshotFile)
    178     IPC_MESSAGE_HANDLER(FileSystemHostMsg_DidReceiveSnapshotFile,
    179                         OnDidReceiveSnapshotFile)
    180     IPC_MESSAGE_HANDLER(FileSystemHostMsg_WillUpdate, OnWillUpdate)
    181     IPC_MESSAGE_HANDLER(FileSystemHostMsg_DidUpdate, OnDidUpdate)
    182     IPC_MESSAGE_HANDLER(FileSystemHostMsg_SyncGetPlatformPath,
    183                         OnSyncGetPlatformPath)
    184     IPC_MESSAGE_HANDLER(BlobHostMsg_StartBuilding, OnStartBuildingBlob)
    185     IPC_MESSAGE_HANDLER(BlobHostMsg_AppendBlobDataItem,
    186                         OnAppendBlobDataItemToBlob)
    187     IPC_MESSAGE_HANDLER(BlobHostMsg_SyncAppendSharedMemory,
    188                         OnAppendSharedMemoryToBlob)
    189     IPC_MESSAGE_HANDLER(BlobHostMsg_FinishBuilding, OnFinishBuildingBlob)
    190     IPC_MESSAGE_HANDLER(BlobHostMsg_Clone, OnCloneBlob)
    191     IPC_MESSAGE_HANDLER(BlobHostMsg_Remove, OnRemoveBlob)
    192     IPC_MESSAGE_HANDLER(StreamHostMsg_StartBuilding, OnStartBuildingStream)
    193     IPC_MESSAGE_HANDLER(StreamHostMsg_AppendBlobDataItem,
    194                         OnAppendBlobDataItemToStream)
    195     IPC_MESSAGE_HANDLER(StreamHostMsg_SyncAppendSharedMemory,
    196                         OnAppendSharedMemoryToStream)
    197     IPC_MESSAGE_HANDLER(StreamHostMsg_FinishBuilding, OnFinishBuildingStream)
    198     IPC_MESSAGE_HANDLER(StreamHostMsg_Clone, OnCloneStream)
    199     IPC_MESSAGE_HANDLER(StreamHostMsg_Remove, OnRemoveStream)
    200     IPC_MESSAGE_UNHANDLED(handled = false)
    201   IPC_END_MESSAGE_MAP_EX()
    202   return handled;
    203 }
    204 
    205 FileAPIMessageFilter::~FileAPIMessageFilter() {}
    206 
    207 void FileAPIMessageFilter::BadMessageReceived() {
    208   RecordAction(UserMetricsAction("BadMessageTerminate_FAMF"));
    209   BrowserMessageFilter::BadMessageReceived();
    210 }
    211 
    212 void FileAPIMessageFilter::OnOpen(
    213     int request_id, const GURL& origin_url, fileapi::FileSystemType type,
    214     int64 requested_size, bool create) {
    215   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    216   if (type == fileapi::kFileSystemTypeTemporary) {
    217     RecordAction(UserMetricsAction("OpenFileSystemTemporary"));
    218   } else if (type == fileapi::kFileSystemTypePersistent) {
    219     RecordAction(UserMetricsAction("OpenFileSystemPersistent"));
    220   }
    221   // TODO(kinuko): Use this mode for IPC too.
    222   fileapi::OpenFileSystemMode mode =
    223       create ? fileapi::OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT
    224              : fileapi::OPEN_FILE_SYSTEM_FAIL_IF_NONEXISTENT;
    225   context_->OpenFileSystem(origin_url, type, mode, base::Bind(
    226       &FileAPIMessageFilter::DidOpenFileSystem, this, request_id));
    227 }
    228 
    229 void FileAPIMessageFilter::OnDeleteFileSystem(
    230     int request_id,
    231     const GURL& origin_url,
    232     fileapi::FileSystemType type) {
    233   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    234   context_->DeleteFileSystem(origin_url, type, base::Bind(
    235       &FileAPIMessageFilter::DidDeleteFileSystem, this, request_id));
    236 }
    237 
    238 void FileAPIMessageFilter::OnMove(
    239     int request_id, const GURL& src_path, const GURL& dest_path) {
    240   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    241   base::PlatformFileError error;
    242   FileSystemURL src_url(context_->CrackURL(src_path));
    243   FileSystemURL dest_url(context_->CrackURL(dest_path));
    244   const int src_permissions =
    245       fileapi::kReadFilePermissions | fileapi::kWriteFilePermissions;
    246   if (!HasPermissionsForFile(src_url, src_permissions, &error) ||
    247       !HasPermissionsForFile(
    248           dest_url, fileapi::kCreateFilePermissions, &error)) {
    249     Send(new FileSystemMsg_DidFail(request_id, error));
    250     return;
    251   }
    252 
    253   operations_[request_id] = operation_runner()->Move(
    254       src_url, dest_url,
    255       base::Bind(&FileAPIMessageFilter::DidFinish, this, request_id));
    256 }
    257 
    258 void FileAPIMessageFilter::OnCopy(
    259     int request_id, const GURL& src_path, const GURL& dest_path) {
    260   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    261   base::PlatformFileError error;
    262   FileSystemURL src_url(context_->CrackURL(src_path));
    263   FileSystemURL dest_url(context_->CrackURL(dest_path));
    264   if (!HasPermissionsForFile(src_url, fileapi::kReadFilePermissions, &error) ||
    265       !HasPermissionsForFile(
    266           dest_url, fileapi::kCreateFilePermissions, &error)) {
    267     Send(new FileSystemMsg_DidFail(request_id, error));
    268     return;
    269   }
    270 
    271   operations_[request_id] = operation_runner()->Copy(
    272       src_url, dest_url,
    273       base::Bind(&FileAPIMessageFilter::DidFinish, this, request_id));
    274 }
    275 
    276 void FileAPIMessageFilter::OnRemove(
    277     int request_id, const GURL& path, bool recursive) {
    278   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    279   base::PlatformFileError error;
    280   FileSystemURL url(context_->CrackURL(path));
    281   if (!HasPermissionsForFile(url, fileapi::kWriteFilePermissions, &error)) {
    282     Send(new FileSystemMsg_DidFail(request_id, error));
    283     return;
    284   }
    285 
    286   operations_[request_id] = operation_runner()->Remove(
    287       url, recursive,
    288       base::Bind(&FileAPIMessageFilter::DidFinish, this, request_id));
    289 }
    290 
    291 void FileAPIMessageFilter::OnReadMetadata(
    292     int request_id, const GURL& path) {
    293   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    294   base::PlatformFileError error;
    295   FileSystemURL url(context_->CrackURL(path));
    296   if (!HasPermissionsForFile(url, fileapi::kReadFilePermissions, &error)) {
    297     Send(new FileSystemMsg_DidFail(request_id, error));
    298     return;
    299   }
    300 
    301   operations_[request_id] = operation_runner()->GetMetadata(
    302       url, base::Bind(&FileAPIMessageFilter::DidGetMetadata, this, request_id));
    303 }
    304 
    305 void FileAPIMessageFilter::OnCreate(
    306     int request_id, const GURL& path, bool exclusive,
    307     bool is_directory, bool recursive) {
    308   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    309   base::PlatformFileError error;
    310   FileSystemURL url(context_->CrackURL(path));
    311   if (!HasPermissionsForFile(url, fileapi::kCreateFilePermissions, &error)) {
    312     Send(new FileSystemMsg_DidFail(request_id, error));
    313     return;
    314   }
    315 
    316   if (is_directory) {
    317     operations_[request_id] = operation_runner()->CreateDirectory(
    318         url, exclusive, recursive,
    319         base::Bind(&FileAPIMessageFilter::DidFinish, this, request_id));
    320   } else {
    321     operations_[request_id] = operation_runner()->CreateFile(
    322         url, exclusive,
    323         base::Bind(&FileAPIMessageFilter::DidFinish, this, request_id));
    324   }
    325 }
    326 
    327 void FileAPIMessageFilter::OnExists(
    328     int request_id, const GURL& path, bool is_directory) {
    329   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    330   base::PlatformFileError error;
    331   FileSystemURL url(context_->CrackURL(path));
    332   if (!HasPermissionsForFile(url, fileapi::kReadFilePermissions, &error)) {
    333     Send(new FileSystemMsg_DidFail(request_id, error));
    334     return;
    335   }
    336 
    337   if (is_directory) {
    338     operations_[request_id] = operation_runner()->DirectoryExists(
    339         url,
    340         base::Bind(&FileAPIMessageFilter::DidFinish, this, request_id));
    341   } else {
    342     operations_[request_id] = operation_runner()->FileExists(
    343         url,
    344         base::Bind(&FileAPIMessageFilter::DidFinish, this, request_id));
    345   }
    346 }
    347 
    348 void FileAPIMessageFilter::OnReadDirectory(
    349     int request_id, const GURL& path) {
    350   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    351   base::PlatformFileError error;
    352   FileSystemURL url(context_->CrackURL(path));
    353   if (!HasPermissionsForFile(url, fileapi::kReadFilePermissions, &error)) {
    354     Send(new FileSystemMsg_DidFail(request_id, error));
    355     return;
    356   }
    357 
    358   operations_[request_id] = operation_runner()->ReadDirectory(
    359       url, base::Bind(&FileAPIMessageFilter::DidReadDirectory,
    360                       this, request_id));
    361 }
    362 
    363 void FileAPIMessageFilter::OnWrite(
    364     int request_id,
    365     const GURL& path,
    366     const GURL& blob_url,
    367     int64 offset) {
    368   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    369   if (!request_context_) {
    370     // We can't write w/o a request context, trying to do so will crash.
    371     NOTREACHED();
    372     return;
    373   }
    374 
    375   FileSystemURL url(context_->CrackURL(path));
    376   base::PlatformFileError error;
    377   if (!HasPermissionsForFile(url, fileapi::kWriteFilePermissions, &error)) {
    378     Send(new FileSystemMsg_DidFail(request_id, error));
    379     return;
    380   }
    381 
    382   operations_[request_id] = operation_runner()->Write(
    383       request_context_, url, blob_url, offset,
    384       base::Bind(&FileAPIMessageFilter::DidWrite, this, request_id));
    385 }
    386 
    387 void FileAPIMessageFilter::OnTruncate(
    388     int request_id,
    389     const GURL& path,
    390     int64 length) {
    391   base::PlatformFileError error;
    392   FileSystemURL url(context_->CrackURL(path));
    393   if (!HasPermissionsForFile(url, fileapi::kWriteFilePermissions, &error)) {
    394     Send(new FileSystemMsg_DidFail(request_id, error));
    395     return;
    396   }
    397 
    398   operations_[request_id] = operation_runner()->Truncate(
    399       url, length,
    400       base::Bind(&FileAPIMessageFilter::DidFinish, this, request_id));
    401 }
    402 
    403 void FileAPIMessageFilter::OnTouchFile(
    404     int request_id,
    405     const GURL& path,
    406     const base::Time& last_access_time,
    407     const base::Time& last_modified_time) {
    408   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    409   FileSystemURL url(context_->CrackURL(path));
    410   base::PlatformFileError error;
    411   if (!HasPermissionsForFile(url, fileapi::kCreateFilePermissions, &error)) {
    412     Send(new FileSystemMsg_DidFail(request_id, error));
    413     return;
    414   }
    415 
    416   operations_[request_id] = operation_runner()->TouchFile(
    417       url, last_access_time, last_modified_time,
    418       base::Bind(&FileAPIMessageFilter::DidFinish, this, request_id));
    419 }
    420 
    421 void FileAPIMessageFilter::OnCancel(
    422     int request_id,
    423     int request_id_to_cancel) {
    424   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    425 
    426   OperationsMap::iterator found = operations_.find(request_id_to_cancel);
    427   if (found != operations_.end()) {
    428     // The cancel will eventually send both the write failure and the cancel
    429     // success.
    430     operation_runner()->Cancel(
    431         found->second,
    432         base::Bind(&FileAPIMessageFilter::DidFinish, this, request_id));
    433   } else {
    434     // The write already finished; report that we failed to stop it.
    435     Send(new FileSystemMsg_DidFail(
    436         request_id, base::PLATFORM_FILE_ERROR_INVALID_OPERATION));
    437   }
    438 }
    439 
    440 void FileAPIMessageFilter::OnOpenFile(
    441     int request_id, const GURL& path, int file_flags) {
    442   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    443   base::PlatformFileError error;
    444   const int open_permissions = file_flags & fileapi::kOpenPepperFilePermissions;
    445   FileSystemURL url(context_->CrackURL(path));
    446   if (!HasPermissionsForFile(url, open_permissions, &error)) {
    447     Send(new FileSystemMsg_DidFail(request_id, error));
    448     return;
    449   }
    450 
    451   quota::QuotaLimitType quota_policy = quota::kQuotaLimitTypeUnknown;
    452   quota::QuotaManagerProxy* quota_manager_proxy =
    453       context_->quota_manager_proxy();
    454   CHECK(quota_manager_proxy);
    455   CHECK(quota_manager_proxy->quota_manager());
    456 
    457   if (quota_manager_proxy->quota_manager()->IsStorageUnlimited(
    458           url.origin(), FileSystemTypeToQuotaStorageType(url.type()))) {
    459     quota_policy = quota::kQuotaLimitTypeUnlimited;
    460   } else {
    461     quota_policy = quota::kQuotaLimitTypeLimited;
    462   }
    463 
    464   operations_[request_id] = operation_runner()->OpenFile(
    465       url, open_permissions, PeerHandle(),
    466       base::Bind(&FileAPIMessageFilter::DidOpenFile, this, request_id,
    467                  quota_policy));
    468 }
    469 
    470 void FileAPIMessageFilter::OnNotifyCloseFile(int file_open_id) {
    471   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    472 
    473   // Remove |file_open_id| from the map of |on_close_callback|s.
    474   // It must only be called for a ID that is successfully opened and enrolled in
    475   // DidOpenFile.
    476   base::Closure* on_close_callback = on_close_callbacks_.Lookup(file_open_id);
    477   if (on_close_callback && !on_close_callback->is_null()) {
    478     on_close_callback->Run();
    479     on_close_callbacks_.Remove(file_open_id);
    480   }
    481 }
    482 
    483 void FileAPIMessageFilter::OnWillUpdate(const GURL& path) {
    484   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    485   FileSystemURL url(context_->CrackURL(path));
    486   if (!url.is_valid())
    487     return;
    488   const UpdateObserverList* observers =
    489       context_->GetUpdateObservers(url.type());
    490   if (!observers)
    491     return;
    492   observers->Notify(&FileUpdateObserver::OnStartUpdate, MakeTuple(url));
    493 }
    494 
    495 void FileAPIMessageFilter::OnDidUpdate(const GURL& path, int64 delta) {
    496   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    497   FileSystemURL url(context_->CrackURL(path));
    498   if (!url.is_valid())
    499     return;
    500   const UpdateObserverList* observers =
    501       context_->GetUpdateObservers(url.type());
    502   if (!observers)
    503     return;
    504   observers->Notify(&FileUpdateObserver::OnUpdate, MakeTuple(url, delta));
    505   observers->Notify(&FileUpdateObserver::OnEndUpdate, MakeTuple(url));
    506 }
    507 
    508 void FileAPIMessageFilter::OnSyncGetPlatformPath(
    509     const GURL& path, base::FilePath* platform_path) {
    510   SyncGetPlatformPath(context_, process_id_, path, platform_path);
    511 }
    512 
    513 void FileAPIMessageFilter::OnCreateSnapshotFile(
    514     int request_id, const GURL& path) {
    515   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    516   FileSystemURL url(context_->CrackURL(path));
    517 
    518   // Make sure if this file can be read by the renderer as this is
    519   // called when the renderer is about to create a new File object
    520   // (for reading the file).
    521   base::PlatformFileError error;
    522   if (!HasPermissionsForFile(url, fileapi::kReadFilePermissions, &error)) {
    523     Send(new FileSystemMsg_DidFail(request_id, error));
    524     return;
    525   }
    526 
    527   operations_[request_id] = operation_runner()->CreateSnapshotFile(
    528       url,
    529       base::Bind(&FileAPIMessageFilter::DidCreateSnapshot,
    530                  this, request_id, url));
    531 }
    532 
    533 void FileAPIMessageFilter::OnDidReceiveSnapshotFile(int request_id) {
    534   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    535   in_transit_snapshot_files_.erase(request_id);
    536 }
    537 
    538 void FileAPIMessageFilter::OnStartBuildingBlob(const GURL& url) {
    539   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    540   blob_storage_context_->controller()->StartBuildingBlob(url);
    541   blob_urls_.insert(url.spec());
    542 }
    543 
    544 void FileAPIMessageFilter::OnAppendBlobDataItemToBlob(
    545     const GURL& url, const BlobData::Item& item) {
    546   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    547   if (item.type() == BlobData::Item::TYPE_FILE_FILESYSTEM) {
    548     base::PlatformFileError error;
    549     FileSystemURL filesystem_url(context_->CrackURL(item.url()));
    550     if (!HasPermissionsForFile(filesystem_url,
    551                                fileapi::kReadFilePermissions, &error)) {
    552       OnRemoveBlob(url);
    553       return;
    554     }
    555   }
    556   if (item.type() == BlobData::Item::TYPE_FILE &&
    557       !ChildProcessSecurityPolicyImpl::GetInstance()->CanReadFile(
    558           process_id_, item.path())) {
    559     OnRemoveBlob(url);
    560     return;
    561   }
    562   if (item.length() == 0) {
    563     BadMessageReceived();
    564     return;
    565   }
    566   blob_storage_context_->controller()->AppendBlobDataItem(url, item);
    567 }
    568 
    569 void FileAPIMessageFilter::OnAppendSharedMemoryToBlob(
    570     const GURL& url, base::SharedMemoryHandle handle, size_t buffer_size) {
    571   DCHECK(base::SharedMemory::IsHandleValid(handle));
    572   if (!buffer_size) {
    573     BadMessageReceived();
    574     return;
    575   }
    576 #if defined(OS_WIN)
    577   base::SharedMemory shared_memory(handle, true, PeerHandle());
    578 #else
    579   base::SharedMemory shared_memory(handle, true);
    580 #endif
    581   if (!shared_memory.Map(buffer_size)) {
    582     OnRemoveBlob(url);
    583     return;
    584   }
    585 
    586   BlobData::Item item;
    587   item.SetToSharedBytes(static_cast<char*>(shared_memory.memory()),
    588                         buffer_size);
    589   blob_storage_context_->controller()->AppendBlobDataItem(url, item);
    590 }
    591 
    592 void FileAPIMessageFilter::OnFinishBuildingBlob(
    593     const GURL& url, const std::string& content_type) {
    594   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    595   blob_storage_context_->controller()->FinishBuildingBlob(url, content_type);
    596 }
    597 
    598 void FileAPIMessageFilter::OnCloneBlob(
    599     const GURL& url, const GURL& src_url) {
    600   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    601   blob_storage_context_->controller()->CloneBlob(url, src_url);
    602   blob_urls_.insert(url.spec());
    603 }
    604 
    605 void FileAPIMessageFilter::OnRemoveBlob(const GURL& url) {
    606   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    607   blob_storage_context_->controller()->RemoveBlob(url);
    608   blob_urls_.erase(url.spec());
    609 }
    610 
    611 void FileAPIMessageFilter::OnStartBuildingStream(
    612     const GURL& url, const std::string& content_type) {
    613   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    614   // Only an internal Blob URL is expected here. See the BlobURL of the Blink.
    615   if (!StartsWithASCII(
    616           url.path(), "blobinternal%3A///", true /* case_sensitive */)) {
    617     NOTREACHED() << "Malformed Stream URL: " << url.spec();
    618     BadMessageReceived();
    619     return;
    620   }
    621   // Use an empty security origin for now. Stream accepts a security origin
    622   // but how it's handled is not fixed yet.
    623   new Stream(stream_context_->registry(),
    624              NULL /* write_observer */,
    625              url);
    626   stream_urls_.insert(url.spec());
    627 }
    628 
    629 void FileAPIMessageFilter::OnAppendBlobDataItemToStream(
    630     const GURL& url, const BlobData::Item& item) {
    631   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    632 
    633   scoped_refptr<Stream> stream(GetStreamForURL(url));
    634   if (!stream.get()) {
    635     NOTREACHED();
    636     return;
    637   }
    638 
    639   // Data for stream is delivered as TYPE_BYTES item.
    640   if (item.type() != BlobData::Item::TYPE_BYTES) {
    641     BadMessageReceived();
    642     return;
    643   }
    644   stream->AddData(item.bytes(), item.length());
    645 }
    646 
    647 void FileAPIMessageFilter::OnAppendSharedMemoryToStream(
    648     const GURL& url, base::SharedMemoryHandle handle, size_t buffer_size) {
    649   DCHECK(base::SharedMemory::IsHandleValid(handle));
    650   if (!buffer_size) {
    651     BadMessageReceived();
    652     return;
    653   }
    654 #if defined(OS_WIN)
    655   base::SharedMemory shared_memory(handle, true, PeerHandle());
    656 #else
    657   base::SharedMemory shared_memory(handle, true);
    658 #endif
    659   if (!shared_memory.Map(buffer_size)) {
    660     OnRemoveStream(url);
    661     return;
    662   }
    663 
    664   scoped_refptr<Stream> stream(GetStreamForURL(url));
    665   if (!stream.get()) {
    666     NOTREACHED();
    667     return;
    668   }
    669 
    670   stream->AddData(static_cast<char*>(shared_memory.memory()), buffer_size);
    671 }
    672 
    673 void FileAPIMessageFilter::OnFinishBuildingStream(const GURL& url) {
    674   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    675   scoped_refptr<Stream> stream(GetStreamForURL(url));
    676   if (stream.get())
    677     stream->Finalize();
    678   else
    679     NOTREACHED();
    680 }
    681 
    682 void FileAPIMessageFilter::OnCloneStream(
    683     const GURL& url, const GURL& src_url) {
    684   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    685   if (!GetStreamForURL(src_url)) {
    686     NOTREACHED();
    687     return;
    688   }
    689 
    690   stream_context_->registry()->CloneStream(url, src_url);
    691   stream_urls_.insert(url.spec());
    692 }
    693 
    694 void FileAPIMessageFilter::OnRemoveStream(const GURL& url) {
    695   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    696 
    697   if (!GetStreamForURL(url).get()) {
    698     NOTREACHED();
    699     return;
    700   }
    701 
    702   stream_context_->registry()->UnregisterStream(url);
    703   stream_urls_.erase(url.spec());
    704 }
    705 
    706 void FileAPIMessageFilter::DidFinish(int request_id,
    707                                      base::PlatformFileError result) {
    708   if (result == base::PLATFORM_FILE_OK)
    709     Send(new FileSystemMsg_DidSucceed(request_id));
    710   else
    711     Send(new FileSystemMsg_DidFail(request_id, result));
    712   operations_.erase(request_id);
    713 }
    714 
    715 void FileAPIMessageFilter::DidGetMetadata(
    716     int request_id,
    717     base::PlatformFileError result,
    718     const base::PlatformFileInfo& info) {
    719   if (result == base::PLATFORM_FILE_OK)
    720     Send(new FileSystemMsg_DidReadMetadata(request_id, info));
    721   else
    722     Send(new FileSystemMsg_DidFail(request_id, result));
    723   operations_.erase(request_id);
    724 }
    725 
    726 void FileAPIMessageFilter::DidReadDirectory(
    727     int request_id,
    728     base::PlatformFileError result,
    729     const std::vector<fileapi::DirectoryEntry>& entries,
    730     bool has_more) {
    731   if (result == base::PLATFORM_FILE_OK)
    732     Send(new FileSystemMsg_DidReadDirectory(request_id, entries, has_more));
    733   else
    734     Send(new FileSystemMsg_DidFail(request_id, result));
    735   operations_.erase(request_id);
    736 }
    737 
    738 void FileAPIMessageFilter::DidOpenFile(int request_id,
    739                                        quota::QuotaLimitType quota_policy,
    740                                        base::PlatformFileError result,
    741                                        base::PlatformFile file,
    742                                        const base::Closure& on_close_callback,
    743                                        base::ProcessHandle peer_handle) {
    744   if (result == base::PLATFORM_FILE_OK) {
    745     IPC::PlatformFileForTransit file_for_transit =
    746         file != base::kInvalidPlatformFileValue ?
    747             IPC::GetFileHandleForProcess(file, peer_handle, true) :
    748             IPC::InvalidPlatformFileForTransit();
    749     int file_open_id = on_close_callbacks_.Add(
    750         new base::Closure(on_close_callback));
    751 
    752     Send(new FileSystemMsg_DidOpenFile(request_id,
    753                                        file_for_transit,
    754                                        file_open_id,
    755                                        quota_policy));
    756   } else {
    757     Send(new FileSystemMsg_DidFail(request_id,
    758                                    result));
    759   }
    760   operations_.erase(request_id);
    761 }
    762 
    763 void FileAPIMessageFilter::DidWrite(int request_id,
    764                                     base::PlatformFileError result,
    765                                     int64 bytes,
    766                                     bool complete) {
    767   if (result == base::PLATFORM_FILE_OK) {
    768     Send(new FileSystemMsg_DidWrite(request_id, bytes, complete));
    769     if (complete)
    770       operations_.erase(request_id);
    771   } else {
    772     Send(new FileSystemMsg_DidFail(request_id, result));
    773     operations_.erase(request_id);
    774   }
    775 }
    776 
    777 void FileAPIMessageFilter::DidOpenFileSystem(int request_id,
    778                                              base::PlatformFileError result,
    779                                              const std::string& name,
    780                                              const GURL& root) {
    781   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    782   if (result == base::PLATFORM_FILE_OK) {
    783     DCHECK(root.is_valid());
    784     Send(new FileSystemMsg_DidOpenFileSystem(request_id, name, root));
    785   } else {
    786     Send(new FileSystemMsg_DidFail(request_id, result));
    787   }
    788   // For OpenFileSystem we do not create a new operation, so no unregister here.
    789 }
    790 
    791 void FileAPIMessageFilter::DidDeleteFileSystem(
    792     int request_id,
    793     base::PlatformFileError result) {
    794   if (result == base::PLATFORM_FILE_OK)
    795     Send(new FileSystemMsg_DidSucceed(request_id));
    796   else
    797     Send(new FileSystemMsg_DidFail(request_id, result));
    798   // For DeleteFileSystem we do not create a new operation,
    799   // so no unregister here.
    800 }
    801 
    802 void FileAPIMessageFilter::DidCreateSnapshot(
    803     int request_id,
    804     const fileapi::FileSystemURL& url,
    805     base::PlatformFileError result,
    806     const base::PlatformFileInfo& info,
    807     const base::FilePath& platform_path,
    808     const scoped_refptr<webkit_blob::ShareableFileReference>& snapshot_file) {
    809   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    810   operations_.erase(request_id);
    811 
    812   if (result != base::PLATFORM_FILE_OK) {
    813     Send(new FileSystemMsg_DidFail(request_id, result));
    814     return;
    815   }
    816 
    817   scoped_refptr<webkit_blob::ShareableFileReference> file_ref = snapshot_file;
    818   if (!ChildProcessSecurityPolicyImpl::GetInstance()->CanReadFile(
    819           process_id_, platform_path)) {
    820     // Give per-file read permission to the snapshot file if it hasn't it yet.
    821     // In order for the renderer to be able to read the file via File object,
    822     // it must be granted per-file read permission for the file's platform
    823     // path. By now, it has already been verified that the renderer has
    824     // sufficient permissions to read the file, so giving per-file permission
    825     // here must be safe.
    826     ChildProcessSecurityPolicyImpl::GetInstance()->GrantReadFile(
    827         process_id_, platform_path);
    828 
    829     // Revoke all permissions for the file when the last ref of the file
    830     // is dropped.
    831     if (!file_ref.get()) {
    832       // Create a reference for temporary permission handling.
    833       file_ref = webkit_blob::ShareableFileReference::GetOrCreate(
    834           platform_path,
    835           webkit_blob::ShareableFileReference::DONT_DELETE_ON_FINAL_RELEASE,
    836           context_->default_file_task_runner());
    837     }
    838     file_ref->AddFinalReleaseCallback(
    839         base::Bind(&RevokeFilePermission, process_id_));
    840   }
    841 
    842   if (file_ref.get()) {
    843     // This ref is held until OnDidReceiveSnapshotFile is called.
    844     in_transit_snapshot_files_[request_id] = file_ref;
    845   }
    846 
    847   // Return the file info and platform_path.
    848   Send(new FileSystemMsg_DidCreateSnapshotFile(
    849                request_id, info, platform_path));
    850 }
    851 
    852 bool FileAPIMessageFilter::HasPermissionsForFile(
    853     const FileSystemURL& url, int permissions, base::PlatformFileError* error) {
    854   return CheckFileSystemPermissionsForProcess(context_, process_id_, url,
    855                                               permissions, error);
    856 }
    857 
    858 scoped_refptr<Stream> FileAPIMessageFilter::GetStreamForURL(const GURL& url) {
    859   return stream_context_->registry()->GetStream(url);
    860 }
    861 
    862 }  // namespace content
    863