Skip to content

part.set_content_disposition is ignored #3035

Closed
@MattIPv4

Description

Long story short

Using part.set_content_disposition for some multipart file stuff, couldn't get it to work.
So I checked the part header, which is as I expected and then made a fake writer to check what the payload being sent actually was. The content disposition in the payload doesn't at all match what I have set in the part.

Expected behaviour

The content disposition in the payload is as set in the part.

Actual behaviour

It appears to generate a fresh content disposition.

Steps to reproduce

Demo

class Writer:

    def __init__(self):
        self.buffer = ""

    async def write(self, stuff):
        self.buffer += stuff.decode('utf-8','ignore')

    def done(self):
        print(self.buffer[:300])

# Generate multipart
with aiohttp.MultipartWriter('form-data') as mp:
    part = mp.append(open(path, 'rb'))
    part.set_content_disposition(
        'form-data',
        quote_fields=False,
        name='files[]',
        filename=os.path.split(path)[1]
    )
    # Fix aiohttp being retarded
    part._headers['Content-Disposition'] = part._headers['Content-Disposition'].split(" filename*=utf-8", 1)[0]
    print("\n", part._headers['Content-Disposition'], "\n")
    w = Writer()
    await mp.write(w)
    w.done()

Your environment

Aiohttp 3.2.1
Python 3.6
macOS 10.13.4

The issue (as far as I can tell)

https://github.com/aio-libs/aiohttp/blob/master/aiohttp/multipart.py#L754-L755
It appears there that the payload headers are saved separately and so no matter what you do to the returned part after it's appended, the headers will never actually be updated in the multipart.

Hotfix (until this issue is resolved)

Create your payload yourself, set headers etc. before you append to the multipart.
eg.

# Hotfix
from multidict import CIMultiDict
payload = aiohttp.payload.get_payload(open(path, 'rb'), headers=CIMultiDict())
payload.set_content_disposition(
    'form-data',
    quote_fields=False,
    name='files[]',
    filename=os.path.split(path)[1]
)
payload._headers['Content-Disposition'] = payload._headers['Content-Disposition'].split(" filename*=utf-8", 1)[0]

# Add part to multipart
part = mp.append(payload)

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions