1

I've noticed strange behavior in javafx.WebView version 14-ea+4 and up.

If you open https://socketio-chat-h9jt.herokuapp.com/ in javafx.WebView of any version, then there will be no problems. The site works well.

But if you install this chat (https://github.com/socketio/socket.io-client-java) locally on your PC, start the NodeJs server and open http://localhost:3000 in javafx.WebView version 14-ea+4 and above, then the page will not load and throw an 'Unknown Error' error.

If you use version 14-ea+2 and below, then there will be no error and the page will load.

If you use a proxy before loading the page then the page will open but socket.io won't work. For the proxy to work, you need to replace 'localhost' with an IPv4 address, which can be found using the 'ipconfig' command in cmd. In my case 'localhost' -> '192.168.56.1':

URI uri = URI.create("http://192.168.56.1:3000/");
if (uri.getHost() != null) System.setProperty("http.proxyHost", uri.getHost());
if (uri.getPort() != -1) System.setProperty("http.proxyPort", String.valueOf(uri.getPort()));

If webkit loggers are enabled, then com.sun.webkit.network.URLLoader will spam 99 with the error 'HTTP/1.1 header parser received no bytes'.

Why did the proxy affect the result so much and what changed in javafx.WebView version 14-ea+4 that got such problems? Why socket.io chat from the Internet opens well, but the same socket.io chat installed locally does not open?

I need WebView version 18 because I need transparency, so unfortunately I can't use a version lower than this...

socket.io index.js:

// Setup basic express server
const express = require('express');
const app = express();
const path = require('path');
const server = require('http').createServer(app);
const io = require('socket.io')(server);
const port = process.env.PORT || 3000;

server.listen(port, () => {
  console.log('Server listening at port %d', port);
});

// Routing
app.use(express.static(path.join(__dirname, 'public')));

// Chatroom

let numUsers = 0;

io.on('connection', (socket) => {
  let addedUser = false;

  // when the client emits 'new message', this listens and executes
  socket.on('new message', (data) => {
    // we tell the client to execute 'new message'
    socket.broadcast.emit('new message', {
      username: socket.username,
      message: data
    });
  });

  // when the client emits 'add user', this listens and executes
  socket.on('add user', (username) => {
    if (addedUser) return;

    // we store the username in the socket session for this client
    socket.username = username;
    ++numUsers;
    addedUser = true;
    socket.emit('login', {
      numUsers: numUsers
    });
    // echo globally (all clients) that a person has connected
    socket.broadcast.emit('user joined', {
      username: socket.username,
      numUsers: numUsers
    });
  });

  // when the client emits 'typing', we broadcast it to others
  socket.on('typing', () => {
    socket.broadcast.emit('typing', {
      username: socket.username
    });
  });

  // when the client emits 'stop typing', we broadcast it to others
  socket.on('stop typing', () => {
    socket.broadcast.emit('stop typing', {
      username: socket.username
    });
  });

  // when the user disconnects.. perform this
  socket.on('disconnect', () => {
    if (addedUser) {
      --numUsers;

      // echo globally that this client has left
      socket.broadcast.emit('user left', {
        username: socket.username,
        numUsers: numUsers
      });
    }
  });
});

Example simple webview app Main.java:

WebView wv = new WebView();

@Override
    public void start(Stage stage) {
        String url = "http://localhost:3000";

        // use proxy
        //String url = "http://192.168.56.1:3000"; // IPv4:3000
        //URI uri = URI.create(url);
        //if (uri.getHost() != null) System.setProperty("http.proxyHost", uri.getHost());
        //if (uri.getPort() != -1) System.setProperty("http.proxyPort", String.valueOf(uri.getPort()));

        wv.getEngine().load(url);
        scene = new Scene(wv, 750, 800);
        stage.setScene(scene);
        stage.show();
    }
Dmitriy
  • 375
  • 1
  • 18
  • The webview http client implementation was [changed in JavaFX 14](https://bugs.openjdk.org/browse/JDK-8211308). There may be an undocumented, unsupported system property to switch webview back to the prior http implementation in some later JavaFX versions. – jewelsea Oct 28 '22 at 20:56
  • 1
    Here is the [context switch which may be used to switch the HTTP implementation used by JavaFX](https://github.com/openjdk/jfx/pull/14/files#diff-593f23fc8227e40ac4ddaf39568aaa3a3abc8204373f9a64cfe07336074bf761R99): System property: `com.sun.webkit.useHTTP2Loader`, if true and running on a compatible JDK, it will use the java.net.http client from JavaFX 11+, otherwise it will use the `URLConnection` class which has always been in the JDK. – jewelsea Oct 28 '22 at 21:31
  • @jewelsea Thanks for the answer, most likely this is the right solution, since it helped another person. I can't replicate my success. Adding a parameter does not solve the problem while trying to figure out why... Using maven, I add "-Dcom.sun.webkit.useHTTP2Loader=false" parameter to the maven application launch configuration in the 'VM options' field in the 'Java Options' section. Is everything right? – Dmitriy Oct 28 '22 at 22:37
  • Run it from the command line, e.g. `java -Dcom.sun.webkit.useHTTP2Loader=false /.Main`. I do not know if it would actually address your problem or not. You can [provide other system properties to the log java net HTTP client calls](https://stackoverflow.com/questions/53215038/how-to-log-request-response-using-java-net-http-httpclient). If useHTTP2Loader is switched off, then you shouldn't see the java net HTTP client calls being generated for the WebView calls. – jewelsea Oct 28 '22 at 22:43
  • @jewelsea I didn't understand how to use *java -Dcom.sun.webkit.useHTTP2Loader=false /.Main* but I tried *System.setProperty('com.sun.webkit.useHTTP2Loader', 'false')* and after that, instead of an _'Unknown Error'_ error, it threw a _'Connection refused'_ error. This is already a success. I tried to open my site and... It opened and the sockets worked! You can write a response and complete it with *System.setProperty('com.sun.webkit.useHTTP2Loader'*, 'false'); to make it the best. – Dmitriy Oct 28 '22 at 23:53

0 Answers0