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 "chrome/browser/extensions/api/webview/webview_api.h"
6
7#include "chrome/browser/extensions/api/browsing_data/browsing_data_api.h"
8#include "chrome/browser/extensions/tab_helper.h"
9#include "chrome/common/extensions/api/webview.h"
10#include "content/public/browser/render_process_host.h"
11#include "content/public/browser/render_view_host.h"
12#include "content/public/browser/storage_partition.h"
13#include "content/public/browser/web_contents.h"
14#include "extensions/common/error_utils.h"
15
16using content::WebContents;
17using extensions::api::tabs::InjectDetails;
18using extensions::api::webview::SetPermission::Params;
19namespace webview = extensions::api::webview;
20
21namespace extensions {
22
23namespace {
24int MaskForKey(const char* key) {
25  if (strcmp(key, extension_browsing_data_api_constants::kAppCacheKey) == 0)
26    return content::StoragePartition::REMOVE_DATA_MASK_APPCACHE;
27  if (strcmp(key, extension_browsing_data_api_constants::kCookiesKey) == 0)
28    return content::StoragePartition::REMOVE_DATA_MASK_COOKIES;
29  if (strcmp(key, extension_browsing_data_api_constants::kFileSystemsKey) == 0)
30    return content::StoragePartition::REMOVE_DATA_MASK_FILE_SYSTEMS;
31  if (strcmp(key, extension_browsing_data_api_constants::kIndexedDBKey) == 0)
32    return content::StoragePartition::REMOVE_DATA_MASK_INDEXEDDB;
33  if (strcmp(key, extension_browsing_data_api_constants::kLocalStorageKey) == 0)
34    return content::StoragePartition::REMOVE_DATA_MASK_LOCAL_STORAGE;
35  if (strcmp(key, extension_browsing_data_api_constants::kWebSQLKey) == 0)
36    return content::StoragePartition::REMOVE_DATA_MASK_WEBSQL;
37  return 0;
38}
39
40}  // namespace
41
42bool WebviewExtensionFunction::RunImpl() {
43  int instance_id = 0;
44  EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &instance_id));
45  WebViewGuest* guest = WebViewGuest::From(
46      render_view_host()->GetProcess()->GetID(), instance_id);
47  if (!guest)
48    return false;
49
50  return RunImplSafe(guest);
51}
52
53WebviewClearDataFunction::WebviewClearDataFunction()
54    : remove_mask_(0),
55      bad_message_(false) {
56};
57
58WebviewClearDataFunction::~WebviewClearDataFunction() {
59};
60
61// Parses the |dataToRemove| argument to generate the remove mask. Sets
62// |bad_message_| (like EXTENSION_FUNCTION_VALIDATE would if this were a bool
63// method) if 'dataToRemove' is not present.
64uint32 WebviewClearDataFunction::GetRemovalMask() {
65  base::DictionaryValue* data_to_remove;
66  if (!args_->GetDictionary(2, &data_to_remove)) {
67    bad_message_ = true;
68    return 0;
69  }
70
71  uint32 remove_mask = 0;
72  for (base::DictionaryValue::Iterator i(*data_to_remove);
73       !i.IsAtEnd();
74       i.Advance()) {
75    bool selected = false;
76    if (!i.value().GetAsBoolean(&selected)) {
77      bad_message_ = true;
78      return 0;
79    }
80    if (selected)
81      remove_mask |= MaskForKey(i.key().c_str());
82  }
83
84  return remove_mask;
85}
86
87// TODO(lazyboy): Parameters in this extension function are similar (or a
88// sub-set) to BrowsingDataRemoverFunction. How can we share this code?
89bool WebviewClearDataFunction::RunImplSafe(WebViewGuest* guest) {
90  // Grab the initial |options| parameter, and parse out the arguments.
91  base::DictionaryValue* options;
92  EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(1, &options));
93  DCHECK(options);
94
95  // If |ms_since_epoch| isn't set, default it to 0.
96  double ms_since_epoch;
97  if (!options->GetDouble(extension_browsing_data_api_constants::kSinceKey,
98                          &ms_since_epoch)) {
99    ms_since_epoch = 0;
100  }
101
102  // base::Time takes a double that represents seconds since epoch. JavaScript
103  // gives developers milliseconds, so do a quick conversion before populating
104  // the object. Also, Time::FromDoubleT converts double time 0 to empty Time
105  // object. So we need to do special handling here.
106  remove_since_ = (ms_since_epoch == 0) ?
107      base::Time::UnixEpoch() :
108      base::Time::FromDoubleT(ms_since_epoch / 1000.0);
109
110  remove_mask_ = GetRemovalMask();
111  if (bad_message_)
112    return false;
113
114  AddRef();  // Balanced below or in WebviewClearDataFunction::Done().
115
116  bool scheduled = false;
117  if (remove_mask_) {
118    scheduled = guest->ClearData(
119        remove_since_,
120        remove_mask_,
121        base::Bind(&WebviewClearDataFunction::ClearDataDone,
122                   this));
123  }
124  if (!remove_mask_ || !scheduled) {
125    SendResponse(false);
126    Release();  // Balanced above.
127    return false;
128  }
129
130  // Will finish asynchronously.
131  return true;
132}
133
134void WebviewClearDataFunction::ClearDataDone() {
135  Release();  // Balanced in RunImpl().
136  SendResponse(true);
137}
138
139WebviewExecuteCodeFunction::WebviewExecuteCodeFunction()
140    : guest_instance_id_(0) {
141}
142
143WebviewExecuteCodeFunction::~WebviewExecuteCodeFunction() {
144}
145
146bool WebviewExecuteCodeFunction::Init() {
147  if (details_.get())
148    return true;
149
150  if (!args_->GetInteger(0, &guest_instance_id_))
151    return false;
152
153  if (!guest_instance_id_)
154    return false;
155
156  base::DictionaryValue* details_value = NULL;
157  if (!args_->GetDictionary(1, &details_value))
158    return false;
159  scoped_ptr<InjectDetails> details(new InjectDetails());
160  if (!InjectDetails::Populate(*details_value, details.get()))
161    return false;
162
163  details_ = details.Pass();
164  return true;
165}
166
167bool WebviewExecuteCodeFunction::ShouldInsertCSS() const {
168  return false;
169}
170
171bool WebviewExecuteCodeFunction::CanExecuteScriptOnPage() {
172  return true;
173}
174
175extensions::ScriptExecutor* WebviewExecuteCodeFunction::GetScriptExecutor() {
176  WebViewGuest* guest = WebViewGuest::From(
177      render_view_host()->GetProcess()->GetID(), guest_instance_id_);
178  if (!guest)
179    return NULL;
180
181  return guest->script_executor();
182}
183
184bool WebviewExecuteCodeFunction::IsWebView() const {
185  return true;
186}
187
188WebviewExecuteScriptFunction::WebviewExecuteScriptFunction() {
189}
190
191void WebviewExecuteScriptFunction::OnExecuteCodeFinished(
192    const std::string& error,
193    int32 on_page_id,
194    const GURL& on_url,
195    const base::ListValue& result) {
196  if (error.empty())
197    SetResult(result.DeepCopy());
198  WebviewExecuteCodeFunction::OnExecuteCodeFinished(error, on_page_id, on_url,
199                                                    result);
200}
201
202WebviewInsertCSSFunction::WebviewInsertCSSFunction() {
203}
204
205bool WebviewInsertCSSFunction::ShouldInsertCSS() const {
206  return true;
207}
208
209WebviewCaptureVisibleRegionFunction::WebviewCaptureVisibleRegionFunction() {
210}
211
212WebviewCaptureVisibleRegionFunction::~WebviewCaptureVisibleRegionFunction() {
213}
214
215bool WebviewCaptureVisibleRegionFunction::IsScreenshotEnabled() {
216  return true;
217}
218
219WebContents* WebviewCaptureVisibleRegionFunction::GetWebContentsForID(
220    int instance_id) {
221  WebViewGuest* guest = WebViewGuest::From(
222      render_view_host()->GetProcess()->GetID(), instance_id);
223  return guest ? guest->guest_web_contents() : NULL;
224}
225
226void WebviewCaptureVisibleRegionFunction::OnCaptureFailure(
227    FailureReason reason) {
228  SendResponse(false);
229}
230
231WebviewGoFunction::WebviewGoFunction() {
232}
233
234WebviewGoFunction::~WebviewGoFunction() {
235}
236
237bool WebviewGoFunction::RunImplSafe(WebViewGuest* guest) {
238  scoped_ptr<webview::Go::Params> params(webview::Go::Params::Create(*args_));
239  EXTENSION_FUNCTION_VALIDATE(params.get());
240
241  guest->Go(params->relative_index);
242  return true;
243}
244
245WebviewReloadFunction::WebviewReloadFunction() {
246}
247
248WebviewReloadFunction::~WebviewReloadFunction() {
249}
250
251bool WebviewReloadFunction::RunImplSafe(WebViewGuest* guest) {
252  guest->Reload();
253  return true;
254}
255
256WebviewSetPermissionFunction::WebviewSetPermissionFunction() {
257}
258
259WebviewSetPermissionFunction::~WebviewSetPermissionFunction() {
260}
261
262bool WebviewSetPermissionFunction::RunImplSafe(WebViewGuest* guest) {
263  scoped_ptr<webview::SetPermission::Params> params(
264      webview::SetPermission::Params::Create(*args_));
265  EXTENSION_FUNCTION_VALIDATE(params.get());
266
267  WebViewGuest::PermissionResponseAction action = WebViewGuest::DEFAULT;
268  switch (params->action) {
269    case Params::ACTION_ALLOW:
270      action = WebViewGuest::ALLOW;
271      break;
272    case Params::ACTION_DENY:
273      action = WebViewGuest::DENY;
274      break;
275    case Params::ACTION_DEFAULT:
276      break;
277    default:
278      NOTREACHED();
279  }
280
281  std::string user_input;
282  if (params->user_input)
283    user_input = *params->user_input;
284
285  WebViewGuest::SetPermissionResult result =
286      guest->SetPermission(params->request_id, action, user_input);
287
288  EXTENSION_FUNCTION_VALIDATE(result != WebViewGuest::SET_PERMISSION_INVALID);
289
290  SetResult(base::Value::CreateBooleanValue(
291      result == WebViewGuest::SET_PERMISSION_ALLOWED));
292  SendResponse(true);
293  return true;
294}
295
296WebviewOverrideUserAgentFunction::WebviewOverrideUserAgentFunction() {
297}
298
299WebviewOverrideUserAgentFunction::~WebviewOverrideUserAgentFunction() {
300}
301
302bool WebviewOverrideUserAgentFunction::RunImplSafe(WebViewGuest* guest) {
303  scoped_ptr<extensions::api::webview::OverrideUserAgent::Params> params(
304      extensions::api::webview::OverrideUserAgent::Params::Create(*args_));
305  EXTENSION_FUNCTION_VALIDATE(params.get());
306
307  guest->SetUserAgentOverride(params->user_agent_override);
308  return true;
309}
310
311WebviewStopFunction::WebviewStopFunction() {
312}
313
314WebviewStopFunction::~WebviewStopFunction() {
315}
316
317bool WebviewStopFunction::RunImplSafe(WebViewGuest* guest) {
318  guest->Stop();
319  return true;
320}
321
322WebviewTerminateFunction::WebviewTerminateFunction() {
323}
324
325WebviewTerminateFunction::~WebviewTerminateFunction() {
326}
327
328bool WebviewTerminateFunction::RunImplSafe(WebViewGuest* guest) {
329  guest->Terminate();
330  return true;
331}
332
333}  // namespace extensions
334