Title: [245625] trunk
Revision
245625
Author
[email protected]
Date
2019-05-22 10:38:42 -0700 (Wed, 22 May 2019)

Log Message

Implement Feature policy self/none/* parsing
https://bugs.webkit.org/show_bug.cgi?id=198078

Reviewed by Eric Carlson.

LayoutTests/imported/w3c:

* web-platform-tests/mediacapture-streams/MediaStream-feature-policy-none.https-expected.txt: Added.
* web-platform-tests/mediacapture-streams/MediaStream-feature-policy-none.https.html: Added.

Source/WebCore:

Start to implement https://w3c.github.io/webappsec-feature-policy/#algo-parse-policy-directive
'src' is not supported yet.
Apply the rules to getUserMedia.
Update getDisplayMedia keyword from 'display' to 'display-capture' as per spec.

Test: imported/w3c/web-platform-tests/mediacapture-streams/MediaStream-feature-policy-none.https.html

* Headers.cmake:
* Modules/mediastream/UserMediaController.cpp:
(WebCore::isSecure):
(WebCore::isAllowedByFeaturePolicy):
(WebCore::isAllowedToUse):
* Sources.txt:
* WebCore.xcodeproj/project.pbxproj:
* html/FeaturePolicy.cpp: Added.
(WebCore::isAllowedByFeaturePolicy):
(WebCore::processOriginItem):
(WebCore::updateList):
(WebCore::FeaturePolicy::parse):
(WebCore::FeaturePolicy::allows const):
* html/FeaturePolicy.h: Added.
* html/HTMLIFrameElement.cpp:
(WebCore::HTMLIFrameElement::featurePolicy const):
* html/HTMLIFrameElement.h:

Source/WebKit:

Fix a case where completion handler might not always be called.

* WebProcess/MediaStream/UserMediaPermissionRequestManager.cpp:
(WebKit::UserMediaPermissionRequestManager::userMediaAccessWasGranted):

LayoutTests:

* http/tests/media/media-stream/get-display-media-iframe-allow-attribute-expected.txt:
* http/tests/media/media-stream/get-display-media-iframe-allow-attribute.html:

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (245624 => 245625)


--- trunk/LayoutTests/ChangeLog	2019-05-22 17:31:06 UTC (rev 245624)
+++ trunk/LayoutTests/ChangeLog	2019-05-22 17:38:42 UTC (rev 245625)
@@ -1,3 +1,13 @@
+2019-05-22  Youenn Fablet  <[email protected]>
+
+        Implement Feature policy self/none/* parsing
+        https://bugs.webkit.org/show_bug.cgi?id=198078
+
+        Reviewed by Eric Carlson.
+
+        * http/tests/media/media-stream/get-display-media-iframe-allow-attribute-expected.txt:
+        * http/tests/media/media-stream/get-display-media-iframe-allow-attribute.html:
+
 2019-05-22  Alicia Boya GarcĂ­a  <[email protected]>
 
         [GTK] Unreviewed test gardening

Modified: trunk/LayoutTests/http/tests/media/media-stream/get-display-media-iframe-allow-attribute-expected.txt (245624 => 245625)


--- trunk/LayoutTests/http/tests/media/media-stream/get-display-media-iframe-allow-attribute-expected.txt	2019-05-22 17:31:06 UTC (rev 245624)
+++ trunk/LayoutTests/http/tests/media/media-stream/get-display-media-iframe-allow-attribute-expected.txt	2019-05-22 17:38:42 UTC (rev 245625)
@@ -5,5 +5,5 @@
 
 PASS: <iframe allow=''> got "deny"
 PASS: <iframe allow='camera'> got "deny"
-PASS: <iframe allow='display'> got "allow"
+PASS: <iframe allow='display-capture'> got "allow"
 PASS: <iframe allow='microphone'> got "deny"

Modified: trunk/LayoutTests/http/tests/media/media-stream/get-display-media-iframe-allow-attribute.html (245624 => 245625)


--- trunk/LayoutTests/http/tests/media/media-stream/get-display-media-iframe-allow-attribute.html	2019-05-22 17:31:06 UTC (rev 245624)
+++ trunk/LayoutTests/http/tests/media/media-stream/get-display-media-iframe-allow-attribute.html	2019-05-22 17:38:42 UTC (rev 245625)
@@ -5,7 +5,7 @@
     <iframe id="none" src=""
     <iframe id="camera" allow="camera" src=""
     <iframe id="microphone" allow="microphone" src=""
-    <iframe id="display" allow="display" src=""
+    <iframe id="display" allow="display-capture" src=""
 
     <script>
         if (window.testRunner) {

Modified: trunk/LayoutTests/imported/w3c/ChangeLog (245624 => 245625)


--- trunk/LayoutTests/imported/w3c/ChangeLog	2019-05-22 17:31:06 UTC (rev 245624)
+++ trunk/LayoutTests/imported/w3c/ChangeLog	2019-05-22 17:38:42 UTC (rev 245625)
@@ -1,3 +1,13 @@
+2019-05-22  Youenn Fablet  <[email protected]>
+
+        Implement Feature policy self/none/* parsing
+        https://bugs.webkit.org/show_bug.cgi?id=198078
+
+        Reviewed by Eric Carlson.
+
+        * web-platform-tests/mediacapture-streams/MediaStream-feature-policy-none.https-expected.txt: Added.
+        * web-platform-tests/mediacapture-streams/MediaStream-feature-policy-none.https.html: Added.
+
 2019-05-21  Antoine Quint  <[email protected]>
 
         [macOS] Compatibility mouse events aren't prevented by calling preventDefault() on pointerdown

Added: trunk/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaStream-feature-policy-none.https-expected.txt (0 => 245625)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaStream-feature-policy-none.https-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaStream-feature-policy-none.https-expected.txt	2019-05-22 17:38:42 UTC (rev 245625)
@@ -0,0 +1,48 @@
+CONSOLE MESSAGE: line 43: Trying to call getUserMedia from a frame without correct 'allow' attribute.
+CONSOLE MESSAGE: line 49: Trying to call getUserMedia from a frame without correct 'allow' attribute.
+CONSOLE MESSAGE: line 37: Trying to call getUserMedia from a frame without correct 'allow' attribute.
+CONSOLE MESSAGE: line 43: Trying to call getUserMedia from a frame without correct 'allow' attribute.
+CONSOLE MESSAGE: line 49: Trying to call getUserMedia from a frame without correct 'allow' attribute.
+CONSOLE MESSAGE: line 37: Trying to call getUserMedia from a frame without correct 'allow' attribute.
+CONSOLE MESSAGE: line 49: Trying to call getUserMedia from a frame without correct 'allow' attribute.
+CONSOLE MESSAGE: line 37: Trying to call getUserMedia from a frame without correct 'allow' attribute.
+CONSOLE MESSAGE: line 43: Trying to call getUserMedia from a frame without correct 'allow' attribute.
+CONSOLE MESSAGE: line 49: Trying to call getUserMedia from a frame without correct 'allow' attribute.
+CONSOLE MESSAGE: line 37: Trying to call getUserMedia from a frame without correct 'allow' attribute.
+CONSOLE MESSAGE: line 49: Trying to call getUserMedia from a frame without correct 'allow' attribute.
+CONSOLE MESSAGE: line 37: Trying to call getUserMedia from a frame without correct 'allow' attribute.
+CONSOLE MESSAGE: line 49: Trying to call getUserMedia from a frame without correct 'allow' attribute.
+CONSOLE MESSAGE: line 43: Trying to call getUserMedia from a frame without correct 'allow' attribute.
+CONSOLE MESSAGE: line 49: Trying to call getUserMedia from a frame without correct 'allow' attribute.
+CONSOLE MESSAGE: line 37: Trying to call getUserMedia from a frame without correct 'allow' attribute.
+CONSOLE MESSAGE: line 49: Trying to call getUserMedia from a frame without correct 'allow' attribute.
+CONSOLE MESSAGE: line 43: Trying to call getUserMedia from a frame without correct 'allow' attribute.
+CONSOLE MESSAGE: line 49: Trying to call getUserMedia from a frame without correct 'allow' attribute.
+CONSOLE MESSAGE: line 43: Trying to call getUserMedia from a frame without correct 'allow' attribute.
+CONSOLE MESSAGE: line 49: Trying to call getUserMedia from a frame without correct 'allow' attribute.
+CONSOLE MESSAGE: line 43: Trying to call getUserMedia from a frame without correct 'allow' attribute.
+CONSOLE MESSAGE: line 49: Trying to call getUserMedia from a frame without correct 'allow' attribute.
+CONSOLE MESSAGE: line 37: Trying to call getUserMedia from a frame without correct 'allow' attribute.
+CONSOLE MESSAGE: line 49: Trying to call getUserMedia from a frame without correct 'allow' attribute.
+CONSOLE MESSAGE: line 43: Trying to call getUserMedia from a frame without correct 'allow' attribute.
+CONSOLE MESSAGE: line 49: Trying to call getUserMedia from a frame without correct 'allow' attribute.
+
+PASS "camera 'none'" - same origin iframe 
+PASS "camera 'none'" - cross origin iframe 
+PASS "microphone 'none'" - same origin iframe 
+PASS "microphone 'none';camera 'none'" - same origin iframe 
+PASS "camera *;microphone 'none'" - same origin iframe 
+PASS "camera *;microphone 'none'" - cross origin iframe 
+PASS "camera 'none';microphone *" - same origin iframe 
+PASS "microphone *; microphone 'none'" - same origin iframe 
+PASS "microphone *; microphone ' none'" - same origin iframe 
+PASS "microphone *; microphone none" - same origin iframe 
+PASS "microphone *; camera 'self'" - same origin iframe 
+PASS "microphone *; camera 'self'" - cross origin iframe 
+PASS "microphone *; camera http:/example.org self" - same origin iframe 
+PASS "microphone *; camera http:/example.org 'self'" - same origin iframe 
+PASS "microphone *; camera http:/example.org 'self'" - cross origin iframe 
+PASS "microphone https://127.0.0.1:9443" - same origin iframe 
+PASS "microphone https://127.0.0.1:9443" - cross origin iframe 
+PASS "microphone 'self' https://127.0.0.1:9443" - same origin iframe 
+

Added: trunk/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaStream-feature-policy-none.https.html (0 => 245625)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaStream-feature-policy-none.https.html	                        (rev 0)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaStream-feature-policy-none.https.html	2019-05-22 17:38:42 UTC (rev 245625)
@@ -0,0 +1,96 @@
+<!DOCTYPE html>
+<body>
+    <script src=""
+    <script src=""
+    <script src=""
+    <script>
+function withIFrame(url, allow) {
+    return new Promise(resolve => {
+        let frame = document.createElement('iframe');
+        frame.src = ""
+        frame.allow = allow;
+        frame._onload_ = () => { resolve(frame); };
+        document.body.appendChild(frame);
+    });
+}
+
+var crossDomain = get_host_info().HTTPS_REMOTE_ORIGIN;
+function runTestInIFrame(allow, crossOrigin)
+{
+    return new Promise(async resolve => {
+        window.addEventListener('message', function handler(event) {
+            resolve(event.data);
+            window.removeEventListener('message', handler);
+            iframe.remove();
+        });
+        let url = "" + "#test";
+        if (crossOrigin)
+            url = "" + url;
+        const iframe = await withIFrame(url, allow);
+    });
+}
+
+async function doTest()
+{
+    let results = { };
+    try {
+        await navigator.mediaDevices.getUserMedia({audio : true});
+        results.audio = true;
+    } catch (e) {
+        results.audio = false;
+    }
+    try {
+        await navigator.mediaDevices.getUserMedia({video : true});
+        results.video = true;
+    } catch (e) {
+        results.video = false;
+    }
+    try {
+        await navigator.mediaDevices.getUserMedia({audio : true, video : true});
+        results.audioVideo = true;
+    } catch (e) {
+        results.audioVideo = false;
+    }
+    return results;
+}
+
+if (location.hash == "#test") {
+    doTest().then(data ="" {
+        parent.postMessage(data, '*');
+    }, error => {
+        parent.postMessage('error', '*');
+    });
+} else {
+    var gum_tests = [
+        { allow: "camera 'none'", results: { audio: true, video: false, audioVideo: false } },
+        { allow: "camera 'none'", results: { audio: false, video: false, audioVideo: false }, crossOrigin: true },
+        { allow: "microphone 'none'", results: { audio: false, video: true, audioVideo: false } },
+        { allow: "microphone 'none';camera 'none'", results: { audio: false, video: false, audioVideo: false } },
+        { allow: "camera *;microphone 'none'", results: { audio: false, video: true, audioVideo: false } },
+        { allow: "camera *;microphone 'none'", results: { audio: false, video: true, audioVideo: false }, crossOrigin: true },
+        { allow: "camera 'none';microphone *", results: { audio: true, video: false, audioVideo: false } },
+        { allow: "microphone *; microphone 'none'", results: { audio: false, video: true, audioVideo: false } },
+        { allow: "microphone *; microphone ' none'", results: { audio: true, video: true, audioVideo: true } },
+        { allow: "microphone *; microphone none", results: { audio: true, video: true, audioVideo: true } },
+        { allow: "microphone *; camera 'self'", results: { audio: true, video: true, audioVideo: true } },
+        { allow: "microphone *; camera 'self'", results: { audio: true, video: false, audioVideo: false }, crossOrigin: true },
+        { allow: "microphone *; camera http:/example.org self", results: { audio: true, video: false, audioVideo: false } },
+        { allow: "microphone *; camera http:/example.org 'self'", results: { audio: true, video: true, audioVideo: true } },
+        { allow: "microphone *; camera http:/example.org 'self'", results: { audio: true, video: false, audioVideo: false }, crossOrigin: true },
+        { allow: "microphone " + crossDomain, results: { audio: false, video: true, audioVideo: false } },
+        { allow: "microphone " + crossDomain, results: { audio: true, video: false, audioVideo: false }, crossOrigin: true },
+        { allow: "microphone 'self' " + crossDomain, results: { audio: true, video: true, audioVideo: true } },
+    ];
+
+    for (let gum_test of gum_tests) {
+        promise_test(async (test) => {
+            const results = await runTestInIFrame(gum_test.allow, gum_test.crossOrigin);
+            assert_equals(results.audio, gum_test.results.audio, "audio");
+            assert_equals(results.video, gum_test.results.video, "video");
+            assert_equals(results.audioVideo, gum_test.results.audioVideo, "audioVideo");
+        }, "\"" + gum_test.allow + "\" - " + (gum_test.crossOrigin ? "cross origin iframe" : "same origin iframe"));
+    }
+}
+  </script>
+</body>
+

Modified: trunk/Source/WebCore/ChangeLog (245624 => 245625)


--- trunk/Source/WebCore/ChangeLog	2019-05-22 17:31:06 UTC (rev 245624)
+++ trunk/Source/WebCore/ChangeLog	2019-05-22 17:38:42 UTC (rev 245625)
@@ -1,3 +1,35 @@
+2019-05-22  Youenn Fablet  <[email protected]>
+
+        Implement Feature policy self/none/* parsing
+        https://bugs.webkit.org/show_bug.cgi?id=198078
+
+        Reviewed by Eric Carlson.
+
+        Start to implement https://w3c.github.io/webappsec-feature-policy/#algo-parse-policy-directive
+        'src' is not supported yet.
+        Apply the rules to getUserMedia.
+        Update getDisplayMedia keyword from 'display' to 'display-capture' as per spec.
+
+        Test: imported/w3c/web-platform-tests/mediacapture-streams/MediaStream-feature-policy-none.https.html
+
+        * Headers.cmake:
+        * Modules/mediastream/UserMediaController.cpp:
+        (WebCore::isSecure):
+        (WebCore::isAllowedByFeaturePolicy):
+        (WebCore::isAllowedToUse):
+        * Sources.txt:
+        * WebCore.xcodeproj/project.pbxproj:
+        * html/FeaturePolicy.cpp: Added.
+        (WebCore::isAllowedByFeaturePolicy):
+        (WebCore::processOriginItem):
+        (WebCore::updateList):
+        (WebCore::FeaturePolicy::parse):
+        (WebCore::FeaturePolicy::allows const):
+        * html/FeaturePolicy.h: Added.
+        * html/HTMLIFrameElement.cpp:
+        (WebCore::HTMLIFrameElement::featurePolicy const):
+        * html/HTMLIFrameElement.h:
+
 2019-05-21  Jer Noble  <[email protected]>
 
         Media controls don't show in WK2 video fullscreen sometimes

Modified: trunk/Source/WebCore/Headers.cmake (245624 => 245625)


--- trunk/Source/WebCore/Headers.cmake	2019-05-22 17:31:06 UTC (rev 245624)
+++ trunk/Source/WebCore/Headers.cmake	2019-05-22 17:38:42 UTC (rev 245625)
@@ -526,6 +526,7 @@
     html/CollectionType.h
     html/DOMTokenList.h
     html/DataListSuggestionInformation.h
+    html/FeaturePolicy.h
     html/FormAssociatedElement.h
     html/FormNamedItem.h
     html/HTMLAnchorElement.h

Modified: trunk/Source/WebCore/Modules/mediastream/UserMediaController.cpp (245624 => 245625)


--- trunk/Source/WebCore/Modules/mediastream/UserMediaController.cpp	2019-05-22 17:31:06 UTC (rev 245624)
+++ trunk/Source/WebCore/Modules/mediastream/UserMediaController.cpp	2019-05-22 17:38:42 UTC (rev 245625)
@@ -61,7 +61,7 @@
     UserMediaController::provideTo(page, UserMediaController::supplementName(), std::make_unique<UserMediaController>(client));
 }
 
-static bool isSecure(DocumentLoader& documentLoader)
+static inline bool isSecure(DocumentLoader& documentLoader)
 {
     auto& response = documentLoader.response();
     if (SecurityOrigin::isLocalHostOrLoopbackIPAddress(documentLoader.response().url().host()))
@@ -71,6 +71,20 @@
         && !response.certificateInfo()->containsNonRootSHA1SignedCertificate();
 }
 
+static inline bool isAllowedByFeaturePolicy(const FeaturePolicy& featurePolicy, const SecurityOriginData& origin, OptionSet<UserMediaController::CaptureType> types)
+{
+    if ((types & UserMediaController::CaptureType::Camera) && !featurePolicy.allows(FeaturePolicy::Type::Camera, origin))
+        return false;
+
+    if ((types & UserMediaController::CaptureType::Microphone) && !featurePolicy.allows(FeaturePolicy::Type::Microphone, origin))
+        return false;
+
+    if ((types & UserMediaController::CaptureType::Display) && !featurePolicy.allows(FeaturePolicy::Type::DisplayCapture, origin))
+        return false;
+
+    return true;
+}
+
 static UserMediaController::GetUserMediaAccess isAllowedToUse(Document& document, Document& topDocument, OptionSet<UserMediaController::CaptureType> types)
 {
     if (&document == &topDocument)
@@ -80,31 +94,13 @@
     if (!parentDocument)
         return UserMediaController::GetUserMediaAccess::BlockedByParent;
 
-    if (document.securityOrigin().isSameSchemeHostPort(parentDocument->securityOrigin()))
-        return UserMediaController::GetUserMediaAccess::CanCall;
-
     auto* element = document.ownerElement();
     ASSERT(element);
-    if (!element)
+    if (!element || !is<HTMLIFrameElement>(*element))
         return UserMediaController::GetUserMediaAccess::BlockedByParent;
 
-    if (!is<HTMLIFrameElement>(*element))
-        return UserMediaController::GetUserMediaAccess::BlockedByParent;
-    auto& allow = downcast<HTMLIFrameElement>(*element).allow();
-
-    bool allowCameraAccess = false;
-    bool allowMicrophoneAccess = false;
-    bool allowDisplay = false;
-    for (auto allowItem : StringView { allow }.split(';')) {
-        auto item = allowItem.stripLeadingAndTrailingMatchedCharacters(isHTMLSpace<UChar>);
-        if (!allowCameraAccess && item == "camera")
-            allowCameraAccess = true;
-        else if (!allowMicrophoneAccess && item == "microphone")
-            allowMicrophoneAccess = true;
-        else if (!allowDisplay && item == "display")
-            allowDisplay = true;
-    }
-    if ((allowCameraAccess || !(types & UserMediaController::CaptureType::Camera)) && (allowMicrophoneAccess || !(types & UserMediaController::CaptureType::Microphone)) && (allowDisplay || !(types & UserMediaController::CaptureType::Display)))
+    auto& featurePolicy = downcast<HTMLIFrameElement>(*element).featurePolicy();
+    if (isAllowedByFeaturePolicy(featurePolicy, document.securityOrigin().data(), types))
         return UserMediaController::GetUserMediaAccess::CanCall;
 
     return UserMediaController::GetUserMediaAccess::BlockedByFeaturePolicy;

Modified: trunk/Source/WebCore/Sources.txt (245624 => 245625)


--- trunk/Source/WebCore/Sources.txt	2019-05-22 17:31:06 UTC (rev 245624)
+++ trunk/Source/WebCore/Sources.txt	2019-05-22 17:38:42 UTC (rev 245625)
@@ -1075,6 +1075,7 @@
 html/EmailInputType.cpp
 html/FTPDirectoryDocument.cpp
 html/FileListCreator.cpp
+html/FeaturePolicy.cpp
 html/FileInputType.cpp
 html/FormAssociatedElement.cpp
 html/FormController.cpp

Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (245624 => 245625)


--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2019-05-22 17:31:06 UTC (rev 245624)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2019-05-22 17:38:42 UTC (rev 245625)
@@ -1104,6 +1104,7 @@
 		419ACF921F97E7DA009F1A83 /* ServiceWorkerFetch.h in Headers */ = {isa = PBXBuildFile; fileRef = 419ACF8E1F97E7D5009F1A83 /* ServiceWorkerFetch.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		419BC2DF1685329900D64D6D /* VisitedLinkState.h in Headers */ = {isa = PBXBuildFile; fileRef = 419BC2DD1685329900D64D6D /* VisitedLinkState.h */; };
 		419BE7591BC7F42B00E1C85B /* WebCoreBuiltinNames.h in Headers */ = {isa = PBXBuildFile; fileRef = 419BE7521BC7F3DB00E1C85B /* WebCoreBuiltinNames.h */; };
+		41A0829C22935F3D008426E0 /* FeaturePolicy.h in Headers */ = {isa = PBXBuildFile; fileRef = 41A0829922932EF4008426E0 /* FeaturePolicy.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		41A1B01C1E54239B007F3769 /* JSDOMGuardedObject.h in Headers */ = {isa = PBXBuildFile; fileRef = 41A1B01A1E542396007F3769 /* JSDOMGuardedObject.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		41A3D58F101C152D00316D07 /* DedicatedWorkerThread.h in Headers */ = {isa = PBXBuildFile; fileRef = 41A3D58D101C152D00316D07 /* DedicatedWorkerThread.h */; };
 		41A7D3531F438D16008988DE /* WorkerCacheStorageConnection.h in Headers */ = {isa = PBXBuildFile; fileRef = 41A7D3501F438D10008988DE /* WorkerCacheStorageConnection.h */; };
@@ -7323,6 +7324,8 @@
 		419FAFAD1ABABCD5005B828B /* ReadableStreamDefaultReader.idl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = ReadableStreamDefaultReader.idl; sourceTree = "<group>"; };
 		41A023ED1A39DB7900F722CF /* ReadableStream.idl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = ReadableStream.idl; sourceTree = "<group>"; };
 		41A023ED1A39DB7900F722DF /* WritableStream.idl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = WritableStream.idl; sourceTree = "<group>"; };
+		41A0829922932EF4008426E0 /* FeaturePolicy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FeaturePolicy.h; sourceTree = "<group>"; };
+		41A0829B22932EF4008426E0 /* FeaturePolicy.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FeaturePolicy.cpp; sourceTree = "<group>"; };
 		41A1B00D1E52656E007F3769 /* LibWebRTCProvider.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = LibWebRTCProvider.cpp; path = libwebrtc/LibWebRTCProvider.cpp; sourceTree = "<group>"; };
 		41A1B01A1E542396007F3769 /* JSDOMGuardedObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSDOMGuardedObject.h; sourceTree = "<group>"; };
 		41A1B01B1E542396007F3769 /* JSDOMGuardedObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSDOMGuardedObject.cpp; sourceTree = "<group>"; };
@@ -21209,6 +21212,8 @@
 				2E37DFD912DBAFB800A6B233 /* DOMURL.idl */,
 				F55B3D871251F12D003EF269 /* EmailInputType.cpp */,
 				F55B3D881251F12D003EF269 /* EmailInputType.h */,
+				41A0829B22932EF4008426E0 /* FeaturePolicy.cpp */,
+				41A0829922932EF4008426E0 /* FeaturePolicy.h */,
 				F55B3D891251F12D003EF269 /* FileInputType.cpp */,
 				F55B3D8A1251F12D003EF269 /* FileInputType.h */,
 				835D54C11F4DE53400E60671 /* FileListCreator.cpp */,
@@ -28958,6 +28963,7 @@
 				E47E276516036ED200EE2AFB /* ExtensionStyleSheets.h in Headers */,
 				5C4304B1191AC908000E2BC0 /* EXTShaderTextureLOD.h in Headers */,
 				7728694F14F8882500F484DC /* EXTTextureFilterAnisotropic.h in Headers */,
+				41A0829C22935F3D008426E0 /* FeaturePolicy.h in Headers */,
 				A75E8B890E1DE2D6007F2481 /* FEBlend.h in Headers */,
 				A75E8B8B0E1DE2D6007F2481 /* FEColorMatrix.h in Headers */,
 				A75E8B8D0E1DE2D6007F2481 /* FEComponentTransfer.h in Headers */,

Added: trunk/Source/WebCore/html/FeaturePolicy.cpp (0 => 245625)


--- trunk/Source/WebCore/html/FeaturePolicy.cpp	                        (rev 0)
+++ trunk/Source/WebCore/html/FeaturePolicy.cpp	2019-05-22 17:38:42 UTC (rev 245625)
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2019 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "FeaturePolicy.h"
+
+#include "Document.h"
+#include "SecurityOrigin.h"
+
+namespace WebCore {
+
+static bool isAllowedByFeaturePolicy(const FeaturePolicy::AllowRule& rule, const SecurityOriginData& origin)
+{
+    switch (rule.type) {
+    case FeaturePolicy::AllowRule::Type::None:
+        return false;
+    case FeaturePolicy::AllowRule::Type::All:
+        return true;
+    case FeaturePolicy::AllowRule::Type::List:
+        return rule.allowedList.contains(origin);
+    }
+    ASSERT_NOT_REACHED();
+    return false;
+}
+
+static inline void processOriginItem(Document& document, FeaturePolicy::AllowRule& rule, StringView item)
+{
+    if (rule.type == FeaturePolicy::AllowRule::Type::None)
+        return;
+
+    item = item.stripLeadingAndTrailingMatchedCharacters(isHTMLSpace<UChar>);
+    // FIXME: Support 'src'.
+    if (item == "'src'")
+        return;
+
+    if (item == "*") {
+        rule.type = FeaturePolicy::AllowRule::Type::All;
+        return;
+    }
+
+    if (item == "'self'") {
+        rule.allowedList.add(document.securityOrigin().data());
+        return;
+    }
+    if (item == "'none'") {
+        rule.type = FeaturePolicy::AllowRule::Type::None;
+        return;
+    }
+    URL url { { }, item.toString() };
+    if (url.isValid())
+        rule.allowedList.add(SecurityOriginData::fromURL(url));
+}
+
+static inline void updateList(Document& document, FeaturePolicy::AllowRule& rule, StringView value)
+{
+    // We keep the empty string value equivalent to '*' for existing websites.
+    if (value.isEmpty()) {
+        rule.type = FeaturePolicy::AllowRule::Type::All;
+        return;
+    }
+
+    while (!value.isEmpty()) {
+        auto position = value.find(isHTMLSpace<UChar>);
+        if (position == notFound) {
+            processOriginItem(document, rule, value);
+            return;
+        }
+
+        processOriginItem(document, rule, value.substring(0, position));
+        value = value.substring(position + 1).stripLeadingAndTrailingMatchedCharacters(isHTMLSpace<UChar>);
+    }
+}
+
+FeaturePolicy FeaturePolicy::parse(Document& document, StringView allowAttributeValue)
+{
+    FeaturePolicy policy;
+    bool isCameraInitialized = false;
+    bool isMicrophoneInitialized = false;
+    bool isDisplayCaptureInitialized = false;
+    for (auto allowItem : allowAttributeValue.split(';')) {
+        auto item = allowItem.stripLeadingAndTrailingMatchedCharacters(isHTMLSpace<UChar>);
+        if (item.startsWith("camera")) {
+            isCameraInitialized = true;
+            updateList(document, policy.m_cameraRule, item.substring(7));
+            continue;
+        }
+        if (item.startsWith("microphone")) {
+            isMicrophoneInitialized = true;
+            updateList(document, policy.m_microphoneRule, item.substring(11));
+            continue;
+        }
+        if (item.startsWith("display-capture")) {
+            isDisplayCaptureInitialized = true;
+            updateList(document, policy.m_displayCaptureRule, item.substring(16));
+            continue;
+        }
+    }
+
+    // By default, camera, microphone and display-capture policy is 'self'
+    if (!isCameraInitialized)
+        policy.m_cameraRule.allowedList.add(document.securityOrigin().data());
+    if (!isMicrophoneInitialized)
+        policy.m_microphoneRule.allowedList.add(document.securityOrigin().data());
+    if (!isDisplayCaptureInitialized)
+        policy.m_displayCaptureRule.allowedList.add(document.securityOrigin().data());
+
+    return policy;
+}
+
+bool FeaturePolicy::allows(Type type, const SecurityOriginData& origin) const
+{
+    switch (type) {
+    case Type::Camera:
+        return isAllowedByFeaturePolicy(m_cameraRule, origin);
+    case Type::Microphone:
+        return isAllowedByFeaturePolicy(m_microphoneRule, origin);
+    case Type::DisplayCapture:
+        return isAllowedByFeaturePolicy(m_displayCaptureRule, origin);
+    }
+    ASSERT_NOT_REACHED();
+    return false;
+}
+
+}

Added: trunk/Source/WebCore/html/FeaturePolicy.h (0 => 245625)


--- trunk/Source/WebCore/html/FeaturePolicy.h	                        (rev 0)
+++ trunk/Source/WebCore/html/FeaturePolicy.h	2019-05-22 17:38:42 UTC (rev 245625)
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2019 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include "SecurityOriginData.h"
+#include <wtf/HashSet.h>
+#include <wtf/text/StringHash.h>
+
+namespace WebCore {
+
+class Document;
+
+class FeaturePolicy {
+public:
+    static FeaturePolicy parse(Document&, StringView);
+
+    enum class Type { Camera, Microphone, DisplayCapture };
+    bool allows(Type, const SecurityOriginData&) const;
+
+    struct AllowRule {
+        enum class Type { All, None, List };
+        Type type { Type::List };
+        HashSet<SecurityOriginData> allowedList;
+    };
+
+private:
+    AllowRule m_cameraRule;
+    AllowRule m_microphoneRule;
+    AllowRule m_displayCaptureRule;
+};
+
+} // namespace WebCore

Modified: trunk/Source/WebCore/html/HTMLIFrameElement.cpp (245624 => 245625)


--- trunk/Source/WebCore/html/HTMLIFrameElement.cpp	2019-05-22 17:31:06 UTC (rev 245624)
+++ trunk/Source/WebCore/html/HTMLIFrameElement.cpp	2019-05-22 17:38:42 UTC (rev 245625)
@@ -150,4 +150,11 @@
     return ReferrerPolicy::EmptyString;
 }
 
+const FeaturePolicy& HTMLIFrameElement::featurePolicy() const
+{
+    if (!m_featurePolicy)
+        m_featurePolicy = FeaturePolicy::parse(document(), m_allow);
+    return *m_featurePolicy;
 }
+
+}

Modified: trunk/Source/WebCore/html/HTMLIFrameElement.h (245624 => 245625)


--- trunk/Source/WebCore/html/HTMLIFrameElement.h	2019-05-22 17:31:06 UTC (rev 245624)
+++ trunk/Source/WebCore/html/HTMLIFrameElement.h	2019-05-22 17:38:42 UTC (rev 245625)
@@ -23,6 +23,7 @@
 
 #pragma once
 
+#include "FeaturePolicy.h"
 #include "HTMLFrameElementBase.h"
 
 namespace WebCore {
@@ -44,6 +45,8 @@
     String referrerPolicyForBindings() const;
     ReferrerPolicy referrerPolicy() const final;
 
+    const FeaturePolicy& featurePolicy() const;
+
 private:
     HTMLIFrameElement(const QualifiedName&, Document&);
 
@@ -60,6 +63,7 @@
 
     std::unique_ptr<DOMTokenList> m_sandbox;
     String m_allow;
+    mutable Optional<FeaturePolicy> m_featurePolicy;
 };
 
 } // namespace WebCore

Modified: trunk/Source/WebKit/ChangeLog (245624 => 245625)


--- trunk/Source/WebKit/ChangeLog	2019-05-22 17:31:06 UTC (rev 245624)
+++ trunk/Source/WebKit/ChangeLog	2019-05-22 17:38:42 UTC (rev 245625)
@@ -1,3 +1,15 @@
+2019-05-22  Youenn Fablet  <[email protected]>
+
+        Implement Feature policy self/none/* parsing
+        https://bugs.webkit.org/show_bug.cgi?id=198078
+
+        Reviewed by Eric Carlson.
+
+        Fix a case where completion handler might not always be called.
+
+        * WebProcess/MediaStream/UserMediaPermissionRequestManager.cpp:
+        (WebKit::UserMediaPermissionRequestManager::userMediaAccessWasGranted):
+
 2019-05-22  Ross Kirsling  <[email protected]>
 
         Unreviewed fix for non-unified build after r245320.

Modified: trunk/Source/WebKit/WebProcess/MediaStream/UserMediaPermissionRequestManager.cpp (245624 => 245625)


--- trunk/Source/WebKit/WebProcess/MediaStream/UserMediaPermissionRequestManager.cpp	2019-05-22 17:31:06 UTC (rev 245624)
+++ trunk/Source/WebKit/WebProcess/MediaStream/UserMediaPermissionRequestManager.cpp	2019-05-22 17:38:42 UTC (rev 245625)
@@ -140,8 +140,10 @@
 void UserMediaPermissionRequestManager::userMediaAccessWasGranted(uint64_t requestID, CaptureDevice&& audioDevice, CaptureDevice&& videoDevice, String&& deviceIdentifierHashSalt, CompletionHandler<void()>&& completionHandler)
 {
     auto request = m_idToUserMediaRequestMap.take(requestID);
-    if (!request)
+    if (!request) {
+        completionHandler();
         return;
+    }
     removeMediaRequestFromMaps(*request);
 
     request->allow(WTFMove(audioDevice), WTFMove(videoDevice), WTFMove(deviceIdentifierHashSalt), WTFMove(completionHandler));
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to