TooTallNate / Java-WebSocket

A barebones WebSocket client and server implementation written in 100% Java.
http://tootallnate.github.io/Java-WebSocket
MIT License
10.48k stars 2.58k forks source link

Support for 401 Status Code in HTTP Response for WebSocket Handshake #1423

Open jjm159 opened 3 months ago

jjm159 commented 3 months ago

Hello,

Currently, I am developing an electric vehicle charging control program, using the Java-WebSocket library to connect with chargers. This program is called CSMS. The OCA organization has created a protocol called OCPP (Open Charge Point Protocol) for communication between CSMS and chargers. OCA provides certification tests to ensure how well CSMS complies with OCPP.

During these certification tests, an issue has arisen with the Java-WebSocket library. In a test case where the charger attempts to connect via WebSocket and the username and password provided in the HTTP headers are not verified by the CSMS, the HTTP response must include a "401" status in the status line.

Currently, the Java-WebSocket library does not allow including a 401 status in the status line of the response. Even if an error with status code and message is thrown in onWebsocketHandshakeReceivedAsServer, the HTTP response status line is handled as 404 instead.

private void closeConnectionDueToWrongHandshake(InvalidDataException exception) {
  write(generateHttpResponseDueToError(404));
  flushAndClose(exception.getCloseCode(), exception.getMessage(), false);
}
private ByteBuffer generateHttpResponseDueToError(int errorCode) {
    String errorCodeDescription;
    switch (errorCode) {
      case 404:
        errorCodeDescription = "404 WebSocket Upgrade Failure";
        break;
      case 500:
      default:
        errorCodeDescription = "500 Internal Server Error";
    }
    return ByteBuffer.wrap(Charsetfunctions.asciiBytes("HTTP/1.1 " + errorCodeDescription
        + "\\r\\nContent-Type: text/html\\r\\nServer: TooTallNate Java-WebSocket\\r\\nContent-Length: "
        + (48 + errorCodeDescription.length()) + "\\r\\n\\r\\n<html><head></head><body><h1>"
        + errorCodeDescription + "</h1></body></html>"));
  }

Regarding this issue, I have reviewed previous issues #977 and #1278 but could not find a clear reason why a 401 error should not be included in the HTTP response status line.

RFC6455 states that during the Opening Handshake, the server can perform additional client authentication and include a 401 status code in the HTTP response in case of authentication failure. Please refer to the link.

Therefore, I believe the server should be able to include a 401 status in the HTTP response upon authentication failure when performing client authentication in onWebsocketHandshakeReceivedAsServer.

I propose the following solution, and would appreciate any better suggestions:

private void closeConnectionDueToWrongHandshake(InvalidDataException exception) {
  int closeCode = exception.getCloseCode();
  String message = exception.getMessage();
  write(generateHttpResponseDueToError(closeCode, message));
  flushAndClose(closeCode, message, false);
}

private void closeConnectionDueToInternalServerError(RuntimeException exception) {
  String message = exception.getMessage();
  write(generateHttpResponseDueToError(500, message));
  flushAndClose(CloseFrame.NEVER_CONNECTED, message, false);
}

private ByteBuffer generateHttpResponseDueToError(int errorCode, String errorMessage) {
  String errorCodeDescription;
  switch (errorCode) {
    case 500:
      if (errorMessage == null || errorMessage.isEmpty()) {
        errorCodeDescription = "500 Internal Server Error";
      } else {
        errorCodeDescription = String.format("500 %s", errorMessage);
      }
      break;
    default:
      if (errorMessage == null || errorMessage.isEmpty()) {
        errorCodeDescription = String.format("%d WebSocket Upgrade Failure", errorCode);
      } else {
        errorCodeDescription = String.format("%d %s", errorCode, errorMessage);
      }
  }
  return ByteBuffer.wrap(Charsetfunctions.asciiBytes("HTTP/1.1 " + errorCodeDescription
      + "\r\nContent-Type: text/html\r\nServer: TooTallNate Java-WebSocket\r\nContent-Length: "
      + (48 + errorCodeDescription.length()) + "\r\n\r\n<html><head></head><body><h1>"
      + errorCodeDescription + "</h1></body></html>"));
}

Currently, Java-OCA-OCPP uses the Java-WebSocket library for OCPP certification. If the 401 status code is not included in the HTTP response of the opening handshake, many Java developers taking the OCPP certification test will need to make extensive code modifications. I hope my request will be considered. Thank you.

sungbeenkim commented 3 months ago

I'm experiencing the same problem