Compresión

El módulo compress codifica y decodifica cadenas con gzip, Brotli, Zstandard, DEFLATE sin procesar y zlib.

Esta es una referencia de API con recetas parciales de HTTP y almacenamiento. Cada operación materializa toda su entrada y salida como cadenas Lua; usa las API de archivo o stream cuando los datos deban seguir procesándose en streaming. Los ejemplos presuponen que la entrada habilita compress y cualquier otro módulo necesario, como json o http.

Carga

local compress = require("compress")

Añade compress a la lista modules: de la entrada ejecutable antes de requerirlo.

GZIP

Gzip está definido por RFC 1952.

Comprimir {id="gzip-compress"}

-- Compress for HTTP response
local body, json_err = json.encode(large_response)
if json_err then return nil, json_err end
local compressed, err = compress.gzip.encode(body)
if err then
    return nil, err
end

-- Set Content-Encoding header
local header_err = res:set_header("Content-Encoding", "gzip")
if header_err then return nil, header_err end
local write_err = res:write(compressed)
if write_err then return nil, write_err end

-- Maximum compression for storage
local archived, archive_err = compress.gzip.encode(data, {level = 9})
if archive_err then return nil, archive_err end

-- Fast compression for real-time
local fast, fast_err = compress.gzip.encode(data, {level = 1})
if fast_err then return nil, fast_err end
Parámetro Tipo Descripción
data string Datos a comprimir
options table? Opciones de codificación opcionales

Opciones {id="gzip-compress-options"}

Campo Tipo Descripción
level integer Nivel de compresión 1-9 (predeterminado: 6)

Devuelve: string, error

Descomprimir {id="gzip-decompress"}

-- Decompress HTTP request
local content_encoding, header_err = req:header("Content-Encoding")
if header_err then return nil, header_err end
if content_encoding == "gzip" then
    local body, body_err = req:body()
    if body_err then return nil, body_err end
    local decompressed, err = compress.gzip.decode(body)
    if err then
        return nil, errors.new("Invalid gzip data"):kind(errors.INVALID)
    end
    body = decompressed
end

-- Decompress with size limit (prevent zip bombs)
local decompressed, err = compress.gzip.decode(data, {max_size = 10 * 1024 * 1024})
if err then
    return nil, errors.new("Decompressed size exceeds 10MB limit"):kind(errors.INVALID)
end
Parámetro Tipo Descripción
data string Datos comprimidos GZIP
options table? Opciones de decodificación opcionales

Opciones {id="gzip-decompress-options"}

Campo Tipo Descripción
max_size integer Tamaño máximo descomprimido en bytes (predeterminado: 128 MB; máximo: 1 GB)

Devuelve: string, error

Brotli

Brotli está definido por RFC 7932 y se utiliza habitualmente para contenido de texto comprimido.

Comprimir {id="brotli-compress"}

-- Best for static assets and text content
local compressed, err = compress.brotli.encode(html_content, {level = 11})
if err then return nil, err end

-- Store `compressed` through the application's cache contract if needed.

-- Moderate compression for API responses
local compressed, err = compress.brotli.encode(json_data, {level = 4})
if err then return nil, err end
Parámetro Tipo Descripción
data string Datos a comprimir
options table? Opciones de codificación opcionales

Opciones {id="brotli-compress-options"}

Campo Tipo Descripción
level integer Nivel de compresión 0-11 (predeterminado: 6)

Devuelve: string, error

Descomprimir {id="brotli-decompress"}

local decompressed, err = compress.brotli.decode(compressed_data)
if err then
    return nil, err
end

-- With size limit
local decompressed, err = compress.brotli.decode(data, {max_size = 50 * 1024 * 1024})
if err then return nil, err end
Parámetro Tipo Descripción
data string Datos comprimidos Brotli
options table? Opciones de decodificación opcionales

Opciones {id="brotli-decompress-options"}

Campo Tipo Descripción
max_size integer Tamaño máximo descomprimido en bytes (predeterminado: 128 MB; máximo: 1 GB)

Devuelve: string, error

Zstandard

Zstandard es un formato de compresión de propósito general definido por RFC 8878.

Comprimir {id="zstd-compress"}

-- Good balance of speed and ratio
local compressed, err = compress.zstd.encode(binary_data)
if err then return nil, err end

-- Higher compression for archival
local archived, archive_err = compress.zstd.encode(data, {level = 19})
if archive_err then return nil, archive_err end

-- Fast mode for latency-sensitive payloads
local fast, fast_err = compress.zstd.encode(data, {level = 1})
if fast_err then return nil, fast_err end
Parámetro Tipo Descripción
data string Datos a comprimir
options table? Opciones de codificación opcionales

Opciones {id="zstd-compress-options"}

Campo Tipo Descripción
level integer Nivel de compresión 1-22 (predeterminado: 3)
dict string? Bytes de diccionario Zstd de train_dict (por defecto: ninguno)

Devuelve: string, error

Descomprimir {id="zstd-decompress"}

local decompressed, err = compress.zstd.decode(compressed_data)
if err then
    return nil, err
end
Parámetro Tipo Descripción
data string Datos comprimidos Zstandard
options table? Opciones de decodificación opcionales

Opciones {id="zstd-decompress-options"}

Campo Tipo Descripción
max_size integer Tamaño máximo descomprimido en bytes (predeterminado: 128 MB; máximo: 1 GB)
dict string? Bytes de diccionario Zstd (deben coincidir con el dict usado al codificar)

Devuelve: string, error

Diccionarios {id="zstd-dictionaries"}

Entrena un diccionario a partir de payloads de muestra similares y pásalo mediante la opción dict a encode y decode. La decodificación requiere el mismo diccionario que se usó para codificar.

local dict, err = compress.zstd.train_dict(samples, { size = 112640 })
if err then return nil, err end
local packed, pack_err = compress.zstd.encode(data, { dict = dict })
if pack_err then return nil, pack_err end
local original, decode_err = compress.zstd.decode(packed, { dict = dict })
if decode_err then return nil, decode_err end

train_dict(samples, options?)

Parámetro Tipo Descripción
samples string[] Muestras de entrenamiento (al menos una >= 8 bytes)
options table? size (integer, bytes objetivo del dict, 256-1048576, por defecto 114688), id (integer, por defecto 0), level (integer, 1-22)

Devuelve: string, error (los bytes del diccionario)

inspect_dict(dict)

Parámetro Tipo Descripción
dict string Bytes del diccionario

Devuelve: table, error — {id: integer, content_size: integer}

Deflate

DEFLATE sin procesar está definido por RFC 1951 y también se usa dentro de otros formatos.

Comprimir {id="deflate-compress"}

local compressed, err = compress.deflate.encode(data, {level = 6})
if err then return nil, err end
Parámetro Tipo Descripción
data string Datos a comprimir
options table? Opciones de codificación opcionales

Opciones {id="deflate-compress-options"}

Campo Tipo Descripción
level integer Nivel de compresión 1-9 (predeterminado: 6)

Devuelve: string, error

Descomprimir {id="deflate-decompress"}

local decompressed, err = compress.deflate.decode(compressed)
if err then return nil, err end
Parámetro Tipo Descripción
data string Datos comprimidos DEFLATE
options table? Opciones de decodificación opcionales

Opciones {id="deflate-decompress-options"}

Campo Tipo Descripción
max_size integer Tamaño máximo descomprimido en bytes (predeterminado: 128 MB; máximo: 1 GB)

Devuelve: string, error

Zlib

Zlib envuelve los datos DEFLATE con una cabecera y una suma de comprobación, según RFC 1950.

Comprimir {id="zlib-compress"}

local compressed, err = compress.zlib.encode(data, {level = 6})
if err then return nil, err end
Parámetro Tipo Descripción
data string Datos a comprimir
options table? Opciones de codificación opcionales

Opciones {id="zlib-compress-options"}

Campo Tipo Descripción
level integer Nivel de compresión 1-9 (predeterminado: 6)

Devuelve: string, error

Descomprimir {id="zlib-decompress"}

local decompressed, err = compress.zlib.decode(compressed)
if err then return nil, err end
Parámetro Tipo Descripción
data string Datos comprimidos Zlib
options table? Opciones de decodificación opcionales

Opciones {id="zlib-decompress-options"}

Campo Tipo Descripción
max_size integer Tamaño máximo descomprimido en bytes (predeterminado: 128 MB; máximo: 1 GB)

Devuelve: string, error

Elección de un algoritmo

Algoritmo Uso recomendado Velocidad Relación Rango de niveles
gzip HTTP, amplia compatibilidad Media Bueno 1-9
brotli Recursos estáticos, texto Lenta La mejor 0-11
zstd Payloads binarios, compresión rápida Rápida Buena 1-22
deflate/zlib Bajo nivel, protocolos específicos Media Buena 1-9
-- HTTP response based on Accept-Encoding
local accept, header_err = req:header("Accept-Encoding")
if header_err then return nil, header_err end
accept = accept or ""
local body, json_err = json.encode(response_data)
if json_err then return nil, json_err end

local qualities = {}
for item in accept:gmatch("[^,]+") do
    local coding = item:match("^%s*([^;%s]+)")
    local has_q = item:match(";%s*[qQ]%s*=") ~= nil
    local q_text = item:match(";%s*[qQ]%s*=%s*([^;%s,]+)")
    local q
    if not has_q then
        q = 1
    elseif q_text == "0" or q_text == "1" or
           (q_text and q_text:match("^0%.%d?%d?%d?$")) or
           (q_text and q_text:match("^1%.0?0?0?$")) then
        q = tonumber(q_text)
    end
    if coding and q and q >= 0 and q <= 1 then
        coding = coding:lower()
        qualities[coding] = math.max(qualities[coding] or 0, q)
    end
end

local function quality(coding)
    if qualities[coding] ~= nil then return qualities[coding] end
    if coding == "identity" then
        return qualities["*"] == 0 and 0 or 1
    end
    return qualities["*"] or 0
end

local selected, selected_q = nil, -1
for _, coding in ipairs({"br", "gzip", "identity"}) do
    local q = quality(coding)
    if q > selected_q then
        selected, selected_q = coding, q
    end
end

-- Include every field used by this handler or its surrounding middleware.
local vary_fields = {"Accept-Encoding"}
local vary_err = res:set_header("Vary", table.concat(vary_fields, ", "))
if vary_err then return nil, vary_err end

if selected_q <= 0 then
    local status_err = res:set_status(http.STATUS.NOT_ACCEPTABLE)
    if status_err then return nil, status_err end
    local write_err = res:write("No acceptable content encoding")
    if write_err then return nil, write_err end
elseif selected == "br" then
    local compressed, compress_err = compress.brotli.encode(body)
    if compress_err then return nil, compress_err end
    local set_err = res:set_header("Content-Encoding", "br")
    if set_err then return nil, set_err end
    local write_err = res:write(compressed)
    if write_err then return nil, write_err end
elseif selected == "gzip" then
    local compressed, compress_err = compress.gzip.encode(body)
    if compress_err then return nil, compress_err end
    local set_err = res:set_header("Content-Encoding", "gzip")
    if set_err then return nil, set_err end
    local write_err = res:write(compressed)
    if write_err then return nil, write_err end
else
    local write_err = res:write(body)
    if write_err then return nil, write_err end
end

Este handler parcial analiza tokens de codificación exactos y valores q de RFC, respeta rechazos explícitos como br;q=0 y emite Vary: Accept-Encoding. set_header sustituye un valor Vary existente, por lo que debes añadir a vary_fields cualquier otro campo que use el middleware circundante antes de establecerlo. Una pila HTTP completa puede proporcionar un helper de negociación compartido.

Errores

Condición Clase Reintentable
Entrada vacía errors.INVALID no
Nivel fuera de rango errors.INVALID no
Datos comprimidos invalidos errors.INVALID no
Tamano descomprimido excede limite errors.INTERNAL (gzip, zlib, zstd) / errors.INVALID (deflate, brotli) no

Consulta Manejo de errores para trabajar con errores.