Unregister from GCM when the only GCM app is removed
[chromium-blink-merge.git] / extensions / browser / guest_view / web_view / web_view_permission_helper.cc
blobc67042ed26e971244edcca1b01dd024ba71b68a6
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "extensions/browser/guest_view/web_view/web_view_permission_helper.h"
7 #include "content/public/browser/render_process_host.h"
8 #include "content/public/browser/render_view_host.h"
9 #include "content/public/browser/user_metrics.h"
10 #include "extensions/browser/api/extensions_api_client.h"
11 #include "extensions/browser/guest_view/web_view/web_view_constants.h"
12 #include "extensions/browser/guest_view/web_view/web_view_guest.h"
13 #include "extensions/browser/guest_view/web_view/web_view_permission_helper_delegate.h"
14 #include "extensions/browser/guest_view/web_view/web_view_permission_types.h"
16 using content::BrowserPluginGuestDelegate;
17 using content::RenderViewHost;
19 namespace extensions {
21 namespace {
22 static std::string PermissionTypeToString(WebViewPermissionType type) {
23 switch (type) {
24 case WEB_VIEW_PERMISSION_TYPE_DOWNLOAD:
25 return webview::kPermissionTypeDownload;
26 case WEB_VIEW_PERMISSION_TYPE_FILESYSTEM:
27 return webview::kPermissionTypeFileSystem;
28 case WEB_VIEW_PERMISSION_TYPE_GEOLOCATION:
29 return webview::kPermissionTypeGeolocation;
30 case WEB_VIEW_PERMISSION_TYPE_JAVASCRIPT_DIALOG:
31 return webview::kPermissionTypeDialog;
32 case WEB_VIEW_PERMISSION_TYPE_LOAD_PLUGIN:
33 return webview::kPermissionTypeLoadPlugin;
34 case WEB_VIEW_PERMISSION_TYPE_MEDIA:
35 return webview::kPermissionTypeMedia;
36 case WEB_VIEW_PERMISSION_TYPE_NEW_WINDOW:
37 return webview::kPermissionTypeNewWindow;
38 case WEB_VIEW_PERMISSION_TYPE_POINTER_LOCK:
39 return webview::kPermissionTypePointerLock;
40 default:
41 NOTREACHED();
42 return std::string();
46 // static
47 void RecordUserInitiatedUMA(
48 const WebViewPermissionHelper::PermissionResponseInfo& info,
49 bool allow) {
50 if (allow) {
51 // Note that |allow| == true means the embedder explicitly allowed the
52 // request. For some requests they might still fail. An example of such
53 // scenario would be: an embedder allows geolocation request but doesn't
54 // have geolocation access on its own.
55 switch (info.permission_type) {
56 case WEB_VIEW_PERMISSION_TYPE_DOWNLOAD:
57 content::RecordAction(
58 UserMetricsAction("WebView.PermissionAllow.Download"));
59 break;
60 case WEB_VIEW_PERMISSION_TYPE_FILESYSTEM:
61 content::RecordAction(
62 UserMetricsAction("WebView.PermissionAllow.FileSystem"));
63 break;
64 case WEB_VIEW_PERMISSION_TYPE_GEOLOCATION:
65 content::RecordAction(
66 UserMetricsAction("WebView.PermissionAllow.Geolocation"));
67 break;
68 case WEB_VIEW_PERMISSION_TYPE_JAVASCRIPT_DIALOG:
69 content::RecordAction(
70 UserMetricsAction("WebView.PermissionAllow.JSDialog"));
71 break;
72 case WEB_VIEW_PERMISSION_TYPE_LOAD_PLUGIN:
73 content::RecordAction(
74 UserMetricsAction("WebView.Guest.PermissionAllow.PluginLoad"));
75 case WEB_VIEW_PERMISSION_TYPE_MEDIA:
76 content::RecordAction(
77 UserMetricsAction("WebView.PermissionAllow.Media"));
78 break;
79 case WEB_VIEW_PERMISSION_TYPE_NEW_WINDOW:
80 content::RecordAction(
81 UserMetricsAction("BrowserPlugin.PermissionAllow.NewWindow"));
82 break;
83 case WEB_VIEW_PERMISSION_TYPE_POINTER_LOCK:
84 content::RecordAction(
85 UserMetricsAction("WebView.PermissionAllow.PointerLock"));
86 break;
87 default:
88 break;
90 } else {
91 switch (info.permission_type) {
92 case WEB_VIEW_PERMISSION_TYPE_DOWNLOAD:
93 content::RecordAction(
94 UserMetricsAction("WebView.PermissionDeny.Download"));
95 break;
96 case WEB_VIEW_PERMISSION_TYPE_FILESYSTEM:
97 content::RecordAction(
98 UserMetricsAction("WebView.PermissionDeny.FileSystem"));
99 break;
100 case WEB_VIEW_PERMISSION_TYPE_GEOLOCATION:
101 content::RecordAction(
102 UserMetricsAction("WebView.PermissionDeny.Geolocation"));
103 break;
104 case WEB_VIEW_PERMISSION_TYPE_JAVASCRIPT_DIALOG:
105 content::RecordAction(
106 UserMetricsAction("WebView.PermissionDeny.JSDialog"));
107 break;
108 case WEB_VIEW_PERMISSION_TYPE_LOAD_PLUGIN:
109 content::RecordAction(
110 UserMetricsAction("WebView.Guest.PermissionDeny.PluginLoad"));
111 break;
112 case WEB_VIEW_PERMISSION_TYPE_MEDIA:
113 content::RecordAction(
114 UserMetricsAction("WebView.PermissionDeny.Media"));
115 break;
116 case WEB_VIEW_PERMISSION_TYPE_NEW_WINDOW:
117 content::RecordAction(
118 UserMetricsAction("BrowserPlugin.PermissionDeny.NewWindow"));
119 break;
120 case WEB_VIEW_PERMISSION_TYPE_POINTER_LOCK:
121 content::RecordAction(
122 UserMetricsAction("WebView.PermissionDeny.PointerLock"));
123 break;
124 default:
125 break;
130 } // namespace
132 WebViewPermissionHelper::WebViewPermissionHelper(WebViewGuest* web_view_guest)
133 : content::WebContentsObserver(web_view_guest->web_contents()),
134 next_permission_request_id_(guestview::kInstanceIDNone),
135 web_view_guest_(web_view_guest),
136 weak_factory_(this) {
137 web_view_permission_helper_delegate_.reset(
138 ExtensionsAPIClient::Get()->CreateWebViewPermissionHelperDelegate(
139 this));
142 WebViewPermissionHelper::~WebViewPermissionHelper() {
145 // static
146 WebViewPermissionHelper* WebViewPermissionHelper::FromFrameID(
147 int render_process_id,
148 int render_frame_id) {
149 WebViewGuest* web_view_guest = WebViewGuest::FromFrameID(
150 render_process_id, render_frame_id);
151 if (!web_view_guest) {
152 return NULL;
154 return web_view_guest->web_view_permission_helper_.get();
157 // static
158 WebViewPermissionHelper* WebViewPermissionHelper::FromWebContents(
159 content::WebContents* web_contents) {
160 WebViewGuest* web_view_guest = WebViewGuest::FromWebContents(web_contents);
161 if (!web_view_guest)
162 return NULL;
163 return web_view_guest->web_view_permission_helper_.get();
166 #if defined(ENABLE_PLUGINS)
167 bool WebViewPermissionHelper::OnMessageReceived(
168 const IPC::Message& message,
169 content::RenderFrameHost* render_frame_host) {
170 return web_view_permission_helper_delegate_->OnMessageReceived(
171 message, render_frame_host);
174 bool WebViewPermissionHelper::OnMessageReceived(const IPC::Message& message) {
175 return web_view_permission_helper_delegate_->OnMessageReceived(message);
177 #endif // defined(ENABLE_PLUGINS)
179 void WebViewPermissionHelper::RequestMediaAccessPermission(
180 content::WebContents* source,
181 const content::MediaStreamRequest& request,
182 const content::MediaResponseCallback& callback) {
183 base::DictionaryValue request_info;
184 request_info.SetString(guestview::kUrl, request.security_origin.spec());
185 RequestPermission(
186 WEB_VIEW_PERMISSION_TYPE_MEDIA,
187 request_info,
188 base::Bind(&WebViewPermissionHelper::OnMediaPermissionResponse,
189 weak_factory_.GetWeakPtr(),
190 request,
191 callback),
192 false /* allowed_by_default */);
195 bool WebViewPermissionHelper::CheckMediaAccessPermission(
196 content::WebContents* source,
197 const GURL& security_origin,
198 content::MediaStreamType type) {
199 if (!web_view_guest()->attached() ||
200 !web_view_guest()->embedder_web_contents()->GetDelegate()) {
201 return false;
203 return web_view_guest()
204 ->embedder_web_contents()
205 ->GetDelegate()
206 ->CheckMediaAccessPermission(
207 web_view_guest()->embedder_web_contents(), security_origin, type);
210 void WebViewPermissionHelper::OnMediaPermissionResponse(
211 const content::MediaStreamRequest& request,
212 const content::MediaResponseCallback& callback,
213 bool allow,
214 const std::string& user_input) {
215 if (!allow) {
216 callback.Run(content::MediaStreamDevices(),
217 content::MEDIA_DEVICE_PERMISSION_DENIED,
218 scoped_ptr<content::MediaStreamUI>());
219 return;
221 if (!web_view_guest()->attached() ||
222 !web_view_guest()->embedder_web_contents()->GetDelegate()) {
223 callback.Run(content::MediaStreamDevices(),
224 content::MEDIA_DEVICE_INVALID_STATE,
225 scoped_ptr<content::MediaStreamUI>());
226 return;
229 web_view_guest()
230 ->embedder_web_contents()
231 ->GetDelegate()
232 ->RequestMediaAccessPermission(
233 web_view_guest()->embedder_web_contents(), request, callback);
236 void WebViewPermissionHelper::CanDownload(
237 content::RenderViewHost* render_view_host,
238 const GURL& url,
239 const std::string& request_method,
240 const base::Callback<void(bool)>& callback) {
241 web_view_permission_helper_delegate_->CanDownload(
242 render_view_host, url, request_method, callback);
245 void WebViewPermissionHelper::RequestPointerLockPermission(
246 bool user_gesture,
247 bool last_unlocked_by_target,
248 const base::Callback<void(bool)>& callback) {
249 web_view_permission_helper_delegate_->RequestPointerLockPermission(
250 user_gesture, last_unlocked_by_target, callback);
253 void WebViewPermissionHelper::RequestGeolocationPermission(
254 int bridge_id,
255 const GURL& requesting_frame,
256 bool user_gesture,
257 const base::Callback<void(bool)>& callback) {
258 web_view_permission_helper_delegate_->RequestGeolocationPermission(
259 bridge_id, requesting_frame, user_gesture, callback);
262 void WebViewPermissionHelper::CancelGeolocationPermissionRequest(
263 int bridge_id) {
264 web_view_permission_helper_delegate_->CancelGeolocationPermissionRequest(
265 bridge_id);
268 void WebViewPermissionHelper::RequestFileSystemPermission(
269 const GURL& url,
270 bool allowed_by_default,
271 const base::Callback<void(bool)>& callback) {
272 web_view_permission_helper_delegate_->RequestFileSystemPermission(
273 url, allowed_by_default, callback);
276 void WebViewPermissionHelper::FileSystemAccessedAsync(int render_process_id,
277 int render_frame_id,
278 int request_id,
279 const GURL& url,
280 bool blocked_by_policy) {
281 web_view_permission_helper_delegate_->FileSystemAccessedAsync(
282 render_process_id, render_frame_id, request_id, url, blocked_by_policy);
285 void WebViewPermissionHelper::FileSystemAccessedSync(int render_process_id,
286 int render_frame_id,
287 const GURL& url,
288 bool blocked_by_policy,
289 IPC::Message* reply_msg) {
290 web_view_permission_helper_delegate_->FileSystemAccessedSync(
291 render_process_id, render_frame_id, url, blocked_by_policy, reply_msg);
294 int WebViewPermissionHelper::RequestPermission(
295 WebViewPermissionType permission_type,
296 const base::DictionaryValue& request_info,
297 const PermissionResponseCallback& callback,
298 bool allowed_by_default) {
299 // If there are too many pending permission requests then reject this request.
300 if (pending_permission_requests_.size() >=
301 webview::kMaxOutstandingPermissionRequests) {
302 // Let the stack unwind before we deny the permission request so that
303 // objects held by the permission request are not destroyed immediately
304 // after creation. This is to allow those same objects to be accessed again
305 // in the same scope without fear of use after freeing.
306 base::MessageLoop::current()->PostTask(
307 FROM_HERE,
308 base::Bind(&PermissionResponseCallback::Run,
309 base::Owned(new PermissionResponseCallback(callback)),
310 allowed_by_default,
311 std::string()));
312 return webview::kInvalidPermissionRequestID;
315 int request_id = next_permission_request_id_++;
316 pending_permission_requests_[request_id] =
317 PermissionResponseInfo(callback, permission_type, allowed_by_default);
318 scoped_ptr<base::DictionaryValue> args(request_info.DeepCopy());
319 args->SetInteger(webview::kRequestId, request_id);
320 switch (permission_type) {
321 case WEB_VIEW_PERMISSION_TYPE_NEW_WINDOW: {
322 web_view_guest_->DispatchEventToView(
323 new GuestViewBase::Event(webview::kEventNewWindow, args.Pass()));
324 break;
326 case WEB_VIEW_PERMISSION_TYPE_JAVASCRIPT_DIALOG: {
327 web_view_guest_->DispatchEventToView(
328 new GuestViewBase::Event(webview::kEventDialog, args.Pass()));
329 break;
331 default: {
332 args->SetString(webview::kPermission,
333 PermissionTypeToString(permission_type));
334 web_view_guest_->DispatchEventToView(new GuestViewBase::Event(
335 webview::kEventPermissionRequest, args.Pass()));
336 break;
339 return request_id;
342 WebViewPermissionHelper::SetPermissionResult
343 WebViewPermissionHelper::SetPermission(
344 int request_id,
345 PermissionResponseAction action,
346 const std::string& user_input) {
347 RequestMap::iterator request_itr =
348 pending_permission_requests_.find(request_id);
350 if (request_itr == pending_permission_requests_.end())
351 return SET_PERMISSION_INVALID;
353 const PermissionResponseInfo& info = request_itr->second;
354 bool allow = (action == ALLOW) ||
355 ((action == DEFAULT) && info.allowed_by_default);
357 info.callback.Run(allow, user_input);
359 // Only record user initiated (i.e. non-default) actions.
360 if (action != DEFAULT)
361 RecordUserInitiatedUMA(info, allow);
363 pending_permission_requests_.erase(request_itr);
365 return allow ? SET_PERMISSION_ALLOWED : SET_PERMISSION_DENIED;
368 void WebViewPermissionHelper::CancelPendingPermissionRequest(int request_id) {
369 RequestMap::iterator request_itr =
370 pending_permission_requests_.find(request_id);
372 if (request_itr == pending_permission_requests_.end())
373 return;
375 pending_permission_requests_.erase(request_itr);
378 WebViewPermissionHelper::PermissionResponseInfo::PermissionResponseInfo()
379 : permission_type(WEB_VIEW_PERMISSION_TYPE_UNKNOWN),
380 allowed_by_default(false) {
383 WebViewPermissionHelper::PermissionResponseInfo::PermissionResponseInfo(
384 const PermissionResponseCallback& callback,
385 WebViewPermissionType permission_type,
386 bool allowed_by_default)
387 : callback(callback),
388 permission_type(permission_type),
389 allowed_by_default(allowed_by_default) {
392 WebViewPermissionHelper::PermissionResponseInfo::~PermissionResponseInfo() {
395 } // namespace extensions