Allow specifying which plug-ins are supported
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 16 Feb 2018 23:31:31 +0000 (23:31 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 16 Feb 2018 23:31:31 +0000 (23:31 +0000)
https://bugs.webkit.org/show_bug.cgi?id=182748

Patch by Youenn Fablet <youenn@apple.com> on 2018-02-16
Reviewed by Chris Dumez.

Source/WebCore:

Tests: http/tests/plugins/nounsupported-plugin.html
       http/tests/plugins/supported-plugin-all-origin-visibility.html
       http/tests/plugins/supported-plugin-on-specific-origin.html
       http/tests/plugins/supported-plugin-origin-specific-visibility.html
       http/tests/plugins/unsupported-plugin-on-specific-origin.html
       plugins/unsupported-plugin.html

Added support for computing plugin web visibility with the added knowledge of supported plugins.
In case of a plugin failing to be created due to being unsupported, update the UI
to use mark the plugin as "Unexpected plug in".

Added internal API to retrieve the plug-in error description message.

* English.lproj/Localizable.strings:
* WebCore.xcodeproj/project.pbxproj:
* html/HTMLPlugInElement.cpp:
(WebCore::HTMLPlugInElement::setReplacement):
* html/HTMLPlugInElement.h:
* loader/EmptyClients.cpp:
* platform/LocalizedStrings.cpp:
(WebCore::unsupportedPluginText):
* platform/LocalizedStrings.h:
* plugins/PluginData.cpp:
(WebCore::PluginData::initPlugins):
* plugins/PluginData.h:
(WebCore::decodePluginNames):
(WebCore::encodePluginNames):
(WebCore::SupportedPluginNames::decode):
(WebCore::SupportedPluginNames::encode const):
* plugins/PluginInfoProvider.h:
* rendering/RenderEmbeddedObject.cpp:
(WebCore::unavailablePluginReplacementText):
* rendering/RenderEmbeddedObject.h:
(WebCore::RenderEmbeddedObject::pluginReplacementTextIfUnavailable const):
* testing/Internals.cpp:
(WebCore::Internals::unavailablePluginReplacementText):
* testing/Internals.h:
* testing/Internals.idl:

Source/WebKit:

Add a C and ObjC API to set which plug-ins are specified.
Plug-ins may be allowed by origin of the main page or for all origins.

If the API to set a supported plug-in is called, WebKit enters a mode
where it will block any plug-in that is not on the list.

The list of supported plug-ins is stored in UIProcess and sent to WebProcess.
This allows to compute the list of visible plug-ins according supported plugins.

PluginInfoStore is storing the list of supported plugins and can
answer whether a plug-in creation request is to be made unsupported or not.
It also creates the structure sent to WebProcess for computing plugin visibility.

Updated ArgumentCoders to accept modern HashSet decoders.

* Platform/IPC/ArgumentCoders.h:
* UIProcess/API/C/WKContext.cpp:
(WKContextAddSupportedPlugin):
(WKContextClearSupportedPlugins):
* UIProcess/API/C/WKContextPrivate.h:
* UIProcess/API/Cocoa/WKProcessPool.mm:
(-[WKProcessPool _addSupportedPlugin:named:withMimeTypes:withExtensions:]):
* UIProcess/API/Cocoa/WKProcessPoolPrivate.h:
* UIProcess/Plugins/PluginInfoStore.cpp:
(WebKit::PluginInfoStore::isSupportedPlugin):
(WebKit::PluginInfoStore::SupportedPlugins::isSupported):
(WebKit::PluginInfoStore::SupportedPlugin::isSupported):
(WebKit::PluginInfoStore::supportedPluginNames):
(WebKit::PluginInfoStore::addSupportedPlugin):
* UIProcess/Plugins/PluginInfoStore.h:
(WebKit::PluginInfoStore::clearSupportedPlugins):
* UIProcess/WebPageProxy.cpp:
(WebKit::WebPageProxy::findPlugin):
(WebKit::WebPageProxy::unavailablePluginButtonClicked):
* UIProcess/WebPageProxy.h:
* UIProcess/WebPageProxy.messages.in:
* UIProcess/WebProcessPool.cpp:
(WebKit::WebProcessPool::addSupportedPlugin):
(WebKit::WebProcessPool::clearSupportedPlugins):
* UIProcess/WebProcessPool.h:
* UIProcess/WebProcessProxy.cpp:
(WebKit::WebProcessProxy::getPlugins):
* UIProcess/WebProcessProxy.h:
* UIProcess/WebProcessProxy.messages.in:
* WebProcess/Plugins/WebPluginInfoProvider.cpp:
(WebKit::WebPluginInfoProvider::getPluginInfo):
(WebKit::WebPluginInfoProvider::getWebVisiblePluginInfo):
(WebKit::WebPluginInfoProvider::populatePluginCache):
* WebProcess/Plugins/WebPluginInfoProvider.h:
* WebProcess/WebCoreSupport/WebChromeClient.cpp:
(WebKit::WebChromeClient::shouldUnavailablePluginMessageBeButton const):
* WebProcess/WebPage/WebPage.cpp:
(WebKit::WebPage::createPlugin):
(WebKit::WebPage::canPluginHandleResponse):

Source/WebKitLegacy/mac:

* WebCoreSupport/WebPluginInfoProvider.h:
* WebCoreSupport/WebPluginInfoProvider.mm:
(WebPluginInfoProvider::getPluginInfo):
(WebPluginInfoProvider::getWebVisiblePluginInfo):

Source/WebKitLegacy/win:

* WebCoreSupport/WebPluginInfoProvider.cpp:
(WebPluginInfoProvider::getPluginInfo):
* WebCoreSupport/WebPluginInfoProvider.h:

Tools:

Add support for a test runner API to specificy supported plug-ins.

* WebKitTestRunner/InjectedBundle/Bindings/TestRunner.idl:
* WebKitTestRunner/InjectedBundle/TestRunner.cpp:
(WTR::TestRunner::setPluginsAsUnsupported):
* WebKitTestRunner/InjectedBundle/TestRunner.h:
* WebKitTestRunner/TestController.cpp:
(WTR::TestController::resetStateToConsistentValues):
(WTR::TestController::setPluginsAsUnsupported):
* WebKitTestRunner/TestController.h:
* WebKitTestRunner/TestInvocation.cpp:
(WTR::TestInvocation::didReceiveMessageFromInjectedBundle):

LayoutTests:

* http/tests/plugins/nounsupported-plugin-expected.txt: Added.
* http/tests/plugins/nounsupported-plugin.html: Added.
* http/tests/plugins/supported-plugin-all-origin-visibility-expected.txt: Added.
* http/tests/plugins/supported-plugin-all-origin-visibility.html: Added.
* http/tests/plugins/supported-plugin-on-specific-origin-expected.txt: Added.
* http/tests/plugins/supported-plugin-on-specific-origin.html: Added.
* http/tests/plugins/supported-plugin-origin-specific-visibility-expected.txt: Added.
* http/tests/plugins/supported-plugin-origin-specific-visibility.html: Added.
* http/tests/plugins/unsupported-plugin-on-specific-origin-expected.txt: Added.
* http/tests/plugins/unsupported-plugin-on-specific-origin.html: Added.
* plugins/unsupported-plugin-expected.txt: Added.
* plugins/unsupported-plugin.html: Added.
* platform/ios-wk1/TestExpectations:
* platform/mac-wk1/TestExpectations:

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

65 files changed:
LayoutTests/ChangeLog
LayoutTests/http/tests/plugins/nounsupported-plugin-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/plugins/nounsupported-plugin.html [new file with mode: 0644]
LayoutTests/http/tests/plugins/supported-plugin-all-origin-visibility-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/plugins/supported-plugin-all-origin-visibility.html [new file with mode: 0644]
LayoutTests/http/tests/plugins/supported-plugin-on-specific-origin-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/plugins/supported-plugin-on-specific-origin.html [new file with mode: 0644]
LayoutTests/http/tests/plugins/supported-plugin-origin-specific-visibility-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/plugins/supported-plugin-origin-specific-visibility.html [new file with mode: 0644]
LayoutTests/http/tests/plugins/unsupported-plugin-on-specific-origin-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/plugins/unsupported-plugin-on-specific-origin.html [new file with mode: 0644]
LayoutTests/platform/ios-wk1/TestExpectations
LayoutTests/platform/mac-wk1/TestExpectations
LayoutTests/plugins/unsupported-plugin-expected.txt [new file with mode: 0644]
LayoutTests/plugins/unsupported-plugin.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/English.lproj/Localizable.strings
Source/WebCore/PAL/pal/SessionID.h
Source/WebCore/html/HTMLPlugInElement.cpp
Source/WebCore/html/HTMLPlugInElement.h
Source/WebCore/loader/EmptyClients.cpp
Source/WebCore/platform/LocalizedStrings.cpp
Source/WebCore/platform/LocalizedStrings.h
Source/WebCore/plugins/PluginData.cpp
Source/WebCore/plugins/PluginData.h
Source/WebCore/plugins/PluginInfoProvider.h
Source/WebCore/rendering/RenderEmbeddedObject.cpp
Source/WebCore/rendering/RenderEmbeddedObject.h
Source/WebCore/testing/Internals.cpp
Source/WebCore/testing/Internals.h
Source/WebCore/testing/Internals.idl
Source/WebKit/ChangeLog
Source/WebKit/Platform/IPC/ArgumentCoders.h
Source/WebKit/Scripts/webkit/messages.py
Source/WebKit/UIProcess/API/C/WKContext.cpp
Source/WebKit/UIProcess/API/C/WKContextPrivate.h
Source/WebKit/UIProcess/API/Cocoa/WKProcessPool.mm
Source/WebKit/UIProcess/API/Cocoa/WKProcessPoolPrivate.h
Source/WebKit/UIProcess/Plugins/PluginInfoStore.cpp
Source/WebKit/UIProcess/Plugins/PluginInfoStore.h
Source/WebKit/UIProcess/WebPageProxy.cpp
Source/WebKit/UIProcess/WebPageProxy.h
Source/WebKit/UIProcess/WebPageProxy.messages.in
Source/WebKit/UIProcess/WebProcessPool.cpp
Source/WebKit/UIProcess/WebProcessPool.h
Source/WebKit/UIProcess/WebProcessProxy.cpp
Source/WebKit/UIProcess/WebProcessProxy.h
Source/WebKit/UIProcess/WebProcessProxy.messages.in
Source/WebKit/WebProcess/Plugins/WebPluginInfoProvider.cpp
Source/WebKit/WebProcess/Plugins/WebPluginInfoProvider.h
Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.cpp
Source/WebKit/WebProcess/WebPage/WebPage.cpp
Source/WebKitLegacy/mac/ChangeLog
Source/WebKitLegacy/mac/WebCoreSupport/WebPluginInfoProvider.h
Source/WebKitLegacy/mac/WebCoreSupport/WebPluginInfoProvider.mm
Source/WebKitLegacy/win/ChangeLog
Source/WebKitLegacy/win/WebCoreSupport/WebPluginInfoProvider.cpp
Source/WebKitLegacy/win/WebCoreSupport/WebPluginInfoProvider.h
Tools/ChangeLog
Tools/WebKitTestRunner/InjectedBundle/Bindings/TestRunner.idl
Tools/WebKitTestRunner/InjectedBundle/TestRunner.cpp
Tools/WebKitTestRunner/InjectedBundle/TestRunner.h
Tools/WebKitTestRunner/TestController.cpp
Tools/WebKitTestRunner/TestController.h
Tools/WebKitTestRunner/TestInvocation.cpp

index eff3340..27fd46b 100644 (file)
@@ -1,3 +1,25 @@
+2018-02-16  Youenn Fablet  <youenn@apple.com>
+
+        Allow specifying which plug-ins are supported
+        https://bugs.webkit.org/show_bug.cgi?id=182748
+
+        Reviewed by Chris Dumez.
+
+        * http/tests/plugins/nounsupported-plugin-expected.txt: Added.
+        * http/tests/plugins/nounsupported-plugin.html: Added.
+        * http/tests/plugins/supported-plugin-all-origin-visibility-expected.txt: Added.
+        * http/tests/plugins/supported-plugin-all-origin-visibility.html: Added.
+        * http/tests/plugins/supported-plugin-on-specific-origin-expected.txt: Added.
+        * http/tests/plugins/supported-plugin-on-specific-origin.html: Added.
+        * http/tests/plugins/supported-plugin-origin-specific-visibility-expected.txt: Added.
+        * http/tests/plugins/supported-plugin-origin-specific-visibility.html: Added.
+        * http/tests/plugins/unsupported-plugin-on-specific-origin-expected.txt: Added.
+        * http/tests/plugins/unsupported-plugin-on-specific-origin.html: Added.
+        * plugins/unsupported-plugin-expected.txt: Added.
+        * plugins/unsupported-plugin.html: Added.
+        * platform/ios-wk1/TestExpectations:
+        * platform/mac-wk1/TestExpectations:
+
 2018-02-16  Ryan Haddad  <ryanhaddad@apple.com>
 
         Mark fast/block/positioning/fixed-container-with-relative-parent.html as flaky.
diff --git a/LayoutTests/http/tests/plugins/nounsupported-plugin-expected.txt b/LayoutTests/http/tests/plugins/nounsupported-plugin-expected.txt
new file mode 100644 (file)
index 0000000..85984a9
--- /dev/null
@@ -0,0 +1,3 @@
+
+PASS Test plugins 
+
diff --git a/LayoutTests/http/tests/plugins/nounsupported-plugin.html b/LayoutTests/http/tests/plugins/nounsupported-plugin.html
new file mode 100644 (file)
index 0000000..628a5df
--- /dev/null
@@ -0,0 +1,16 @@
+<html>
+<body>
+<script src= "../resources/testharness.js"></script>
+<script src= "../resources/testharnessreport.js"></script>
+<script>
+function checkPlugins()
+{
+    return !!(navigator.plugins["WebKit Test PlugIn"] || navigator.plugins["WebKit built-in PDF"]);
+}
+
+test(() => {
+    assert_true(checkPlugins());
+}, "Test plugins");
+</script>
+</body>
+</html>
diff --git a/LayoutTests/http/tests/plugins/supported-plugin-all-origin-visibility-expected.txt b/LayoutTests/http/tests/plugins/supported-plugin-all-origin-visibility-expected.txt
new file mode 100644 (file)
index 0000000..0f9bef2
--- /dev/null
@@ -0,0 +1,3 @@
+
+PASS Ensure plugins visibility for supported plug-in for all origins 
+
diff --git a/LayoutTests/http/tests/plugins/supported-plugin-all-origin-visibility.html b/LayoutTests/http/tests/plugins/supported-plugin-all-origin-visibility.html
new file mode 100644 (file)
index 0000000..250ba0f
--- /dev/null
@@ -0,0 +1,19 @@
+<html>
+<body>
+<script src= "../resources/testharness.js"></script>
+<script src= "../resources/testharnessreport.js"></script>
+<script>
+function checkPlugins()
+{
+    return !!(navigator.plugins["WebKit Test PlugIn"] || navigator.plugins["WebKit built-in PDF"]);
+}
+
+test(() => {
+    assert_true(!!window.testRunner);
+    testRunner.setPluginSupportedMode("allOrigins");
+    var plugins = navigator.plugins;
+    assert_true(checkPlugins());
+}, "Ensure plugins visibility for supported plug-in for all origins");
+</script>
+</body>
+</html>
diff --git a/LayoutTests/http/tests/plugins/supported-plugin-on-specific-origin-expected.txt b/LayoutTests/http/tests/plugins/supported-plugin-on-specific-origin-expected.txt
new file mode 100644 (file)
index 0000000..86fc4ba
--- /dev/null
@@ -0,0 +1,6 @@
+On WebKitTestRunner, no console log message should appear stating the plugin is unsupported.
+
+
+
+PASS Testing unsupported plug-in 
+
diff --git a/LayoutTests/http/tests/plugins/supported-plugin-on-specific-origin.html b/LayoutTests/http/tests/plugins/supported-plugin-on-specific-origin.html
new file mode 100644 (file)
index 0000000..7c1e1d1
--- /dev/null
@@ -0,0 +1,46 @@
+<!DOCTYPE html>
+<html>
+<body>
+<script src= "../resources/testharness.js"></script>
+<script src= "../resources/testharnessreport.js"></script>
+<script>
+if (window.testRunner) {
+    testRunner.waitUntilDone();
+    testRunner.dumpAsText();
+}
+</script>
+<p>On WebKitTestRunner, no console log message should appear stating the plugin is unsupported.</p>
+<div id="pluginPlaceholder"></div>
+
+<script>
+function doTest()
+{
+    if (window.location.origin !== "http://localhost:8080") {
+        if (!window.testRunner) {
+            assert_not_reached("Needs test runnner");
+            return;
+        }
+        testRunner.setPluginSupportedMode("specificOrigin");
+        window.location = "http://localhost:8080/plugins/supported-plugin-on-specific-origin.html";
+        return;
+    }
+    pluginPlaceholder.innerHTML = '<embed id="plugin" type="application/x-webkit-test-netscape"></embed>';
+    var test = async_test("Testing unsupported plug-in");
+    test.step(() => {
+        if (!window.internals) {
+           test.done();
+           return;
+        }
+        var counter = 0;
+        setInterval(test.step_func(() => {
+            let text = internals.unavailablePluginReplacementText(plugin);
+            assert_equals(text, "");
+            if (++counter > 5)
+                test.done();
+        }), 50);
+    });
+}
+doTest();
+</script>
+</body>
+</html>
diff --git a/LayoutTests/http/tests/plugins/supported-plugin-origin-specific-visibility-expected.txt b/LayoutTests/http/tests/plugins/supported-plugin-origin-specific-visibility-expected.txt
new file mode 100644 (file)
index 0000000..e7c98a4
--- /dev/null
@@ -0,0 +1,3 @@
+
+PASS Ensure per-origin supported plugins origin 
+
diff --git a/LayoutTests/http/tests/plugins/supported-plugin-origin-specific-visibility.html b/LayoutTests/http/tests/plugins/supported-plugin-origin-specific-visibility.html
new file mode 100644 (file)
index 0000000..bc0d047
--- /dev/null
@@ -0,0 +1,35 @@
+<html>
+<body>
+<script src= "../resources/testharness.js"></script>
+<script src= "../resources/testharnessreport.js"></script>
+<script>
+function checkPlugins()
+{
+    return !!(navigator.plugins["WebKit Test PlugIn"] || navigator.plugins["WebKit built-in PDF"]);
+}
+
+function doTest()
+{
+    if (window.location.origin !== "http://localhost:8080") {
+        test(() => {
+            if (!window.testRunner) {
+                assert_not_reached("Needs test runnner");
+                return;
+            }
+            testRunner.setPluginSupportedMode("specificOrigin");
+
+            assert_false(checkPlugins());
+            window.location = "http://localhost:8080/plugins/supported-plugin-origin-specific-visibility.html";
+        }, "Ensure per-origin supported plugins origin - first");
+        return;
+    }
+    test(() => {
+        assert_true(checkPlugins());
+    }, "Ensure per-origin supported plugins origin");
+    if (window.testRunner)
+        testRunner.notifyDone();
+}
+doTest();
+</script>
+</body>
+</html>
diff --git a/LayoutTests/http/tests/plugins/unsupported-plugin-on-specific-origin-expected.txt b/LayoutTests/http/tests/plugins/unsupported-plugin-on-specific-origin-expected.txt
new file mode 100644 (file)
index 0000000..e173adb
--- /dev/null
@@ -0,0 +1,7 @@
+CONSOLE MESSAGE: Tried to use an unsupported plug-in.
+A console log message should appear stating the plugin is unsupported.
+
+
+
+PASS Testing unsupported plug-in 
+
diff --git a/LayoutTests/http/tests/plugins/unsupported-plugin-on-specific-origin.html b/LayoutTests/http/tests/plugins/unsupported-plugin-on-specific-origin.html
new file mode 100644 (file)
index 0000000..17d4ed7
--- /dev/null
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<html>
+<body>
+<script src= "../resources/testharness.js"></script>
+<script src= "../resources/testharnessreport.js"></script>
+<script>
+if (window.testRunner)
+    testRunner.setPluginSupportedMode("specificOrigin");
+</script>
+<p>A console log message should appear stating the plugin is unsupported.</p>
+<embed id="plugin" type="application/x-webkit-test-netscape"></embed>
+
+<script>
+var test = async_test("Testing unsupported plug-in");
+test.step(() => {
+    if (!window.internals) {
+       test.done();
+       return;
+    }
+    var counter = 0;
+    setInterval(test.step_func(() => {
+        assert_true(++counter < 20, "Test timed out");
+        let text = internals.unavailablePluginReplacementText(plugin);
+        if (!text)
+            return;
+        assert_equals(text, "Unsupported Plug-in");
+        test.done();
+    }), 50);
+});
+</script>
+</body>
+</html>
index a9d1aeb..3867199 100644 (file)
@@ -1094,6 +1094,13 @@ http/tests/security/video-cross-origin-accessfailure.html [ Failure ]
 http/tests/security/video-cross-origin-readback.html [ Failure ]
 http/tests/security/xssAuditor/link-opens-new-window.html [ Failure ]
 
+http/tests/plugins/nounsupported-plugin.html [ Skip ]
+http/tests/plugins/supported-plugin-all-origin-visibility.html [ Skip ]
+http/tests/plugins/supported-plugin-origin-specific-visibility.html [ Skip ]
+http/tests/plugins/supported-plugin-on-specific-origin.html [ Skip ]
+http/tests/plugins/unsupported-plugin-on-specific-origin.html [ Skip ]
+plugins/unsupported-plugin.html [ Skip ]
+
 # HTTP tests that assert:
 http/tests/navigation/metaredirect-basic.html
 http/tests/navigation/metaredirect-goback.html
index 49901cb..66bddf6 100644 (file)
@@ -102,6 +102,13 @@ editing/secure-input/reset-state-on-navigation.html [ Failure ]
 # Plug-in blocking callback doesn't exist in WebKit1.
 plugins/unavailable-plugin-indicator-obscurity.html
 
+http/tests/plugins/nounsupported-plugin.html [ Skip ]
+http/tests/plugins/supported-plugin-all-origin-visibility.html [ Skip ]
+http/tests/plugins/supported-plugin-origin-specific-visibility.html [ Skip ]
+http/tests/plugins/supported-plugin-on-specific-origin.html [ Skip ]
+http/tests/plugins/unsupported-plugin-on-specific-origin.html [ Skip ]
+plugins/unsupported-plugin.html [ Skip ]
+
 # Color input is not yet implemented on Mac WK1. Currently, using it erroneously triggers an ASSERT_NOT_REACHED.
 webkit.org/b/119094 fast/forms/color/input-color-onchange-event.html [ Skip ]
 webkit.org/b/119094 fast/forms/color/color-suggestion-picker-crash-on-set-value.html [ Skip ]
diff --git a/LayoutTests/plugins/unsupported-plugin-expected.txt b/LayoutTests/plugins/unsupported-plugin-expected.txt
new file mode 100644 (file)
index 0000000..e173adb
--- /dev/null
@@ -0,0 +1,7 @@
+CONSOLE MESSAGE: Tried to use an unsupported plug-in.
+A console log message should appear stating the plugin is unsupported.
+
+
+
+PASS Testing unsupported plug-in 
+
diff --git a/LayoutTests/plugins/unsupported-plugin.html b/LayoutTests/plugins/unsupported-plugin.html
new file mode 100644 (file)
index 0000000..3b746e3
--- /dev/null
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<html>
+<body>
+<script src= "../resources/testharness.js"></script>
+<script src= "../resources/testharnessreport.js"></script>
+<script>
+if (window.testRunner)
+    testRunner.setPluginSupportedMode("none");
+</script>
+<p>A console log message should appear stating the plugin is unsupported.</p>
+<embed id="plugin" type="application/x-webkit-test-netscape"></embed>
+
+<script>
+var test = async_test("Testing unsupported plug-in");
+test.step(() => {
+    if (!window.internals) {
+       test.done();
+       return;
+    }
+    var counter = 0;
+    setInterval(test.step_func(() => {
+        assert_true(++counter < 20, "Test timed out");
+        let text = internals.unavailablePluginReplacementText(plugin);
+        if (!text)
+            return;
+        assert_equals(text, "Unsupported Plug-in");
+        test.done();
+    }), 50);
+});
+</script>
+</body>
+</html>
index 97d9460..4700d5a 100644 (file)
@@ -1,3 +1,49 @@
+2018-02-16  Youenn Fablet  <youenn@apple.com>
+
+        Allow specifying which plug-ins are supported
+        https://bugs.webkit.org/show_bug.cgi?id=182748
+
+        Reviewed by Chris Dumez.
+
+        Tests: http/tests/plugins/nounsupported-plugin.html
+               http/tests/plugins/supported-plugin-all-origin-visibility.html
+               http/tests/plugins/supported-plugin-on-specific-origin.html
+               http/tests/plugins/supported-plugin-origin-specific-visibility.html
+               http/tests/plugins/unsupported-plugin-on-specific-origin.html
+               plugins/unsupported-plugin.html
+
+        Added support for computing plugin web visibility with the added knowledge of supported plugins.
+        In case of a plugin failing to be created due to being unsupported, update the UI
+        to use mark the plugin as "Unexpected plug in".
+
+        Added internal API to retrieve the plug-in error description message.
+
+        * English.lproj/Localizable.strings:
+        * WebCore.xcodeproj/project.pbxproj:
+        * html/HTMLPlugInElement.cpp:
+        (WebCore::HTMLPlugInElement::setReplacement):
+        * html/HTMLPlugInElement.h:
+        * loader/EmptyClients.cpp:
+        * platform/LocalizedStrings.cpp:
+        (WebCore::unsupportedPluginText):
+        * platform/LocalizedStrings.h:
+        * plugins/PluginData.cpp:
+        (WebCore::PluginData::initPlugins):
+        * plugins/PluginData.h:
+        (WebCore::decodePluginNames):
+        (WebCore::encodePluginNames):
+        (WebCore::SupportedPluginNames::decode):
+        (WebCore::SupportedPluginNames::encode const):
+        * plugins/PluginInfoProvider.h:
+        * rendering/RenderEmbeddedObject.cpp:
+        (WebCore::unavailablePluginReplacementText):
+        * rendering/RenderEmbeddedObject.h:
+        (WebCore::RenderEmbeddedObject::pluginReplacementTextIfUnavailable const):
+        * testing/Internals.cpp:
+        (WebCore::Internals::unavailablePluginReplacementText):
+        * testing/Internals.h:
+        * testing/Internals.idl:
+
 2018-02-16  Chris Dumez  <cdumez@apple.com>
 
         http/tests/security/http-0.9/xhr-blocked.html is flaky
index e6e3ef1..5fbc2e1 100644 (file)
 /* Label text to be used when an insecure plug-in version was blocked from loading */
 "Blocked Plug-In (Insecure plug-in)" = "Blocked Plug-in";
 
+/* Label text to be used when an insecure plug-in version was blocked from loading */
+"Unsupported Plug-In" = "Unsupported Plug-in";
+
 /* Bold context menu item */
 "Bold" = "Bold";
 
index def497e..d726830 100644 (file)
@@ -64,6 +64,7 @@ public:
 
     template<class Encoder> void encode(Encoder&) const;
     template<class Decoder> static bool decode(Decoder&, SessionID&);
+    template<class Decoder> static std::optional<SessionID> decode(Decoder&);
 
     SessionID isolatedCopy() const;
 
@@ -86,13 +87,27 @@ void SessionID::encode(Encoder& encoder) const
 template<class Decoder>
 bool SessionID::decode(Decoder& decoder, SessionID& sessionID)
 {
-    if (!decoder.decode(sessionID.m_sessionID))
+    std::optional<SessionID> decodedSessionID;
+    decoder >> decodedSessionID;
+    if (!decodedSessionID)
         return false;
 
-    // FIXME: Eliminate places that encode invalid SessionIDs, then fail to decode an invalid sessionID.
+    sessionID = decodedSessionID.value();
     return true;
 }
 
+template<class Decoder>
+std::optional<SessionID> SessionID::decode(Decoder& decoder)
+{
+    std::optional<uint64_t> sessionID;
+    decoder >> sessionID;
+    if (!sessionID)
+        return std::nullopt;
+
+    // FIXME: Eliminate places that encode invalid SessionIDs, then fail to decode an invalid sessionID.
+    return SessionID { *sessionID };
+}
+
 } // namespace PAL
 
 namespace WTF {
index dce2d0b..31ac810 100644 (file)
@@ -403,13 +403,16 @@ JSC::JSObject* HTMLPlugInElement::scriptObjectForPluginReplacement()
     return nullptr;
 }
 
-// Return whether or not the replacement content for blocked plugins is accessible to the user.
-bool HTMLPlugInElement::isReplacementObscured(const String& unavailabilityDescription)
+bool HTMLPlugInElement::setReplacement(RenderEmbeddedObject::PluginUnavailabilityReason reason, const String& unavailabilityDescription)
 {
     if (!is<RenderEmbeddedObject>(renderer()))
         return false;
+
+    if (reason == RenderEmbeddedObject::UnsupportedPlugin)
+        document().addConsoleMessage(MessageSource::JS, MessageLevel::Warning, ASCIILiteral("Tried to use an unsupported plug-in."));
+
     Ref<HTMLPlugInElement> protectedThis(*this);
-    downcast<RenderEmbeddedObject>(*renderer()).setPluginUnavailabilityReasonWithDescription(RenderEmbeddedObject::InsecurePluginVersion, unavailabilityDescription);
+    downcast<RenderEmbeddedObject>(*renderer()).setPluginUnavailabilityReasonWithDescription(reason, unavailabilityDescription);
     bool replacementIsObscured = isReplacementObscured();
     // hittest in isReplacementObscured() method could destroy the renderer. Let's refetch it.
     if (is<RenderEmbeddedObject>(renderer()))
index 4c3f087..bf174c1 100644 (file)
@@ -24,6 +24,7 @@
 
 #include "HTMLFrameOwnerElement.h"
 #include "Image.h"
+#include "RenderEmbeddedObject.h"
 
 namespace JSC {
 namespace Bindings {
@@ -34,7 +35,6 @@ class Instance;
 namespace WebCore {
 
 class PluginReplacement;
-class RenderEmbeddedObject;
 class RenderWidget;
 class Widget;
 
@@ -82,7 +82,9 @@ public:
 
     bool isUserObservable() const;
 
-    WEBCORE_EXPORT bool isReplacementObscured(const String& unavailabilityDescription);
+    // Return whether or not the replacement content for blocked plugins is accessible to the user.
+    WEBCORE_EXPORT bool setReplacement(RenderEmbeddedObject::PluginUnavailabilityReason, const String& unavailabilityDescription);
+
     WEBCORE_EXPORT bool isReplacementObscured();
 
 protected:
index 1478fc1..3386802 100644 (file)
@@ -325,7 +325,7 @@ class EmptyPaymentCoordinatorClient final : public PaymentCoordinatorClient {
 
 class EmptyPluginInfoProvider final : public PluginInfoProvider {
     void refreshPlugins() final { };
-    void getPluginInfo(Page&, Vector<PluginInfo>&) final { }
+    void getPluginInfo(Page&, Vector<PluginInfo>&, std::optional<SupportedPluginNames>&) final { }
     void getWebVisiblePluginInfo(Page&, Vector<PluginInfo>&) final { }
 };
 
index ee9317b..1cc4be4 100644 (file)
@@ -660,6 +660,11 @@ String insecurePluginVersionText()
     return WEB_UI_STRING_KEY("Blocked Plug-in", "Blocked Plug-In (Insecure plug-in)", "Label text to be used when an insecure plug-in version was blocked from loading");
 }
 
+String unsupportedPluginText()
+{
+    return WEB_UI_STRING_KEY("Unsupported Plug-in", "Unsupported Plug-In", "Label text to be used when an unsupported plug-in was blocked from loading");
+}
+
 String multipleFileUploadText(unsigned numberOfFiles)
 {
     return formatLocalizedString(WEB_UI_STRING("%d files", "Label to describe the number of files selected in a file upload control that allows multiple files"), numberOfFiles);
index 3fa7d6b..42bba25 100644 (file)
@@ -223,6 +223,7 @@ namespace WebCore {
     String crashedPluginText();
     String blockedPluginByContentSecurityPolicyText();
     String insecurePluginVersionText();
+    String unsupportedPluginText();
 
     String multipleFileUploadText(unsigned numberOfFiles);
     String unknownFileSizeText();
index 26e498c..d3bc06a 100644 (file)
@@ -174,7 +174,7 @@ void PluginData::initPlugins()
 {
     ASSERT(m_plugins.isEmpty());
 
-    m_page.pluginInfoProvider().getPluginInfo(m_page, m_plugins);
+    m_page.pluginInfoProvider().getPluginInfo(m_page, m_plugins, m_supportedPluginNames);
 }
 
 } // namespace WebCore
index 4ce8541..690ba72 100644 (file)
 
 #pragma once
 
+#include "SecurityOriginData.h"
+#include <wtf/HashMap.h>
+#include <wtf/HashSet.h>
 #include <wtf/RefCounted.h>
 #include <wtf/Vector.h>
+#include <wtf/text/StringHash.h>
 #include <wtf/text/WTFString.h>
 
 namespace WebCore {
@@ -84,6 +88,14 @@ inline bool operator==(PluginInfo& a, PluginInfo& b)
     return result;
 }
 
+struct SupportedPluginNames {
+    HashSet<String> allOriginPlugins;
+    HashMap<SecurityOriginData, HashSet<String>> originSpecificPlugins;
+
+    template<class Encoder> void encode(Encoder&) const;
+    template<class Decoder> static std::optional<SupportedPluginNames> decode(Decoder&);
+};
+
 // FIXME: merge with PluginDatabase in the future
 class PluginData : public RefCounted<PluginData> {
 public:
@@ -114,6 +126,39 @@ private:
 protected:
     Page& m_page;
     Vector<PluginInfo> m_plugins;
+    std::optional<SupportedPluginNames> m_supportedPluginNames;
 };
 
+inline bool isSupportedPlugin(SupportedPluginNames& pluginNames, SecurityOriginData& origin, const String& pluginName)
+{
+    auto iterator = pluginNames.originSpecificPlugins.find(origin);
+    if (iterator != pluginNames.originSpecificPlugins.end()) {
+        if (iterator->value.contains(pluginName))
+            return true;
+    }
+
+    return pluginNames.allOriginPlugins.contains(pluginName);
+}
+
+template<class Decoder> inline std::optional<SupportedPluginNames> SupportedPluginNames::decode(Decoder& decoder)
+{
+    std::optional<HashSet<String>> allOriginPlugins;
+    decoder >> allOriginPlugins;
+    if (!allOriginPlugins)
+        return std::nullopt;
+
+    std::optional<HashMap<SecurityOriginData, HashSet<String>>> originSpecificPlugins;
+    decoder >> originSpecificPlugins;
+    if (!originSpecificPlugins)
+        return std::nullopt;
+
+    return SupportedPluginNames { WTFMove(allOriginPlugins.value()), WTFMove(originSpecificPlugins.value()) };
+}
+
+template<class Encoder> inline void SupportedPluginNames::encode(Encoder& encoder) const
+{
+    encoder << allOriginPlugins;
+    encoder << originSpecificPlugins;
+}
+
 } // namespace WebCore
index dafa165..6e05efb 100644 (file)
@@ -39,7 +39,7 @@ public:
     void addPage(Page&);
     void removePage(Page&);
 
-    virtual void getPluginInfo(Page&, Vector<PluginInfo>&) = 0;
+    virtual void getPluginInfo(Page&, Vector<PluginInfo>&, std::optional<SupportedPluginNames>&) = 0;
     virtual void getWebVisiblePluginInfo(Page&, Vector<PluginInfo>&) = 0;
 
 private:
index f8869db..4437e06 100644 (file)
@@ -156,6 +156,8 @@ static String unavailablePluginReplacementText(RenderEmbeddedObject::PluginUnava
         return blockedPluginByContentSecurityPolicyText();
     case RenderEmbeddedObject::InsecurePluginVersion:
         return insecurePluginVersionText();
+    case RenderEmbeddedObject::UnsupportedPlugin:
+        return unsupportedPluginText();
     }
 
     ASSERT_NOT_REACHED();
index 50f576f..33f1925 100644 (file)
@@ -45,6 +45,7 @@ public:
         PluginCrashed,
         PluginBlockedByContentSecurityPolicy,
         InsecurePluginVersion,
+        UnsupportedPlugin
     };
     WEBCORE_EXPORT void setPluginUnavailabilityReason(PluginUnavailabilityReason);
     WEBCORE_EXPORT void setPluginUnavailabilityReasonWithDescription(PluginUnavailabilityReason, const String& description);
@@ -58,6 +59,9 @@ public:
     bool allowsAcceleratedCompositing() const;
 
     LayoutRect unavailablePluginIndicatorBounds(const LayoutPoint& accumulatedOffset) const;
+
+    const String& pluginReplacementTextIfUnavailable() const { return m_unavailablePluginReplacementText; }
+
 protected:
     void paintReplaced(PaintInfo&, const LayoutPoint&) final;
     void paint(PaintInfo&, const LayoutPoint&) override;
index 6fa8cc7..21f4d37 100644 (file)
@@ -3278,6 +3278,18 @@ ExceptionOr<bool> Internals::isPluginUnavailabilityIndicatorObscured(Element& el
     return downcast<HTMLPlugInElement>(element).isReplacementObscured();
 }
 
+ExceptionOr<String> Internals::unavailablePluginReplacementText(Element& element)
+{
+    if (!is<HTMLPlugInElement>(element))
+        return Exception { InvalidAccessError };
+
+    auto* renderer = element.renderer();
+    if (!is<RenderEmbeddedObject>(renderer))
+        return String { };
+
+    return String { downcast<RenderEmbeddedObject>(*renderer).pluginReplacementTextIfUnavailable() };
+}
+
 bool Internals::isPluginSnapshotted(Element& element)
 {
     return is<HTMLPlugInElement>(element) && downcast<HTMLPlugInElement>(element).displayState() <= HTMLPlugInElement::DisplayingSnapshot;
index 380fd07..cc27deb 100644 (file)
@@ -480,6 +480,7 @@ public:
     ExceptionOr<Ref<DOMRect>> selectionBounds();
 
     ExceptionOr<bool> isPluginUnavailabilityIndicatorObscured(Element&);
+    ExceptionOr<String> unavailablePluginReplacementText(Element&);
     bool isPluginSnapshotted(Element&);
 
 #if ENABLE(MEDIA_SOURCE)
index f8979a2..6a6623d 100644 (file)
@@ -440,6 +440,7 @@ enum EventThrottlingBehavior {
     boolean isSelectPopupVisible(HTMLSelectElement element);
 
     [MayThrowException] boolean isPluginUnavailabilityIndicatorObscured(Element element);
+    [MayThrowException] DOMString unavailablePluginReplacementText(Element element);
     boolean isPluginSnapshotted(Element element);
 
     [MayThrowException] DOMRect selectionBounds();
index ce29785..37be0fe 100644 (file)
@@ -1,3 +1,65 @@
+2018-02-16  Youenn Fablet  <youenn@apple.com>
+
+        Allow specifying which plug-ins are supported
+        https://bugs.webkit.org/show_bug.cgi?id=182748
+
+        Reviewed by Chris Dumez.
+
+        Add a C and ObjC API to set which plug-ins are specified.
+        Plug-ins may be allowed by origin of the main page or for all origins.
+
+        If the API to set a supported plug-in is called, WebKit enters a mode
+        where it will block any plug-in that is not on the list.
+
+        The list of supported plug-ins is stored in UIProcess and sent to WebProcess.
+        This allows to compute the list of visible plug-ins according supported plugins.
+
+        PluginInfoStore is storing the list of supported plugins and can
+        answer whether a plug-in creation request is to be made unsupported or not.
+        It also creates the structure sent to WebProcess for computing plugin visibility.
+
+        Updated ArgumentCoders to accept modern HashSet decoders.
+
+        * Platform/IPC/ArgumentCoders.h:
+        * UIProcess/API/C/WKContext.cpp:
+        (WKContextAddSupportedPlugin):
+        (WKContextClearSupportedPlugins):
+        * UIProcess/API/C/WKContextPrivate.h:
+        * UIProcess/API/Cocoa/WKProcessPool.mm:
+        (-[WKProcessPool _addSupportedPlugin:named:withMimeTypes:withExtensions:]):
+        * UIProcess/API/Cocoa/WKProcessPoolPrivate.h:
+        * UIProcess/Plugins/PluginInfoStore.cpp:
+        (WebKit::PluginInfoStore::isSupportedPlugin):
+        (WebKit::PluginInfoStore::SupportedPlugins::isSupported):
+        (WebKit::PluginInfoStore::SupportedPlugin::isSupported):
+        (WebKit::PluginInfoStore::supportedPluginNames):
+        (WebKit::PluginInfoStore::addSupportedPlugin):
+        * UIProcess/Plugins/PluginInfoStore.h:
+        (WebKit::PluginInfoStore::clearSupportedPlugins):
+        * UIProcess/WebPageProxy.cpp:
+        (WebKit::WebPageProxy::findPlugin):
+        (WebKit::WebPageProxy::unavailablePluginButtonClicked):
+        * UIProcess/WebPageProxy.h:
+        * UIProcess/WebPageProxy.messages.in:
+        * UIProcess/WebProcessPool.cpp:
+        (WebKit::WebProcessPool::addSupportedPlugin):
+        (WebKit::WebProcessPool::clearSupportedPlugins):
+        * UIProcess/WebProcessPool.h:
+        * UIProcess/WebProcessProxy.cpp:
+        (WebKit::WebProcessProxy::getPlugins):
+        * UIProcess/WebProcessProxy.h:
+        * UIProcess/WebProcessProxy.messages.in:
+        * WebProcess/Plugins/WebPluginInfoProvider.cpp:
+        (WebKit::WebPluginInfoProvider::getPluginInfo):
+        (WebKit::WebPluginInfoProvider::getWebVisiblePluginInfo):
+        (WebKit::WebPluginInfoProvider::populatePluginCache):
+        * WebProcess/Plugins/WebPluginInfoProvider.h:
+        * WebProcess/WebCoreSupport/WebChromeClient.cpp:
+        (WebKit::WebChromeClient::shouldUnavailablePluginMessageBeButton const):
+        * WebProcess/WebPage/WebPage.cpp:
+        (WebKit::WebPage::createPlugin):
+        (WebKit::WebPage::canPluginHandleResponse):
+
 2018-02-16  Jiewen Tan  <jiewen_tan@apple.com>
 
         [WebAuthN] Implement PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable()
index 47fd98b..d9e9fa4 100644 (file)
@@ -368,23 +368,26 @@ template<typename KeyArg, typename MappedArg, typename HashArg, typename KeyTrai
         uint64_t hashMapSize;
         if (!decoder.decode(hashMapSize))
             return std::nullopt;
-        
+
         HashMapType hashMap;
         for (uint64_t i = 0; i < hashMapSize; ++i) {
-            KeyArg key;
-            MappedArg value;
-            if (!decoder.decode(key))
+            std::optional<KeyArg> key;
+            decoder >> key;
+            if (!key)
                 return std::nullopt;
-            if (!decoder.decode(value))
+
+            std::optional<MappedArg> value;
+            decoder >> value;
+            if (!value)
                 return std::nullopt;
-            
-            if (!hashMap.add(key, value).isNewEntry) {
+
+            if (!hashMap.add(WTFMove(key.value()), WTFMove(value.value())).isNewEntry) {
                 // The hash map already has the specified key, bail.
                 decoder.markInvalid();
                 return std::nullopt;
             }
         }
-        
+
         return WTFMove(hashMap);
     }
 };
@@ -401,26 +404,36 @@ template<typename KeyArg, typename HashArg, typename KeyTraitsArg> struct Argume
 
     static bool decode(Decoder& decoder, HashSetType& hashSet)
     {
+        std::optional<HashSetType> tempHashSet;
+        decoder >> tempHashSet;
+        if (!tempHashSet)
+            return false;
+
+        hashSet.swap(tempHashSet.value());
+        return true;
+    }
+
+    static std::optional<HashSetType> decode(Decoder& decoder)
+    {
         uint64_t hashSetSize;
         if (!decoder.decode(hashSetSize))
-            return false;
+            return std::nullopt;
 
-        HashSetType tempHashSet;
+        HashSetType hashSet;
         for (uint64_t i = 0; i < hashSetSize; ++i) {
             std::optional<KeyArg> key;
             decoder >> key;
             if (!key)
-                return false;
+                return std::nullopt;
 
-            if (!tempHashSet.add(*key).isNewEntry) {
-                // The hash map already has the specified key, bail.
+            if (!hashSet.add(WTFMove(key.value())).isNewEntry) {
+                // The hash set already has the specified key, bail.
                 decoder.markInvalid();
-                return false;
+                return std::nullopt;
             }
         }
 
-        hashSet.swap(tempHashSet);
-        return true;
+        return WTFMove(hashSet);
     }
 };
 
index a8bcc97..4ba3adb 100644 (file)
@@ -398,6 +398,7 @@ def headers_for_type(type):
         'WebCore::ShippingMethodUpdate': ['<WebCore/ApplePaySessionPaymentRequest.h>'],
         'WebCore::ShouldNotifyWhenResolved': ['<WebCore/ServiceWorkerTypes.h>'],
         'WebCore::ShouldSample': ['<WebCore/DiagnosticLoggingClient.h>'],
+        'WebCore::SupportedPluginNames': ['<WebCore/PluginData.h>'],
         'WebCore::TextCheckingRequestData': ['<WebCore/TextChecking.h>'],
         'WebCore::TextCheckingResult': ['<WebCore/TextCheckerClient.h>'],
         'WebCore::TextIndicatorData': ['<WebCore/TextIndicator.h>'],
index e574694..405486c 100644 (file)
 #include "AuthenticationChallengeProxy.h"
 #include "DownloadProxy.h"
 #include "WKAPICast.h"
+#include "WKArray.h"
 #include "WKContextConfigurationRef.h"
 #include "WKRetainPtr.h"
+#include "WKString.h"
 #include "WebCertificateInfo.h"
 #include "WebContextInjectedBundleClient.h"
 #include "WebProcessPool.h"
@@ -618,3 +620,30 @@ ProcessID WKContextGetDatabaseProcessIdentifier(WKContextRef contextRef)
 {
     return toImpl(contextRef)->storageProcessIdentifier();
 }
+
+void WKContextAddSupportedPlugin(WKContextRef contextRef, WKStringRef originRef, WKStringRef nameRef, WKArrayRef mimeTypesRef, WKArrayRef extensionsRef)
+{
+#if ENABLE(NETSCAPE_PLUGIN_API)
+    HashSet<String> mimeTypes;
+    HashSet<String> extensions;
+
+    size_t count = WKArrayGetSize(mimeTypesRef);
+    for (size_t i = 0; i < count; ++i)
+        mimeTypes.add(toWTFString(static_cast<WKStringRef>(WKArrayGetItemAtIndex(mimeTypesRef, i))));
+    count = WKArrayGetSize(extensionsRef);
+    for (size_t i = 0; i < count; ++i)
+        extensions.add(toWTFString(static_cast<WKStringRef>(WKArrayGetItemAtIndex(extensionsRef, i))));
+
+    RefPtr<SecurityOrigin> origin;
+    if (!WKStringIsEmpty(originRef))
+        origin = SecurityOrigin::createFromString(toWTFString(originRef));
+    toImpl(contextRef)->addSupportedPlugin(origin.get(), toWTFString(nameRef), WTFMove(mimeTypes), WTFMove(extensions));
+#endif
+}
+
+void WKContextClearSupportedPlugins(WKContextRef contextRef)
+{
+#if ENABLE(NETSCAPE_PLUGIN_API)
+    toImpl(contextRef)->clearSupportedPlugins();
+#endif
+}
index a0fc1c2..06480e1 100644 (file)
@@ -112,6 +112,9 @@ WK_EXPORT void WKContextPreconnectToServer(WKContextRef context, WKURLRef server
 WK_EXPORT WKProcessID WKContextGetNetworkProcessIdentifier(WKContextRef context);
 WK_EXPORT WKProcessID WKContextGetDatabaseProcessIdentifier(WKContextRef context);
 
+WK_EXPORT void WKContextAddSupportedPlugin(WKContextRef context, WKStringRef origin, WKStringRef name, WKArrayRef mimeTypes, WKArrayRef extensions);
+WK_EXPORT void WKContextClearSupportedPlugins(WKContextRef context);
+
 #ifdef __cplusplus
 }
 #endif
index f731fef..5f0c326 100644 (file)
@@ -397,6 +397,23 @@ static NSDictionary *policiesHashMapToDictionary(const HashMap<String, HashMap<S
     _processPool->setAutomationSession(automationSession ? automationSession->_session.get() : nullptr);
 }
 
+- (void)_addSupportedPlugin:(NSString *) origin named:(NSString *) name withMimeTypes: (NSSet<NSString *> *) nsMimeTypes withExtensions: (NSSet<NSString *> *) nsExtensions
+{
+    HashSet<String> mimeTypes;
+    for (NSString *mimeType in nsMimeTypes)
+        mimeTypes.add(mimeType);
+    HashSet<String> extensions;
+    for (NSString *extension in nsExtensions)
+        extensions.add(extension);
+
+    _processPool->addSupportedPlugin([origin length] ? WebCore::SecurityOrigin::createFromString(origin).ptr() : nullptr, name, WTFMove(mimeTypes), WTFMove(extensions));
+}
+
+- (void)_clearSupportedPlugins
+{
+    _processPool->clearSupportedPlugins();
+}
+
 - (void)_terminateStorageProcess
 {
     _processPool->terminateStorageProcess();
index d7e0103..8d152b5 100644 (file)
@@ -24,6 +24,7 @@
  */
 
 #import <WebKit/WKProcessPool.h>
+#import <WebKit/WKSecurityOrigin.h>
 
 #if WK_API_ENABLED
 
@@ -71,6 +72,9 @@
 - (void)_automationCapabilitiesDidChange WK_API_AVAILABLE(macosx(10.12), ios(10.0));
 - (void)_setAutomationSession:(_WKAutomationSession *)automationSession WK_API_AVAILABLE(macosx(10.12), ios(10.0));
 
+- (void)_addSupportedPlugin:(NSString *) origin named:(NSString *) name withMimeTypes: (NSSet<NSString *> *) mimeTypes withExtensions: (NSSet<NSString *> *) extensions WK_API_AVAILABLE(macosx(WK_MAC_TBA), ios(WK_IOS_TBA));
+- (void)_clearSupportedPlugins WK_API_AVAILABLE(macosx(WK_MAC_TBA), ios(WK_IOS_TBA));
+
 // Test only. Should be called only while no web content processes are running.
 - (void)_terminateStorageProcess;
 - (void)_terminateNetworkProcess;
index 6079068..61c00ee 100644 (file)
@@ -204,6 +204,65 @@ PluginModuleInfo PluginInfoStore::findPlugin(String& mimeType, const URL& url, P
     return PluginModuleInfo();
 }
 
+bool PluginInfoStore::isSupportedPlugin(const PluginInfoStore::SupportedPlugin& plugin, const String& mimeType, const URL& pluginURL)
+{
+    if (plugin.mimeTypes.contains(mimeType))
+        return true;
+    auto extension = pathExtension(pluginURL);
+    return extension.isEmpty() ? false : plugin.extensions.contains(extension);
+}
+
+bool PluginInfoStore::isSupportedPlugin(const String& mimeType, const URL& pluginURL, const String&, const URL& pageURL)
+{
+    // We check only pageURLString for consistency with WebProcess visible plugins.
+    if (!m_supportedPlugins)
+        return true;
+
+    for (auto& plugin : m_supportedPlugins->originSpecificPlugins.get(SecurityOriginData { pageURL.protocol().toString(), pageURL.host(), pageURL.port() })) {
+        if (isSupportedPlugin(plugin, mimeType, pluginURL))
+            return true;
+    }
+    for (auto& plugin : m_supportedPlugins->allOriginPlugins) {
+        if (isSupportedPlugin(plugin, mimeType, pluginURL))
+            return true;
+    }
+    return false;
+}
+
+std::optional<SupportedPluginNames> PluginInfoStore::supportedPluginNames()
+{
+    if (!m_supportedPlugins)
+        return std::nullopt;
+
+    HashSet<String> allOriginPlugins;
+    for (auto& plugin : m_supportedPlugins->allOriginPlugins)
+        allOriginPlugins.add(plugin.name);
+
+    HashMap<SecurityOriginData, HashSet<String>> originSpecificPlugins;
+    for (auto& keyValue : m_supportedPlugins->originSpecificPlugins) {
+        HashSet<String> names;
+        for (auto& plugin : keyValue.value)
+            names.add(plugin.name);
+        originSpecificPlugins.add(keyValue.key, WTFMove(names));
+    }
+    return SupportedPluginNames { WTFMove(allOriginPlugins), WTFMove(originSpecificPlugins) };
+}
+
+void PluginInfoStore::addSupportedPlugin(const SecurityOrigin* origin, String&& name, HashSet<String>&& mimeTypes, HashSet<String> extensions)
+{
+    if (!m_supportedPlugins)
+        m_supportedPlugins = SupportedPlugins { };
+
+    SupportedPlugin plugin { WTFMove(name), WTFMove(mimeTypes), WTFMove(extensions) };
+    if (!origin) {
+        m_supportedPlugins->allOriginPlugins.append(WTFMove(plugin));
+        return;
+    }
+    m_supportedPlugins->originSpecificPlugins.ensure(SecurityOriginData::fromSecurityOrigin(*origin), [] {
+        return Vector<SupportedPlugin> { };
+    }).iterator->value.append(WTFMove(plugin));
+}
+
 PluginModuleInfo PluginInfoStore::infoForPluginWithPath(const String& pluginPath) const
 {
     for (const auto& plugin : m_plugins) {
index 2791c98..d3a109f 100644 (file)
@@ -23,8 +23,7 @@
  * THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#ifndef PluginInfoStore_h
-#define PluginInfoStore_h
+#pragma once
 
 #if ENABLE(NETSCAPE_PLUGIN_API)
 
@@ -33,7 +32,7 @@
 #include <WebCore/PluginData.h>
 
 namespace WebCore {
-    class URL;
+class URL;
 }
 
 namespace WebKit {
@@ -64,6 +63,11 @@ public:
 
     static PluginModuleLoadPolicy defaultLoadPolicyForPlugin(const PluginModuleInfo&);
 
+    bool isSupportedPlugin(const String& mimeType, const WebCore::URL& pluginURL, const String& frameURLString, const WebCore::URL& pageURL);
+    std::optional<WebCore::SupportedPluginNames> supportedPluginNames();
+    void addSupportedPlugin(const WebCore::SecurityOrigin*, String&& name, HashSet<String>&& mimeTypes, HashSet<String> extensions);
+    void clearSupportedPlugins() { m_supportedPlugins = std::nullopt; }
+
 private:
     PluginModuleInfo findPluginForMIMEType(const String& mimeType, WebCore::PluginData::AllowedPluginTypes) const;
     PluginModuleInfo findPluginForExtension(const String& extension, String& mimeType, WebCore::PluginData::AllowedPluginTypes) const;
@@ -91,10 +95,21 @@ private:
     Vector<String> m_additionalPluginsDirectories;
     Vector<PluginModuleInfo> m_plugins;
     bool m_pluginListIsUpToDate;
+
+    struct SupportedPlugin {
+        String name;
+        HashSet<String> mimeTypes;
+        HashSet<String> extensions;
+    };
+    struct SupportedPlugins {
+        Vector<SupportedPlugin> allOriginPlugins;
+        HashMap<WebCore::SecurityOriginData, Vector<SupportedPlugin>> originSpecificPlugins;
+    };
+    static bool isSupportedPlugin(const SupportedPlugin&, const String& mimeType, const WebCore::URL& pluginURL);
+
+    std::optional<SupportedPlugins> m_supportedPlugins;
 };
     
 } // namespace WebKit
 
 #endif // ENABLE(NETSCAPE_PLUGIN_API)
-
-#endif // PluginInfoStore_h
index 1fc9982..9f9cfcd 100644 (file)
@@ -2055,17 +2055,27 @@ WebPreferencesStore WebPageProxy::preferencesStore() const
 }
 
 #if ENABLE(NETSCAPE_PLUGIN_API)
-void WebPageProxy::findPlugin(const String& mimeType, uint32_t processType, const String& urlString, const String& frameURLString, const String& pageURLString, bool allowOnlyApplicationPlugins, uint64_t& pluginProcessToken, String& newMimeType, uint32_t& pluginLoadPolicy, String& unavailabilityDescription)
+void WebPageProxy::findPlugin(const String& mimeType, uint32_t processType, const String& urlString, const String& frameURLString, const String& pageURLString, bool allowOnlyApplicationPlugins, uint64_t& pluginProcessToken, String& newMimeType, uint32_t& pluginLoadPolicy, String& unavailabilityDescription, bool& isUnsupported)
 {
     PageClientProtector protector(m_pageClient);
 
     MESSAGE_CHECK_URL(urlString);
 
+    URL pluginURL = URL { URL(), urlString };
     newMimeType = mimeType.convertToASCIILowercase();
-    pluginLoadPolicy = PluginModuleLoadNormally;
 
     PluginData::AllowedPluginTypes allowedPluginTypes = allowOnlyApplicationPlugins ? PluginData::OnlyApplicationPlugins : PluginData::AllPlugins;
-    PluginModuleInfo plugin = m_process->processPool().pluginInfoStore().findPlugin(newMimeType, URL(URL(), urlString), allowedPluginTypes);
+
+    URL pageURL = URL { URL(), pageURLString };
+    if (!m_process->processPool().pluginInfoStore().isSupportedPlugin(mimeType, pluginURL, frameURLString, pageURL)) {
+        isUnsupported = true;
+        pluginProcessToken = 0;
+        return;
+    }
+
+    isUnsupported = false;
+    pluginLoadPolicy = PluginModuleLoadNormally;
+    PluginModuleInfo plugin = m_process->processPool().pluginInfoStore().findPlugin(newMimeType, pluginURL, allowedPluginTypes);
     if (!plugin.path) {
         pluginProcessToken = 0;
         return;
@@ -4143,6 +4153,7 @@ void WebPageProxy::unavailablePluginButtonClicked(uint32_t opaquePluginUnavailab
         pluginUnavailabilityReason = kWKPluginUnavailabilityReasonPluginCrashed;
         break;
     case RenderEmbeddedObject::PluginBlockedByContentSecurityPolicy:
+    case RenderEmbeddedObject::UnsupportedPlugin:
         ASSERT_NOT_REACHED();
     }
 
index dab2400..0c238c4 100644 (file)
@@ -1655,7 +1655,7 @@ private:
 #endif
 
 #if ENABLE(NETSCAPE_PLUGIN_API)
-    void findPlugin(const String& mimeType, uint32_t processType, const String& urlString, const String& frameURLString, const String& pageURLString, bool allowOnlyApplicationPlugins, uint64_t& pluginProcessToken, String& newMIMEType, uint32_t& pluginLoadPolicy, String& unavailabilityDescription);
+    void findPlugin(const String& mimeType, uint32_t processType, const String& urlString, const String& frameURLString, const String& pageURLString, bool allowOnlyApplicationPlugins, uint64_t& pluginProcessToken, String& newMIMEType, uint32_t& pluginLoadPolicy, String& unavailabilityDescription, bool& isUnsupported);
 #endif
 
 #if USE(QUICK_LOOK)
index a2d484d..d41fe92 100644 (file)
@@ -420,7 +420,7 @@ messages -> WebPageProxy {
 #endif
 
 #if ENABLE(NETSCAPE_PLUGIN_API)
-    FindPlugin(String mimeType, uint32_t processType, String urlString, String frameURLString, String pageURLString, bool allowOnlyApplicationPlugins) -> (uint64_t pluginProcessToken, String newMIMEType, uint32_t pluginLoadPolicy, String unavailabilityDescription)
+    FindPlugin(String mimeType, uint32_t processType, String urlString, String frameURLString, String pageURLString, bool allowOnlyApplicationPlugins) -> (uint64_t pluginProcessToken, String newMIMEType, uint32_t pluginLoadPolicy, String unavailabilityDescription, bool isUnsupported)
 #endif
 
     DidUpdateActivityState()
index 6ee6795..faa1deb 100644 (file)
@@ -1760,6 +1760,25 @@ void WebProcessPool::clearPluginClientPolicies()
 }
 #endif
 
+void WebProcessPool::addSupportedPlugin(SecurityOrigin* origin, String&& name, HashSet<String>&& mimeTypes, HashSet<String> extensions)
+{
+#if ENABLE(NETSCAPE_PLUGIN_API)
+    m_pluginInfoStore.addSupportedPlugin(origin, WTFMove(name), WTFMove(mimeTypes), WTFMove(extensions));
+#else
+    UNUSED_PARAM(origin);
+    UNUSED_PARAM(name);
+    UNUSED_PARAM(mimeTypes);
+    UNUSED_PARAM(extensions);
+#endif
+}
+
+void WebProcessPool::clearSupportedPlugins()
+{
+#if ENABLE(NETSCAPE_PLUGIN_API)
+    m_pluginInfoStore.clearSupportedPlugins();
+#endif
+}
+
 void WebProcessPool::setMemoryCacheDisabled(bool disabled)
 {
     m_memoryCacheDisabled = disabled;
index 8c8b258..4125819 100644 (file)
@@ -202,6 +202,9 @@ public:
     const HashMap<String, HashMap<String, HashMap<String, uint8_t>>>& pluginLoadClientPolicies() const { return m_pluginLoadClientPolicies; }
 #endif
 
+    void addSupportedPlugin(WebCore::SecurityOrigin*, String&& name, HashSet<String>&& mimeTypes, HashSet<String> extensions);
+    void clearSupportedPlugins();
+
     ProcessID networkProcessIdentifier();
     ProcessID storageProcessIdentifier();
 
index 0451561..2719786 100644 (file)
@@ -567,11 +567,13 @@ void WebProcessProxy::addBackForwardItem(uint64_t itemID, uint64_t pageID, const
 }
 
 #if ENABLE(NETSCAPE_PLUGIN_API)
-void WebProcessProxy::getPlugins(bool refresh, Vector<PluginInfo>& plugins, Vector<PluginInfo>& applicationPlugins)
+void WebProcessProxy::getPlugins(bool refresh, Vector<PluginInfo>& plugins, Vector<PluginInfo>& applicationPlugins, std::optional<WebCore::SupportedPluginNames>& supportedPluginNames)
 {
     if (refresh)
         m_processPool->pluginInfoStore().refresh();
 
+    supportedPluginNames = m_processPool->pluginInfoStore().supportedPluginNames();
+
     Vector<PluginModuleInfo> pluginModules = m_processPool->pluginInfoStore().plugins();
     for (size_t i = 0; i < pluginModules.size(); ++i)
         plugins.append(pluginModules[i].info);
index 3701f7b..13c2016 100644 (file)
@@ -238,7 +238,7 @@ private:
 
     // Plugins
 #if ENABLE(NETSCAPE_PLUGIN_API)
-    void getPlugins(bool refresh, Vector<WebCore::PluginInfo>& plugins, Vector<WebCore::PluginInfo>& applicationPlugins);
+    void getPlugins(bool refresh, Vector<WebCore::PluginInfo>& plugins, Vector<WebCore::PluginInfo>& applicationPlugins, std::optional<WebCore::SupportedPluginNames>&);
 #endif // ENABLE(NETSCAPE_PLUGIN_API)
 #if ENABLE(NETSCAPE_PLUGIN_API)
     void getPluginProcessConnection(uint64_t pluginProcessToken, Ref<Messages::WebProcessProxy::GetPluginProcessConnection::DelayedReply>&&);
index e6c5dc8..7f809f8 100644 (file)
@@ -33,7 +33,7 @@ messages -> WebProcessProxy LegacyReceiver {
 
     # Plugin messages.
 #if ENABLE(NETSCAPE_PLUGIN_API)
-    GetPlugins(bool refresh) -> (Vector<WebCore::PluginInfo> plugins, Vector<WebCore::PluginInfo> applicationPlugins)
+    GetPlugins(bool refresh) -> (Vector<WebCore::PluginInfo> plugins, Vector<WebCore::PluginInfo> applicationPlugins, struct std::optional<WebCore::SupportedPluginNames> supportedPluginNames)
     GetPluginProcessConnection(uint64_t pluginProcessToken) -> (IPC::Attachment connectionHandle, bool supportsAsynchronousInitialization) Delayed
 #endif
     GetNetworkProcessConnection() -> (IPC::Attachment connectionHandle) Delayed
index 4b95509..d97c020 100644 (file)
 #include <WebCore/FrameLoader.h>
 #include <WebCore/MainFrame.h>
 #include <WebCore/Page.h>
-#include <WebCore/SecurityOrigin.h>
+#include <WebCore/SecurityOriginData.h>
 #include <WebCore/SubframeLoader.h>
 #include <wtf/text/StringHash.h>
 
 #if PLATFORM(MAC)
 #include <WebCore/StringUtilities.h>
+#endif
 
 using namespace WebCore;
-#endif
 
 namespace WebKit {
 
@@ -97,11 +97,14 @@ void WebPluginInfoProvider::refreshPlugins()
 #endif
 }
 
-void WebPluginInfoProvider::getPluginInfo(WebCore::Page& page, Vector<WebCore::PluginInfo>& plugins)
+void WebPluginInfoProvider::getPluginInfo(Page& page, Vector<PluginInfo>& plugins, std::optional<SupportedPluginNames>& supportedPluginNames)
 {
 #if ENABLE(NETSCAPE_PLUGIN_API)
     populatePluginCache(page);
 
+    if (m_cachedSupportedPluginNames)
+        supportedPluginNames = *m_cachedSupportedPluginNames;
+
     if (page.mainFrame().loader().subframeLoader().allowPlugins()) {
         plugins = m_cachedPlugins;
         return;
@@ -118,14 +121,23 @@ void WebPluginInfoProvider::getWebVisiblePluginInfo(WebCore::Page& page, Vector<
 {
     ASSERT_ARG(plugins, plugins.isEmpty());
 
-    getPluginInfo(page, plugins);
+    std::optional<WebCore::SupportedPluginNames> supportedPluginNames;
+    getPluginInfo(page, plugins, supportedPluginNames);
 
-#if PLATFORM(MAC)
-    if (auto* document = page.mainFrame().document()) {
-        if (document->securityOrigin().isLocal())
-            return;
+    auto* document = page.mainFrame().document();
+    auto* origin = document ? &document->securityOrigin(): nullptr;
+
+    if (origin && supportedPluginNames) {
+        auto originData = SecurityOriginData::fromSecurityOrigin(*origin);
+        plugins.removeAllMatching([&] (auto& plugin) {
+            return !isSupportedPlugin(*supportedPluginNames, originData, plugin.name);
+        });
     }
 
+#if PLATFORM(MAC)
+    if (origin && origin->isLocal())
+        return;
+
     for (int32_t i = plugins.size() - 1; i >= 0; --i) {
         auto& info = plugins.at(i);
 
@@ -146,7 +158,7 @@ void WebPluginInfoProvider::populatePluginCache(const WebCore::Page& page)
         HangDetectionDisabler hangDetectionDisabler;
 
         if (!WebProcess::singleton().parentProcessConnection()->sendSync(Messages::WebProcessProxy::GetPlugins(m_shouldRefreshPlugins),
-            Messages::WebProcessProxy::GetPlugins::Reply(m_cachedPlugins, m_cachedApplicationPlugins), 0,
+            Messages::WebProcessProxy::GetPlugins::Reply(m_cachedPlugins, m_cachedApplicationPlugins, m_cachedSupportedPluginNames), 0,
             Seconds::infinity(), IPC::SendSyncOption::DoNotProcessIncomingMessagesWhenWaitingForSyncReply))
             return;
 
index 49f4054..c5cb1d8 100644 (file)
@@ -45,8 +45,8 @@ public:
 private:
     WebPluginInfoProvider();
 
-    void getPluginInfo(WebCore::Page&, Vector<WebCore::PluginInfo>&) override;
-    void getWebVisiblePluginInfo(WebCore::Page&, Vector<WebCore::PluginInfo>&) override;
+    void getPluginInfo(WebCore::Page&, Vector<WebCore::PluginInfo>&, std::optional<WebCore::SupportedPluginNames>&) final;
+    void getWebVisiblePluginInfo(WebCore::Page&, Vector<WebCore::PluginInfo>&) final;
     void refreshPlugins() override;
 
 #if ENABLE(NETSCAPE_PLUGIN_API)
@@ -68,6 +68,7 @@ private:
     bool m_shouldRefreshPlugins { false };
     Vector<WebCore::PluginInfo> m_cachedPlugins;
     Vector<WebCore::PluginInfo> m_cachedApplicationPlugins;
+    std::optional<WebCore::SupportedPluginNames> m_cachedSupportedPluginNames;
 #endif
 };
 
index 946d6ac..90b5b20 100644 (file)
@@ -633,6 +633,7 @@ bool WebChromeClient::shouldUnavailablePluginMessageBeButton(RenderEmbeddedObjec
 
     case RenderEmbeddedObject::PluginCrashed:
     case RenderEmbeddedObject::PluginBlockedByContentSecurityPolicy:
+    case RenderEmbeddedObject::UnsupportedPlugin:
         return false;
     }
 
index 92e486f..16177f7 100644 (file)
@@ -828,13 +828,14 @@ RefPtr<Plugin> WebPage::createPlugin(WebFrame* frame, HTMLPlugInElement* pluginE
     uint64_t pluginProcessToken;
     uint32_t pluginLoadPolicy;
     String unavailabilityDescription;
-    if (!sendSync(Messages::WebPageProxy::FindPlugin(parameters.mimeType, static_cast<uint32_t>(processType), parameters.url.string(), frameURLString, pageURLString, allowOnlyApplicationPlugins), Messages::WebPageProxy::FindPlugin::Reply(pluginProcessToken, newMIMEType, pluginLoadPolicy, unavailabilityDescription)))
+    bool isUnsupported;
+    if (!sendSync(Messages::WebPageProxy::FindPlugin(parameters.mimeType, static_cast<uint32_t>(processType), parameters.url.string(), frameURLString, pageURLString, allowOnlyApplicationPlugins), Messages::WebPageProxy::FindPlugin::Reply(pluginProcessToken, newMIMEType, pluginLoadPolicy, unavailabilityDescription, isUnsupported)))
         return nullptr;
 
     PluginModuleLoadPolicy loadPolicy = static_cast<PluginModuleLoadPolicy>(pluginLoadPolicy);
     bool isBlockedPlugin = (loadPolicy == PluginModuleBlockedForSecurity) || (loadPolicy == PluginModuleBlockedForCompatibility);
 
-    if (isBlockedPlugin || !pluginProcessToken) {
+    if (isUnsupported || isBlockedPlugin || !pluginProcessToken) {
 #if ENABLE(PDFKIT_PLUGIN)
         String path = parameters.url.path();
         if (shouldUsePDFPlugin() && (MIMETypeRegistry::isPDFOrPostScriptMIMEType(parameters.mimeType) || (parameters.mimeType.isEmpty() && (path.endsWithIgnoringASCIICase(".pdf") || path.endsWithIgnoringASCIICase(".ps")))))
@@ -842,8 +843,14 @@ RefPtr<Plugin> WebPage::createPlugin(WebFrame* frame, HTMLPlugInElement* pluginE
 #endif
     }
 
+    if (isUnsupported) {
+        pluginElement->setReplacement(RenderEmbeddedObject::UnsupportedPlugin, unavailabilityDescription);
+        return nullptr;
+    }
+
     if (isBlockedPlugin) {
-        send(Messages::WebPageProxy::DidBlockInsecurePluginVersion(parameters.mimeType, parameters.url.string(), frameURLString, pageURLString, pluginElement->isReplacementObscured(unavailabilityDescription)));
+        bool isReplacementObscured = pluginElement->setReplacement(RenderEmbeddedObject::InsecurePluginVersion, unavailabilityDescription);
+        send(Messages::WebPageProxy::DidBlockInsecurePluginVersion(parameters.mimeType, parameters.url.string(), frameURLString, pageURLString, isReplacementObscured));
         return nullptr;
     }
 
@@ -4547,11 +4554,13 @@ bool WebPage::canPluginHandleResponse(const ResourceResponse& response)
     uint64_t pluginProcessToken;
     String newMIMEType;
     String unavailabilityDescription;
-    if (!sendSync(Messages::WebPageProxy::FindPlugin(response.mimeType(), PluginProcessTypeNormal, response.url().string(), response.url().string(), response.url().string(), allowOnlyApplicationPlugins), Messages::WebPageProxy::FindPlugin::Reply(pluginProcessToken, newMIMEType, pluginLoadPolicy, unavailabilityDescription)))
+    bool isUnsupported = false;
+    if (!sendSync(Messages::WebPageProxy::FindPlugin(response.mimeType(), PluginProcessTypeNormal, response.url().string(), response.url().string(), response.url().string(), allowOnlyApplicationPlugins), Messages::WebPageProxy::FindPlugin::Reply(pluginProcessToken, newMIMEType, pluginLoadPolicy, unavailabilityDescription, isUnsupported)))
         return false;
 
+    ASSERT(!isUnsupported);
     bool isBlockedPlugin = (pluginLoadPolicy == PluginModuleBlockedForSecurity) || (pluginLoadPolicy == PluginModuleBlockedForCompatibility);
-    return !isBlockedPlugin && pluginProcessToken;
+    return !isUnsupported && !isBlockedPlugin && pluginProcessToken;
 #else
     UNUSED_PARAM(response);
     return false;
index 2e38388..8cb4ac5 100644 (file)
@@ -1,3 +1,15 @@
+2018-02-16  Youenn Fablet  <youenn@apple.com>
+
+        Allow specifying which plug-ins are supported
+        https://bugs.webkit.org/show_bug.cgi?id=182748
+
+        Reviewed by Chris Dumez.
+
+        * WebCoreSupport/WebPluginInfoProvider.h:
+        * WebCoreSupport/WebPluginInfoProvider.mm:
+        (WebPluginInfoProvider::getPluginInfo):
+        (WebPluginInfoProvider::getWebVisiblePluginInfo):
+
 2018-02-16  Brent Fulgham  <bfulgham@apple.com>
 
         [Cocoa][WebKitLegacy] REGRESSION(r221559): Coda 2 crashes when switching views
index aaea045..4a91bab 100644 (file)
@@ -34,8 +34,8 @@ public:
 
 private:
     void refreshPlugins() override;
-    void getPluginInfo(WebCore::Page&, Vector<WebCore::PluginInfo>&) override;
-    void getWebVisiblePluginInfo(WebCore::Page&, Vector<WebCore::PluginInfo>&) override;
+    void getPluginInfo(WebCore::Page&, Vector<WebCore::PluginInfo>&, std::optional<WebCore::SupportedPluginNames>&) final;
+    void getWebVisiblePluginInfo(WebCore::Page&, Vector<WebCore::PluginInfo>&) final;
 
     WebPluginInfoProvider();
 };
index f417413..982db72 100644 (file)
@@ -55,7 +55,7 @@ void WebPluginInfoProvider::refreshPlugins()
     [[WebPluginDatabase sharedDatabaseIfExists] refresh];
 }
 
-void WebPluginInfoProvider::getPluginInfo(WebCore::Page& page, Vector<WebCore::PluginInfo>& plugins)
+void WebPluginInfoProvider::getPluginInfo(WebCore::Page& page, Vector<WebCore::PluginInfo>& plugins, std::optional<SupportedPluginNames>&)
 {
     BEGIN_BLOCK_OBJC_EXCEPTIONS;
 
@@ -71,5 +71,6 @@ void WebPluginInfoProvider::getPluginInfo(WebCore::Page& page, Vector<WebCore::P
 
 void WebPluginInfoProvider::getWebVisiblePluginInfo(WebCore::Page& page, Vector<WebCore::PluginInfo>& plugins)
 {
-    getPluginInfo(page, plugins);
+    std::optional<SupportedPluginNames> supportedPluginNames;
+    getPluginInfo(page, plugins, supportedPluginNames);
 }
index 7dbd11a..788021e 100644 (file)
@@ -1,3 +1,14 @@
+2018-02-16  Youenn Fablet  <youenn@apple.com>
+
+        Allow specifying which plug-ins are supported
+        https://bugs.webkit.org/show_bug.cgi?id=182748
+
+        Reviewed by Chris Dumez.
+
+        * WebCoreSupport/WebPluginInfoProvider.cpp:
+        (WebPluginInfoProvider::getPluginInfo):
+        * WebCoreSupport/WebPluginInfoProvider.h:
+
 2018-02-15  Don Olmstead  <don.olmstead@sony.com>
 
         WebCore headers should not be included relatively within dependent projects
index 2f6e9a7..8db9d09 100644 (file)
@@ -49,7 +49,7 @@ void WebPluginInfoProvider::refreshPlugins()
     PluginDatabase::installedPlugins()->refresh();
 }
 
-void WebPluginInfoProvider::getPluginInfo(WebCore::Page& page, Vector<WebCore::PluginInfo>& outPlugins)
+void WebPluginInfoProvider::getPluginInfo(WebCore::Page& page, Vector<WebCore::PluginInfo>& outPlugins, std::optional<WebCore::SupportedPluginNames>&)
 {
     const Vector<PluginPackage*>& plugins = PluginDatabase::installedPlugins()->plugins();
 
@@ -84,5 +84,6 @@ void WebPluginInfoProvider::getPluginInfo(WebCore::Page& page, Vector<WebCore::P
 
 void WebPluginInfoProvider::getWebVisiblePluginInfo(WebCore::Page& page, Vector<WebCore::PluginInfo>& plugins)
 {
-    getPluginInfo(page, plugins);
+    std::optional<WebCore::SupportedPluginNames> supportedPluginNames;
+    getPluginInfo(page, plugins, supportedPluginNames);
 }
index a815cc8..bbc9bdc 100644 (file)
@@ -35,12 +35,12 @@ public:
     virtual ~WebPluginInfoProvider();
 
 private:
-    void refreshPlugins() override;
-    void getPluginInfo(WebCore::Page&, Vector<WebCore::PluginInfo>&) override;
-    void getWebVisiblePluginInfo(WebCore::Page&, Vector<WebCore::PluginInfo>&) override;
+    void refreshPlugins() final;
+    void getPluginInfo(WebCore::Page&, Vector<WebCore::PluginInfo>&, std::optional<WebCore::SupportedPluginNames>&) final;
+    void getWebVisiblePluginInfo(WebCore::Page&, Vector<WebCore::PluginInfo>&) final;
 #if PLATFORM(MAC)
-    void setPluginLoadClientPolicy(WebCore::PluginLoadClientPolicy, const String& host, const String& bundleIdentifier, const String& versionString) override;
-    void clearPluginClientPolicies() override;
+    void setPluginLoadClientPolicy(WebCore::PluginLoadClientPolicy, const String& host, const String& bundleIdentifier, const String& versionString) final;
+    void clearPluginClientPolicies() final;
 #endif
 
     WebPluginInfoProvider();
index 5ab16a7..bc1c0f8 100644 (file)
@@ -1,3 +1,23 @@
+2018-02-16  Youenn Fablet  <youenn@apple.com>
+
+        Allow specifying which plug-ins are supported
+        https://bugs.webkit.org/show_bug.cgi?id=182748
+
+        Reviewed by Chris Dumez.
+
+        Add support for a test runner API to specificy supported plug-ins.
+
+        * WebKitTestRunner/InjectedBundle/Bindings/TestRunner.idl:
+        * WebKitTestRunner/InjectedBundle/TestRunner.cpp:
+        (WTR::TestRunner::setPluginsAsUnsupported):
+        * WebKitTestRunner/InjectedBundle/TestRunner.h:
+        * WebKitTestRunner/TestController.cpp:
+        (WTR::TestController::resetStateToConsistentValues):
+        (WTR::TestController::setPluginsAsUnsupported):
+        * WebKitTestRunner/TestController.h:
+        * WebKitTestRunner/TestInvocation.cpp:
+        (WTR::TestInvocation::didReceiveMessageFromInjectedBundle):
+
 2018-02-16  Per Arne Vollan  <pvollan@apple.com>
 
         Implement stopping of run loop in the WebContent process when using NSRunLoop.
index ac79672..8b25dea 100644 (file)
@@ -233,7 +233,8 @@ interface TestRunner {
     
     // Override plugin load policy.
     void setBlockAllPlugins(boolean shouldBlock);
-    
+    void setPluginSupportedMode(DOMString mode);
+
     // Hooks to the JSC compiler.
     object failNextNewCodeBlock();
     object numberOfDFGCompiles(object function);
index 1251cf3..0c8c040 100644 (file)
@@ -1075,6 +1075,13 @@ void TestRunner::setBlockAllPlugins(bool shouldBlock)
     WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get());
 }
 
+void TestRunner::setPluginSupportedMode(JSStringRef mode)
+{
+    WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetPluginSupportedMode"));
+    WKRetainPtr<WKStringRef> messageBody(AdoptWK, WKStringCreateWithJSString(mode));
+    WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get());
+}
+
 JSValueRef TestRunner::failNextNewCodeBlock()
 {
     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
index 3ccea72..3effac8 100644 (file)
@@ -188,7 +188,8 @@ public:
     // Audio testing.
     void setAudioResult(JSContextRef, JSValueRef data);
 
-    void setBlockAllPlugins(bool shouldBlock);
+    void setBlockAllPlugins(bool);
+    void setPluginSupportedMode(JSStringRef);
 
     enum WhatToDump { RenderTree, MainFrameText, AllFramesText, Audio, DOMAsWebArchive };
     WhatToDump whatToDump() const { return m_whatToDump; }
index e446017..52689b1 100644 (file)
@@ -843,6 +843,7 @@ bool TestController::resetStateToConsistentValues(const TestOptions& options)
     m_authenticationPassword = String();
 
     m_shouldBlockAllPlugins = false;
+    setPluginSupportedMode({ });
 
     m_shouldLogDownloadCallbacks = false;
     m_shouldLogHistoryClientCallbacks = false;
@@ -1669,6 +1670,44 @@ WKPluginLoadPolicy TestController::decidePolicyForPluginLoad(WKPageRef, WKPlugin
 #endif
 }
 
+void TestController::setPluginSupportedMode(const String& mode)
+{
+    if (m_unsupportedPluginMode == mode)
+        return;
+
+    m_unsupportedPluginMode = mode;
+    if (m_unsupportedPluginMode.isEmpty()) {
+        WKContextClearSupportedPlugins(m_context.get());
+        return;
+    }
+
+    WKRetainPtr<WKMutableArrayRef> emptyArray = adoptWK(WKMutableArrayCreate());
+    WKRetainPtr<WKStringRef> allOrigins = adoptWK(WKStringCreateWithUTF8CString(""));
+    WKRetainPtr<WKStringRef> specificOrigin = adoptWK(WKStringCreateWithUTF8CString("http://localhost:8080"));
+
+    WKRetainPtr<WKStringRef> pdfName = adoptWK(WKStringCreateWithUTF8CString("My personal PDF"));
+    WKContextAddSupportedPlugin(m_context.get(), allOrigins.get(), pdfName.get(), emptyArray.get(), emptyArray.get());
+
+    WKRetainPtr<WKStringRef> nameNetscape = adoptWK(WKStringCreateWithUTF8CString("com.apple.testnetscapeplugin"));
+    WKRetainPtr<WKStringRef> mimeTypeNetscape = adoptWK(WKStringCreateWithUTF8CString("application/x-webkit-test-netscape"));
+    WKRetainPtr<WKMutableArrayRef> mimeTypesNetscape = adoptWK(WKMutableArrayCreate());
+    WKArrayAppendItem(mimeTypesNetscape.get(), mimeTypeNetscape.get());
+
+    WKRetainPtr<WKStringRef> namePdf = adoptWK(WKStringCreateWithUTF8CString("WebKit built-in PDF"));
+
+    if (m_unsupportedPluginMode == "allOrigins") {
+        WKContextAddSupportedPlugin(m_context.get(), allOrigins.get(), nameNetscape.get(), mimeTypesNetscape.get(), emptyArray.get());
+        WKContextAddSupportedPlugin(m_context.get(), allOrigins.get(), namePdf.get(), emptyArray.get(), emptyArray.get());
+        return;
+    }
+
+    if (m_unsupportedPluginMode == "specificOrigin") {
+        WKContextAddSupportedPlugin(m_context.get(), specificOrigin.get(), nameNetscape.get(), mimeTypesNetscape.get(), emptyArray.get());
+        WKContextAddSupportedPlugin(m_context.get(), specificOrigin.get(), namePdf.get(), emptyArray.get(), emptyArray.get());
+        return;
+    }
+}
+
 void TestController::didCommitNavigation(WKPageRef page, WKNavigationRef navigation)
 {
     mainWebView()->focus();
index a32f18f..01c17e0 100644 (file)
@@ -139,6 +139,7 @@ public:
     void setAllowsAnySSLCertificate(bool);
 
     void setBlockAllPlugins(bool shouldBlock) { m_shouldBlockAllPlugins = shouldBlock; }
+    void setPluginSupportedMode(const String&);
 
     void setShouldLogHistoryClientCallbacks(bool shouldLog) { m_shouldLogHistoryClientCallbacks = shouldLog; }
     void setShouldLogCanAuthenticateAgainstProtectionSpace(bool shouldLog) { m_shouldLogCanAuthenticateAgainstProtectionSpace = shouldLog; }
@@ -398,6 +399,7 @@ private:
     String m_authenticationPassword;
 
     bool m_shouldBlockAllPlugins { false };
+    String m_unsupportedPluginMode;
 
     bool m_forceComplexText { false };
     bool m_shouldUseAcceleratedDrawing { false };
index 5a7e9a4..7699c9b 100644 (file)
@@ -710,6 +710,13 @@ void TestInvocation::didReceiveMessageFromInjectedBundle(WKStringRef messageName
         return;
     }
 
+    if (WKStringIsEqualToUTF8CString(messageName, "SetPluginSupportedMode")) {
+        ASSERT(WKGetTypeID(messageBody) == WKStringGetTypeID());
+        WKStringRef mode = static_cast<WKStringRef>(messageBody);
+        TestController::singleton().setPluginSupportedMode(toWTFString(mode));
+        return;
+    }
+
     if (WKStringIsEqualToUTF8CString(messageName, "SetShouldDecideNavigationPolicyAfterDelay")) {
         ASSERT(WKGetTypeID(messageBody) == WKBooleanGetTypeID());
         WKBooleanRef value = static_cast<WKBooleanRef>(messageBody);