We had a impromptu meeting today discussing what a new Content Policy
API would look like. We have for a long time been suffering from an
API which provides very little convenience for code needing to do
security checks before opening a network connection, while also
providing very little support for people implementing the Content
Policy API in order to block certain network loads.
Additionally the existing API works very poorly in e10s since it's
fully synchronous and uses XPCOM component registration.
So below is what we are thinking. There's not a lot of detail yet,
more higher-level ideas. Please do ask questions if you have concerns
or ideas!
Here's how things would work from the point of view of someone
implementing a content policy:
First off, we want to use normal (but chrome-only) DOM events to
deliver the notifications. This works better with e10s as have been
discussed at [1]. Each content policy would then register to be an
event handler for this event.
When the event fires, a event handler can either do nothing if it
wants to let the load proceed as normal, or it can call a function on
the Event indicating that the load should be blocked. There should
also be a function to indicate "I don't have an answer yet, but I'll
call you back asynchronously to let you know my answer". We won't
start any network traffic until everyone that requested to reply
asynchronously has responded.
As a performance saving measure we can make the call to synchronously
block the load also call Event.stopImmediatePropagation, which would
prevent more of the content-policy-event-handlers from getting called.
When the event fires, we make the following information available:
* Load type. I.e. stylesheet, document, XHR, etc. [2] is the list of
types that we currently have
* URI. The uri we're about to load
* Node. The note initiating the load. In some cases when we can't
figure out the exact node it'll be the document where the load
happens.
* Channel. The channel we're about to start loading.
A big change here is that we provide the channel. This will make it
much easier to track a single load through the rest of necko. Another
thing to note is that since we provide a reference to the node the
event has to be fired in the e10s content process. This shouldn't be
too hard to deal with for addons though as we have good mechanisms for
registering event handlers in all e10s content processes as detailed
in [1]. The principal of the loader will be trivially accessible from
the Node.
If a redirect occurs we'll again fire an event looking exactly like
the first event which provides the same data and additionally the old
channel and old URI. This makes handling redirects *a lot* easier
compared to how things work today. Again the
content-policy-event-handler has the ability to respond synchronously
or asynchronously and we won't hit the network for the new URI until
everyone has responded.
We'll also provide a explicit API on the event to allow a content
policy to redirect a load to a new URI. When that happens we'll treat
this like a "normal" redirect and fire a new event on all content
policy just like for a http redirect. If multiple policies want to
redirect to different URIs we'll have to handle that somehow.
Once we have downloaded enough of the resource that we have things
like header data we fire a second, in place of the current
nsIContentPolicy.shouldProcess callback. Again content policies will
have the ability to respond synchronously or asynchronously. Not until
we have responses from all event handlers will we hand the result of
the network request to the client.
For someone wanting to call into the content policy API before
starting a network load here's what things would look like:
First the caller creates a channel for the load. The caller then calls
into the content policy API and provide the load type, the loading
node and the channel (the URI can be derived from the channel) and
flags. The flags are for things like:
* Do same-origin check
* Is data: considered same-origin
* Are loads from chrome: allowed
* Other checkloaduri flags [3]
The API takes care of doing the same-origin check if requested,
including on redirects. It also performs the CheckLoadURI check
according to flags. If those checks pass it'll notify the content
policy implementations by firing the above described event. Once all
the checks have passed, which could happen asynchronously, it'll fire
off the network load.
Even if the API doesn't synchronously know if it's safe to hit the
network it'll still have to call AsyncOpen on the channel
synchronously. Or at least it'll have make the channel act as if
AsyncOpen had been called. This is important as to allow the channel
to be canceled and to prevent SetRequestHeader and similar APIs from
being called.
Another important aspect is that the API has to fire the event off of
a scriptrunner. This to ensure that content-policy-event-handlers
doesn't take any actions that we're not prepared for due to being in
an inconsistent state.
Once we get the OnStartRequest notification from necko we'll fire the
second event. While waiting for the response to this event (which
could come asynchronously) we'll have to pause the channel to prevent
OnDataAvailable calls from coming in. We also don't call
OnStartRequest on the streamlistener.
Questions:
Is the above list of information enough to provide to the content
policy consumers? I.e. is channel, node, uri and load type enough? We
currently have some additional properties, but they seem mostly
useless. The reason we want to drop them is to have to carry around
less information in case a redirect happens.
Is the current list of load types that we have good? This is pretty
orthogonal to the other changes proposed here, but since we're
changing the API in backwards incompatible ways anyway, we have a good
opportunity to make improvements.
[1] http://groups.google.com/group/mozilla.dev.platform/browse_thread/thread/a0030ea69fa5fa1a/371558655716c965
[2] http://mxr.mozilla.org/mozilla-central/source/content/base/public/nsIContentPolicy.idl#57
[3] http://mxr.mozilla.org/mozilla-central/source/caps/idl/nsIScriptSecurityManager.idl#69
/ Jonas
That would require some significant necko changes; it's almost certainly
out of the scope of the work we're taking on here.
It would be good to add such hooks to necko, of course, and once they
exist we can surface them to extensions, but that can be an additive
change later and I don't think it should block the initial API change
here....
-Boris