title: HTTP PUT with base64 encoded attachment using requests
body: <p>I'm using <code>requests</code> to perform an HTTP PUT on a file, but for some reason, it is uploading the raw ASCII and not base64-encoding it first.</p>
  
  <pre><code>files = {'file': ('mydata.csv', open('mydata.csv', 'rb'))}  
  ...  
  try:
      logging.info("Upload URL: " + insert_upload_url)
      headers = {'Content-type': 'multipart/form-data'}
      upload_res = requests.put(insert_upload_url, files=files,
                                data={'insertUpload': data}, headers=headers)
      logging.info("Status: " + str(upload_res.status_code))
      if upload_res.status_code != requests.codes.ok:
          logging.info("Reason: " + upload_res.reason)
      else:
          logging.info("Response: " + upload_res.text)
  except Exception as e:
      logging.info("Error: " + e.message)
  </code></pre>
  
  <p>When I dump the raw HTTP request, I see that the data is not being encoded as <code>application/octet-stream</code> and not in base64:</p>
  
  <pre><code>PUT /apibatchmember/services/rest/batchmemberservice/G9X7CsNn3HisxFdwAu4W76mBewUkQcKD_limGK1MDZ-eW3-olsn8HW0l5oePvEU_ZwHaPbEz2_c1YonjauDs7Jhk9DGvGNSTLMbgSSY9TGVuk00I_-tKPw8mjoXzC63YsFzBIYIeYXHKf34dYxmmhz4iSeDw/batchmember/insertUpload HTTP/1.1
  Host: api.example.com
  Content-Length: 5062
  Content-type: multipart/form-data
  Accept-Encoding: gzip, deflate, compress
  Accept: */*
  User-Agent: python-requests/1.2.3 CPython/2.7.5 Darwin/12.5.0
  
  --5f934d42eabb4d7abe8bdef2cea94b6b
  Content-Disposition: form-data; name="insertUpload"
  
  &lt;?xml version="1.0" encoding="UTF-8"?&gt;
  &lt;insertUpload&gt;
      &lt;criteria&gt;LOWER(EMAIL)&lt;/criteria&gt;
      &lt;fileName&gt;email.csv&lt;/fileName&gt;
      &lt;separator&gt;,&lt;/separator&gt;
      &lt;fileEncoding&gt;UTF-8&lt;/fileEncoding&gt;
      &lt;skipFirstLine&gt;false&lt;/skipFirstLine&gt;
      &lt;dateFormat&gt;mm/dd/YYYY&lt;/dateFormat&gt;
      &lt;mapping&gt;
          &lt;column&gt;
              &lt;colNum&gt;0&lt;/colNum&gt;
              &lt;fieldName&gt;CUSTNUM&lt;/colNum&gt;
          &lt;column&gt;
          &lt;column&gt;
              &lt;colNum&gt;1&lt;/colNum&gt;
              &lt;fieldName&gt;FIRSTNAME&lt;/colNum&gt;
          &lt;column&gt;
          &lt;column&gt;
              &lt;colNum&gt;2&lt;/colNum&gt;
              &lt;fieldName&gt;LASTNAME&lt;/colNum&gt;
          &lt;column&gt;
          &lt;column&gt;
              &lt;colNum&gt;3&lt;/colNum&gt;
              &lt;fieldName&gt;EMAIL&lt;/colNum&gt;
          &lt;column&gt;
      &lt;/mapping&gt;
  &lt;/insertUpload&gt;
  --5f934d42eabb4d7abe8bdef2cea94b6b
  Content-Disposition: form-data; name="file"; filename="email.csv"
  Content-Type: text/csv
  
  \xef\xbb\xbf1045,Janice,Waddell,blah@example.com
  1156,Scott,Sheldon,blah@example.com
  1267,Adrianus,Lengkeek,blah@example.com
  1295,EDWIN,ODIFE,blah@example.com
  1345,Albert,Stephenson,blah@example.com
  ...
  
  --5f934d42eabb4d7abe8bdef2cea94b6b--
  </code></pre>
  
  <p>How can I get that <code>text/csv</code> part to be a base64-encoded stream?</p>
  
  <p>Thanks!</p>
  
  <p><strong>UPDATE</strong></p>
  
  <p>I am getting the correct attachment header now using the following:</p>
  
  <pre><code>with open('/Users/mark.richman/email.csv', 'rb') as fd:
       b64data = base64.b64encode(fd.read())
  
  files = {'file': ('email.csv', b64data, 'application/octet-stream')}
  </code></pre>
  
  <p>However, I still don't get <code>Content-Transfer-Encoding: base64</code> in the file attachment header. Any idea?</p>
  
  <p><strong>UPDATE 2</strong></p>
  
  <p>I had to hack in the header as such: <code>files = {'file': ('email.csv', b64data, 'application/octet-stream\r\nContent-Transfer-Encoding: base64')}</code></p>
  
  <p>I see the header in the HTTP Dump, but I am still getting back <code>HTTP 415 Unsupported Media Type</code>.</p>
  
  <p><strong>UPDATE 3</strong></p>
  
  <p>It looks like <code>requests</code> needs an API update to support what I'm trying to do here. The first part of the multipart (the XML data) needs to have <code>Content-Type: text/xml</code> set, and the API currently doesn't support this. Discussion over <a href="https://github.com/kennethreitz/requests/pull/1640" rel="nofollow">here</a>.</p>