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