Question

I'm currently starting work for my bachelor thesis and recently started 'digging' into the use of node.js and webSocket. My webSocket server runs without problems when accessed in Firefox 15.0 and Chrome 21.0.1180.89 m. In Opera 12.02, there seems to be a problem with the client-server handshake. This is what Opera's error console says:

[31.08.2012 01:03:51] WebSockets - http://10.0.0.2/
Connection
WebSocket handshake failure, invalid response code '400'.

Funny thgough: I can't find this error anywhere in the Dragonfly console's network log. All the fields that are requested when accessing the website (index.html, client.js etc.) are found and served as they should be (HTTP Status code 200 OK). Also, the only status codes that my server returns are 200, 404 and 500, so this looks like it's coming from within webSocket itself.

And yes, webSocket IS enabled in Opera...I have no idea what the problem could be

Any help would be really appreciated :)

EDIT: This is my code so far so you can see which headers my server sends and how I create webSocket connections with my client.js:

server.js:

// load required modules:
var http = require("http");
var WebSocketServer = require("websocket").server;
path = require("path");
url = require("url");
filesys = require("fs");

// declare listening port vars:
var httpListeningPort = 80;
var webSocketListeningPort = 80;

// create HTTP-server:
var httpSrv = http.createServer(function(request, response) {
    console.log((new Date()) + ":\tReceived request for " + request.url);
//  response.writeHead(200);
//  response.end();
    var myPath = url.parse(request.url).pathname;
    var fullPath = path.join(process.cwd(), myPath);
    if(myPath === "/") {
        fullPath += "index.html";
        console.log("Full path:\t" + fullPath);
        filesys.readFile(fullPath, "binary", function(err, file) {
            if(err) {
                response.writeHeader(500, {"Content-Type": "text/plain"});
                response.write(err + "\n");
                response.end();
            }
            else {
                response.writeHeader(200);
                response.write(file, "binary");
                response.end();
            }
        });
    }
    else {
        path.exists(fullPath, function(exists) {
        if(!exists) {
            response.writeHeader(404, {"Content-Type": "text/plain"});
            response.write("404 Not Found\n");
            response.end();
        }
        else {
            filesys.readFile(fullPath, "binary", function(err, file) {
                if(err) {
                    response.writeHeader(500, {"Content-Type": "text/plain"});
                    response.write(err + "\n");
                    response.end();
                }
                else {
                    response.writeHeader(200);
                    response.write(file, "binary");
                    response.end();
                }
            });
        }
        });
    }   
});
httpSrv.listen(httpListeningPort, function() {
    console.log((new Date()) + ":\tServer is now listening on port " + httpListeningPort);
});

// create webSocket server and tie it to the http server:
wsServer = new WebSocketServer({
    httpServer: httpSrv
});

function originChecker(origin) {
    if(origin) {
        console.log("Origin " + origin + " is allowed");
        return true;
    } else {
        console.log("origin is NOT allowed.");
        return false;
    }
}

// how to handle requests:
wsServer.on("request", function(request) {
    // check whether origin is allowed or not:
    if(originChecker(request.origin) === false) {
        request.reject();
        console.log((new Date()) + ":\tConnection request from origin " + request.origin + " rejected.");
        return;
    }

    // accept the connecteion request -> open the connection:
    var connection = request.accept(null, request.origin);
    console.log((new Date()) + ":\tConnection request from " + request.origin + " accepted.");

    // handle incoming messages from the clients:
    connection.on("message", function(message) {
        if(message.type === "utf8") {
            console.log((new Date()) + ":\tReceived message from " + request.origin + ":\nType: " + message.type + "\nLength: " + message.utf8Data.length + "\nMessage: " + message.utf8Data);
            // echo "Message received":
            connection.sendUTF(JSON.stringify( { type: "message", data: "Message received !" } ));
        } else {
            // send error message back to client:
            console.log((new Date()) + ":\tReceived message from " + request.origin + ":\nERROR:\tMessage is NOT UTF-8! it's " + message.type);
            connection.sendUTF(JSON.stringify( { type: "message", data: "ONLY UTF-8 accepted !" } ));
        }
    });

    // what to do when connection is closed:
    connection.on("close", function() {
        console.log((new Date()) + ":\tClient @" + connection.remoteAddress + " disconnected.");
    });
});

client.js:

function client() {

    if("WebSocket" in window) {
        alert("WebSocket is supported by your browser!");

        // try to connect to the webSocket server:
        var connection = null;
        connection = new WebSocket("ws://10.0.0.2:80");

        // things to do once the connection is opened:
        connection.onopen = function() {
            alert("INFO:\tConnection to server is OPEN");

            document.getElementById("msgInput").focus();
            document.getElementById("msgInput").disabled = false;
            document.getElementById("msgInput").value = "";

            document.getElementById("msgInput").onkeyup = function(key) {
                switch(key.keyCode) {
                    case 13:    if(document.getElementById("msgInput").value === "") { 
                                break;
                                }
                                var messageText = document.getElementById("msgInput").value;
                                document.getElementById("msgInput").disabled = true;
                                document.getElementById("msgInput").value = "";
                                document.getElementById("statusHeader").innerHTML = "Sending...";
                                connection.send(messageText);
                    break;
                    default: document.getElementById("statusHeader").innerHTML = "Press ENTER to send!";
                }
            };
        };

        connection.onerror = function(error) {
            document.body.style.backgroundColor = "#220000";
            document.body.style.color = "#aa0000";
            document.getElementById("statusHeader").innerHTML = "ERROR connecting to server -> OFFLINE";
            return;
        };

        connection.onmessage = function(message) {
            try {
                var json = JSON.parse(message.data);
            } catch (error) {
                alert("ERROR parsing message:\t" + error);
                return;
            }

            document.getElementById("statusHeader").innerHTML = json.data;
            document.getElementById("msgInput").disabled = false;
        };

        connection.onclose = function() {
            setTimeout(function() { 
            document.body.style.backgroundColor = "#808080";
            document.body.style.color = "#ffffff";
            document.getElementById("statusHeader").innerHTML = "OFFLINE";
            document.getElementById("msgInput").disabled = true;
            document.getElementById("msgInput").value = "OFFLINE";
            }, 5000);
            return;
        };
    } else {
        alert("WebSocket is NOT supported by your browser! Exiting now.");
        return;
    }   
};
Was it helpful?

Solution

According to a recent question Opera 12 supports an older, incompatible version of websockets. This version (Hixie-76) uses a different set of headers in its handshake. Your server presumably doesn't understand these which explains its 400 error response.

If you can afford to wait for Opera to catch up, the easiest 'solution' is to use other browsers for your testing for now. The hixie protocol drafts are deprecated so Opera is bound to upgrade to RFC 6455 eventually.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top