| OLD | NEW |
| 1 # urllib3/filepost.py | 1 # urllib3/filepost.py |
| 2 # Copyright 2008-2012 Andrey Petrov and contributors (see CONTRIBUTORS.txt) | 2 # Copyright 2008-2013 Andrey Petrov and contributors (see CONTRIBUTORS.txt) |
| 3 # | 3 # |
| 4 # This module is part of urllib3 and is released under | 4 # This module is part of urllib3 and is released under |
| 5 # the MIT License: http://www.opensource.org/licenses/mit-license.php | 5 # the MIT License: http://www.opensource.org/licenses/mit-license.php |
| 6 | 6 |
| 7 import codecs | 7 import codecs |
| 8 import mimetypes | 8 import mimetypes |
| 9 | 9 |
| 10 from uuid import uuid4 | 10 from uuid import uuid4 |
| 11 from io import BytesIO | 11 from io import BytesIO |
| 12 | 12 |
| 13 from .packages import six | 13 from .packages import six |
| 14 from .packages.six import b | 14 from .packages.six import b |
| 15 from .fields import RequestField |
| 15 | 16 |
| 16 writer = codecs.lookup('utf-8')[3] | 17 writer = codecs.lookup('utf-8')[3] |
| 17 | 18 |
| 18 | 19 |
| 19 def choose_boundary(): | 20 def choose_boundary(): |
| 20 """ | 21 """ |
| 21 Our embarassingly-simple replacement for mimetools.choose_boundary. | 22 Our embarassingly-simple replacement for mimetools.choose_boundary. |
| 22 """ | 23 """ |
| 23 return uuid4().hex | 24 return uuid4().hex |
| 24 | 25 |
| 25 | 26 |
| 26 def get_content_type(filename): | 27 def iter_field_objects(fields): |
| 27 return mimetypes.guess_type(filename)[0] or 'application/octet-stream' | 28 """ |
| 29 Iterate over fields. |
| 30 |
| 31 Supports list of (k, v) tuples and dicts, and lists of |
| 32 :class:`~urllib3.fields.RequestField`. |
| 33 |
| 34 """ |
| 35 if isinstance(fields, dict): |
| 36 i = six.iteritems(fields) |
| 37 else: |
| 38 i = iter(fields) |
| 39 |
| 40 for field in i: |
| 41 if isinstance(field, RequestField): |
| 42 yield field |
| 43 else: |
| 44 yield RequestField.from_tuples(*field) |
| 28 | 45 |
| 29 | 46 |
| 30 def iter_fields(fields): | 47 def iter_fields(fields): |
| 31 """ | 48 """ |
| 32 Iterate over fields. | 49 Iterate over fields. |
| 33 | 50 |
| 51 .. deprecated :: |
| 52 |
| 53 The addition of `~urllib3.fields.RequestField` makes this function |
| 54 obsolete. Instead, use :func:`iter_field_objects`, which returns |
| 55 `~urllib3.fields.RequestField` objects, instead. |
| 56 |
| 34 Supports list of (k, v) tuples and dicts. | 57 Supports list of (k, v) tuples and dicts. |
| 58 |
| 35 """ | 59 """ |
| 36 if isinstance(fields, dict): | 60 if isinstance(fields, dict): |
| 37 return ((k, v) for k, v in six.iteritems(fields)) | 61 return ((k, v) for k, v in six.iteritems(fields)) |
| 38 | 62 |
| 39 return ((k, v) for k, v in fields) | 63 return ((k, v) for k, v in fields) |
| 40 | 64 |
| 41 | 65 |
| 42 def encode_multipart_formdata(fields, boundary=None): | 66 def encode_multipart_formdata(fields, boundary=None): |
| 43 """ | 67 """ |
| 44 Encode a dictionary of ``fields`` using the multipart/form-data MIME format. | 68 Encode a dictionary of ``fields`` using the multipart/form-data MIME format. |
| 45 | 69 |
| 46 :param fields: | 70 :param fields: |
| 47 Dictionary of fields or list of (key, value) or (key, value, MIME type) | 71 Dictionary of fields or list of (key, :class:`~urllib3.fields.RequestFie
ld`). |
| 48 field tuples. The key is treated as the field name, and the value as | |
| 49 the body of the form-data bytes. If the value is a tuple of two | |
| 50 elements, then the first element is treated as the filename of the | |
| 51 form-data section and a suitable MIME type is guessed based on the | |
| 52 filename. If the value is a tuple of three elements, then the third | |
| 53 element is treated as an explicit MIME type of the form-data section. | |
| 54 | |
| 55 Field names and filenames must be unicode. | |
| 56 | 72 |
| 57 :param boundary: | 73 :param boundary: |
| 58 If not specified, then a random boundary will be generated using | 74 If not specified, then a random boundary will be generated using |
| 59 :func:`mimetools.choose_boundary`. | 75 :func:`mimetools.choose_boundary`. |
| 60 """ | 76 """ |
| 61 body = BytesIO() | 77 body = BytesIO() |
| 62 if boundary is None: | 78 if boundary is None: |
| 63 boundary = choose_boundary() | 79 boundary = choose_boundary() |
| 64 | 80 |
| 65 for fieldname, value in iter_fields(fields): | 81 for field in iter_field_objects(fields): |
| 66 body.write(b('--%s\r\n' % (boundary))) | 82 body.write(b('--%s\r\n' % (boundary))) |
| 67 | 83 |
| 68 if isinstance(value, tuple): | 84 writer(body).write(field.render_headers()) |
| 69 if len(value) == 3: | 85 data = field.data |
| 70 filename, data, content_type = value | |
| 71 else: | |
| 72 filename, data = value | |
| 73 content_type = get_content_type(filename) | |
| 74 writer(body).write('Content-Disposition: form-data; name="%s"; ' | |
| 75 'filename="%s"\r\n' % (fieldname, filename)) | |
| 76 body.write(b('Content-Type: %s\r\n\r\n' % | |
| 77 (content_type,))) | |
| 78 else: | |
| 79 data = value | |
| 80 writer(body).write('Content-Disposition: form-data; name="%s"\r\n' | |
| 81 % (fieldname)) | |
| 82 body.write(b'\r\n') | |
| 83 | 86 |
| 84 if isinstance(data, int): | 87 if isinstance(data, int): |
| 85 data = str(data) # Backwards compatibility | 88 data = str(data) # Backwards compatibility |
| 86 | 89 |
| 87 if isinstance(data, six.text_type): | 90 if isinstance(data, six.text_type): |
| 88 writer(body).write(data) | 91 writer(body).write(data) |
| 89 else: | 92 else: |
| 90 body.write(data) | 93 body.write(data) |
| 91 | 94 |
| 92 body.write(b'\r\n') | 95 body.write(b'\r\n') |
| 93 | 96 |
| 94 body.write(b('--%s--\r\n' % (boundary))) | 97 body.write(b('--%s--\r\n' % (boundary))) |
| 95 | 98 |
| 96 content_type = str('multipart/form-data; boundary=%s' % boundary) | 99 content_type = str('multipart/form-data; boundary=%s' % boundary) |
| 97 | 100 |
| 98 return body.getvalue(), content_type | 101 return body.getvalue(), content_type |
| OLD | NEW |