Solicitar checksums de contenido

Varias piezas de código pueden consumir los datos de la solicitud y preprocesarlos. Por ejemplo, los datos JSON terminan en el objeto de la petición ya leídos y procesados, los datos de los formularios también terminan allí pero pasan por una ruta de código diferente. Esto parece un inconveniente cuando se quiere calcular la suma de comprobación de los datos de la solicitud entrante. Esto es necesario a veces para algunas APIs.

Afortunadamente, esto es muy sencillo de cambiar envolviendo el flujo de entrada.

El siguiente ejemplo calcula el checksum SHA1 de los datos entrantes a medida que se leen y los almacena en el entorno WSGI:

import hashlib

class ChecksumCalcStream(object):

    def __init__(self, stream):
        self._stream = stream
        self._hash = hashlib.sha1()

    def read(self, bytes):
        rv = self._stream.read(bytes)
        self._hash.update(rv)
        return rv

    def readline(self, size_hint):
        rv = self._stream.readline(size_hint)
        self._hash.update(rv)
        return rv

def generate_checksum(request):
    env = request.environ
    stream = ChecksumCalcStream(env['wsgi.input'])
    env['wsgi.input'] = stream
    return stream._hash

Para usar esto, todo lo que necesitas hacer es enganchar el flujo de cálculo antes de que la solicitud comience a consumir datos. (Por ejemplo: Ten cuidado al acceder a request.form o cualquier cosa de esa naturaleza. before_request_handlers por ejemplo hay que tener cuidado de no acceder a él).

Ejemplo de uso:

@app.route('/special-api', methods=['POST'])
def special_api():
    hash = generate_checksum(request)
    # Accessing this parses the input stream
    files = request.files
    # At this point the hash is fully constructed.
    checksum = hash.hexdigest()
    return f"Hash was: {checksum}"