3

Can anyone tell me how I can continue to display web pages using a self-signed https certificate in WebView after updating to JavaFX 14?

Prior to JavaFX 14 we have been handling this by implementing a custom TrustHandler and HostnameVerifier using HttpsURLConnection.setDefaultSSLSocketFactory and HttpsURLConnection.setDefaultHostnameVerifier.

When I switch to JavaFX 14 and WebView tries to load the self-signed web pages

  • they do not load,
  • the custom TrustHandler code is no longer called, and
  • I get this back from webView.getEngine().getLoadWorker().getException():
      java.lang.Throwable: SSL handshake failed  
       at javafx.web/javafx.scene.web.WebEngine$LoadWorker.describeError(WebEngine.java:1431)  
       at javafx.web/javafx.scene.web.WebEngine$LoadWorker.dispatchLoadEvent(WebEngine.java:1370)  
       at javafx.web/javafx.scene.web.WebEngine$PageLoadListener.dispatchLoadEvent(WebEngine.java:1231)  
       at javafx.web/com.sun.webkit.WebPage.fireLoadEvent(WebPage.java:2514)  
       at javafx.web/com.sun.webkit.WebPage.fwkFireLoadEvent(WebPage.java:2359)  
       at javafx.web/com.sun.webkit.network.URLLoaderBase.twkDidFail(Native Method)  
       at javafx.web/com.sun.webkit.network.HTTP2Loader.notifyDidFail(HTTP2Loader.java:624)  
       at javafx.web/com.sun.webkit.network.HTTP2Loader.lambda$didFail$18(HTTP2Loader.java:606)  
       at javafx.web/com.sun.webkit.network.HTTP2Loader.lambda$callBackIfNotCanceled$10(HTTP2Loader.java:437)  
       at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$10(PlatformImpl.java:428)  
       at java.base/java.security.AccessController.doPrivileged(AccessController.java:391)  
       at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$11(PlatformImpl.java:427)  
       at javafx.graphics/com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96)  
       at javafx.graphics/com.sun.glass.ui.win.WinApplication._runLoop(Native Method)  
       at javafx.graphics/com.sun.glass.ui.win.WinApplication.lambda$runLoop$3(WinApplication.java:174)  
       at java.base/java.lang.Thread.run(Thread.java:830) 
    

I have no problem with JavaFX 13.0.2, but it fails with 14 or 14.0.1.  Curiously there is also no problem even with JavaFX 14 if I run against OpenJDK up to 11.0.2, but the problem occurs from 12 up to 15ea20.

From looking through the release notes for both JavaFX and the JDK, the only likely cause looks to me to be JDK-8211308 - Support HTTP/2 in WebView.  This implies moving away from using JDK's URLConnection class and I'm guessing that this could cause it to then no longer use my custom TrustHandler.

If I'm correct, then I need to know how to continue to use my custom TrustHandler for connections initiated below WebView, but I can't see how to do that from the API in java.net.http.

Alternately the enhancement description mentions:

a Runtime property will be provided to fallback to legacy HTTP API

but I can find no other mention of this - how do I use this fallback?  Or is there some alternate way to get the WebView to allow the self-signed certificates?  Or am I wrong about what has changed with JavaFX 14 and there is some other solution?

  • If you are deploying your app as jlinked module, it is necessary to require the needed crypto modules. See [Modular Java 13 / JavaFx WebWiew fails to display when jlinked](https://stackoverflow.com/a/60092805/1155209), which recommends the following requirement: `requires jdk.crypto.cryptoki;`. – jewelsea Jun 28 '23 at 22:02

3 Answers3

5

I found that -Dcom.sun.webkit.useHTTP2Loader=false disables HTTP2 support, and fixes the issue.

wlcrs
  • 350
  • 3
  • 10
  • The `com.sun` properties are internal implementations, not part of the public API. Support for them could be dropped in future releases without warning. – jewelsea Jun 29 '23 at 23:03
1

If you want to make -Dcom.sun.webkit.useHTTP2Loader=false, you can make it also easily runtime like this:

static {
            System.setProperty("com.sun.webkit.useHTTP2Loader", "false");
       }
Denkov
  • 11
  • 1
0

Your assumption on the switch-to-HTTP2 being (part of) the problem, is correct.

TL;DR

  • newer JavaFX use HTTP2Loader by default, which ignores HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory()).
    Instead/additionally do SSLContext.setDefault(yourSslContext).
  • the "runtime property to fallback to legacy HTTP API" is -Dcom.sun.webkit.useHTTP2Loader={true,false}

Related JDK bugs:

relevant sections in JavaFX code

I've just spent multiple hours stepping through WebEngine.load(..) in a Debugger.
The JavaFX version I am working on is org.openjfx 17.0.2 from Maven.
I'm documenting my results to help travelers from the future.

  • WebEngine.open(..) delegates to WebPage.open which does its loading in
    com.sun.webkit.network.NetworkContext#fwkLoad(..)
  • NetworkContext has a flag useHTTP2Loader
    • defaults to true on System.getProperty("java.version") >= 12
    • overridden via VM-option -Dcom.sun.webkit.useHTTP2Loader={true,false}
  • com.sun.webkit.network.HTTP2Loader has a private final static HTTP_CLIENT created by a jdk.internal.net.http.HttpClientBuilderImpl.
    • this builder could receive an SSLContext, but the HTTP2Loader implementation doesn't provide one, so it falls back to SSLContext.getDefault() -> SSLContext.getInstance("Default") -> private static volatile SSLContext defaultContext
    • HttpsUrlConnection is never touched/queried by the HTTP2Loader
    • thus, the HTTP2Loader, and thus JavaFX WebEngine, always uses the global default SSLContext
  • the oft-copy-pasted // Create a trust manager that does not validate certificate chains-snippet sets
    HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory())
    • as mentioned in JDK-8242077, the only way to configure HTTP2Loader is to override the global default SSLContext:
      SSLContext.setDefault( <your-context-with-alltrusting-TrustManager> );