Skip to content

Instantly share code, notes, and snippets.

@DaCurse
Last active January 17, 2018 01:34
Show Gist options
  • Save DaCurse/79c027f7aa00160051d900119e8e347e to your computer and use it in GitHub Desktop.
Save DaCurse/79c027f7aa00160051d900119e8e347e to your computer and use it in GitHub Desktop.
A websocket frame parser in javascript
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