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