1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
|
import itertools
from email.generator import _make_boundary
from mimetypes import guess_type
class MultiPartForm(dict):
def __init__(self):
self.files = []
self.boundary = _make_boundary()
def get_content_type(self):
return 'multipart/form-data; boundary="%s"' % self.boundary
def add_file(self, fieldname, filename, fd, mimetype=None):
body = fd.read()
if mimetype is None:
mimetype = guess_type(filename)[0] or 'application/octet-stream'
self.files.append((fieldname, filename, mimetype, body))
def bytes(self):
parts = []
part_boundary = bytearray('--%s' % self.boundary, 'ascii')
# Add the form fields
parts.extend(
[
part_boundary,
bytearray(
'Content-Disposition: form-data; name="%s"' % k,
'ascii',
),
b'',
v if isinstance(v, bytes) else bytearray(v, 'ascii'),
]
for k, v in list(self.items())
)
# Add the files to upload
parts.extend(
[
part_boundary,
bytearray(
'Content-Disposition: form-data; name="%s"; filename="%s"' % (fieldname, filename),
'ascii',
),
bytearray('Content-Type: %s' % content_type, 'ascii'),
bytearray(),
body if isinstance(body, bytes) else bytearray(body, 'ascii'),
]
for fieldname, filename, content_type, body in self.files
)
# Flatten the list and add closing boundary marker,
# then return CR+LF separated data
flattened = list(itertools.chain(*parts))
flattened.append(bytearray('--%s--' % self.boundary, 'ascii'))
res = bytearray()
for item in flattened:
res += item
res += bytearray('\r\n', 'ascii')
return res
|