JDK-8242077 : Add information about HTTP/2 and HttpClient usage in WebEngine
  • Type: Bug
  • Component: javafx
  • Sub-Component: web
  • Affected Version: openjfx14
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • Submitted: 2020-04-03
  • Updated: 2021-06-29
  • Resolved: 2020-04-28
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
Other
openjfx15Fixed
Related Reports
Duplicate :  
Relates :  
Description
Using Java 14 (OpenJDK download), older versions of the JavaFX SDK (e.g. JavaFX 12) were capable of loading web pages with expired certificates. With Java 14 and JavaFX 14, an error is printed and the webpage is not shown.

However, with Java 11.0.2 and JavaFX 14, no error is printed and the page with the expired certificate is shown.

There is currently no clear and consistent documentation about how WebView should handle sites with expired certificates.

Might be related to JDK-8221097 and JDK-8211308. 

Sample
=====

import javafx.application.Application;
import javafx.concurrent.Worker;
import javafx.scene.Scene;
import javafx.scene.layout.VBox;
import javafx.scene.web.WebView;
import javafx.stage.Stage;

import javax.net.ssl.*;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.X509Certificate;

public class Html5Webview extends Application {

    public void start(Stage primaryStage) {
        HttpsURLConnection.setDefaultSSLSocketFactory(TrustAllSSLProvider.getSslSocketFactory());
        HttpsURLConnection.setDefaultHostnameVerifier(TrustAllSSLProvider.getHostNameVerifier());

        primaryStage.setTitle("JavaFX WebView Html5 Support");

        WebView webView = new WebView();
        webView.getEngine().getLoadWorker().stateProperty().addListener((o, ov, nv) -> {
            if (nv == Worker.State.FAILED) {
                System.out.println(webView.getEngine().getLoadWorker().getMessage());
                webView.getEngine().getLoadWorker().getException().printStackTrace();
            }
        });
        webView.getEngine().load("https://188.166.109.46");

        VBox vBox = new VBox(webView);
        Scene scene = new Scene(vBox);

        primaryStage.setScene(scene);
        primaryStage.show();
    }

    public static class TrustAllSSLProvider {

        // Verify-all name verifier
        private final static HostnameVerifier hostNameVerifier = (hostname, session) -> true;

        // Trust-all socket factory
        private static final SSLSocketFactory sslSocketFactory;
        static {
            TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
                public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                    return null;
                }
                public void checkClientTrusted(X509Certificate[] certs, String authType) {
                }
                public void checkServerTrusted(X509Certificate[] certs, String authType) {
                }
            }};
            SSLContext sc;
            try {
                sc = SSLContext.getInstance("TLS");
            } catch (NoSuchAlgorithmException e) {
                throw new IllegalStateException(e);
            }
            try {
                sc.init(null, trustAllCerts, new java.security.SecureRandom());
            } catch (KeyManagementException e) {
                throw new IllegalStateException(e);
            }
            sslSocketFactory = sc.getSocketFactory();
        }

        public static HostnameVerifier getHostNameVerifier() {
            return hostNameVerifier;
        }

        public static SSLSocketFactory getSslSocketFactory() {
            return sslSocketFactory;
        }
    }

    public static void main(String[] args) {
        // System.setProperty("javax.net.debug", "ssl");
        launch(args);
    }
}

Error (in case there is one):

ome/bin/java -p /opt/javafx-sdk-14/lib  --add-modules javafx.web Html5Webview
Loading failed
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)

Comments
For information, I was able to work-around the issue by adding SSLContext.setDefault(sc); where "sc" is the SSLContext created with the TrustManager.
29-06-2021

Changeset: e30049f0 Author: Abhinay Agarwal <abhinay.agarwal@gluonhq.com> Committer: Kevin Rushforth <kcr@openjdk.org> Date: 2020-04-28 16:42:31 +0000 URL: https://git.openjdk.java.net/jfx/commit/e30049f0
28-04-2020

Option 1 would indeed provide backward behavioural compatibility, but I feel it hides potential security issues. With option 2, we indeed provide similar functionality to what browsers are doing, so +1 on that, but it could bring us in a less clear situation if different browsers are going to behave different in the future. Another option would be to leave the code as is, but to document the change in behavior (which actually makes sense to me(.
15-04-2020

With HTTP/2 "java.lang.Throwable: SSL handshake failed" is thrown and webpage is not loaded where as using non HTTP/2 loader the webpage is loaded. There are two solution i could think of now. 1. Suppress the SSL handshake exception (to behave similar to earlier implementation) or 2. Display "Insecure page ..." like many browser loads a intermediary web content with user consent to proceed (load) further.
15-04-2020

Yes, this does appear to be a behavior change with HTTP/2, which went into JavaFX 14 and is enabled by default if the JDK that you are running on is >= 12 (it doesn't matter what JavaFX is compiled with so JDK-8221097 is not related). The following will disable HTTP/2: java -Dcom.sun.webkit.useHTTP2Loader=false
03-04-2020