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/ppapi_plugin/broker_process_dispatcher.h"
6
7#include "base/bind.h"
8#include "base/bind_helpers.h"
9#include "base/memory/scoped_ptr.h"
10#include "base/strings/utf_string_conversions.h"
11#include "content/child/child_process.h"
12#include "ppapi/c/pp_bool.h"
13#include "ppapi/c/private/ppp_flash_browser_operations.h"
14#include "ppapi/proxy/ppapi_messages.h"
15
16namespace content {
17namespace {
18
19// How long we wait before releasing the broker process.
20const int kBrokerReleaseTimeSeconds = 30;
21
22std::string ConvertPluginDataPath(const base::FilePath& plugin_data_path) {
23  // The string is always 8-bit, convert on Windows.
24#if defined(OS_WIN)
25  return WideToUTF8(plugin_data_path.value());
26#else
27  return plugin_data_path.value();
28#endif
29}
30
31struct GetPermissionSettingsContext {
32  GetPermissionSettingsContext(
33      const base::WeakPtr<BrokerProcessDispatcher> in_dispatcher,
34      uint32 in_request_id)
35      : dispatcher(in_dispatcher),
36        request_id(in_request_id) {
37  }
38
39  base::WeakPtr<BrokerProcessDispatcher> dispatcher;
40  uint32 request_id;
41};
42
43void GetPermissionSettingsCallback(
44    void* user_data,
45    PP_Bool success,
46    PP_Flash_BrowserOperations_Permission default_permission,
47    uint32_t site_count,
48    const PP_Flash_BrowserOperations_SiteSetting sites[]) {
49  scoped_ptr<GetPermissionSettingsContext> context(
50      reinterpret_cast<GetPermissionSettingsContext*>(user_data));
51
52  if (!context->dispatcher.get())
53    return;
54
55  ppapi::FlashSiteSettings site_vector;
56  if (success) {
57    site_vector.reserve(site_count);
58    for (uint32_t i = 0; i < site_count; ++i) {
59      if (!sites[i].site) {
60        success = PP_FALSE;
61        break;
62      }
63      site_vector.push_back(
64          ppapi::FlashSiteSetting(sites[i].site, sites[i].permission));
65    }
66
67    if (!success)
68      site_vector.clear();
69  }
70  context->dispatcher->OnGetPermissionSettingsCompleted(
71      context->request_id, PP_ToBool(success), default_permission, site_vector);
72}
73
74}  // namespace
75
76BrokerProcessDispatcher::BrokerProcessDispatcher(
77    PP_GetInterface_Func get_plugin_interface,
78    PP_ConnectInstance_Func connect_instance)
79    : ppapi::proxy::BrokerSideDispatcher(connect_instance),
80      get_plugin_interface_(get_plugin_interface),
81      flash_browser_operations_1_3_(NULL),
82      flash_browser_operations_1_2_(NULL),
83      flash_browser_operations_1_0_(NULL) {
84  if (get_plugin_interface) {
85    flash_browser_operations_1_0_ =
86        static_cast<const PPP_Flash_BrowserOperations_1_0*>(
87            get_plugin_interface_(PPP_FLASH_BROWSEROPERATIONS_INTERFACE_1_0));
88
89    flash_browser_operations_1_2_ =
90        static_cast<const PPP_Flash_BrowserOperations_1_2*>(
91            get_plugin_interface_(PPP_FLASH_BROWSEROPERATIONS_INTERFACE_1_2));
92
93    flash_browser_operations_1_3_ =
94        static_cast<const PPP_Flash_BrowserOperations_1_3*>(
95            get_plugin_interface_(PPP_FLASH_BROWSEROPERATIONS_INTERFACE_1_3));
96  }
97}
98
99BrokerProcessDispatcher::~BrokerProcessDispatcher() {
100  DVLOG(1) << "BrokerProcessDispatcher::~BrokerProcessDispatcher()";
101  // Don't free the process right away. This timer allows the child process
102  // to be re-used if the user rapidly goes to a new page that requires this
103  // plugin. This is the case for common plugins where they may be used on a
104  // source and destination page of a navigation. We don't want to tear down
105  // and re-start processes each time in these cases.
106  process_ref_.ReleaseWithDelay(
107      base::TimeDelta::FromSeconds(kBrokerReleaseTimeSeconds));
108}
109
110bool BrokerProcessDispatcher::OnMessageReceived(const IPC::Message& msg) {
111  IPC_BEGIN_MESSAGE_MAP(BrokerProcessDispatcher, msg)
112    IPC_MESSAGE_HANDLER(PpapiMsg_GetSitesWithData, OnGetSitesWithData)
113    IPC_MESSAGE_HANDLER(PpapiMsg_ClearSiteData, OnClearSiteData)
114    IPC_MESSAGE_HANDLER(PpapiMsg_DeauthorizeContentLicenses,
115                        OnDeauthorizeContentLicenses)
116    IPC_MESSAGE_HANDLER(PpapiMsg_GetPermissionSettings, OnGetPermissionSettings)
117    IPC_MESSAGE_HANDLER(PpapiMsg_SetDefaultPermission, OnSetDefaultPermission)
118    IPC_MESSAGE_HANDLER(PpapiMsg_SetSitePermission, OnSetSitePermission)
119    IPC_MESSAGE_UNHANDLED(return BrokerSideDispatcher::OnMessageReceived(msg))
120  IPC_END_MESSAGE_MAP()
121  return true;
122}
123
124void BrokerProcessDispatcher::OnGetPermissionSettingsCompleted(
125    uint32 request_id,
126    bool success,
127    PP_Flash_BrowserOperations_Permission default_permission,
128    const ppapi::FlashSiteSettings& sites) {
129  Send(new PpapiHostMsg_GetPermissionSettingsResult(
130      request_id, success, default_permission, sites));
131}
132
133void BrokerProcessDispatcher::OnGetSitesWithData(
134    uint32 request_id,
135    const base::FilePath& plugin_data_path) {
136  std::vector<std::string> sites;
137  GetSitesWithData(plugin_data_path, &sites);
138  Send(new PpapiHostMsg_GetSitesWithDataResult(request_id, sites));
139}
140
141void BrokerProcessDispatcher::OnClearSiteData(
142    uint32 request_id,
143    const base::FilePath& plugin_data_path,
144    const std::string& site,
145    uint64 flags,
146    uint64 max_age) {
147  Send(new PpapiHostMsg_ClearSiteDataResult(
148      request_id, ClearSiteData(plugin_data_path, site, flags, max_age)));
149}
150
151void BrokerProcessDispatcher::OnDeauthorizeContentLicenses(
152    uint32 request_id,
153    const base::FilePath& plugin_data_path) {
154  Send(new PpapiHostMsg_DeauthorizeContentLicensesResult(
155      request_id, DeauthorizeContentLicenses(plugin_data_path)));
156}
157
158void BrokerProcessDispatcher::OnGetPermissionSettings(
159    uint32 request_id,
160    const base::FilePath& plugin_data_path,
161    PP_Flash_BrowserOperations_SettingType setting_type) {
162  if (flash_browser_operations_1_3_) {
163    std::string data_str = ConvertPluginDataPath(plugin_data_path);
164    // The GetPermissionSettingsContext object will be deleted in
165    // GetPermissionSettingsCallback().
166    flash_browser_operations_1_3_->GetPermissionSettings(
167        data_str.c_str(), setting_type, &GetPermissionSettingsCallback,
168        new GetPermissionSettingsContext(AsWeakPtr(), request_id));
169    return;
170  }
171
172  if (flash_browser_operations_1_2_) {
173    std::string data_str = ConvertPluginDataPath(plugin_data_path);
174    // The GetPermissionSettingsContext object will be deleted in
175    // GetPermissionSettingsCallback().
176    flash_browser_operations_1_2_->GetPermissionSettings(
177        data_str.c_str(), setting_type, &GetPermissionSettingsCallback,
178        new GetPermissionSettingsContext(AsWeakPtr(), request_id));
179    return;
180  }
181
182  OnGetPermissionSettingsCompleted(
183      request_id, false, PP_FLASH_BROWSEROPERATIONS_PERMISSION_DEFAULT,
184      ppapi::FlashSiteSettings());
185  return;
186}
187
188void BrokerProcessDispatcher::OnSetDefaultPermission(
189    uint32 request_id,
190    const base::FilePath& plugin_data_path,
191    PP_Flash_BrowserOperations_SettingType setting_type,
192    PP_Flash_BrowserOperations_Permission permission,
193    bool clear_site_specific) {
194  Send(new PpapiHostMsg_SetDefaultPermissionResult(
195      request_id,
196      SetDefaultPermission(plugin_data_path, setting_type, permission,
197                           clear_site_specific)));
198}
199
200void BrokerProcessDispatcher::OnSetSitePermission(
201    uint32 request_id,
202    const base::FilePath& plugin_data_path,
203    PP_Flash_BrowserOperations_SettingType setting_type,
204    const ppapi::FlashSiteSettings& sites) {
205  Send(new PpapiHostMsg_SetSitePermissionResult(
206      request_id, SetSitePermission(plugin_data_path, setting_type, sites)));
207}
208
209void BrokerProcessDispatcher::GetSitesWithData(
210    const base::FilePath& plugin_data_path,
211    std::vector<std::string>* site_vector) {
212  std::string data_str = ConvertPluginDataPath(plugin_data_path);
213  if (flash_browser_operations_1_3_) {
214    char** sites = NULL;
215    flash_browser_operations_1_3_->GetSitesWithData(data_str.c_str(), &sites);
216    if (!sites)
217      return;
218
219    for (size_t i = 0; sites[i]; ++i)
220      site_vector->push_back(sites[i]);
221
222    flash_browser_operations_1_3_->FreeSiteList(sites);
223  }
224}
225
226bool BrokerProcessDispatcher::ClearSiteData(
227    const base::FilePath& plugin_data_path,
228    const std::string& site,
229    uint64 flags,
230    uint64 max_age) {
231  std::string data_str = ConvertPluginDataPath(plugin_data_path);
232  if (flash_browser_operations_1_3_) {
233    flash_browser_operations_1_3_->ClearSiteData(
234        data_str.c_str(), site.empty() ? NULL : site.c_str(), flags, max_age);
235    return true;
236  }
237
238  // TODO(viettrungluu): Remove this (and the 1.0 interface) sometime after M21
239  // goes to Stable.
240  if (flash_browser_operations_1_2_) {
241    flash_browser_operations_1_2_->ClearSiteData(
242        data_str.c_str(), site.empty() ? NULL : site.c_str(), flags, max_age);
243    return true;
244  }
245
246  if (flash_browser_operations_1_0_) {
247    flash_browser_operations_1_0_->ClearSiteData(
248        data_str.c_str(), site.empty() ? NULL : site.c_str(), flags, max_age);
249    return true;
250  }
251
252  return false;
253}
254
255bool BrokerProcessDispatcher::DeauthorizeContentLicenses(
256    const base::FilePath& plugin_data_path) {
257  if (flash_browser_operations_1_3_) {
258    std::string data_str = ConvertPluginDataPath(plugin_data_path);
259    return PP_ToBool(flash_browser_operations_1_3_->DeauthorizeContentLicenses(
260        data_str.c_str()));
261  }
262
263  if (flash_browser_operations_1_2_) {
264    std::string data_str = ConvertPluginDataPath(plugin_data_path);
265    return PP_ToBool(flash_browser_operations_1_2_->DeauthorizeContentLicenses(
266        data_str.c_str()));
267  }
268
269  return false;
270}
271
272bool BrokerProcessDispatcher::SetDefaultPermission(
273    const base::FilePath& plugin_data_path,
274    PP_Flash_BrowserOperations_SettingType setting_type,
275    PP_Flash_BrowserOperations_Permission permission,
276    bool clear_site_specific) {
277  if (flash_browser_operations_1_3_) {
278    std::string data_str = ConvertPluginDataPath(plugin_data_path);
279    return PP_ToBool(flash_browser_operations_1_3_->SetDefaultPermission(
280        data_str.c_str(), setting_type, permission,
281        PP_FromBool(clear_site_specific)));
282  }
283
284  if (flash_browser_operations_1_2_) {
285    std::string data_str = ConvertPluginDataPath(plugin_data_path);
286    return PP_ToBool(flash_browser_operations_1_2_->SetDefaultPermission(
287        data_str.c_str(), setting_type, permission,
288        PP_FromBool(clear_site_specific)));
289  }
290
291  return false;
292}
293
294bool BrokerProcessDispatcher::SetSitePermission(
295    const base::FilePath& plugin_data_path,
296    PP_Flash_BrowserOperations_SettingType setting_type,
297    const ppapi::FlashSiteSettings& sites) {
298  if (sites.empty())
299    return true;
300
301  std::string data_str = ConvertPluginDataPath(plugin_data_path);
302  scoped_ptr<PP_Flash_BrowserOperations_SiteSetting[]> site_array(
303      new PP_Flash_BrowserOperations_SiteSetting[sites.size()]);
304
305  for (size_t i = 0; i < sites.size(); ++i) {
306    site_array[i].site = sites[i].site.c_str();
307    site_array[i].permission = sites[i].permission;
308  }
309
310  if (flash_browser_operations_1_3_) {
311    PP_Bool result = flash_browser_operations_1_3_->SetSitePermission(
312        data_str.c_str(), setting_type, sites.size(), site_array.get());
313
314    return PP_ToBool(result);
315  }
316
317  if (flash_browser_operations_1_2_) {
318    PP_Bool result = flash_browser_operations_1_2_->SetSitePermission(
319        data_str.c_str(), setting_type, sites.size(), site_array.get());
320
321    return PP_ToBool(result);
322  }
323
324  return false;
325}
326
327}  // namespace content
328