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/renderer_host/pepper/content_browser_pepper_host_factory.h"
6
7#include "content/browser/renderer_host/pepper/browser_ppapi_host_impl.h"
8#include "content/browser/renderer_host/pepper/pepper_browser_font_singleton_host.h"
9#include "content/browser/renderer_host/pepper/pepper_file_io_host.h"
10#include "content/browser/renderer_host/pepper/pepper_file_ref_host.h"
11#include "content/browser/renderer_host/pepper/pepper_file_system_browser_host.h"
12#include "content/browser/renderer_host/pepper/pepper_flash_file_message_filter.h"
13#include "content/browser/renderer_host/pepper/pepper_gamepad_host.h"
14#include "content/browser/renderer_host/pepper/pepper_host_resolver_message_filter.h"
15#include "content/browser/renderer_host/pepper/pepper_network_monitor_host.h"
16#include "content/browser/renderer_host/pepper/pepper_network_proxy_host.h"
17#include "content/browser/renderer_host/pepper/pepper_print_settings_manager.h"
18#include "content/browser/renderer_host/pepper/pepper_printing_host.h"
19#include "content/browser/renderer_host/pepper/pepper_tcp_server_socket_message_filter.h"
20#include "content/browser/renderer_host/pepper/pepper_tcp_socket_message_filter.h"
21#include "content/browser/renderer_host/pepper/pepper_truetype_font_host.h"
22#include "content/browser/renderer_host/pepper/pepper_truetype_font_list_host.h"
23#include "content/browser/renderer_host/pepper/pepper_udp_socket_message_filter.h"
24#include "ppapi/host/message_filter_host.h"
25#include "ppapi/host/ppapi_host.h"
26#include "ppapi/host/resource_host.h"
27#include "ppapi/proxy/ppapi_messages.h"
28#include "ppapi/shared_impl/ppapi_permissions.h"
29
30using ppapi::host::MessageFilterHost;
31using ppapi::host::ResourceHost;
32using ppapi::host::ResourceMessageFilter;
33using ppapi::proxy::SerializedTrueTypeFontDesc;
34using ppapi::UnpackMessage;
35
36namespace content {
37
38namespace {
39
40const size_t kMaxSocketsAllowed = 1024;
41
42bool CanCreateSocket() {
43  return PepperTCPServerSocketMessageFilter::GetNumInstances() +
44             PepperTCPSocketMessageFilter::GetNumInstances() +
45             PepperUDPSocketMessageFilter::GetNumInstances() <
46         kMaxSocketsAllowed;
47}
48
49}  // namespace
50
51ContentBrowserPepperHostFactory::ContentBrowserPepperHostFactory(
52    BrowserPpapiHostImpl* host)
53    : host_(host) {}
54
55ContentBrowserPepperHostFactory::~ContentBrowserPepperHostFactory() {}
56
57scoped_ptr<ResourceHost> ContentBrowserPepperHostFactory::CreateResourceHost(
58    ppapi::host::PpapiHost* host,
59    const ppapi::proxy::ResourceMessageCallParams& params,
60    PP_Instance instance,
61    const IPC::Message& message) {
62  DCHECK(host == host_->GetPpapiHost());
63
64  // Make sure the plugin is giving us a valid instance for this resource.
65  if (!host_->IsValidInstance(instance))
66    return scoped_ptr<ResourceHost>();
67
68  // Public interfaces.
69  switch (message.type()) {
70    case PpapiHostMsg_FileIO_Create::ID: {
71      return scoped_ptr<ResourceHost>(
72          new PepperFileIOHost(host_, instance, params.pp_resource()));
73    }
74    case PpapiHostMsg_FileSystem_Create::ID: {
75      PP_FileSystemType file_system_type;
76      if (!ppapi::UnpackMessage<PpapiHostMsg_FileSystem_Create>(
77              message, &file_system_type)) {
78        NOTREACHED();
79        return scoped_ptr<ResourceHost>();
80      }
81      return scoped_ptr<ResourceHost>(new PepperFileSystemBrowserHost(
82          host_, instance, params.pp_resource(), file_system_type));
83    }
84    case PpapiHostMsg_Gamepad_Create::ID: {
85      return scoped_ptr<ResourceHost>(
86          new PepperGamepadHost(host_, instance, params.pp_resource()));
87    }
88    case PpapiHostMsg_NetworkProxy_Create::ID: {
89      return scoped_ptr<ResourceHost>(
90          new PepperNetworkProxyHost(host_, instance, params.pp_resource()));
91    }
92    case PpapiHostMsg_HostResolver_Create::ID: {
93      scoped_refptr<ResourceMessageFilter> host_resolver(
94          new PepperHostResolverMessageFilter(host_, instance, false));
95      return scoped_ptr<ResourceHost>(
96          new MessageFilterHost(host_->GetPpapiHost(),
97                                instance,
98                                params.pp_resource(),
99                                host_resolver));
100    }
101    case PpapiHostMsg_FileRef_CreateForFileAPI::ID: {
102      PP_Resource file_system;
103      std::string internal_path;
104      if (!UnpackMessage<PpapiHostMsg_FileRef_CreateForFileAPI>(
105              message, &file_system, &internal_path)) {
106        NOTREACHED();
107        return scoped_ptr<ResourceHost>();
108      }
109      return scoped_ptr<ResourceHost>(new PepperFileRefHost(
110          host_, instance, params.pp_resource(), file_system, internal_path));
111    }
112    case PpapiHostMsg_TCPSocket_Create::ID: {
113      ppapi::TCPSocketVersion version;
114      if (!UnpackMessage<PpapiHostMsg_TCPSocket_Create>(message, &version) ||
115          version == ppapi::TCP_SOCKET_VERSION_PRIVATE) {
116        return scoped_ptr<ResourceHost>();
117      }
118
119      return CreateNewTCPSocket(instance, params.pp_resource(), version);
120    }
121    case PpapiHostMsg_UDPSocket_Create::ID: {
122      if (CanCreateSocket()) {
123        scoped_refptr<ResourceMessageFilter> udp_socket(
124            new PepperUDPSocketMessageFilter(host_, instance, false));
125        return scoped_ptr<ResourceHost>(new MessageFilterHost(
126            host_->GetPpapiHost(), instance, params.pp_resource(), udp_socket));
127      } else {
128        return scoped_ptr<ResourceHost>();
129      }
130    }
131  }
132
133  // Dev interfaces.
134  if (GetPermissions().HasPermission(ppapi::PERMISSION_DEV)) {
135    switch (message.type()) {
136      case PpapiHostMsg_Printing_Create::ID: {
137        scoped_ptr<PepperPrintSettingsManager> manager(
138            new PepperPrintSettingsManagerImpl());
139        return scoped_ptr<ResourceHost>(
140            new PepperPrintingHost(host_->GetPpapiHost(),
141                                   instance,
142                                   params.pp_resource(),
143                                   manager.Pass()));
144      }
145      case PpapiHostMsg_TrueTypeFont_Create::ID: {
146        SerializedTrueTypeFontDesc desc;
147        if (!UnpackMessage<PpapiHostMsg_TrueTypeFont_Create>(message, &desc)) {
148          NOTREACHED();
149          return scoped_ptr<ResourceHost>();
150        }
151        // Check that the family name is valid UTF-8 before passing it to the
152        // host OS.
153        if (!base::IsStringUTF8(desc.family))
154          return scoped_ptr<ResourceHost>();
155
156        return scoped_ptr<ResourceHost>(new PepperTrueTypeFontHost(
157            host_, instance, params.pp_resource(), desc));
158      }
159      case PpapiHostMsg_TrueTypeFontSingleton_Create::ID: {
160        return scoped_ptr<ResourceHost>(new PepperTrueTypeFontListHost(
161            host_, instance, params.pp_resource()));
162      }
163    }
164  }
165
166  // Private interfaces.
167  if (GetPermissions().HasPermission(ppapi::PERMISSION_PRIVATE)) {
168    switch (message.type()) {
169      case PpapiHostMsg_BrowserFontSingleton_Create::ID:
170        return scoped_ptr<ResourceHost>(new PepperBrowserFontSingletonHost(
171            host_, instance, params.pp_resource()));
172    }
173  }
174
175  // Permissions for the following interfaces will be checked at the
176  // time of the corresponding instance's methods calls (because
177  // permission check can be performed only on the UI
178  // thread). Currently these interfaces are available only for
179  // whitelisted apps which may not have access to the other private
180  // interfaces.
181  if (message.type() == PpapiHostMsg_HostResolver_CreatePrivate::ID) {
182    scoped_refptr<ResourceMessageFilter> host_resolver(
183        new PepperHostResolverMessageFilter(host_, instance, true));
184    return scoped_ptr<ResourceHost>(new MessageFilterHost(
185        host_->GetPpapiHost(), instance, params.pp_resource(), host_resolver));
186  }
187  if (message.type() == PpapiHostMsg_TCPServerSocket_CreatePrivate::ID) {
188    if (CanCreateSocket()) {
189      scoped_refptr<ResourceMessageFilter> tcp_server_socket(
190          new PepperTCPServerSocketMessageFilter(this, host_, instance, true));
191      return scoped_ptr<ResourceHost>(
192          new MessageFilterHost(host_->GetPpapiHost(),
193                                instance,
194                                params.pp_resource(),
195                                tcp_server_socket));
196    } else {
197      return scoped_ptr<ResourceHost>();
198    }
199  }
200  if (message.type() == PpapiHostMsg_TCPSocket_CreatePrivate::ID) {
201    return CreateNewTCPSocket(
202        instance, params.pp_resource(), ppapi::TCP_SOCKET_VERSION_PRIVATE);
203  }
204  if (message.type() == PpapiHostMsg_UDPSocket_CreatePrivate::ID) {
205    if (CanCreateSocket()) {
206      scoped_refptr<ResourceMessageFilter> udp_socket(
207          new PepperUDPSocketMessageFilter(host_, instance, true));
208      return scoped_ptr<ResourceHost>(new MessageFilterHost(
209          host_->GetPpapiHost(), instance, params.pp_resource(), udp_socket));
210    } else {
211      return scoped_ptr<ResourceHost>();
212    }
213  }
214  if (message.type() == PpapiHostMsg_NetworkMonitor_Create::ID) {
215    return scoped_ptr<ResourceHost>(
216        new PepperNetworkMonitorHost(host_, instance, params.pp_resource()));
217  }
218
219  // Flash interfaces.
220  if (GetPermissions().HasPermission(ppapi::PERMISSION_FLASH)) {
221    switch (message.type()) {
222      case PpapiHostMsg_FlashFile_Create::ID: {
223        scoped_refptr<ResourceMessageFilter> file_filter(
224            new PepperFlashFileMessageFilter(instance, host_));
225        return scoped_ptr<ResourceHost>(
226            new MessageFilterHost(host_->GetPpapiHost(),
227                                  instance,
228                                  params.pp_resource(),
229                                  file_filter));
230      }
231    }
232  }
233
234  return scoped_ptr<ResourceHost>();
235}
236
237scoped_ptr<ppapi::host::ResourceHost>
238ContentBrowserPepperHostFactory::CreateAcceptedTCPSocket(
239    PP_Instance instance,
240    ppapi::TCPSocketVersion version,
241    scoped_ptr<net::TCPSocket> socket) {
242  if (!CanCreateSocket())
243    return scoped_ptr<ResourceHost>();
244  scoped_refptr<ResourceMessageFilter> tcp_socket(
245      new PepperTCPSocketMessageFilter(
246          host_, instance, version, socket.Pass()));
247  return scoped_ptr<ResourceHost>(
248      new MessageFilterHost(host_->GetPpapiHost(), instance, 0, tcp_socket));
249}
250
251scoped_ptr<ppapi::host::ResourceHost>
252ContentBrowserPepperHostFactory::CreateNewTCPSocket(
253    PP_Instance instance,
254    PP_Resource resource,
255    ppapi::TCPSocketVersion version) {
256  if (!CanCreateSocket())
257    return scoped_ptr<ResourceHost>();
258
259  scoped_refptr<ResourceMessageFilter> tcp_socket(
260      new PepperTCPSocketMessageFilter(this, host_, instance, version));
261  if (!tcp_socket.get())
262    return scoped_ptr<ResourceHost>();
263
264  return scoped_ptr<ResourceHost>(new MessageFilterHost(
265      host_->GetPpapiHost(), instance, resource, tcp_socket));
266}
267
268const ppapi::PpapiPermissions& ContentBrowserPepperHostFactory::GetPermissions()
269    const {
270  return host_->GetPpapiHost()->permissions();
271}
272
273}  // namespace content
274