HTTP/2 Overview
Starting with 2.4.0, Grizzly offers support for HTTP/2. The goal of HTTP/2 is to reduce web page load time. This is achieved by prioritizing and multiplexing the transfer of web page resources so that only one connection per client is required.
How it works
The HTTP/2 protocol implementation is represented, at least in the server case, a Filter that sits between the HTTP/1.1 Filter and the HTTP server filter. All the Filters upstream to HTTP/2 filter receive HTTP messages for processing, so they are not even aware of HTTP/2 protocol.
Grizzly supports HTTP/2 over plain text and TLS. However, to support HTTP/2 over TLS, you will be required to include a special library on the JVM’s bootclasspath to override the default SSL/TLS handshake implementation with support for Application-Layer Protocol Negotiation Extension. (see https://tools.ietf.org/html/rfc7540#section-3.3 for details on ALPN). Because this requires modifying internal JDK classes, the ALPN implementation is sensitive to version of the Oracle JDK that’s being used. As such, the current Grizzly ALPN implementation requires JDK 1.8.0_(121,131,141). Later versions of JDK8 may work, but if the classes change in a significant way, it will result in a runtime issue.
Dependency | Description |
---|---|
grizzly-npn-api-1.7.jar | This JAR exposes the Grizzly-side of the ALPN API. Typically won't be needed by developers unless they wish to expose custom protocols via ALPN. |
grizzly-npn-bootstrap-1.7.jar | Includes both the ALPN API and the SSL implementation overrides. This JAR must be specified on the bootclasspath (-Xbootclasspath/p:<path_to_and_including_grizzly-npn-bootstrap-1.7.jar>) in order for ALPN to function. |
grizzly-npn-osgi-1.7.jar | This JAR is an OSGi bundle fragment. It's used to ensure the ALPN API classes are properly available to an OSGi runtime. |
In order to simplify HttpServer HTTP/2 configuration, there is a HTTP/2AddOn available, which may be registered on the required HttpServer’s NetworkListener like:
HttpServer httpServer = new HttpServer(); NetworkListener listener = new NetworkListener("grizzly", NetworkListener.DEFAULT_NETWORK_HOST, PORT); listener.setSecure(true); // Include environmental specific SSL configuration. listener.setSSLEngineConfig(...); // Create default HTTP/2 configuration and provide it to the AddOn Http2Configuration configuration = Http2Configuration.builder().build(); Http2AddOn http2Addon = new Http2AddOn(configuration); // Register the Addon. listener.registerAddOn(http2Addon); httpServer.addListener(listener);
The Http2Configuration class provides the following properties:
maxConcurrentStreams | Configures how many streams may be multiplexed over a single connection. The default is 100. |
initialWindowSize | Configures how much memory, in bytes, each stream will consume on the server side. The default is 64KB. |
maxFramePayLoadSize | Configures the upper bound, in bytes, on allowable frame sizes. Frames above this bound will be rejected. If not explicitly configured, the default will be the largest allowed by the RFC. |
maxHeaderListSize | Configures the maximum size, in bytes, of the headers. The default is 4096. |
disableCipherCheck | The HTTP/2 RFC defines a set of cipher suites that shouldn't be allowed to be used to establish a secure connection. Set this to true to disable this security protection. |
priorKnowledge | This property is relevant to the client only. It connects directly to a server using special magic instead of using the HTTP upgrade mechanism. Only use this if the target server is known to support HTTP/2. |
threadPoolConfig | If specified, a new thread pool will be created to process HTTP streams and push requests. |
executorService | Provide an existing ExecutorService for processing HTTP/2 streams and push requests. |
HTTP/2 Server Push
Starting with 2.4.0, Grizzly offers support for HTTP/2 server push mechanism https://tools.ietf.org/html/rfc7540#section-8.2.
Quote:
HTTP/2 allows a server to pre-emptively send (or “push”) responses (along with corresponding “promised” requests) to a client in association with a previous client-initiated request. This can be useful when the server knows the client will need to have those responses available in order to fully process the response to the original request.
To support this feature, we’ve provided an API similar to the PushBuilder defined in Servlet 4.0. This mechanism allows the developer to issue a push for an existing static or dynamic resource.
Consider the following example:
final HttpHandler mainHandler = new HttpHandler() { @Override public void service(final Request request, final Response response) throws Exception { final PushBuilder builder = request.newPushBuilder(); builder.path("/resource1"); builder.push(); builder.path("/resource2"); builder.push(); response.setCharacterEncoding("UTF-8"); response.setContentType("text/plain"); response.getWriter().write("main"); } }; final HttpHandler resource1 = new HttpHandler() { @Override public void service(final Request request, final Response response) throws Exception { response.setCharacterEncoding("UTF-8"); response.setContentType("text/plain"); response.getWriter().write("resource1"); } }; final HttpHandler resource2 = new HttpHandler() { @Override public void service(final Request request, final Response response) throws Exception { response.setCharacterEncoding("UTF-8"); response.setContentType("text/plain"); response.getWriter().write("resource2"); } };
In the example above, three _HttpHandler_s are defined. The first, mainHandler, pushes two resources to the client prior to sending its own response (NOTE: the push() calls do not block). The runtime will send the HTTP/2 PUSH_PROMISE frame to the peer and then dispatch the request back through the FilterChain for normal request/response processing.
The PushBuilder provides several APIs for generating conditional requests so that content isn’t needlessly pushed to the peer.
Care should be taken that the call to Request.newPushBuilder() will return null if HTTP/2 push has been disabled for this session.
See the org.glassfish.grizzly.http.server.http2.PushBuilder javadocs for more details on what features it provides.