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.

112 lines
3.2 KiB

4 years ago
  1. 'use strict';
  2. var util = require('util'),
  3. HttpParser = require('../http_parser'),
  4. Base = require('./base'),
  5. Draft75 = require('./draft75'),
  6. Draft76 = require('./draft76'),
  7. Hybi = require('./hybi');
  8. var Server = function(options) {
  9. Base.call(this, null, null, options);
  10. this._http = new HttpParser('request');
  11. };
  12. util.inherits(Server, Base);
  13. var instance = {
  14. EVENTS: ['open', 'message', 'error', 'close'],
  15. _bindEventListeners: function() {
  16. this.messages.on('error', function() {});
  17. this.on('error', function() {});
  18. },
  19. parse: function(chunk) {
  20. if (this._delegate) return this._delegate.parse(chunk);
  21. this._http.parse(chunk);
  22. if (!this._http.isComplete()) return;
  23. this.method = this._http.method;
  24. this.url = this._http.url;
  25. this.headers = this._http.headers;
  26. this.body = this._http.body;
  27. var self = this;
  28. this._delegate = Server.http(this, this._options);
  29. this._delegate.messages = this.messages;
  30. this._delegate.io = this.io;
  31. this._open();
  32. this.EVENTS.forEach(function(event) {
  33. this._delegate.on(event, function(e) { self.emit(event, e) });
  34. }, this);
  35. this.protocol = this._delegate.protocol;
  36. this.version = this._delegate.version;
  37. this.parse(this._http.body);
  38. this.emit('connect', new Base.ConnectEvent());
  39. },
  40. _open: function() {
  41. this.__queue.forEach(function(msg) {
  42. this._delegate[msg[0]].apply(this._delegate, msg[1]);
  43. }, this);
  44. this.__queue = [];
  45. }
  46. };
  47. ['addExtension', 'setHeader', 'start', 'frame', 'text', 'binary', 'ping', 'close'].forEach(function(method) {
  48. instance[method] = function() {
  49. if (this._delegate) {
  50. return this._delegate[method].apply(this._delegate, arguments);
  51. } else {
  52. this.__queue.push([method, arguments]);
  53. return true;
  54. }
  55. };
  56. });
  57. for (var key in instance)
  58. Server.prototype[key] = instance[key];
  59. Server.isSecureRequest = function(request) {
  60. if (request.connection && request.connection.authorized !== undefined) return true;
  61. if (request.socket && request.socket.secure) return true;
  62. var headers = request.headers;
  63. if (!headers) return false;
  64. if (headers['https'] === 'on') return true;
  65. if (headers['x-forwarded-ssl'] === 'on') return true;
  66. if (headers['x-forwarded-scheme'] === 'https') return true;
  67. if (headers['x-forwarded-proto'] === 'https') return true;
  68. return false;
  69. };
  70. Server.determineUrl = function(request) {
  71. var scheme = this.isSecureRequest(request) ? 'wss:' : 'ws:';
  72. return scheme + '//' + request.headers.host + request.url;
  73. };
  74. Server.http = function(request, options) {
  75. options = options || {};
  76. if (options.requireMasking === undefined) options.requireMasking = true;
  77. var headers = request.headers,
  78. version = headers['sec-websocket-version'],
  79. key = headers['sec-websocket-key'],
  80. key1 = headers['sec-websocket-key1'],
  81. key2 = headers['sec-websocket-key2'],
  82. url = this.determineUrl(request);
  83. if (version || key)
  84. return new Hybi(request, url, options);
  85. else if (key1 || key2)
  86. return new Draft76(request, url, options);
  87. else
  88. return new Draft75(request, url, options);
  89. };
  90. module.exports = Server;