1// Copyright (c) 2013 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/renderer/pepper/pepper_file_system_host.h"
6
7#include "base/bind.h"
8#include "base/callback.h"
9#include "content/child/child_thread.h"
10#include "content/child/fileapi/file_system_dispatcher.h"
11#include "content/renderer/pepper/pepper_plugin_instance_impl.h"
12#include "content/public/renderer/render_view.h"
13#include "content/public/renderer/renderer_ppapi_host.h"
14#include "ppapi/c/pp_errors.h"
15#include "ppapi/host/dispatch_host_message.h"
16#include "ppapi/host/ppapi_host.h"
17#include "ppapi/proxy/ppapi_messages.h"
18#include "ppapi/shared_impl/file_type_conversion.h"
19#include "third_party/WebKit/public/web/WebDocument.h"
20#include "third_party/WebKit/public/web/WebElement.h"
21#include "third_party/WebKit/public/web/WebFrame.h"
22#include "third_party/WebKit/public/web/WebPluginContainer.h"
23#include "third_party/WebKit/public/web/WebView.h"
24#include "webkit/common/fileapi/file_system_util.h"
25
26namespace content {
27
28namespace {
29
30bool LooksLikeAGuid(const std::string& fsid) {
31  const size_t kExpectedFsIdSize = 32;
32  if (fsid.size() != kExpectedFsIdSize)
33    return false;
34  for (std::string::const_iterator it = fsid.begin(); it != fsid.end(); ++it) {
35    if (('A' <= *it && *it <= 'F') ||
36        ('0' <= *it && *it <= '9'))
37      continue;
38    return false;
39  }
40  return true;
41}
42
43}  // namespace
44
45PepperFileSystemHost::PepperFileSystemHost(RendererPpapiHost* host,
46                                           PP_Instance instance,
47                                           PP_Resource resource,
48                                           PP_FileSystemType type)
49    : ResourceHost(host->GetPpapiHost(), instance, resource),
50      renderer_ppapi_host_(host),
51      weak_factory_(this),
52      type_(type),
53      opened_(false),
54      called_open_(false) {
55}
56
57PepperFileSystemHost::~PepperFileSystemHost() {
58}
59
60int32_t PepperFileSystemHost::OnResourceMessageReceived(
61    const IPC::Message& msg,
62    ppapi::host::HostMessageContext* context) {
63  IPC_BEGIN_MESSAGE_MAP(PepperFileSystemHost, msg)
64    PPAPI_DISPATCH_HOST_RESOURCE_CALL(
65        PpapiHostMsg_FileSystem_Open,
66        OnHostMsgOpen)
67    PPAPI_DISPATCH_HOST_RESOURCE_CALL(
68        PpapiHostMsg_FileSystem_InitIsolatedFileSystem,
69        OnHostMsgInitIsolatedFileSystem)
70  IPC_END_MESSAGE_MAP()
71  return PP_ERROR_FAILED;
72}
73
74bool PepperFileSystemHost::IsFileSystemHost() {
75  return true;
76}
77
78void PepperFileSystemHost::DidOpenFileSystem(
79    const std::string& /* name_unused */,
80    const GURL& root) {
81  opened_ = true;
82  root_url_ = root;
83  reply_context_.params.set_result(PP_OK);
84  host()->SendReply(reply_context_, PpapiPluginMsg_FileSystem_OpenReply());
85  reply_context_ = ppapi::host::ReplyMessageContext();
86}
87
88void PepperFileSystemHost::DidFailOpenFileSystem(
89    base::PlatformFileError error) {
90  int32 pp_error = ppapi::PlatformFileErrorToPepperError(error);
91  opened_ = (pp_error == PP_OK);
92  reply_context_.params.set_result(pp_error);
93  host()->SendReply(reply_context_, PpapiPluginMsg_FileSystem_OpenReply());
94  reply_context_ = ppapi::host::ReplyMessageContext();
95}
96
97int32_t PepperFileSystemHost::OnHostMsgOpen(
98    ppapi::host::HostMessageContext* context,
99    int64_t expected_size) {
100  // Not allow multiple opens.
101  if (called_open_)
102    return PP_ERROR_INPROGRESS;
103  called_open_ = true;
104
105  fileapi::FileSystemType file_system_type;
106  switch (type_) {
107    case PP_FILESYSTEMTYPE_LOCALTEMPORARY:
108      file_system_type = fileapi::kFileSystemTypeTemporary;
109      break;
110    case PP_FILESYSTEMTYPE_LOCALPERSISTENT:
111      file_system_type = fileapi::kFileSystemTypePersistent;
112      break;
113    case PP_FILESYSTEMTYPE_EXTERNAL:
114      file_system_type = fileapi::kFileSystemTypeExternal;
115      break;
116    default:
117      return PP_ERROR_FAILED;
118  }
119
120  PepperPluginInstance* plugin_instance =
121      renderer_ppapi_host_->GetPluginInstance(pp_instance());
122  if (!plugin_instance)
123    return PP_ERROR_FAILED;
124
125  FileSystemDispatcher* file_system_dispatcher =
126      ChildThread::current()->file_system_dispatcher();
127  reply_context_ = context->MakeReplyMessageContext();
128  file_system_dispatcher->OpenFileSystem(
129      GURL(plugin_instance->GetContainer()->element().document().url()).
130          GetOrigin(),
131      file_system_type, expected_size, true /* create */,
132      base::Bind(&PepperFileSystemHost::DidOpenFileSystem,
133                 weak_factory_.GetWeakPtr()),
134      base::Bind(&PepperFileSystemHost::DidFailOpenFileSystem,
135                 weak_factory_.GetWeakPtr()));
136  return PP_OK_COMPLETIONPENDING;
137}
138
139int32_t PepperFileSystemHost::OnHostMsgInitIsolatedFileSystem(
140    ppapi::host::HostMessageContext* context,
141    const std::string& fsid) {
142  called_open_ = true;
143  // Do a sanity check.
144  if (!LooksLikeAGuid(fsid))
145    return PP_ERROR_BADARGUMENT;
146  RenderView* view =
147      renderer_ppapi_host_->GetRenderViewForInstance(pp_instance());
148  if (!view)
149    return PP_ERROR_FAILED;
150  const GURL& url = view->GetWebView()->mainFrame()->document().url();
151  root_url_ = GURL(fileapi::GetIsolatedFileSystemRootURIString(
152      url.GetOrigin(), fsid, "crxfs"));
153  opened_ = true;
154  return PP_OK;
155}
156
157}  // namespace content
158