1
votes

I am POSTing files from Python to a vendor's API, and the vendor's API is complaining that the content is missing size in the Content-Disposition header. The example they give is like:

Content-Disposition: form-data; filename=filename; name=name; size=1234

Is there a Python HTTP client that will let me include the size without re-writing everything from scratch? Requests uses urllib3 for file POSTing, and those don't seem to support setting the size of the file attachment.

1
What happens when you set the header manually? - Colonel Thirty Two
I don't think I can in requests since it's not the header for the request, it's the header for the file. - Carl
When I look at the request.body, it's like '--d1cfff1341d94dd293f9aafd98ebc6e5\r\nContent-Disposition: form-data; name="my_file"; filename="filename.json"\r\nContent-Type: application/json\r\n\r\n...file...\r\n--d1cfff1341d94dd293f9aafd98ebc6e5--\r\n'. I can add more headers, like Content-Type: application/json, but I don't see any way to change the Content-Disposition. - Carl
If the header is in the request body (which is really weird), then it's irrelevant to HTTP. Modify the POST contents. - Colonel Thirty Two
All I know is that the API I'm calling is complaining about not getting a file size, even though it is getting a content-length. I would rather not rewrite the code to attach a file to a request from scratch if I can help it. - Carl

1 Answers

0
votes

For the record, here's how I ended up solving my problem:

from requests.packages.urllib3.fields import RequestField
from requests.packages.urllib3.filepost import encode_multipart_formdata


def prepare_body_with_size(request, files):
    new_fields = []
    for name, filename, data, file_type in files:
        rf = RequestField(name=name, data=data, filename=filename)
        content_disposition = 'form-data; size=%d' % len(data)
        rf.make_multipart(content_disposition=content_disposition, content_type=file_type)
        new_fields.append(rf)

    body, content_type = encode_multipart_formdata(new_fields)
    request.headers['Content-Type'] = content_type
    request.body = body
    return request

from requests import Request, Session

with Session() as s:
    req = Request('POST', POST_ENDPOINT)
    prepped = req.prepare()
    prepare_body_with_size(prepped, files)
    response = s.send(prepped)

The code was mostly just a rewrite of how requests' prepare_body method works.