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