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