12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970 |
- 'use strict'
- const { createInflateRaw, Z_DEFAULT_WINDOWBITS } = require('node:zlib')
- const { isValidClientWindowBits } = require('./util')
- const tail = Buffer.from([0x00, 0x00, 0xff, 0xff])
- const kBuffer = Symbol('kBuffer')
- const kLength = Symbol('kLength')
- class PerMessageDeflate {
- /** @type {import('node:zlib').InflateRaw} */
- #inflate
- #options = {}
- constructor (extensions) {
- this.#options.serverNoContextTakeover = extensions.has('server_no_context_takeover')
- this.#options.serverMaxWindowBits = extensions.get('server_max_window_bits')
- }
- decompress (chunk, fin, callback) {
- // An endpoint uses the following algorithm to decompress a message.
- // 1. Append 4 octets of 0x00 0x00 0xff 0xff to the tail end of the
- // payload of the message.
- // 2. Decompress the resulting data using DEFLATE.
- if (!this.#inflate) {
- let windowBits = Z_DEFAULT_WINDOWBITS
- if (this.#options.serverMaxWindowBits) { // empty values default to Z_DEFAULT_WINDOWBITS
- if (!isValidClientWindowBits(this.#options.serverMaxWindowBits)) {
- callback(new Error('Invalid server_max_window_bits'))
- return
- }
- windowBits = Number.parseInt(this.#options.serverMaxWindowBits)
- }
- this.#inflate = createInflateRaw({ windowBits })
- this.#inflate[kBuffer] = []
- this.#inflate[kLength] = 0
- this.#inflate.on('data', (data) => {
- this.#inflate[kBuffer].push(data)
- this.#inflate[kLength] += data.length
- })
- this.#inflate.on('error', (err) => {
- this.#inflate = null
- callback(err)
- })
- }
- this.#inflate.write(chunk)
- if (fin) {
- this.#inflate.write(tail)
- }
- this.#inflate.flush(() => {
- const full = Buffer.concat(this.#inflate[kBuffer], this.#inflate[kLength])
- this.#inflate[kBuffer].length = 0
- this.#inflate[kLength] = 0
- callback(null, full)
- })
- }
- }
- module.exports = { PerMessageDeflate }
|