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 };