UNPKG

qws

Version:

An HTML5 Web Sockets Server Module

234 lines (218 loc) 5.29 kB
// Generated by CoffeeScript 1.6.3 var Frame, crypto, inflate, opcodes, opcodesMap, pack, unmask, unpack, zlib; zlib = require('zlib'); crypto = require('crypto'); unmask = function(data, mask) { var d1, i, mod, _i, _ref; d1 = new Buffer(data.length); for (i = _i = 0, _ref = data.length; _i < _ref; i = _i += 4) { d1[i + 3] = data[i + 3] ^ mask[3]; d1[i + 2] = data[i + 2] ^ mask[2]; d1[i + 1] = data[i + 1] ^ mask[1]; d1[i] = data[i] ^ mask[0]; } mod = data.length % 4; if (mod > 0) { d1[i] = data[i] ^ mask[0]; } if (mod > 1) { d1[i + 1] = data[i + 1] ^ mask[0]; } if (mod > 2) { d1[i + 2] = data[i + 2] ^ mask[0]; } return d1; }; inflate = function(frame, stream, cb) { var b, len; if (!frame.rsv1) { return cb(null, frame); } stream.once('error', function(err) { return cb(err); }); stream.once('data', function(data) { frame.data = data; return cb(null, frame); }); len = frame.data.length; b = new Buffer(len + 4); b[len] = 0x00; b[len + 1] = 0x00; b[len + 2] = 0xff; b[len + 3] = 0xff; frame.data.copy(b); stream.write(b); }; opcodes = ['continue', 'text', 'binary', 'non-control 3', 'non-control 4', 'non-control 5', 'non-control 6', ' non-control 7', 'close', 'ping', 'pong', 'control B', 'control C', 'control D', 'control E', ' control F']; unpack = function(buf, frame) { var b1, b2, idx; if (frame) { if (buf.length > frame.left) { frame.data.push(buf.slice(0, frame.left)); buf = buf.slice(frame.left); frame.left = 0; } else { frame.data.push(buf); frame.left -= buf.length; buf = null; } } else { b1 = buf[0]; b2 = buf[1]; frame = { fin: 0 < (b1 & 0x80), rsv1: 0 < (b1 & 0x40), rsv2: 0 < (b1 & 0x20), rsv3: 0 < (b1 & 0x10), opcode: opcodes[b1 & 0xf], mask: 0 < (b2 & 128), length: b2 & 127, data: [], left: 0, done: false }; idx = 2; if (frame.length > 0) { if (frame.length === 126) { frame.length = buf.readUInt16BE(2, true); idx = 4; } else if (frame.length === 127) { frame.length = buf.readUInt32BE(2, true) * 0xffffffff + buf.readUInt32BE(6, true); idx = 10; } if (frame.mask) { frame.maskKey = buf.slice(idx, idx += 4); } frame.data.push(buf.slice(idx, idx += frame.length)); frame.left = frame.length - frame.data[0].length; } if (buf.length > idx) { buf = buf.slice(idx); } else { buf = null; } } if (frame.left === 0) { if (frame.length > 0) { frame.data = Buffer.concat(frame.data); if (frame.mask && frame.length > 0) { frame.data = unmask(frame.data, frame.maskKey); } } else { frame.data = null; } frame.done = true; delete frame.left; } return [frame, buf]; }; pack = function(frame, data) { var b1, b2, buf, dlen, lenFix, plen; b1 = opcodesMap[frame.opcode]; if (frame.rsv3) { b1 |= 0x10; } if (frame.rsv2) { b1 |= 0x20; } if (frame.rsv1) { b1 |= 0x40; } if (frame.fin) { b1 |= 0x80; } dlen = data != null ? data.length : 0; if (dlen > 0xffff) { lenFix = 10; plen = 127; } else if (dlen >= 126) { lenFix = 4; plen = 126; } else { lenFix = 2; plen = dlen; } if (dlen === 0) { frame.mask = false; } b2 = plen; if (frame.mask) { b2 |= 0x80; buf = new Buffer(lenFix + 4 + dlen); frame.maskKey = crypto.randomBytes(4); frame.maskKey.copy(buf, lenFix); lenFix += 4; data = unmask(data, frame.maskKey); } else { buf = new Buffer(lenFix + dlen); } buf[0] = b1; buf[1] = b2; if (dlen > 0xffff) { buf.writeUInt32BE(Math.floor(dlen / 0xffffffff), 2, true); buf.writeUInt32BE(dlen % 0xffffffff, 6, true); } else if (dlen >= 126) { buf.writeUInt16BE(dlen, 2, true); } if (dlen > 0) { data.copy(buf, lenFix); } return buf; }; opcodesMap = { 'continue': 0, 'text': 1, 'binary': 2, 'close': 8, 'ping': 9, 'pong': 10 }; Frame = (function() { function Frame(prop) { var k; this.minDeflateLength = 32; this.opcode = 'text'; this.fin = false; this.rsv1 = false; this.rsv2 = false; this.rsv3 = false; this.mask = false; this.data = null; for (k in prop) { if (prop) { this[k] = prop[k]; } } } Frame.prototype.pack = function(deflate, cb) { var data, _this = this; if (opcodesMap[this.opcode] == null) { return cb(new Error("Opcode Not Found \"" + this.opcode + "\"")); } if (this.data == null) { data = null; } else if (this.data instanceof Buffer) { data = this.data; } else { data = new Buffer(typeof this.data === 'string' ? this.data : this.data.toString()); } if (deflate && data.length < this.minDeflateLength) { deflate = false; } if (deflate) { this.rsv1 = true; zlib.deflateRaw(data, function(err, data) { cb(null, pack(_this, data)); }); } else { this.rsv1 = false; cb(null, pack(this, data)); } }; return Frame; })(); exports.unpack = unpack; exports.inflate = inflate; exports.Frame = Frame;