Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

nodejs + WebSockets - reject the connection with a message

I want to provide a meaningful error to the client when too many users are connected or when they're connecting from an unsupported domain, so...

I wrote some WebSocket server code:

var http = require('http');
var httpServer = http.createServer(function (request, response)
{
    // i see this if i hit http://localhost:8001/
    response.end('go away');
});

httpServer.listen(8001);

// https://github.com/Worlize/WebSocket-Node/wiki/Documentation
var webSocket = require('websocket');
var webSocketServer = new webSocket.server({ 'httpServer': httpServer });

webSocketServer.on('request', function (request)
{
    var connection = request.reject(102, 'gtfo'); 
});

And some WebSocket client code:

var connection = new WebSocket('ws://127.0.0.1:8001');
connection.onopen = function (openEvent)
{
    alert('onopen');
    console.log(openEvent);
};
connection.onclose = function (closeEvent)
{
    alert('onclose');
    console.log(closeEvent);
}
connection.onerror = function (errorEvent)
{
    alert('onerror');
    console.log(errorEvent);
};
connection.onmessage = function (messageEvent)
{
    alert('onmessage');
    console.log(messageEvent);
};

All I get is alert('onclose'); with a CloseEvent object logged to the console without any status code or message that I can find. When I connect via ws://localhost:8001 the httpServer callback doesn't come into play, so I can't catch it there. The RFC suggests I should be able to send any status code other than 101 when there's a problem, but Chrome throws an error in the console Unexpected response code: 102. If I call request.reject(101, 'gtfo'), implying it was successful I get a handshake error, as I'd expect.

Not really sure what else I can do. Is it just not possible right now to get the server response in Chrome's WebSocket implementation?

ETA: Here's a really nasty hack in the mean time, I hope that's not what I have to end up doing.

var connection = request.accept(null, request.origin);
connection.sendUTF('gtfo');
connection.close();
like image 549
Langdon Avatar asked May 12 '12 02:05

Langdon


1 Answers

I'm the author of WebSocket-Node and I've also posted this response to the corresponding issue on GitHub: https://github.com/Worlize/WebSocket-Node/issues/46

Unfortunately, the WebSocket protocol does not provide any specific mechanism for providing a close code or reason at this stage when rejecting a client connection. The rejection is in the form of an HTTP response with an HTTP status of something like 40x or 50x. The spec allows for this but does not define a specific way that the client should attempt to divine any specific error messaging from such a response.

In reality, connections should be rejected at this stage only when you are rejecting a user from a disallowed origin (i.e. someone from another website is trying to connect users to your websocket server without permission) or when a user otherwise does not have permission to connect (i.e. they are not logged in). The latter case should be handled by other code on your site: a user should not be able to attempt to connect the websocket connection if they are not logged in.

The code and reason that WebSocket-Node allow you to specify here are an HTTP Status code (e.g. 404, 500, etc.) and a reason to include as a non-standard "X-WebSocket-Reject-Reason" HTTP header in the response. It is mostly useful when analyzing the connection with a packet sniffer, such as WireShark. No browser has any facility for providing rejection codes or reasons to the client-side JavaScript code when a connection is rejected in this way, because it's not provided for in the WebSocket specification.

like image 146
Brian McKelvey Avatar answered Oct 17 '22 23:10

Brian McKelvey