[M108 Aura Migration][NaCl][PPFwk] Add error logs + SVACE/DLOG/Static analysis fix
[platform/framework/web/chromium-efl.git] / content / browser / renderer_host / pepper / pepper_file_system_browser_host.cc
1 // Copyright 2013 The Chromium Authors
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/renderer_host/pepper/pepper_file_system_browser_host.h"
6
7 #include "base/bind.h"
8 #include "base/callback.h"
9 #include "base/logging.h"
10 #include "base/task/task_runner_util.h"
11 #include "base/threading/sequenced_task_runner_handle.h"
12 #include "base/threading/thread_task_runner_handle.h"
13 #include "content/browser/renderer_host/pepper/pepper_file_io_host.h"
14 #include "content/browser/renderer_host/pepper/quota_reservation.h"
15 #include "content/common/pepper_file_util.h"
16 #include "content/public/browser/browser_ppapi_host.h"
17 #include "content/public/browser/browser_task_traits.h"
18 #include "content/public/browser/plugin_service.h"
19 #include "content/public/browser/render_process_host.h"
20 #include "content/public/browser/storage_partition.h"
21 #include "content/public/common/content_plugin_info.h"
22 #include "net/base/mime_util.h"
23 #include "ppapi/c/pp_errors.h"
24 #include "ppapi/host/dispatch_host_message.h"
25 #include "ppapi/host/ppapi_host.h"
26 #include "ppapi/proxy/ppapi_messages.h"
27 #include "ppapi/shared_impl/file_system_util.h"
28 #include "ppapi/shared_impl/file_type_conversion.h"
29 #include "storage/browser/file_system/file_system_operation_runner.h"
30 #include "storage/browser/file_system/file_system_util.h"
31 #include "storage/browser/file_system/isolated_context.h"
32 #include "storage/browser/quota/quota_manager_proxy.h"
33 #include "storage/common/file_system/file_system_util.h"
34 #include "third_party/blink/public/common/storage_key/storage_key.h"
35 #include "url/gurl.h"
36 #include "url/origin.h"
37
38 namespace content {
39
40 namespace {
41
42 // This is the minimum amount of quota we reserve per file system.
43 const int64_t kMinimumQuotaReservationSize = 1024 * 1024;  // 1 MB
44
45 storage::FileSystemType PepperFileSystemTypeToFileSystemType(
46     PP_FileSystemType type) {
47   switch (type) {
48     case PP_FILESYSTEMTYPE_LOCALTEMPORARY:
49       return storage::kFileSystemTypeTemporary;
50     case PP_FILESYSTEMTYPE_LOCALPERSISTENT:
51       return storage::kFileSystemTypePersistent;
52     case PP_FILESYSTEMTYPE_EXTERNAL:
53       return storage::kFileSystemTypeExternal;
54     default:
55       return storage::kFileSystemTypeUnknown;
56   }
57 }
58
59 void RunOpenQuotaCallbackOnUI(
60     PepperFileSystemBrowserHost::OpenQuotaFileCallback callback,
61     int64_t max_written_offset) {
62   GetUIThreadTaskRunner({})->PostTask(
63       FROM_HERE, base::BindOnce(std::move(callback), max_written_offset));
64 }
65
66 void RunReserveQuotaCallbackOnUI(
67     QuotaReservation::ReserveQuotaCallback callback,
68     int64_t amount,
69     const ppapi::FileSizeMap& file_sizes) {
70   GetUIThreadTaskRunner({})->PostTask(
71       FROM_HERE, base::BindOnce(std::move(callback), amount, file_sizes));
72 }
73
74 }  // namespace
75
76 PepperFileSystemBrowserHost::IOThreadState::IOThreadState(
77     PP_FileSystemType type,
78     base::WeakPtr<PepperFileSystemBrowserHost> host)
79     : type_(type),
80       task_runner_(base::ThreadTaskRunnerHandle::Get()),
81       host_(host) {}
82
83 PepperFileSystemBrowserHost::IOThreadState::~IOThreadState() {
84   // All FileRefs and FileIOs that reference us must have been destroyed. Cancel
85   // all pending file system operations.
86   if (file_system_operation_runner_)
87     file_system_operation_runner_->Shutdown();
88 }
89
90 void PepperFileSystemBrowserHost::IOThreadState::OpenExistingFileSystem(
91     const GURL& root_url,
92     base::OnceClosure callback,
93     scoped_refptr<storage::FileSystemContext> file_system_context) {
94   DCHECK_CURRENTLY_ON(BrowserThread::IO);
95   root_url_ = root_url;
96   if (file_system_context.get()) {
97     opened_ = true;
98   } else {
99     // If there is no file system context, we log a warning and continue with an
100     // invalid resource (which will produce errors when used), since we have no
101     // way to communicate the error to the caller.
102     LOG(WARNING) << "Could not retrieve file system context.";
103   }
104   SetFileSystemContext(file_system_context);
105
106   ShouldCreateQuotaReservation(base::BindOnce(
107       [](scoped_refptr<IOThreadState> io_thread_state,
108          base::OnceClosure callback, bool should_create_quota_reservation) {
109         if (should_create_quota_reservation) {
110           io_thread_state->CreateQuotaReservation(std::move(callback));
111         } else {
112           io_thread_state->RunCallbackIfHostAlive(std::move(callback));
113         }
114       },
115       base::WrapRefCounted(this), std::move(callback)));
116 }
117
118 void PepperFileSystemBrowserHost::IOThreadState::OpenFileSystem(
119     const GURL& origin,
120     ppapi::host::ReplyMessageContext reply_context,
121     storage::FileSystemType file_system_type,
122     scoped_refptr<storage::FileSystemContext> file_system_context) {
123   DCHECK_CURRENTLY_ON(BrowserThread::IO);
124   if (!file_system_context.get()) {
125     OpenFileSystemComplete(reply_context, storage::FileSystemURL(),
126                            std::string(), base::File::FILE_ERROR_FAILED);
127     return;
128   }
129
130   SetFileSystemContext(file_system_context);
131
132   // TODO(https://crbug.com/1236243): figure out if StorageKey conversion
133   // should replaced with a third-party value: is ppapi only limited to
134   // first-party contexts? If so, the implementation below is correct.
135   file_system_context_->OpenFileSystem(
136       blink::StorageKey(url::Origin::Create(origin)), /*bucket=*/absl::nullopt,
137       file_system_type, storage::OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT,
138       base::BindOnce(&IOThreadState::OpenFileSystemComplete, this,
139                      reply_context));
140 }
141
142 void PepperFileSystemBrowserHost::IOThreadState::OpenIsolatedFileSystem(
143     const GURL& origin,
144     const GURL& root_url,
145     const std::string& plugin_id,
146     ppapi::host::ReplyMessageContext reply_context,
147     const std::string& fsid,
148     PP_IsolatedFileSystemType_Private type,
149     scoped_refptr<storage::FileSystemContext> file_system_context) {
150   DCHECK_CURRENTLY_ON(BrowserThread::IO);
151   if (!file_system_context.get()) {
152     SendReplyForIsolatedFileSystem(reply_context, fsid, PP_ERROR_FAILED);
153     return;
154   }
155   SetFileSystemContext(file_system_context);
156
157   if (!root_url_.is_valid()) {
158     SendReplyForIsolatedFileSystem(reply_context, fsid, PP_ERROR_FAILED);
159     return;
160   }
161
162   switch (type) {
163     case PP_ISOLATEDFILESYSTEMTYPE_PRIVATE_CRX:
164       opened_ = true;
165       SendReplyForIsolatedFileSystem(reply_context, fsid, PP_OK);
166       return;
167     default:
168       NOTREACHED();
169       SendReplyForIsolatedFileSystem(reply_context, fsid, PP_ERROR_BADARGUMENT);
170       return;
171   }
172 }
173
174 void PepperFileSystemBrowserHost::IOThreadState::OpenFileSystemComplete(
175     ppapi::host::ReplyMessageContext reply_context,
176     const storage::FileSystemURL& root,
177     const std::string& name,
178     base::File::Error error) {
179   DCHECK_CURRENTLY_ON(BrowserThread::IO);
180   int32_t pp_error = ppapi::FileErrorToPepperError(error);
181   if (pp_error == PP_OK) {
182     opened_ = true;
183     // TODO(crbug.com/1323925): Store and use FileSystemURL instead.
184     root_url_ = root.ToGURL();
185
186     ShouldCreateQuotaReservation(base::BindOnce(
187         [](scoped_refptr<IOThreadState> io_thread_state,
188            ppapi::host::ReplyMessageContext reply_context,
189            bool should_create_quota_reservation) {
190           if (should_create_quota_reservation) {
191             io_thread_state->CreateQuotaReservation(base::BindOnce(
192                 &IOThreadState::SendReplyForFileSystemIfHostAlive,
193                 io_thread_state, reply_context, static_cast<int32_t>(PP_OK)));
194           } else {
195             io_thread_state->SendReplyForFileSystemIfHostAlive(reply_context,
196                                                                PP_OK);
197           }
198         },
199         base::WrapRefCounted(this), reply_context));
200     return;
201   }
202   SendReplyForFileSystemIfHostAlive(reply_context, pp_error);
203 }
204
205 void PepperFileSystemBrowserHost::IOThreadState::RunCallbackIfHostAlive(
206     base::OnceClosure callback) {
207   if (!task_runner_->BelongsToCurrentThread()) {
208     task_runner_->PostTask(
209         FROM_HERE, base::BindOnce(&IOThreadState::RunCallbackIfHostAlive, this,
210                                   std::move(callback)));
211     return;
212   }
213
214   if (!host_)
215     return;
216
217   std::move(callback).Run();
218 }
219
220 void PepperFileSystemBrowserHost::IOThreadState::
221     SendReplyForFileSystemIfHostAlive(
222         ppapi::host::ReplyMessageContext reply_context,
223         int32_t pp_error) {
224   if (!task_runner_->BelongsToCurrentThread()) {
225     task_runner_->PostTask(
226         FROM_HERE,
227         base::BindOnce(&IOThreadState::SendReplyForFileSystemIfHostAlive, this,
228                        reply_context, pp_error));
229     return;
230   }
231
232   if (!host_)
233     return;
234
235   reply_context.params.set_result(pp_error);
236   host_->host()->SendReply(reply_context,
237                            PpapiPluginMsg_FileSystem_OpenReply());
238 }
239
240 void PepperFileSystemBrowserHost::IOThreadState::SendReplyForIsolatedFileSystem(
241     ppapi::host::ReplyMessageContext reply_context,
242     const std::string& fsid,
243     int32_t error) {
244   if (!task_runner_->BelongsToCurrentThread()) {
245     task_runner_->PostTask(
246         FROM_HERE,
247         base::BindOnce(&IOThreadState::SendReplyForIsolatedFileSystem, this,
248                        reply_context, fsid, error));
249     return;
250   }
251
252   if (!host_)
253     return;
254
255   if (error != PP_OK)
256     storage::IsolatedContext::GetInstance()->RevokeFileSystem(fsid);
257   reply_context.params.set_result(error);
258   host_->SendReply(reply_context,
259                    PpapiPluginMsg_FileSystem_InitIsolatedFileSystemReply());
260 }
261
262 void PepperFileSystemBrowserHost::IOThreadState::SetFileSystemContext(
263     scoped_refptr<storage::FileSystemContext> file_system_context) {
264   DCHECK_CURRENTLY_ON(BrowserThread::IO);
265   file_system_context_ = file_system_context;
266   if (type_ != PP_FILESYSTEMTYPE_EXTERNAL || root_url_.is_valid()) {
267     file_system_operation_runner_ =
268         file_system_context_->CreateFileSystemOperationRunner();
269   }
270 }
271
272 void PepperFileSystemBrowserHost::IOThreadState::ShouldCreateQuotaReservation(
273     base::OnceCallback<void(bool)> callback) const {
274   DCHECK_CURRENTLY_ON(BrowserThread::IO);
275   // Some file system types don't have quota.
276   if (!ppapi::FileSystemTypeHasQuota(type_)) {
277     std::move(callback).Run(false);
278     return;
279   }
280
281   // For file system types with quota, some origins have unlimited storage.
282   const scoped_refptr<storage::QuotaManagerProxy>& quota_manager_proxy =
283       file_system_context_->quota_manager_proxy();
284   CHECK(quota_manager_proxy);
285   storage::FileSystemType file_system_type =
286       PepperFileSystemTypeToFileSystemType(type_);
287   quota_manager_proxy->IsStorageUnlimited(
288       blink::StorageKey(url::Origin::Create(root_url_)),
289       storage::FileSystemTypeToQuotaStorageType(file_system_type),
290       base::SequencedTaskRunnerHandle::Get(),
291       base::BindOnce(
292           [](base::OnceCallback<void(bool)> callback,
293              bool is_storage_unlimited) {
294             std::move(callback).Run(!is_storage_unlimited);
295           },
296           std::move(callback)));
297 }
298
299 void PepperFileSystemBrowserHost::IOThreadState::CreateQuotaReservation(
300     base::OnceClosure callback) {
301   DCHECK_CURRENTLY_ON(BrowserThread::IO);
302   DCHECK(root_url_.is_valid());
303   base::PostTaskAndReplyWithResult(
304       file_system_context_->default_file_task_runner(), FROM_HERE,
305       base::BindOnce(&QuotaReservation::Create, file_system_context_,
306                      root_url_.DeprecatedGetOriginAsURL(),
307                      PepperFileSystemTypeToFileSystemType(type_)),
308       base::BindOnce(&IOThreadState::GotQuotaReservation, this,
309                      std::move(callback)));
310 }
311
312 void PepperFileSystemBrowserHost::IOThreadState::GotQuotaReservation(
313     base::OnceClosure callback,
314     scoped_refptr<QuotaReservation> quota_reservation) {
315   DCHECK_CURRENTLY_ON(BrowserThread::IO);
316
317   task_runner_->PostTask(
318       FROM_HERE,
319       base::BindOnce(&PepperFileSystemBrowserHost::GotQuotaReservation, host_,
320                      std::move(callback), quota_reservation));
321 }
322
323 PepperFileSystemBrowserHost::PepperFileSystemBrowserHost(BrowserPpapiHost* host,
324                                                          PP_Instance instance,
325                                                          PP_Resource resource,
326                                                          PP_FileSystemType type)
327     : ResourceHost(host->GetPpapiHost(), instance, resource),
328       browser_ppapi_host_(host),
329       type_(type),
330       called_open_(false),
331       reserved_quota_(0),
332       reserving_quota_(false) {
333   io_thread_state_ =
334       base::MakeRefCounted<IOThreadState>(type, weak_factory_.GetWeakPtr());
335 }
336
337 PepperFileSystemBrowserHost::~PepperFileSystemBrowserHost() {
338   // If |files_| is not empty, the plugin failed to close some files. It must
339   // have crashed.
340   if (!files_.empty()) {
341     io_thread_state_->file_system_context()
342         ->default_file_task_runner()
343         ->PostTask(FROM_HERE, base::BindOnce(&QuotaReservation::OnClientCrash,
344                                              quota_reservation_));
345   }
346 }
347
348 void PepperFileSystemBrowserHost::OpenExisting(const GURL& root_url,
349                                                base::OnceClosure callback) {
350   int render_process_id = 0;
351   int unused;
352   if (!browser_ppapi_host_->GetRenderFrameIDsForInstance(
353           pp_instance(), &render_process_id, &unused)) {
354     NOTREACHED();
355   }
356   called_open_ = true;
357   // Get the file system context asynchronously, and then complete the Open
358   // operation by calling |callback|.
359   GetIOThreadTaskRunner({})->PostTask(
360       FROM_HERE,
361       base::BindOnce(&IOThreadState::OpenExistingFileSystem, io_thread_state_,
362                      root_url, std::move(callback),
363                      GetFileSystemContextFromRenderId(render_process_id)));
364 }
365
366 int32_t PepperFileSystemBrowserHost::OnResourceMessageReceived(
367     const IPC::Message& msg,
368     ppapi::host::HostMessageContext* context) {
369   PPAPI_BEGIN_MESSAGE_MAP(PepperFileSystemBrowserHost, msg)
370     PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_FileSystem_Open,
371                                       OnHostMsgOpen)
372     PPAPI_DISPATCH_HOST_RESOURCE_CALL(
373         PpapiHostMsg_FileSystem_InitIsolatedFileSystem,
374         OnHostMsgInitIsolatedFileSystem)
375     PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_FileSystem_ReserveQuota,
376                                       OnHostMsgReserveQuota)
377   PPAPI_END_MESSAGE_MAP()
378   LOG(ERROR) << "Resource message not resolved";
379   return PP_ERROR_FAILED;
380 }
381
382 bool PepperFileSystemBrowserHost::IsFileSystemHost() {
383   return true;
384 }
385
386 bool PepperFileSystemBrowserHost::IsOpened() const {
387   DCHECK(called_open_);
388   return io_thread_state_->opened();
389 }
390
391 GURL PepperFileSystemBrowserHost::GetRootUrl() const {
392   DCHECK(called_open_);
393   return io_thread_state_->root_url();
394 }
395
396 PepperFileSystemBrowserHost::GetOperationRunnerCallback
397 PepperFileSystemBrowserHost::GetFileSystemOperationRunner() const {
398   return base::BindRepeating(
399       &PepperFileSystemBrowserHost::GetFileSystemOperationRunnerInternal,
400       io_thread_state_);
401 }
402
403 void PepperFileSystemBrowserHost::OpenQuotaFile(
404     PepperFileIOHost* file_io_host,
405     const storage::FileSystemURL& url,
406     OpenQuotaFileCallback callback) {
407   int32_t id = file_io_host->pp_resource();
408   std::pair<FileMap::iterator, bool> insert_result =
409       files_.insert(std::make_pair(id, file_io_host));
410   if (!insert_result.second) {
411     NOTREACHED();
412     return;
413   }
414
415   base::PostTaskAndReplyWithResult(
416       io_thread_state_->file_system_context()->default_file_task_runner(),
417       FROM_HERE,
418       base::BindOnce(&QuotaReservation::OpenFile, quota_reservation_, id, url),
419       base::BindOnce(RunOpenQuotaCallbackOnUI, std::move(callback)));
420 }
421
422 void PepperFileSystemBrowserHost::CloseQuotaFile(
423     PepperFileIOHost* file_io_host,
424     const ppapi::FileGrowth& file_growth) {
425   int32_t id = file_io_host->pp_resource();
426   auto it = files_.find(id);
427   if (it != files_.end()) {
428     files_.erase(it);
429   } else {
430     NOTREACHED();
431     return;
432   }
433
434   io_thread_state_->file_system_context()->default_file_task_runner()->PostTask(
435       FROM_HERE, base::BindOnce(&QuotaReservation::CloseFile,
436                                 quota_reservation_, id, file_growth));
437 }
438
439 scoped_refptr<storage::FileSystemContext>
440 PepperFileSystemBrowserHost::GetFileSystemContextFromRenderId(
441     int render_process_id) {
442   DCHECK_CURRENTLY_ON(BrowserThread::UI);
443   RenderProcessHost* host = RenderProcessHost::FromID(render_process_id);
444   if (!host)
445     return nullptr;
446   StoragePartition* storage_partition = host->GetStoragePartition();
447   if (!storage_partition)
448     return nullptr;
449   return storage_partition->GetFileSystemContext();
450 }
451
452 int32_t PepperFileSystemBrowserHost::OnHostMsgOpen(
453     ppapi::host::HostMessageContext* context,
454     int64_t /* unused */) {
455   // TODO(raymes): The file system size is now unused by FileSystemDispatcher.
456   // Figure out why. Why is the file system size signed?
457
458   // Not allow multiple opens.
459   if (called_open_) {
460     LOG(ERROR) << "Open has already been called - Not allow multiple opens";
461     return PP_ERROR_INPROGRESS;
462   }
463   called_open_ = true;
464
465   storage::FileSystemType file_system_type =
466       PepperFileSystemTypeToFileSystemType(type_);
467   if (file_system_type == storage::kFileSystemTypeUnknown) {
468     LOG(ERROR) << "Unknown file system type";
469     return PP_ERROR_FAILED;
470   }
471
472   int render_process_id = 0;
473   int unused;
474   if (!browser_ppapi_host_->GetRenderFrameIDsForInstance(
475           pp_instance(), &render_process_id, &unused)) {
476     LOG(ERROR);
477     return PP_ERROR_FAILED;
478   }
479
480   GURL origin = browser_ppapi_host_->GetDocumentURLForInstance(pp_instance())
481                     .DeprecatedGetOriginAsURL();
482   GetIOThreadTaskRunner({})->PostTask(
483       FROM_HERE,
484       base::BindOnce(&IOThreadState::OpenFileSystem, io_thread_state_, origin,
485                      context->MakeReplyMessageContext(), file_system_type,
486                      GetFileSystemContextFromRenderId(render_process_id)));
487
488   return PP_OK_COMPLETIONPENDING;
489 }
490
491 int32_t PepperFileSystemBrowserHost::OnHostMsgInitIsolatedFileSystem(
492     ppapi::host::HostMessageContext* context,
493     const std::string& fsid,
494     PP_IsolatedFileSystemType_Private type) {
495   // Do not allow multiple opens.
496   if (called_open_) {
497     LOG(ERROR) << "Open has already been called - Not allow multiple opens";
498     return PP_ERROR_INPROGRESS;
499   }
500   called_open_ = true;
501
502   // Do a sanity check.
503   if (!storage::ValidateIsolatedFileSystemId(fsid)) {
504     LOG(ERROR);
505     return PP_ERROR_BADARGUMENT;
506   }
507
508   int render_process_id = 0;
509   int unused;
510   if (!browser_ppapi_host_->GetRenderFrameIDsForInstance(
511           pp_instance(), &render_process_id, &unused)) {
512     storage::IsolatedContext::GetInstance()->RevokeFileSystem(fsid);
513     LOG(ERROR);
514     return PP_ERROR_FAILED;
515   }
516
517   GURL origin = browser_ppapi_host_->GetDocumentURLForInstance(pp_instance())
518                     .DeprecatedGetOriginAsURL();
519   GURL root_url = GURL(storage::GetIsolatedFileSystemRootURIString(
520       origin, fsid, ppapi::IsolatedFileSystemTypeToRootName(type)));
521
522   const std::string& plugin_id = GeneratePluginId(GetPluginMimeType());
523
524   GetIOThreadTaskRunner({})->PostTask(
525       FROM_HERE,
526       base::BindOnce(&IOThreadState::OpenIsolatedFileSystem, io_thread_state_,
527                      origin, root_url, plugin_id,
528                      context->MakeReplyMessageContext(), fsid, type,
529                      GetFileSystemContextFromRenderId(render_process_id)));
530   return PP_OK_COMPLETIONPENDING;
531 }
532
533 int32_t PepperFileSystemBrowserHost::OnHostMsgReserveQuota(
534     ppapi::host::HostMessageContext* context,
535     int64_t amount,
536     const ppapi::FileGrowthMap& file_growths) {
537   DCHECK(ChecksQuota());
538   DCHECK_GT(amount, 0);
539
540   if (reserving_quota_) {
541     LOG(ERROR) << "Reserving quota in progress";
542     return PP_ERROR_INPROGRESS;
543   }
544   reserving_quota_ = true;
545
546   int64_t reservation_amount =
547       std::max<int64_t>(kMinimumQuotaReservationSize, amount);
548
549   QuotaReservation::ReserveQuotaCallback callback = base::BindOnce(
550       &PepperFileSystemBrowserHost::GotReservedQuota,
551       weak_factory_.GetWeakPtr(), context->MakeReplyMessageContext());
552
553   io_thread_state_->file_system_context()->default_file_task_runner()->PostTask(
554       FROM_HERE,
555       base::BindOnce(
556           &QuotaReservation::ReserveQuota, quota_reservation_,
557           reservation_amount, file_growths,
558           base::BindOnce(RunReserveQuotaCallbackOnUI, std::move(callback))));
559
560   return PP_OK_COMPLETIONPENDING;
561 }
562
563 void PepperFileSystemBrowserHost::GotQuotaReservation(
564     base::OnceClosure callback,
565     scoped_refptr<QuotaReservation> quota_reservation) {
566   quota_reservation_ = quota_reservation;
567   std::move(callback).Run();
568 }
569
570 void PepperFileSystemBrowserHost::GotReservedQuota(
571     ppapi::host::ReplyMessageContext reply_context,
572     int64_t amount,
573     const ppapi::FileSizeMap& file_sizes) {
574   DCHECK(reserving_quota_);
575   reserving_quota_ = false;
576   reserved_quota_ = amount;
577
578   reply_context.params.set_result(PP_OK);
579   host()->SendReply(
580       reply_context,
581       PpapiPluginMsg_FileSystem_ReserveQuotaReply(amount, file_sizes));
582 }
583
584 std::string PepperFileSystemBrowserHost::GetPluginMimeType() const {
585   base::FilePath plugin_path = browser_ppapi_host_->GetPluginPath();
586   const ContentPluginInfo* info =
587       PluginService::GetInstance()->GetRegisteredPluginInfo(plugin_path);
588   if (!info || info->mime_types.empty())
589     return std::string();
590   // Use the first element in |info->mime_types| even if several elements exist.
591   return info->mime_types[0].mime_type;
592 }
593
594 std::string PepperFileSystemBrowserHost::GeneratePluginId(
595     const std::string& mime_type) const {
596   // TODO(nhiroki): This function is very specialized for specific plugins (MIME
597   // types).  If we bring this API to stable, we might have to make it more
598   // general.
599
600   std::string top_level_type;
601   std::string subtype;
602   if (!net::ParseMimeTypeWithoutParameter(
603           mime_type, &top_level_type, &subtype) ||
604       !net::IsValidTopLevelMimeType(top_level_type))
605     return std::string();
606
607   // Replace a slash used for type/subtype separator with an underscore.
608   std::string output = top_level_type + "_" + subtype;
609
610   // Verify |output| contains only alphabets, digits, or "._-".
611   for (std::string::const_iterator it = output.begin(); it != output.end();
612        ++it) {
613     if (!base::IsAsciiAlpha(*it) && !base::IsAsciiDigit(*it) &&
614         *it != '.' && *it != '_' && *it != '-') {
615       LOG(WARNING) << "Failed to generate a plugin id.";
616       return std::string();
617     }
618   }
619   return output;
620 }
621
622 storage::FileSystemOperationRunner*
623 PepperFileSystemBrowserHost::GetFileSystemOperationRunnerInternal(
624     scoped_refptr<IOThreadState> io_thread_state) {
625   DCHECK_CURRENTLY_ON(BrowserThread::IO);
626   return io_thread_state->GetFileSystemOperationRunner();
627 }
628
629 }  // namespace content