users@servlet-spec.java.net

[servlet-spec users] Re: [jsr340-experts] Re: HTTP/2 Push Was: Server-Sent Events in Java EE 8

From: Edward Burns <edward.burns_at_oracle.com>
Date: Thu, 21 Aug 2014 13:50:26 -0700

>>>>> On Wed, 20 Aug 2014 09:23:17 +1000, Greg Wilkins <gregw_at_intalio.com> said:

EB> Greg, is this the rationalization used by the httpbis wg to justify not
EB> handling the problem more explicitly?

GW> I can't speak for the WG, but I posted them a link to this thread and ask
GW> for confirmation of my characterisation of the mechanism as follows:

GW> - Push is a server-side coordinated mechanism in as much as the server
GW> must decide to push a resourced based only on information that it already
GW> has. Specifically h2 provides no information on the contents or status of
GW> downstream caches.
[...]

GW> This has received an OK from the WG chair and editor.

GW> So to answer your original question, yes it is expected behaviour that
GW> bandwidth can be saved on unnecessary pushes by RST streams.

Ok, good, thanks for firmly establishing the context.

Let's explore this further as we wait for the JCP machinery to make our
new JSR official*.

Your colleague Simone Bordet posted this blog entry:

https://webtide.com/http2-push-with-experimental-servlet-api/

in which this idiom is proposed for doing server push:

SB> The experimental Servlet API (designed by @gregwilkins) is very
SB> simple and would consist of only one additional method in
SB> javax.servlet.RequestDispatcher:

SB> public interface RequestDispatcher
SB> {
SB> public void push(ServletRequest request);
SB>
SB> ....
SB> }

Usage example:

SB> public class MyServlet extends HttpServlet
SB> {
SB> public void doGet(HttpServletRequest request, HttpServletResponse response)
SB> throws ServletException, IOException
SB> {
SB> String uri = request.getRequestURI();
SB> if ("/index.html".equals(uri))
SB> {
SB> String resourceToPush = "/js/jquery.js";
SB> RequestDispatcher dispatcher =
SB> request.getRequestDispatcher(resourceToPush);
SB> dispatcher.push(request);
SB> }
SB> }
SB> }

You can't argue this isn't simple. It is, and I like that. However,
when I think of how I'd use this from JSF, I can't see how I'd do it.

I'd want to push out the resources after rendering the Facelets page.
When the rendering of the Facelets page is done, I know exactly what
resources the browser is going to request. Let's say we have a simple
JSF page that uses Ajax and has a CSS file. This means we'll have three
things to send down:

index.xhtml
jsf.js
style.css

So, we have our existing FacesServlet.service() {

  ...
  FacesContext context = factory.createFacesContext(request, response);
  ResourceHandler handler = context.getResourceHandler();
  ...
  if (handler.isResourceRequest(context)) {
    handler.handleResourceRequest(context);
  } else {
    lifecycle.attachWindow(context);
    lifecycle.execute(context);
    lifecycle.render(context);
  }
  ...
  context.release();

}

On the initial request, the latter branch of the "if" is executed. When
the browser requests the js and css the former branch of the "if" is
executed.

I'd like to be able to do something like this, instead.

FacesServlet.service() {

  ...
  FacesContext context = factory.createFacesContext(request, response);
  ResourceHandler handler = context.getResourceHandler();
  ...
  if (handler.isResourceRequest(context)) {
    handler.handleResourceRequest(context);
  } else {
    lifecycle.attachWindow(context);
    lifecycle.execute(context);
    lifecycle.render(context);
  }

  if (isHttp2) {
    handler.pushResources(context);
  }
  ...
  context.release();
}

Now of course the question is what does pushResources() do? I'd like an
API where I can issue N responses, with arbitrary headers and arbitrary
bytes for each, naturally writing using non-blocking IO, and possibly
asynchronously. I could be missing something, but Greg's API of getting
a RequestDispatcher *around* a static resource does not appear allow
this level of control.

Something like this:

pushResources(FacesContext context) {

  for (Resource cur : myResources) {

    // Do each resource in parallel, using non-blocking IO.

      // write headers
      // write bytes
  }
}

Also, when the browser sends RST to one of the N pushed resources, I want it
to only cancel that one resource and the rest of them can proceed
unhindered.

Does this seem in-scope for Servlet 4?

Ed

-- 
| edward.burns_at_oracle.com | office: +1 407 458 0017
| 21 work days til JavaOne 2014
* Teaser: it will be JSR-369