python-multipart 0.0.7__tar.gz → 0.0.8__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. {python_multipart-0.0.7 → python_multipart-0.0.8}/PKG-INFO +1 -1
  2. {python_multipart-0.0.7 → python_multipart-0.0.8}/multipart/__init__.py +1 -1
  3. {python_multipart-0.0.7 → python_multipart-0.0.8}/multipart/multipart.py +5 -11
  4. {python_multipart-0.0.7 → python_multipart-0.0.8}/tests/test_multipart.py +10 -0
  5. {python_multipart-0.0.7 → python_multipart-0.0.8}/.gitignore +0 -0
  6. {python_multipart-0.0.7 → python_multipart-0.0.8}/LICENSE.txt +0 -0
  7. {python_multipart-0.0.7 → python_multipart-0.0.8}/README.rst +0 -0
  8. {python_multipart-0.0.7 → python_multipart-0.0.8}/multipart/decoders.py +0 -0
  9. {python_multipart-0.0.7 → python_multipart-0.0.8}/multipart/exceptions.py +0 -0
  10. {python_multipart-0.0.7 → python_multipart-0.0.8}/pyproject.toml +0 -0
  11. {python_multipart-0.0.7 → python_multipart-0.0.8}/tests/__init__.py +0 -0
  12. {python_multipart-0.0.7 → python_multipart-0.0.8}/tests/compat.py +0 -0
  13. {python_multipart-0.0.7 → python_multipart-0.0.8}/tests/test_data/http/CR_in_header.http +0 -0
  14. {python_multipart-0.0.7 → python_multipart-0.0.8}/tests/test_data/http/CR_in_header.yaml +0 -0
  15. {python_multipart-0.0.7 → python_multipart-0.0.8}/tests/test_data/http/CR_in_header_value.http +0 -0
  16. {python_multipart-0.0.7 → python_multipart-0.0.8}/tests/test_data/http/CR_in_header_value.yaml +0 -0
  17. {python_multipart-0.0.7 → python_multipart-0.0.8}/tests/test_data/http/almost_match_boundary.http +0 -0
  18. {python_multipart-0.0.7 → python_multipart-0.0.8}/tests/test_data/http/almost_match_boundary.yaml +0 -0
  19. {python_multipart-0.0.7 → python_multipart-0.0.8}/tests/test_data/http/almost_match_boundary_without_CR.http +0 -0
  20. {python_multipart-0.0.7 → python_multipart-0.0.8}/tests/test_data/http/almost_match_boundary_without_CR.yaml +0 -0
  21. {python_multipart-0.0.7 → python_multipart-0.0.8}/tests/test_data/http/almost_match_boundary_without_LF.http +0 -0
  22. {python_multipart-0.0.7 → python_multipart-0.0.8}/tests/test_data/http/almost_match_boundary_without_LF.yaml +0 -0
  23. {python_multipart-0.0.7 → python_multipart-0.0.8}/tests/test_data/http/almost_match_boundary_without_final_hyphen.http +0 -0
  24. {python_multipart-0.0.7 → python_multipart-0.0.8}/tests/test_data/http/almost_match_boundary_without_final_hyphen.yaml +0 -0
  25. {python_multipart-0.0.7 → python_multipart-0.0.8}/tests/test_data/http/bad_end_of_headers.http +0 -0
  26. {python_multipart-0.0.7 → python_multipart-0.0.8}/tests/test_data/http/bad_end_of_headers.yaml +0 -0
  27. {python_multipart-0.0.7 → python_multipart-0.0.8}/tests/test_data/http/bad_header_char.http +0 -0
  28. {python_multipart-0.0.7 → python_multipart-0.0.8}/tests/test_data/http/bad_header_char.yaml +0 -0
  29. {python_multipart-0.0.7 → python_multipart-0.0.8}/tests/test_data/http/bad_initial_boundary.http +0 -0
  30. {python_multipart-0.0.7 → python_multipart-0.0.8}/tests/test_data/http/bad_initial_boundary.yaml +0 -0
  31. {python_multipart-0.0.7 → python_multipart-0.0.8}/tests/test_data/http/base64_encoding.http +0 -0
  32. {python_multipart-0.0.7 → python_multipart-0.0.8}/tests/test_data/http/base64_encoding.yaml +0 -0
  33. {python_multipart-0.0.7 → python_multipart-0.0.8}/tests/test_data/http/empty_header.http +0 -0
  34. {python_multipart-0.0.7 → python_multipart-0.0.8}/tests/test_data/http/empty_header.yaml +0 -0
  35. {python_multipart-0.0.7 → python_multipart-0.0.8}/tests/test_data/http/multiple_fields.http +0 -0
  36. {python_multipart-0.0.7 → python_multipart-0.0.8}/tests/test_data/http/multiple_fields.yaml +0 -0
  37. {python_multipart-0.0.7 → python_multipart-0.0.8}/tests/test_data/http/multiple_files.http +0 -0
  38. {python_multipart-0.0.7 → python_multipart-0.0.8}/tests/test_data/http/multiple_files.yaml +0 -0
  39. {python_multipart-0.0.7 → python_multipart-0.0.8}/tests/test_data/http/quoted_printable_encoding.http +0 -0
  40. {python_multipart-0.0.7 → python_multipart-0.0.8}/tests/test_data/http/quoted_printable_encoding.yaml +0 -0
  41. {python_multipart-0.0.7 → python_multipart-0.0.8}/tests/test_data/http/single_field.http +0 -0
  42. {python_multipart-0.0.7 → python_multipart-0.0.8}/tests/test_data/http/single_field.yaml +0 -0
  43. {python_multipart-0.0.7 → python_multipart-0.0.8}/tests/test_data/http/single_field_blocks.http +0 -0
  44. {python_multipart-0.0.7 → python_multipart-0.0.8}/tests/test_data/http/single_field_blocks.yaml +0 -0
  45. {python_multipart-0.0.7 → python_multipart-0.0.8}/tests/test_data/http/single_field_longer.http +0 -0
  46. {python_multipart-0.0.7 → python_multipart-0.0.8}/tests/test_data/http/single_field_longer.yaml +0 -0
  47. {python_multipart-0.0.7 → python_multipart-0.0.8}/tests/test_data/http/single_field_single_file.http +0 -0
  48. {python_multipart-0.0.7 → python_multipart-0.0.8}/tests/test_data/http/single_field_single_file.yaml +0 -0
  49. {python_multipart-0.0.7 → python_multipart-0.0.8}/tests/test_data/http/single_field_with_leading_newlines.http +0 -0
  50. {python_multipart-0.0.7 → python_multipart-0.0.8}/tests/test_data/http/single_field_with_leading_newlines.yaml +0 -0
  51. {python_multipart-0.0.7 → python_multipart-0.0.8}/tests/test_data/http/single_file.http +0 -0
  52. {python_multipart-0.0.7 → python_multipart-0.0.8}/tests/test_data/http/single_file.yaml +0 -0
  53. {python_multipart-0.0.7 → python_multipart-0.0.8}/tests/test_data/http/utf8_filename.http +0 -0
  54. {python_multipart-0.0.7 → python_multipart-0.0.8}/tests/test_data/http/utf8_filename.yaml +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: python-multipart
3
- Version: 0.0.7
3
+ Version: 0.0.8
4
4
  Summary: A streaming multipart parser for Python
5
5
  Project-URL: Homepage, https://github.com/andrew-d/python-multipart
6
6
  Project-URL: Documentation, https://andrew-d.github.io/python-multipart/
@@ -2,7 +2,7 @@
2
2
  __author__ = "Andrew Dunham"
3
3
  __license__ = "Apache"
4
4
  __copyright__ = "Copyright (c) 2012-2013, Andrew Dunham"
5
- __version__ = "0.0.7"
5
+ __version__ = "0.0.8"
6
6
 
7
7
 
8
8
  from .multipart import (
@@ -2,7 +2,6 @@ from .decoders import *
2
2
  from .exceptions import *
3
3
 
4
4
  import os
5
- import re
6
5
  import sys
7
6
  import shutil
8
7
  import logging
@@ -67,16 +66,6 @@ lower_char = lambda c: c | 0x20
67
66
  ord_char = lambda c: c
68
67
  join_bytes = lambda b: bytes(list(b))
69
68
 
70
- # These are regexes for parsing header values.
71
- SPECIAL_CHARS = re.escape(b'()<>@,;:\\"/[]?={} \t')
72
- QUOTED_STR = br'"(?:\\.|[^"])*"'
73
- VALUE_STR = br'(?:[^' + SPECIAL_CHARS + br']+|' + QUOTED_STR + br')'
74
- OPTION_RE_STR = (
75
- br'(?:;|^)\s*([^' + SPECIAL_CHARS + br']+)\s*=\s*(' + VALUE_STR + br')'
76
- )
77
- OPTION_RE = re.compile(OPTION_RE_STR)
78
- QUOTE = b'"'[0]
79
-
80
69
 
81
70
  def parse_options_header(value: Union[str, bytes]) -> Tuple[bytes, Dict[bytes, bytes]]:
82
71
  """
@@ -110,6 +99,11 @@ def parse_options_header(value: Union[str, bytes]) -> Tuple[bytes, Dict[bytes, b
110
99
  options = {}
111
100
  for param in params:
112
101
  key, value = param
102
+ # If the value returned from get_params() is a 3-tuple, the last
103
+ # element corresponds to the value.
104
+ # See: https://docs.python.org/3/library/email.compat32-message.html
105
+ if isinstance(value, tuple):
106
+ value = value[-1]
113
107
  # If the value is a filename, we need to fix a bug on IE6 that sends
114
108
  # the full file path instead of the filename.
115
109
  if key == 'filename':
@@ -270,6 +270,16 @@ class TestParseOptionsHeader(unittest.TestCase):
270
270
  t, p = parse_options_header(b'text/plain; filename="C:\\this\\is\\a\\path\\file.txt"')
271
271
 
272
272
  self.assertEqual(p[b'filename'], b'file.txt')
273
+
274
+ def test_redos_attack_header(self):
275
+ t, p = parse_options_header(b'application/x-www-form-urlencoded; !="\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\')
276
+ # If vulnerable, this test wouldn't finish, the line above would hang
277
+ self.assertIn(b'"\\', p[b'!'])
278
+
279
+ def test_handles_rfc_2231(self):
280
+ t, p = parse_options_header(b'text/plain; param*=us-ascii\'en-us\'encoded%20message')
281
+
282
+ self.assertEqual(p[b'param'], b'encoded message')
273
283
 
274
284
 
275
285
  class TestBaseParser(unittest.TestCase):