filepost.py 2.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. from __future__ import absolute_import
  2. import binascii
  3. import codecs
  4. import os
  5. from io import BytesIO
  6. from .fields import RequestField
  7. from .packages import six
  8. from .packages.six import b
  9. writer = codecs.lookup("utf-8")[3]
  10. def choose_boundary():
  11. """
  12. Our embarrassingly-simple replacement for mimetools.choose_boundary.
  13. """
  14. boundary = binascii.hexlify(os.urandom(16))
  15. if not six.PY2:
  16. boundary = boundary.decode("ascii")
  17. return boundary
  18. def iter_field_objects(fields):
  19. """
  20. Iterate over fields.
  21. Supports list of (k, v) tuples and dicts, and lists of
  22. :class:`~urllib3.fields.RequestField`.
  23. """
  24. if isinstance(fields, dict):
  25. i = six.iteritems(fields)
  26. else:
  27. i = iter(fields)
  28. for field in i:
  29. if isinstance(field, RequestField):
  30. yield field
  31. else:
  32. yield RequestField.from_tuples(*field)
  33. def iter_fields(fields):
  34. """
  35. .. deprecated:: 1.6
  36. Iterate over fields.
  37. The addition of :class:`~urllib3.fields.RequestField` makes this function
  38. obsolete. Instead, use :func:`iter_field_objects`, which returns
  39. :class:`~urllib3.fields.RequestField` objects.
  40. Supports list of (k, v) tuples and dicts.
  41. """
  42. if isinstance(fields, dict):
  43. return ((k, v) for k, v in six.iteritems(fields))
  44. return ((k, v) for k, v in fields)
  45. def encode_multipart_formdata(fields, boundary=None):
  46. """
  47. Encode a dictionary of ``fields`` using the multipart/form-data MIME format.
  48. :param fields:
  49. Dictionary of fields or list of (key, :class:`~urllib3.fields.RequestField`).
  50. :param boundary:
  51. If not specified, then a random boundary will be generated using
  52. :func:`urllib3.filepost.choose_boundary`.
  53. """
  54. body = BytesIO()
  55. if boundary is None:
  56. boundary = choose_boundary()
  57. for field in iter_field_objects(fields):
  58. body.write(b("--%s\r\n" % (boundary)))
  59. writer(body).write(field.render_headers())
  60. data = field.data
  61. if isinstance(data, int):
  62. data = str(data) # Backwards compatibility
  63. if isinstance(data, six.text_type):
  64. writer(body).write(data)
  65. else:
  66. body.write(data)
  67. body.write(b"\r\n")
  68. body.write(b("--%s--\r\n" % (boundary)))
  69. content_type = str("multipart/form-data; boundary=%s" % boundary)
  70. return body.getvalue(), content_type