I ran into the same problem, and I needed to do a multi-page form entry without using external libraries. I wrote a whole blog about the problems I encountered .
I ended up using a modified version of http://code.activestate.com/recipes/146306/ . The code in this url actually just adds the contents of the file as a string, which can cause binary problems. Here is my working code.
import mimetools import mimetypes import io import http import json form = MultiPartForm() form.add_field("form_field", "my awesome data") # Add a fake file form.add_file(key, os.path.basename(filepath), fileHandle=codecs.open("/path/to/my/file.zip", "rb")) # Build the request url = "http://www.example.com/endpoint" schema, netloc, url, params, query, fragments = urlparse.urlparse(url) try: form_buffer = form.get_binary().getvalue() http = httplib.HTTPConnection(netloc) http.connect() http.putrequest("POST", url) http.putheader('Content-type',form.get_content_type()) http.putheader('Content-length', str(len(form_buffer))) http.endheaders() http.send(form_buffer) except socket.error, e: raise SystemExit(1) r = http.getresponse() if r.status == 200: return json.loads(r.read()) else: print('Upload failed (%s): %s' % (r.status, r.reason)) class MultiPartForm(object): """Accumulate the data to be used when posting a form.""" def __init__(self): self.form_fields = [] self.files = [] self.boundary = mimetools.choose_boundary() return def get_content_type(self): return 'multipart/form-data; boundary=%s' % self.boundary def add_field(self, name, value): """Add a simple field to the form data.""" self.form_fields.append((name, value)) return def add_file(self, fieldname, filename, fileHandle, mimetype=None): """Add a file to be uploaded.""" body = fileHandle.read() if mimetype is None: mimetype = mimetypes.guess_type(filename)[0] or 'application/octet-stream' self.files.append((fieldname, filename, mimetype, body)) return def get_binary(self): """Return a binary buffer containing the form data, including attached files.""" part_boundary = '--' + self.boundary binary = io.BytesIO() needsCLRF = False # Add the form fields for name, value in self.form_fields: if needsCLRF: binary.write('\r\n') needsCLRF = True block = [part_boundary, 'Content-Disposition: form-data; name="%s"' % name, '', value ] binary.write('\r\n'.join(block)) # Add the files to upload for field_name, filename, content_type, body in self.files: if needsCLRF: binary.write('\r\n') needsCLRF = True block = [part_boundary, str('Content-Disposition: file; name="%s"; filename="%s"' % \ (field_name, filename)), 'Content-Type: %s' % content_type, '' ] binary.write('\r\n'.join(block)) binary.write('\r\n') binary.write(body) # add closing boundary marker, binary.write('\r\n--' + self.boundary + '--\r\n') return binary
Jason Kulatunga Mar 29 '15 at 17:49 2015-03-29 17:49
source share