Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to read status code from rejected WebSocket opening handshake with JavaScript?

I created a WebSocket client in JavaScript

if ("WebSocket" in window) {            
    ws = new WebSocket(url);
    ws.binaryType = "arraybuffer";      
} else if ("MozWebSocket" in window) {  
    ws = new MozWebSocket(url);
    ws.binaryType = "arraybuffer";  
}

and a WebSocket server application. For certain cases I programmed the server to reject the connection request and provide an error code.

In e.g. Firefox Console then a message is shown

Firefox can't establish a connection to the server at ws://123.123.123.123:1234/.

and it provides the status code

HTTP/1.1 403 

which is the error code that I have sent by my WebSocket server.

My question is: how can I read this status code in my JavaScript client?

ws.onerror = function(e) {
    console.log(e);     
};   
ws.onclose = function(e) {
    console.log(e); 
};

are both called, but none of the Event objects contains this error code.

like image 816
Artas Avatar asked Feb 13 '14 18:02

Artas


People also ask

How do I check my WebSocket connection status?

In the search field, enter websocket . From the search results, click WebSocket Connection Status.

How do you test a WebSocket handshake?

Click echo.websocket.org in the Name column, representing the WebSocket connection. Client the Headers tab. This tab shows the WebSocket handshake (upgrade request and response).

How does a WebSocket handshake work?

WebSocket uses a unified TCP connection and needs one party to terminate the connection. Until it happens, the connection remains active. HTTP needs to build a distinct connection for separate requests. Once the request is completed, the connection breaks automatically.


1 Answers

The spec forbids reading the HTTP status code (or anything like it) from the WebSocket object because otherwise the WebSocket object could be used to probe non-WebSocket endpoints, which would be a security issue:

User agents must not convey any failure information to scripts in a way that would allow a script to distinguish the following situations:

  • A server whose host name could not be resolved.
  • A server to which packets could not successfully be routed.
  • A server that refused the connection on the specified port.
  • A server that failed to correctly perform a TLS handshake (e.g., the server certificate can't be verified).
  • A server that did not complete the opening handshake (e.g. because it was not a WebSocket server).
  • A WebSocket server that sent a correct opening handshake, but that specified options that caused the client to drop the connection (e.g. the server specified a subprotocol that the client did not offer).
  • A WebSocket server that abruptly closed the connection after successfully completing the opening handshake.

— https://www.w3.org/TR/websockets/#feedback-from-the-protocol


There is another way to do it though!

The WebSocket protocol allows for custom close codes:

4000-4999

Status codes in the range 4000-4999 are reserved for private use and thus can't be registered. Such codes can be used by prior agreements between WebSocket applications. The interpretation of these codes is undefined by this protocol.

— https://www.rfc-editor.org/rfc/rfc6455#section-7.4.2

In your server-side logic, even when you ultimately want to reject the connection (like say the user is currently unauthenticated), do this instead:

  1. Accept the WebSocket connection
  2. Immediately close the connection with a custom close status

The client can now look at the CloseEvent.code to know why the connection was rejected.

You don't need to do this every time the server wants to reject a WebSocket connection. For example, I'd still reject the connection with a 4xx HTTP status if the request isn't a proper WebSocket request, or for security reasons (like if the anti-CSWSH Origin check fails). You only need to use the WebSocket close status for cases that you want the client-side logic to handle.

like image 145
Michael Kropat Avatar answered Oct 22 '22 12:10

Michael Kropat