falconry / falcon

The no-magic web data plane API and microservices framework for Python developers, with a focus on reliability, correctness, and performance at scale.
https://falcon.readthedocs.io/en/stable/
Apache License 2.0
9.51k stars 937 forks source link

unable to iterate through `MultipartForm` multiple times #2180

Closed introprog-dc closed 11 months ago

introprog-dc commented 11 months ago

I'm building a simple web app that receives a form with an attached file. I'm also using a logger middleware to store a log of each request, thus I want to log the content of the file as well. However, it seems the MultipartForm object gets consumed on the on_post() method and when the logger middleware tries to access it, it breaks.

Things I've tried:

  1. use copy.deepcopy() to clone the MultipartForm object so it gets not destroyed -> it breaks with TypeError: no default __reduce__ due to non-trivial __cinit__

The behavior can be easily reproduced iterating twice:

def on_post(self, req, resp):
        form = req.get_media()

        if type(form) == falcon.media.multipart.MultipartForm:
            for part in form:
                print(part, part.name)

            for part in form:
                print(part, part.name)

It only prints results for the first loop:

<falcon.media.multipart.BodyPart object at 0x7f43861b12d0> respuesta_ej1
<falcon.media.multipart.BodyPart object at 0x7f43861b1300> myfile

Thanks in advance for any help you can provide. I really like falcon :)

vytas7 commented 11 months ago

Hi @introprog-dc! This is by design -- in the same way as you cannot read from a stream twice (unless it is seekable).

Iterating over a multipart form consumes the request stream, and no, you cannot iterate twice.

Maybe you could potentially redesign your application so that it doesn't need to iterate twice, and handle the form on-the-fly, or at least its file parts? Other small fields you can buffer in a dict.

introprog-dc commented 11 months ago

Hi @vytas7! Thanks for your quick reply. I will try to implement a different approach then.