Following the post about the small HTTP server using the the com.sun.net.httpserver API, I thought I’d try to make it work with WebSockets. I’ll save the suspense; it wont work. And I’m not the first to have failed at it, but it’s always more fun to search for the solution afterwards..

The problem is that the httpserver package is not designed for the persistent bi-directional connection used by the WebSocket protocol. The only part which will work is the handshake, which transmits a HTTP like request and response. However, as soon as that response is sent, the connection is closed, and thus the WebSocket object in the browser client will close.

There is a WebSocket API in Java EE, however it will require an application server like Glassfish or Tomcat to run. Another option is the SimpleFramework server, which also includes a WebSocket implementation. More about that in a later post.

The only part of the code worth mentioning here is the handshake response from the server. It sets the correct headers and encodes the server accept key according to the specification. Connecting to this server will therefore result in a valid websocket object on the client, as long as handle() method on the server does not return.

  public void handle(HttpExchange ex) throws IOException {
    Headers reqHeaders = ex.getRequestHeaders();
    reqHeaders.entrySet().forEach(System.out::println);

    String serverResponseKey = getServerResponseKey(reqHeaders.get("Sec-websocket-key").get(0));

    Headers resHeaders = ex.getResponseHeaders();
    resHeaders.add("Sec-WebSocket-Accept", serverResponseKey);
    resHeaders.add("Upgrade", "websocket");
    resHeaders.add("Connection", "Upgrade");

    ex.sendResponseHeaders(101, -1);

    // When time is up, the connection will be closed, and the browser object
    // will get a call to onClose() on the websocket object.
    sleep(5000);
  }

  private String getServerResponseKey(String clientKey) {
    try {
      MessageDigest digest = MessageDigest.getInstance("SHA-1");
      digest.update(clientKey.getBytes());
      digest.update(WEB_SOCKET_GUID.getBytes());
      byte[] sha1 = digest.digest();

      return Base64.getEncoder().encodeToString(sha1);

    } catch (NoSuchAlgorithmException e) {
      e.printStackTrace();
    }

    return null;
  }