Filter out Overconstrainederror.constraint when getUserMedia is not granted
authoryouenn@apple.com <youenn@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 11 Feb 2019 18:49:10 +0000 (18:49 +0000)
committeryouenn@apple.com <youenn@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 11 Feb 2019 18:49:10 +0000 (18:49 +0000)
https://bugs.webkit.org/show_bug.cgi?id=194240

Reviewed by Eric Carlson.

Source/WebKit:

Make sure in UIProcess to filter out constraint if either the page was not granted gum access or it has no persistent access.

Refactor UserMediaPermissionRequestManagerProxy to make the implementation easier to understand.

Covered by added test.

* UIProcess/UserMediaPermissionCheckProxy.cpp:
(WebKit::UserMediaPermissionCheckProxy::setUserMediaAccessInfo):
* UIProcess/UserMediaPermissionRequestManagerProxy.cpp:
(WebKit::UserMediaPermissionRequestManagerProxy::captureDevicesChanged):
(WebKit::UserMediaPermissionRequestManagerProxy::userMediaAccessWasGranted):
(WebKit::UserMediaPermissionRequestManagerProxy::grantAccess):
(WebKit::UserMediaPermissionRequestManagerProxy::getRequestAction):
(WebKit::UserMediaPermissionRequestManagerProxy::requestUserMediaPermissionForFrame):
(WebKit::UserMediaPermissionRequestManagerProxy::processUserMediaPermissionRequest):
(WebKit::UserMediaPermissionRequestManagerProxy::processUserMediaPermissionInvalidRequest):
(WebKit::UserMediaPermissionRequestManagerProxy::processUserMediaPermissionValidRequest):
(WebKit::UserMediaPermissionRequestManagerProxy::getUserMediaPermissionInfo):
(WebKit::UserMediaPermissionRequestManagerProxy::wasGrantedVideoOrAudioAccess):
(WebKit::UserMediaPermissionRequestManagerProxy::computeFilteredDeviceList):
(WebKit::UserMediaPermissionRequestManagerProxy::enumerateMediaDevicesForFrame):
(WebKit::UserMediaPermissionRequestManagerProxy::createPermissionRequest): Deleted.
* UIProcess/UserMediaPermissionRequestManagerProxy.h:
* UIProcess/UserMediaPermissionRequestProxy.h:
(WebKit::UserMediaPermissionRequestProxy::isPending const):
(WebKit::UserMediaPermissionRequestProxy::setEligibleVideoDeviceUIDs):
(WebKit::UserMediaPermissionRequestProxy::setEligibleAudioDeviceUIDs):
(WebKit::UserMediaPermissionRequestProxy::hasAudioDevice const):
(WebKit::UserMediaPermissionRequestProxy::hasVideoDevice const):
(WebKit::UserMediaPermissionRequestProxy::hasPersistentAccess const):
(WebKit::UserMediaPermissionRequestProxy::setHasPersistentAccess):
(WebKit::UserMediaPermissionRequestProxy::userMediaID const):
(WebKit::UserMediaPermissionRequestProxy::topLevelDocumentSecurityOrigin const):
(WebKit::UserMediaPermissionRequestProxy::userMediaDocumentSecurityOrigin const):
(WebKit::UserMediaPermissionRequestProxy::userRequest const):
(WebKit::UserMediaPermissionRequestProxy::setDeviceIdentifierHashSalt):
(WebKit::UserMediaPermissionRequestProxy::deviceIdentifierHashSalt const):
(WebKit::UserMediaPermissionRequestProxy::audioDevice const):
(WebKit::UserMediaPermissionRequestProxy::videoDevice const):
* UIProcess/WebPageProxy.cpp:
(WebKit::WebPageProxy::requestUserMediaPermissionForFrame):
* UIProcess/WebPageProxy.h:

LayoutTests:

* fast/mediastream/overconstrainederror-constraint-expected.txt: Added.
* fast/mediastream/overconstrainederror-constraint.html: Added.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@241270 268f45cc-cd09-0410-ab3c-d52691b4dbfc

LayoutTests/ChangeLog
LayoutTests/fast/mediastream/overconstrainederror-constraint-expected.txt [new file with mode: 0644]
LayoutTests/fast/mediastream/overconstrainederror-constraint.html [new file with mode: 0644]
Source/WebKit/ChangeLog
Source/WebKit/UIProcess/UserMediaPermissionCheckProxy.cpp
Source/WebKit/UIProcess/UserMediaPermissionCheckProxy.h
Source/WebKit/UIProcess/UserMediaPermissionRequestManagerProxy.cpp
Source/WebKit/UIProcess/UserMediaPermissionRequestManagerProxy.h
Source/WebKit/UIProcess/UserMediaPermissionRequestProxy.h
Source/WebKit/UIProcess/WebPageProxy.cpp
Source/WebKit/UIProcess/WebPageProxy.h

index 20e3c41..a492ad1 100644 (file)
@@ -1,3 +1,13 @@
+2019-02-11  Youenn Fablet  <youenn@apple.com>
+
+        Filter out Overconstrainederror.constraint when getUserMedia is not granted
+        https://bugs.webkit.org/show_bug.cgi?id=194240
+
+        Reviewed by Eric Carlson.
+
+        * fast/mediastream/overconstrainederror-constraint-expected.txt: Added.
+        * fast/mediastream/overconstrainederror-constraint.html: Added.
+
 2019-02-11  Truitt Savell  <tsavell@apple.com>
 
         Unreviewed, rolling out r241229.
diff --git a/LayoutTests/fast/mediastream/overconstrainederror-constraint-expected.txt b/LayoutTests/fast/mediastream/overconstrainederror-constraint-expected.txt
new file mode 100644 (file)
index 0000000..442b5ba
--- /dev/null
@@ -0,0 +1,4 @@
+
+PASS Before grant 
+PASS After grant 
+
diff --git a/LayoutTests/fast/mediastream/overconstrainederror-constraint.html b/LayoutTests/fast/mediastream/overconstrainederror-constraint.html
new file mode 100644 (file)
index 0000000..c176efc
--- /dev/null
@@ -0,0 +1,39 @@
+<!doctype html>
+<html>
+    <head>
+        <meta charset="utf-8">
+        <title>OverConstrainedError.constraint testing</title>
+        <script src="../../resources/testharness.js"></script>
+        <script src="../../resources/testharnessreport.js"></script>
+    </head>
+    <body>
+
+        <script>
+if (window.testRunner)
+    testRunner.setUserMediaPermission(true);
+if (window.internals)
+    window.internals.setMockMediaCaptureDevicesEnabled(true);
+
+promise_test(async () => {
+    return navigator.mediaDevices.getUserMedia({audio: {deviceId: {exact:"none"}}}).then(
+        () => assert_not_reached("gum should fail"),
+        (e) => {
+            assert_true(e instanceof OverconstrainedError);
+            assert_equals(e.constraint, "", "constraint should be the empty string");
+        }
+    );
+}, "Before grant");
+
+promise_test(async(test) => {
+    await navigator.mediaDevices.getUserMedia({audio: true});
+    return navigator.mediaDevices.getUserMedia({audio: {deviceId: {exact:"none"}}}).then(
+        () => assert_not_reached("gum should fail"),
+        (e) => {
+            assert_true(e instanceof OverconstrainedError);
+            assert_equals(e.constraint, "deviceId", "constraint should be deviceId");
+        }
+    );
+}, "After grant");
+        </script>
+    </body>
+</html>
index 599cff1..5530f16 100644 (file)
@@ -1,3 +1,53 @@
+2019-02-11  Youenn Fablet  <youenn@apple.com>
+
+        Filter out Overconstrainederror.constraint when getUserMedia is not granted
+        https://bugs.webkit.org/show_bug.cgi?id=194240
+
+        Reviewed by Eric Carlson.
+
+        Make sure in UIProcess to filter out constraint if either the page was not granted gum access or it has no persistent access.
+
+        Refactor UserMediaPermissionRequestManagerProxy to make the implementation easier to understand.
+
+        Covered by added test.
+
+        * UIProcess/UserMediaPermissionCheckProxy.cpp:
+        (WebKit::UserMediaPermissionCheckProxy::setUserMediaAccessInfo):
+        * UIProcess/UserMediaPermissionRequestManagerProxy.cpp:
+        (WebKit::UserMediaPermissionRequestManagerProxy::captureDevicesChanged):
+        (WebKit::UserMediaPermissionRequestManagerProxy::userMediaAccessWasGranted):
+        (WebKit::UserMediaPermissionRequestManagerProxy::grantAccess):
+        (WebKit::UserMediaPermissionRequestManagerProxy::getRequestAction):
+        (WebKit::UserMediaPermissionRequestManagerProxy::requestUserMediaPermissionForFrame):
+        (WebKit::UserMediaPermissionRequestManagerProxy::processUserMediaPermissionRequest):
+        (WebKit::UserMediaPermissionRequestManagerProxy::processUserMediaPermissionInvalidRequest):
+        (WebKit::UserMediaPermissionRequestManagerProxy::processUserMediaPermissionValidRequest):
+        (WebKit::UserMediaPermissionRequestManagerProxy::getUserMediaPermissionInfo):
+        (WebKit::UserMediaPermissionRequestManagerProxy::wasGrantedVideoOrAudioAccess):
+        (WebKit::UserMediaPermissionRequestManagerProxy::computeFilteredDeviceList):
+        (WebKit::UserMediaPermissionRequestManagerProxy::enumerateMediaDevicesForFrame):
+        (WebKit::UserMediaPermissionRequestManagerProxy::createPermissionRequest): Deleted.
+        * UIProcess/UserMediaPermissionRequestManagerProxy.h:
+        * UIProcess/UserMediaPermissionRequestProxy.h:
+        (WebKit::UserMediaPermissionRequestProxy::isPending const):
+        (WebKit::UserMediaPermissionRequestProxy::setEligibleVideoDeviceUIDs):
+        (WebKit::UserMediaPermissionRequestProxy::setEligibleAudioDeviceUIDs):
+        (WebKit::UserMediaPermissionRequestProxy::hasAudioDevice const):
+        (WebKit::UserMediaPermissionRequestProxy::hasVideoDevice const):
+        (WebKit::UserMediaPermissionRequestProxy::hasPersistentAccess const):
+        (WebKit::UserMediaPermissionRequestProxy::setHasPersistentAccess):
+        (WebKit::UserMediaPermissionRequestProxy::userMediaID const):
+        (WebKit::UserMediaPermissionRequestProxy::topLevelDocumentSecurityOrigin const):
+        (WebKit::UserMediaPermissionRequestProxy::userMediaDocumentSecurityOrigin const):
+        (WebKit::UserMediaPermissionRequestProxy::userRequest const):
+        (WebKit::UserMediaPermissionRequestProxy::setDeviceIdentifierHashSalt):
+        (WebKit::UserMediaPermissionRequestProxy::deviceIdentifierHashSalt const):
+        (WebKit::UserMediaPermissionRequestProxy::audioDevice const):
+        (WebKit::UserMediaPermissionRequestProxy::videoDevice const):
+        * UIProcess/WebPageProxy.cpp:
+        (WebKit::WebPageProxy::requestUserMediaPermissionForFrame):
+        * UIProcess/WebPageProxy.h:
+
 2019-02-11  Carlos Garcia Campos  <cgarcia@igalia.com>
 
         [WPE] Do not try to create empty egl windows
index 96513eb..304fa21 100644 (file)
@@ -41,19 +41,24 @@ UserMediaPermissionCheckProxy::UserMediaPermissionCheckProxy(uint64_t frameID, C
 {
 }
 
+UserMediaPermissionCheckProxy::~UserMediaPermissionCheckProxy()
+{
+    invalidate();
+}
+
 void UserMediaPermissionCheckProxy::setUserMediaAccessInfo(bool allowed)
 {
     ASSERT(m_completionHandler);
-    if (!m_completionHandler)
-        return;
-
-    m_completionHandler(allowed);
-    m_completionHandler = nullptr;
+    complete(allowed);
 }
 
-void UserMediaPermissionCheckProxy::invalidate()
+void UserMediaPermissionCheckProxy::complete(Optional<bool> allowed)
 {
-    m_completionHandler = nullptr;
+    if (!m_completionHandler)
+        return;
+
+    auto completionHandler = WTFMove(m_completionHandler);
+    completionHandler(allowed);
 }
 
 } // namespace WebKit
index 6a08950..9e00bb9 100644 (file)
@@ -27,7 +27,7 @@
 
 #include "APIObject.h"
 #include <WebCore/MediaConstraints.h>
-#include <wtf/Function.h>
+#include <wtf/CompletionHandler.h>
 #include <wtf/text/WTFString.h>
 
 namespace WebCore {
@@ -39,7 +39,7 @@ namespace WebKit {
 class UserMediaPermissionCheckProxy : public API::ObjectImpl<API::Object::Type::UserMediaPermissionCheck> {
 public:
 
-    using CompletionHandler = WTF::Function<void(bool allowed)>;
+    using CompletionHandler = WTF::CompletionHandler<void(Optional<bool> allowed)>;
 
     static Ref<UserMediaPermissionCheckProxy> create(uint64_t frameID, CompletionHandler&& handler, Ref<WebCore::SecurityOrigin>&& userMediaDocumentOrigin, Ref<WebCore::SecurityOrigin>&& topLevelDocumentOrigin)
     {
@@ -48,7 +48,7 @@ public:
 
     void deny() { setUserMediaAccessInfo(false); }
     void setUserMediaAccessInfo(bool);
-    void invalidate();
+    void invalidate() { complete({ }); }
 
     uint64_t frameID() const { return m_frameID; }
     WebCore::SecurityOrigin& userMediaDocumentSecurityOrigin() { return m_userMediaDocumentSecurityOrigin.get(); }
@@ -56,7 +56,10 @@ public:
     
 private:
     UserMediaPermissionCheckProxy(uint64_t frameID, CompletionHandler&&, Ref<WebCore::SecurityOrigin>&& userMediaDocumentOrigin, Ref<WebCore::SecurityOrigin>&& topLevelDocumentOrigin);
+    ~UserMediaPermissionCheckProxy();
 
+    void complete(Optional<bool> allowed);
+    
     uint64_t m_frameID;
     CompletionHandler m_completionHandler;
     Ref<WebCore::SecurityOrigin> m_userMediaDocumentSecurityOrigin;
index 9fa3a50..31b4671 100644 (file)
@@ -75,8 +75,6 @@ void UserMediaPermissionRequestManagerProxy::invalidatePendingRequests()
         request->invalidate();
     m_pendingUserMediaRequests.clear();
 
-    for (auto& request : m_pendingDeviceRequests.values())
-        request->invalidate();
     m_pendingDeviceRequests.clear();
 }
 
@@ -92,23 +90,18 @@ void UserMediaPermissionRequestManagerProxy::captureDevicesChanged()
     if (!m_page.isValid() || !m_page.mainFrame())
         return;
 
-    auto requestID = generateRequestID();
-    auto handler = [this, weakThis = makeWeakPtr(*this), requestID](bool originHasPersistentAccess) mutable {
-        if (!weakThis)
+    auto handler = [this](Optional<bool> originHasPersistentAccess) mutable {
+        if (!originHasPersistentAccess || !m_page.isValid())
             return;
 
-        auto pendingRequest = m_pendingDeviceRequests.take(requestID);
-        if (!pendingRequest || !m_page.isValid())
-            return;
-
-        if (m_grantedRequests.isEmpty() && !originHasPersistentAccess)
+        if (m_grantedRequests.isEmpty() && !*originHasPersistentAccess)
             return;
 
         m_page.process().send(Messages::WebPage::CaptureDevicesChanged(), m_page.pageID());
     };
 
     auto origin = WebCore::SecurityOrigin::create(m_page.mainFrame()->url());
-    getUserMediaPermissionInfo(requestID, m_page.mainFrame()->frameID(), WTFMove(handler), origin.get(), WTFMove(origin));
+    getUserMediaPermissionInfo(m_page.mainFrame()->frameID(), origin.get(), WTFMove(origin), WTFMove(handler));
 #endif
 }
 
@@ -117,13 +110,6 @@ void UserMediaPermissionRequestManagerProxy::clearCachedState()
     invalidatePendingRequests();
 }
 
-Ref<UserMediaPermissionRequestProxy> UserMediaPermissionRequestManagerProxy::createPermissionRequest(uint64_t userMediaID, uint64_t mainFrameID, uint64_t frameID, Ref<SecurityOrigin>&& userMediaDocumentOrigin, Ref<SecurityOrigin>&& topLevelDocumentOrigin, Vector<CaptureDevice>&& audioDevices, Vector<CaptureDevice>&& videoDevices, MediaStreamRequest&& request)
-{
-    auto permissionRequest = UserMediaPermissionRequestProxy::create(*this, userMediaID, mainFrameID, frameID, WTFMove(userMediaDocumentOrigin), WTFMove(topLevelDocumentOrigin), WTFMove(audioDevices), WTFMove(videoDevices), WTFMove(request));
-    m_pendingUserMediaRequests.add(userMediaID, permissionRequest.ptr());
-    return permissionRequest;
-}
-
 #if ENABLE(MEDIA_STREAM)
 static uint64_t toWebCore(UserMediaPermissionRequestProxy::UserMediaAccessDenialReason reason)
 {
@@ -188,15 +174,18 @@ void UserMediaPermissionRequestManagerProxy::userMediaAccessWasGranted(uint64_t
     if (!request)
         return;
 
-    m_page.websiteDataStore().deviceIdHashSaltStorage().deviceIdHashSaltForOrigin(request->userMediaDocumentSecurityOrigin(), request->topLevelDocumentSecurityOrigin(), [this, weakThis = makeWeakPtr(*this), userMediaID, audioDevice = WTFMove(audioDevice), videoDevice = WTFMove(videoDevice), localRequest = request.copyRef()] (String&& deviceIDHashSalt) mutable {
+    auto& userMediaDocumentSecurityOrigin = request->userMediaDocumentSecurityOrigin();
+    auto& topLevelDocumentSecurityOrigin = request->topLevelDocumentSecurityOrigin();
+    m_page.websiteDataStore().deviceIdHashSaltStorage().deviceIdHashSaltForOrigin(userMediaDocumentSecurityOrigin, topLevelDocumentSecurityOrigin, [this, weakThis = makeWeakPtr(*this), request = request.releaseNonNull()] (String&& deviceIDHashSalt) mutable {
         if (!weakThis)
             return;
-        if (grantAccess(userMediaID, WTFMove(audioDevice), WTFMove(videoDevice), WTFMove(deviceIDHashSalt))) {
-            m_grantedRequests.append(localRequest.releaseNonNull());
-            if (m_hasFilteredDeviceList)
-                captureDevicesChanged();
-            m_hasFilteredDeviceList = false;
-        }
+        if (!grantAccess(request))
+            return;
+
+        m_grantedRequests.append(WTFMove(request));
+        if (m_hasFilteredDeviceList)
+            captureDevicesChanged();
+        m_hasFilteredDeviceList = false;
     });
 #else
     UNUSED_PARAM(userMediaID);
@@ -266,14 +255,14 @@ bool UserMediaPermissionRequestManagerProxy::wasRequestDenied(uint64_t mainFrame
     return false;
 }
 
-bool UserMediaPermissionRequestManagerProxy::grantAccess(uint64_t userMediaID, const CaptureDevice audioDevice, const CaptureDevice videoDevice, const String& deviceIdentifierHashSalt)
+bool UserMediaPermissionRequestManagerProxy::grantAccess(const UserMediaPermissionRequestProxy& request)
 {
-    if (!UserMediaProcessManager::singleton().willCreateMediaStream(*this, !!audioDevice, !!videoDevice)) {
-        denyRequest(userMediaID, UserMediaPermissionRequestProxy::UserMediaAccessDenialReason::OtherFailure, "Unable to extend sandbox.");
+    if (!UserMediaProcessManager::singleton().willCreateMediaStream(*this, request.hasAudioDevice(), request.hasVideoDevice())) {
+        denyRequest(request.userMediaID(), UserMediaPermissionRequestProxy::UserMediaAccessDenialReason::OtherFailure, "Unable to extend sandbox.");
         return false;
     }
 
-    m_page.process().send(Messages::WebPage::UserMediaAccessWasGranted(userMediaID, audioDevice, videoDevice, deviceIdentifierHashSalt), m_page.pageID());
+    m_page.process().send(Messages::WebPage::UserMediaAccessWasGranted(request.userMediaID(), request.audioDevice(), request.videoDevice(), request.deviceIdentifierHashSalt()), m_page.pageID());
     return true;
 }
 #endif
@@ -296,25 +285,26 @@ void UserMediaPermissionRequestManagerProxy::scheduleNextRejection()
 }
 
 #if ENABLE(MEDIA_STREAM)
-UserMediaPermissionRequestManagerProxy::RequestAction UserMediaPermissionRequestManagerProxy::getRequestAction(uint64_t frameID, SecurityOrigin& userMediaDocumentOrigin, SecurityOrigin& topLevelDocumentOrigin, const MediaStreamRequest& userRequest, Vector<CaptureDevice>& audioDevices, Vector<CaptureDevice>& videoDevices)
+UserMediaPermissionRequestManagerProxy::RequestAction UserMediaPermissionRequestManagerProxy::getRequestAction(const UserMediaPermissionRequestProxy& request)
 {
-    bool requestingScreenCapture = userRequest.type == MediaStreamRequest::Type::DisplayMedia;
-    ASSERT(!(requestingScreenCapture && videoDevices.isEmpty()));
-    ASSERT(!(requestingScreenCapture && !audioDevices.isEmpty()));
-    bool requestingCamera = !requestingScreenCapture && !videoDevices.isEmpty();
-    bool requestingMicrophone = !audioDevices.isEmpty();
+    bool requestingScreenCapture = request.requestType() == MediaStreamRequest::Type::DisplayMedia;
+    bool requestingCamera = !requestingScreenCapture && request.hasVideoDevice();
+    bool requestingMicrophone = request.hasAudioDevice();
 
-    if (wasRequestDenied(frameID, userMediaDocumentOrigin, topLevelDocumentOrigin, requestingMicrophone, requestingCamera, requestingScreenCapture))
+    ASSERT(!(requestingScreenCapture && !request.hasVideoDevice()));
+    ASSERT(!(requestingScreenCapture && requestingMicrophone));
+
+    if (wasRequestDenied(request.frameID(), request.userMediaDocumentSecurityOrigin(), request.topLevelDocumentSecurityOrigin(), requestingMicrophone, requestingCamera, requestingScreenCapture))
         return RequestAction::Deny;
 
-    if (userRequest.type == MediaStreamRequest::Type::DisplayMedia)
+    if (request.requestType() == MediaStreamRequest::Type::DisplayMedia)
         return RequestAction::Prompt;
 
-    return searchForGrantedRequest(frameID, userMediaDocumentOrigin, topLevelDocumentOrigin, requestingMicrophone, requestingCamera) ? RequestAction::Grant : RequestAction::Prompt;
+    return searchForGrantedRequest(request.frameID(), request.userMediaDocumentSecurityOrigin(), request.topLevelDocumentSecurityOrigin(), requestingMicrophone, requestingCamera) ? RequestAction::Grant : RequestAction::Prompt;
 }
 #endif
 
-void UserMediaPermissionRequestManagerProxy::requestUserMediaPermissionForFrame(uint64_t userMediaID, uint64_t frameID, Ref<SecurityOrigin>&& userMediaDocumentOrigin, Ref<SecurityOrigin>&& topLevelDocumentOrigin, const MediaStreamRequest& userRequest)
+void UserMediaPermissionRequestManagerProxy::requestUserMediaPermissionForFrame(uint64_t userMediaID, uint64_t frameID, Ref<SecurityOrigin>&& userMediaDocumentOrigin, Ref<SecurityOrigin>&& topLevelDocumentOrigin, MediaStreamRequest&& userRequest)
 {
 #if ENABLE(MEDIA_STREAM)
     if (!UserMediaProcessManager::singleton().captureEnabled()) {
@@ -323,95 +313,61 @@ void UserMediaPermissionRequestManagerProxy::requestUserMediaPermissionForFrame(
         return;
     }
 
-    RealtimeMediaSourceCenter::InvalidConstraintsHandler invalidHandler = [this, userMediaID](const String& invalidConstraint) {
-        if (!m_page.isValid())
-            return;
-
-        denyRequest(userMediaID, UserMediaPermissionRequestProxy::UserMediaAccessDenialReason::InvalidConstraint, invalidConstraint);
-    };
+    if (!m_page.isValid())
+        return;
 
-    auto validHandler = [this, userMediaID, frameID, userMediaDocumentOrigin = userMediaDocumentOrigin.copyRef(), topLevelDocumentOrigin = topLevelDocumentOrigin.copyRef(), localUserRequest = userRequest](Vector<CaptureDevice>&& audioDevices, Vector<CaptureDevice>&& videoDevices, String&& deviceIdentifierHashSalt) mutable {
-        if (!m_page.isValid() || !m_page.mainFrame())
-            return;
+    auto request = m_pendingUserMediaRequests.add(userMediaID, UserMediaPermissionRequestProxy::create(*this, userMediaID, m_page.mainFrame()->frameID(), frameID, WTFMove(userMediaDocumentOrigin), WTFMove(topLevelDocumentOrigin), { }, { }, WTFMove(userRequest))).iterator->value.copyRef();
 
-        if (videoDevices.isEmpty() && audioDevices.isEmpty()) {
-            denyRequest(userMediaID, UserMediaPermissionRequestProxy::UserMediaAccessDenialReason::NoConstraints, emptyString());
+    auto& userMediaOrigin = request->userMediaDocumentSecurityOrigin();
+    auto& topLevelOrigin = request->topLevelDocumentSecurityOrigin();
+    getUserMediaPermissionInfo(frameID, userMediaOrigin, topLevelOrigin, [this, request = request.releaseNonNull()](Optional<bool> hasPersistentAccess) mutable {
+        if (!request->isPending())
             return;
-        }
 
-        auto action = getRequestAction(m_page.mainFrame()->frameID(), userMediaDocumentOrigin.get(), topLevelDocumentOrigin.get(), localUserRequest, audioDevices, videoDevices);
-        if (action == RequestAction::Deny) {
-            denyRequest(userMediaID, UserMediaPermissionRequestProxy::UserMediaAccessDenialReason::PermissionDenied, emptyString());
+        if (!hasPersistentAccess) {
+            request->deny(UserMediaPermissionRequestProxy::UserMediaAccessDenialReason::OtherFailure);
             return;
         }
 
-        if (action == RequestAction::Grant) {
-            ASSERT(localUserRequest.type != MediaStreamRequest::Type::DisplayMedia);
+        processUserMediaPermissionRequest(WTFMove(request), *hasPersistentAccess);
+    });
+}
 
-            if (m_page.isViewVisible()) {
-                // We select the first available devices, but the current client API allows client to select which device to pick.
-                // FIXME: Remove the possiblity for the client to do the device selection.
-                auto audioDevice = !audioDevices.isEmpty() ? audioDevices[0] : CaptureDevice();
-                auto videoDevice = !videoDevices.isEmpty() ? videoDevices[0] : CaptureDevice();
-                grantAccess(userMediaID, WTFMove(audioDevice), WTFMove(videoDevice), WTFMove(deviceIdentifierHashSalt));
-            } else
-                m_pregrantedRequests.append(createPermissionRequest(userMediaID, m_page.mainFrame()->frameID(), frameID, WTFMove(userMediaDocumentOrigin), WTFMove(topLevelDocumentOrigin), WTFMove(audioDevices), WTFMove(videoDevices), WTFMove(localUserRequest)));
+void UserMediaPermissionRequestManagerProxy::processUserMediaPermissionRequest(Ref<UserMediaPermissionRequestProxy>&& request, bool hasPersistentAccess)
+{
+    if (hasPersistentAccess)
+        request->setHasPersistentAccess();
 
+    auto& userMediaDocumentSecurityOrigin = request->userMediaDocumentSecurityOrigin();
+    auto& topLevelDocumentSecurityOrigin = request->topLevelDocumentSecurityOrigin();
+    m_page.websiteDataStore().deviceIdHashSaltStorage().deviceIdHashSaltForOrigin(userMediaDocumentSecurityOrigin, topLevelDocumentSecurityOrigin, [this, request = WTFMove(request)] (String&& deviceIDHashSalt) mutable {
+        if (!request->isPending())
             return;
-        }
-
-        auto userMediaOrigin = API::SecurityOrigin::create(userMediaDocumentOrigin.get());
-        auto topLevelOrigin = API::SecurityOrigin::create(topLevelDocumentOrigin.get());
-        auto pendingRequest = createPermissionRequest(userMediaID, m_page.mainFrame()->frameID(), frameID, WTFMove(userMediaDocumentOrigin), WTFMove(topLevelDocumentOrigin), WTFMove(audioDevices), WTFMove(videoDevices), WTFMove(localUserRequest));
-
-        if (m_page.isControlledByAutomation()) {
-            if (WebAutomationSession* automationSession = m_page.process().processPool().automationSession()) {
-                if (automationSession->shouldAllowGetUserMediaForPage(m_page))
-                    pendingRequest->allow();
-                else
-                    userMediaAccessWasDenied(userMediaID, UserMediaPermissionRequestProxy::UserMediaAccessDenialReason::PermissionDenied);
 
+        RealtimeMediaSourceCenter::InvalidConstraintsHandler invalidHandler = [this, request = request.copyRef()](const String& invalidConstraint) {
+            if (!request->isPending())
                 return;
-            }
-        }
 
-        if (m_page.preferences().mockCaptureDevicesEnabled() && !m_page.preferences().mockCaptureDevicesPromptEnabled()) {
-            pendingRequest->allow();
-            return;
-        }
+            if (!m_page.isValid())
+                return;
 
-        // If page navigated, there is no need to call the page client for authorization.
-        auto* webFrame = m_page.process().webFrame(frameID);
+            processUserMediaPermissionInvalidRequest(request.get(), invalidConstraint);
+        };
 
-        if (!webFrame || !SecurityOrigin::createFromString(m_page.pageLoadState().activeURL())->isSameSchemeHostPort(topLevelOrigin->securityOrigin())) {
-            denyRequest(userMediaID, UserMediaPermissionRequestProxy::UserMediaAccessDenialReason::NoConstraints, emptyString());
-            return;
-        }
-
-        // FIXME: Remove webFrame, userMediaOrigin and topLevelOrigin from this uiClient API call.
-        m_page.uiClient().decidePolicyForUserMediaPermissionRequest(m_page, *webFrame, WTFMove(userMediaOrigin), WTFMove(topLevelOrigin), pendingRequest.get());
-    };
+        auto validHandler = [this, request = request.copyRef()](Vector<CaptureDevice>&& audioDevices, Vector<CaptureDevice>&& videoDevices, String&& deviceIdentifierHashSalt) mutable {
+            if (!request->isPending())
+                return;
 
-    auto requestID = generateRequestID();
-    auto havePermissionInfoHandler = [this, weakThis = makeWeakPtr(*this), requestID, validHandler = WTFMove(validHandler), invalidHandler = WTFMove(invalidHandler), localUserRequest = userRequest](bool originHasPersistentAccess) mutable {
-        if (!weakThis)
-            return;
+            if (!m_page.isValid() || !m_page.mainFrame())
+                return;
 
-        auto pendingRequest = m_pendingDeviceRequests.take(requestID);
-        if (!pendingRequest)
-            return;
-
-        if (!m_page.isValid())
-            return;
+            processUserMediaPermissionValidRequest(WTFMove(request), WTFMove(audioDevices), WTFMove(videoDevices), WTFMove(deviceIdentifierHashSalt));
+        };
 
         syncWithWebCorePrefs();
 
-        m_page.websiteDataStore().deviceIdHashSaltStorage().deviceIdHashSaltForOrigin(pendingRequest.value()->userMediaDocumentSecurityOrigin(), pendingRequest.value()->topLevelDocumentSecurityOrigin(), [validHandler = WTFMove(validHandler), invalidHandler = WTFMove(invalidHandler), localUserRequest = localUserRequest] (String&& deviceIDHashSalt) mutable {
-            RealtimeMediaSourceCenter::singleton().validateRequestConstraints(WTFMove(validHandler), WTFMove(invalidHandler), WTFMove(localUserRequest), WTFMove(deviceIDHashSalt));
-        });
-    };
-
-    getUserMediaPermissionInfo(requestID, frameID, WTFMove(havePermissionInfoHandler), WTFMove(userMediaDocumentOrigin), WTFMove(topLevelDocumentOrigin));
+        RealtimeMediaSourceCenter::singleton().validateRequestConstraints(WTFMove(validHandler), WTFMove(invalidHandler), request->userRequest(), WTFMove(deviceIDHashSalt));
+    });
 #else
     UNUSED_PARAM(userMediaID);
     UNUSED_PARAM(frameID);
@@ -422,19 +378,93 @@ void UserMediaPermissionRequestManagerProxy::requestUserMediaPermissionForFrame(
 }
 
 #if ENABLE(MEDIA_STREAM)
-void UserMediaPermissionRequestManagerProxy::getUserMediaPermissionInfo(uint64_t requestID, uint64_t frameID, UserMediaPermissionCheckProxy::CompletionHandler&& handler, Ref<SecurityOrigin>&& userMediaDocumentOrigin, Ref<SecurityOrigin>&& topLevelDocumentOrigin)
+void UserMediaPermissionRequestManagerProxy::processUserMediaPermissionInvalidRequest(const UserMediaPermissionRequestProxy& request, const String& invalidConstraint)
+{
+    bool filterConstraint = !request.hasPersistentAccess() && !wasGrantedVideoOrAudioAccess(request.frameID(), request.userMediaDocumentSecurityOrigin(), request.topLevelDocumentSecurityOrigin());
+
+    denyRequest(request.userMediaID(), UserMediaPermissionRequestProxy::UserMediaAccessDenialReason::InvalidConstraint, filterConstraint ? String { } : invalidConstraint);
+}
+
+void UserMediaPermissionRequestManagerProxy::processUserMediaPermissionValidRequest(Ref<UserMediaPermissionRequestProxy>&& request, Vector<CaptureDevice>&& audioDevices, Vector<CaptureDevice>&& videoDevices, String&& deviceIdentifierHashSalt)
+{
+    if (videoDevices.isEmpty() && audioDevices.isEmpty()) {
+        denyRequest(request->userMediaID(), UserMediaPermissionRequestProxy::UserMediaAccessDenialReason::NoConstraints, emptyString());
+        return;
+    }
+
+    request->setDeviceIdentifierHashSalt(WTFMove(deviceIdentifierHashSalt));
+    request->setEligibleVideoDeviceUIDs(WTFMove(videoDevices));
+    request->setEligibleAudioDeviceUIDs(WTFMove(audioDevices));
+
+    auto action = getRequestAction(request);
+    if (action == RequestAction::Deny) {
+        denyRequest(request->userMediaID(), UserMediaPermissionRequestProxy::UserMediaAccessDenialReason::PermissionDenied, emptyString());
+        return;
+    }
+
+    if (action == RequestAction::Grant) {
+        ASSERT(request->requestType() != MediaStreamRequest::Type::DisplayMedia);
+
+        if (m_page.isViewVisible())
+            grantAccess(request);
+        else
+            m_pregrantedRequests.append(WTFMove(request));
+
+        return;
+    }
+
+    if (m_page.isControlledByAutomation()) {
+        if (WebAutomationSession* automationSession = m_page.process().processPool().automationSession()) {
+            if (automationSession->shouldAllowGetUserMediaForPage(m_page))
+                request->allow();
+            else
+                userMediaAccessWasDenied(request->userMediaID(), UserMediaPermissionRequestProxy::UserMediaAccessDenialReason::PermissionDenied);
+
+            return;
+        }
+    }
+
+    if (m_page.preferences().mockCaptureDevicesEnabled() && !m_page.preferences().mockCaptureDevicesPromptEnabled()) {
+        request->allow();
+        return;
+    }
+
+    // If page navigated, there is no need to call the page client for authorization.
+    auto* webFrame = m_page.process().webFrame(request->frameID());
+
+    if (!webFrame || !SecurityOrigin::createFromString(m_page.pageLoadState().activeURL())->isSameSchemeHostPort(request->topLevelDocumentSecurityOrigin())) {
+        denyRequest(request->userMediaID(), UserMediaPermissionRequestProxy::UserMediaAccessDenialReason::NoConstraints, emptyString());
+        return;
+    }
+
+    // FIXME: Remove webFrame, userMediaOrigin and topLevelOrigin from this uiClient API call.
+    auto userMediaOrigin = API::SecurityOrigin::create(request->userMediaDocumentSecurityOrigin());
+    auto topLevelOrigin = API::SecurityOrigin::create(request->topLevelDocumentSecurityOrigin());
+    m_page.uiClient().decidePolicyForUserMediaPermissionRequest(m_page, *webFrame, WTFMove(userMediaOrigin), WTFMove(topLevelOrigin), request);
+}
+
+void UserMediaPermissionRequestManagerProxy::getUserMediaPermissionInfo(uint64_t frameID, Ref<SecurityOrigin>&& userMediaDocumentOrigin, Ref<SecurityOrigin>&& topLevelDocumentOrigin, CompletionHandler<void(Optional<bool>)>&& handler)
 {
     auto* webFrame = m_page.process().webFrame(frameID);
     if (!webFrame || !SecurityOrigin::createFromString(m_page.pageLoadState().activeURL())->isSameSchemeHostPort(topLevelDocumentOrigin.get())) {
-        handler(false);
+        handler({ });
         return;
     }
 
     auto userMediaOrigin = API::SecurityOrigin::create(userMediaDocumentOrigin.get());
     auto topLevelOrigin = API::SecurityOrigin::create(topLevelDocumentOrigin.get());
-    auto request = UserMediaPermissionCheckProxy::create(frameID, WTFMove(handler), WTFMove(userMediaDocumentOrigin), WTFMove(topLevelDocumentOrigin));
 
-    m_pendingDeviceRequests.add(requestID, request.copyRef());
+    auto requestID = generateRequestID();
+    m_pendingDeviceRequests.add(requestID);
+
+    auto request = UserMediaPermissionCheckProxy::create(frameID, [this, weakThis = makeWeakPtr(*this), requestID, handler = WTFMove(handler)](Optional<bool> allowed) mutable {
+        if (!weakThis || !m_pendingDeviceRequests.remove(requestID) || !allowed) {
+            handler({ });
+            return;
+        }
+        handler(*allowed);
+    }, WTFMove(userMediaDocumentOrigin), WTFMove(topLevelDocumentOrigin));
+
     // FIXME: Remove webFrame, userMediaOrigin and topLevelOrigin from this uiClient API call.
     m_page.uiClient().checkUserMediaPermissionForOrigin(m_page, *webFrame, userMediaOrigin.get(), topLevelOrigin.get(), request.get());
 }
@@ -457,12 +487,9 @@ bool UserMediaPermissionRequestManagerProxy::wasGrantedVideoOrAudioAccess(uint64
 
     return false;
 }
-#endif
 
-void UserMediaPermissionRequestManagerProxy::enumerateMediaDevicesForFrame(uint64_t userMediaID, uint64_t frameID, Ref<SecurityOrigin>&& userMediaDocumentOrigin, Ref<SecurityOrigin>&& topLevelDocumentOrigin)
+Vector<CaptureDevice> UserMediaPermissionRequestManagerProxy::computeFilteredDeviceList(bool revealIdsAndLabels, const String& deviceIDHashSalt)
 {
-#if ENABLE(MEDIA_STREAM)
-
 #if PLATFORM(IOS_FAMILY)
     static const int defaultMaximumCameraCount = 2;
 #else
@@ -470,19 +497,56 @@ void UserMediaPermissionRequestManagerProxy::enumerateMediaDevicesForFrame(uint6
 #endif
     static const int defaultMaximumMicrophoneCount = 1;
 
-    auto requestID = generateRequestID();
-    auto completionHandler = [this, weakThis = makeWeakPtr(*this), requestID, userMediaID, requestOrigin = userMediaDocumentOrigin.copyRef(), topOrigin = topLevelDocumentOrigin.copyRef()](bool originHasPersistentAccess) mutable {
-        if (!weakThis)
+    auto devices = RealtimeMediaSourceCenter::singleton().getMediaStreamDevices();
+    int cameraCount = 0;
+    int microphoneCount = 0;
+
+    Vector<CaptureDevice> filteredDevices;
+    for (const auto& device : devices) {
+        if (!device.enabled() || (device.type() != WebCore::CaptureDevice::DeviceType::Camera && device.type() != WebCore::CaptureDevice::DeviceType::Microphone))
+            continue;
+
+        if (!revealIdsAndLabels) {
+            if (device.type() == WebCore::CaptureDevice::DeviceType::Camera && ++cameraCount > defaultMaximumCameraCount)
+                continue;
+            if (device.type() == WebCore::CaptureDevice::DeviceType::Microphone && ++microphoneCount > defaultMaximumMicrophoneCount)
+                continue;
+        }
+
+        auto label = emptyString();
+        auto id = emptyString();
+        auto groupId = emptyString();
+        if (revealIdsAndLabels) {
+            label = device.label();
+            id = RealtimeMediaSourceCenter::singleton().hashStringWithSalt(device.persistentId(), deviceIDHashSalt);
+            groupId = RealtimeMediaSourceCenter::singleton().hashStringWithSalt(device.groupId(), deviceIDHashSalt);
+        }
+
+        filteredDevices.append(CaptureDevice(id, device.type(), label, groupId));
+    }
+
+    m_hasFilteredDeviceList = !revealIdsAndLabels;
+    return filteredDevices;
+}
+#endif
+
+void UserMediaPermissionRequestManagerProxy::enumerateMediaDevicesForFrame(uint64_t userMediaID, uint64_t frameID, Ref<SecurityOrigin>&& userMediaDocumentOrigin, Ref<SecurityOrigin>&& topLevelDocumentOrigin)
+{
+#if ENABLE(MEDIA_STREAM)
+    auto completionHandler = [this, userMediaID, frameID, userMediaDocumentOrigin = userMediaDocumentOrigin.copyRef(), topLevelDocumentOrigin = topLevelDocumentOrigin.copyRef()](Optional<bool> originHasPersistentAccess) mutable {
+        if (!originHasPersistentAccess)
             return;
 
         if (!m_page.isValid())
             return;
 
-        m_page.websiteDataStore().deviceIdHashSaltStorage().deviceIdHashSaltForOrigin(requestOrigin.get(), topOrigin.get(), [this, weakThis = WTFMove(weakThis), requestID, userMediaID, &originHasPersistentAccess] (String&& deviceIDHashSalt) {
-            if (!weakThis)
-                return;
-            auto pendingRequest = m_pendingDeviceRequests.take(requestID);
-            if (!pendingRequest)
+        auto requestID = generateRequestID();
+        m_pendingDeviceRequests.add(requestID);
+
+        auto& requestOrigin = userMediaDocumentOrigin.get();
+        auto& topOrigin = topLevelDocumentOrigin.get();
+        m_page.websiteDataStore().deviceIdHashSaltStorage().deviceIdHashSaltForOrigin(requestOrigin, topOrigin, [this, weakThis = makeWeakPtr(*this), requestID, frameID, userMediaID, userMediaDocumentOrigin = WTFMove(userMediaDocumentOrigin), topLevelDocumentOrigin = WTFMove(topLevelDocumentOrigin), originHasPersistentAccess = *originHasPersistentAccess] (String&& deviceIDHashSalt) {
+            if (!weakThis || !m_pendingDeviceRequests.remove(requestID))
                 return;
 
             if (!m_page.isValid())
@@ -490,43 +554,13 @@ void UserMediaPermissionRequestManagerProxy::enumerateMediaDevicesForFrame(uint6
 
             syncWithWebCorePrefs();
 
-            auto devices = RealtimeMediaSourceCenter::singleton().getMediaStreamDevices();
-            auto& request = *pendingRequest;
-            bool revealIdsAndLabels = originHasPersistentAccess || wasGrantedVideoOrAudioAccess(request->frameID(), request->userMediaDocumentSecurityOrigin(), request->topLevelDocumentSecurityOrigin());
-            int cameraCount = 0;
-            int microphoneCount = 0;
-
-            Vector<CaptureDevice> filteredDevices;
-            for (const auto& device : devices) {
-                if (!device.enabled() || (device.type() != WebCore::CaptureDevice::DeviceType::Camera && device.type() != WebCore::CaptureDevice::DeviceType::Microphone))
-                    continue;
-
-                if (!revealIdsAndLabels) {
-                    if (device.type() == WebCore::CaptureDevice::DeviceType::Camera && ++cameraCount > defaultMaximumCameraCount)
-                        continue;
-                    if (device.type() == WebCore::CaptureDevice::DeviceType::Microphone && ++microphoneCount > defaultMaximumMicrophoneCount)
-                        continue;
-                }
-
-                auto label = emptyString();
-                auto id = emptyString();
-                auto groupId = emptyString();
-                if (revealIdsAndLabels) {
-                    label = device.label();
-                    id = RealtimeMediaSourceCenter::singleton().hashStringWithSalt(device.persistentId(), deviceIDHashSalt);
-                    groupId = RealtimeMediaSourceCenter::singleton().hashStringWithSalt(device.groupId(), deviceIDHashSalt);
-                }
-
-                filteredDevices.append(CaptureDevice(id, device.type(), label, groupId));
-            }
-
-            m_hasFilteredDeviceList = !revealIdsAndLabels;
-
-            m_page.process().send(Messages::WebPage::DidCompleteMediaDeviceEnumeration(userMediaID, WTFMove(filteredDevices), WTFMove(deviceIDHashSalt), originHasPersistentAccess), m_page.pageID());
+            bool revealIdsAndLabels = originHasPersistentAccess || wasGrantedVideoOrAudioAccess(frameID, userMediaDocumentOrigin.get(), topLevelDocumentOrigin.get());
+
+            m_page.process().send(Messages::WebPage::DidCompleteMediaDeviceEnumeration { userMediaID, computeFilteredDeviceList(revealIdsAndLabels, deviceIDHashSalt), deviceIDHashSalt, originHasPersistentAccess }, m_page.pageID());
         });
     };
 
-    getUserMediaPermissionInfo(requestID, frameID, WTFMove(completionHandler), WTFMove(userMediaDocumentOrigin), WTFMove(topLevelDocumentOrigin));
+    getUserMediaPermissionInfo(frameID, WTFMove(userMediaDocumentOrigin), WTFMove(topLevelDocumentOrigin), WTFMove(completionHandler));
 #else
     UNUSED_PARAM(userMediaID);
     UNUSED_PARAM(frameID);
index eacce6f..a115c43 100644 (file)
@@ -23,6 +23,7 @@
 #include "UserMediaPermissionRequestProxy.h"
 #include <WebCore/MediaProducer.h>
 #include <WebCore/SecurityOrigin.h>
+#include <wtf/CompletionHandler.h>
 #include <wtf/HashMap.h>
 #include <wtf/RunLoop.h>
 #include <wtf/Seconds.h>
@@ -48,7 +49,7 @@ public:
 
     void invalidatePendingRequests();
 
-    void requestUserMediaPermissionForFrame(uint64_t userMediaID, uint64_t frameID, Ref<WebCore::SecurityOrigin>&&  userMediaDocumentOrigin, Ref<WebCore::SecurityOrigin>&& topLevelDocumentOrigin, const WebCore::MediaStreamRequest&);
+    void requestUserMediaPermissionForFrame(uint64_t userMediaID, uint64_t frameID, Ref<WebCore::SecurityOrigin>&&  userMediaDocumentOrigin, Ref<WebCore::SecurityOrigin>&& topLevelDocumentOrigin, WebCore::MediaStreamRequest&&);
 
     void resetAccess(uint64_t mainFrameID);
     void viewIsBecomingVisible();
@@ -71,27 +72,33 @@ private:
     Ref<UserMediaPermissionRequestProxy> createPermissionRequest(uint64_t userMediaID, uint64_t mainFrameID, uint64_t frameID, Ref<WebCore::SecurityOrigin>&& userMediaDocumentOrigin, Ref<WebCore::SecurityOrigin>&& topLevelDocumentOrigin, Vector<WebCore::CaptureDevice>&& audioDevices, Vector<WebCore::CaptureDevice>&& videoDevices, WebCore::MediaStreamRequest&&);
     void denyRequest(uint64_t userMediaID, UserMediaPermissionRequestProxy::UserMediaAccessDenialReason, const String& invalidConstraint);
 #if ENABLE(MEDIA_STREAM)
-    bool grantAccess(uint64_t userMediaID, const WebCore::CaptureDevice audioDevice, const WebCore::CaptureDevice videoDevice, const String& deviceIdentifierHashSalt);
+    bool grantAccess(const UserMediaPermissionRequestProxy&);
 
     const UserMediaPermissionRequestProxy* searchForGrantedRequest(uint64_t frameID, const WebCore::SecurityOrigin& userMediaDocumentOrigin, const WebCore::SecurityOrigin& topLevelDocumentOrigin, bool needsAudio, bool needsVideo) const;
     bool wasRequestDenied(uint64_t mainFrameID, const WebCore::SecurityOrigin& userMediaDocumentOrigin, const WebCore::SecurityOrigin& topLevelDocumentOrigin, bool needsAudio, bool needsVideo, bool needsScreenCapture);
 
-    void getUserMediaPermissionInfo(uint64_t requestID, uint64_t frameID, UserMediaPermissionCheckProxy::CompletionHandler&&, Ref<WebCore::SecurityOrigin>&& userMediaDocumentOrigin, Ref<WebCore::SecurityOrigin>&& topLevelDocumentOrigin);
+    void getUserMediaPermissionInfo(uint64_t frameID, Ref<WebCore::SecurityOrigin>&& userMediaDocumentOrigin, Ref<WebCore::SecurityOrigin>&& topLevelDocumentOrigin, CompletionHandler<void(Optional<bool>)>&&);
 
     enum class RequestAction {
         Deny,
         Grant,
         Prompt
     };
-    RequestAction getRequestAction(uint64_t frameID, WebCore::SecurityOrigin& userMediaDocumentOrigin, WebCore::SecurityOrigin& topLevelDocumentOrigin, const WebCore::MediaStreamRequest&, Vector<WebCore::CaptureDevice>& audioDevices, Vector<WebCore::CaptureDevice>& videoDevices);
+    RequestAction getRequestAction(const UserMediaPermissionRequestProxy&);
 
     bool wasGrantedVideoOrAudioAccess(uint64_t, const WebCore::SecurityOrigin& userMediaDocumentOrigin, const WebCore::SecurityOrigin& topLevelDocumentOrigin);
+
+    Vector<WebCore::CaptureDevice> computeFilteredDeviceList(bool revealIdsAndLabels, const String& deviceIDHashSalt);
+
+    void processUserMediaPermissionRequest(Ref<UserMediaPermissionRequestProxy>&&, bool hasPersistentAccess);
+    void processUserMediaPermissionInvalidRequest(const UserMediaPermissionRequestProxy&, const String& invalidConstraint);
+    void processUserMediaPermissionValidRequest(Ref<UserMediaPermissionRequestProxy>&&, Vector<WebCore::CaptureDevice>&& audioDevices, Vector<WebCore::CaptureDevice>&& videoDevices, String&& deviceIdentifierHashSalt);
 #endif
 
     void watchdogTimerFired();
 
     HashMap<uint64_t, RefPtr<UserMediaPermissionRequestProxy>> m_pendingUserMediaRequests;
-    HashMap<uint64_t, Ref<UserMediaPermissionCheckProxy>> m_pendingDeviceRequests;
+    HashSet<uint64_t> m_pendingDeviceRequests;
 
     WebPageProxy& m_page;
 
index ac805e7..067f802 100644 (file)
@@ -48,21 +48,42 @@ public:
     void deny(UserMediaAccessDenialReason = UserMediaAccessDenialReason::UserMediaDisabled);
 
     void invalidate();
+    bool isPending() const { return m_manager; }
 
     bool requiresAudioCapture() const { return m_eligibleAudioDevices.size(); }
     bool requiresVideoCapture() const { return !requiresDisplayCapture() && m_eligibleVideoDevices.size(); }
     bool requiresDisplayCapture() const { return m_request.type == WebCore::MediaStreamRequest::Type::DisplayMedia && m_eligibleVideoDevices.size(); }
 
+    void setEligibleVideoDeviceUIDs(Vector<WebCore::CaptureDevice>&& devices) { m_eligibleVideoDevices = WTFMove(devices); }
+    void setEligibleAudioDeviceUIDs(Vector<WebCore::CaptureDevice>&& devices) { m_eligibleAudioDevices = WTFMove(devices); }
+
     Vector<String> videoDeviceUIDs() const;
     Vector<String> audioDeviceUIDs() const;
+    bool hasAudioDevice() const { return !m_eligibleAudioDevices.isEmpty(); }
+    bool hasVideoDevice() const { return !m_eligibleVideoDevices.isEmpty(); }
+
+    bool hasPersistentAccess() const { return m_hasPersistentAccess; }
+    void setHasPersistentAccess() { m_hasPersistentAccess = true; }
 
+    uint64_t userMediaID() const { return m_userMediaID; }
     uint64_t mainFrameID() const { return m_mainFrameID; }
     uint64_t frameID() const { return m_frameID; }
+
     WebCore::SecurityOrigin& topLevelDocumentSecurityOrigin() { return m_topLevelDocumentSecurityOrigin.get(); }
     WebCore::SecurityOrigin& userMediaDocumentSecurityOrigin() { return m_userMediaDocumentSecurityOrigin.get(); }
+    const WebCore::SecurityOrigin& topLevelDocumentSecurityOrigin() const { return m_topLevelDocumentSecurityOrigin.get(); }
+    const WebCore::SecurityOrigin& userMediaDocumentSecurityOrigin() const { return m_userMediaDocumentSecurityOrigin.get(); }
+
+    const WebCore::MediaStreamRequest& userRequest() const { return m_request; }
 
     WebCore::MediaStreamRequest::Type requestType() const { return m_request.type; }
 
+    void setDeviceIdentifierHashSalt(String&& salt) { m_deviceIdentifierHashSalt = WTFMove(salt); }
+    const String& deviceIdentifierHashSalt() const { return m_deviceIdentifierHashSalt; }
+
+    WebCore::CaptureDevice audioDevice() const { return m_eligibleAudioDevices.isEmpty() ? WebCore::CaptureDevice { } : m_eligibleAudioDevices[0]; }
+    WebCore::CaptureDevice videoDevice() const { return m_eligibleVideoDevices.isEmpty() ? WebCore::CaptureDevice { } : m_eligibleVideoDevices[0]; }
+
 private:
     UserMediaPermissionRequestProxy(UserMediaPermissionRequestManagerProxy&, uint64_t userMediaID, uint64_t mainFrameID, uint64_t frameID, Ref<WebCore::SecurityOrigin>&& userMediaDocumentOrigin, Ref<WebCore::SecurityOrigin>&& topLevelDocumentOrigin, Vector<WebCore::CaptureDevice>&& audioDevices, Vector<WebCore::CaptureDevice>&& videoDevices, WebCore::MediaStreamRequest&&);
 
@@ -75,6 +96,8 @@ private:
     Vector<WebCore::CaptureDevice> m_eligibleVideoDevices;
     Vector<WebCore::CaptureDevice> m_eligibleAudioDevices;
     WebCore::MediaStreamRequest m_request;
+    bool m_hasPersistentAccess { false };
+    String m_deviceIdentifierHashSalt;
 };
 
 } // namespace WebKit
index 94bb07b..6a17745 100644 (file)
@@ -7022,12 +7022,12 @@ UserMediaPermissionRequestManagerProxy& WebPageProxy::userMediaPermissionRequest
 }
 #endif
 
-void WebPageProxy::requestUserMediaPermissionForFrame(uint64_t userMediaID, uint64_t frameID, const WebCore::SecurityOriginData&  userMediaDocumentOriginData, const WebCore::SecurityOriginData& topLevelDocumentOriginData, const WebCore::MediaStreamRequest& request)
+void WebPageProxy::requestUserMediaPermissionForFrame(uint64_t userMediaID, uint64_t frameID, const WebCore::SecurityOriginData&  userMediaDocumentOriginData, const WebCore::SecurityOriginData& topLevelDocumentOriginData, WebCore::MediaStreamRequest&& request)
 {
 #if ENABLE(MEDIA_STREAM)
     MESSAGE_CHECK(m_process, m_process->webFrame(frameID));
 
-    userMediaPermissionRequestManager().requestUserMediaPermissionForFrame(userMediaID, frameID, userMediaDocumentOriginData.securityOrigin(), topLevelDocumentOriginData.securityOrigin(), request);
+    userMediaPermissionRequestManager().requestUserMediaPermissionForFrame(userMediaID, frameID, userMediaDocumentOriginData.securityOrigin(), topLevelDocumentOriginData.securityOrigin(), WTFMove(request));
 #else
     UNUSED_PARAM(userMediaID);
     UNUSED_PARAM(frameID);
index d384cd7..d99c2ad 100644 (file)
@@ -1603,7 +1603,7 @@ private:
 #if ENABLE(MEDIA_STREAM)
     UserMediaPermissionRequestManagerProxy& userMediaPermissionRequestManager();
 #endif
-    void requestUserMediaPermissionForFrame(uint64_t userMediaID, uint64_t frameID, const WebCore::SecurityOriginData& userMediaDocumentOriginIdentifier, const WebCore::SecurityOriginData& topLevelDocumentOriginIdentifier, const WebCore::MediaStreamRequest&);
+    void requestUserMediaPermissionForFrame(uint64_t userMediaID, uint64_t frameID, const WebCore::SecurityOriginData& userMediaDocumentOriginIdentifier, const WebCore::SecurityOriginData& topLevelDocumentOriginIdentifier, WebCore::MediaStreamRequest&&);
     void enumerateMediaDevicesForFrame(uint64_t userMediaID, uint64_t frameID, const WebCore::SecurityOriginData& userMediaDocumentOriginData, const WebCore::SecurityOriginData& topLevelDocumentOriginData);
     void beginMonitoringCaptureDevices();