Payara Platform 5 Community Edition Supports HTTP/2 on All JDK Versions
Originally published on 24 Jul 2020
Last updated on 14 Sep 2020
Payara Platform 5 brought with it an implementation of Servlet 4.0, which itself contains support for the HTTP/2 standard. HTTP/2 support in Java has been fairly obscure for JDK 8 users, causing issues for many depending on their JDK minor version. This blog hopes to clarify the state of HTTP/2 in Payara Platform 5.
If you just want a quick answer to which Payara versions support HTTP/2 on which JDK version, jump ahead to Does Payara Server Support HTTP/2?
What is HTTP/2?
HTTP/2 is an update on HTTP 1.1 that aims to address its shortfalls caused by the evolution of modern websites. Some of the main features of HTTP/2 include:
- HTTP/2 is a binary protocol, which makes data transfer more efficient than plain text.
- Resource prioritisation, which allows the server to prioritise which requests to fulfill first.
- Multiple requests can be multiplexed over a single connection, allowing them to be served concurrently.
- The big one - server push. This allows resources to be pushed to the client before they are requested. So rather than an HTML page and associated CSS file taking 2 request round trips to be fetched, it takes 1.
You can see the performance difference demonstrated in the Akamai HTTP/2 Demo.
Does Payara Server Support HTTP/2?
Payara Community Edition 5.2020.3 supports HTTP/2 on all JDK versions. Support for HTTP/2 on all JDK versions will be added to Payara Enterprise Edition upon maturity (and we're sure it is stable enough for our Enterprise Edition!)
There is one notable caveat to this however: Zulu JDK versions between 8u222 and 8u242 will still not work out of the box with HTTP/2. This is because these versions use the -XX:+OpenJSSE JVM flag, which overwrites the JDK SSL classes in order to enable TLS 1.3 support. This will overwrite the Grizzly versions of the SSL classes, which in turn disables HTTP/2 support. This means you can work around this either by removing the -XX:+OpenJSSE Flag, or by upgrading your JDK version.
All Payara Server versions before Community 5.2020.3 or Enterprise 5.21.0 support any JDK version without ALPN support. What this means will be explained in the section titled Does Java Include Native Support for HTTP/2?.
Is HTTP/2 Enabled Out-of-the-box?
All Payara Server 5 versions before 5.183 have both HTTP/2 and HTTP/2 server push enabled by default.
NOTE: Although HTTP/2 isn't strictly prohibited without SSL, at the time of writing this blog no major browsers support HTTP/2 on an insecure connection.
Since 5.183, server push is disabled by default. This is because server push was causing some issues. Although a lot of these issues have been fixed, it is still disabled by default until the HTTP/2 push experience has been smoothed out. You can still manually enable this feature in Payara Server to try it out in your own environment. Server push can be enabled through either the admin console or the asadmin utility.
Asadmin Utility
asadmin> set configs.config.server-config.network-config.protocols.protocol.http-listener-2.http.http2-push-enabled=true
Admin Console
Does Java Include Native Support for HTTP/2?
In short: kind of. JDK 9 includes full HTTP/2 support, but this isn't particularly helpful to JDK 8 users.
JDK 9 includes JEP 110 which describes an HTTP/2 compatible client to replace the legacy HttpURLConnection API. This means that native HTTP/2 client support is only available in JDK 9 or above. This also means that in JDK 8, the only way to get an HTTP/2 compatible client is through an external library (such as the Grizzly Client).
JDK 9 also includes JEP 244 which describes TLS Application-Layer Protocol Negotiation Extension (ALPN), which is essential to all HTTP/2 support in Java whether natively or through a library. This is because HTTP/2 is only supported on major browsers over a secure TLS connection and HTTP/2 requires a protocol negotiation during the TLS handshake, which the javax.net.ssl packages didn't support before JEP 244.
To further complicate things, JDK 8u251 included a backport of these ALPN APIs. This means that for the purposes of libraries providing HTTP/2 support such as Grizzly (as used by the Payara Platform) JDK 8u251 needs treating just like JDK 9 and above.
How Does Payara Server Support HTTP/2 Without Native JDK Support?
Since JEP 244 (ALPN) isn't present in JDK 8 versions below 8u251, Payara Server 5 needed to find a way to support HTTP/2 in older JDK versions. Fortunately Grizzly produced an ALPN JAR (from now on referred to as Grizzly NPN Bootstrap) which, when placed on the Java boot classpath would forcefully replace the JDK SSL classes used in ALPN negotiation. While this sounds great at a glance, any time the internal JDK classes change, it risks breaking the replacement JAR. Because of this, the inclusion of each new ALPN JAR would completely replace the list of JDK 8 update versions that would work with HTTP/2.
Payara Server utilises the fact that the start command runs a separate Java process with a customised list of JVM options as well as versioned JVM options to provide a different ALPN JAR depending on the running JDK update version. This means that for any given release, Payara Server can now work for every JDK 8 update version available at that time. The inevitable problem with this however, is that any new JDK update may require a new ALPN JAR to be added to the runtime options.
Since Payara Community Edition 5.2020.3 and Enterprise Edition 5.21.0, Grizzly has been updated to make use of the native ALPN APIs if they're found, which means that HTTP/2 support should continue to work in all future Java versions.
Does This Mean I Can Patch My Payara Server Installation to Support Later JDKs?
Yes! Each JDK 8 update version should have a corresponding Grizzly NPN Bootstrap JAR version that can be used to allow HTTP/2 to work seamlessly with that JDK version. In Payara Server 5.184 the mappings from JDK version to NPN bootstrap version are as follows:
Minimum JDK Version | Maximum JDK Version | Grizzly NPN Bootstrap Version |
N/A | 1.8u120 | 1.6 |
1.8u121 | 1.8u160 | 1.7 |
1.8u161 | 1.8u190 | 1.8 |
1.8u191 | N/A | 1.8.1 |
NOTE: the JDK selection can only check the JDK version, and not the build number. Be aware that issues may still arise if a backport of an API change has been made to a subsequent build of a JDK version. For example, specific builds of 1.8u182 will require NPN Bootstrap JAR 1.8.1, despite this chart saying otherwise.
These NPN version mappings are specified in the domain.xml, and may be updated with additional versions:
<jvm-options>[1.8.0|1.8.0u120]-Xbootclasspath/p:${com.sun.aas.installRoot}/lib/grizzly-npn-bootstrap-1.6.jar</jvm-options>
<jvm-options>[1.8.0u121|1.8.0u160]-Xbootclasspath/p:${com.sun.aas.installRoot}/lib/grizzly-npn-bootstrap-1.7.jar</jvm-options>
<jvm-options>[1.8.0u161|1.8.0u190]-Xbootclasspath/p:${com.sun.aas.installRoot}/lib/grizzly-npn-bootstrap-1.8.jar</jvm-options>
<jvm-options>[1.8.0u191|1.8.0u500]-Xbootclasspath/p:${com.sun.aas.installRoot}/lib/grizzly-npn-bootstrap-1.8.1.jar</jvm-options>
So if for example you found that JDK 1.8u200 breaks with NPN bootstrap version 1.8.1 and you see a more recent NPN bootstrap JAR, you could download a more recent JAR and add an additional domain.xml entry, for example:
<jvm-options>[1.8.0|1.8.0u120]-Xbootclasspath/p:${com.sun.aas.installRoot}/lib/grizzly-npn-bootstrap-1.6.jar</jvm-options>
<jvm-options>[1.8.0u121|1.8.0u160]-Xbootclasspath/p:${com.sun.aas.installRoot}/lib/grizzly-npn-bootstrap-1.7.jar</jvm-options>
<jvm-options>[1.8.0u161|1.8.0u190]-Xbootclasspath/p:${com.sun.aas.installRoot}/lib/grizzly-npn-bootstrap-1.8.jar</jvm-options>
<jvm-options>[1.8.0u191|1.8.0u200]-Xbootclasspath/p:${com.sun.aas.installRoot}/lib/grizzly-npn-bootstrap-1.8.1.jar</jvm-options>
<jvm-options>[1.8.0u201|1.8.0u500]-Xbootclasspath/p:${com.sun.aas.installRoot}/lib/grizzly-npn-bootstrap-new-version.jar</jvm-options>
How Can I Tell if the ALPN JAR Version is Incorrect?
When the ALPN JAR version is incorrect and you make requests to the server, you often may find errors in the server logs such as the following:
[2018-08-19T19:07:07.724+0000] [] [WARNING] [] [org.glassfish.grizzly.filterchain.DefaultFilterChain] [tid: _ThreadID=48 _ThreadName=http-thread-pool::https-listener(1)] [timeMillis: 1534705627724] [levelValue: 900] [[
GRIZZLY0013: Exception during FilterChain execution
java.lang.NoClassDefFoundError: sun/security/ssl/EllipticCurvesExtension
at sun.security.ssl.Handshaker.getActiveProtocols(Handshaker.java:793)
at sun.security.ssl.Handshaker.activate(Handshaker.java:549)
at sun.security.ssl.SSLEngineImpl.kickstartHandshake(SSLEngineImpl.java:744)
at sun.security.ssl.SSLEngineImpl.beginHandshake(SSLEngineImpl.java:771)
...
at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.run(AbstractThreadPool.java:549)
at java.lang.Thread.run(Thread.java:748)
]]
[2018-10-17T15:20:32.654+0200] [Payara 5.183] [WARNING] [] [org.glassfish.grizzly.filterchain.DefaultFilterChain] [tid: _ThreadID=94 _ThreadName=http-thread-pool::http-listener-2(1)] [timeMillis: 1539782432654] [levelValue: 900] [[
GRIZZLY0013: Exception during FilterChain execution
java.lang.NoSuchMethodError: sun.security.ssl.SSLSessionImpl.<init>(Lsun/security/ssl/ProtocolVersion;Lsun/security/ssl/CipherSuite;Ljava/util/Collection;Ljava/security/SecureRandom;Ljava/lang/String;IZ)V
at sun.security.ssl.ServerHandshaker.clientHello(ServerHandshaker.java:862)
at sun.security.ssl.ServerHandshaker.processMessage(ServerHandshaker.java:245)
at sun.security.ssl.Handshaker.processLoop(Handshaker.java:1077)
at sun.security.ssl.Handshaker$1.run(Handshaker.java:1017)
...
at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.run(AbstractThreadPool.java:549)
at java.lang.Thread.run(Thread.java:748)
]]
When you see errors like these, it likely means the wrong version of the ALPN JAR has been used. Try out the nearest Grizzly NPN Bootstrap JAR versions to find the one that fits your JDK distribution.
Conclusion
HTTP/2 support in Java 8 is complicated, and the solution provided by Payara makes the best of a bad situation. After JDK versions 8u252 or JDK 9, HTTP/2 should now work on the Community Edition with fewer caveats or issues than before, so upgrade for the latest compatibility. Later, once deemed stable, we will add support for HTTP/2 to our Payara Enterprise Edition.
Related Posts
The Payara Monthly Catch - November 2024
Published on 28 Nov 2024
by Chiara Civardi
0 Comments
The Payara Monthly Catch - October 2024
Published on 30 Oct 2024
by Chiara Civardi
0 Comments