You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

180 lines
4.5 KiB

  1. var http = require('http')
  2. , util = require('util')
  3. , crypto = require('crypto')
  4. , events = require('events')
  5. , Sender = require('../lib/Sender')
  6. , Receiver = require('../lib/Receiver');
  7. module.exports = {
  8. handlers: {
  9. valid: validServer,
  10. invalidKey: invalidRequestHandler,
  11. closeAfterConnect: closeAfterConnectHandler,
  12. return401: return401
  13. },
  14. createServer: function(port, handler, cb) {
  15. if (handler && !cb) {
  16. cb = handler;
  17. handler = null;
  18. }
  19. var webServer = http.createServer(function (req, res) {
  20. res.writeHead(200, {'Content-Type': 'text/plain'});
  21. res.end('okay');
  22. });
  23. var srv = new Server(webServer);
  24. webServer.on('upgrade', function(req, socket) {
  25. webServer._socket = socket;
  26. (handler || validServer)(srv, req, socket);
  27. });
  28. webServer.listen(port, '127.0.0.1', function() { cb(srv); });
  29. }
  30. };
  31. /**
  32. * Test strategies
  33. */
  34. function validServer(server, req, socket) {
  35. if (typeof req.headers.upgrade === 'undefined' ||
  36. req.headers.upgrade.toLowerCase() !== 'websocket') {
  37. throw new Error('invalid headers');
  38. return;
  39. }
  40. if (!req.headers['sec-websocket-key']) {
  41. socket.end();
  42. throw new Error('websocket key is missing');
  43. }
  44. // calc key
  45. var key = req.headers['sec-websocket-key'];
  46. var shasum = crypto.createHash('sha1');
  47. shasum.update(key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11");
  48. key = shasum.digest('base64');
  49. var headers = [
  50. 'HTTP/1.1 101 Switching Protocols'
  51. , 'Upgrade: websocket'
  52. , 'Connection: Upgrade'
  53. , 'Sec-WebSocket-Accept: ' + key
  54. ];
  55. socket.write(headers.concat('', '').join('\r\n'));
  56. socket.setTimeout(0);
  57. socket.setNoDelay(true);
  58. var sender = new Sender(socket);
  59. var receiver = new Receiver();
  60. receiver.ontext = function (message, flags) {
  61. server.emit('message', message, flags);
  62. sender.send(message);
  63. };
  64. receiver.onbinary = function (message, flags) {
  65. flags = flags || {};
  66. flags.binary = true;
  67. server.emit('message', message, flags);
  68. sender.send(message, {binary: true});
  69. };
  70. receiver.onping = function (message, flags) {
  71. flags = flags || {};
  72. server.emit('ping', message, flags);
  73. };
  74. receiver.onpong = function (message, flags) {
  75. flags = flags || {};
  76. server.emit('pong', message, flags);
  77. };
  78. receiver.onclose = function (code, message, flags) {
  79. flags = flags || {};
  80. server.emit('close', code, message, flags);
  81. };
  82. socket.on('data', function (data) {
  83. receiver.add(data);
  84. });
  85. socket.on('end', function() {
  86. socket.end();
  87. });
  88. }
  89. function invalidRequestHandler(server, req, socket) {
  90. if (typeof req.headers.upgrade === 'undefined' ||
  91. req.headers.upgrade.toLowerCase() !== 'websocket') {
  92. throw new Error('invalid headers');
  93. return;
  94. }
  95. if (!req.headers['sec-websocket-key']) {
  96. socket.end();
  97. throw new Error('websocket key is missing');
  98. }
  99. // calc key
  100. var key = req.headers['sec-websocket-key'];
  101. var shasum = crypto.createHash('sha1');
  102. shasum.update(key + "bogus");
  103. key = shasum.digest('base64');
  104. var headers = [
  105. 'HTTP/1.1 101 Switching Protocols'
  106. , 'Upgrade: websocket'
  107. , 'Connection: Upgrade'
  108. , 'Sec-WebSocket-Accept: ' + key
  109. ];
  110. socket.write(headers.concat('', '').join('\r\n'));
  111. socket.end();
  112. }
  113. function closeAfterConnectHandler(server, req, socket) {
  114. if (typeof req.headers.upgrade === 'undefined' ||
  115. req.headers.upgrade.toLowerCase() !== 'websocket') {
  116. throw new Error('invalid headers');
  117. return;
  118. }
  119. if (!req.headers['sec-websocket-key']) {
  120. socket.end();
  121. throw new Error('websocket key is missing');
  122. }
  123. // calc key
  124. var key = req.headers['sec-websocket-key'];
  125. var shasum = crypto.createHash('sha1');
  126. shasum.update(key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11");
  127. key = shasum.digest('base64');
  128. var headers = [
  129. 'HTTP/1.1 101 Switching Protocols'
  130. , 'Upgrade: websocket'
  131. , 'Connection: Upgrade'
  132. , 'Sec-WebSocket-Accept: ' + key
  133. ];
  134. socket.write(headers.concat('', '').join('\r\n'));
  135. socket.end();
  136. }
  137. function return401(server, req, socket) {
  138. var headers = [
  139. 'HTTP/1.1 401 Unauthorized'
  140. , 'Content-type: text/html'
  141. ];
  142. socket.write(headers.concat('', '').join('\r\n'));
  143. socket.end();
  144. }
  145. /**
  146. * Server object, which will do the actual emitting
  147. */
  148. function Server(webServer) {
  149. this.webServer = webServer;
  150. }
  151. util.inherits(Server, events.EventEmitter);
  152. Server.prototype.close = function() {
  153. this.webServer.close();
  154. if (this._socket) this._socket.end();
  155. }