[d24f17c] | 1 | 'use strict'
|
---|
| 2 |
|
---|
| 3 | const { maxUnsigned16Bit } = require('./constants')
|
---|
| 4 |
|
---|
| 5 | /** @type {import('crypto')} */
|
---|
| 6 | let crypto
|
---|
| 7 | try {
|
---|
| 8 | crypto = require('crypto')
|
---|
| 9 | } catch {
|
---|
| 10 |
|
---|
| 11 | }
|
---|
| 12 |
|
---|
| 13 | class WebsocketFrameSend {
|
---|
| 14 | /**
|
---|
| 15 | * @param {Buffer|undefined} data
|
---|
| 16 | */
|
---|
| 17 | constructor (data) {
|
---|
| 18 | this.frameData = data
|
---|
| 19 | this.maskKey = crypto.randomBytes(4)
|
---|
| 20 | }
|
---|
| 21 |
|
---|
| 22 | createFrame (opcode) {
|
---|
| 23 | const bodyLength = this.frameData?.byteLength ?? 0
|
---|
| 24 |
|
---|
| 25 | /** @type {number} */
|
---|
| 26 | let payloadLength = bodyLength // 0-125
|
---|
| 27 | let offset = 6
|
---|
| 28 |
|
---|
| 29 | if (bodyLength > maxUnsigned16Bit) {
|
---|
| 30 | offset += 8 // payload length is next 8 bytes
|
---|
| 31 | payloadLength = 127
|
---|
| 32 | } else if (bodyLength > 125) {
|
---|
| 33 | offset += 2 // payload length is next 2 bytes
|
---|
| 34 | payloadLength = 126
|
---|
| 35 | }
|
---|
| 36 |
|
---|
| 37 | const buffer = Buffer.allocUnsafe(bodyLength + offset)
|
---|
| 38 |
|
---|
| 39 | // Clear first 2 bytes, everything else is overwritten
|
---|
| 40 | buffer[0] = buffer[1] = 0
|
---|
| 41 | buffer[0] |= 0x80 // FIN
|
---|
| 42 | buffer[0] = (buffer[0] & 0xF0) + opcode // opcode
|
---|
| 43 |
|
---|
| 44 | /*! ws. MIT License. Einar Otto Stangvik <einaros@gmail.com> */
|
---|
| 45 | buffer[offset - 4] = this.maskKey[0]
|
---|
| 46 | buffer[offset - 3] = this.maskKey[1]
|
---|
| 47 | buffer[offset - 2] = this.maskKey[2]
|
---|
| 48 | buffer[offset - 1] = this.maskKey[3]
|
---|
| 49 |
|
---|
| 50 | buffer[1] = payloadLength
|
---|
| 51 |
|
---|
| 52 | if (payloadLength === 126) {
|
---|
| 53 | buffer.writeUInt16BE(bodyLength, 2)
|
---|
| 54 | } else if (payloadLength === 127) {
|
---|
| 55 | // Clear extended payload length
|
---|
| 56 | buffer[2] = buffer[3] = 0
|
---|
| 57 | buffer.writeUIntBE(bodyLength, 4, 6)
|
---|
| 58 | }
|
---|
| 59 |
|
---|
| 60 | buffer[1] |= 0x80 // MASK
|
---|
| 61 |
|
---|
| 62 | // mask body
|
---|
| 63 | for (let i = 0; i < bodyLength; i++) {
|
---|
| 64 | buffer[offset + i] = this.frameData[i] ^ this.maskKey[i % 4]
|
---|
| 65 | }
|
---|
| 66 |
|
---|
| 67 | return buffer
|
---|
| 68 | }
|
---|
| 69 | }
|
---|
| 70 |
|
---|
| 71 | module.exports = {
|
---|
| 72 | WebsocketFrameSend
|
---|
| 73 | }
|
---|