Title: [274206] trunk
Revision
274206
Author
[email protected]
Date
2021-03-10 03:52:49 -0800 (Wed, 10 Mar 2021)

Log Message

Remove getUserMedia denied requests if user grants a new getUserMedia request
https://bugs.webkit.org/show_bug.cgi?id=222962
<rdar://74805451>

Reviewed by Eric Carlson.

Source/WebKit:

A user may deny an audio getUserMedia request.
On user gesture, user may be reprompted, in which case user may grant access.
Before the patch, after these two getUserMedia calls, if the web page was trying to call getUserMedia without user gesture, it would fail.
With this patch, we remove the first denied request based on the second granted request.
This allows getUserMedia to be granted, even without a user gesture.

Tests: fast/mediastream/granted-denied-request-management1.html
       fast/mediastream/granted-denied-request-management2.html

* UIProcess/UserMediaPermissionRequestManagerProxy.cpp:
(WebKit::UserMediaPermissionRequestManagerProxy::finishGrantingRequest):
(WebKit::isMatchingDeniedRequest):
(WebKit::UserMediaPermissionRequestManagerProxy::wasRequestDenied):
(WebKit::UserMediaPermissionRequestManagerProxy::updateStoredRequests):
(WebKit::UserMediaPermissionRequestManagerProxy::getRequestAction):
* UIProcess/UserMediaPermissionRequestManagerProxy.h:

LayoutTests:

* fast/mediastream/getUserMedia-deny-persistency5.html:
Update according new heuristic.
* fast/mediastream/granted-denied-request-management1-expected.txt: Added.
* fast/mediastream/granted-denied-request-management1.html: Added.
* fast/mediastream/granted-denied-request-management2-expected.txt: Added.
* fast/mediastream/granted-denied-request-management2.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (274205 => 274206)


--- trunk/LayoutTests/ChangeLog	2021-03-10 11:24:47 UTC (rev 274205)
+++ trunk/LayoutTests/ChangeLog	2021-03-10 11:52:49 UTC (rev 274206)
@@ -1,3 +1,18 @@
+2021-03-10  Youenn Fablet  <[email protected]>
+
+        Remove getUserMedia denied requests if user grants a new getUserMedia request
+        https://bugs.webkit.org/show_bug.cgi?id=222962
+        <rdar://74805451>
+
+        Reviewed by Eric Carlson.
+
+        * fast/mediastream/getUserMedia-deny-persistency5.html:
+        Update according new heuristic.
+        * fast/mediastream/granted-denied-request-management1-expected.txt: Added.
+        * fast/mediastream/granted-denied-request-management1.html: Added.
+        * fast/mediastream/granted-denied-request-management2-expected.txt: Added.
+        * fast/mediastream/granted-denied-request-management2.html: Added.
+
 2021-03-09  Venky Dass  <[email protected]>
 
         Nullptr crash in Node::isTextNode() via ApplyBlockElementCommand::endOfNextParagraphSplittingTextNodesIfNeeded

Modified: trunk/LayoutTests/fast/mediastream/getUserMedia-deny-persistency5.html (274205 => 274206)


--- trunk/LayoutTests/fast/mediastream/getUserMedia-deny-persistency5.html	2021-03-10 11:24:47 UTC (rev 274205)
+++ trunk/LayoutTests/fast/mediastream/getUserMedia-deny-persistency5.html	2021-03-10 11:52:49 UTC (rev 274206)
@@ -26,19 +26,21 @@
         promise = navigator.mediaDevices.getUserMedia({audio:false, video:true});
     });
     await promise;
+
+    // We still have audio denied.
+    await navigator.mediaDevices.getUserMedia({audio:true, video:false}).then(assert_unreached, (e) => { });
+    await navigator.mediaDevices.getUserMedia({audio:true, video:true}).then(assert_unreached, (e) => { });
+
+    await navigator.mediaDevices.getUserMedia({audio:false, video:true});
+
     internals.withUserGesture(() => {
         promise = navigator.mediaDevices.getUserMedia({audio:true, video:false});
     });
     await promise;
 
-    internals.withUserGesture(() => {
-        promise = navigator.mediaDevices.getUserMedia({audio:true, video:true});
-    });
-    await promise;
-
-    await navigator.mediaDevices.getUserMedia({audio:false, video:true}).then(assert_unreached, (e) => { });
-    await navigator.mediaDevices.getUserMedia({audio:true, video:false}).then(assert_unreached, (e) => { });
-    await navigator.mediaDevices.getUserMedia({audio:true, video:true}).then(assert_unreached, (e) => { });
+    // We should neither have audio nor video denied anymore.
+    await navigator.mediaDevices.getUserMedia({audio:true, video:false});
+    await navigator.mediaDevices.getUserMedia({audio:true, video:true});
 }, "Testing getUserMedia with and without user gesture after user denied access");
         </script>
     </body>

Added: trunk/LayoutTests/fast/mediastream/granted-denied-request-management1-expected.txt (0 => 274206)


--- trunk/LayoutTests/fast/mediastream/granted-denied-request-management1-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/fast/mediastream/granted-denied-request-management1-expected.txt	2021-03-10 11:52:49 UTC (rev 274206)
@@ -0,0 +1,3 @@
+
+PASS Remove audio denied request upon successful audio request
+

Added: trunk/LayoutTests/fast/mediastream/granted-denied-request-management1.html (0 => 274206)


--- trunk/LayoutTests/fast/mediastream/granted-denied-request-management1.html	                        (rev 0)
+++ trunk/LayoutTests/fast/mediastream/granted-denied-request-management1.html	2021-03-10 11:52:49 UTC (rev 274206)
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <meta charset="utf-8">
+    <script src=""
+    <script src=""
+</head>
+<body>
+    <script>
+promise_test(async (test) => {
+    if (!window.internals)
+        return;
+    if (window.testRunner)
+        testRunner.setUserMediaPermission(false);
+
+    await navigator.mediaDevices.getUserMedia({ audio: true }).then(assert_unreached, () => { });
+
+    if (window.testRunner)
+        testRunner.setUserMediaPermission(true);
+
+    let promise;
+    internals.withUserGesture(() => {
+        promise = navigator.mediaDevices.getUserMedia({ audio: true }).then((stream) => {
+            stream.getAudioTracks()[0].stop();
+        }, assert_unreached);
+    });
+    await promise;
+
+    return navigator.mediaDevices.getUserMedia({ audio: true });
+}, "Remove audio denied request upon successful audio request");
+    </script>
+</body>
+</html>

Added: trunk/LayoutTests/fast/mediastream/granted-denied-request-management2-expected.txt (0 => 274206)


--- trunk/LayoutTests/fast/mediastream/granted-denied-request-management2-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/fast/mediastream/granted-denied-request-management2-expected.txt	2021-03-10 11:52:49 UTC (rev 274206)
@@ -0,0 +1,3 @@
+
+PASS Remove audio denied request upon successful audio/video request
+

Added: trunk/LayoutTests/fast/mediastream/granted-denied-request-management2.html (0 => 274206)


--- trunk/LayoutTests/fast/mediastream/granted-denied-request-management2.html	                        (rev 0)
+++ trunk/LayoutTests/fast/mediastream/granted-denied-request-management2.html	2021-03-10 11:52:49 UTC (rev 274206)
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <meta charset="utf-8">
+    <script src=""
+    <script src=""
+</head>
+<body>
+    <script>
+promise_test(async (test) => {
+    if (!window.internals)
+        return;
+    if (window.testRunner)
+        testRunner.setUserMediaPermission(false);
+
+    await navigator.mediaDevices.getUserMedia({ audio: true }).then(assert_unreached, () => { });
+
+    if (window.testRunner)
+        testRunner.setUserMediaPermission(true);
+
+    let promise;
+    internals.withUserGesture(() => {
+        promise = navigator.mediaDevices.getUserMedia({ audio: true, video: true }).then((stream) => {
+            stream.getAudioTracks()[0].stop();
+            stream.getVideoTracks()[0].stop();
+        }, assert_unreached);
+    });
+    await promise;
+
+    return navigator.mediaDevices.getUserMedia({ audio: true });
+}, "Remove audio denied request upon successful audio/video request");
+    </script>
+</body>
+</html>

Modified: trunk/Source/WebKit/ChangeLog (274205 => 274206)


--- trunk/Source/WebKit/ChangeLog	2021-03-10 11:24:47 UTC (rev 274205)
+++ trunk/Source/WebKit/ChangeLog	2021-03-10 11:52:49 UTC (rev 274206)
@@ -1,3 +1,28 @@
+2021-03-10  Youenn Fablet  <[email protected]>
+
+        Remove getUserMedia denied requests if user grants a new getUserMedia request
+        https://bugs.webkit.org/show_bug.cgi?id=222962
+        <rdar://74805451>
+
+        Reviewed by Eric Carlson.
+
+        A user may deny an audio getUserMedia request.
+        On user gesture, user may be reprompted, in which case user may grant access.
+        Before the patch, after these two getUserMedia calls, if the web page was trying to call getUserMedia without user gesture, it would fail.
+        With this patch, we remove the first denied request based on the second granted request.
+        This allows getUserMedia to be granted, even without a user gesture.
+
+        Tests: fast/mediastream/granted-denied-request-management1.html
+               fast/mediastream/granted-denied-request-management2.html
+
+        * UIProcess/UserMediaPermissionRequestManagerProxy.cpp:
+        (WebKit::UserMediaPermissionRequestManagerProxy::finishGrantingRequest):
+        (WebKit::isMatchingDeniedRequest):
+        (WebKit::UserMediaPermissionRequestManagerProxy::wasRequestDenied):
+        (WebKit::UserMediaPermissionRequestManagerProxy::updateStoredRequests):
+        (WebKit::UserMediaPermissionRequestManagerProxy::getRequestAction):
+        * UIProcess/UserMediaPermissionRequestManagerProxy.h:
+
 2021-03-10  Commit Queue  <[email protected]>
 
         Unreviewed, reverting r274186.

Modified: trunk/Source/WebKit/UIProcess/UserMediaPermissionRequestManagerProxy.cpp (274205 => 274206)


--- trunk/Source/WebKit/UIProcess/UserMediaPermissionRequestManagerProxy.cpp	2021-03-10 11:24:47 UTC (rev 274205)
+++ trunk/Source/WebKit/UIProcess/UserMediaPermissionRequestManagerProxy.cpp	2021-03-10 11:52:49 UTC (rev 274206)
@@ -274,8 +274,7 @@
 
         auto& request = strongRequest.get();
 
-        if (request.requestType() == MediaStreamRequest::Type::UserMedia)
-            m_grantedRequests.append(makeRef(request));
+        updateStoredRequests(request);
 
         // FIXME: m_hasFilteredDeviceList will trigger ondevicechange events for various documents from different origins.
         if (m_hasFilteredDeviceList)
@@ -351,15 +350,18 @@
     return nullptr;
 }
 
-bool UserMediaPermissionRequestManagerProxy::wasRequestDenied(FrameIdentifier mainFrameID, const SecurityOrigin& userMediaDocumentOrigin, const SecurityOrigin& topLevelDocumentOrigin, bool needsAudio, bool needsVideo, bool needsScreenCapture)
+static bool isMatchingDeniedRequest(const UserMediaPermissionRequestProxy& request, const UserMediaPermissionRequestManagerProxy::DeniedRequest& deniedRequest)
 {
+    return deniedRequest.mainFrameID == request.mainFrameID()
+        && deniedRequest.userMediaDocumentOrigin->isSameSchemeHostPort(request.userMediaDocumentSecurityOrigin())
+        && deniedRequest.topLevelDocumentOrigin->isSameSchemeHostPort(request.topLevelDocumentSecurityOrigin());
+}
+
+bool UserMediaPermissionRequestManagerProxy::wasRequestDenied(const UserMediaPermissionRequestProxy& request, bool needsAudio, bool needsVideo, bool needsScreenCapture)
+{
     for (const auto& deniedRequest : m_deniedRequests) {
-        if (!deniedRequest.userMediaDocumentOrigin->isSameSchemeHostPort(userMediaDocumentOrigin))
+        if (!isMatchingDeniedRequest(request, deniedRequest))
             continue;
-        if (!deniedRequest.topLevelDocumentOrigin->isSameSchemeHostPort(topLevelDocumentOrigin))
-            continue;
-        if (deniedRequest.mainFrameID != mainFrameID)
-            continue;
 
         if (deniedRequest.isScreenCaptureDenied && needsScreenCapture)
             return true;
@@ -379,6 +381,25 @@
     return false;
 }
 
+void UserMediaPermissionRequestManagerProxy::updateStoredRequests(UserMediaPermissionRequestProxy& request)
+{
+    if (request.requestType() == MediaStreamRequest::Type::UserMedia)
+        m_grantedRequests.append(makeRef(request));
+
+    m_deniedRequests.removeAllMatching([&request](auto& deniedRequest) {
+        if (!isMatchingDeniedRequest(request, deniedRequest))
+            return false;
+
+        if (deniedRequest.isAudioDenied && request.requiresAudioCapture())
+            return true;
+        if (deniedRequest.isVideoDenied && request.requiresVideoCapture())
+            return true;
+        if (deniedRequest.isScreenCaptureDenied && request.requiresDisplayCapture())
+            return true;
+
+        return false;
+    });
+}
 #endif
 
 void UserMediaPermissionRequestManagerProxy::rejectionTimerFired()
@@ -405,7 +426,7 @@
     ASSERT(!(requestingScreenCapture && !request.hasVideoDevice()));
     ASSERT(!(requestingScreenCapture && requestingMicrophone));
 
-    if (!request.isUserGesturePriviledged() && wasRequestDenied(request.frameID(), request.userMediaDocumentSecurityOrigin(), request.topLevelDocumentSecurityOrigin(), requestingMicrophone, requestingCamera, requestingScreenCapture))
+    if (!request.isUserGesturePriviledged() && wasRequestDenied(request, requestingMicrophone, requestingCamera, requestingScreenCapture))
         return RequestAction::Deny;
 
     if (request.requestType() == MediaStreamRequest::Type::DisplayMedia)

Modified: trunk/Source/WebKit/UIProcess/UserMediaPermissionRequestManagerProxy.h (274205 => 274206)


--- trunk/Source/WebKit/UIProcess/UserMediaPermissionRequestManagerProxy.h	2021-03-10 11:24:47 UTC (rev 274205)
+++ trunk/Source/WebKit/UIProcess/UserMediaPermissionRequestManagerProxy.h	2021-03-10 11:52:49 UTC (rev 274206)
@@ -99,6 +99,15 @@
 
     void checkUserMediaPermissionForSpeechRecognition(WebCore::FrameIdentifier, const WebCore::SecurityOrigin&, const WebCore::SecurityOrigin&, const WebCore::CaptureDevice&, CompletionHandler<void(bool)>&&);
 
+    struct DeniedRequest {
+        WebCore::FrameIdentifier mainFrameID;
+        Ref<WebCore::SecurityOrigin> userMediaDocumentOrigin;
+        Ref<WebCore::SecurityOrigin> topLevelDocumentOrigin;
+        bool isAudioDenied;
+        bool isVideoDenied;
+        bool isScreenCaptureDenied;
+    };
+
 private:
 #if !RELEASE_LOG_DISABLED
     const Logger& logger() const final;
@@ -112,7 +121,7 @@
     void finishGrantingRequest(UserMediaPermissionRequestProxy&);
 
     const UserMediaPermissionRequestProxy* searchForGrantedRequest(WebCore::FrameIdentifier, const WebCore::SecurityOrigin& userMediaDocumentOrigin, const WebCore::SecurityOrigin& topLevelDocumentOrigin, bool needsAudio, bool needsVideo) const;
-    bool wasRequestDenied(WebCore::FrameIdentifier mainFrameID, const WebCore::SecurityOrigin& userMediaDocumentOrigin, const WebCore::SecurityOrigin& topLevelDocumentOrigin, bool needsAudio, bool needsVideo, bool needsScreenCapture);
+    bool wasRequestDenied(const UserMediaPermissionRequestProxy&, bool needsAudio, bool needsVideo, bool needsScreenCapture);
 
     using PermissionInfo = UserMediaPermissionCheckProxy::PermissionInfo;
     void getUserMediaPermissionInfo(WebCore::FrameIdentifier, Ref<WebCore::SecurityOrigin>&& userMediaDocumentOrigin, Ref<WebCore::SecurityOrigin>&& topLevelDocumentOrigin, CompletionHandler<void(PermissionInfo)>&&);
@@ -131,9 +140,7 @@
     void startProcessingUserMediaPermissionRequest(Ref<UserMediaPermissionRequestProxy>&&);
 
     static void requestSystemValidation(const WebPageProxy&, UserMediaPermissionRequestProxy&, CompletionHandler<void(bool)>&&);
-#endif
 
-#if ENABLE(MEDIA_STREAM)
     void platformValidateUserMediaRequestConstraints(WebCore::RealtimeMediaSourceCenter::ValidConstraintsHandler&& validHandler, WebCore::RealtimeMediaSourceCenter::InvalidConstraintsHandler&& invalidHandler, String&& deviceIDHashSalt);
 #endif
 
@@ -141,6 +148,7 @@
 
     void processNextUserMediaRequestIfNeeded();
     void decidePolicyForUserMediaPermissionRequest();
+    void updateStoredRequests(UserMediaPermissionRequestProxy&);
 
     RefPtr<UserMediaPermissionRequestProxy> m_currentUserMediaRequest;
     Deque<Ref<UserMediaPermissionRequestProxy>> m_pendingUserMediaRequests;
@@ -154,14 +162,6 @@
     Vector<Ref<UserMediaPermissionRequestProxy>> m_pregrantedRequests;
     Vector<Ref<UserMediaPermissionRequestProxy>> m_grantedRequests;
 
-    struct DeniedRequest {
-        WebCore::FrameIdentifier mainFrameID;
-        Ref<WebCore::SecurityOrigin> userMediaDocumentOrigin;
-        Ref<WebCore::SecurityOrigin> topLevelDocumentOrigin;
-        bool isAudioDenied;
-        bool isVideoDenied;
-        bool isScreenCaptureDenied;
-    };
     Vector<DeniedRequest> m_deniedRequests;
 
     WebCore::MediaProducer::MediaStateFlags m_captureState { WebCore::MediaProducer::IsNotPlaying };
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to