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