Click here to Skip to main content
15,879,326 members
Articles / Web Development / Node.js

Node.Js And Stuff

Rate me:
Please Sign up or sign in to vote.
4.97/5 (55 votes)
11 Feb 2013CPOL23 min read 356.2K   2.3K   172  
Small demo app using Node.Js/Socket.IO/MongoDB/D3.Js and jQuery.
var http = require('http')
  , https = require('https')
  , WebSocket = require('../')
  , WebSocketServer = WebSocket.Server
  , fs = require('fs')
  , should = require('should');

var port = 20000;

function getArrayBuffer(buf) {
  var l = buf.length;
  var arrayBuf = new ArrayBuffer(l);
  for (var i = 0; i < l; ++i) {
    arrayBuf[i] = buf[i];
  }
  return arrayBuf;
}

function areArraysEqual(x, y) {
  if (x.length != y.length) return false;
  for (var i = 0, l = x.length; i < l; ++i) {
    if (x[i] !== y[i]) return false;
  }
  return true;
}

describe('WebSocketServer', function() {
  describe('#ctor', function() {
    it('throws an error if no option object is passed', function() {
      var gotException = false;
      try {
        var wss = new WebSocketServer();
      }
      catch (e) {
        gotException = true;
      }
      gotException.should.be.ok;
    });

    it('throws an error if no port or server is specified', function() {
      var gotException = false;
      try {
        var wss = new WebSocketServer({});
      }
      catch (e) {
        gotException = true;
      }
      gotException.should.be.ok;
    });

    it('does not throw an error if no port or server is specified, when the noServer option is true', function() {
      var gotException = false;
      try {
        var wss = new WebSocketServer({noServer: true});
      }
      catch (e) {
        gotException = true;
      }
      gotException.should.eql(false);
    });

    it('emits an error if http server bind fails', function(done) {
      var wss = new WebSocketServer({port: 1});
      wss.on('error', function() { done(); });
    });

    it('starts a server on a given port', function(done) {
      var wss = new WebSocketServer({port: ++port}, function() {
        var ws = new WebSocket('ws://localhost:' + port);
      });
      wss.on('connection', function(client) {
        wss.close();
        done();
      });
    });

    it('uses a precreated http server', function (done) {
      var srv = http.createServer();
      srv.listen(++port, function () {
        var wss = new WebSocketServer({server: srv});
        var ws = new WebSocket('ws://localhost:' + port);

        wss.on('connection', function(client) {
          wss.close();
          srv.close();
          done();
        });
      });
    });

    it('uses a precreated http server listening on unix socket', function (done) {
      var srv = http.createServer();
      var sockPath = '/tmp/ws_socket_'+new Date().getTime()+'.'+Math.floor(Math.random() * 1000);
      srv.listen(sockPath, function () {
        var wss = new WebSocketServer({server: srv});
        var ws = new WebSocket('ws+unix://'+sockPath);

        wss.on('connection', function(client) {
          wss.close();
          srv.close();
          done();
        });
      });
    });

    it('emits path specific connection event', function (done) {
      var srv = http.createServer();
      srv.listen(++port, function () {
        var wss = new WebSocketServer({server: srv});
        var ws = new WebSocket('ws://localhost:' + port+'/endpointName');

        wss.on('connection/endpointName', function(client) {
          wss.close();
          srv.close();
          done();
        });
      });
    });

    it('can have two different instances listening on the same http server with two different paths', function(done) {
      var srv = http.createServer();
      srv.listen(++port, function () {
        var wss1 = new WebSocketServer({server: srv, path: '/wss1'})
          , wss2 = new WebSocketServer({server: srv, path: '/wss2'});
        var doneCount = 0;
        wss1.on('connection', function(client) {
          wss1.close();
          if (++doneCount == 2) {
            srv.close();
            done();
          }
        });
        wss2.on('connection', function(client) {
          wss2.close();
          if (++doneCount == 2) {
            srv.close();
            done();
          }
        });
        var ws1 = new WebSocket('ws://localhost:' + port + '/wss1');
        var ws2 = new WebSocket('ws://localhost:' + port + '/wss2?foo=1');
      });
    });

    it('cannot have two different instances listening on the same http server with the same path', function(done) {
      var srv = http.createServer();
      srv.listen(++port, function () {
        var wss1 = new WebSocketServer({server: srv, path: '/wss1'});
        try {
          var wss2 = new WebSocketServer({server: srv, path: '/wss1'});
        }
        catch (e) {
          wss1.close();
          srv.close();
          done();
        }
      });
    });
  });

  describe('#close', function() {
    it('will close all clients', function(done) {
      var wss = new WebSocketServer({port: ++port}, function() {
        var ws = new WebSocket('ws://localhost:' + port);
        ws.on('close', function() {
          if (++closes == 2) done();
        });
      });
      var closes = 0;
      wss.on('connection', function(client) {
        client.on('close', function() {
          if (++closes == 2) done();
        });
        wss.close();
      });
    });

    it('does not close a precreated server', function(done) {
      var srv = http.createServer();
      var realClose = srv.close;
      srv.close = function() {
        should.fail('must not close pre-created server');
      }
      srv.listen(++port, function () {
        var wss = new WebSocketServer({server: srv});
        var ws = new WebSocket('ws://localhost:' + port);
        wss.on('connection', function(client) {
          wss.close();
          srv.close = realClose;
          srv.close();
          done();
        });
      });
    });

    it('cleans up websocket data on a precreated server', function(done) {
      var srv = http.createServer();
      srv.listen(++port, function () {
        var wss1 = new WebSocketServer({server: srv, path: '/wss1'})
          , wss2 = new WebSocketServer({server: srv, path: '/wss2'});
        (typeof srv._webSocketPaths).should.eql('object');
        Object.keys(srv._webSocketPaths).length.should.eql(2);
        wss1.close();
        Object.keys(srv._webSocketPaths).length.should.eql(1);
        wss2.close();
        (typeof srv._webSocketPaths).should.eql('undefined');
        srv.close();
        done();
      });
    });
  });

  describe('#clients', function() {
    it('returns a list of connected clients', function(done) {
      var wss = new WebSocketServer({port: ++port}, function() {
        wss.clients.length.should.eql(0);
        var ws = new WebSocket('ws://localhost:' + port);
      });
      wss.on('connection', function(client) {
        wss.clients.length.should.eql(1);
        wss.close();
        done();
      });
    });

    it('can be disabled', function(done) {
      var wss = new WebSocketServer({port: ++port, clientTracking: false}, function() {
        wss.clients.length.should.eql(0);
        var ws = new WebSocket('ws://localhost:' + port);
      });
      wss.on('connection', function(client) {
        wss.clients.length.should.eql(0);
        wss.close();
        done();
      });
    });

    it('is updated when client terminates the connection', function(done) {
      var ws;
      var wss = new WebSocketServer({port: ++port}, function() {
        ws = new WebSocket('ws://localhost:' + port);
      });
      wss.on('connection', function(client) {
        client.on('close', function() {
          wss.clients.length.should.eql(0);
          wss.close();
          done();
        });
        ws.terminate();
      });
    });

    it('is updated when client closes the connection', function(done) {
      var ws;
      var wss = new WebSocketServer({port: ++port}, function() {
        ws = new WebSocket('ws://localhost:' + port);
      });
      wss.on('connection', function(client) {
        client.on('close', function() {
          wss.clients.length.should.eql(0);
          wss.close();
          done();
        });
        ws.close();
      });
    });
  });

  describe('#options', function() {
    it('exposes options passed to constructor', function(done) {
      var wss = new WebSocketServer({port: ++port}, function() {
        wss.options.port.should.eql(port);
        wss.close();
        done();
      });
    });
  });

  describe('#handleUpgrade', function() {
    it('can be used for a pre-existing server', function (done) {
      var srv = http.createServer();
      srv.listen(++port, function () {
        var wss = new WebSocketServer({noServer: true});
        srv.on('upgrade', function(req, socket, upgradeHead) {
          wss.handleUpgrade(req, socket, upgradeHead, function(client) {
            client.send('hello');
          });
        });
        var ws = new WebSocket('ws://localhost:' + port);
        ws.on('message', function(message) {
          message.should.eql('hello');
          wss.close();
          srv.close();
          done();
        });
      });
    });
  });

  describe('hybi mode', function() {
    describe('connection establishing', function() {
      it('does not accept connections with no sec-websocket-key', function(done) {
        var wss = new WebSocketServer({port: ++port}, function() {
          var options = {
            port: port,
            host: '127.0.0.1',
            headers: {
              'Connection': 'Upgrade',
              'Upgrade': 'websocket'
            }
          };
          var req = http.request(options);
          req.end();
          req.on('response', function(res) {
            res.statusCode.should.eql(400);
            wss.close();
            done();
          });
        });
        wss.on('connection', function(ws) {
          done(new Error('connection must not be established'));
        });
        wss.on('error', function() {});
      });

      it('does not accept connections with no sec-websocket-version', function(done) {
        var wss = new WebSocketServer({port: ++port}, function() {
          var options = {
            port: port,
            host: '127.0.0.1',
            headers: {
              'Connection': 'Upgrade',
              'Upgrade': 'websocket',
              'Sec-WebSocket-Key': 'dGhlIHNhbXBsZSBub25jZQ=='
            }
          };
          var req = http.request(options);
          req.end();
          req.on('response', function(res) {
            res.statusCode.should.eql(400);
            wss.close();
            done();
          });
        });
        wss.on('connection', function(ws) {
          done(new Error('connection must not be established'));
        });
        wss.on('error', function() {});
      });

      it('does not accept connections with invalid sec-websocket-version', function(done) {
        var wss = new WebSocketServer({port: ++port}, function() {
          var options = {
            port: port,
            host: '127.0.0.1',
            headers: {
              'Connection': 'Upgrade',
              'Upgrade': 'websocket',
              'Sec-WebSocket-Key': 'dGhlIHNhbXBsZSBub25jZQ==',
              'Sec-WebSocket-Version': 12
            }
          };
          var req = http.request(options);
          req.end();
          req.on('response', function(res) {
            res.statusCode.should.eql(400);
            wss.close();
            done();
          });
        });
        wss.on('connection', function(ws) {
          done(new Error('connection must not be established'));
        });
        wss.on('error', function() {});
      });

      it('client can be denied', function(done) {
        var wss = new WebSocketServer({port: ++port, verifyClient: function(o) {
          return false;
        }}, function() {
          var options = {
            port: port,
            host: '127.0.0.1',
            headers: {
              'Connection': 'Upgrade',
              'Upgrade': 'websocket',
              'Sec-WebSocket-Key': 'dGhlIHNhbXBsZSBub25jZQ==',
              'Sec-WebSocket-Version': 8,
              'Sec-WebSocket-Origin': 'http://foobar.com'
            }
          };
          var req = http.request(options);
          req.end();
          req.on('response', function(res) {
            res.statusCode.should.eql(401);
            process.nextTick(function() {
              wss.close();
              done();
            });
          });
        });
        wss.on('connection', function(ws) {
          done(new Error('connection must not be established'));
        });
        wss.on('error', function() {});
      });

      it('client can be accepted', function(done) {
        var wss = new WebSocketServer({port: ++port, verifyClient: function(o) {
          return true;
        }}, function() {
          var options = {
            port: port,
            host: '127.0.0.1',
            headers: {
              'Connection': 'Upgrade',
              'Upgrade': 'websocket',
              'Sec-WebSocket-Key': 'dGhlIHNhbXBsZSBub25jZQ==',
              'Sec-WebSocket-Version': 13,
              'Origin': 'http://foobar.com'
            }
          };
          var req = http.request(options);
          req.end();
        });
        wss.on('connection', function(ws) {
          ws.terminate();
          wss.close();
          done();
        });
        wss.on('error', function() {});
      });

      it('verifyClient gets client origin', function(done) {
        var verifyClientCalled = false;
        var wss = new WebSocketServer({port: ++port, verifyClient: function(info) {
          info.origin.should.eql('http://foobarbaz.com');
          verifyClientCalled = true;
          return false;
        }}, function() {
          var options = {
            port: port,
            host: '127.0.0.1',
            headers: {
              'Connection': 'Upgrade',
              'Upgrade': 'websocket',
              'Sec-WebSocket-Key': 'dGhlIHNhbXBsZSBub25jZQ==',
              'Sec-WebSocket-Version': 13,
              'Origin': 'http://foobarbaz.com'
            }
          };
          var req = http.request(options);
          req.end();
          req.on('response', function(res) {
            verifyClientCalled.should.be.ok;
            wss.close();
            done();
          });
        });
        wss.on('error', function() {});
      });

      it('verifyClient gets original request', function(done) {
        var verifyClientCalled = false;
        var wss = new WebSocketServer({port: ++port, verifyClient: function(info) {
          info.req.headers['sec-websocket-key'].should.eql('dGhlIHNhbXBsZSBub25jZQ==');
          verifyClientCalled = true;
          return false;
        }}, function() {
          var options = {
            port: port,
            host: '127.0.0.1',
            headers: {
              'Connection': 'Upgrade',
              'Upgrade': 'websocket',
              'Sec-WebSocket-Key': 'dGhlIHNhbXBsZSBub25jZQ==',
              'Sec-WebSocket-Version': 13,
              'Origin': 'http://foobarbaz.com'
            }
          };
          var req = http.request(options);
          req.end();
          req.on('response', function(res) {
            verifyClientCalled.should.be.ok;
            wss.close();
            done();
          });
        });
        wss.on('error', function() {});
      });

      it('verifyClient has secure:true for ssl connections', function(done) {
        var options = {
          key: fs.readFileSync('test/fixtures/key.pem'),
          cert: fs.readFileSync('test/fixtures/certificate.pem')
        };
        var app = https.createServer(options, function (req, res) {
          res.writeHead(200);
          res.end();
        });
        var success = false;
        var wss = new WebSocketServer({
          server: app,
          verifyClient: function(info) {
            success = info.secure === true;
            return true;
          }
        });
        app.listen(++port, function() {
          var ws = new WebSocket('wss://localhost:' + port);
        });
        wss.on('connection', function(ws) {
          app.close();
          ws.terminate();
          wss.close();
          success.should.be.ok;
          done();
        });
      });

      it('verifyClient has secure:false for non-ssl connections', function(done) {
        var app = http.createServer(function (req, res) {
          res.writeHead(200);
          res.end();
        });
        var success = false;
        var wss = new WebSocketServer({
          server: app,
          verifyClient: function(info) {
            success = info.secure === false;
            return true;
          }
        });
        app.listen(++port, function() {
          var ws = new WebSocket('ws://localhost:' + port);
        });
        wss.on('connection', function(ws) {
          app.close();
          ws.terminate();
          wss.close();
          success.should.be.ok;
          done();
        });
      });

      it('client can be denied asynchronously', function(done) {
        var wss = new WebSocketServer({port: ++port, verifyClient: function(o, cb) {
          process.nextTick(function() {
            cb(false);
          });
        }}, function() {
          var options = {
            port: port,
            host: '127.0.0.1',
            headers: {
              'Connection': 'Upgrade',
              'Upgrade': 'websocket',
              'Sec-WebSocket-Key': 'dGhlIHNhbXBsZSBub25jZQ==',
              'Sec-WebSocket-Version': 8,
              'Sec-WebSocket-Origin': 'http://foobar.com'
            }
          };
          var req = http.request(options);
          req.end();
          req.on('response', function(res) {
            res.statusCode.should.eql(401);
            process.nextTick(function() {
              wss.close();
              done();
            });
          });
        });
        wss.on('connection', function(ws) {
          done(new Error('connection must not be established'));
        });
        wss.on('error', function() {});
      });

      it('client can be accepted asynchronously', function(done) {
        var wss = new WebSocketServer({port: ++port, verifyClient: function(o, cb) {
          process.nextTick(function() {
            cb(true);
          });
        }}, function() {
          var options = {
            port: port,
            host: '127.0.0.1',
            headers: {
              'Connection': 'Upgrade',
              'Upgrade': 'websocket',
              'Sec-WebSocket-Key': 'dGhlIHNhbXBsZSBub25jZQ==',
              'Sec-WebSocket-Version': 13,
              'Origin': 'http://foobar.com'
            }
          };
          var req = http.request(options);
          req.end();
        });
        wss.on('connection', function(ws) {
          ws.terminate();
          wss.close();
          done();
        });
        wss.on('error', function() {});
      });

      it('handles messages passed along with the upgrade request (upgrade head)', function(done) {
        var wss = new WebSocketServer({port: ++port, verifyClient: function(o) {
          return true;
        }}, function() {
          var options = {
            port: port,
            host: '127.0.0.1',
            headers: {
              'Connection': 'Upgrade',
              'Upgrade': 'websocket',
              'Sec-WebSocket-Key': 'dGhlIHNhbXBsZSBub25jZQ==',
              'Sec-WebSocket-Version': 13,
              'Origin': 'http://foobar.com'
            }
          };
          var req = http.request(options);
          req.write(new Buffer([0x81, 0x05, 0x48, 0x65, 0x6c, 0x6c, 0x6f], 'binary'));
          req.end();
        });
        wss.on('connection', function(ws) {
          ws.on('message', function(data) {
            data.should.eql('Hello');
            ws.terminate();
            wss.close();
            done();
          });
        });
        wss.on('error', function() {});
      });
    });

    describe('messaging', function() {
      it('can send and receive data', function(done) {
        var data = new Array(65*1024);
        for (var i = 0; i < data.length; ++i) {
          data[i] = String.fromCharCode(65 + ~~(25 * Math.random()));
        }
        data = data.join('');
        var wss = new WebSocketServer({port: ++port}, function() {
          var ws = new WebSocket('ws://localhost:' + port);
          ws.on('message', function(message, flags) {
            ws.send(message);
          });
        });
        wss.on('connection', function(client) {
          client.on('message', function(message) {
            message.should.eql(data);
            wss.close();
            done();
          });
          client.send(data);
        });
      });
    });
  });

  describe('hixie mode', function() {
    it('can be disabled', function(done) {
      var wss = new WebSocketServer({port: ++port, disableHixie: true}, function() {
        var options = {
          port: port,
          host: '127.0.0.1',
          headers: {
            'Connection': 'Upgrade',
            'Upgrade': 'WebSocket',
            'Sec-WebSocket-Key1': '3e6b263  4 17 80',
            'Sec-WebSocket-Key2': '17  9 G`ZD9   2 2b 7X 3 /r90'
          }
        };
        var req = http.request(options);
        req.write('WjN}|M(6');
        req.end();
        req.on('response', function(res) {
          res.statusCode.should.eql(401);
          process.nextTick(function() {
            wss.close();
            done();
          });
        });
      });
      wss.on('connection', function(ws) {
        done(new Error('connection must not be established'));
      });
      wss.on('error', function() {});
    });

    describe('connection establishing', function() {
      it('does not accept connections with no sec-websocket-key1', function(done) {
        var wss = new WebSocketServer({port: ++port}, function() {
          var options = {
            port: port,
            host: '127.0.0.1',
            headers: {
              'Connection': 'Upgrade',
              'Upgrade': 'WebSocket',
              'Sec-WebSocket-Key1': '3e6b263  4 17 80'
            }
          };
          var req = http.request(options);
          req.end();
          req.on('response', function(res) {
            res.statusCode.should.eql(400);
            wss.close();
            done();
          });
        });
        wss.on('connection', function(ws) {
          done(new Error('connection must not be established'));
        });
        wss.on('error', function() {});
      });

      it('does not accept connections with no sec-websocket-key2', function(done) {
        var wss = new WebSocketServer({port: ++port}, function() {
          var options = {
            port: port,
            host: '127.0.0.1',
            headers: {
              'Connection': 'Upgrade',
              'Upgrade': 'WebSocket',
              'Sec-WebSocket-Key2': '17  9 G`ZD9   2 2b 7X 3 /r90'
            }
          };
          var req = http.request(options);
          req.end();
          req.on('response', function(res) {
            res.statusCode.should.eql(400);
            wss.close();
            done();
          });
        });
        wss.on('connection', function(ws) {
          done(new Error('connection must not be established'));
        });
        wss.on('error', function() {});
      });

      it('accepts connections with valid handshake', function(done) {
        var wss = new WebSocketServer({port: ++port}, function() {
          var options = {
            port: port,
            host: '127.0.0.1',
            headers: {
              'Connection': 'Upgrade',
              'Upgrade': 'WebSocket',
              'Sec-WebSocket-Key1': '3e6b263  4 17 80',
              'Sec-WebSocket-Key2': '17  9 G`ZD9   2 2b 7X 3 /r90'
            }
          };
          var req = http.request(options);
          req.write('WjN}|M(6');
          req.end();
        });
        wss.on('connection', function(ws) {
          ws.terminate();
          wss.close();
          done();
        });
        wss.on('error', function() {});
      });

      it('client can be denied', function(done) {
        var wss = new WebSocketServer({port: ++port, verifyClient: function(o) {
          return false;
        }}, function() {
          var options = {
            port: port,
            host: '127.0.0.1',
            headers: {
              'Connection': 'Upgrade',
              'Upgrade': 'WebSocket',
              'Sec-WebSocket-Key1': '3e6b263  4 17 80',
              'Sec-WebSocket-Key2': '17  9 G`ZD9   2 2b 7X 3 /r90'
            }
          };
          var req = http.request(options);
          req.write('WjN}|M(6');
          req.end();
          req.on('response', function(res) {
            res.statusCode.should.eql(401);
            process.nextTick(function() {
              wss.close();
              done();
            });
          });
        });
        wss.on('connection', function(ws) {
          done(new Error('connection must not be established'));
        });
        wss.on('error', function() {});
      });

      it('client can be accepted', function(done) {
        var wss = new WebSocketServer({port: ++port, verifyClient: function(o) {
          return true;
        }}, function() {
          var options = {
            port: port,
            host: '127.0.0.1',
            headers: {
              'Connection': 'Upgrade',
              'Upgrade': 'WebSocket',
              'Sec-WebSocket-Key1': '3e6b263  4 17 80',
              'Sec-WebSocket-Key2': '17  9 G`ZD9   2 2b 7X 3 /r90'
            }
          };
          var req = http.request(options);
          req.write('WjN}|M(6');
          req.end();
        });
        wss.on('connection', function(ws) {
          ws.terminate();
          wss.close();
          done();
        });
        wss.on('error', function() {});
      });

      it('verifyClient gets client origin', function(done) {
        var verifyClientCalled = false;
        var wss = new WebSocketServer({port: ++port, verifyClient: function(info) {
          info.origin.should.eql('http://foobarbaz.com');
          verifyClientCalled = true;
          return false;
        }}, function() {
          var options = {
            port: port,
            host: '127.0.0.1',
            headers: {
              'Connection': 'Upgrade',
              'Upgrade': 'WebSocket',
              'Origin': 'http://foobarbaz.com',
              'Sec-WebSocket-Key1': '3e6b263  4 17 80',
              'Sec-WebSocket-Key2': '17  9 G`ZD9   2 2b 7X 3 /r90'
            }
          };
          var req = http.request(options);
          req.write('WjN}|M(6');
          req.end();
          req.on('response', function(res) {
            verifyClientCalled.should.be.ok;
            wss.close();
            done();
          });
        });
        wss.on('error', function() {});
      });

      it('verifyClient gets original request', function(done) {
        var verifyClientCalled = false;
        var wss = new WebSocketServer({port: ++port, verifyClient: function(info) {
          info.req.headers['sec-websocket-key1'].should.eql('3e6b263  4 17 80');
          verifyClientCalled = true;
          return false;
        }}, function() {
          var options = {
            port: port,
            host: '127.0.0.1',
            headers: {
              'Connection': 'Upgrade',
              'Upgrade': 'WebSocket',
              'Origin': 'http://foobarbaz.com',
              'Sec-WebSocket-Key1': '3e6b263  4 17 80',
              'Sec-WebSocket-Key2': '17  9 G`ZD9   2 2b 7X 3 /r90'
            }
          };
          var req = http.request(options);
          req.write('WjN}|M(6');
          req.end();
          req.on('response', function(res) {
            verifyClientCalled.should.be.ok;
            wss.close();
            done();
          });
        });
        wss.on('error', function() {});
      });

      it('client can be denied asynchronously', function(done) {
        var wss = new WebSocketServer({port: ++port, verifyClient: function(o, cb) {
          cb(false);
        }}, function() {
          var options = {
            port: port,
            host: '127.0.0.1',
            headers: {
              'Connection': 'Upgrade',
              'Upgrade': 'WebSocket',
              'Origin': 'http://foobarbaz.com',
              'Sec-WebSocket-Key1': '3e6b263  4 17 80',
              'Sec-WebSocket-Key2': '17  9 G`ZD9   2 2b 7X 3 /r90'
            }
          };
          var req = http.request(options);
          req.write('WjN}|M(6');
          req.end();
          req.on('response', function(res) {
            res.statusCode.should.eql(401);
            process.nextTick(function() {
              wss.close();
              done();
            });
          });
        });
        wss.on('connection', function(ws) {
          done(new Error('connection must not be established'));
        });
        wss.on('error', function() {});
      });

      it('client can be accepted asynchronously', function(done) {
        var wss = new WebSocketServer({port: ++port, verifyClient: function(o, cb) {
          cb(true);
        }}, function() {
          var options = {
            port: port,
            host: '127.0.0.1',
            headers: {
              'Connection': 'Upgrade',
              'Upgrade': 'WebSocket',
              'Origin': 'http://foobarbaz.com',
              'Sec-WebSocket-Key1': '3e6b263  4 17 80',
              'Sec-WebSocket-Key2': '17  9 G`ZD9   2 2b 7X 3 /r90'
            }
          };
          var req = http.request(options);
          req.write('WjN}|M(6');
          req.end();
        });
        wss.on('connection', function(ws) {
          wss.close();
          done();
        });
        wss.on('error', function() {});
      });

      it('handles messages passed along with the upgrade request (upgrade head)', function(done) {
        var wss = new WebSocketServer({port: ++port, verifyClient: function(o) {
          return true;
        }}, function() {
          var options = {
            port: port,
            host: '127.0.0.1',
            headers: {
              'Connection': 'Upgrade',
              'Upgrade': 'WebSocket',
              'Sec-WebSocket-Key1': '3e6b263  4 17 80',
              'Sec-WebSocket-Key2': '17  9 G`ZD9   2 2b 7X 3 /r90',
              'Origin': 'http://foobar.com'
            }
          };
          var req = http.request(options);
          req.write('WjN}|M(6');
          req.write(new Buffer([0x00, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0xff], 'binary'));
          req.end();
        });
        wss.on('connection', function(ws) {
          ws.on('message', function(data) {
            data.should.eql('Hello');
            ws.terminate();
            wss.close();
            done();
          });
        });
        wss.on('error', function() {});
      });
    });
  });

  describe('client properties', function() {
    it('protocol is exposed', function(done) {
      var wss = new WebSocketServer({port: ++port}, function() {
        var ws = new WebSocket('ws://localhost:' + port, {protocol: 'hi'});
      });
      wss.on('connection', function(client) {
        client.protocol.should.eql('hi');
        wss.close();
        done();
      });
    });

    it('protocolVersion is exposed', function(done) {
      var wss = new WebSocketServer({port: ++port}, function() {
        var ws = new WebSocket('ws://localhost:' + port, {protocolVersion: 8});
      });
      wss.on('connection', function(client) {
        client.protocolVersion.should.eql(8);
        wss.close();
        done();
      });
    });

    it('upgradeReq is the original request object', function(done) {
      var wss = new WebSocketServer({port: ++port}, function() {
        var ws = new WebSocket('ws://localhost:' + port, {protocolVersion: 8});
      });
      wss.on('connection', function(client) {
        client.upgradeReq.httpVersion.should.eql('1.1');
        wss.close();
        done();
      });
    });
  });

});

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
United Kingdom United Kingdom
I currently hold the following qualifications (amongst others, I also studied Music Technology and Electronics, for my sins)

- MSc (Passed with distinctions), in Information Technology for E-Commerce
- BSc Hons (1st class) in Computer Science & Artificial Intelligence

Both of these at Sussex University UK.

Award(s)

I am lucky enough to have won a few awards for Zany Crazy code articles over the years

  • Microsoft C# MVP 2016
  • Codeproject MVP 2016
  • Microsoft C# MVP 2015
  • Codeproject MVP 2015
  • Microsoft C# MVP 2014
  • Codeproject MVP 2014
  • Microsoft C# MVP 2013
  • Codeproject MVP 2013
  • Microsoft C# MVP 2012
  • Codeproject MVP 2012
  • Microsoft C# MVP 2011
  • Codeproject MVP 2011
  • Microsoft C# MVP 2010
  • Codeproject MVP 2010
  • Microsoft C# MVP 2009
  • Codeproject MVP 2009
  • Microsoft C# MVP 2008
  • Codeproject MVP 2008
  • And numerous codeproject awards which you can see over at my blog

Comments and Discussions