I need to understand how the code below works so I can better control incoming data generated from other JavaScript functions. Most of the people told me that I don't need to understand what I do. It would just add more complication. What I need to know is how to call a function. But is it even possible to reverse JavaScript call? var myFunc = function() {} myFunc.prototype.passData = function (data) { extract.start.call(this, data); } var extract = { start: function(data) { var self = this; var firstLength = data[1] & 0x7f; getData.call(self, firstLength); }, getData: function(length) { var self = this; self.firstData(4, function(data) { var mask = data; self.Data(length, function(data) { finish.call(self, mask, data); }); }); }, finish: function(mask, data) { // If this code works, it was written by ME. } } Code (markup): I want it to be as simple as this: function myFunc(data) { extract.start(data); } var extract = { start: function(data) { this.data = data; var firstLength = data[1] & 0x7f; this.getData(firstLength); }, getData: function(length) { firstData(4, function(data) { var mask = data; Data(length, function(data) { this.finish(mask, this.data); }); }); }, finish: function(mask, data) { // If this code works, it was written by ME. } } Code (markup): Thanks in advanced.
That code is a convoluted mess; really stupid in some parts. 1) why is it copy "this" to "self" 2) why is it creating a variables for no reason like "firstData" 3) self/this doesn't even appear to have a "firstData" method for it to even be calling, so getData should be bombing out. 4) what does "Data" do, since that's different from "data" can I at least assume that's a function declared somewhere else? Can't be sure what that's even supposed to do since it's unlikely we're seeing all of it, and if that is all of it then it shouldn't work... though I highly suspect we're seeing a nasty case of "objects for nothing". I guess the big question is, what's it fed for data, and what's it supposed to vomit out the other side?
Yes, I agree. The code is stupid. I'm not writing this.I take it from a library of tens thousand line of JavaScript. That library isn't work well so I decide to write my own. This is the only part I do not understand. That's why I've tried to reverse its engineer. It's websocket library. 1. I don't know. If you don't do it the code doesn't work. 2. To send data through websocket there is the header part and the message part. firstData is a function that separate header from the message. 3. I've no idea what are you talking about. I don't understand this. 4. The Data is a function that hold data from separated header. It is to be processed further. So I guess this function cannot be reversed. Here's the full code: // be warned of the headache The function I'm trying to solve called opcodes. It is down to the bottom. var util = require('util') , events = require('events') , http = require('http') , crypto = require('crypto') , clients = []; function WebSocketServer() { options = { host: '0.0.0.0', port: 443 }; var self = this; var server = http.createServer(function (req, res) { res.writeHead(200, {'Content-Type': 'text/plain'}); res.end(); }).listen(options.port, options.host); server.on('upgrade', function(req, socket) { self.handleUpgrade(req, socket); }); } util.inherits(WebSocketServer, events.EventEmitter); WebSocketServer.prototype.handleUpgrade = function(req, socket) { // calc key var key = req.headers['sec-websocket-key']; var shasum = crypto.createHash('sha1'); shasum.update(key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"); key = shasum.digest('base64'); var headers = [ 'HTTP/1.1 101 Switching Protocols' , 'Upgrade: websocket' , 'Connection: Upgrade' , 'Sec-WebSocket-Accept: ' + key ]; try { socket.write(headers.concat('', '').join('\r\n')); } catch (e) { // if the upgrade write fails, shut the connection down hard try { socket.destroy(); } catch (e) {} return; } var client = new WebSocket([req, socket]); // signal upgrade complete socket.removeListener('error', function() { try { socket.destroy(); } catch (e) {} }); this.emit('connection', client); } // WebSocket function WebSocket(address) { initAsServerClient.apply(this, address); } util.inherits(WebSocket, events.EventEmitter); WebSocket.prototype.send = function(data) { this._sender.send(data); } function initAsServerClient(req, socket) { var self = this; var receiver = new Receiver(); // receiver event handlers receiver.ontext = function (data) { self.emit('message', data); }; receiver.onbinary = function (data) { self.emit('message', data); }; this._sender = new Sender(socket); socket.on('data', function(data) { self.bytesReceived += data.length; receiver.add(data); }); } // Sender function Sender(socket) { this._socket = socket; } Sender.prototype.send = function(data, options) { var finalFragment = options && options.fin === false ? false : true; var mask = options && options.mask; var opcode = options && options.binary ? 2 : 1; this.frameAndSend(opcode, data, finalFragment, mask); }; Sender.prototype.frameAndSend = function(opcode, data, finalFragment, maskData) { data = new Buffer(data); var dataLength = data.length , dataOffset = maskData ? 6 : 2 , secondByte = dataLength; if (dataLength >= 65536) { dataOffset += 8; secondByte = 127; } else if (dataLength > 125) { dataOffset += 2; secondByte = 126; } var mergeBuffers = dataLength < 32768; var totalLength = mergeBuffers ? dataLength + dataOffset : dataOffset; var outputBuffer = new Buffer(totalLength); outputBuffer[0] = finalFragment ? opcode | 0x80 : opcode; switch (secondByte) { case 126: writeUInt16BE.call(outputBuffer, dataLength, 2); break; case 127: writeUInt32BE.call(outputBuffer, 0, 2); writeUInt32BE.call(outputBuffer, dataLength, 6); } outputBuffer[1] = secondByte; data.copy(outputBuffer, dataOffset); try { this._socket.write(outputBuffer, 'binary'); } catch (e) { this.emit('error', e); } }; function writeUInt16BE(value, offset) { this[offset] = (value & 0xff00)>>8; this[offset+1] = value & 0xff; } function writeUInt32BE(value, offset) { this[offset] = (value & 0xff000000)>>24; this[offset+1] = (value & 0xff0000)>>16; this[offset+2] = (value & 0xff00)>>8; this[offset+3] = value & 0xff; } // Receiver function Receiver () { this.overflow = []; this.headerBuffer = new Buffer(10); this.expectOffset = 0; this.currentMessage = []; this.expectHeader(2, this.processPacket); } Receiver.prototype.add = function(data) { var toRead = Math.min(data.length, this.expectBuffer.length - this.expectOffset); fastCopy(toRead, data, this.expectBuffer, this.expectOffset); this.expectOffset += toRead; this.overflow.push(data.slice(toRead)); while (this.expectBuffer && this.expectOffset == this.expectBuffer.length) { var bufferForHandler = this.expectBuffer; this.expectBuffer = null; this.expectOffset = 0; this.expectHandler.call(this, bufferForHandler); } }; Receiver.prototype.expectHeader = function(length, handler) { this.expectBuffer = this.headerBuffer.slice(this.expectOffset, this.expectOffset + length); this.expectHandler = handler; var toRead = length; while (toRead > 0 && this.overflow.length > 0) { var fromOverflow = this.overflow.pop(); if (toRead < fromOverflow.length) this.overflow.push(fromOverflow.slice(toRead)); var read = Math.min(fromOverflow.length, toRead); fastCopy(read, fromOverflow, this.expectBuffer, this.expectOffset); this.expectOffset += read; toRead -= read; } }; Receiver.prototype.expectData = function(length, handler) { this.expectBuffer = this.allocateFromPool(length); this.expectHandler = handler; var toRead = length; while (toRead > 0 && this.overflow.length > 0) { var fromOverflow = this.overflow.pop(); if (toRead < fromOverflow.length) this.overflow.push(fromOverflow.slice(toRead)); var read = Math.min(fromOverflow.length, toRead); fastCopy(read, fromOverflow, this.expectBuffer, this.expectOffset); this.expectOffset += read; toRead -= read; } }; Receiver.prototype.allocateFromPool = function(length) { var newBuf = new Buffer(length); this._buffer = newBuf; this._offset = 0; var buf = this._buffer.slice(this._offset, this._offset + length); this._offset += length; return buf; }; Receiver.prototype.processPacket = function (data) { opcodes['1'].start.call(this, data); }; Receiver.prototype.unmask = function (mask, buf) { var maskNum = mask.readUInt32LE(0, true); var length = buf.length; var i = 0; for (; i < length - 3; i += 4) { var num = maskNum ^ buf.readUInt32LE(i, true); if (num < 0) num = 4294967296 + num; buf.writeUInt32LE(num, i, true); } switch (length % 4) { case 3: buf[i + 2] = buf[i + 2] ^ mask[2]; case 2: buf[i + 1] = buf[i + 1] ^ mask[1]; case 1: buf[i] = buf[i] ^ mask[0]; case 0:; } return buf != null ? buf.toString('utf8') : ''; }; function fastCopy(length, srcBuffer, dstBuffer, dstOffset) { switch (length) { default: srcBuffer.copy(dstBuffer, dstOffset, 0, length); break; case 16: dstBuffer[dstOffset+15] = srcBuffer[15]; case 15: dstBuffer[dstOffset+14] = srcBuffer[14]; case 14: dstBuffer[dstOffset+13] = srcBuffer[13]; case 13: dstBuffer[dstOffset+12] = srcBuffer[12]; case 12: dstBuffer[dstOffset+11] = srcBuffer[11]; case 11: dstBuffer[dstOffset+10] = srcBuffer[10]; case 10: dstBuffer[dstOffset+9] = srcBuffer[9]; case 9: dstBuffer[dstOffset+8] = srcBuffer[8]; case 8: dstBuffer[dstOffset+7] = srcBuffer[7]; case 7: dstBuffer[dstOffset+6] = srcBuffer[6]; case 6: dstBuffer[dstOffset+5] = srcBuffer[5]; case 5: dstBuffer[dstOffset+4] = srcBuffer[4]; case 4: dstBuffer[dstOffset+3] = srcBuffer[3]; case 3: dstBuffer[dstOffset+2] = srcBuffer[2]; case 2: dstBuffer[dstOffset+1] = srcBuffer[1]; case 1: dstBuffer[dstOffset] = srcBuffer[0]; } } var opcodes = { '1': { start: function(data) { var self = this; var firstLength = data[1] & 0x7f; opcodes['1'].getData.call(self, firstLength); }, getData: function(length) { var self = this; self.expectHeader(4, function(data) { var mask = data; self.expectData(length, function(data) { opcodes['1'].finish.call(self, mask, data); }); }); }, finish: function(mask, data) { var packet = this.unmask(mask, data, true); if (packet != null) this.currentMessage.push(packet); var messageBuffer = this.currentMessage; this.ontext(messageBuffer.toString('utf8')); this.currentMessage = []; this.expectHeader(2, this.processPacket); } } } // Server var wss = new WebSocketServer(); wss.on("connection", function(ws) { clients.push(ws); ws.on('message', function(message) { console.log(message); for(var i = 0, j = clients.length; i < j; i += 1) { clients[i].send(message); } }); ws.on('close', function(message) { var index = clients.indexOf(ws); if (index !== -1) { clients.splice(index, 1); } }); }); Code (markup):