Last active
January 17, 2018 01:34
-
-
Save DaCurse/79c027f7aa00160051d900119e8e347e to your computer and use it in GitHub Desktop.
A websocket frame parser in javascript
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class WSFrame { | |
constructor(buffer) { | |
if(buffer.byteLength < 2) { | |
throw new Error('Incomplete frame: Header data missing'); | |
} | |
this.fin = 0; | |
this.opcode = 0; | |
this.mask = 0; | |
this.payloadLength = 0; | |
this.maskKey = null; | |
this.length = 0; | |
this._message = null; | |
this.frameLength = 0; | |
this.fin = buffer[0] >> 7; | |
this.opcode = buffer[0] & 0b1111; | |
this.payloadLength = buffer[1] & 0b1111111; | |
this.mask = buffer[1] >> 7; | |
buffer = buffer.slice(2); | |
if(this.payloadLength < 126) { | |
this.length = this.payloadLength; | |
if(this.mask) { | |
this.frameLength = 6 + this.length; | |
} else { | |
this.frameLength = 2 + this.length; | |
} | |
if(buffer.byteLength < 4 && this.mask) { | |
throw new Error('Incomplete frame: Mask key missing'); | |
} | |
if(this.mask) { | |
this.maskKey = buffer.slice(0, 4); | |
buffer = buffer.slice(4); | |
} | |
else { | |
buffer = buffer.slice(0, this.length); | |
} | |
} else if(this.payloadLength == 126) { | |
if(buffer.byteLength < 6 && this.mask) { | |
throw new Error('Incomplete frame: Mask key missing'); | |
} | |
let bytes = [ | |
[0, 1], | |
[1, 0] | |
]; | |
for(let b of bytes) { | |
let k, i; | |
for(k = 0, i = 1; i < b.length ; i++, k++) { | |
this.length += buffer[k] * 1 << (8*i); | |
} | |
} | |
if(this.mask) { | |
this.frameLength = 8 + this.length; | |
} | |
else { | |
this.frameLength = 4 + this.length; | |
} | |
buffer = buffer.slice(2); | |
if(this.mask) { | |
this.maskKey = buffer.slice(0, 4); | |
buffer = buffer.slice(4); | |
} | |
else { | |
buffer = buffer.slice(0, this.length); | |
} | |
} else { | |
if(buffer.byteLength < 10 && this.mask) { | |
throw new Error('Incomplete frame: Mask key missing'); | |
} | |
let bytes = [ | |
[0, 7], | |
[1, 6], | |
[2, 5], | |
[3, 4], | |
[4, 3], | |
[5, 2], | |
[6, 1], | |
[7, 0] | |
]; | |
for(let b of bytes) { | |
let k, i; | |
for(k = 0, i = 1; i < b.length ; i++, k++) { | |
this.length += buffer[k] * 1 << (8*i); | |
} | |
} | |
if(this.mask) { | |
this.frameLength = 14 + this.length; | |
} else { | |
this.frameLength = 10 + this.length; | |
} | |
buffer = buffer.slice(8); | |
if(this.mask) { | |
this.maskKey = buffer.slice(0, 4); | |
buffer = buffer.slice(4); | |
} else { | |
buffer = buffer[this.length]; | |
} | |
} | |
this._message = buffer; | |
} | |
get message() { | |
if(!this.mask) { | |
return this._message.toString('utf8'); | |
} else { | |
let message = Buffer.alloc(this._message.length); | |
for(let i = 0; i < this.length; i++) { | |
message[i] = this._message[i] ^ this.maskKey[i % 4]; | |
} | |
return message.toString('utf8'); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment