diff options
author | hanxi@chromium.org <hanxi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-07-09 17:44:35 +0000 |
---|---|---|
committer | hanxi@chromium.org <hanxi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-07-09 17:44:35 +0000 |
commit | 7adb26a7bd8d39a8c15704e4a9d331c1341580ff (patch) | |
tree | 6e7ce8b21bd95ceb54794b04427e386c5c12dd70 /chrome | |
parent | f695672d97c523e003f1dbb659a11fd705c1735d (diff) | |
download | chromium_src-7adb26a7bd8d39a8c15704e4a9d331c1341580ff.zip chromium_src-7adb26a7bd8d39a8c15704e4a9d331c1341580ff.tar.gz chromium_src-7adb26a7bd8d39a8c15704e4a9d331c1341580ff.tar.bz2 |
WebViewGuest is growing fairly large (~ 1600 lines). This CL aims to move all permission related code to a new helper class WebViewPermissionHelper:
- Rename PluginPermissionHelper to WebViewPermissionHelper;
- Move permission request code:
--- Include permissions: Download, PointerLock, Media, Geolocation, FileSystem, Plugin;
--- Not include: New Window API, Dialog API.
Review URL: https://codereview.chromium.org/347113002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@282080 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
16 files changed, 1000 insertions, 834 deletions
diff --git a/chrome/browser/extensions/api/web_view/web_view_internal_api.cc b/chrome/browser/extensions/api/web_view/web_view_internal_api.cc index ac0e542..dcb866d 100644 --- a/chrome/browser/extensions/api/web_view/web_view_internal_api.cc +++ b/chrome/browser/extensions/api/web_view/web_view_internal_api.cc @@ -9,6 +9,7 @@ #include "chrome/browser/extensions/api/context_menus/context_menus_api.h" #include "chrome/browser/extensions/api/context_menus/context_menus_api_helpers.h" #include "chrome/browser/extensions/tab_helper.h" +#include "chrome/browser/guest_view/web_view/web_view_permission_helper.h" #include "chrome/browser/profiles/profile.h" #include "chrome/common/extensions/api/web_view_internal.h" #include "content/public/browser/render_process_host.h" @@ -505,13 +506,14 @@ bool WebViewInternalSetPermissionFunction::RunAsyncSafe(WebViewGuest* guest) { webview::SetPermission::Params::Create(*args_)); EXTENSION_FUNCTION_VALIDATE(params.get()); - WebViewGuest::PermissionResponseAction action = WebViewGuest::DEFAULT; + WebViewPermissionHelper::PermissionResponseAction action = + WebViewPermissionHelper::DEFAULT; switch (params->action) { case Params::ACTION_ALLOW: - action = WebViewGuest::ALLOW; + action = WebViewPermissionHelper::ALLOW; break; case Params::ACTION_DENY: - action = WebViewGuest::DENY; + action = WebViewPermissionHelper::DENY; break; case Params::ACTION_DEFAULT: break; @@ -523,13 +525,18 @@ bool WebViewInternalSetPermissionFunction::RunAsyncSafe(WebViewGuest* guest) { if (params->user_input) user_input = *params->user_input; - WebViewGuest::SetPermissionResult result = - guest->SetPermission(params->request_id, action, user_input); + WebViewPermissionHelper* web_view_permission_helper = + WebViewPermissionHelper:: FromWebContents(guest->guest_web_contents()); - EXTENSION_FUNCTION_VALIDATE(result != WebViewGuest::SET_PERMISSION_INVALID); + WebViewPermissionHelper::SetPermissionResult result = + web_view_permission_helper->SetPermission( + params->request_id, action, user_input); + + EXTENSION_FUNCTION_VALIDATE( + result != WebViewPermissionHelper::SET_PERMISSION_INVALID); SetResult(base::Value::CreateBooleanValue( - result == WebViewGuest::SET_PERMISSION_ALLOWED)); + result == WebViewPermissionHelper::SET_PERMISSION_ALLOWED)); SendResponse(true); return true; } diff --git a/chrome/browser/geolocation/geolocation_permission_context_extensions.cc b/chrome/browser/geolocation/geolocation_permission_context_extensions.cc index 8a99a39..e0496b1 100644 --- a/chrome/browser/geolocation/geolocation_permission_context_extensions.cc +++ b/chrome/browser/geolocation/geolocation_permission_context_extensions.cc @@ -9,7 +9,7 @@ #if defined(ENABLE_EXTENSIONS) #include "chrome/browser/content_settings/permission_request_id.h" #include "chrome/browser/extensions/suggest_permission_util.h" -#include "chrome/browser/guest_view/web_view/web_view_guest.h" +#include "chrome/browser/guest_view/web_view/web_view_permission_helper.h" #include "chrome/browser/profiles/profile.h" #include "extensions/browser/extension_registry.h" #include "extensions/browser/process_map.h" @@ -41,12 +41,11 @@ bool GeolocationPermissionContextExtensions::RequestPermission( #if defined(ENABLE_EXTENSIONS) GURL requesting_frame_origin = requesting_frame.GetOrigin(); - WebViewGuest* guest = WebViewGuest::FromWebContents(web_contents); - if (guest) { - guest->RequestGeolocationPermission(bridge_id, - requesting_frame, - user_gesture, - callback); + WebViewPermissionHelper* web_view_permission_helper = + WebViewPermissionHelper::FromWebContents(web_contents); + if (web_view_permission_helper) { + web_view_permission_helper->RequestGeolocationPermission( + bridge_id, requesting_frame, user_gesture, callback); *permission_set = false; *new_permission = false; return true; @@ -91,10 +90,11 @@ bool GeolocationPermissionContextExtensions::CancelPermissionRequest( content::WebContents* web_contents, int bridge_id) { #if defined(ENABLE_EXTENSIONS) - WebViewGuest* guest = - web_contents ? WebViewGuest::FromWebContents(web_contents) : NULL; - if (guest) { - guest->CancelGeolocationPermissionRequest(bridge_id); + WebViewPermissionHelper* web_view_permission_helper = + web_contents ? WebViewPermissionHelper::FromWebContents(web_contents) + : NULL; + if (web_view_permission_helper) { + web_view_permission_helper->CancelGeolocationPermissionRequest(bridge_id); return true; } #endif // defined(ENABLE_EXTENSIONS) diff --git a/chrome/browser/guest_view/guest_view_base.cc b/chrome/browser/guest_view/guest_view_base.cc index 2b33501..69c4d99 100644 --- a/chrome/browser/guest_view/guest_view_base.cc +++ b/chrome/browser/guest_view/guest_view_base.cc @@ -302,7 +302,7 @@ GuestViewBase::~GuestViewBase() { pending_events_.clear(); } -void GuestViewBase::DispatchEvent(Event* event) { +void GuestViewBase::DispatchEventToEmbedder(Event* event) { scoped_ptr<Event> event_ptr(event); if (!in_extension()) { NOTREACHED(); @@ -337,7 +337,7 @@ void GuestViewBase::SendQueuedEvents() { while (!pending_events_.empty()) { linked_ptr<Event> event_ptr = pending_events_.front(); pending_events_.pop_front(); - DispatchEvent(event_ptr.release()); + DispatchEventToEmbedder(event_ptr.release()); } } diff --git a/chrome/browser/guest_view/guest_view_base.h b/chrome/browser/guest_view/guest_view_base.h index a8b8aa4..e85b952 100644 --- a/chrome/browser/guest_view/guest_view_base.h +++ b/chrome/browser/guest_view/guest_view_base.h @@ -204,15 +204,15 @@ class GuestViewBase : public content::BrowserPluginGuestDelegate, content::WebContents* embedder_web_contents, const base::DictionaryValue& extra_params) OVERRIDE FINAL; + // Dispatches an event |event_name| to the embedder with the |event| fields. + void DispatchEventToEmbedder(Event* event); + protected: GuestViewBase(content::BrowserContext* browser_context, int guest_instance_id); virtual ~GuestViewBase(); - // Dispatches an event |event_name| to the embedder with the |event| fields. - void DispatchEvent(Event* event); - private: class EmbedderWebContentsObserver; diff --git a/chrome/browser/guest_view/web_view/javascript_dialog_helper.cc b/chrome/browser/guest_view/web_view/javascript_dialog_helper.cc index a522195..c2fe9a4 100644 --- a/chrome/browser/guest_view/web_view/javascript_dialog_helper.cc +++ b/chrome/browser/guest_view/web_view/javascript_dialog_helper.cc @@ -9,6 +9,7 @@ #include "chrome/browser/guest_view/guest_view_constants.h" #include "chrome/browser/guest_view/web_view/web_view_constants.h" #include "chrome/browser/guest_view/web_view/web_view_guest.h" +#include "chrome/browser/guest_view/web_view/web_view_permission_helper.h" #include "chrome/browser/guest_view/web_view/web_view_permission_types.h" namespace { @@ -31,7 +32,7 @@ std::string JavaScriptMessageTypeToString( } // namespace JavaScriptDialogHelper::JavaScriptDialogHelper(WebViewGuest* guest) - : webview_guest_(guest) { + : web_view_guest_(guest) { } JavaScriptDialogHelper::~JavaScriptDialogHelper() { @@ -56,7 +57,9 @@ void JavaScriptDialogHelper::RunJavaScriptDialog( new base::StringValue( JavaScriptMessageTypeToString(javascript_message_type))); request_info.Set(guestview::kUrl, new base::StringValue(origin_url.spec())); - webview_guest_->RequestPermission( + WebViewPermissionHelper* web_view_permission_helper = + WebViewPermissionHelper::FromWebContents(web_contents); + web_view_permission_helper->RequestPermission( WEB_VIEW_PERMISSION_TYPE_JAVASCRIPT_DIALOG, request_info, base::Bind(&JavaScriptDialogHelper::OnPermissionResponse, @@ -94,6 +97,6 @@ void JavaScriptDialogHelper::OnPermissionResponse( const DialogClosedCallback& callback, bool allow, const std::string& user_input) { - callback.Run(allow && webview_guest_->attached(), + callback.Run(allow && web_view_guest_->attached(), base::UTF8ToUTF16(user_input)); } diff --git a/chrome/browser/guest_view/web_view/javascript_dialog_helper.h b/chrome/browser/guest_view/web_view/javascript_dialog_helper.h index 94f7374..7f37002 100644 --- a/chrome/browser/guest_view/web_view/javascript_dialog_helper.h +++ b/chrome/browser/guest_view/web_view/javascript_dialog_helper.h @@ -45,7 +45,7 @@ class JavaScriptDialogHelper : public content::JavaScriptDialogManager { const std::string& user_input); // Pointer to the webview that is being helped. - WebViewGuest* const webview_guest_; + WebViewGuest* const web_view_guest_; DISALLOW_COPY_AND_ASSIGN(JavaScriptDialogHelper); }; diff --git a/chrome/browser/guest_view/web_view/plugin_permission_helper.cc b/chrome/browser/guest_view/web_view/plugin_permission_helper.cc deleted file mode 100644 index b86b2d2..0000000 --- a/chrome/browser/guest_view/web_view/plugin_permission_helper.cc +++ /dev/null @@ -1,121 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/guest_view/web_view/plugin_permission_helper.h" - -#include "chrome/browser/guest_view/web_view/web_view_guest.h" -#include "chrome/browser/guest_view/web_view/web_view_permission_types.h" -#include "chrome/browser/plugins/chrome_plugin_service_filter.h" -#include "chrome/common/render_messages.h" -#include "content/public/browser/render_process_host.h" -#include "content/public/browser/render_view_host.h" -#include "content/public/browser/user_metrics.h" - -using content::BrowserPluginGuestDelegate; -using content::RenderViewHost; -using content::WebContents; - -DEFINE_WEB_CONTENTS_USER_DATA_KEY(PluginPermissionHelper); - -PluginPermissionHelper::PluginPermissionHelper(WebContents* contents) - : content::WebContentsObserver(contents), - weak_factory_(this) { -} - -PluginPermissionHelper::~PluginPermissionHelper() { -} - -bool PluginPermissionHelper::OnMessageReceived( - const IPC::Message& message, - content::RenderFrameHost* render_frame_host) { - IPC_BEGIN_MESSAGE_MAP(PluginPermissionHelper, message) - IPC_MESSAGE_HANDLER(ChromeViewHostMsg_BlockedOutdatedPlugin, - OnBlockedOutdatedPlugin) - IPC_MESSAGE_HANDLER(ChromeViewHostMsg_BlockedUnauthorizedPlugin, - OnBlockedUnauthorizedPlugin) - IPC_MESSAGE_HANDLER(ChromeViewHostMsg_NPAPINotSupported, - OnNPAPINotSupported) -#if defined(ENABLE_PLUGIN_INSTALLATION) - IPC_MESSAGE_HANDLER(ChromeViewHostMsg_FindMissingPlugin, - OnFindMissingPlugin) -#endif - IPC_MESSAGE_UNHANDLED(return false) - IPC_END_MESSAGE_MAP() - - return true; -} - -bool PluginPermissionHelper::OnMessageReceived(const IPC::Message& message) { - IPC_BEGIN_MESSAGE_MAP(PluginPermissionHelper, message) - IPC_MESSAGE_HANDLER(ChromeViewHostMsg_CouldNotLoadPlugin, - OnCouldNotLoadPlugin) - IPC_MESSAGE_HANDLER(ChromeViewHostMsg_OpenAboutPlugins, - OnOpenAboutPlugins) -#if defined(ENABLE_PLUGIN_INSTALLATION) - IPC_MESSAGE_HANDLER(ChromeViewHostMsg_RemovePluginPlaceholderHost, - OnRemovePluginPlaceholderHost) -#endif - IPC_MESSAGE_UNHANDLED(return false) - IPC_END_MESSAGE_MAP() - - return true; -} - -void PluginPermissionHelper::OnBlockedUnauthorizedPlugin( - const base::string16& name, - const std::string& identifier) { - const char kPluginName[] = "name"; - const char kPluginIdentifier[] = "identifier"; - - WebViewGuest* webview = WebViewGuest::FromWebContents(web_contents()); - if (!webview) - return; - - base::DictionaryValue info; - info.SetString(std::string(kPluginName), name); - info.SetString(std::string(kPluginIdentifier), identifier); - webview->RequestPermission( - WEB_VIEW_PERMISSION_TYPE_LOAD_PLUGIN, - info, - base::Bind(&PluginPermissionHelper::OnPermissionResponse, - weak_factory_.GetWeakPtr(), - identifier), - true /* allowed_by_default */); - content::RecordAction( - base::UserMetricsAction("WebView.Guest.PluginLoadRequest")); -} - -void PluginPermissionHelper::OnCouldNotLoadPlugin( - const base::FilePath& plugin_path) { -} - -void PluginPermissionHelper::OnBlockedOutdatedPlugin( - int placeholder_id, - const std::string& identifier) { -} - -void PluginPermissionHelper::OnNPAPINotSupported(const std::string& id) { -} - -void PluginPermissionHelper::OnOpenAboutPlugins() { -} - -#if defined(ENABLE_PLUGIN_INSTALLATION) -void PluginPermissionHelper::OnFindMissingPlugin(int placeholder_id, - const std::string& mime_type) { - Send(new ChromeViewMsg_DidNotFindMissingPlugin(placeholder_id)); -} - -void PluginPermissionHelper::OnRemovePluginPlaceholderHost(int placeholder_id) { -} -#endif // defined(ENABLE_PLUGIN_INSTALLATION) - -void PluginPermissionHelper::OnPermissionResponse(const std::string& identifier, - bool allow, - const std::string& input) { - if (allow) { - ChromePluginServiceFilter::GetInstance()->AuthorizeAllPlugins( - web_contents(), true, identifier); - } -} diff --git a/chrome/browser/guest_view/web_view/plugin_permission_helper.h b/chrome/browser/guest_view/web_view/plugin_permission_helper.h deleted file mode 100644 index 93ecabd..0000000 --- a/chrome/browser/guest_view/web_view/plugin_permission_helper.h +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_GUEST_VIEW_WEB_VIEW_PLUGIN_PERMISSION_HELPER_H_ -#define CHROME_BROWSER_GUEST_VIEW_WEB_VIEW_PLUGIN_PERMISSION_HELPER_H_ - -#include "base/memory/weak_ptr.h" -#include "content/public/browser/web_contents_observer.h" -#include "content/public/browser/web_contents_user_data.h" - -class PluginPermissionHelper - : public content::WebContentsUserData<PluginPermissionHelper>, - public content::WebContentsObserver { - public: - virtual ~PluginPermissionHelper(); - - private: - explicit PluginPermissionHelper(content::WebContents* web_contents); - friend class content::WebContentsUserData<PluginPermissionHelper>; - - // content::WebContentsObserver implementation. - virtual bool OnMessageReceived( - const IPC::Message& message, - content::RenderFrameHost* render_frame_host) OVERRIDE; - virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; - - // Message handlers: - void OnBlockedUnauthorizedPlugin(const base::string16& name, - const std::string& identifier); - void OnCouldNotLoadPlugin(const base::FilePath& plugin_path); - void OnBlockedOutdatedPlugin(int placeholder_id, - const std::string& identifier); - void OnNPAPINotSupported(const std::string& identifier); - void OnOpenAboutPlugins(); -#if defined(ENABLE_PLUGIN_INSTALLATION) - void OnFindMissingPlugin(int placeholder_id, const std::string& mime_type); - - void OnRemovePluginPlaceholderHost(int placeholder_id); -#endif - - void OnPermissionResponse(const std::string& identifier, - bool allow, - const std::string& user_input); - - base::WeakPtrFactory<PluginPermissionHelper> weak_factory_; - - DISALLOW_COPY_AND_ASSIGN(PluginPermissionHelper); -}; - -#endif // CHROME_BROWSER_GUEST_VIEW_WEB_VIEW_PLUGIN_PERMISSION_HELPER_H_ diff --git a/chrome/browser/guest_view/web_view/web_view_find_helper.cc b/chrome/browser/guest_view/web_view/web_view_find_helper.cc index 27b960b..229565b4 100644 --- a/chrome/browser/guest_view/web_view/web_view_find_helper.cc +++ b/chrome/browser/guest_view/web_view/web_view_find_helper.cc @@ -35,7 +35,7 @@ void WebViewFindHelper::DispatchFindUpdateEvent(bool canceled, args->SetBoolean(webview::kFindCanceled, canceled); args->SetBoolean(webview::kFindFinalUpdate, final_update); DCHECK(webview_guest_); - webview_guest_->DispatchEvent( + webview_guest_->DispatchEventToEmbedder( new GuestViewBase::Event(webview::kEventFindReply, args.Pass())); } diff --git a/chrome/browser/guest_view/web_view/web_view_guest.cc b/chrome/browser/guest_view/web_view/web_view_guest.cc index 6b21413..946194d 100644 --- a/chrome/browser/guest_view/web_view/web_view_guest.cc +++ b/chrome/browser/guest_view/web_view/web_view_guest.cc @@ -8,18 +8,16 @@ #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" #include "chrome/browser/chrome_notification_types.h" -#include "chrome/browser/content_settings/tab_specific_content_settings.h" #include "chrome/browser/extensions/api/web_request/web_request_api.h" #include "chrome/browser/extensions/api/web_view/web_view_internal_api.h" #include "chrome/browser/extensions/chrome_extension_web_contents_observer.h" #include "chrome/browser/extensions/menu_manager.h" #include "chrome/browser/extensions/script_executor.h" #include "chrome/browser/favicon/favicon_tab_helper.h" -#include "chrome/browser/geolocation/geolocation_permission_context.h" -#include "chrome/browser/geolocation/geolocation_permission_context_factory.h" #include "chrome/browser/guest_view/guest_view_constants.h" #include "chrome/browser/guest_view/guest_view_manager.h" #include "chrome/browser/guest_view/web_view/web_view_constants.h" +#include "chrome/browser/guest_view/web_view/web_view_permission_helper.h" #include "chrome/browser/guest_view/web_view/web_view_permission_types.h" #include "chrome/browser/guest_view/web_view/web_view_renderer_state.h" #include "chrome/browser/renderer_context_menu/context_menu_delegate.h" @@ -65,10 +63,6 @@ #endif // defined(ENABLE_FULL_PRINTING) #endif // defined(ENABLE_PRINTING) -#if defined(ENABLE_PLUGINS) && !defined(OS_ANDROID) -#include "chrome/browser/guest_view/web_view/plugin_permission_helper.h" -#endif - #if defined(OS_CHROMEOS) #include "chrome/browser/chromeos/accessibility/accessibility_manager.h" #endif @@ -121,30 +115,6 @@ static std::string TerminationStatusToString(base::TerminationStatus status) { return "unknown"; } -static std::string PermissionTypeToString(WebViewPermissionType type) { - switch (type) { - case WEB_VIEW_PERMISSION_TYPE_DOWNLOAD: - return webview::kPermissionTypeDownload; - case WEB_VIEW_PERMISSION_TYPE_FILESYSTEM: - return webview::kPermissionTypeFileSystem; - case WEB_VIEW_PERMISSION_TYPE_GEOLOCATION: - return webview::kPermissionTypeGeolocation; - case WEB_VIEW_PERMISSION_TYPE_JAVASCRIPT_DIALOG: - return webview::kPermissionTypeDialog; - case WEB_VIEW_PERMISSION_TYPE_LOAD_PLUGIN: - return webview::kPermissionTypeLoadPlugin; - case WEB_VIEW_PERMISSION_TYPE_MEDIA: - return webview::kPermissionTypeMedia; - case WEB_VIEW_PERMISSION_TYPE_NEW_WINDOW: - return webview::kPermissionTypeNewWindow; - case WEB_VIEW_PERMISSION_TYPE_POINTER_LOCK: - return webview::kPermissionTypePointerLock; - default: - NOTREACHED(); - return std::string(); - } -} - std::string GetStoragePartitionIdFromSiteURL(const GURL& site_url) { const std::string& partition_id = site_url.query(); bool persist_storage = site_url.path().find("persist") != std::string::npos; @@ -164,32 +134,6 @@ void RemoveWebViewEventListenersOnIOThread( view_instance_id); } -void AttachWebViewHelpers(WebContents* contents) { - // Create a zoom controller for the guest contents give it access to - // GetZoomLevel() and and SetZoomLevel() in WebViewGuest. - // TODO(wjmaclean) This currently uses the same HostZoomMap as the browser - // context, but we eventually want to isolate the guest contents from zoom - // changes outside the guest (e.g. in the main browser), so we should - // create a separate HostZoomMap for the guest. - ZoomController::CreateForWebContents(contents); - - FaviconTabHelper::CreateForWebContents(contents); - extensions::ChromeExtensionWebContentsObserver::CreateForWebContents( - contents); -#if defined(ENABLE_PLUGINS) && !defined(OS_ANDROID) - PluginPermissionHelper::CreateForWebContents(contents); -#endif -#if defined(ENABLE_PRINTING) -#if defined(ENABLE_FULL_PRINTING) - printing::PrintViewManager::CreateForWebContents(contents); - printing::PrintPreviewMessageHandler::CreateForWebContents(contents); -#else - printing::PrintViewManagerBasic::CreateForWebContents(contents); -#endif // defined(ENABLE_FULL_PRINTING) -#endif // defined(ENABLE_PRINTING) - PDFTabHelper::CreateForWebContents(contents); -} - void ParsePartitionParam(const base::DictionaryValue& create_params, std::string* storage_partition_id, bool* persist_storage) { @@ -225,7 +169,6 @@ WebViewGuest::WebViewGuest(content::BrowserContext* browser_context, int guest_instance_id) : GuestView<WebViewGuest>(browser_context, guest_instance_id), pending_context_menu_request_id_(0), - next_permission_request_id_(0), is_overriding_user_agent_(false), chromevox_injected_(false), current_zoom_factor_(1.0), @@ -269,89 +212,6 @@ int WebViewGuest::GetViewInstanceId(WebContents* contents) { } // static -void WebViewGuest::RecordUserInitiatedUMA(const PermissionResponseInfo& info, - bool allow) { - if (allow) { - // Note that |allow| == true means the embedder explicitly allowed the - // request. For some requests they might still fail. An example of such - // scenario would be: an embedder allows geolocation request but doesn't - // have geolocation access on its own. - switch (info.permission_type) { - case WEB_VIEW_PERMISSION_TYPE_DOWNLOAD: - content::RecordAction( - UserMetricsAction("WebView.PermissionAllow.Download")); - break; - case WEB_VIEW_PERMISSION_TYPE_FILESYSTEM: - content::RecordAction( - UserMetricsAction("WebView.PermissionAllow.FileSystem")); - break; - case WEB_VIEW_PERMISSION_TYPE_GEOLOCATION: - content::RecordAction( - UserMetricsAction("WebView.PermissionAllow.Geolocation")); - break; - case WEB_VIEW_PERMISSION_TYPE_JAVASCRIPT_DIALOG: - content::RecordAction( - UserMetricsAction("WebView.PermissionAllow.JSDialog")); - break; - case WEB_VIEW_PERMISSION_TYPE_LOAD_PLUGIN: - content::RecordAction( - UserMetricsAction("WebView.Guest.PermissionAllow.PluginLoad")); - case WEB_VIEW_PERMISSION_TYPE_MEDIA: - content::RecordAction( - UserMetricsAction("WebView.PermissionAllow.Media")); - break; - case WEB_VIEW_PERMISSION_TYPE_NEW_WINDOW: - content::RecordAction( - UserMetricsAction("BrowserPlugin.PermissionAllow.NewWindow")); - break; - case WEB_VIEW_PERMISSION_TYPE_POINTER_LOCK: - content::RecordAction( - UserMetricsAction("WebView.PermissionAllow.PointerLock")); - break; - default: - break; - } - } else { - switch (info.permission_type) { - case WEB_VIEW_PERMISSION_TYPE_DOWNLOAD: - content::RecordAction( - UserMetricsAction("WebView.PermissionDeny.Download")); - break; - case WEB_VIEW_PERMISSION_TYPE_FILESYSTEM: - content::RecordAction( - UserMetricsAction("WebView.PermissionDeny.FileSystem")); - break; - case WEB_VIEW_PERMISSION_TYPE_GEOLOCATION: - content::RecordAction( - UserMetricsAction("WebView.PermissionDeny.Geolocation")); - break; - case WEB_VIEW_PERMISSION_TYPE_JAVASCRIPT_DIALOG: - content::RecordAction( - UserMetricsAction("WebView.PermissionDeny.JSDialog")); - break; - case WEB_VIEW_PERMISSION_TYPE_LOAD_PLUGIN: - content::RecordAction( - UserMetricsAction("WebView.Guest.PermissionDeny.PluginLoad")); - break; - case WEB_VIEW_PERMISSION_TYPE_MEDIA: - content::RecordAction( - UserMetricsAction("WebView.PermissionDeny.Media")); - break; - case WEB_VIEW_PERMISSION_TYPE_NEW_WINDOW: - content::RecordAction( - UserMetricsAction("BrowserPlugin.PermissionDeny.NewWindow")); - break; - case WEB_VIEW_PERMISSION_TYPE_POINTER_LOCK: - content::RecordAction( - UserMetricsAction("WebView.PermissionDeny.PointerLock")); - break; - default: - break; - } - } -} - -// static scoped_ptr<base::ListValue> WebViewGuest::MenuModelToValue( const ui::SimpleMenuModel& menu_model) { scoped_ptr<base::ListValue> items(new base::ListValue()); @@ -492,10 +352,34 @@ void WebViewGuest::DidInitialize() { AttachWebViewHelpers(guest_web_contents()); } +void WebViewGuest::AttachWebViewHelpers(WebContents* contents) { + // Create a zoom controller for the guest contents give it access to + // GetZoomLevel() and and SetZoomLevel() in WebViewGuest. + // TODO(wjmaclean) This currently uses the same HostZoomMap as the browser + // context, but we eventually want to isolate the guest contents from zoom + // changes outside the guest (e.g. in the main browser), so we should + // create a separate HostZoomMap for the guest. + ZoomController::CreateForWebContents(contents); + + FaviconTabHelper::CreateForWebContents(contents); + extensions::ChromeExtensionWebContentsObserver::CreateForWebContents( + contents); +#if defined(ENABLE_PRINTING) +#if defined(ENABLE_FULL_PRINTING) + printing::PrintViewManager::CreateForWebContents(contents); + printing::PrintPreviewMessageHandler::CreateForWebContents(contents); +#else + printing::PrintViewManagerBasic::CreateForWebContents(contents); +#endif // defined(ENABLE_FULL_PRINTING) +#endif // defined(ENABLE_PRINTING) + PDFTabHelper::CreateForWebContents(contents); + web_view_permission_helper_.reset(new WebViewPermissionHelper(this)); +} void WebViewGuest::DidStopLoading() { scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue()); - DispatchEvent(new GuestViewBase::Event(webview::kEventLoadStop, args.Pass())); + DispatchEventToEmbedder( + new GuestViewBase::Event(webview::kEventLoadStop, args.Pass())); } void WebViewGuest::EmbedderDestroyed() { @@ -547,14 +431,15 @@ bool WebViewGuest::AddMessageToConsole(WebContents* source, args->SetString(webview::kMessage, message); args->SetInteger(webview::kLine, line_no); args->SetString(webview::kSourceId, source_id); - DispatchEvent( + DispatchEventToEmbedder( new GuestViewBase::Event(webview::kEventConsoleMessage, args.Pass())); return true; } void WebViewGuest::CloseContents(WebContents* source) { scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue()); - DispatchEvent(new GuestViewBase::Event(webview::kEventClose, args.Pass())); + DispatchEventToEmbedder( + new GuestViewBase::Event(webview::kEventClose, args.Pass())); } void WebViewGuest::FindReply(WebContents* source, @@ -582,8 +467,8 @@ bool WebViewGuest::HandleContextMenu( MenuModelToValue(pending_menu_->menu_model()); args->Set(webview::kContextMenuItems, items.release()); args->SetInteger(webview::kRequestId, request_id); - DispatchEvent(new GuestViewBase::Event(webview::kEventContextMenu, - args.Pass())); + DispatchEventToEmbedder( + new GuestViewBase::Event(webview::kEventContextMenu, args.Pass())); return true; } @@ -611,7 +496,7 @@ void WebViewGuest::LoadProgressChanged(content::WebContents* source, scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue()); args->SetString(guestview::kUrl, guest_web_contents()->GetURL().spec()); args->SetDouble(webview::kProgress, progress); - DispatchEvent( + DispatchEventToEmbedder( new GuestViewBase::Event(webview::kEventLoadProgress, args.Pass())); } @@ -622,7 +507,7 @@ void WebViewGuest::LoadAbort(bool is_top_level, args->SetBoolean(guestview::kIsTopLevel, is_top_level); args->SetString(guestview::kUrl, url.possibly_invalid_spec()); args->SetString(guestview::kReason, error_type); - DispatchEvent( + DispatchEventToEmbedder( new GuestViewBase::Event(webview::kEventLoadAbort, args.Pass())); } @@ -681,7 +566,7 @@ void WebViewGuest::RendererResponsive(content::WebContents* source) { scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue()); args->SetInteger(webview::kProcessId, guest_web_contents()->GetRenderProcessHost()->GetID()); - DispatchEvent( + DispatchEventToEmbedder( new GuestViewBase::Event(webview::kEventResponsive, args.Pass())); } @@ -689,7 +574,7 @@ void WebViewGuest::RendererUnresponsive(content::WebContents* source) { scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue()); args->SetInteger(webview::kProcessId, guest_web_contents()->GetRenderProcessHost()->GetID()); - DispatchEvent( + DispatchEventToEmbedder( new GuestViewBase::Event(webview::kEventUnresponsive, args.Pass())); } @@ -749,154 +634,6 @@ void WebViewGuest::Reload() { guest_web_contents()->GetController().Reload(false); } -void WebViewGuest::RequestFileSystemPermission( - const GURL& url, - bool allowed_by_default, - const base::Callback<void(bool)>& callback) { - base::DictionaryValue request_info; - request_info.Set(guestview::kUrl, new base::StringValue(url.spec())); - RequestPermission( - WEB_VIEW_PERMISSION_TYPE_FILESYSTEM, - request_info, - base::Bind(&WebViewGuest::OnWebViewFileSystemPermissionResponse, - base::Unretained(this), - callback), - allowed_by_default); -} - -void WebViewGuest::OnWebViewFileSystemPermissionResponse( - const base::Callback<void(bool)>& callback, - bool allow, - const std::string& user_input) { - callback.Run(allow && attached()); -} - -void WebViewGuest::RequestGeolocationPermission( - int bridge_id, - const GURL& requesting_frame, - bool user_gesture, - const base::Callback<void(bool)>& callback) { - base::DictionaryValue request_info; - request_info.Set(guestview::kUrl, - new base::StringValue(requesting_frame.spec())); - request_info.Set(guestview::kUserGesture, - base::Value::CreateBooleanValue(user_gesture)); - - // It is safe to hold an unretained pointer to WebViewGuest because this - // callback is called from WebViewGuest::SetPermission. - const PermissionResponseCallback permission_callback = - base::Bind(&WebViewGuest::OnWebViewGeolocationPermissionResponse, - base::Unretained(this), - bridge_id, - user_gesture, - callback); - int request_id = RequestPermission( - WEB_VIEW_PERMISSION_TYPE_GEOLOCATION, - request_info, - permission_callback, - false /* allowed_by_default */); - bridge_id_to_request_id_map_[bridge_id] = request_id; -} - -void WebViewGuest::OnWebViewGeolocationPermissionResponse( - int bridge_id, - bool user_gesture, - const base::Callback<void(bool)>& callback, - bool allow, - const std::string& user_input) { - // The <webview> embedder has allowed the permission. We now need to make sure - // that the embedder has geolocation permission. - RemoveBridgeID(bridge_id); - - if (!allow || !attached()) { - callback.Run(false); - return; - } - - Profile* profile = Profile::FromBrowserContext(browser_context()); - GeolocationPermissionContextFactory::GetForProfile(profile)-> - RequestGeolocationPermission( - embedder_web_contents(), - // The geolocation permission request here is not initiated - // through WebGeolocationPermissionRequest. We are only interested - // in the fact whether the embedder/app has geolocation - // permission. Therefore we use an invalid |bridge_id|. - -1, - embedder_web_contents()->GetLastCommittedURL(), - user_gesture, - callback, - NULL); -} - -void WebViewGuest::CancelGeolocationPermissionRequest(int bridge_id) { - int request_id = RemoveBridgeID(bridge_id); - RequestMap::iterator request_itr = - pending_permission_requests_.find(request_id); - - if (request_itr == pending_permission_requests_.end()) - return; - - pending_permission_requests_.erase(request_itr); -} - -void WebViewGuest::OnWebViewMediaPermissionResponse( - const content::MediaStreamRequest& request, - const content::MediaResponseCallback& callback, - bool allow, - const std::string& user_input) { - if (!allow || !attached()) { - // Deny the request. - callback.Run(content::MediaStreamDevices(), - content::MEDIA_DEVICE_INVALID_STATE, - scoped_ptr<content::MediaStreamUI>()); - return; - } - if (!embedder_web_contents()->GetDelegate()) - return; - - embedder_web_contents()->GetDelegate()-> - RequestMediaAccessPermission(embedder_web_contents(), request, callback); -} - -void WebViewGuest::OnWebViewDownloadPermissionResponse( - const base::Callback<void(bool)>& callback, - bool allow, - const std::string& user_input) { - callback.Run(allow && attached()); -} - -void WebViewGuest::OnWebViewPointerLockPermissionResponse( - const base::Callback<void(bool)>& callback, - bool allow, - const std::string& user_input) { - callback.Run(allow && attached()); -} - -WebViewGuest::SetPermissionResult WebViewGuest::SetPermission( - int request_id, - PermissionResponseAction action, - const std::string& user_input) { - RequestMap::iterator request_itr = - pending_permission_requests_.find(request_id); - - if (request_itr == pending_permission_requests_.end()) - return SET_PERMISSION_INVALID; - - const PermissionResponseInfo& info = request_itr->second; - bool allow = (action == ALLOW) || - ((action == DEFAULT) && info.allowed_by_default); - - info.callback.Run(allow, user_input); - - // Only record user initiated (i.e. non-default) actions. - if (action != DEFAULT) - RecordUserInitiatedUMA(info, allow); - - pending_permission_requests_.erase(request_itr); - - return allow ? SET_PERMISSION_ALLOWED : SET_PERMISSION_DENIED; -} - void WebViewGuest::SetUserAgentOverride( const std::string& user_agent_override) { if (!attached()) @@ -943,78 +680,6 @@ bool WebViewGuest::ClearData(const base::Time remove_since, return true; } -// static -void WebViewGuest::FileSystemAccessedAsync(int render_process_id, - int render_frame_id, - int request_id, - const GURL& url, - bool blocked_by_policy) { - WebViewGuest* guest = - WebViewGuest::FromFrameID(render_process_id, render_frame_id); - DCHECK(guest); - guest->RequestFileSystemPermission( - url, - !blocked_by_policy, - base::Bind(&WebViewGuest::FileSystemAccessedAsyncResponse, - render_process_id, - render_frame_id, - request_id, - url)); -} - -// static -void WebViewGuest::FileSystemAccessedAsyncResponse(int render_process_id, - int render_frame_id, - int request_id, - const GURL& url, - bool allowed) { - TabSpecificContentSettings::FileSystemAccessed( - render_process_id, render_frame_id, url, !allowed); - content::RenderFrameHost* render_frame_host = - content::RenderFrameHost::FromID(render_process_id, render_frame_id); - if (!render_frame_host) - return; - render_frame_host->Send( - new ChromeViewMsg_RequestFileSystemAccessAsyncResponse( - render_frame_id, request_id, allowed)); -} - -// static -void WebViewGuest::FileSystemAccessedSync(int render_process_id, - int render_frame_id, - const GURL& url, - bool blocked_by_policy, - IPC::Message* reply_msg) { - WebViewGuest* guest = - WebViewGuest::FromFrameID(render_process_id, render_frame_id); - DCHECK(guest); - guest->RequestFileSystemPermission( - url, - !blocked_by_policy, - base::Bind(&WebViewGuest::FileSystemAccessedSyncResponse, - render_process_id, - render_frame_id, - url, - reply_msg)); -} - -// static -void WebViewGuest::FileSystemAccessedSyncResponse(int render_process_id, - int render_frame_id, - const GURL& url, - IPC::Message* reply_msg, - bool allowed) { - TabSpecificContentSettings::FileSystemAccessed( - render_process_id, render_frame_id, url, !allowed); - ChromeViewHostMsg_RequestFileSystemAccessSync::WriteReplyParams(reply_msg, - allowed); - content::RenderFrameHost* render_frame_host = - content::RenderFrameHost::FromID(render_process_id, render_frame_id); - if (!render_frame_id) - return; - render_frame_host->Send(reply_msg); -} - WebViewGuest::~WebViewGuest() { } @@ -1033,7 +698,7 @@ void WebViewGuest::DidCommitProvisionalLoadForFrame( guest_web_contents()->GetController().GetEntryCount()); args->SetInteger(webview::kInternalProcessId, guest_web_contents()->GetRenderProcessHost()->GetID()); - DispatchEvent( + DispatchEventToEmbedder( new GuestViewBase::Event(webview::kEventLoadCommit, args.Pass())); // Update the current zoom factor for the new page. @@ -1066,7 +731,7 @@ void WebViewGuest::DidStartProvisionalLoadForFrame( scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue()); args->SetString(guestview::kUrl, validated_url.spec()); args->SetBoolean(guestview::kIsTopLevel, !render_frame_host->GetParent()); - DispatchEvent( + DispatchEventToEmbedder( new GuestViewBase::Event(webview::kEventLoadStart, args.Pass())); } @@ -1094,7 +759,8 @@ void WebViewGuest::RenderProcessGone(base::TerminationStatus status) { args->SetInteger(webview::kProcessId, guest_web_contents()->GetRenderProcessHost()->GetID()); args->SetString(webview::kReason, TerminationStatusToString(status)); - DispatchEvent(new GuestViewBase::Event(webview::kEventExit, args.Pass())); + DispatchEventToEmbedder( + new GuestViewBase::Event(webview::kEventExit, args.Pass())); } void WebViewGuest::UserAgentOverrideSet(const std::string& user_agent) { @@ -1119,13 +785,13 @@ void WebViewGuest::ReportFrameNameChange(const std::string& name) { name_ = name; scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue()); args->SetString(webview::kName, name); - DispatchEvent( + DispatchEventToEmbedder( new GuestViewBase::Event(webview::kEventFrameNameChanged, args.Pass())); } void WebViewGuest::LoadHandlerCalled() { scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue()); - DispatchEvent( + DispatchEventToEmbedder( new GuestViewBase::Event(webview::kEventContentLoad, args.Pass())); } @@ -1136,7 +802,7 @@ void WebViewGuest::LoadRedirect(const GURL& old_url, args->SetBoolean(guestview::kIsTopLevel, is_top_level); args->SetString(webview::kNewURL, new_url.spec()); args->SetString(webview::kOldURL, old_url.spec()); - DispatchEvent( + DispatchEventToEmbedder( new GuestViewBase::Event(webview::kEventLoadRedirect, args.Pass())); } @@ -1198,7 +864,7 @@ void WebViewGuest::SizeChanged(const gfx::Size& old_size, args->SetInteger(webview::kOldWidth, old_size.width()); args->SetInteger(webview::kNewHeight, new_size.height()); args->SetInteger(webview::kNewWidth, new_size.width()); - DispatchEvent( + DispatchEventToEmbedder( new GuestViewBase::Event(webview::kEventSizeChanged, args.Pass())); } @@ -1206,16 +872,9 @@ void WebViewGuest::RequestMediaAccessPermission( content::WebContents* source, const content::MediaStreamRequest& request, const content::MediaResponseCallback& callback) { - base::DictionaryValue request_info; - request_info.Set(guestview::kUrl, - new base::StringValue(request.security_origin.spec())); - RequestPermission(WEB_VIEW_PERMISSION_TYPE_MEDIA, - request_info, - base::Bind(&WebViewGuest::OnWebViewMediaPermissionResponse, - base::Unretained(this), - request, - callback), - false /* allowed_by_default */); + web_view_permission_helper_->RequestMediaAccessPermission(source, + request, + callback); } void WebViewGuest::CanDownload( @@ -1223,37 +882,20 @@ void WebViewGuest::CanDownload( const GURL& url, const std::string& request_method, const base::Callback<void(bool)>& callback) { - base::DictionaryValue request_info; - request_info.Set(guestview::kUrl, new base::StringValue(url.spec())); - RequestPermission( - WEB_VIEW_PERMISSION_TYPE_DOWNLOAD, - request_info, - base::Bind(&WebViewGuest::OnWebViewDownloadPermissionResponse, - base::Unretained(this), - callback), - false /* allowed_by_default */); + web_view_permission_helper_->CanDownload(render_view_host, + url, + request_method, + callback); } void WebViewGuest::RequestPointerLockPermission( bool user_gesture, bool last_unlocked_by_target, const base::Callback<void(bool)>& callback) { - base::DictionaryValue request_info; - request_info.Set(guestview::kUserGesture, - base::Value::CreateBooleanValue(user_gesture)); - request_info.Set(webview::kLastUnlockedBySelf, - base::Value::CreateBooleanValue(last_unlocked_by_target)); - request_info.Set(guestview::kUrl, - new base::StringValue( - guest_web_contents()->GetLastCommittedURL().spec())); - - RequestPermission( - WEB_VIEW_PERMISSION_TYPE_POINTER_LOCK, - request_info, - base::Bind(&WebViewGuest::OnWebViewPointerLockPermissionResponse, - base::Unretained(this), - callback), - false /* allowed_by_default */); + web_view_permission_helper_->RequestPointerLockPermission( + user_gesture, + last_unlocked_by_target, + callback); } void WebViewGuest::WillAttachToEmbedder() { @@ -1347,65 +989,6 @@ void WebViewGuest::InjectChromeVoxIfNeeded( #endif } -int WebViewGuest::RemoveBridgeID(int bridge_id) { - std::map<int, int>::iterator bridge_itr = - bridge_id_to_request_id_map_.find(bridge_id); - if (bridge_itr == bridge_id_to_request_id_map_.end()) - return webview::kInvalidPermissionRequestID; - - int request_id = bridge_itr->second; - bridge_id_to_request_id_map_.erase(bridge_itr); - return request_id; -} - -int WebViewGuest::RequestPermission( - WebViewPermissionType permission_type, - const base::DictionaryValue& request_info, - const PermissionResponseCallback& callback, - bool allowed_by_default) { - // If there are too many pending permission requests then reject this request. - if (pending_permission_requests_.size() >= - webview::kMaxOutstandingPermissionRequests) { - // Let the stack unwind before we deny the permission request so that - // objects held by the permission request are not destroyed immediately - // after creation. This is to allow those same objects to be accessed again - // in the same scope without fear of use after freeing. - base::MessageLoop::current()->PostTask( - FROM_HERE, - base::Bind(&PermissionResponseCallback::Run, - base::Owned(new PermissionResponseCallback(callback)), - allowed_by_default, - std::string())); - return webview::kInvalidPermissionRequestID; - } - - int request_id = next_permission_request_id_++; - pending_permission_requests_[request_id] = - PermissionResponseInfo(callback, permission_type, allowed_by_default); - scoped_ptr<base::DictionaryValue> args(request_info.DeepCopy()); - args->SetInteger(webview::kRequestId, request_id); - switch (permission_type) { - case WEB_VIEW_PERMISSION_TYPE_NEW_WINDOW: { - DispatchEvent( - new GuestViewBase::Event(webview::kEventNewWindow, args.Pass())); - break; - } - case WEB_VIEW_PERMISSION_TYPE_JAVASCRIPT_DIALOG: { - DispatchEvent( - new GuestViewBase::Event(webview::kEventDialog, args.Pass())); - break; - } - default: { - args->SetString(webview::kPermission, - PermissionTypeToString(permission_type)); - DispatchEvent(new GuestViewBase::Event(webview::kEventPermissionRequest, - args.Pass())); - break; - } - } - return request_id; -} - bool WebViewGuest::HandleKeyboardShortcuts( const content::NativeWebKeyboardEvent& event) { if (event.type != blink::WebInputEvent::RawKeyDown) @@ -1446,23 +1029,6 @@ bool WebViewGuest::HandleKeyboardShortcuts( return false; } -WebViewGuest::PermissionResponseInfo::PermissionResponseInfo() - : permission_type(WEB_VIEW_PERMISSION_TYPE_UNKNOWN), - allowed_by_default(false) { -} - -WebViewGuest::PermissionResponseInfo::PermissionResponseInfo( - const PermissionResponseCallback& callback, - WebViewPermissionType permission_type, - bool allowed_by_default) - : callback(callback), - permission_type(permission_type), - allowed_by_default(allowed_by_default) { -} - -WebViewGuest::PermissionResponseInfo::~PermissionResponseInfo() { -} - void WebViewGuest::ShowContextMenu(int request_id, const MenuItemVector* items) { if (!pending_menu_.get()) @@ -1498,7 +1064,7 @@ void WebViewGuest::SetZoom(double zoom_factor) { scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue()); args->SetDouble(webview::kOldZoomFactor, current_zoom_factor_); args->SetDouble(webview::kNewZoomFactor, zoom_factor); - DispatchEvent( + DispatchEventToEmbedder( new GuestViewBase::Event(webview::kEventZoomChange, args.Pass())); current_zoom_factor_ = zoom_factor; @@ -1613,12 +1179,13 @@ void WebViewGuest::RequestNewWindowPermission( webview::kWindowOpenDisposition, new base::StringValue(WindowOpenDispositionToString(disposition))); - RequestPermission(WEB_VIEW_PERMISSION_TYPE_NEW_WINDOW, - request_info, - base::Bind(&WebViewGuest::OnWebViewNewWindowResponse, - base::Unretained(this), - guest->GetGuestInstanceID()), - false /* allowed_by_default */); + web_view_permission_helper_-> + RequestPermission(WEB_VIEW_PERMISSION_TYPE_NEW_WINDOW, + request_info, + base::Bind(&WebViewGuest::OnWebViewNewWindowResponse, + base::Unretained(this), + guest->GetGuestInstanceID()), + false /* allowed_by_default */); } void WebViewGuest::DestroyUnattachedWindows() { diff --git a/chrome/browser/guest_view/web_view/web_view_guest.h b/chrome/browser/guest_view/web_view/web_view_guest.h index 447d062..da23db0 100644 --- a/chrome/browser/guest_view/web_view/web_view_guest.h +++ b/chrome/browser/guest_view/web_view/web_view_guest.h @@ -12,6 +12,7 @@ #include "chrome/browser/guest_view/guest_view.h" #include "chrome/browser/guest_view/web_view/javascript_dialog_helper.h" #include "chrome/browser/guest_view/web_view/web_view_find_helper.h" +#include "chrome/browser/guest_view/web_view/web_view_permission_helper.h" #include "chrome/browser/guest_view/web_view/web_view_permission_types.h" #include "chrome/common/extensions/api/web_view_internal.h" #include "content/public/browser/javascript_dialog_manager.h" @@ -203,25 +204,6 @@ class WebViewGuest : public GuestView<WebViewGuest>, bool allowed_by_default, const base::Callback<void(bool)>& callback); - enum PermissionResponseAction { - DENY, - ALLOW, - DEFAULT - }; - - enum SetPermissionResult { - SET_PERMISSION_INVALID, - SET_PERMISSION_ALLOWED, - SET_PERMISSION_DENIED - }; - - // Responds to the permission request |request_id| with |action| and - // |user_input|. Returns whether there was a pending request for the provided - // |request_id|. - SetPermissionResult SetPermission(int request_id, - PermissionResponseAction action, - const std::string& user_input); - // Overrides the user agent for this guest. // This affects subsequent guest navigations. void SetUserAgentOverride(const std::string& user_agent_override); @@ -244,105 +226,20 @@ class WebViewGuest : public GuestView<WebViewGuest>, return script_executor_.get(); } - // Called when file system access is requested by the guest content using the - // asynchronous HTML5 file system API. The request is plumbed through the - // <webview> permission request API. The request will be: - // - Allowed if the embedder explicitly allowed it. - // - Denied if the embedder explicitly denied. - // - Determined by the guest's content settings if the embedder does not - // perform an explicit action. - // If access was blocked due to the page's content settings, - // |blocked_by_policy| should be true, and this function should invoke - // OnContentBlocked. - static void FileSystemAccessedAsync(int render_process_id, - int render_frame_id, - int request_id, - const GURL& url, - bool blocked_by_policy); - - // Called when file system access is requested by the guest content using the - // synchronous HTML5 file system API in a worker thread or shared worker. The - // request is plumbed through the <webview> permission request API. The - // request will be: - // - Allowed if the embedder explicitly allowed it. - // - Denied if the embedder explicitly denied. - // - Determined by the guest's content settings if the embedder does not - // perform an explicit action. - // If access was blocked due to the page's content settings, - // |blocked_by_policy| should be true, and this function should invoke - // OnContentBlocked. - static void FileSystemAccessedSync(int render_process_id, - int render_frame_id, - const GURL& url, - bool blocked_by_policy, - IPC::Message* reply_msg); - private: + friend class WebViewPermissionHelper; virtual ~WebViewGuest(); - // A map to store the callback for a request keyed by the request's id. - struct PermissionResponseInfo { - PermissionResponseCallback callback; - WebViewPermissionType permission_type; - bool allowed_by_default; - PermissionResponseInfo(); - PermissionResponseInfo(const PermissionResponseCallback& callback, - WebViewPermissionType permission_type, - bool allowed_by_default); - ~PermissionResponseInfo(); - }; - - static void RecordUserInitiatedUMA(const PermissionResponseInfo& info, - bool allow); - // Returns the top level items (ignoring submenus) as Value. static scoped_ptr<base::ListValue> MenuModelToValue( const ui::SimpleMenuModel& menu_model); - void OnWebViewGeolocationPermissionResponse( - int bridge_id, - bool user_gesture, - const base::Callback<void(bool)>& callback, - bool allow, - const std::string& user_input); - - void OnWebViewFileSystemPermissionResponse( - const base::Callback<void(bool)>& callback, - bool allow, - const std::string& user_input); - - void OnWebViewMediaPermissionResponse( - const content::MediaStreamRequest& request, - const content::MediaResponseCallback& callback, - bool allow, - const std::string& user_input); - - void OnWebViewDownloadPermissionResponse( - const base::Callback<void(bool)>& callback, - bool allow, - const std::string& user_input); - - void OnWebViewPointerLockPermissionResponse( - const base::Callback<void(bool)>& callback, - bool allow, - const std::string& user_input); + void AttachWebViewHelpers(content::WebContents* contents); void OnWebViewNewWindowResponse(int new_window_instance_id, bool allow, const std::string& user_input); - static void FileSystemAccessedAsyncResponse(int render_process_id, - int render_frame_id, - int request_id, - const GURL& url, - bool allowed); - - static void FileSystemAccessedSyncResponse(int render_process_id, - int render_frame_id, - const GURL& url, - IPC::Message* reply_msg, - bool allowed); - // WebContentsObserver implementation. virtual void DidCommitProvisionalLoadForFrame( content::RenderFrameHost* render_frame_host, @@ -390,11 +287,6 @@ class WebViewGuest : public GuestView<WebViewGuest>, void InjectChromeVoxIfNeeded(content::RenderViewHost* render_view_host); - // Bridge IDs correspond to a geolocation request. This method will remove - // the bookkeeping for a particular geolocation request associated with the - // provided |bridge_id|. It returns the request ID of the geolocation request. - int RemoveBridgeID(int bridge_id); - void LoadURLWithParams(const GURL& url, const content::Referrer& referrer, content::PageTransition transition_type, @@ -439,13 +331,6 @@ class WebViewGuest : public GuestView<WebViewGuest>, // We only need the ids to be unique for a given WebViewGuest. int pending_context_menu_request_id_; - // A counter to generate a unique request id for a permission request. - // We only need the ids to be unique for a given WebViewGuest. - int next_permission_request_id_; - - typedef std::map<int, PermissionResponseInfo> RequestMap; - RequestMap pending_permission_requests_; - // True if the user agent is overridden. bool is_overriding_user_agent_; @@ -464,6 +349,9 @@ class WebViewGuest : public GuestView<WebViewGuest>, // Handles the JavaScript dialog requests. JavaScriptDialogHelper javascript_dialog_helper_; + // Handels permission requests. + scoped_ptr<WebViewPermissionHelper> web_view_permission_helper_; + friend void WebViewFindHelper::DispatchFindUpdateEvent(bool canceled, bool final_update); @@ -477,8 +365,6 @@ class WebViewGuest : public GuestView<WebViewGuest>, accessibility_subscription_; #endif - std::map<int, int> bridge_id_to_request_id_map_; - // Tracks the name, and target URL of the new window. Once the first // navigation commits, we no longer track this information. struct NewWindowInfo { diff --git a/chrome/browser/guest_view/web_view/web_view_permission_helper.cc b/chrome/browser/guest_view/web_view/web_view_permission_helper.cc new file mode 100644 index 0000000..a9b9b5e --- /dev/null +++ b/chrome/browser/guest_view/web_view/web_view_permission_helper.cc @@ -0,0 +1,604 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/guest_view/web_view/web_view_permission_helper.h" + +#include "chrome/browser/content_settings/tab_specific_content_settings.h" +#include "chrome/browser/geolocation/geolocation_permission_context.h" +#include "chrome/browser/geolocation/geolocation_permission_context_factory.h" +#include "chrome/browser/guest_view/web_view/web_view_constants.h" +#include "chrome/browser/guest_view/web_view/web_view_guest.h" +#include "chrome/browser/guest_view/web_view/web_view_permission_types.h" +#include "chrome/browser/plugins/chrome_plugin_service_filter.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/common/render_messages.h" +#include "content/public/browser/render_process_host.h" +#include "content/public/browser/render_view_host.h" +#include "content/public/browser/user_metrics.h" + +using content::BrowserPluginGuestDelegate; +using content::RenderViewHost; + +namespace { +static std::string PermissionTypeToString(WebViewPermissionType type) { + switch (type) { + case WEB_VIEW_PERMISSION_TYPE_DOWNLOAD: + return webview::kPermissionTypeDownload; + case WEB_VIEW_PERMISSION_TYPE_FILESYSTEM: + return webview::kPermissionTypeFileSystem; + case WEB_VIEW_PERMISSION_TYPE_GEOLOCATION: + return webview::kPermissionTypeGeolocation; + case WEB_VIEW_PERMISSION_TYPE_JAVASCRIPT_DIALOG: + return webview::kPermissionTypeDialog; + case WEB_VIEW_PERMISSION_TYPE_LOAD_PLUGIN: + return webview::kPermissionTypeLoadPlugin; + case WEB_VIEW_PERMISSION_TYPE_MEDIA: + return webview::kPermissionTypeMedia; + case WEB_VIEW_PERMISSION_TYPE_NEW_WINDOW: + return webview::kPermissionTypeNewWindow; + case WEB_VIEW_PERMISSION_TYPE_POINTER_LOCK: + return webview::kPermissionTypePointerLock; + default: + NOTREACHED(); + return std::string(); + } +} + +// static +void RecordUserInitiatedUMA( + const WebViewPermissionHelper::PermissionResponseInfo& info, + bool allow) { + if (allow) { + // Note that |allow| == true means the embedder explicitly allowed the + // request. For some requests they might still fail. An example of such + // scenario would be: an embedder allows geolocation request but doesn't + // have geolocation access on its own. + switch (info.permission_type) { + case WEB_VIEW_PERMISSION_TYPE_DOWNLOAD: + content::RecordAction( + UserMetricsAction("WebView.PermissionAllow.Download")); + break; + case WEB_VIEW_PERMISSION_TYPE_FILESYSTEM: + content::RecordAction( + UserMetricsAction("WebView.PermissionAllow.FileSystem")); + break; + case WEB_VIEW_PERMISSION_TYPE_GEOLOCATION: + content::RecordAction( + UserMetricsAction("WebView.PermissionAllow.Geolocation")); + break; + case WEB_VIEW_PERMISSION_TYPE_JAVASCRIPT_DIALOG: + content::RecordAction( + UserMetricsAction("WebView.PermissionAllow.JSDialog")); + break; + case WEB_VIEW_PERMISSION_TYPE_LOAD_PLUGIN: + content::RecordAction( + UserMetricsAction("WebView.Guest.PermissionAllow.PluginLoad")); + case WEB_VIEW_PERMISSION_TYPE_MEDIA: + content::RecordAction( + UserMetricsAction("WebView.PermissionAllow.Media")); + break; + case WEB_VIEW_PERMISSION_TYPE_NEW_WINDOW: + content::RecordAction( + UserMetricsAction("BrowserPlugin.PermissionAllow.NewWindow")); + break; + case WEB_VIEW_PERMISSION_TYPE_POINTER_LOCK: + content::RecordAction( + UserMetricsAction("WebView.PermissionAllow.PointerLock")); + break; + default: + break; + } + } else { + switch (info.permission_type) { + case WEB_VIEW_PERMISSION_TYPE_DOWNLOAD: + content::RecordAction( + UserMetricsAction("WebView.PermissionDeny.Download")); + break; + case WEB_VIEW_PERMISSION_TYPE_FILESYSTEM: + content::RecordAction( + UserMetricsAction("WebView.PermissionDeny.FileSystem")); + break; + case WEB_VIEW_PERMISSION_TYPE_GEOLOCATION: + content::RecordAction( + UserMetricsAction("WebView.PermissionDeny.Geolocation")); + break; + case WEB_VIEW_PERMISSION_TYPE_JAVASCRIPT_DIALOG: + content::RecordAction( + UserMetricsAction("WebView.PermissionDeny.JSDialog")); + break; + case WEB_VIEW_PERMISSION_TYPE_LOAD_PLUGIN: + content::RecordAction( + UserMetricsAction("WebView.Guest.PermissionDeny.PluginLoad")); + break; + case WEB_VIEW_PERMISSION_TYPE_MEDIA: + content::RecordAction( + UserMetricsAction("WebView.PermissionDeny.Media")); + break; + case WEB_VIEW_PERMISSION_TYPE_NEW_WINDOW: + content::RecordAction( + UserMetricsAction("BrowserPlugin.PermissionDeny.NewWindow")); + break; + case WEB_VIEW_PERMISSION_TYPE_POINTER_LOCK: + content::RecordAction( + UserMetricsAction("WebView.PermissionDeny.PointerLock")); + break; + default: + break; + } + } +} + +} // namespace + +WebViewPermissionHelper::WebViewPermissionHelper(WebViewGuest* web_view_guest) + : content::WebContentsObserver(web_view_guest->guest_web_contents()), + next_permission_request_id_(guestview::kInstanceIDNone), + web_view_guest_(web_view_guest), + weak_factory_(this) { +} + +WebViewPermissionHelper::~WebViewPermissionHelper() { +} + +// static +WebViewPermissionHelper* WebViewPermissionHelper::FromFrameID( + int render_process_id, + int render_frame_id) { + WebViewGuest* web_view_guest = WebViewGuest::FromFrameID( + render_process_id, render_frame_id); + if (!web_view_guest) { + return NULL; + } + return web_view_guest->web_view_permission_helper_.get(); +} + +// static +WebViewPermissionHelper* WebViewPermissionHelper::FromWebContents( + content::WebContents* web_contents) { + WebViewGuest* web_view_guest = WebViewGuest::FromWebContents(web_contents); + if (!web_view_guest) + return NULL; + return web_view_guest->web_view_permission_helper_.get(); +} + +#if defined(ENABLE_PLUGINS) +bool WebViewPermissionHelper::OnMessageReceived( + const IPC::Message& message, + content::RenderFrameHost* render_frame_host) { + IPC_BEGIN_MESSAGE_MAP(WebViewPermissionHelper, message) + IPC_MESSAGE_HANDLER(ChromeViewHostMsg_BlockedOutdatedPlugin, + OnBlockedOutdatedPlugin) + IPC_MESSAGE_HANDLER(ChromeViewHostMsg_BlockedUnauthorizedPlugin, + OnBlockedUnauthorizedPlugin) + IPC_MESSAGE_HANDLER(ChromeViewHostMsg_NPAPINotSupported, + OnNPAPINotSupported) +#if defined(ENABLE_PLUGIN_INSTALLATION) + IPC_MESSAGE_HANDLER(ChromeViewHostMsg_FindMissingPlugin, + OnFindMissingPlugin) +#endif + IPC_MESSAGE_UNHANDLED(return false) + IPC_END_MESSAGE_MAP() + + return true; +} + +bool WebViewPermissionHelper::OnMessageReceived(const IPC::Message& message) { + IPC_BEGIN_MESSAGE_MAP(WebViewPermissionHelper, message) + IPC_MESSAGE_HANDLER(ChromeViewHostMsg_CouldNotLoadPlugin, + OnCouldNotLoadPlugin) + IPC_MESSAGE_HANDLER(ChromeViewHostMsg_OpenAboutPlugins, + OnOpenAboutPlugins) +#if defined(ENABLE_PLUGIN_INSTALLATION) + IPC_MESSAGE_HANDLER(ChromeViewHostMsg_RemovePluginPlaceholderHost, + OnRemovePluginPlaceholderHost) +#endif + IPC_MESSAGE_UNHANDLED(return false) + IPC_END_MESSAGE_MAP() + + return true; +} + +void WebViewPermissionHelper::OnBlockedUnauthorizedPlugin( + const base::string16& name, + const std::string& identifier) { + const char kPluginName[] = "name"; + const char kPluginIdentifier[] = "identifier"; + + base::DictionaryValue info; + info.SetString(std::string(kPluginName), name); + info.SetString(std::string(kPluginIdentifier), identifier); + RequestPermission( + WEB_VIEW_PERMISSION_TYPE_LOAD_PLUGIN, + info, + base::Bind(&WebViewPermissionHelper::OnPermissionResponse, + weak_factory_.GetWeakPtr(), + identifier), + true /* allowed_by_default */); + content::RecordAction( + base::UserMetricsAction("WebView.Guest.PluginLoadRequest")); +} + +void WebViewPermissionHelper::OnCouldNotLoadPlugin( + const base::FilePath& plugin_path) { +} + +void WebViewPermissionHelper::OnBlockedOutdatedPlugin( + int placeholder_id, + const std::string& identifier) { +} + +void WebViewPermissionHelper::OnNPAPINotSupported(const std::string& id) { +} + +void WebViewPermissionHelper::OnOpenAboutPlugins() { +} + +#if defined(ENABLE_PLUGIN_INSTALLATION) +void WebViewPermissionHelper::OnFindMissingPlugin( + int placeholder_id, + const std::string& mime_type) { + Send(new ChromeViewMsg_DidNotFindMissingPlugin(placeholder_id)); +} + +void WebViewPermissionHelper::OnRemovePluginPlaceholderHost( + int placeholder_id) { +} +#endif // defined(ENABLE_PLUGIN_INSTALLATION) + +void WebViewPermissionHelper::OnPermissionResponse( + const std::string& identifier, + bool allow, + const std::string& input) { + if (allow) { + ChromePluginServiceFilter::GetInstance()->AuthorizeAllPlugins( + web_contents(), true, identifier); + } +} + +#endif // defined(ENABLE_PLUGINS) + +void WebViewPermissionHelper::RequestMediaAccessPermission( + content::WebContents* source, + const content::MediaStreamRequest& request, + const content::MediaResponseCallback& callback) { + base::DictionaryValue request_info; + request_info.Set(guestview::kUrl, + new base::StringValue(request.security_origin.spec())); + RequestPermission(WEB_VIEW_PERMISSION_TYPE_MEDIA, + request_info, + base::Bind(&WebViewPermissionHelper:: + OnMediaPermissionResponse, + base::Unretained(this), + request, + callback), + false /* allowed_by_default */); +} + + void WebViewPermissionHelper::OnMediaPermissionResponse( + const content::MediaStreamRequest& request, + const content::MediaResponseCallback& callback, + bool allow, + const std::string& user_input) { + if (!allow || !web_view_guest_->attached()) { + // Deny the request. + callback.Run(content::MediaStreamDevices(), + content::MEDIA_DEVICE_INVALID_STATE, + scoped_ptr<content::MediaStreamUI>()); + return; + } + if (!web_view_guest_->embedder_web_contents()->GetDelegate()) + return; + + web_view_guest_->embedder_web_contents()->GetDelegate()-> + RequestMediaAccessPermission(web_view_guest_->embedder_web_contents(), + request, + callback); +} + +void WebViewPermissionHelper::CanDownload( + content::RenderViewHost* render_view_host, + const GURL& url, + const std::string& request_method, + const base::Callback<void(bool)>& callback) { + base::DictionaryValue request_info; + request_info.Set(guestview::kUrl, new base::StringValue(url.spec())); + RequestPermission( + WEB_VIEW_PERMISSION_TYPE_DOWNLOAD, + request_info, + base::Bind(&WebViewPermissionHelper::OnDownloadPermissionResponse, + base::Unretained(this), + callback), + false /* allowed_by_default */); +} + +void WebViewPermissionHelper::OnDownloadPermissionResponse( + const base::Callback<void(bool)>& callback, + bool allow, + const std::string& user_input) { + callback.Run(allow && web_view_guest_->attached()); +} + +void WebViewPermissionHelper::RequestPointerLockPermission( + bool user_gesture, + bool last_unlocked_by_target, + const base::Callback<void(bool)>& callback) { + base::DictionaryValue request_info; + request_info.Set(guestview::kUserGesture, + base::Value::CreateBooleanValue(user_gesture)); + request_info.Set(webview::kLastUnlockedBySelf, + base::Value::CreateBooleanValue(last_unlocked_by_target)); + request_info.Set(guestview::kUrl, + new base::StringValue( + web_contents()->GetLastCommittedURL().spec())); + + RequestPermission( + WEB_VIEW_PERMISSION_TYPE_POINTER_LOCK, + request_info, + base::Bind( + &WebViewPermissionHelper::OnPointerLockPermissionResponse, + base::Unretained(this), + callback), + false /* allowed_by_default */); +} + +void WebViewPermissionHelper::OnPointerLockPermissionResponse( + const base::Callback<void(bool)>& callback, + bool allow, + const std::string& user_input) { + callback.Run(allow && web_view_guest_->attached()); +} + +void WebViewPermissionHelper::RequestGeolocationPermission( + int bridge_id, + const GURL& requesting_frame, + bool user_gesture, + const base::Callback<void(bool)>& callback) { + base::DictionaryValue request_info; + request_info.Set(guestview::kUrl, + new base::StringValue(requesting_frame.spec())); + request_info.Set(guestview::kUserGesture, + base::Value::CreateBooleanValue(user_gesture)); + + // It is safe to hold an unretained pointer to WebViewPermissionHelper because + // this callback is called from WebViewPermissionHelper::SetPermission. + const PermissionResponseCallback permission_callback = + base::Bind( + &WebViewPermissionHelper::OnGeolocationPermissionResponse, + base::Unretained(this), + bridge_id, + user_gesture, + callback); + int request_id = RequestPermission( + WEB_VIEW_PERMISSION_TYPE_GEOLOCATION, + request_info, + permission_callback, + false /* allowed_by_default */); + bridge_id_to_request_id_map_[bridge_id] = request_id; +} + +void WebViewPermissionHelper::OnGeolocationPermissionResponse( + int bridge_id, + bool user_gesture, + const base::Callback<void(bool)>& callback, + bool allow, + const std::string& user_input) { + // The <webview> embedder has allowed the permission. We now need to make sure + // that the embedder has geolocation permission. + RemoveBridgeID(bridge_id); + + if (!allow || !web_view_guest_->attached()) { + callback.Run(false); + return; + } + + Profile* profile = Profile::FromBrowserContext( + web_view_guest_->browser_context()); + GeolocationPermissionContextFactory::GetForProfile(profile)-> + RequestGeolocationPermission( + web_view_guest_->embedder_web_contents(), + // The geolocation permission request here is not initiated + // through WebGeolocationPermissionRequest. We are only interested + // in the fact whether the embedder/app has geolocation + // permission. Therefore we use an invalid |bridge_id|. + -1, + web_view_guest_->embedder_web_contents()->GetLastCommittedURL(), + user_gesture, + callback, + NULL); +} + +void WebViewPermissionHelper::CancelGeolocationPermissionRequest( + int bridge_id) { + int request_id = RemoveBridgeID(bridge_id); + RequestMap::iterator request_itr = + pending_permission_requests_.find(request_id); + + if (request_itr == pending_permission_requests_.end()) + return; + + pending_permission_requests_.erase(request_itr); +} + +int WebViewPermissionHelper::RemoveBridgeID(int bridge_id) { + std::map<int, int>::iterator bridge_itr = + bridge_id_to_request_id_map_.find(bridge_id); + if (bridge_itr == bridge_id_to_request_id_map_.end()) + return webview::kInvalidPermissionRequestID; + + int request_id = bridge_itr->second; + bridge_id_to_request_id_map_.erase(bridge_itr); + return request_id; +} + +void WebViewPermissionHelper::RequestFileSystemPermission( + const GURL& url, + bool allowed_by_default, + const base::Callback<void(bool)>& callback) { + base::DictionaryValue request_info; + request_info.Set(guestview::kUrl, new base::StringValue(url.spec())); + RequestPermission( + WEB_VIEW_PERMISSION_TYPE_FILESYSTEM, + request_info, + base::Bind( + &WebViewPermissionHelper::OnFileSystemPermissionResponse, + base::Unretained(this), + callback), + allowed_by_default); +} + +void WebViewPermissionHelper::OnFileSystemPermissionResponse( + const base::Callback<void(bool)>& callback, + bool allow, + const std::string& user_input) { + callback.Run(allow && web_view_guest_->attached()); +} + +void WebViewPermissionHelper::FileSystemAccessedAsync(int render_process_id, + int render_frame_id, + int request_id, + const GURL& url, + bool blocked_by_policy) { + RequestFileSystemPermission( + url, + !blocked_by_policy, + base::Bind(&WebViewPermissionHelper::FileSystemAccessedAsyncResponse, + base::Unretained(this), + render_process_id, + render_frame_id, + request_id, + url)); +} + +void WebViewPermissionHelper::FileSystemAccessedAsyncResponse( + int render_process_id, + int render_frame_id, + int request_id, + const GURL& url, + bool allowed) { + TabSpecificContentSettings::FileSystemAccessed( + render_process_id, render_frame_id, url, !allowed); + Send(new ChromeViewMsg_RequestFileSystemAccessAsyncResponse( + render_frame_id, request_id, allowed)); +} + +void WebViewPermissionHelper::FileSystemAccessedSync(int render_process_id, + int render_frame_id, + const GURL& url, + bool blocked_by_policy, + IPC::Message* reply_msg) { + RequestFileSystemPermission( + url, + !blocked_by_policy, + base::Bind(&WebViewPermissionHelper::FileSystemAccessedSyncResponse, + base::Unretained(this), + render_process_id, + render_frame_id, + url, + reply_msg)); +} + +void WebViewPermissionHelper::FileSystemAccessedSyncResponse( + int render_process_id, + int render_frame_id, + const GURL& url, + IPC::Message* reply_msg, + bool allowed) { + TabSpecificContentSettings::FileSystemAccessed( + render_process_id, render_frame_id, url, !allowed); + ChromeViewHostMsg_RequestFileSystemAccessSync::WriteReplyParams(reply_msg, + allowed); + Send(reply_msg); +} + +int WebViewPermissionHelper::RequestPermission( + WebViewPermissionType permission_type, + const base::DictionaryValue& request_info, + const PermissionResponseCallback& callback, + bool allowed_by_default) { + // If there are too many pending permission requests then reject this request. + if (pending_permission_requests_.size() >= + webview::kMaxOutstandingPermissionRequests) { + // Let the stack unwind before we deny the permission request so that + // objects held by the permission request are not destroyed immediately + // after creation. This is to allow those same objects to be accessed again + // in the same scope without fear of use after freeing. + base::MessageLoop::current()->PostTask( + FROM_HERE, + base::Bind(&PermissionResponseCallback::Run, + base::Owned(new PermissionResponseCallback(callback)), + allowed_by_default, + std::string())); + return webview::kInvalidPermissionRequestID; + } + + int request_id = next_permission_request_id_++; + pending_permission_requests_[request_id] = + PermissionResponseInfo(callback, permission_type, allowed_by_default); + scoped_ptr<base::DictionaryValue> args(request_info.DeepCopy()); + args->SetInteger(webview::kRequestId, request_id); + switch (permission_type) { + case WEB_VIEW_PERMISSION_TYPE_NEW_WINDOW: { + web_view_guest_->DispatchEventToEmbedder( + new GuestViewBase::Event(webview::kEventNewWindow, args.Pass())); + break; + } + case WEB_VIEW_PERMISSION_TYPE_JAVASCRIPT_DIALOG: { + web_view_guest_->DispatchEventToEmbedder( + new GuestViewBase::Event(webview::kEventDialog, args.Pass())); + break; + } + default: { + args->SetString(webview::kPermission, + PermissionTypeToString(permission_type)); + web_view_guest_->DispatchEventToEmbedder(new GuestViewBase::Event( + webview::kEventPermissionRequest, + args.Pass())); + break; + } + } + return request_id; +} + +WebViewPermissionHelper::SetPermissionResult +WebViewPermissionHelper::SetPermission( + int request_id, + PermissionResponseAction action, + const std::string& user_input) { + RequestMap::iterator request_itr = + pending_permission_requests_.find(request_id); + + if (request_itr == pending_permission_requests_.end()) + return SET_PERMISSION_INVALID; + + const PermissionResponseInfo& info = request_itr->second; + bool allow = (action == ALLOW) || + ((action == DEFAULT) && info.allowed_by_default); + + info.callback.Run(allow, user_input); + + // Only record user initiated (i.e. non-default) actions. + if (action != DEFAULT) + RecordUserInitiatedUMA(info, allow); + + pending_permission_requests_.erase(request_itr); + + return allow ? SET_PERMISSION_ALLOWED : SET_PERMISSION_DENIED; +} + +WebViewPermissionHelper::PermissionResponseInfo::PermissionResponseInfo() + : permission_type(WEB_VIEW_PERMISSION_TYPE_UNKNOWN), + allowed_by_default(false) { +} + +WebViewPermissionHelper::PermissionResponseInfo::PermissionResponseInfo( + const PermissionResponseCallback& callback, + WebViewPermissionType permission_type, + bool allowed_by_default) + : callback(callback), + permission_type(permission_type), + allowed_by_default(allowed_by_default) { +} + +WebViewPermissionHelper::PermissionResponseInfo::~PermissionResponseInfo() { +} diff --git a/chrome/browser/guest_view/web_view/web_view_permission_helper.h b/chrome/browser/guest_view/web_view/web_view_permission_helper.h new file mode 100644 index 0000000..dd1231d --- /dev/null +++ b/chrome/browser/guest_view/web_view/web_view_permission_helper.h @@ -0,0 +1,214 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_GUEST_VIEW_WEB_VIEW_WEB_VIEW_PERMISSION_HELPER_H_ +#define CHROME_BROWSER_GUEST_VIEW_WEB_VIEW_WEB_VIEW_PERMISSION_HELPER_H_ + +#include "base/memory/weak_ptr.h" +#include "base/metrics/user_metrics_action.h" +#include "chrome/browser/guest_view/guest_view_constants.h" +#include "chrome/browser/guest_view/web_view/web_view_permission_types.h" +#include "content/public/browser/web_contents.h" +#include "content/public/browser/web_contents_observer.h" +#include "content/public/common/media_stream_request.h" + +using base::UserMetricsAction; + +class WebViewGuest; + +// WebViewPermissionHelper manages <webview> permission requests. This helper +// class is owned by WebViewGuest. Its purpose is to request permission for +// various operations from the <webview> embedder, and reply back via callbacks +// to the callers on a response from the embedder. +class WebViewPermissionHelper + : public content::WebContentsObserver { + public: + explicit WebViewPermissionHelper(WebViewGuest* guest); + virtual ~WebViewPermissionHelper(); + typedef base::Callback< + void(bool /* allow */, const std::string& /* user_input */)> + PermissionResponseCallback; + + // A map to store the callback for a request keyed by the request's id. + struct PermissionResponseInfo { + PermissionResponseCallback callback; + WebViewPermissionType permission_type; + bool allowed_by_default; + PermissionResponseInfo(); + PermissionResponseInfo(const PermissionResponseCallback& callback, + WebViewPermissionType permission_type, + bool allowed_by_default); + ~PermissionResponseInfo(); + }; + + typedef std::map<int, PermissionResponseInfo> RequestMap; + + int RequestPermission(WebViewPermissionType permission_type, + const base::DictionaryValue& request_info, + const PermissionResponseCallback& callback, + bool allowed_by_default); + + static WebViewPermissionHelper* FromWebContents( + content::WebContents* web_contents); + static WebViewPermissionHelper* FromFrameID(int render_process_id, + int render_frame_id); + void RequestMediaAccessPermission( + content::WebContents* source, + const content::MediaStreamRequest& request, + const content::MediaResponseCallback& callback); + void CanDownload(content::RenderViewHost* render_view_host, + const GURL& url, + const std::string& request_method, + const base::Callback<void(bool)>& callback); + void RequestPointerLockPermission(bool user_gesture, + bool last_unlocked_by_target, + const base::Callback<void(bool)>& callback); + + // Requests Geolocation Permission from the embedder. + void RequestGeolocationPermission(int bridge_id, + const GURL& requesting_frame, + bool user_gesture, + const base::Callback<void(bool)>& callback); + void CancelGeolocationPermissionRequest(int bridge_id); + + void RequestFileSystemPermission(const GURL& url, + bool allowed_by_default, + const base::Callback<void(bool)>& callback); + + // Called when file system access is requested by the guest content using the + // asynchronous HTML5 file system API. The request is plumbed through the + // <webview> permission request API. The request will be: + // - Allowed if the embedder explicitly allowed it. + // - Denied if the embedder explicitly denied. + // - Determined by the guest's content settings if the embedder does not + // perform an explicit action. + // If access was blocked due to the page's content settings, + // |blocked_by_policy| should be true, and this function should invoke + // OnContentBlocked. + void FileSystemAccessedAsync(int render_process_id, + int render_frame_id, + int request_id, + const GURL& url, + bool blocked_by_policy); + + // Called when file system access is requested by the guest content using the + // synchronous HTML5 file system API in a worker thread or shared worker. The + // request is plumbed through the <webview> permission request API. The + // request will be: + // - Allowed if the embedder explicitly allowed it. + // - Denied if the embedder explicitly denied. + // - Determined by the guest's content settings if the embedder does not + // perform an explicit action. + // If access was blocked due to the page's content settings, + // |blocked_by_policy| should be true, and this function should invoke + // OnContentBlocked. + void FileSystemAccessedSync(int render_process_id, + int render_frame_id, + const GURL& url, + bool blocked_by_policy, + IPC::Message* reply_msg); + + enum PermissionResponseAction { DENY, ALLOW, DEFAULT }; + + enum SetPermissionResult { + SET_PERMISSION_INVALID, + SET_PERMISSION_ALLOWED, + SET_PERMISSION_DENIED + }; + + // Responds to the permission request |request_id| with |action| and + // |user_input|. Returns whether there was a pending request for the provided + // |request_id|. + SetPermissionResult SetPermission(int request_id, + PermissionResponseAction action, + const std::string& user_input); + + private: +#if defined(ENABLE_PLUGINS) + // content::WebContentsObserver implementation. + virtual bool OnMessageReceived( + const IPC::Message& message, + content::RenderFrameHost* render_frame_host) OVERRIDE; + virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; + + // Message handlers: + void OnBlockedUnauthorizedPlugin(const base::string16& name, + const std::string& identifier); + void OnCouldNotLoadPlugin(const base::FilePath& plugin_path); + void OnBlockedOutdatedPlugin(int placeholder_id, + const std::string& identifier); + void OnNPAPINotSupported(const std::string& identifier); + void OnOpenAboutPlugins(); +#if defined(ENABLE_PLUGIN_INSTALLATION) + void OnFindMissingPlugin(int placeholder_id, const std::string& mime_type); + + void OnRemovePluginPlaceholderHost(int placeholder_id); +#endif // defined(ENABLE_PLUGIN_INSTALLATION) + + void OnPermissionResponse(const std::string& identifier, + bool allow, + const std::string& user_input); +#endif // defiend(ENABLE_PLUGINS) + + void OnGeolocationPermissionResponse( + int bridge_id, + bool user_gesture, + const base::Callback<void(bool)>& callback, + bool allow, + const std::string& user_input); + + void OnFileSystemPermissionResponse( + const base::Callback<void(bool)>& callback, + bool allow, + const std::string& user_input); + + void OnMediaPermissionResponse( + const content::MediaStreamRequest& request, + const content::MediaResponseCallback& callback, + bool allow, + const std::string& user_input); + + void OnDownloadPermissionResponse( + const base::Callback<void(bool)>& callback, + bool allow, + const std::string& user_input); + + void OnPointerLockPermissionResponse( + const base::Callback<void(bool)>& callback, + bool allow, + const std::string& user_input); + + // Bridge IDs correspond to a geolocation request. This method will remove + // the bookkeeping for a particular geolocation request associated with the + // provided |bridge_id|. It returns the request ID of the geolocation request. + int RemoveBridgeID(int bridge_id); + + void FileSystemAccessedAsyncResponse(int render_process_id, + int render_frame_id, + int request_id, + const GURL& url, + bool allowed); + + void FileSystemAccessedSyncResponse(int render_process_id, + int render_frame_id, + const GURL& url, + IPC::Message* reply_msg, + bool allowed); + + // A counter to generate a unique request id for a permission request. + // We only need the ids to be unique for a given WebViewGuest. + int next_permission_request_id_; + + WebViewPermissionHelper::RequestMap pending_permission_requests_; + + std::map<int, int> bridge_id_to_request_id_map_; + + WebViewGuest* web_view_guest_; + + base::WeakPtrFactory<WebViewPermissionHelper> weak_factory_; + + DISALLOW_COPY_AND_ASSIGN(WebViewPermissionHelper); +}; + +#endif // CHROME_BROWSER_GUEST_VIEW_WEB_VIEW_WEB_VIEW_PERMISSION_HELPER_H_ diff --git a/chrome/browser/renderer_host/chrome_render_message_filter.cc b/chrome/browser/renderer_host/chrome_render_message_filter.cc index 3307d34..d1de52c 100644 --- a/chrome/browser/renderer_host/chrome_render_message_filter.cc +++ b/chrome/browser/renderer_host/chrome_render_message_filter.cc @@ -14,7 +14,7 @@ #include "chrome/browser/content_settings/tab_specific_content_settings.h" #if defined(ENABLE_EXTENSIONS) -#include "chrome/browser/guest_view/web_view/web_view_guest.h" +#include "chrome/browser/guest_view/web_view/web_view_permission_helper.h" #include "chrome/browser/guest_view/web_view/web_view_renderer_state.h" #endif @@ -208,14 +208,16 @@ void ChromeRenderMessageFilter::OnRequestFileSystemAccessSync( WebViewRendererState::GetInstance()->IsGuest(render_process_id_); if (is_web_view_guest) { // Record access to file system for potential display in UI. - BrowserThread::PostTask(BrowserThread::UI, - FROM_HERE, - base::Bind(&WebViewGuest::FileSystemAccessedSync, - render_process_id_, - render_frame_id, - origin_url, - !allowed, - reply_msg)); + BrowserThread::PostTask( + BrowserThread::UI, + FROM_HERE, + base::Bind(&ChromeRenderMessageFilter:: + FileSystemAccessedSyncOnUIThread, + render_process_id_, + render_frame_id, + origin_url, + !allowed, + reply_msg)); return; } #endif @@ -233,6 +235,24 @@ void ChromeRenderMessageFilter::OnRequestFileSystemAccessSync( !allowed)); } +#if defined(ENABLE_EXTENSIONS) +void ChromeRenderMessageFilter::FileSystemAccessedSyncOnUIThread( + int render_process_id, + int render_frame_id, + const GURL& url, + bool blocked_by_policy, + IPC::Message* reply_msg) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + WebViewPermissionHelper* web_view_permission_helper = + WebViewPermissionHelper::FromFrameID(render_process_id, render_frame_id); + web_view_permission_helper->FileSystemAccessedSync(render_process_id, + render_frame_id, + url, + blocked_by_policy, + reply_msg); +} +#endif + void ChromeRenderMessageFilter::OnRequestFileSystemAccessAsync( int render_frame_id, int request_id, @@ -248,14 +268,16 @@ void ChromeRenderMessageFilter::OnRequestFileSystemAccessAsync( WebViewRendererState::GetInstance()->IsGuest(render_process_id_); if (is_web_view_guest) { // Record access to file system for potential display in UI. - BrowserThread::PostTask(BrowserThread::UI, - FROM_HERE, - base::Bind(&WebViewGuest::FileSystemAccessedAsync, - render_process_id_, - render_frame_id, - request_id, - origin_url, - !allowed)); + BrowserThread::PostTask( + BrowserThread::UI, + FROM_HERE, + base::Bind(&ChromeRenderMessageFilter:: + FileSystemAccessedAsyncOnUIThread, + render_process_id_, + render_frame_id, + request_id, + origin_url, + !allowed)); return; } #endif @@ -273,6 +295,24 @@ void ChromeRenderMessageFilter::OnRequestFileSystemAccessAsync( !allowed)); } +#if defined(ENABLE_EXTENSIONS) +void ChromeRenderMessageFilter::FileSystemAccessedAsyncOnUIThread( + int render_process_id, + int render_frame_id, + int request_id, + const GURL& url, + bool blocked_by_policy) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + WebViewPermissionHelper* web_view_permission_helper = + WebViewPermissionHelper::FromFrameID(render_process_id, render_frame_id); + web_view_permission_helper->FileSystemAccessedAsync(render_process_id, + render_frame_id, + request_id, + url, + blocked_by_policy); +} +#endif + void ChromeRenderMessageFilter::OnAllowIndexedDB(int render_frame_id, const GURL& origin_url, const GURL& top_origin_url, diff --git a/chrome/browser/renderer_host/chrome_render_message_filter.h b/chrome/browser/renderer_host/chrome_render_message_filter.h index 3bf3490..3dc8bdc 100644 --- a/chrome/browser/renderer_host/chrome_render_message_filter.h +++ b/chrome/browser/renderer_host/chrome_render_message_filter.h @@ -76,10 +76,27 @@ class ChromeRenderMessageFilter : public content::BrowserMessageFilter { const GURL& origin_url, const GURL& top_origin_url, IPC::Message* message); +#if defined(ENABLE_EXTENSIONS) + static void FileSystemAccessedSyncOnUIThread( + int render_process_id, + int render_frame_id, + const GURL& url, + bool blocked_by_policy, + IPC::Message* reply_msg); +#endif void OnRequestFileSystemAccessAsync(int render_frame_id, int request_id, const GURL& origin_url, const GURL& top_origin_url); +#if defined(ENABLE_EXTENSIONS) + static void FileSystemAccessedAsyncOnUIThread( + int render_process_id, + int render_frame_id, + int request_id, + const GURL& url, + bool blocked_by_policy); +#endif + void OnAllowIndexedDB(int render_frame_id, const GURL& origin_url, const GURL& top_origin_url, diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index c098d87..34e7846 100644 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -1526,6 +1526,8 @@ 'browser/guest_view/web_view/web_view_guest.cc', 'browser/guest_view/web_view/web_view_guest.h', 'browser/guest_view/web_view/web_view_permission_types.h', + 'browser/guest_view/web_view/web_view_permission_helper.cc', + 'browser/guest_view/web_view/web_view_permission_helper.h', 'browser/guest_view/web_view/web_view_renderer_state.cc', 'browser/guest_view/web_view/web_view_renderer_state.h', 'browser/infobars/infobar_extension_api.cc', @@ -1761,8 +1763,6 @@ ], # See also the plugin_installation_sources list below. 'chrome_browser_plugins_sources': [ - 'browser/guest_view/web_view/plugin_permission_helper.cc', - 'browser/guest_view/web_view/plugin_permission_helper.h', 'browser/metrics/plugin_metrics_provider.cc', 'browser/metrics/plugin_metrics_provider.h', 'browser/pepper_broker_infobar_delegate.cc', |