1
// vim:expandtab:shiftwidth=2:tabstop=2:
2
// Copyright (C) 2014-2015 Canonical Ltd.
4
// This library is free software; you can redistribute it and/or
5
// modify it under the terms of the GNU Lesser General Public
6
// License as published by the Free Software Foundation; either
7
// version 2.1 of the License, or (at your option) any later version.
9
// This library is distributed in the hope that it will be useful,
10
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
// Lesser General Public License for more details.
14
// You should have received a copy of the GNU Lesser General Public
15
// License along with this library; if not, write to the Free Software
16
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
#include "oxide_permission_request_dispatcher.h"
22
#include "base/logging.h"
23
#include "base/memory/weak_ptr.h"
24
#include "content/public/browser/media_capture_devices.h"
25
#include "content/public/browser/render_frame_host.h"
26
#include "content/public/browser/render_process_host.h"
27
#include "content/public/browser/render_view_host.h"
28
#include "content/public/browser/web_contents.h"
31
#include "shared/browser/oxide_web_frame.h"
33
#include "oxide_permission_request.h"
34
#include "oxide_permission_request_dispatcher_client.h"
35
#include "oxide_permission_request_id.h"
39
DEFINE_WEB_CONTENTS_USER_DATA_KEY(PermissionRequestDispatcher);
41
class PermissionRequestDispatcher::IteratorGuard {
43
IteratorGuard(PermissionRequestDispatcher* dispatcher);
47
base::WeakPtr<PermissionRequestDispatcher> dispatcher_;
48
bool iterating_original_;
50
DISALLOW_COPY_AND_ASSIGN(IteratorGuard);
53
PermissionRequestDispatcher::IteratorGuard::IteratorGuard(
54
PermissionRequestDispatcher* dispatcher)
55
: dispatcher_(dispatcher->weak_factory_.GetWeakPtr()),
56
iterating_original_(dispatcher->iterating_) {
57
dispatcher->iterating_ = true;
60
PermissionRequestDispatcher::IteratorGuard::~IteratorGuard() {
65
dispatcher_->iterating_ = iterating_original_;
66
if (!dispatcher_->iterating_) {
67
dispatcher_->Compact();
71
PermissionRequestDispatcher::PermissionRequestDispatcher(
72
content::WebContents* contents)
73
: contents_(contents),
76
weak_factory_(this) {}
78
void PermissionRequestDispatcher::AddPendingRequest(PermissionRequest* request) {
79
DCHECK(!request->dispatcher_);
80
DCHECK(std::find(pending_requests_.begin(),
81
pending_requests_.end(),
83
pending_requests_.end());
85
request->dispatcher_ = this;
86
pending_requests_.push_back(request);
89
void PermissionRequestDispatcher::RemovePendingRequest(
90
PermissionRequest* request) {
91
DCHECK_EQ(request->dispatcher_, this);
92
auto it = std::find(pending_requests_.begin(),
93
pending_requests_.end(),
95
DCHECK(it != pending_requests_.end());
99
pending_requests_.erase(it);
102
request->dispatcher_ = nullptr;
105
void PermissionRequestDispatcher::Compact() {
108
pending_requests_.erase(
109
std::remove(pending_requests_.begin(), pending_requests_.end(), nullptr),
110
pending_requests_.end());
113
PermissionRequestDispatcher::~PermissionRequestDispatcher() {
114
CancelPendingRequests();
117
void PermissionRequestDispatcher::RequestPermission(
118
content::PermissionType permission,
120
const GURL& requesting_origin,
121
const base::Callback<void(content::PermissionStatus)>& callback) {
123
callback.Run(content::PERMISSION_STATUS_DENIED);
127
PermissionRequestID id(
128
contents_->GetRenderProcessHost()->GetID(),
129
contents_->GetRenderViewHost()->GetRoutingID(),
133
scoped_ptr<SimplePermissionRequest> request(
134
new SimplePermissionRequest(
137
contents_->GetLastCommittedURL().GetOrigin(),
139
AddPendingRequest(request.get());
141
switch (permission) {
142
case content::PermissionType::GEOLOCATION:
143
client_->RequestGeolocationPermission(request.Pass());
151
void PermissionRequestDispatcher::CancelPermissionRequest(
152
content::PermissionType permission,
154
const GURL& requesting_origin) {
155
PermissionRequestID id(
156
contents_->GetRenderProcessHost()->GetID(),
157
contents_->GetRenderViewHost()->GetRoutingID(),
161
IteratorGuard guard(this);
162
for (auto request : pending_requests_) {
166
if (request->request_id_ != id) {
173
void PermissionRequestDispatcher::RequestMediaAccessPermission(
174
const content::MediaStreamRequest& request,
175
const content::MediaResponseCallback& callback) {
176
// XXX(chrisccoulson): This logic probably doesn't belong here
177
if (request.video_type == content::MEDIA_DEVICE_AUDIO_OUTPUT ||
178
request.audio_type == content::MEDIA_DEVICE_AUDIO_OUTPUT) {
179
callback.Run(content::MediaStreamDevices(),
180
content::MEDIA_DEVICE_INVALID_STATE,
185
if (request.video_type == content::MEDIA_NO_SERVICE &&
186
request.audio_type == content::MEDIA_NO_SERVICE) {
187
callback.Run(content::MediaStreamDevices(),
188
content::MEDIA_DEVICE_INVALID_STATE,
193
// Desktop / tab capture not supported
194
if (request.video_type == content::MEDIA_DESKTOP_VIDEO_CAPTURE ||
195
request.audio_type == content::MEDIA_DESKTOP_AUDIO_CAPTURE ||
196
request.video_type == content::MEDIA_TAB_VIDEO_CAPTURE ||
197
request.audio_type == content::MEDIA_TAB_AUDIO_CAPTURE) {
198
callback.Run(content::MediaStreamDevices(),
199
content::MEDIA_DEVICE_NOT_SUPPORTED,
204
// Only MEDIA_GENERATE_STREAM is valid here - MEDIA_DEVICE_ACCESS doesn't
205
// come from media stream, MEDIA_ENUMERATE_DEVICES doesn't trigger a
206
// permission request and MEDIA_OPEN_DEVICE is used from pepper
207
if (request.request_type != content::MEDIA_GENERATE_STREAM) {
208
callback.Run(content::MediaStreamDevices(),
209
content::MEDIA_DEVICE_NOT_SUPPORTED,
214
content::MediaCaptureDevices* devices =
215
content::MediaCaptureDevices::GetInstance();
217
if (request.audio_type == content::MEDIA_DEVICE_AUDIO_CAPTURE &&
218
devices->GetAudioCaptureDevices().empty()) {
219
callback.Run(content::MediaStreamDevices(),
220
content::MEDIA_DEVICE_NO_HARDWARE,
225
if (request.video_type == content::MEDIA_DEVICE_VIDEO_CAPTURE &&
226
devices->GetVideoCaptureDevices().empty()) {
227
callback.Run(content::MediaStreamDevices(),
228
content::MEDIA_DEVICE_NO_HARDWARE,
234
callback.Run(content::MediaStreamDevices(),
235
content::MEDIA_DEVICE_PERMISSION_DENIED,
240
content::RenderFrameHost* rfh =
241
content::RenderFrameHost::FromID(request.render_process_id,
242
request.render_frame_id);
244
callback.Run(content::MediaStreamDevices(),
245
content::MEDIA_DEVICE_PERMISSION_DENIED,
250
WebFrame* frame = WebFrame::FromRenderFrameHost(rfh);
252
callback.Run(content::MediaStreamDevices(),
253
content::MEDIA_DEVICE_PERMISSION_DENIED,
258
scoped_ptr<MediaAccessPermissionRequest> req(
259
new MediaAccessPermissionRequest(
261
request.security_origin,
262
contents_->GetLastCommittedURL().GetOrigin(),
263
request.audio_type == content::MEDIA_DEVICE_AUDIO_CAPTURE,
264
request.video_type == content::MEDIA_DEVICE_VIDEO_CAPTURE,
266
AddPendingRequest(req.get());
268
client_->RequestMediaAccessPermission(req.Pass());
271
void PermissionRequestDispatcher::CancelPendingRequests() {
272
IteratorGuard guard(this);
273
for (auto request : pending_requests_) {
281
void PermissionRequestDispatcher::CancelPendingRequestsForFrame(
285
IteratorGuard guard(this);
286
for (auto request : pending_requests_) {
290
if (request->frame_ != frame) {