Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Replacing CGI that will be deprecated

Tags:

python

cgi

I read that multipart and email.message are candidates for using for processing HTML forms. Neither one works for me. Can somebody point me to an example for how to process an HTML form without using cgi.FieldStorage.

 import multipart
 parser = multipart.MultipartParser()
 data = parser.parse_form()
 print( data['number'])

Error: MultipartParser.init() missing 2 required positional arguments: 'stream' and 'boundary',

import email.message
msg = email.message.Message()
data = msg.parse_args()
print( str(data))

Error: Message' object has no attribute 'parse_args'

like image 733
Kal Avatar asked Aug 12 '26 17:08

Kal


1 Answers

Here's how I did it using only standard library imports:

import io
import email


def parse_multipart(headers, body):
    parsed_body = {}

    em = email.message_from_bytes(
        b"\r\n".join(headers) + b"\r\n\r\n" + body)
    for part in em.walk():
        if not part.is_multipart():
            data = part.get_payload(decode=True)
            params = {}
            for header_name in part:
                for k, v in part.get_params(header=header_name)[1:]:
                    params[k] = v

            if "name" not in params:
                raise IOError("Bad body data")

            if "filename" in params:
                fp = io.BytesIO(data)
                fp.filename = params["filename"]
                parsed_body[params["name"]] = fp

            else:
                parsed_body[params["name"]] = data

    return parsed_body

You can then use it like this:

# notice headers is a list of byte strings
headers = [
    b"Content-Type: multipart/form-data; boundary=340fd0"
]

# notice body is a byte string
body = b"\r\n".join([
    b"--340fd0",
    b"Content-Disposition: form-data; name=\"foo\"",
    b"",
    b"value-foo",
    b"--340fd0",
    b"Content-Disposition: form-data; name=\"baz\"",
    b"",
    b"value-baz",
    b"--340fd0",
    b"Content-Disposition: form-data; name=\"file\"; filename=\"filename.txt\"",
    b"",
    b"this is a text file to upload",
    b"--340fd0--",
])

parsed_body = parse_multipart(headers, body)

print(len(parsed_body)) # 3

print(parsed_body["foo"]) # b'value-foo'
print(type(parsed_body["foo"])) # <class 'bytes'>

print(parsed_body["file"].filename) # filename.txt
print(parsed_body["file"].read()) # b'this is a text file to upload'

It wasn't as straightforward to parse the body as I was expecting it to be but hopefully this points someone in the right direction in the future.

like image 61
Jaymon Avatar answered Aug 15 '26 09:08

Jaymon



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!