• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 {
MaskForKey(const char * key)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 
RunAsync()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*).
RunAsync()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 
RunAsyncSafe(WebViewGuest * guest)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 
RunAsync()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 
RunAsync()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 
RunAsync()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 
WebviewClearDataFunction()175 WebviewClearDataFunction::WebviewClearDataFunction()
176     : remove_mask_(0), bad_message_(false) {}
177 
~WebviewClearDataFunction()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.
GetRemovalMask()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?
RunAsyncSafe(WebViewGuest * guest)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 
ClearDataDone()253 void WebviewClearDataFunction::ClearDataDone() {
254   Release();  // Balanced in RunAsync().
255   SendResponse(true);
256 }
257 
WebviewExecuteCodeFunction()258 WebviewExecuteCodeFunction::WebviewExecuteCodeFunction()
259     : guest_instance_id_(0), guest_src_(GURL::EmptyGURL()) {}
260 
~WebviewExecuteCodeFunction()261 WebviewExecuteCodeFunction::~WebviewExecuteCodeFunction() {
262 }
263 
Init()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 
ShouldInsertCSS() const293 bool WebviewExecuteCodeFunction::ShouldInsertCSS() const {
294   return false;
295 }
296 
CanExecuteScriptOnPage()297 bool WebviewExecuteCodeFunction::CanExecuteScriptOnPage() {
298   return true;
299 }
300 
GetScriptExecutor()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 
IsWebView() const310 bool WebviewExecuteCodeFunction::IsWebView() const {
311   return true;
312 }
313 
GetWebViewSrc() const314 const GURL& WebviewExecuteCodeFunction::GetWebViewSrc() const {
315   return guest_src_;
316 }
317 
WebviewExecuteScriptFunction()318 WebviewExecuteScriptFunction::WebviewExecuteScriptFunction() {
319 }
320 
OnExecuteCodeFinished(const std::string & error,int32 on_page_id,const GURL & on_url,const base::ListValue & result)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 
WebviewInsertCSSFunction()332 WebviewInsertCSSFunction::WebviewInsertCSSFunction() {
333 }
334 
ShouldInsertCSS() const335 bool WebviewInsertCSSFunction::ShouldInsertCSS() const {
336   return true;
337 }
338 
WebviewCaptureVisibleRegionFunction()339 WebviewCaptureVisibleRegionFunction::WebviewCaptureVisibleRegionFunction() {
340 }
341 
~WebviewCaptureVisibleRegionFunction()342 WebviewCaptureVisibleRegionFunction::~WebviewCaptureVisibleRegionFunction() {
343 }
344 
IsScreenshotEnabled()345 bool WebviewCaptureVisibleRegionFunction::IsScreenshotEnabled() {
346   return true;
347 }
348 
GetWebContentsForID(int instance_id)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 
OnCaptureFailure(FailureReason reason)356 void WebviewCaptureVisibleRegionFunction::OnCaptureFailure(
357     FailureReason reason) {
358   SendResponse(false);
359 }
360 
WebviewSetNameFunction()361 WebviewSetNameFunction::WebviewSetNameFunction() {
362 }
363 
~WebviewSetNameFunction()364 WebviewSetNameFunction::~WebviewSetNameFunction() {
365 }
366 
WebviewSetZoomFunction()367 WebviewSetZoomFunction::WebviewSetZoomFunction() {
368 }
369 
~WebviewSetZoomFunction()370 WebviewSetZoomFunction::~WebviewSetZoomFunction() {
371 }
372 
RunAsyncSafe(WebViewGuest * guest)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 
RunAsyncSafe(WebViewGuest * guest)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 
WebviewGetZoomFunction()392 WebviewGetZoomFunction::WebviewGetZoomFunction() {
393 }
394 
~WebviewGetZoomFunction()395 WebviewGetZoomFunction::~WebviewGetZoomFunction() {
396 }
397 
RunAsyncSafe(WebViewGuest * guest)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 
WebviewFindFunction()409 WebviewFindFunction::WebviewFindFunction() {
410 }
411 
~WebviewFindFunction()412 WebviewFindFunction::~WebviewFindFunction() {
413 }
414 
RunAsyncSafe(WebViewGuest * guest)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 
WebviewStopFindingFunction()439 WebviewStopFindingFunction::WebviewStopFindingFunction() {
440 }
441 
~WebviewStopFindingFunction()442 WebviewStopFindingFunction::~WebviewStopFindingFunction() {
443 }
444 
RunAsyncSafe(WebViewGuest * guest)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 
WebviewGoFunction()470 WebviewGoFunction::WebviewGoFunction() {
471 }
472 
~WebviewGoFunction()473 WebviewGoFunction::~WebviewGoFunction() {
474 }
475 
RunAsyncSafe(WebViewGuest * guest)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 
WebviewReloadFunction()484 WebviewReloadFunction::WebviewReloadFunction() {
485 }
486 
~WebviewReloadFunction()487 WebviewReloadFunction::~WebviewReloadFunction() {
488 }
489 
RunAsyncSafe(WebViewGuest * guest)490 bool WebviewReloadFunction::RunAsyncSafe(WebViewGuest* guest) {
491   guest->Reload();
492   return true;
493 }
494 
WebviewSetPermissionFunction()495 WebviewSetPermissionFunction::WebviewSetPermissionFunction() {
496 }
497 
~WebviewSetPermissionFunction()498 WebviewSetPermissionFunction::~WebviewSetPermissionFunction() {
499 }
500 
RunAsyncSafe(WebViewGuest * guest)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 
WebviewShowContextMenuFunction()535 WebviewShowContextMenuFunction::WebviewShowContextMenuFunction() {
536 }
537 
~WebviewShowContextMenuFunction()538 WebviewShowContextMenuFunction::~WebviewShowContextMenuFunction() {
539 }
540 
RunAsyncSafe(WebViewGuest * guest)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 
WebviewOverrideUserAgentFunction()554 WebviewOverrideUserAgentFunction::WebviewOverrideUserAgentFunction() {
555 }
556 
~WebviewOverrideUserAgentFunction()557 WebviewOverrideUserAgentFunction::~WebviewOverrideUserAgentFunction() {
558 }
559 
RunAsyncSafe(WebViewGuest * guest)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 
WebviewStopFunction()569 WebviewStopFunction::WebviewStopFunction() {
570 }
571 
~WebviewStopFunction()572 WebviewStopFunction::~WebviewStopFunction() {
573 }
574 
RunAsyncSafe(WebViewGuest * guest)575 bool WebviewStopFunction::RunAsyncSafe(WebViewGuest* guest) {
576   guest->Stop();
577   return true;
578 }
579 
WebviewTerminateFunction()580 WebviewTerminateFunction::WebviewTerminateFunction() {
581 }
582 
~WebviewTerminateFunction()583 WebviewTerminateFunction::~WebviewTerminateFunction() {
584 }
585 
RunAsyncSafe(WebViewGuest * guest)586 bool WebviewTerminateFunction::RunAsyncSafe(WebViewGuest* guest) {
587   guest->Terminate();
588   return true;
589 }
590 
591 }  // namespace extensions
592