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.
5 #include "chrome/browser/extensions/api/webview/webview_api.h"
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"
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;
28 namespace extensions {
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;
49 bool WebviewExtensionFunction::RunAsync() {
51 EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &instance_id));
52 WebViewGuest* guest = WebViewGuest::From(
53 render_view_host()->GetProcess()->GetID(), instance_id);
57 return RunAsyncSafe(guest);
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());
68 Profile::FromBrowserContext(browser_context())->IsOffTheRecord(),
69 MenuItem::ExtensionKey(extension_id(), params->instance_id));
71 if (params->create_properties.id.get()) {
72 id.string_uid = *params->create_properties.id;
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));
81 bool success = extensions::context_menus_api_helpers::CreateMenuItem(
82 params->create_properties,
83 Profile::FromBrowserContext(browser_context()),
88 SendResponse(success);
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);
101 bool WebviewContextMenusUpdateFunction::RunAsync() {
102 scoped_ptr<webview::ContextMenusUpdate::Params> params(
103 webview::ContextMenusUpdate::Params::Create(*args_));
104 EXTENSION_FUNCTION_VALIDATE(params.get());
106 Profile* profile = Profile::FromBrowserContext(browser_context());
107 MenuItem::Id item_id(
108 profile->IsOffTheRecord(),
109 MenuItem::ExtensionKey(extension_id(), params->instance_id));
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;
118 bool success = extensions::context_menus_api_helpers::UpdateMenuItem(
119 params->update_properties, profile, GetExtension(), item_id, &error_);
120 SendResponse(success);
124 bool WebviewContextMenusRemoveFunction::RunAsync() {
125 scoped_ptr<webview::ContextMenusRemove::Params> params(
126 webview::ContextMenusRemove::Params::Create(*args_));
127 EXTENSION_FUNCTION_VALIDATE(params.get());
129 MenuManager* menu_manager =
130 MenuManager::Get(Profile::FromBrowserContext(browser_context()));
133 Profile::FromBrowserContext(browser_context())->IsOffTheRecord(),
134 MenuItem::ExtensionKey(extension_id(), params->instance_id));
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;
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));
152 } else if (!menu_manager->RemoveContextMenuItem(id)) {
156 SendResponse(success);
160 bool WebviewContextMenusRemoveAllFunction::RunAsync() {
161 scoped_ptr<webview::ContextMenusRemoveAll::Params> params(
162 webview::ContextMenusRemoveAll::Params::Create(*args_));
163 EXTENSION_FUNCTION_VALIDATE(params.get());
165 MenuManager* menu_manager =
166 MenuManager::Get(Profile::FromBrowserContext(browser_context()));
168 int webview_instance_id = params->instance_id;
169 menu_manager->RemoveAllContextItems(
170 MenuItem::ExtensionKey(GetExtension()->id(), webview_instance_id));
175 WebviewClearDataFunction::WebviewClearDataFunction()
176 : remove_mask_(0), bad_message_(false) {}
178 WebviewClearDataFunction::~WebviewClearDataFunction() {}
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)) {
190 uint32 remove_mask = 0;
191 for (base::DictionaryValue::Iterator i(*data_to_remove);
194 bool selected = false;
195 if (!i.value().GetAsBoolean(&selected)) {
200 remove_mask |= MaskForKey(i.key().c_str());
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));
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,
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);
229 remove_mask_ = GetRemovalMask();
233 AddRef(); // Balanced below or in WebviewClearDataFunction::Done().
235 bool scheduled = false;
237 scheduled = guest->ClearData(
240 base::Bind(&WebviewClearDataFunction::ClearDataDone,
243 if (!remove_mask_ || !scheduled) {
245 Release(); // Balanced above.
249 // Will finish asynchronously.
253 void WebviewClearDataFunction::ClearDataDone() {
254 Release(); // Balanced in RunAsync().
258 WebviewExecuteCodeFunction::WebviewExecuteCodeFunction()
259 : guest_instance_id_(0), guest_src_(GURL::EmptyGURL()) {}
261 WebviewExecuteCodeFunction::~WebviewExecuteCodeFunction() {
264 bool WebviewExecuteCodeFunction::Init() {
268 if (!args_->GetInteger(0, &guest_instance_id_))
271 if (!guest_instance_id_)
275 if (!args_->GetString(1, &src))
278 guest_src_ = GURL(src);
279 if (!guest_src_.is_valid())
282 base::DictionaryValue* details_value = NULL;
283 if (!args_->GetDictionary(2, &details_value))
285 scoped_ptr<InjectDetails> details(new InjectDetails());
286 if (!InjectDetails::Populate(*details_value, details.get()))
289 details_ = details.Pass();
293 bool WebviewExecuteCodeFunction::ShouldInsertCSS() const {
297 bool WebviewExecuteCodeFunction::CanExecuteScriptOnPage() {
301 extensions::ScriptExecutor* WebviewExecuteCodeFunction::GetScriptExecutor() {
302 WebViewGuest* guest = WebViewGuest::From(
303 render_view_host()->GetProcess()->GetID(), guest_instance_id_);
307 return guest->script_executor();
310 bool WebviewExecuteCodeFunction::IsWebView() const {
314 const GURL& WebviewExecuteCodeFunction::GetWebViewSrc() const {
318 WebviewExecuteScriptFunction::WebviewExecuteScriptFunction() {
321 void WebviewExecuteScriptFunction::OnExecuteCodeFinished(
322 const std::string& error,
325 const base::ListValue& result) {
327 SetResult(result.DeepCopy());
328 WebviewExecuteCodeFunction::OnExecuteCodeFinished(error, on_page_id, on_url,
332 WebviewInsertCSSFunction::WebviewInsertCSSFunction() {
335 bool WebviewInsertCSSFunction::ShouldInsertCSS() const {
339 WebviewCaptureVisibleRegionFunction::WebviewCaptureVisibleRegionFunction() {
342 WebviewCaptureVisibleRegionFunction::~WebviewCaptureVisibleRegionFunction() {
345 bool WebviewCaptureVisibleRegionFunction::IsScreenshotEnabled() {
349 WebContents* WebviewCaptureVisibleRegionFunction::GetWebContentsForID(
351 WebViewGuest* guest = WebViewGuest::From(
352 render_view_host()->GetProcess()->GetID(), instance_id);
353 return guest ? guest->guest_web_contents() : NULL;
356 void WebviewCaptureVisibleRegionFunction::OnCaptureFailure(
357 FailureReason reason) {
361 WebviewSetNameFunction::WebviewSetNameFunction() {
364 WebviewSetNameFunction::~WebviewSetNameFunction() {
367 WebviewSetZoomFunction::WebviewSetZoomFunction() {
370 WebviewSetZoomFunction::~WebviewSetZoomFunction() {
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);
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);
392 WebviewGetZoomFunction::WebviewGetZoomFunction() {
395 WebviewGetZoomFunction::~WebviewGetZoomFunction() {
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());
403 double zoom_factor = guest->GetZoom();
404 SetResult(base::Value::CreateDoubleValue(zoom_factor));
409 WebviewFindFunction::WebviewFindFunction() {
412 WebviewFindFunction::~WebviewFindFunction() {
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());
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(),
426 // Set the find options to their default values.
427 blink::WebFindOptions options;
428 if (params->options) {
430 params->options->backward ? !*params->options->backward : true;
432 params->options->match_case ? *params->options->match_case : false;
435 guest->Find(search_text, options, this);
439 WebviewStopFindingFunction::WebviewStopFindingFunction() {
442 WebviewStopFindingFunction::~WebviewStopFindingFunction() {
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());
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;
456 case webview::StopFinding::Params::ACTION_KEEP:
457 action = content::STOP_FIND_ACTION_KEEP_SELECTION;
459 case webview::StopFinding::Params::ACTION_ACTIVATE:
460 action = content::STOP_FIND_ACTION_ACTIVATE_SELECTION;
463 action = content::STOP_FIND_ACTION_KEEP_SELECTION;
466 guest->StopFinding(action);
470 WebviewGoFunction::WebviewGoFunction() {
473 WebviewGoFunction::~WebviewGoFunction() {
476 bool WebviewGoFunction::RunAsyncSafe(WebViewGuest* guest) {
477 scoped_ptr<webview::Go::Params> params(webview::Go::Params::Create(*args_));
478 EXTENSION_FUNCTION_VALIDATE(params.get());
480 guest->Go(params->relative_index);
484 WebviewReloadFunction::WebviewReloadFunction() {
487 WebviewReloadFunction::~WebviewReloadFunction() {
490 bool WebviewReloadFunction::RunAsyncSafe(WebViewGuest* guest) {
495 WebviewSetPermissionFunction::WebviewSetPermissionFunction() {
498 WebviewSetPermissionFunction::~WebviewSetPermissionFunction() {
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());
506 WebViewGuest::PermissionResponseAction action = WebViewGuest::DEFAULT;
507 switch (params->action) {
508 case Params::ACTION_ALLOW:
509 action = WebViewGuest::ALLOW;
511 case Params::ACTION_DENY:
512 action = WebViewGuest::DENY;
514 case Params::ACTION_DEFAULT:
520 std::string user_input;
521 if (params->user_input)
522 user_input = *params->user_input;
524 WebViewGuest::SetPermissionResult result =
525 guest->SetPermission(params->request_id, action, user_input);
527 EXTENSION_FUNCTION_VALIDATE(result != WebViewGuest::SET_PERMISSION_INVALID);
529 SetResult(base::Value::CreateBooleanValue(
530 result == WebViewGuest::SET_PERMISSION_ALLOWED));
535 WebviewShowContextMenuFunction::WebviewShowContextMenuFunction() {
538 WebviewShowContextMenuFunction::~WebviewShowContextMenuFunction() {
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());
546 // TODO(lazyboy): Actually implement filtering menu items, we pass NULL for
548 guest->ShowContextMenu(params->request_id, NULL);
554 WebviewOverrideUserAgentFunction::WebviewOverrideUserAgentFunction() {
557 WebviewOverrideUserAgentFunction::~WebviewOverrideUserAgentFunction() {
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());
565 guest->SetUserAgentOverride(params->user_agent_override);
569 WebviewStopFunction::WebviewStopFunction() {
572 WebviewStopFunction::~WebviewStopFunction() {
575 bool WebviewStopFunction::RunAsyncSafe(WebViewGuest* guest) {
580 WebviewTerminateFunction::WebviewTerminateFunction() {
583 WebviewTerminateFunction::~WebviewTerminateFunction() {
586 bool WebviewTerminateFunction::RunAsyncSafe(WebViewGuest* guest) {
591 } // namespace extensions