draft75.js 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. 'use strict';
  2. var Buffer = require('safe-buffer').Buffer,
  3. Base = require('./base'),
  4. util = require('util');
  5. var Draft75 = function(request, url, options) {
  6. Base.apply(this, arguments);
  7. this._stage = 0;
  8. this.version = 'hixie-75';
  9. this._headers.set('Upgrade', 'WebSocket');
  10. this._headers.set('Connection', 'Upgrade');
  11. this._headers.set('WebSocket-Origin', this._request.headers.origin);
  12. this._headers.set('WebSocket-Location', this.url);
  13. };
  14. util.inherits(Draft75, Base);
  15. var instance = {
  16. close: function() {
  17. if (this.readyState === 3) return false;
  18. this.readyState = 3;
  19. this.emit('close', new Base.CloseEvent(null, null));
  20. return true;
  21. },
  22. parse: function(chunk) {
  23. if (this.readyState > 1) return;
  24. this._reader.put(chunk);
  25. this._reader.eachByte(function(octet) {
  26. var message;
  27. switch (this._stage) {
  28. case -1:
  29. this._body.push(octet);
  30. this._sendHandshakeBody();
  31. break;
  32. case 0:
  33. this._parseLeadingByte(octet);
  34. break;
  35. case 1:
  36. this._length = (octet & 0x7F) + 128 * this._length;
  37. if (this._closing && this._length === 0) {
  38. return this.close();
  39. }
  40. else if ((octet & 0x80) !== 0x80) {
  41. if (this._length === 0) {
  42. this._stage = 0;
  43. }
  44. else {
  45. this._skipped = 0;
  46. this._stage = 2;
  47. }
  48. }
  49. break;
  50. case 2:
  51. if (octet === 0xFF) {
  52. this._stage = 0;
  53. message = Buffer.from(this._buffer).toString('utf8', 0, this._buffer.length);
  54. this.emit('message', new Base.MessageEvent(message));
  55. }
  56. else {
  57. if (this._length) {
  58. this._skipped += 1;
  59. if (this._skipped === this._length)
  60. this._stage = 0;
  61. } else {
  62. this._buffer.push(octet);
  63. if (this._buffer.length > this._maxLength) return this.close();
  64. }
  65. }
  66. break;
  67. }
  68. }, this);
  69. },
  70. frame: function(buffer) {
  71. if (this.readyState === 0) return this._queue([buffer]);
  72. if (this.readyState > 1) return false;
  73. if (typeof buffer !== 'string') buffer = buffer.toString();
  74. var length = Buffer.byteLength(buffer),
  75. frame = Buffer.allocUnsafe(length + 2);
  76. frame[0] = 0x00;
  77. frame.write(buffer, 1);
  78. frame[frame.length - 1] = 0xFF;
  79. this._write(frame);
  80. return true;
  81. },
  82. _handshakeResponse: function() {
  83. var start = 'HTTP/1.1 101 Web Socket Protocol Handshake',
  84. headers = [start, this._headers.toString(), ''];
  85. return Buffer.from(headers.join('\r\n'), 'utf8');
  86. },
  87. _parseLeadingByte: function(octet) {
  88. if ((octet & 0x80) === 0x80) {
  89. this._length = 0;
  90. this._stage = 1;
  91. } else {
  92. delete this._length;
  93. delete this._skipped;
  94. this._buffer = [];
  95. this._stage = 2;
  96. }
  97. }
  98. };
  99. for (var key in instance)
  100. Draft75.prototype[key] = instance[key];
  101. module.exports = Draft75;