|
|
|
# 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) 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.
|
|
|
|
|
|
|
|
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):
|
|
|
|
filename, data = value
|
|
|
|
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' %
|
|
|
|
(get_content_type(filename))))
|
|
|
|
else:
|
|
|
|
data = value
|
|
|
|
writer(body).write('Content-Disposition: form-data; name="%s"\r\n'
|
|
|
|
% (fieldname))
|
|
|
|
body.write(b'Content-Type: text/plain\r\n\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 = b('multipart/form-data; boundary=%s' % boundary)
|
|
|
|
|
|
|
|
return body.getvalue(), content_type
|