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