filepost.py 2.3 KB

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