Not only am I using C++ at my new job, but i’m also doing some Perl and some Python. I actually have found that I rather like Python. It’s a great language for what we’re using it for. As an aside that has nothing to do with this blog post, this link shows the most popular programming languages. I am using 7 of the top 20 (as of July 2008) programming languages right now. :)

Anyway, back to the point of this post: I was very surprised to learn that Python 2.5x does not have support for uploading binary files over http (i.e. it can’t do file upload). What? That’s crazy. I happen to need this functionality for a task i’m working on. After some searching, i was able to pull together a bunch of pieces on the net and get a custom solution working. Many sites had pieces of the puzzle, but nobody had an entire working example all put together. Anyway, here is my solution:

import os, stat, mimetypes, httplib

def post_multipart(host, selector, fields, files):
    """
Post fields and files to an http host as multipart/form-data.
@param host: the hostname of the server to connect to.  For example: www.myserver.com
@param selector: where to go on the host.  For example: cgi-bin/myscript.pl or blog/upload, etc..
@param fields: a sequence of (name, value) elements for regular form fields.  For example:
    [("vals", "16,18,19"), ("foo", "bar")]
@param files: a sequence of (name, file) elements for data to be uploaded as files.  For example:
    [ ("mugshot", open("/images/me.jpg", "rb")) ]
@return: the server's response page.
    """

    content_type, body = _encode_multipart_formdata(fields, files)
    h = httplib.HTTPConnection(host)
    headers = {
        'User-Agent': 'python_multipart_caller',
        'Content-Type': content_type
        }
    h.request('POST', selector, body, headers)
    res = h.getresponse()
    return res.read() 

def _encode_multipart_formdata(fields, files):
    """
@return: (content_type, body) ready for httplib.HTTP instance
    """

    BOUNDARY = '----------ThIs_Is_tHe_bouNdaRY_$'
    CRLF = '\r\n'
    L = []
    for (key, value) in fields:
        L.append('--' + BOUNDARY)
        L.append('Content-Disposition: form-data; name="%s"' % key)
        L.append('')
        L.append(value)
    for (key, fd) in files:
        file_size = os.fstat(fd.fileno())[stat.ST_SIZE]
        filename = fd.name.split('/')[-1]
        contenttype = mimetypes.guess_type(filename)[0] or 'application/octet-stream'
        L.append('--%s' % BOUNDARY)
        L.append('Content-Disposition: form-data; name="%s"; filename="%s"' % (key, filename))
        L.append('Content-Type: %s' % contenttype)
        fd.seek(0)
        L.append('\r\n' + fd.read())
    L.append('--' + BOUNDARY + '--')
    L.append('')
    body = CRLF.join(L)
    content_type = 'multipart/form-data; boundary=%s' % BOUNDARY
    return content_type, body

if __name__ == '__main__':
    post_multipart("my.server.com", "/cgi-bin/uploadphoto.pl", [("foo", "bar")], [("mugshot", open("/images/me.jpg", "rb"))])
Share

Sorry, the comment form is closed at this time.

© 2013 The Hawker Squawker Suffusion theme by Sayontan Sinha