[webkit-gtk] Block/Unblock plugin API

Carlos Garcia Campos cgarcia at igalia.com
Tue Dec 16 04:47:28 PST 2014

El lun, 15-12-2014 a las 13:24 +0100, Marcos Chavarría Teijeiro
> Hi,
> I'm working on implementing a new API for block and unblock plugins
> [1]. I want to discuss here how we should implement it.
> The current API WebKitPlugin suggests to add new methods get_enabled
> and set_enabled but by implementing this methods we could not specify
> the unavailabilityDescription and populate the unavailable plugin
> button with this information. In addition we don't leave almost any
> control to the app, implementing unblock certain plugins for certain
> domains could be more difficult using this way for example.
> I have been talking with Carlos García and we believe  that we should
> implement a PluginLoadPermissionRequest so we can use
> "permission-request" signal to block/unblock plugin load. The
> information about if a plugin is blocked or not would be stored in the
> app.

Well, that's just a possibility, but I'm not sure permission request
would work for this particular case for several reasons. First, let's
see how WebKit2 works internally, what we want to achieve, and how we
could do that.

When plugins are not disabled, they are always scanned on demand to keep
a list of plugins in the UI process. Fortunately that's no longer a
problem with the plugins cache. Every plugin scanned to get its metadata
can be filtered out by PluginInfoStore::shouldUsePlugin(). This doesn't
have any API client, so it's to disable plugins internally, for example,
if a particular version of a plugin is known to be insecure. In this
cases the plugins are not added to the list of plugins.

When the WebProcess needs to create a plugin, it sends a message to the
UI process (FindPlugin) that returns False if the plugin was not found
(this includes the plugins disabled since they are not included in the
list) or True if the plugin was found. When a plugin is found,
API::LoaderClient::pluginLoadPolicy() is called, so that the API layer
can decide whether to block the plugin or not, and provide additional
information like the reason why the plugin is blocked. This is called
everytime a page is loaded and for every plugin that is created. The
internal load policy values are currently PluginModuleLoadNormally,
PluginModuleLoadUnsandboxed or PluginModuleBlocked. 

When the API layer blocks a plugin, the plugin process is not spawned
and the web process renders a button with the text returned by the API
layer with the reasons for blocking the plugin. However, this button
might be obscured in the page or not present for plugins without UI for
example. When a plugin is blocked, the web process sends a message to
the UI process (DidBlockInsecurePluginVersion) to notify that the plugin
has been blocked (the UI process already knows that) including whether
the plugin button is obscured or not. The WebKit layer is notified about
this using API::LoaderClient::didBlockInsecurePluginVersion().

Finally when the user clicks on a blocked plugin button, the
API::UIClient::unavailablePluginButtonClicked() is called so that the
WebKit layer can react to that.

Note also that canShowMIMEType also uses findPlugin, but it doesn't
check the load policy, so it will return false for plugins disabled by
PluginInfoStore::shouldUsePlugin(), but true for plugins blocked by
pluginLoadPolicy(), since those could actually be shown if unblocked by
the user.

So, there are 3 points to expose in the API, loadPolicy, didBlockPlugin
and unavailablePluginButtonClicked.

We could use the current permission request API for the loadPolicy as
Marcos said, but it's probably too limited for this particular case. The
permission request API only allows for allow/deny results, but even if
we currently don't PluginModuleLoadUnsandboxed policy, we might support
that eventually, or new policies might be added. Also, we need a way to
provide additional information, like the blocked reason, but
permission-request signal only expects allow/deny from the user. And
even more important, prmission-request allows to handle requests
asynchronously, but FindPlugin message is synchronous, so we can't
handle this asynchronously.

So, for the load plugin policy I propose to use a dedicated signal that
returns the policy as an enum.

WebKitPluginLoadPolicy (* load_plugin) (WebKitWebView *web_view, WebKitPluginLoadRequest *request);

WebKitPluginLoadPolicy would have WEBKIT_PLUGIN_LOAD_NORMALLY and
WEBKIT_PLUGIN_LOAD_BLOCK for now. The default implementation returns

WebKitPluginLoadRequest would be a boxed type, alive during the signal
emission, since this can't be handled asynchronously. This way we could
provide additional information in the future without breaking the API,
for now it could have this API:

WebKitPlugin *webkit_plugin_load_request_get_plugin (WebKitPluginLoadRequest *request);
const char *webkit_plugin_load_request_get_page_uri (WebKitPluginLoadRequest *request);
void webkit_plugin_load_request_set_description (WebKitPluginLoadRequest *request, const char *description);

For didBlockPlugin we could use a similar signal, for just informative
ins this case.

void (* plugin_blocked) (WebKitWebView *web_view, WebKitPlugin *plugin, gboolean is_visible_in_page);

The application could check if after load completes there are blocked
plugins, but none of them visible, and use a popup to ask the user, or
add a button to the URL bar, or whatever considering that plugin blocked
buttons will not be available.

And finally a signal emitted when the plugin blocked button is clicked.

void (* plugin_unavailability_button_clicked) (WebKitWebView *web_view, WebKitPluginUnavailabilityInformation *info);

I'm using unavailability here instead of blocked, because this is also
used for plugins that are missing, this can happen for example if the
plugin is uninstalled after the plugin list has been populated. 

WebKitPluginUnavailabilityInformation would be a boxed type with an API
like this one.

WebKitPluginUnavailabilityReason webkit_plugin_unavailability_information_get_reason (WebKitPluginUnavailabilityInformation *info);
WebKitPlugin *webkit_plugin_unavailability_information_get_plugin (WebKitPluginUnavailabilityInformation *info);
const char *webkit_plugin_unavailability_information_get_page_uri (WebKitPluginUnavailabilityInformation *info);

Reason would be MISSING or BLOCKED for now. Then the application could
enable the plugin internally and reload the page so that when
load-plugin signal is emitted again it will return LOAD_NORMALLY for
that plugin.

I think this API provides all the flexibility that the internal or C API
allows. There are a few things I'm not completely sure about:

  - WebKitPluginLoadRequest: do we really need the get_page_uri?
wouldn't that be always the current web view uri? I've added the method
because that information is provided by the loader client callback, but
we need to make sure it's actually needed. For a first version we could
avoid that method, and add it later if it's actually useful. But without
method, the request is a very simple object, so maybe we could pass the
WebKitPlugin directly to the signal and pass an out parameter for the
button description. That would make everything simpler, but we won't be
able to add more info to the signal without breaking the API.

  - plugin-blocked: In this case I did the opposite, passing the
information as signal arguments. Currently wk passes the frame URL, page
URL, plugin mime type and whether the plugin is obscured. We might use a
boxed type here too, for example to also provide the page uri and the
plugin mime type if needed/useful. 

  - plugin-unavailability-button-clicked: the signal name and the boxed
type used to provide the information are too long, we could think about
better names. Again I'm not sure about the needed to provide the page
uri. Also internally, wk passes the plugin page attribute (I guess this
is the page where the plugin can be downloaded in case of missing

> In addition, we should also add a new signal
> "unavailable-plugin-button-clicked" to WebView so when this button is
> clicked we could unblock this plugin and reload the webpage.
> Best Regards,
> Marcos Chavarría Teijeiro.
> [1] https://bugs.webkit.org/show_bug.cgi?id=134357
> _______________________________________________
> webkit-gtk mailing list
> webkit-gtk at lists.webkit.org
> https://lists.webkit.org/mailman/listinfo/webkit-gtk

Carlos Garcia Campos
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 181 bytes
Desc: This is a digitally signed message part
URL: <https://lists.webkit.org/pipermail/webkit-gtk/attachments/20141216/a54e612f/attachment.sig>

More information about the webkit-gtk mailing list