As promised on my last post on HTTP/2, we have implemented and deployed the HTTP/2 Push functionality on this very website, webtide.com. For the other HTTP/2 implementers out there, if you request "/"
on webtide.com, you will get "/wp-includes/js/jquery/jquery.js"
pushed. We have already implemented SPDY Push in the past, but this time we wanted to go a step further and implement HTTP/2 Push in the context of an experimental Servlet API that applications can use to decide what to resources needs to be pushed.
The experimental Servlet API (designed by @gregwilkins) is very simple and would consist of only one additional method in javax.servlet.RequestDispatcher
:
public interface RequestDispatcher { public void push(ServletRequest request); .... }
An application receiving a request for a primary resource, say index.html
, would identify what secondary resources it would like to push along with the primary resource. For each secondary resource, the application would obtain a RequestDispatcher
, and then call push()
on it, passing the primary resource request:
public class MyServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String uri = request.getRequestURI(); if ("/index.html".equals(uri)) { String resourceToPush = "/js/jquery.js"; RequestDispatcher dispatcher = request.getRequestDispatcher(resourceToPush); dispatcher.push(request); } } }
For applications that use web frameworks, in general, is difficult to identify a resource to push. For example, if you use a JSF library, your application is not in control of what secondary resources the JSF library may need to push (for example, css, javascript snippets, images, etc. associated to the JSF components that are being rendered).
Browsers, on the other hand, are in a much better position to identify secondary resources belonging to a primary resource, when they parse the primary resource. It would be great if browsers could request those resources with a special HTTP header that marks the secondary resource request as associated to the primary resource. Not only, it would be great if this could be completely automated, so that applications need not to worry about primary and secondary resources.
This is exactly what we have done in PushCacheFilter
. We have implemented a strategy where the Referer
header is being used to associate secondary resources to primary resources. With this association information, the filter builds a cache where secondary resources are linked to a primary resource, and every time a primary resource is being requested, we push also the associated secondary resources.
The PushCacheFilter
looks for the resource being requested; if it is not known to the filter, it assumes it is a primary resource and assigns a timestamp to it. Then it “opens” a window of – by default – 2000 ms where other requests may arrive; if these other requests have the former request as referrer, then these are secondary resources associated to the primary resource. The next time that the primary resource is requested, the filter knows about it, and pushes its secondary resources via the experimental Servlet API discussed above.
We have kept the filter intentionally simple to foster discussion about what strategies could be more useful, and what features would be needed, for example:
- Would browsers use a special header (not the
Referer
header) to mark the a resource as associated to another resource ? - How would be possible to evict entries from the push cache without manual intervention ?
- Is there a relationship between the cacheability of the primary resource and that of the secondary resources that we can leverage ?
- How can a browser tell the server to not push a resource that it is already in the browser’s cache ?
We encourage anyone that is interested to join the Jetty mailing lists and contribute to the discussion.
If you are interested to make your website faster, look at what HTTP/2 Push could do to your website (from our SPDY Push Demo Video), and contact us.
2 Comments
edburns · 18/08/2014 at 20:45
SB> For applications that use web frameworks, in general, is difficult
SB> to identify a resource to push.
Doch, this is exactly what a framework is well positioned to do.
SB> For example, if you use a JSF library, your application is not in
SB> control of what secondary resources the JSF library may need to push
SB> (for example, css, javascript snippets, images, etc. associated to
SB> the JSF components that are being rendered).
The application is not, but the framework most certainly is, and is able
to take advantage of that information.
In the case of JSF (and any other framework that maintains UI state on
the server) once the view to serve has been identified, the server knows
exactly what resources the browser is going to request *before it
requests them*. This is exactly the use case for http/2 server push.
The only problem remains to be avoiding wasted bandwidth by pushing
resources the browser already has. As mentioned on the servlet users
mailing list, it’s possible browsers could cause the optimistic pushes
to be canceled.
But back to Greg’s suggested new method. I’m not ready to study it at
that level yet, but I do like the simplicity.
gregw · 22/01/2015 at 17:11
Note that since this blog I have rethought this API and have a new proposal for push. Please see discussion on expert group here: https://java.net/projects/servlet-spec/lists/jsr369-experts/archive/2014-12/message/2