All,
We are at the stage where we need to play around with some http/2 push APIs
in order to test the underlying mechanism. So it would be really good to
get some feedback on some of these ideas below, as I'm a bit torn.
Some background first....
http/2 push is not general purpose pushing of messages from server to
client like websocket is (or long polling). Rather it is a mechanism to
push resources that are related to one that was fetched by a normal request.
For example, when the server receives a request for /index.html it may
decide that for minimum round trips that along with index.html response, it
should push favicon.ico, logo.png, mysite.css and jquery.js. It does this
by including a push promise frame for each of those associated resources in
the response stream to /index.html. Each push promise contains a fake
request (method, uri and fields) to which the push resource will pretend to
be a response to, plus the stream id of the new stream on which that
response will be sent.
Clients receiving a push promise can decide that they already have the
resource (or don't need it) and reset the new stream, or they can accept
the new streams data and typically use it to populate their cache. So
essentially http2 push is a way for a server to preload a clients cache.
So an API for this could be put on the ServletResponse something like:
doGet(ServletRequest request, ServletResponse response)
{
response.push("/jquery.js");
response.push("/css/mysite.css");
response.push("/images/logo.png");
...
}
This is good because it means we can use the response state to do an
illegalStateException if the response is not in a state where a push
promise can be sent (eg already closed).
However, to be consistent with other API, the path passed would have to be
relative to the current context. This means that you can't push resources
from another context.
Another slight issue, is that there is no scope to adjust the fake request,
as you might like to add a Cookie or other header to reflect some state
that has changed in the processing of the original request.
So the alternative is to put the API on a request dispatcher:
doGet(ServletRequest request, ServletResponse response)
{
getServletContext().getRequestDispatcher("/jquery.js").push(request,response);
getServletContext().getRequestDispatcher("/css/mysite.css").push(request,response);
getServletContext().getRequestDispatcher("/images/logo.png").push(request,response);
...
}
this is a little more verbose, but the dispatchers could be obtain ahead of
time in init. The request object is passed, so it can be wrapped to add
extra fields if need be. The response is there as that is where the push
promise will be sent, so it's state needs to be checked. Note that it is
not the response the pushed resource itself will go on, so wrapping the
response object will not achieve anything.
You can of course get request dispatchers from other contexts if you really
really want to do cross context push.
thoughts?
--
Greg Wilkins <gregw_at_intalio.com>
http://eclipse.org/jetty HTTP, SPDY, Websocket server and client that scales
http://www.webtide.com advice and support for jetty and cometd.