Watch at EaseHistorias. Respuestas. Perspectiva.

Tecnología · GUÍA PRÁCTICA

¿El bucle zlib sigue con eof? Distinga entrada pendiente y el siguiente miembro gzip

28 pruebas locales separan la repetición tras el final, la salida de un solo miembro y un segundo miembro truncado que aun así entrega todo el texto esperado.

Ilustración explicativa original de tres repeticiones de la cola tras eof: salida constante y crecimiento de unused_data.
Ilustración explicativa original: CPython 3.12.14/zlib 1.3.2 observado con tres llamadas acotadas, sin ejecutar un bucle infinito. Watch at Ease

Un descompresor puede tener eof=True y dejar otro miembro en la entrada gzip. En nuestro CPython 3.12.14 instalado también podía conservar unconsumed_tail después de eof. Volver a darle esa cola al mismo objeto terminado añadía bytes del sufijo a unused_data sin generar salida.

Son fallos distintos: seguir iterando después de terminar un miembro o parar demasiado pronto y perder el siguiente. Las 28 pruebas pequeñas también mostraron un límite engañoso: un segundo miembro truncado emitía los nueve bytes de texto esperados entre ambos miembros, pero su eof seguía siendo False.

1. Registre el estado, no solo la longitud de salida

Registre sys.version, zlib.ZLIB_VERSION, zlib.ZLIB_RUNTIME_VERSION, wbits y la regla de uno o varios miembros. Ejecutamos CPython 3.12.14/Linux con zlib 1.3.2 tanto de compilación como de ejecución. El manual original de la biblioteca C consultado se identifica como 1.3.1: es una referencia, no la versión ejecutada.

En cada llamada diagnóstica pequeña, registre longitud de salida, eof y longitudes de unconsumed_tail y unused_data. Antes de eof, puede ser necesario reprocesar entrada retenida porque max_length limitó la salida. Al llegar a eof, interprete el resto según la política del formato en lugar de devolver ciegamente ambos atributos al mismo objeto.

2. No vuelva a alimentar un objeto que ya terminó

La prueba con envoltura zlib contenía 1024 bytes de texto y el sufijo extra de cinco bytes. Con llamadas de 100 bytes y continuando solo mientras not d.eof and d.unconsumed_tail obtuvimos el contenido exacto. En este intérprete, ambos atributos de cola contenían extra al terminar; no eran dos fragmentos independientes para concatenar.

Después realizamos exactamente tres llamadas adicionales con la cola retenida. Todas devolvieron cero bytes; unused_data creció de 5 a 20 bytes y unconsumed_tail permaneció en 5. No ejecutamos un bucle infinito. La incidencia original ya aporta la condición eof y está cerrada con correcciones enlazadas. Compruebe su instalación; no describa el informe como un defecto nuevo sin corregir en toda versión actual de Python.

3. El final de un miembro no completa toda la entrada

La prueba gzip de 49 bytes concatenó un miembro de 25 bytes con alpha y otro de 24 con beta. Un zlib.decompressobj(31) devolvió solo alpha, marcó eof=True y conservó exactamente los 24 bytes del segundo en unused_data. En esa llamada sin límite de salida, unconsumed_tail estaba vacío.

Un objeto nuevo alimentado con unused_data produjo beta y llegó a eof sin sufijo. gzip.decompress sobre la prueba pequeña completa devolvió alphabeta directamente, como documenta su soporte de varios miembros. Estas API y la receta comunitaria del nuevo objeto ya son conocidas. Para entradas grandes o externas, elija un lector mantenido con la política y límites necesarios; esta comparación en memoria no es un diseño de ingestión de producción.

4. Ni salida vacía ni texto esperado prueban finalización

Un miembro gzip vacío válido no produjo texto, pero llegó a eof y dejó disponible el siguiente miembro. Un bucle que interpreta un bloque vacío como final de toda la entrada puede omitir datos posteriores válidos. Siga el estado de cada miembro y la entrada pendiente, no solo si la última salida está vacía.

Quitamos cuatro bytes del tráiler del segundo miembro. Los dos objetos todavía emitieron alphabeta, los nueve bytes esperados, pero el segundo mantuvo eof=False. flush() no acreditó el tráiler ausente. Al alterar en otra prueba el CRC del segundo miembro, el primer objeto siguió devolviendo alpha; el error apareció únicamente al procesar el segundo.

5. Defina qué miembros y datos finales acepta

Un protocolo puede aceptar exactamente un miembro completo y rechazar cualquier byte posterior. Otro puede permitir miembros concatenados y exigir un decodificador nuevo para cada uno. No descarte unused_data en silencio, no suponga que todo sufijo es válido ni lo sume a un unconsumed_tail posiblemente solapado. El sufijo garbage falló al tratarlo como un miembro gzip nuevo.

Mantenga un presupuesto agregado de salida entre todos los miembros aceptados, además de controles de entrada, cantidad de miembros, tiempo y búferes previos adecuados al lector. max_length limita una llamada; cero significa salida sin ese límite. flush(length) establece un tamaño inicial de búfer, no un techo. Verificamos 1024 bytes con max_length=0 y uno con max_length=1. No medimos memoria del proceso, límites de CPU ni un cliente de red.

6. Confirme solo el resultado respaldado por las comprobaciones

Use pruebas pequeñas conocidas para regresión: un miembro válido, dos válidos, un primero vacío, un segundo tráiler truncado, un segundo CRC corrupto y un sufijo que no sea miembro. Compruebe la salida exacta, la finalización de cada miembro aceptado y la decisión final sobre datos posteriores. Conserve los fallos en vez de publicar un prefijo útil como resultado completo.

Las 28 aserciones pasaron en el entorno indicado. El informe guarda versiones, plataforma, SHA del programa y estados observados. No implementamos un lector de streaming general, no ejecutamos las versiones corregidas ni probamos integridad HTTP, origen autenticado o seguridad de recursos. La transición correcta entre miembros es necesaria; la aplicación aún debe definir cuándo está completa toda la entrada aceptada.

Ilustración explicativa original del primer miembro y del segundo válido o truncado, con salida y eof.
Ilustración explicativa original: obtener alphabeta no prueba que se validó el tráiler del segundo miembro; compruebe cada finalización. Watch at Ease