Bug 62053

Summary: NullPointerException in Http2AsyncUpgradeHandler with Server Push
Product: Tomcat 9 Reporter: Holger Sunke <holger.sunke>
Component: ConnectorsAssignee: Tomcat Developers Mailing List <dev>
Status: RESOLVED FIXED    
Severity: normal    
Priority: P2    
Version: 9.0.4   
Target Milestone: -----   
Hardware: PC   
OS: All   

Description Holger Sunke 2018-01-29 12:00:05 UTC
Hello,

I try to get a JSF (Mojarra 2.3.3) application working with Server Push and keep getting a NPE when using HTTP/2.
Tested with JDK8 + OpenSSL and JDK9 + JSSE.
Application in question is Primefaces 6.1 Showcase, modified to use Servlet 4 and Mojarra 2.3.3.

The Exception Stacktrace:

java.lang.NullPointerException
	at org.apache.coyote.http2.Http2AsyncUpgradeHandler$AsyncHeaderFrameBuffers.access$200(Http2AsyncUpgradeHandler.java:425)
	at org.apache.coyote.http2.Http2AsyncUpgradeHandler.writeHeaders(Http2AsyncUpgradeHandler.java:158)
	at org.apache.coyote.http2.Http2UpgradeHandler.push(Http2UpgradeHandler.java:1120)
	at org.apache.coyote.http2.Stream.push(Stream.java:672)
	at org.apache.coyote.http2.Stream.push(Stream.java:642)
	at org.apache.coyote.http2.StreamProcessor.doPush(StreamProcessor.java:280)
	at org.apache.coyote.AbstractProcessor.action(AbstractProcessor.java:490)
	at org.apache.coyote.Request.action(Request.java:432)
	at org.apache.catalina.core.ApplicationPushBuilder.push(ApplicationPushBuilder.java:370)
	at com.sun.faces.context.ExternalContextImpl.pushIfPossibleAndNecessary(ExternalContextImpl.java:704)
	at com.sun.faces.context.ExternalContextImpl.encodeResourceURL(ExternalContextImpl.java:662)
	at javax.faces.context.ExternalContextWrapper.encodeResourceURL(ExternalContextWrapper.java:164)
	at com.sun.faces.renderkit.html_basic.ScriptStyleBaseRenderer.encodeEnd(ScriptStyleBaseRenderer.java:246)
	at javax.faces.component.UIComponentBase.encodeEnd(UIComponentBase.java:949)
	at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1912)
	at org.primefaces.renderkit.HeadRenderer.encodeBegin(HeadRenderer.java:97)
	at javax.faces.component.UIComponentBase.encodeBegin(UIComponentBase.java:892)
	at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1903)
	at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1908)
	at com.sun.faces.application.view.FaceletViewHandlingStrategy.renderView(FaceletViewHandlingStrategy.java:491)
	at com.sun.faces.application.view.MultiViewHandler.renderView(MultiViewHandler.java:194)
	at javax.faces.application.ViewHandlerWrapper.renderView(ViewHandlerWrapper.java:151)
	at javax.faces.application.ViewHandlerWrapper.renderView(ViewHandlerWrapper.java:151)
	at com.sun.faces.lifecycle.RenderResponsePhase.execute(RenderResponsePhase.java:126)
	at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:100)
	at com.sun.faces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:223)
	at javax.faces.webapp.FacesServlet.service(FacesServlet.java:671)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.primefaces.webapp.filter.FileUploadFilter.doFilter(FileUploadFilter.java:100)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.primefaces.showcase.filter.CharacterEncodingFilter.doFilter(CharacterEncodingFilter.java:32)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:199)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:81)
	at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:651)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342)
	at org.apache.coyote.http2.StreamProcessor.service(StreamProcessor.java:324)
	at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
	at org.apache.coyote.http2.StreamProcessor.process(StreamProcessor.java:72)
	at org.apache.coyote.http2.StreamRunnable.run(StreamRunnable.java:35)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
	at java.base/java.lang.Thread.run(Unknown Source)
Comment 1 Remy Maucherat 2018-01-29 12:39:54 UTC
The exception is too odd to be able to make something out of it at the moment. Since you're using NIO2, you can try NIO instead.
Comment 2 Holger Sunke 2018-02-01 11:02:43 UTC
It seemes to be triggered by a flaw in web application layer. Google Chrome keeps closing the SSL connection due to Server Push protocol violations.

https://github.com/javaserverfaces/mojarra/issues/4329


Nevertheless I'd suggest to add a [null] check at Http2AsyncUpgradeHandler.java:158 as return value of org.apache.coyote.http2.Http2UpgradeHandler.doWriteHeaders(Stream, int, MimeHeaders, boolean, int) is obviously @Nullable:

 protected HeaderFrameBuffers doWriteHeaders(Stream stream, int pushedStreamId, MimeHeaders mimeHeaders,
            boolean endOfStream, int payloadSize) throws IOException {
...
  if (!stream.canWrite()) {
            return null;
  }
...
}

This turns the NullPointerException into a more expressive one:

org.apache.catalina.connector.ClientAbortException: org.apache.coyote.CloseNowException: Connection [1], Stream [10], This stream is not writable
Caused by: org.apache.coyote.CloseNowException: Connection [1], Stream [10], This stream is not writable

Tahnks for quick response and kind regards
Comment 3 Remy Maucherat 2018-02-01 11:20:00 UTC
Thanks a lot for the testing and the fix proposal, this actually looked like a possibly complex problem, so I guess it was almost normal besides the scary stack.
This NPE was added as part of a recent refactoring, and NIO was not affected as it did not use the return value.
The null check fix will be in 9.0.5.