* Runs whenever a new chunk is received. * Callback is called whenever there are no more chunks buffering, * or not enough bytes are buffered to parse.
(callback)
| 63371 | this.#byteOffset += chunk.length; |
| 63372 | this.run(callback); |
| 63373 | } |
| 63374 | /** |
| 63375 | * Runs whenever a new chunk is received. |
| 63376 | * Callback is called whenever there are no more chunks buffering, |
| 63377 | * or not enough bytes are buffered to parse. |
| 63378 | */ |
| 63379 | run(callback) { |
| 63380 | while (true) { |
| 63381 | if (this.#state === parserStates.INFO) { |
| 63382 | if (this.#byteOffset < 2) { |
| 63383 | return callback(); |
| 63384 | } |
| 63385 | const buffer = this.consume(2); |
| 63386 | this.#info.fin = (buffer[0] & 128) !== 0; |
| 63387 | this.#info.opcode = buffer[0] & 15; |
| 63388 | this.#info.originalOpcode ??= this.#info.opcode; |
| 63389 | this.#info.fragmented = !this.#info.fin && this.#info.opcode !== opcodes.CONTINUATION; |
| 63390 | if (this.#info.fragmented && this.#info.opcode !== opcodes.BINARY && this.#info.opcode !== opcodes.TEXT) { |
| 63391 | failWebsocketConnection(this.ws, "Invalid frame type was fragmented."); |
| 63392 | return; |
| 63393 | } |
| 63394 | const payloadLength = buffer[1] & 127; |
| 63395 | if (payloadLength <= 125) { |
| 63396 | this.#info.payloadLength = payloadLength; |
| 63397 | this.#state = parserStates.READ_DATA; |
| 63398 | } else if (payloadLength === 126) { |
| 63399 | this.#state = parserStates.PAYLOADLENGTH_16; |
| 63400 | } else if (payloadLength === 127) { |
| 63401 | this.#state = parserStates.PAYLOADLENGTH_64; |
| 63402 | } |
| 63403 | if (this.#info.fragmented && payloadLength > 125) { |
| 63404 | failWebsocketConnection(this.ws, "Fragmented frame exceeded 125 bytes."); |
| 63405 | return; |
| 63406 | } else if ((this.#info.opcode === opcodes.PING || this.#info.opcode === opcodes.PONG || this.#info.opcode === opcodes.CLOSE) && payloadLength > 125) { |
| 63407 | failWebsocketConnection(this.ws, "Payload length for control frame exceeded 125 bytes."); |
| 63408 | return; |
| 63409 | } else if (this.#info.opcode === opcodes.CLOSE) { |
| 63410 | if (payloadLength === 1) { |
| 63411 | failWebsocketConnection(this.ws, "Received close frame with a 1-byte body."); |
| 63412 | return; |
| 63413 | } |
| 63414 | const body = this.consume(payloadLength); |
| 63415 | this.#info.closeInfo = this.parseCloseBody(false, body); |
| 63416 | if (!this.ws[kSentClose]) { |
| 63417 | const body2 = Buffer.allocUnsafe(2); |
| 63418 | body2.writeUInt16BE(this.#info.closeInfo.code, 0); |
| 63419 | const closeFrame = new WebsocketFrameSend(body2); |
| 63420 | this.ws[kResponse].socket.write( |
| 63421 | closeFrame.createFrame(opcodes.CLOSE), |
| 63422 | (err) => { |
| 63423 | if (!err) { |
| 63424 | this.ws[kSentClose] = true; |
| 63425 | } |
| 63426 | } |
| 63427 | ); |
| 63428 | } |
| 63429 | this.ws[kReadyState] = states.CLOSING; |
| 63430 | this.ws[kReceivedClose] = true; |
no test coverage detected