[WTF] Import std::optional reference implementation as WTF::Optional
[WebKit-https.git] / Source / WebKit2 / UIProcess / UserMediaPermissionRequestManagerProxy.cpp
1 /*
2  * Copyright (C) 2014 Igalia S.L.
3  * Copyright (C) 2016 Apple Inc. All rights reserved.
4  *
5  *  This library is free software; you can redistribute it and/or
6  *  modify it under the terms of the GNU Lesser General Public
7  *  License as published by the Free Software Foundation; either
8  *  version 2 of the License, or (at your option) any later version.
9  *
10  *  This library is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  *  Lesser General Public License for more details.
14  *
15  *  You should have received a copy of the GNU Lesser General Public
16  *  License along with this library; if not, write to the Free Software
17  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
18  */
19
20 #include "config.h"
21 #include "UserMediaPermissionRequestManagerProxy.h"
22
23 #include "APISecurityOrigin.h"
24 #include "APIUIClient.h"
25 #include "WebPageMessages.h"
26 #include "WebPageProxy.h"
27 #include "WebProcessProxy.h"
28 #include <WebCore/MediaConstraintsImpl.h>
29 #include <WebCore/MockRealtimeMediaSourceCenter.h>
30 #include <WebCore/RealtimeMediaSource.h>
31 #include <WebCore/SecurityOriginData.h>
32
33 using namespace WebCore;
34
35 namespace WebKit {
36
37 UserMediaPermissionRequestManagerProxy::UserMediaPermissionRequestManagerProxy(WebPageProxy& page)
38     : m_page(page)
39 {
40 }
41
42 void UserMediaPermissionRequestManagerProxy::invalidateRequests()
43 {
44     for (auto& request : m_pendingUserMediaRequests.values())
45         request->invalidate();
46     m_pendingUserMediaRequests.clear();
47
48     for (auto& request : m_pendingDeviceRequests.values())
49         request->invalidate();
50     m_pendingDeviceRequests.clear();
51
52     m_pageSandboxExtensionsGranted.clear();
53 }
54
55 Ref<UserMediaPermissionRequestProxy> UserMediaPermissionRequestManagerProxy::createRequest(uint64_t userMediaID, const Vector<String>& audioDeviceUIDs, const Vector<String>& videoDeviceUIDs)
56 {
57     Ref<UserMediaPermissionRequestProxy> request = UserMediaPermissionRequestProxy::create(*this, userMediaID, audioDeviceUIDs, videoDeviceUIDs);
58     m_pendingUserMediaRequests.add(userMediaID, request.ptr());
59     return request;
60 }
61
62 Ref<UserMediaPermissionRequestProxy> UserMediaPermissionRequestManagerProxy::createRequest(uint64_t userMediaID)
63 {
64     Ref<UserMediaPermissionRequestProxy> request = UserMediaPermissionRequestProxy::create(*this, userMediaID, Vector<String>(), Vector<String>());
65     m_pendingUserMediaRequests.add(userMediaID, request.ptr());
66     return request;
67 }
68
69 #if ENABLE(MEDIA_STREAM)
70 static uint64_t toWebCore(UserMediaPermissionRequestProxy::UserMediaAccessDenialReason reason)
71 {
72     switch (reason) {
73     case UserMediaPermissionRequestProxy::UserMediaAccessDenialReason::NoConstraints:
74         return static_cast<uint64_t>(UserMediaRequest::MediaAccessDenialReason::NoConstraints);
75         break;
76     case UserMediaPermissionRequestProxy::UserMediaAccessDenialReason::UserMediaDisabled:
77         return static_cast<uint64_t>(UserMediaRequest::MediaAccessDenialReason::UserMediaDisabled);
78         break;
79     case UserMediaPermissionRequestProxy::UserMediaAccessDenialReason::NoCaptureDevices:
80         return static_cast<uint64_t>(UserMediaRequest::MediaAccessDenialReason::NoCaptureDevices);
81         break;
82     case UserMediaPermissionRequestProxy::UserMediaAccessDenialReason::InvalidConstraint:
83         return static_cast<uint64_t>(UserMediaRequest::MediaAccessDenialReason::InvalidConstraint);
84         break;
85     case UserMediaPermissionRequestProxy::UserMediaAccessDenialReason::HardwareError:
86         return static_cast<uint64_t>(UserMediaRequest::MediaAccessDenialReason::HardwareError);
87         break;
88     case UserMediaPermissionRequestProxy::UserMediaAccessDenialReason::PermissionDenied:
89         return static_cast<uint64_t>(UserMediaRequest::MediaAccessDenialReason::PermissionDenied);
90         break;
91     case UserMediaPermissionRequestProxy::UserMediaAccessDenialReason::OtherFailure:
92         return static_cast<uint64_t>(UserMediaRequest::MediaAccessDenialReason::OtherFailure);
93         break;
94     }
95     
96     ASSERT_NOT_REACHED();
97     return static_cast<uint64_t>(UserMediaRequest::MediaAccessDenialReason::OtherFailure);
98 }
99 #endif
100
101 void UserMediaPermissionRequestManagerProxy::userMediaAccessWasDenied(uint64_t userMediaID, UserMediaPermissionRequestProxy::UserMediaAccessDenialReason reason)
102 {
103     if (!m_page.isValid())
104         return;
105
106     if (!m_pendingUserMediaRequests.take(userMediaID))
107         return;
108
109     denyRequest(userMediaID, reason, "");
110 }
111
112 void UserMediaPermissionRequestManagerProxy::denyRequest(uint64_t userMediaID, UserMediaPermissionRequestProxy::UserMediaAccessDenialReason reason, const String& invalidConstraint)
113 {
114     ASSERT(m_page.isValid());
115
116 #if ENABLE(MEDIA_STREAM)
117     m_page.process().send(Messages::WebPage::UserMediaAccessWasDenied(userMediaID, toWebCore(reason), invalidConstraint), m_page.pageID());
118 #else
119     UNUSED_PARAM(reason);
120     UNUSED_PARAM(invalidConstraint);
121 #endif
122 }
123
124 void UserMediaPermissionRequestManagerProxy::userMediaAccessWasGranted(uint64_t userMediaID, const String& audioDeviceUID, const String& videoDeviceUID)
125 {
126     ASSERT(!audioDeviceUID.isEmpty() || !videoDeviceUID.isEmpty());
127
128     if (!m_page.isValid())
129         return;
130
131     if (!m_pendingUserMediaRequests.take(userMediaID))
132         return;
133
134 #if ENABLE(MEDIA_STREAM)
135     size_t extensionCount = 0;
136     unsigned requiredExtensions = SandboxExtensionsGranted::None;
137     if (!audioDeviceUID.isEmpty()) {
138         requiredExtensions |= SandboxExtensionsGranted::Audio;
139         extensionCount++;
140     }
141     if (!videoDeviceUID.isEmpty()) {
142         requiredExtensions |= SandboxExtensionsGranted::Video;
143         extensionCount++;
144     }
145
146     unsigned currentExtensions = m_pageSandboxExtensionsGranted.get(m_page.pageID());
147     if (!(requiredExtensions & currentExtensions)) {
148         ASSERT(extensionCount);
149         m_pageSandboxExtensionsGranted.set(m_page.pageID(), requiredExtensions | currentExtensions);
150         SandboxExtension::HandleArray handles;
151         handles.allocate(extensionCount);
152         if (!videoDeviceUID.isEmpty())
153             SandboxExtension::createHandleForGenericExtension("com.apple.webkit.camera", handles[--extensionCount]);
154         if (!audioDeviceUID.isEmpty())
155             SandboxExtension::createHandleForGenericExtension("com.apple.webkit.microphone", handles[--extensionCount]);
156         m_page.process().send(Messages::WebPage::GrantUserMediaDevicesSandboxExtension(handles), m_page.pageID());
157     }
158
159     m_page.process().send(Messages::WebPage::UserMediaAccessWasGranted(userMediaID, audioDeviceUID, videoDeviceUID), m_page.pageID());
160 #else
161     UNUSED_PARAM(audioDeviceUID);
162     UNUSED_PARAM(videoDeviceUID);
163 #endif
164 }
165
166 void UserMediaPermissionRequestManagerProxy::requestUserMediaPermissionForFrame(uint64_t userMediaID, uint64_t frameID, String userMediaDocumentOriginIdentifier, String topLevelDocumentOriginIdentifier, const WebCore::MediaConstraintsData& audioConstraintsData, const WebCore::MediaConstraintsData& videoConstraintsData)
167 {
168 #if ENABLE(MEDIA_STREAM)
169     auto invalidHandler = [this, userMediaID](const String& invalidConstraint) {
170         if (!m_page.isValid())
171             return;
172
173         denyRequest(userMediaID, UserMediaPermissionRequestProxy::UserMediaAccessDenialReason::InvalidConstraint, invalidConstraint);
174     };
175
176     auto validHandler = [this, userMediaID, frameID, userMediaDocumentOriginIdentifier, topLevelDocumentOriginIdentifier](const Vector<String>&& audioDeviceUIDs, const Vector<String>&& videoDeviceUIDs) {
177         if (!m_page.isValid())
178             return;
179
180         if (videoDeviceUIDs.isEmpty() && audioDeviceUIDs.isEmpty()) {
181             denyRequest(userMediaID, UserMediaPermissionRequestProxy::UserMediaAccessDenialReason::NoConstraints, "");
182             return;
183         }
184
185         auto userMediaOrigin = API::SecurityOrigin::create(SecurityOriginData::fromDatabaseIdentifier(userMediaDocumentOriginIdentifier)->securityOrigin());
186         auto topLevelOrigin = API::SecurityOrigin::create(SecurityOriginData::fromDatabaseIdentifier(topLevelDocumentOriginIdentifier)->securityOrigin());
187         auto request = createRequest(userMediaID, audioDeviceUIDs, videoDeviceUIDs);
188
189         if (!m_page.uiClient().decidePolicyForUserMediaPermissionRequest(m_page, *m_page.process().webFrame(frameID), *userMediaOrigin.get(), *topLevelOrigin.get(), request.get())) {
190             m_pendingUserMediaRequests.take(userMediaID);
191             request->deny(UserMediaPermissionRequestProxy::UserMediaAccessDenialReason::UserMediaDisabled);
192         }
193     };
194
195     auto audioConstraints = MediaConstraintsImpl::create(audioConstraintsData);
196     auto videoConstraints = MediaConstraintsImpl::create(videoConstraintsData);
197
198     syncWithWebCorePrefs();
199     RealtimeMediaSourceCenter::singleton().validateRequestConstraints(validHandler, invalidHandler, audioConstraints, videoConstraints);
200 #else
201     UNUSED_PARAM(userMediaID);
202     UNUSED_PARAM(frameID);
203     UNUSED_PARAM(userMediaDocumentOriginIdentifier);
204     UNUSED_PARAM(topLevelDocumentOriginIdentifier);
205     UNUSED_PARAM(audioConstraintsData);
206     UNUSED_PARAM(videoConstraintsData);
207 #endif
208 }
209
210 void UserMediaPermissionRequestManagerProxy::enumerateMediaDevicesForFrame(uint64_t userMediaID, uint64_t frameID, String userMediaDocumentOriginIdentifier, String topLevelDocumentOriginIdentifier)
211 {
212 #if ENABLE(MEDIA_STREAM)
213     auto request = UserMediaPermissionCheckProxy::create(*this, userMediaID);
214     m_pendingDeviceRequests.add(userMediaID, request.ptr());
215
216     auto userMediaOrigin = API::SecurityOrigin::create(SecurityOriginData::fromDatabaseIdentifier(userMediaDocumentOriginIdentifier).value_or(SecurityOriginData()).securityOrigin());
217     auto topLevelOrigin = API::SecurityOrigin::create(SecurityOriginData::fromDatabaseIdentifier(topLevelDocumentOriginIdentifier).value_or(SecurityOriginData()).securityOrigin());
218
219     if (!m_page.uiClient().checkUserMediaPermissionForOrigin(m_page, *m_page.process().webFrame(frameID), *userMediaOrigin.get(), *topLevelOrigin.get(), request.get())) {
220         m_pendingDeviceRequests.take(userMediaID);
221         m_page.process().send(Messages::WebPage::DidCompleteMediaDeviceEnumeration(userMediaID, Vector<WebCore::CaptureDevice>(), emptyString(), false), m_page.pageID());
222     }
223 #else
224     UNUSED_PARAM(userMediaID);
225     UNUSED_PARAM(frameID);
226     UNUSED_PARAM(userMediaDocumentOriginIdentifier);
227     UNUSED_PARAM(topLevelDocumentOriginIdentifier);
228 #endif
229 }
230
231 void UserMediaPermissionRequestManagerProxy::didCompleteUserMediaPermissionCheck(uint64_t userMediaID, const String& deviceIdentifierHashSalt, bool originHasPersistentAccess)
232 {
233     if (!m_page.isValid())
234         return;
235
236     if (!m_pendingDeviceRequests.take(userMediaID))
237         return;
238
239 #if ENABLE(MEDIA_STREAM)
240     syncWithWebCorePrefs();
241     auto deviceInfo = RealtimeMediaSourceCenter::singleton().getMediaStreamDevices();
242     m_page.process().send(Messages::WebPage::DidCompleteMediaDeviceEnumeration(userMediaID, deviceInfo, deviceIdentifierHashSalt, originHasPersistentAccess), m_page.pageID());
243 #else
244     UNUSED_PARAM(deviceIdentifierHashSalt);
245     UNUSED_PARAM(originHasPersistentAccess);
246 #endif
247 }
248
249 void UserMediaPermissionRequestManagerProxy::syncWithWebCorePrefs() const
250 {
251 #if ENABLE(MEDIA_STREAM)
252     // Enable/disable the mock capture devices for the UI process as per the WebCore preferences. Note that
253     // this is a noop if the preference hasn't changed since the last time this was called.
254     bool mockDevicesEnabled = m_page.preferences().mockCaptureDevicesEnabled();
255     WebCore::MockRealtimeMediaSourceCenter::setMockRealtimeMediaSourceCenterEnabled(mockDevicesEnabled);
256 #endif
257 }
258
259 } // namespace WebKit