psf / psf/requests

Set "Content-Disposition" header in `file` multipart failed

Open
#5,177 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Python
Stars
54.3k
Forks
10.4k
Avg merge
16h 43m
Merged PRs (30d)
3

Description

Summary.

    class RequestEncodingMixin(object):
        ...
        def _encode_files(files, data):
            ...
            rf = RequestField(name=k, data=fdata, filename=fn, headers=fh)
            rf.make_multipart(content_type=ft)

Variable fh holdes the 4th tuple item passed from

    files = {'settings': (filename, io.BytesIO(b'some,data,to,send\nanother,row,to,send\n'),
             'app/xml', {'Content-Disposition':'attachment'} )}

The rf.header dict get set passing headers=fh with 'Content-Disposition':....
Calling rf.make_multipart(content_type=ft), at the next line, only passing the 3trd tuple item.

The method make_multipart - urllib3/fields.py is defined as

    def make_multipart(
        self, content_disposition=None, content_type=None, content_location=None
    ):
        self.headers["Content-Disposition"] = content_disposition or u"form-data"
        ...

which replaces, as content_disposition is None, the allready set self.headers["Content-Disposition"] with the default u"form-data".

Expected Result

--e96a4935b8d5b2355f1da3070faa4b28
Content-Disposition: attachment; name="settings"; filename="settings.xml"
Content-Type: app/xml

some,data,to,send
another,row,to,send

--e96a4935b8d5b2355f1da3070faa4b28--

Actual Result

--e96a4935b8d5b2355f1da3070faa4b28
Content-Disposition: form-data; name="settings"; filename="settings.xml"
Content-Type: app/xml

some,data,to,send
another,row,to,send

--e96a4935b8d5b2355f1da3070faa4b28--

Reproduction Steps

import requests

url = 'http://127.0.0.1:8080'
filename = "settings.xml"

files = {'settings': (filename, io.BytesIO(b'some,data,to,send\nanother,row,to,send\n'),
         'app/xml', {'Content-Disposition':'attachment'} )}

r = requests.post(url, files=files)

System Information

Tested with Python: 3.5 - urllib3: 1.23 - requests: 2.19.1

Possible Solution

Pass all three parameter explicit to .make_multipart(..., e.g.

  rf.make_multipart(content_disposition=fh.get('Content-Disposition'), 
                    content_type=ft, 
                    content_location=fh.get('Content-Location')

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in requests/models.py at RequestEncodingMixin._encode_files and compare how urllib3/fields.py handles RequestField.make_multipart. Reproduce the supplied files payload, then verify that the resulting multipart request preserves the requested Content-Disposition header and still includes the content type.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
api
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Stale
Clarity
Clearly specified
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.