Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getting bad request error when posting file to server using python requests library

I am getting http code 400 (bad request) when I am trying to post a file to server using python requests library.

Corresponding curl request which is successful:

curl -X POST -i https://de.api.labs.sophos.com/analysis/file/static/v1 \
-H 'Authorization: auth_string' \
-H 'Content-Type: multipart/form-data' \
-F "file=@filename"

API documentation: https://api.labs.sophos.com/doc/analysis/file/static.html

Can someone help me out what I might be doing wrong?
My code so far:

import requests

url = "https://de.api.labs.sophos.com/analysis/file/static/v1"
headers = {'content-type': 'multipart/form-data', 'Authorization': authorization}

with open(filepath, 'rb') as f:      
    files = {'file': f}  # Even tried {'file': f.read()}
    r = requests.post(url, files=files, headers=headers)
    if r.status_code in [200, 202]:
        return r.json()
    else:
        return r
like image 944
Deval Jain Avatar asked Apr 07 '26 22:04

Deval Jain


1 Answers

TL;DR

Try to do it this way:

import requests

url = "https://de.api.labs.sophos.com/analysis/file/static/v1"
headers = {'Authorization': authorization}  # no Content-Type here

r = requests.post(url, headers=headers, files={"file": open(filepath, "rb")})
print(r.status_code, r.text)

Why

You shouldn't set Content-Type header manually when posting files with requests.

There are 2 reasons why:

  • requests will set Content-Type to multipart/form-data implicitly before making an actual HTTP request (as it does for Content-Length for example)
  • When using Content-Type: multipart/form-data you should specify a boundary as well. If no boundary is set, server will not be able to read data from request body correctly. So boundary is a required part of Content-Type header, if you use multipart/form-data.

In your example you haven't set boundary for the request. The fact is that requests does not set it for you if you override Content-Type header (which you do). And then server is not able to read your file in request body. Therefore, it returns you 400 Bad Request.

You can check it by typing print(r.request.headers["Content-Type"]) after you've made your request. It will output this:

multipart/form-data

, but it must look like this instead:

multipart/form-data; boundary=6387a52fb4d1465310a2b63b2d1c6e70

On the other hand, curl adds boundary implicitly, so you everything is fine and you receive 200 OK.

You can check it as well:

curl -H 'Content-Type: multipart/form-data' -F "[email protected]" -v http://httpbin.org/post

Which outputs:

* Connected to httpbin.org (34.230.136.58) port 80 (#0)
> POST /post HTTP/1.1
> Host: httpbin.org
> User-Agent: curl/7.47.0
> Content-Type: multipart/form-data; boundary=------------------------d257f5f4377a3997
...
like image 126
Ivan Vinogradov Avatar answered Apr 10 '26 12:04

Ivan Vinogradov



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!