~zaspire/oxide/push-messaging

« back to all changes in this revision

Viewing changes to shared/browser/permissions/oxide_permission_request_dispatcher.cc

  • Committer: Chris Coulson
  • Date: 2015-06-04 13:21:49 UTC
  • mfrom: (1103.2.4 permissions)
  • Revision ID: chris.coulson@canonical.com-20150604132149-lgnyd0lduibnwbjr
Land some refactoring of permissions, which starts to decouple it from WebView in to separate classes

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// vim:expandtab:shiftwidth=2:tabstop=2:
 
2
// Copyright (C) 2014-2015 Canonical Ltd.
 
3
 
 
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.
 
8
 
 
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.
 
13
 
 
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
 
17
 
 
18
#include "oxide_permission_request_dispatcher.h"
 
19
 
 
20
#include <algorithm>
 
21
 
 
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"
 
29
#include "url/gurl.h"
 
30
 
 
31
#include "shared/browser/oxide_web_frame.h"
 
32
 
 
33
#include "oxide_permission_request.h"
 
34
#include "oxide_permission_request_dispatcher_client.h"
 
35
#include "oxide_permission_request_id.h"
 
36
 
 
37
namespace oxide {
 
38
 
 
39
DEFINE_WEB_CONTENTS_USER_DATA_KEY(PermissionRequestDispatcher);
 
40
 
 
41
class PermissionRequestDispatcher::IteratorGuard {
 
42
 public:
 
43
  IteratorGuard(PermissionRequestDispatcher* dispatcher);
 
44
  ~IteratorGuard();
 
45
 
 
46
 private:
 
47
  base::WeakPtr<PermissionRequestDispatcher> dispatcher_;
 
48
  bool iterating_original_;
 
49
 
 
50
  DISALLOW_COPY_AND_ASSIGN(IteratorGuard);
 
51
};
 
52
 
 
53
PermissionRequestDispatcher::IteratorGuard::IteratorGuard(
 
54
    PermissionRequestDispatcher* dispatcher)
 
55
    : dispatcher_(dispatcher->weak_factory_.GetWeakPtr()),
 
56
      iterating_original_(dispatcher->iterating_) {
 
57
  dispatcher->iterating_ = true;
 
58
}
 
59
 
 
60
PermissionRequestDispatcher::IteratorGuard::~IteratorGuard() {
 
61
  if (!dispatcher_) {
 
62
    return;
 
63
  }
 
64
 
 
65
  dispatcher_->iterating_ = iterating_original_;
 
66
  if (!dispatcher_->iterating_) {
 
67
    dispatcher_->Compact();
 
68
  }
 
69
}
 
70
 
 
71
PermissionRequestDispatcher::PermissionRequestDispatcher(
 
72
    content::WebContents* contents)
 
73
    : contents_(contents),
 
74
      client_(nullptr),
 
75
      iterating_(false),
 
76
      weak_factory_(this) {}
 
77
 
 
78
void PermissionRequestDispatcher::AddPendingRequest(PermissionRequest* request) {
 
79
  DCHECK(!request->dispatcher_);
 
80
  DCHECK(std::find(pending_requests_.begin(),
 
81
                   pending_requests_.end(),
 
82
                   request) ==
 
83
         pending_requests_.end());
 
84
 
 
85
  request->dispatcher_ = this;
 
86
  pending_requests_.push_back(request);
 
87
}
 
88
 
 
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(),
 
94
                      request);
 
95
  DCHECK(it != pending_requests_.end());
 
96
  if (iterating_) {
 
97
    *it = nullptr;
 
98
  } else {
 
99
    pending_requests_.erase(it);
 
100
  }
 
101
 
 
102
  request->dispatcher_ = nullptr;
 
103
}
 
104
 
 
105
void PermissionRequestDispatcher::Compact() {
 
106
  DCHECK(!iterating_);
 
107
 
 
108
  pending_requests_.erase(
 
109
      std::remove(pending_requests_.begin(), pending_requests_.end(), nullptr),
 
110
      pending_requests_.end());
 
111
}
 
112
 
 
113
PermissionRequestDispatcher::~PermissionRequestDispatcher() {
 
114
  CancelPendingRequests();
 
115
}
 
116
 
 
117
void PermissionRequestDispatcher::RequestPermission(
 
118
    content::PermissionType permission,
 
119
    int request_id,
 
120
    const GURL& requesting_origin,
 
121
    const base::Callback<void(content::PermissionStatus)>& callback) {
 
122
  if (!client_) {
 
123
    callback.Run(content::PERMISSION_STATUS_DENIED);
 
124
    return;
 
125
  }
 
126
 
 
127
  PermissionRequestID id(
 
128
      contents_->GetRenderProcessHost()->GetID(),
 
129
      contents_->GetRenderViewHost()->GetRoutingID(),
 
130
      request_id,
 
131
      requesting_origin);
 
132
 
 
133
  scoped_ptr<SimplePermissionRequest> request(
 
134
      new SimplePermissionRequest(
 
135
        id,
 
136
        requesting_origin,
 
137
        contents_->GetLastCommittedURL().GetOrigin(),
 
138
        callback));
 
139
  AddPendingRequest(request.get());
 
140
 
 
141
  switch (permission) {
 
142
    case content::PermissionType::GEOLOCATION:
 
143
      client_->RequestGeolocationPermission(request.Pass());
 
144
      break;
 
145
    default:
 
146
      NOTIMPLEMENTED();
 
147
      break;
 
148
  }
 
149
}
 
150
 
 
151
void PermissionRequestDispatcher::CancelPermissionRequest(
 
152
    content::PermissionType permission,
 
153
    int request_id,
 
154
    const GURL& requesting_origin) {
 
155
  PermissionRequestID id(
 
156
      contents_->GetRenderProcessHost()->GetID(),
 
157
      contents_->GetRenderViewHost()->GetRoutingID(),
 
158
      request_id,
 
159
      requesting_origin);
 
160
 
 
161
  IteratorGuard guard(this);
 
162
  for (auto request : pending_requests_) {
 
163
    if (!request) {
 
164
      continue;
 
165
    }
 
166
    if (request->request_id_ != id) {
 
167
      continue;
 
168
    }
 
169
    request->Cancel();
 
170
  }
 
171
}
 
172
 
 
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,
 
181
                 nullptr);
 
182
    return;
 
183
  }
 
184
 
 
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,
 
189
                 nullptr);
 
190
    return;
 
191
  }
 
192
 
 
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,
 
200
                 nullptr);
 
201
    return;
 
202
  }
 
203
 
 
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,
 
210
                 nullptr);
 
211
    return;
 
212
  }
 
213
 
 
214
  content::MediaCaptureDevices* devices =
 
215
      content::MediaCaptureDevices::GetInstance();
 
216
 
 
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,
 
221
                 nullptr);
 
222
    return;
 
223
  }
 
224
 
 
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,
 
229
                 nullptr);
 
230
    return;
 
231
  }
 
232
 
 
233
  if (!client_) {
 
234
    callback.Run(content::MediaStreamDevices(),
 
235
                 content::MEDIA_DEVICE_PERMISSION_DENIED,
 
236
                 nullptr);
 
237
    return;
 
238
  }
 
239
 
 
240
  content::RenderFrameHost* rfh =
 
241
      content::RenderFrameHost::FromID(request.render_process_id,
 
242
                                       request.render_frame_id);
 
243
  if (!rfh) {
 
244
    callback.Run(content::MediaStreamDevices(),
 
245
                 content::MEDIA_DEVICE_PERMISSION_DENIED,
 
246
                 nullptr);
 
247
    return;
 
248
  }
 
249
 
 
250
  WebFrame* frame = WebFrame::FromRenderFrameHost(rfh);
 
251
  if (!frame) {
 
252
    callback.Run(content::MediaStreamDevices(),
 
253
                 content::MEDIA_DEVICE_PERMISSION_DENIED,
 
254
                 nullptr);
 
255
    return;
 
256
  }
 
257
 
 
258
  scoped_ptr<MediaAccessPermissionRequest> req(
 
259
      new MediaAccessPermissionRequest(
 
260
        frame,
 
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,
 
265
        callback));
 
266
  AddPendingRequest(req.get());
 
267
 
 
268
  client_->RequestMediaAccessPermission(req.Pass());
 
269
}
 
270
 
 
271
void PermissionRequestDispatcher::CancelPendingRequests() {
 
272
  IteratorGuard guard(this);
 
273
  for (auto request : pending_requests_) {
 
274
    if (!request) {
 
275
      continue;
 
276
    }
 
277
    request->Cancel();
 
278
  }
 
279
}
 
280
 
 
281
void PermissionRequestDispatcher::CancelPendingRequestsForFrame(
 
282
    WebFrame* frame) {
 
283
  DCHECK(frame);
 
284
 
 
285
  IteratorGuard guard(this);
 
286
  for (auto request : pending_requests_) {
 
287
    if (!request) {
 
288
      continue;
 
289
    }
 
290
    if (request->frame_ != frame) {
 
291
      continue;
 
292
    }
 
293
    request->Cancel();
 
294
  }
 
295
}
 
296
 
 
297
} // namespace oxide