Example POSTing binary data using pycurl
Since urllib2 doesn't easily support POSTing binary data, I used pycurl. It's less fun to use. I think I remember reading that Requests supports this, but someone said something about speed a while back. It may warrant a second look. I couldn't figure out if httplib2 supports POSTing binary data.
Here's how I would do it with curl:
$ curl -v --data-binary @blank-contact-photo.jpg -H 'Content-Type: image/jpeg' 'http://localhost:8000'
* About to connect() to localhost port 8000 (#0)
* Trying 127.0.0.1... connected
> POST / HTTP/1.1
> User-Agent: curl/7.22.0 (x86_64-pc-linux-gnu) libcurl/7.22.0 OpenSSL/1.0.1 zlib/1.2.3.4 libidn/1.23 librtmp/2.3
> Host: localhost:8000
> Accept: */*
> Content-Type: image/jpeg
> Content-Length: 1335
> Expect: 100-continue
>
* Empty reply from server
* Connection #0 to host localhost left intact
curl: (52) Empty reply from server
* Closing connection #0
Here's the headers received by my simulated server:
['User-Agent: curl/7.22.0 (x86_64-pc-linux-gnu) libcurl/7.22.0 OpenSSL/1.0.1 zlib/1.2.3.4 libidn/1.23 librtmp/2.3\r\n', 'Host: localhost:8000\r\n', 'Accept: */*\r\n', 'Content-Type: image/jpeg\r\n', 'Content-Length: 1335\r\n', 'Expect: 100-continue\r\n']
Here's what I tried. Method 4 is what worked.
import StringIO
import os.path
import pycurl
def main():
"""
http://curl.haxx.se/libcurl/c/curl_easy_setopt.html
http://code.activestate.com/recipes/576422-python-http-post-binary-file-upload-with-pycurl/
http://pycurl.cvs.sourceforge.net/pycurl/pycurl/tests/test_post2.py?view=markup
"""
method = 4
filename = 'blank-contact-photo.jpg'
url = 'http://localhost:8000'
c = pycurl.Curl()
c.setopt(pycurl.VERBOSE, 1)
c.setopt(pycurl.URL, url)
fout = StringIO.StringIO()
c.setopt(pycurl.WRITEFUNCTION, fout.write)
if method == 1:
c.setopt(pycurl.HTTPPOST, [
("file1",
(c.FORM_FILE, filename))])
c.setopt(pycurl.HTTPHEADER, ['Content-Type: image/jpeg'])
elif method == 2:
c.setopt(c.HTTPPOST, [
("uploadfieldname",
(c.FORM_FILE, filename,
c.FORM_CONTENTTYPE, "image/jpeg"))])
elif method == 3:
c.setopt(pycurl.UPLOAD, 1)
c.setopt(pycurl.READFUNCTION, open(filename, 'rb').read)
filesize = os.path.getsize(filename)
c.setopt(pycurl.INFILESIZE, filesize)
elif method == 4:
c.setopt(pycurl.POST, 1)
c.setopt(pycurl.HTTPHEADER, [
'Content-Type: image/jpeg'])
filesize = os.path.getsize(filename)
c.setopt(pycurl.POSTFIELDSIZE, filesize)
fin = open(filename, 'rb')
c.setopt(pycurl.READFUNCTION, fin.read)
c.perform()
response_code = c.getinfo(pycurl.RESPONSE_CODE)
response_data = fout.getvalue()
print response_code
print response_data
c.close()
if __name__ == '__main__':
main()
Here's the code for my simulated server in case you're curious:
import BaseHTTPServer
import SocketServer
class MyHandler(BaseHTTPServer.BaseHTTPRequestHandler):
def do_POST(self):
# from debugtools import pvar; pvar('self')
# from debugtools import pvar; pvar('dir(self)')
# from debugtools import pvar; pvar('vars(self)')
# from debugtools import pvar; pvar('self.request')
# from debugtools import pvar; pvar('self.rfile')
# from debugtools import pvar; pvar('self.headers')
# from debugtools import pvar; pvar('self.headers.headers')
print self.headers.headers
return 'asdfasdf'
PORT = 8000
Handler = MyHandler
SocketServer.TCPServer.allow_reuse_address = True
httpd = SocketServer.TCPServer(("", PORT), Handler)
print "serving at port", PORT
try:
httpd.serve_forever()
except KeyboardInterrupt:
httpd.shutdown()