Upstream version 9.37.197.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / extensions / api / webview / webview_api.cc
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 "base/strings/utf_string_conversions.h"
8 #include "chrome/browser/extensions/api/browsing_data/browsing_data_api.h"
9 #include "chrome/browser/extensions/api/context_menus/context_menus_api.h"
10 #include "chrome/browser/extensions/api/context_menus/context_menus_api_helpers.h"
11 #include "chrome/browser/extensions/tab_helper.h"
12 #include "chrome/browser/profiles/profile.h"
13 #include "chrome/common/extensions/api/webview.h"
14 #include "content/public/browser/render_process_host.h"
15 #include "content/public/browser/render_view_host.h"
16 #include "content/public/browser/storage_partition.h"
17 #include "content/public/browser/web_contents.h"
18 #include "content/public/common/stop_find_action.h"
19 #include "extensions/common/error_utils.h"
20 #include "third_party/WebKit/public/web/WebFindOptions.h"
21
22 using content::WebContents;
23 using extensions::api::tabs::InjectDetails;
24 using extensions::api::webview::SetPermission::Params;
25 namespace helpers = extensions::context_menus_api_helpers;
26 namespace webview = extensions::api::webview;
27
28 namespace extensions {
29
30 namespace {
31 int MaskForKey(const char* key) {
32   if (strcmp(key, extension_browsing_data_api_constants::kAppCacheKey) == 0)
33     return content::StoragePartition::REMOVE_DATA_MASK_APPCACHE;
34   if (strcmp(key, extension_browsing_data_api_constants::kCookiesKey) == 0)
35     return content::StoragePartition::REMOVE_DATA_MASK_COOKIES;
36   if (strcmp(key, extension_browsing_data_api_constants::kFileSystemsKey) == 0)
37     return content::StoragePartition::REMOVE_DATA_MASK_FILE_SYSTEMS;
38   if (strcmp(key, extension_browsing_data_api_constants::kIndexedDBKey) == 0)
39     return content::StoragePartition::REMOVE_DATA_MASK_INDEXEDDB;
40   if (strcmp(key, extension_browsing_data_api_constants::kLocalStorageKey) == 0)
41     return content::StoragePartition::REMOVE_DATA_MASK_LOCAL_STORAGE;
42   if (strcmp(key, extension_browsing_data_api_constants::kWebSQLKey) == 0)
43     return content::StoragePartition::REMOVE_DATA_MASK_WEBSQL;
44   return 0;
45 }
46
47 }  // namespace
48
49 bool WebviewExtensionFunction::RunAsync() {
50   int instance_id = 0;
51   EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &instance_id));
52   WebViewGuest* guest = WebViewGuest::From(
53       render_view_host()->GetProcess()->GetID(), instance_id);
54   if (!guest)
55     return false;
56
57   return RunAsyncSafe(guest);
58 }
59
60 // TODO(lazyboy): Add checks similar to
61 // WebviewExtensionFunction::RunAsyncSafe(WebViewGuest*).
62 bool WebviewContextMenusCreateFunction::RunAsync() {
63   scoped_ptr<webview::ContextMenusCreate::Params> params(
64       webview::ContextMenusCreate::Params::Create(*args_));
65   EXTENSION_FUNCTION_VALIDATE(params.get());
66
67   MenuItem::Id id(
68       Profile::FromBrowserContext(browser_context())->IsOffTheRecord(),
69       MenuItem::ExtensionKey(extension_id(), params->instance_id));
70
71   if (params->create_properties.id.get()) {
72     id.string_uid = *params->create_properties.id;
73   } else {
74     // The Generated Id is added by webview_custom_bindings.js.
75     base::DictionaryValue* properties = NULL;
76     EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(1, &properties));
77     EXTENSION_FUNCTION_VALIDATE(
78         properties->GetInteger(helpers::kGeneratedIdKey, &id.uid));
79   }
80
81   bool success = extensions::context_menus_api_helpers::CreateMenuItem(
82       params->create_properties,
83       Profile::FromBrowserContext(browser_context()),
84       GetExtension(),
85       id,
86       &error_);
87
88   SendResponse(success);
89   return success;
90 }
91
92 bool WebviewNavigateFunction::RunAsyncSafe(WebViewGuest* guest) {
93   scoped_ptr<webview::Navigate::Params> params(
94       webview::Navigate::Params::Create(*args_));
95   EXTENSION_FUNCTION_VALIDATE(params.get());
96   std::string src = params->src;
97   guest->NavigateGuest(src);
98   return true;
99 }
100
101 bool WebviewContextMenusUpdateFunction::RunAsync() {
102   scoped_ptr<webview::ContextMenusUpdate::Params> params(
103       webview::ContextMenusUpdate::Params::Create(*args_));
104   EXTENSION_FUNCTION_VALIDATE(params.get());
105
106   Profile* profile = Profile::FromBrowserContext(browser_context());
107   MenuItem::Id item_id(
108       profile->IsOffTheRecord(),
109       MenuItem::ExtensionKey(extension_id(), params->instance_id));
110
111   if (params->id.as_string)
112     item_id.string_uid = *params->id.as_string;
113   else if (params->id.as_integer)
114     item_id.uid = *params->id.as_integer;
115   else
116     NOTREACHED();
117
118   bool success = extensions::context_menus_api_helpers::UpdateMenuItem(
119       params->update_properties, profile, GetExtension(), item_id, &error_);
120   SendResponse(success);
121   return success;
122 }
123
124 bool WebviewContextMenusRemoveFunction::RunAsync() {
125   scoped_ptr<webview::ContextMenusRemove::Params> params(
126       webview::ContextMenusRemove::Params::Create(*args_));
127   EXTENSION_FUNCTION_VALIDATE(params.get());
128
129   MenuManager* menu_manager =
130       MenuManager::Get(Profile::FromBrowserContext(browser_context()));
131
132   MenuItem::Id id(
133       Profile::FromBrowserContext(browser_context())->IsOffTheRecord(),
134       MenuItem::ExtensionKey(extension_id(), params->instance_id));
135
136   if (params->menu_item_id.as_string) {
137     id.string_uid = *params->menu_item_id.as_string;
138   } else if (params->menu_item_id.as_integer) {
139     id.uid = *params->menu_item_id.as_integer;
140   } else {
141     NOTREACHED();
142   }
143
144   bool success = true;
145   MenuItem* item = menu_manager->GetItemById(id);
146   // Ensure one <webview> can't remove another's menu items.
147   if (!item || item->id().extension_key != id.extension_key) {
148     error_ = ErrorUtils::FormatErrorMessage(
149         context_menus_api_helpers::kCannotFindItemError,
150         context_menus_api_helpers::GetIDString(id));
151     success = false;
152   } else if (!menu_manager->RemoveContextMenuItem(id)) {
153     success = false;
154   }
155
156   SendResponse(success);
157   return success;
158 }
159
160 bool WebviewContextMenusRemoveAllFunction::RunAsync() {
161   scoped_ptr<webview::ContextMenusRemoveAll::Params> params(
162       webview::ContextMenusRemoveAll::Params::Create(*args_));
163   EXTENSION_FUNCTION_VALIDATE(params.get());
164
165   MenuManager* menu_manager =
166       MenuManager::Get(Profile::FromBrowserContext(browser_context()));
167
168   int webview_instance_id = params->instance_id;
169   menu_manager->RemoveAllContextItems(
170       MenuItem::ExtensionKey(GetExtension()->id(), webview_instance_id));
171   SendResponse(true);
172   return true;
173 }
174
175 WebviewClearDataFunction::WebviewClearDataFunction()
176     : remove_mask_(0), bad_message_(false) {}
177
178 WebviewClearDataFunction::~WebviewClearDataFunction() {}
179
180 // Parses the |dataToRemove| argument to generate the remove mask. Sets
181 // |bad_message_| (like EXTENSION_FUNCTION_VALIDATE would if this were a bool
182 // method) if 'dataToRemove' is not present.
183 uint32 WebviewClearDataFunction::GetRemovalMask() {
184   base::DictionaryValue* data_to_remove;
185   if (!args_->GetDictionary(2, &data_to_remove)) {
186     bad_message_ = true;
187     return 0;
188   }
189
190   uint32 remove_mask = 0;
191   for (base::DictionaryValue::Iterator i(*data_to_remove);
192        !i.IsAtEnd();
193        i.Advance()) {
194     bool selected = false;
195     if (!i.value().GetAsBoolean(&selected)) {
196       bad_message_ = true;
197       return 0;
198     }
199     if (selected)
200       remove_mask |= MaskForKey(i.key().c_str());
201   }
202
203   return remove_mask;
204 }
205
206 // TODO(lazyboy): Parameters in this extension function are similar (or a
207 // sub-set) to BrowsingDataRemoverFunction. How can we share this code?
208 bool WebviewClearDataFunction::RunAsyncSafe(WebViewGuest* guest) {
209   // Grab the initial |options| parameter, and parse out the arguments.
210   base::DictionaryValue* options;
211   EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(1, &options));
212   DCHECK(options);
213
214   // If |ms_since_epoch| isn't set, default it to 0.
215   double ms_since_epoch;
216   if (!options->GetDouble(extension_browsing_data_api_constants::kSinceKey,
217                           &ms_since_epoch)) {
218     ms_since_epoch = 0;
219   }
220
221   // base::Time takes a double that represents seconds since epoch. JavaScript
222   // gives developers milliseconds, so do a quick conversion before populating
223   // the object. Also, Time::FromDoubleT converts double time 0 to empty Time
224   // object. So we need to do special handling here.
225   remove_since_ = (ms_since_epoch == 0) ?
226       base::Time::UnixEpoch() :
227       base::Time::FromDoubleT(ms_since_epoch / 1000.0);
228
229   remove_mask_ = GetRemovalMask();
230   if (bad_message_)
231     return false;
232
233   AddRef();  // Balanced below or in WebviewClearDataFunction::Done().
234
235   bool scheduled = false;
236   if (remove_mask_) {
237     scheduled = guest->ClearData(
238         remove_since_,
239         remove_mask_,
240         base::Bind(&WebviewClearDataFunction::ClearDataDone,
241                    this));
242   }
243   if (!remove_mask_ || !scheduled) {
244     SendResponse(false);
245     Release();  // Balanced above.
246     return false;
247   }
248
249   // Will finish asynchronously.
250   return true;
251 }
252
253 void WebviewClearDataFunction::ClearDataDone() {
254   Release();  // Balanced in RunAsync().
255   SendResponse(true);
256 }
257
258 WebviewExecuteCodeFunction::WebviewExecuteCodeFunction()
259     : guest_instance_id_(0), guest_src_(GURL::EmptyGURL()) {}
260
261 WebviewExecuteCodeFunction::~WebviewExecuteCodeFunction() {
262 }
263
264 bool WebviewExecuteCodeFunction::Init() {
265   if (details_.get())
266     return true;
267
268   if (!args_->GetInteger(0, &guest_instance_id_))
269     return false;
270
271   if (!guest_instance_id_)
272     return false;
273
274   std::string src;
275   if (!args_->GetString(1, &src))
276     return false;
277
278   guest_src_ = GURL(src);
279   if (!guest_src_.is_valid())
280     return false;
281
282   base::DictionaryValue* details_value = NULL;
283   if (!args_->GetDictionary(2, &details_value))
284     return false;
285   scoped_ptr<InjectDetails> details(new InjectDetails());
286   if (!InjectDetails::Populate(*details_value, details.get()))
287     return false;
288
289   details_ = details.Pass();
290   return true;
291 }
292
293 bool WebviewExecuteCodeFunction::ShouldInsertCSS() const {
294   return false;
295 }
296
297 bool WebviewExecuteCodeFunction::CanExecuteScriptOnPage() {
298   return true;
299 }
300
301 extensions::ScriptExecutor* WebviewExecuteCodeFunction::GetScriptExecutor() {
302   WebViewGuest* guest = WebViewGuest::From(
303       render_view_host()->GetProcess()->GetID(), guest_instance_id_);
304   if (!guest)
305     return NULL;
306
307   return guest->script_executor();
308 }
309
310 bool WebviewExecuteCodeFunction::IsWebView() const {
311   return true;
312 }
313
314 const GURL& WebviewExecuteCodeFunction::GetWebViewSrc() const {
315   return guest_src_;
316 }
317
318 WebviewExecuteScriptFunction::WebviewExecuteScriptFunction() {
319 }
320
321 void WebviewExecuteScriptFunction::OnExecuteCodeFinished(
322     const std::string& error,
323     int32 on_page_id,
324     const GURL& on_url,
325     const base::ListValue& result) {
326   if (error.empty())
327     SetResult(result.DeepCopy());
328   WebviewExecuteCodeFunction::OnExecuteCodeFinished(error, on_page_id, on_url,
329                                                     result);
330 }
331
332 WebviewInsertCSSFunction::WebviewInsertCSSFunction() {
333 }
334
335 bool WebviewInsertCSSFunction::ShouldInsertCSS() const {
336   return true;
337 }
338
339 WebviewCaptureVisibleRegionFunction::WebviewCaptureVisibleRegionFunction() {
340 }
341
342 WebviewCaptureVisibleRegionFunction::~WebviewCaptureVisibleRegionFunction() {
343 }
344
345 bool WebviewCaptureVisibleRegionFunction::IsScreenshotEnabled() {
346   return true;
347 }
348
349 WebContents* WebviewCaptureVisibleRegionFunction::GetWebContentsForID(
350     int instance_id) {
351   WebViewGuest* guest = WebViewGuest::From(
352       render_view_host()->GetProcess()->GetID(), instance_id);
353   return guest ? guest->guest_web_contents() : NULL;
354 }
355
356 void WebviewCaptureVisibleRegionFunction::OnCaptureFailure(
357     FailureReason reason) {
358   SendResponse(false);
359 }
360
361 WebviewSetNameFunction::WebviewSetNameFunction() {
362 }
363
364 WebviewSetNameFunction::~WebviewSetNameFunction() {
365 }
366
367 WebviewSetZoomFunction::WebviewSetZoomFunction() {
368 }
369
370 WebviewSetZoomFunction::~WebviewSetZoomFunction() {
371 }
372
373 bool WebviewSetNameFunction::RunAsyncSafe(WebViewGuest* guest) {
374   scoped_ptr<webview::SetName::Params> params(
375       webview::SetName::Params::Create(*args_));
376   EXTENSION_FUNCTION_VALIDATE(params.get());
377   guest->SetName(params->frame_name);
378   SendResponse(true);
379   return true;
380 }
381
382 bool WebviewSetZoomFunction::RunAsyncSafe(WebViewGuest* guest) {
383   scoped_ptr<webview::SetZoom::Params> params(
384       webview::SetZoom::Params::Create(*args_));
385   EXTENSION_FUNCTION_VALIDATE(params.get());
386   guest->SetZoom(params->zoom_factor);
387
388   SendResponse(true);
389   return true;
390 }
391
392 WebviewGetZoomFunction::WebviewGetZoomFunction() {
393 }
394
395 WebviewGetZoomFunction::~WebviewGetZoomFunction() {
396 }
397
398 bool WebviewGetZoomFunction::RunAsyncSafe(WebViewGuest* guest) {
399   scoped_ptr<webview::GetZoom::Params> params(
400       webview::GetZoom::Params::Create(*args_));
401   EXTENSION_FUNCTION_VALIDATE(params.get());
402
403   double zoom_factor = guest->GetZoom();
404   SetResult(base::Value::CreateDoubleValue(zoom_factor));
405   SendResponse(true);
406   return true;
407 }
408
409 WebviewFindFunction::WebviewFindFunction() {
410 }
411
412 WebviewFindFunction::~WebviewFindFunction() {
413 }
414
415 bool WebviewFindFunction::RunAsyncSafe(WebViewGuest* guest) {
416   scoped_ptr<webview::Find::Params> params(
417       webview::Find::Params::Create(*args_));
418   EXTENSION_FUNCTION_VALIDATE(params.get());
419
420   // Convert the std::string search_text to string16.
421   base::string16 search_text;
422   base::UTF8ToUTF16(params->search_text.c_str(),
423                     params->search_text.length(),
424                     &search_text);
425
426   // Set the find options to their default values.
427   blink::WebFindOptions options;
428   if (params->options) {
429     options.forward =
430         params->options->backward ? !*params->options->backward : true;
431     options.matchCase =
432         params->options->match_case ? *params->options->match_case : false;
433   }
434
435   guest->Find(search_text, options, this);
436   return true;
437 }
438
439 WebviewStopFindingFunction::WebviewStopFindingFunction() {
440 }
441
442 WebviewStopFindingFunction::~WebviewStopFindingFunction() {
443 }
444
445 bool WebviewStopFindingFunction::RunAsyncSafe(WebViewGuest* guest) {
446   scoped_ptr<webview::StopFinding::Params> params(
447       webview::StopFinding::Params::Create(*args_));
448   EXTENSION_FUNCTION_VALIDATE(params.get());
449
450   // Set the StopFindAction.
451   content::StopFindAction action;
452   switch (params->action) {
453     case webview::StopFinding::Params::ACTION_CLEAR:
454       action = content::STOP_FIND_ACTION_CLEAR_SELECTION;
455       break;
456     case webview::StopFinding::Params::ACTION_KEEP:
457       action = content::STOP_FIND_ACTION_KEEP_SELECTION;
458       break;
459     case webview::StopFinding::Params::ACTION_ACTIVATE:
460       action = content::STOP_FIND_ACTION_ACTIVATE_SELECTION;
461       break;
462     default:
463       action = content::STOP_FIND_ACTION_KEEP_SELECTION;
464   }
465
466   guest->StopFinding(action);
467   return true;
468 }
469
470 WebviewGoFunction::WebviewGoFunction() {
471 }
472
473 WebviewGoFunction::~WebviewGoFunction() {
474 }
475
476 bool WebviewGoFunction::RunAsyncSafe(WebViewGuest* guest) {
477   scoped_ptr<webview::Go::Params> params(webview::Go::Params::Create(*args_));
478   EXTENSION_FUNCTION_VALIDATE(params.get());
479
480   guest->Go(params->relative_index);
481   return true;
482 }
483
484 WebviewReloadFunction::WebviewReloadFunction() {
485 }
486
487 WebviewReloadFunction::~WebviewReloadFunction() {
488 }
489
490 bool WebviewReloadFunction::RunAsyncSafe(WebViewGuest* guest) {
491   guest->Reload();
492   return true;
493 }
494
495 WebviewSetPermissionFunction::WebviewSetPermissionFunction() {
496 }
497
498 WebviewSetPermissionFunction::~WebviewSetPermissionFunction() {
499 }
500
501 bool WebviewSetPermissionFunction::RunAsyncSafe(WebViewGuest* guest) {
502   scoped_ptr<webview::SetPermission::Params> params(
503       webview::SetPermission::Params::Create(*args_));
504   EXTENSION_FUNCTION_VALIDATE(params.get());
505
506   WebViewGuest::PermissionResponseAction action = WebViewGuest::DEFAULT;
507   switch (params->action) {
508     case Params::ACTION_ALLOW:
509       action = WebViewGuest::ALLOW;
510       break;
511     case Params::ACTION_DENY:
512       action = WebViewGuest::DENY;
513       break;
514     case Params::ACTION_DEFAULT:
515       break;
516     default:
517       NOTREACHED();
518   }
519
520   std::string user_input;
521   if (params->user_input)
522     user_input = *params->user_input;
523
524   WebViewGuest::SetPermissionResult result =
525       guest->SetPermission(params->request_id, action, user_input);
526
527   EXTENSION_FUNCTION_VALIDATE(result != WebViewGuest::SET_PERMISSION_INVALID);
528
529   SetResult(base::Value::CreateBooleanValue(
530       result == WebViewGuest::SET_PERMISSION_ALLOWED));
531   SendResponse(true);
532   return true;
533 }
534
535 WebviewShowContextMenuFunction::WebviewShowContextMenuFunction() {
536 }
537
538 WebviewShowContextMenuFunction::~WebviewShowContextMenuFunction() {
539 }
540
541 bool WebviewShowContextMenuFunction::RunAsyncSafe(WebViewGuest* guest) {
542   scoped_ptr<webview::ShowContextMenu::Params> params(
543       webview::ShowContextMenu::Params::Create(*args_));
544   EXTENSION_FUNCTION_VALIDATE(params.get());
545
546   // TODO(lazyboy): Actually implement filtering menu items, we pass NULL for
547   // now.
548   guest->ShowContextMenu(params->request_id, NULL);
549
550   SendResponse(true);
551   return true;
552 }
553
554 WebviewOverrideUserAgentFunction::WebviewOverrideUserAgentFunction() {
555 }
556
557 WebviewOverrideUserAgentFunction::~WebviewOverrideUserAgentFunction() {
558 }
559
560 bool WebviewOverrideUserAgentFunction::RunAsyncSafe(WebViewGuest* guest) {
561   scoped_ptr<extensions::api::webview::OverrideUserAgent::Params> params(
562       extensions::api::webview::OverrideUserAgent::Params::Create(*args_));
563   EXTENSION_FUNCTION_VALIDATE(params.get());
564
565   guest->SetUserAgentOverride(params->user_agent_override);
566   return true;
567 }
568
569 WebviewStopFunction::WebviewStopFunction() {
570 }
571
572 WebviewStopFunction::~WebviewStopFunction() {
573 }
574
575 bool WebviewStopFunction::RunAsyncSafe(WebViewGuest* guest) {
576   guest->Stop();
577   return true;
578 }
579
580 WebviewTerminateFunction::WebviewTerminateFunction() {
581 }
582
583 WebviewTerminateFunction::~WebviewTerminateFunction() {
584 }
585
586 bool WebviewTerminateFunction::RunAsyncSafe(WebViewGuest* guest) {
587   guest->Terminate();
588   return true;
589 }
590
591 }  // namespace extensions