Search code examples
pythoncurlpython-requestssesame

cURL request to Python (using multipart/form-data)


I am trying to translate this cURL request:

curl -X POST "endpoint" -H 'Content-Type: multipart/form-data' -F "config=@conf.ttl"

So far I've got this:

requests.post(
     endpoint,
     headers={"Content-Type": "multipart/form-data"},
     files={"config": ("conf.ttl", open("conf.ttl", "rb"), "text/turtle")}
)

But it doesn't work quite as expected. What is it I'm missing?


Solution

  • You shouldn't be explicitly setting "multipart/form-data". It is overwriting all the other part of the header set by requests ("multipart/form-data; boundary=4b9...",). There is no need to set the header, requests will do that for you. You can see the request headers (requests.headers) in the example below. You can see that

    import requests
    endpoint = "http://httpbin.org/post"
    r = requests.post(
         endpoint,
         files={"config": ("conf.ttl", open("conf.ttl", "rb"), "text/turtle")}
    )
    print r.request.headers
    print r.headers
    print r.text
    

    gives:

    {'Content-Length': '259', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'User-Agent': 'python-requests/2.10.0', 'Connection': 'keep-alive', 'Content-Type': 'multipart/form-data; boundary=4b99265adcf04931964cb96f48b53a36'}
    {'Content-Length': '530', 'Server': 'nginx', 'Connection': 'keep-alive', 'Access-Control-Allow-Credentials': 'true', 'Date': 'Fri, 20 May 2016 20:50:05 GMT', 'Access-Control-Allow-Origin': '*', 'Content-Type': 'application/json'}
    {
      "args": {}, 
      "data": "", 
      "files": {
        "config": "curl -X POST \"endpoint\" -H 'Content-Type: multipart/form-data' -F \"config=@conf.ttl\"\n\n"
      }, 
      "form": {}, 
      "headers": {
        "Accept": "*/*", 
        "Accept-Encoding": "gzip, deflate", 
        "Content-Length": "259", 
        "Content-Type": "multipart/form-data; boundary=4b99265adcf04931964cb96f48b53a36", 
        "Host": "httpbin.org", 
        "User-Agent": "python-requests/2.10.0"
      }, 
      "json": null, 
      "origin": "84.92.144.93", 
      "url": "http://httpbin.org/post"
    }
    

    Where as your code with the explicit header gives a error to the same URL.

    {'Content-Length': '259', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'User-Agent': 'python-requests/2.10.0', 'Connection': 'keep-alive', 'Content-Type': 'multipart/form-data'}
    {'Date': 'Fri, 20 May 2016 20:54:34 GMT', 'Content-Length': '291', 'Content-Type': 'text/html', 'Connection': 'keep-alive', 'Server': 'nginx'}
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
    <title>500 Internal Server Error</title>
    <h1>Internal Server Error</h1>
    <p>The server encountered an internal error and was unable to complete your request.  Either the server is overloaded or there is an error in the application.</p>