Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chrome 16 kills the example server #32

Closed
timglabisch opened this issue Jan 30, 2012 · 30 comments
Closed

chrome 16 kills the example server #32

timglabisch opened this issue Jan 30, 2012 · 30 comments

Comments

@timglabisch
Copy link

if i run in the chrome console:

websocket = new WebSocket('ws://****.l:8081/echo-protocol');
WebSocket
Unexpected response code: 500

the server just crashes with this exception:

Wed Jan 25 2012 22:12:42 GMT-0800 (PST) Server is listening on port 8080

/home/dev/.node_libraries/.npm/websocket/1.0.4/package/lib/WebSocketRequest.js:240
throw new Error("Specified protocol was not requested by the clien
^
Error: Specified protocol was not requested by the client.
at WebSocketRequest.accept (/home/dev/.node_libraries/.npm/websocket/1.0.4/package/lib/WebSocketRequest.js:240:19)
at WebSocketServer. (/var/www/pimcore-current/website/lib/socket_server.js:36:30)
at WebSocketServer.emit (events.js:81:20)
at WebSocketServer.handleUpgrade (/home/dev/.node_libraries/.npm/websocket/1.0.4/package/lib/WebSocketServer.js:179:14)
at Server. (native)
at Server.emit (events.js:81:20)
at Socket. (http.js:1035:14)
at Socket._onReadable (net.js:683:27)
at IOWatcher.onReadable as callback

using this example code:

var WebSocketServer = require('websocket').server;
var http = require('http');

var server = http.createServer(function(request, response) {
    console.log((new Date()) + ' Received request for ' + request.url);
    response.writeHead(404);
    response.end();
});
server.listen(8081, function() {
    console.log((new Date()) + ' Server is listening on port 8080');
});

wsServer = new WebSocketServer({
    httpServer: server,
    // You should not use autoAcceptConnections for production
    // applications, as it defeats all standard cross-origin protection
    // facilities built into the protocol and the browser.  You should
    // *always* verify the connection's origin and decide whether or not
    // to accept it.
    autoAcceptConnections: false
});

function originIsAllowed(origin) {
  // put logic here to detect whether the specified origin is allowed.
  return true;
}

wsServer.on('request', function(request) {
    if (!originIsAllowed(request.origin)) {
      // Make sure we only accept requests from an allowed origin
      request.reject();
      console.log((new Date()) + ' Connection from origin ' + request.origin + ' rejected.');
      return;
    }

    var connection = request.accept('echo-protocol', request.origin);
    console.log((new Date()) + ' Connection accepted.');
    connection.on('message', function(message) {
        if (message.type === 'utf8') {
            console.log('Received Message: ' + message.utf8Data);
            connection.sendUTF(message.utf8Data);
        }
        else if (message.type === 'binary') {
            console.log('Received Binary Message of ' + message.binaryData.length + ' bytes');
            connection.sendBytes(message.binaryData);
        }
    });
    connection.on('close', function(reasonCode, description) {
        console.log((new Date()) + ' Peer ' + connection.remoteAddress + ' disconnected.');
    });
});

any ideas?

@theturtle32
Copy link
Owner

This is actually intended behavior. Your problem is with this line where you are incorrectly specifying the protocol as a component of the path in the URL:

websocket = new WebSocket('ws://****.l:8081/echo-protocol');

It should be:

websocket = new WebSocket('ws://****.l:8081/', 'echo-protocol');

The reason that the server is throwing an error is that, according to the WebSockets spec, the server cannot specify a subprotocol (echo-protocol) that has not been explicitly requested by the client. And in your original code, you were specifically not requesting the use of the echo-protocol subprotocol but instead were requesting the path /echo-protocol.

To avoid the possibility of the server "crashing" due to specifying a protocol that a client didn't request, you need to be sure to check the list of subprotocols requested by the client and make sure that the one you want to speak has been requested before accepting the connection. If it has not requested your desired subprotocol and you cannot fall back to one of the other protocols that the client would like to speak, you must explicitly reject the connection instead of accepting it.

@theturtle32
Copy link
Owner

I should mention that the list of subprotocols requested by the client can be accessed at request.requestedProtocols.

Example:

if (request.requestedProtocols.indexOf('my_great_protocol') === -1) {
    request.reject();
}
else {
    var connection = request.accept('my_great_protocol', request.origin);
}

Note that any protocols will have been converted to all lowercase during parsing.

@timglabisch
Copy link
Author

thanks a lot! works great!

@theturtle32
Copy link
Owner

No problem!

@ketting00
Copy link

I've this problem too and I tested the script provided by theturtle32 above. Instead of the server rejects requested connection coming from illegal protocol (not 'echo-protocol' but 'some-others-protocol') it just stopped working. How do I keep the server running?

Thanks

@alinz
Copy link

alinz commented Jan 2, 2013

Hi ketting00,
I have the same problem. I think requestedProtocol is not being set by the framework. But no worry, you can check the protocol by doing the following:

if ( request.httpRequest.headers['sec-websocket-protocol'] !== 'myprotocol' ) {
    request.reject();
}

Cheers,
Ali

@theturtle32
Copy link
Owner

@alinz Yes, you can do that, but it's not recommended. The sec-websocket-protocol header is allowed to contain multiple values, and so the simple string matching method you show in your example will not always work as expected. A full HTTP-compliant parser should be used to determine the actual value(s) of the header.

As for requestedProtocol, it is indeed being set by the framework. It's used internally for verification and if it were not being set, the entire framework would not work and would throw errors when you tried to accept incoming connections. I recommend you double-check your code.

@alinz
Copy link

alinz commented Jan 10, 2013

So how would we get the websocket protocol if the framework doesn't set for
us? Is it a bug?

@theturtle32
Copy link
Owner

No, it is being set by the framework. Double-check your code, or if you are certain there is a bug, please post some example code that shows the problem you're running into.

@jamesjenner
Copy link

I'm doing the following and it works fine for me:

    // process protocols
    for(var i=0, l=request.requestedProtocols.length; i < l; i++) {
    if(request.requestedProtocols[i] === 'videre_1.1') {
            connection = request.accept(request.requestedProtocols[i], request.origin);
        break;
    }
    }

    // test if no connection was created, due to no protocol match
    if(!connection) {
    console.log((new Date()) + ' Connection rejected, invalid protocol(s): ' + request.requestedProtocols);
        connection = request.reject();
    return;
    }

The above is where request is the request passed by the 'request' event by the server.

@ketting00
Copy link

@alinz I tried your method. It doesn't work.

@ketting00
Copy link

Otherwise, use upstart and monit to automatically restart your app if it stopped.

@r4jin
Copy link

r4jin commented Nov 13, 2013

Thanks for the great answers guys

@Sinkthor
Copy link

Hello I'm having the same problem and obviously there is a solution.
I did the things you said above and I though it was a good idea to way you try to know the protocol's name but it appears in the console: undefined...
In the code console I have this error:

C:\Users\User\Desktop\RaphaelClc\Notification\node_modules\websocket\lib\WebSocketRequest.js:289
            throw new Error('Specified protocol was not requested by the client.');
            ^
Error: Specified protocol was not requested by the client.
    at WebSocketRequest.accept (C:\Users\User\Desktop\RaphaelClc\Notification\node_modules\websocket\lib\WebSocketRequest.js:289:19)
    at WebSocketServer.<anonymous> (C:\Users\User\Desktop\RaphaelClc\Notification\bin\www:45:24)
    at emitOne (events.js:77:13)
    at WebSocketServer.emit (events.js:169:7)
    at WebSocketServer.handleUpgrade (C:\Users\User\Desktop\RaphaelClc\Notification\node_modules\websocket\lib\WebSocketServer.js:213:14)
    at emitThree (events.js:102:20)
    at Server.emit (events.js:175:7)
    at onParserExecuteCommon (_http_server.js:400:14)
    at HTTPParser.onParserExecute (_http_server.js:368:5)

In the browser's extension develop tools I'm using (MQTT2Chrome) I have this error:
WebSocket connection to 'ws://localhost:3000/mqtt' failed: Error during WebSocket handshake: Sent non-empty 'Sec-WebSocket-Protocol' header but no response was received

I think it's related but haven't figured out how to solve this.
Here is my critical code (especially where is in capital text):

var WebSocketServer = require('websocket').server;
wss = new WebSocketServer({
  httpServer: server});
wss.on('connect', function(connection){
  console.log('connected');
  connection.send('yo!!');});
wss.on('request', function(req){
  console.log('request');
  console.log(req.httpRequest.headers['sec-websocket-protocol']);
  VAR CONNECTION = REQ.ACCEPT('MQTT', REQ.ORIGIN);            <-----------------------
  connection.on('message', function(message){
    console.log(message.utf8Data);});
  connection.on('close', function(reasonCode, description){
    console.log('connection closed', reasonCode, description);});});
wss.on('close', function(conn, reason, description){
  console.log('closing', reason, description);});

@ibc
Copy link
Collaborator

ibc commented Aug 17, 2016

This is not the proper place to ask questions regarding how the WebSocket protocol (and its "subprotocol negotiation") works. Please, read the doc:

@pontiyaraja
Copy link

Its not working I'm also getting below error,

WebSocket connection to 'ws://localhost:8091/join/pan' failed: Error during WebSocket handshake: Sent non-empty 'Sec-WebSocket-Protocol' header but no response was received

@daveime
Copy link

daveime commented May 15, 2017

Are you serious here? A client requests an unknown protocol, and instead of just rejecting it, you crash the server with a throw Error? And someone else suggests using a monitoring tool to restart the server if it fails?

Tell me, what happens to all the other poor connections that are working correctly? A rogue connection taking down the server does not seem like sound design.

@theturtle32
Copy link
Owner

@daveime - Your description is inaccurate. The server doesn't crash when a client requests an unknown protocol. Because the protocol is flexible enough to allow the client to specify multiple potentially acceptable protocols, the server can choose one from the list of protocols proposed by the client. It's your responsibility to choose the correct protocol, and attempting to accept the connection with any protocol other than one proposed by the client is your own programming error. This is not a condition that can arise from a mis-behaving client.

If you're seeing this error, then your server-side code is trying to do something it shouldn't be doing. It is an explicit design decision to raise and crash on mis-behaving server code rather than potentially silently swallow those errors, because they're important things that you need to be aware of and fix.

@grapevine2383
Copy link

What if the clients are browsers? Someone can deliberately crash a websocket server by just sending another protocol

@theturtle32
Copy link
Owner

theturtle32 commented May 26, 2017 via email

@grapevine2383
Copy link

grapevine2383 commented May 26, 2017 via email

@ibc
Copy link
Collaborator

ibc commented May 26, 2017

Maybe put it somewhere on the documentation and the example.

https://tools.ietf.org/html/rfc6455

Users should read protocol specifications before using libraries that implement such a protocol.

@grapevine2383
Copy link

grapevine2383 commented May 26, 2017 via email

@jamesjenner
Copy link

Sigh. I cannot believe this conversation is still continuing.

Failing to catch errors is lazy, expecting an API to hold your hand is lazy. If you write code that fails because you didn't read the protocol and didn't catch any potential exceptions then you only have yourself to blame.

The owners of this repository are not going to change the logic just because you guys are lazy and/or don't understand the concept of capturing thrown exceptions.

I even offered a link to my github project that I wrote over four years ago that demonstrates clearly how to catch the errors and handle them.

You have this lib for free, it's FOSS, from the generosity of the author. Stop being lazy, invest some of your own time and accept responsibility for your inability to code appropriately.

@ibc
Copy link
Collaborator

ibc commented May 26, 2017

The protocol doesn't specify that it should crash the server.

The protocol states that replyig with an non matching WC subprotocol is not valid and hence the Node-WebSocket library must react according. It's up to the developer to properly implement the logic.

@grapevine2383
Copy link

I'm just giving a recommendation because I can see this becoming an issue with people. It's up to the developer to implement the logic and that can be to not crash the server or at least put it in the documentation if you are going to go the crash route.

I'd rather go the prevention route. If prepared SQL statements were more prevalent in API's in the beginning there wouldn't be so many SQL injection vulnerabilities.

@grapevine2383
Copy link

Either way it is up to the developers of this library. They can choose to do something or not. This issue is bound to continue coming up.

I'm not going to argue any longer, I've stated my reasons already.

@jamesjenner
Copy link

I think it is clear that the code will not change. However clearer examples or documentation may make make it easier for some people.

So I would suggest that if you find this an issue @jimmaay (and others), then you could write some examples and doco and do a pull request.

Unfortunately people are often eager to ask for improvements. But the best way to get improvements in, or to address a problem, is to do it yourself and do a pull request.

The alternative is to do a fork and make changes as you see fit.

@ibc
Copy link
Collaborator

ibc commented May 26, 2017

Yes, please send a PR with the proper documentation.

@theturtle32
Copy link
Owner

theturtle32 commented Jun 22, 2017

@jimmaay & @daveime - Just checked, it turns out that the documentation is already pretty clear.

https://github.com/theturtle32/WebSocket-Node/blob/master/docs/WebSocketRequest.md#acceptacceptedprotocol-allowedorigin

After inspecting the WebSocketRequest's properties, call this function on the request object to accept the connection. If you don't have a particular subprotocol you wish to speak, you may pass null for the acceptedProtocol parameter. Note that the acceptedProtocol parameter is case-insensitive, and you must either pass a value that was originally requested by the client or null

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests