|
|
|
# urllib3/filepost.py
|
|
|
|
# Copyright 2008-2012 Andrey Petrov and contributors (see CONTRIBUTORS.txt)
|
|
|
|
#
|
|
|
|
# This module is part of urllib3 and is released under
|
|
|
|
# the MIT License: http://www.opensource.org/licenses/mit-license.php
|
|
|
|
|
|
|
|
import codecs
|
|
|
|
import mimetypes
|
|
|
|
|
|
|
|
from uuid import uuid4
|
|
|
|
from io import BytesIO
|
|
|
|
|
|
|
|
from .packages import six
|
|
|
|
from .packages.six import b
|
|
|
|
|
|
|
|
writer = codecs.lookup('utf-8')[3]
|
|
|
|
|
|
|
|
|
|
|
|
def choose_boundary():
|
|
|
|
"""
|
|
|
|
Our embarassingly-simple replacement for mimetools.choose_boundary.
|
|
|
|
"""
|
|
|
|
return uuid4().hex
|
|
|
|
|
|
|
|
|
|
|
|
def get_content_type(filename):
|
|
|
|
return mimetypes.guess_type(filename)[0] or 'application/octet-stream'
|
|
|
|
|
|
|
|
|
|
|
|
def iter_fields(fields):
|
|
|
|
"""
|
|
|
|
Iterate over fields.
|
|
|
|
|
|
|
|
Supports list of (k, v) tuples and dicts.
|
|
|
|
"""
|
|
|
|
if isinstance(fields, dict):
|
|
|
|
return ((k, v) for k, v in six.iteritems(fields))
|
|
|
|
|
|
|
|
return ((k, v) for k, v in fields)
|
|
|
|
|
|
|
|
|
|
|
|
def encode_multipart_formdata(fields, boundary=None):
|
|
|
|
"""
|
|
|
|
Encode a dictionary of ``fields`` using the multipart/form-data MIME format.
|
|
|
|
|
|
|
|
:param fields:
|
|
|
|
Dictionary of fields or list of (key, value) or (key, value, MIME type)
|
|
|
|
field tuples. The key is treated as the field name, and the value as
|
|
|
|
the body of the form-data bytes. If the value is a tuple of two
|
|
|
|
elements, then the first element is treated as the filename of the
|
|
|
|
form-data section and a suitable MIME type is guessed based on the
|
|
|
|
filename. If the value is a tuple of three elements, then the third
|
|
|
|
element is treated as an explicit MIME type of the form-data section.
|
|
|
|
|
|
|
|
Field names and filenames must be unicode.
|
|
|
|
|
|
|
|
:param boundary:
|
|
|
|
If not specified, then a random boundary will be generated using
|
|
|
|
:func:`mimetools.choose_boundary`.
|
|
|
|
"""
|
|
|
|
body = BytesIO()
|
|
|
|
if boundary is None:
|
|
|
|
boundary = choose_boundary()
|
|
|
|
|
|
|
|
for fieldname, value in iter_fields(fields):
|
|
|
|
body.write(b('--%s\r\n' % (boundary)))
|
|
|
|
|
|
|
|
if isinstance(value, tuple):
|
|
|
|
if len(value) == 3:
|
|
|
|
filename, data, content_type = value
|
|
|
|
else:
|
|
|
|
filename, data = value
|
|
|
|
content_type = get_content_type(filename)
|
|
|
|
writer(body).write('Content-Disposition: form-data; name="%s"; '
|
|
|
|
'filename="%s"\r\n' % (fieldname, filename))
|
|
|
|
body.write(b('Content-Type: %s\r\n\r\n' %
|
|
|
|
(content_type,)))
|
|
|
|
else:
|
|
|
|
data = value
|
|
|
|
writer(body).write('Content-Disposition: form-data; name="%s"\r\n'
|
|
|
|
% (fieldname))
|
|
|
|
body.write(b'\r\n')
|
|
|
|
|
|
|
|
if isinstance(data, int):
|
|
|
|
data = str(data) # Backwards compatibility
|
|
|
|
|
|
|
|
if isinstance(data, six.text_type):
|
|
|
|
writer(body).write(data)
|
|
|
|
else:
|
|
|
|
body.write(data)
|
|
|
|
|
|
|
|
body.write(b'\r\n')
|
|
|
|
|
|
|
|
body.write(b('--%s--\r\n' % (boundary)))
|
|
|
|
|
|
|
|
content_type = str('multipart/form-data; boundary=%s' % boundary)
|
|
|
|
|
|
|
|
return body.getvalue(), content_type
|