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.
- {python_multipart-0.0.7 → python_multipart-0.0.8}/PKG-INFO +1 -1
- {python_multipart-0.0.7 → python_multipart-0.0.8}/multipart/__init__.py +1 -1
- {python_multipart-0.0.7 → python_multipart-0.0.8}/multipart/multipart.py +5 -11
- {python_multipart-0.0.7 → python_multipart-0.0.8}/tests/test_multipart.py +10 -0
- {python_multipart-0.0.7 → python_multipart-0.0.8}/.gitignore +0 -0
- {python_multipart-0.0.7 → python_multipart-0.0.8}/LICENSE.txt +0 -0
- {python_multipart-0.0.7 → python_multipart-0.0.8}/README.rst +0 -0
- {python_multipart-0.0.7 → python_multipart-0.0.8}/multipart/decoders.py +0 -0
- {python_multipart-0.0.7 → python_multipart-0.0.8}/multipart/exceptions.py +0 -0
- {python_multipart-0.0.7 → python_multipart-0.0.8}/pyproject.toml +0 -0
- {python_multipart-0.0.7 → python_multipart-0.0.8}/tests/__init__.py +0 -0
- {python_multipart-0.0.7 → python_multipart-0.0.8}/tests/compat.py +0 -0
- {python_multipart-0.0.7 → python_multipart-0.0.8}/tests/test_data/http/CR_in_header.http +0 -0
- {python_multipart-0.0.7 → python_multipart-0.0.8}/tests/test_data/http/CR_in_header.yaml +0 -0
- {python_multipart-0.0.7 → python_multipart-0.0.8}/tests/test_data/http/CR_in_header_value.http +0 -0
- {python_multipart-0.0.7 → python_multipart-0.0.8}/tests/test_data/http/CR_in_header_value.yaml +0 -0
- {python_multipart-0.0.7 → python_multipart-0.0.8}/tests/test_data/http/almost_match_boundary.http +0 -0
- {python_multipart-0.0.7 → python_multipart-0.0.8}/tests/test_data/http/almost_match_boundary.yaml +0 -0
- {python_multipart-0.0.7 → python_multipart-0.0.8}/tests/test_data/http/almost_match_boundary_without_CR.http +0 -0
- {python_multipart-0.0.7 → python_multipart-0.0.8}/tests/test_data/http/almost_match_boundary_without_CR.yaml +0 -0
- {python_multipart-0.0.7 → python_multipart-0.0.8}/tests/test_data/http/almost_match_boundary_without_LF.http +0 -0
- {python_multipart-0.0.7 → python_multipart-0.0.8}/tests/test_data/http/almost_match_boundary_without_LF.yaml +0 -0
- {python_multipart-0.0.7 → python_multipart-0.0.8}/tests/test_data/http/almost_match_boundary_without_final_hyphen.http +0 -0
- {python_multipart-0.0.7 → python_multipart-0.0.8}/tests/test_data/http/almost_match_boundary_without_final_hyphen.yaml +0 -0
- {python_multipart-0.0.7 → python_multipart-0.0.8}/tests/test_data/http/bad_end_of_headers.http +0 -0
- {python_multipart-0.0.7 → python_multipart-0.0.8}/tests/test_data/http/bad_end_of_headers.yaml +0 -0
- {python_multipart-0.0.7 → python_multipart-0.0.8}/tests/test_data/http/bad_header_char.http +0 -0
- {python_multipart-0.0.7 → python_multipart-0.0.8}/tests/test_data/http/bad_header_char.yaml +0 -0
- {python_multipart-0.0.7 → python_multipart-0.0.8}/tests/test_data/http/bad_initial_boundary.http +0 -0
- {python_multipart-0.0.7 → python_multipart-0.0.8}/tests/test_data/http/bad_initial_boundary.yaml +0 -0
- {python_multipart-0.0.7 → python_multipart-0.0.8}/tests/test_data/http/base64_encoding.http +0 -0
- {python_multipart-0.0.7 → python_multipart-0.0.8}/tests/test_data/http/base64_encoding.yaml +0 -0
- {python_multipart-0.0.7 → python_multipart-0.0.8}/tests/test_data/http/empty_header.http +0 -0
- {python_multipart-0.0.7 → python_multipart-0.0.8}/tests/test_data/http/empty_header.yaml +0 -0
- {python_multipart-0.0.7 → python_multipart-0.0.8}/tests/test_data/http/multiple_fields.http +0 -0
- {python_multipart-0.0.7 → python_multipart-0.0.8}/tests/test_data/http/multiple_fields.yaml +0 -0
- {python_multipart-0.0.7 → python_multipart-0.0.8}/tests/test_data/http/multiple_files.http +0 -0
- {python_multipart-0.0.7 → python_multipart-0.0.8}/tests/test_data/http/multiple_files.yaml +0 -0
- {python_multipart-0.0.7 → python_multipart-0.0.8}/tests/test_data/http/quoted_printable_encoding.http +0 -0
- {python_multipart-0.0.7 → python_multipart-0.0.8}/tests/test_data/http/quoted_printable_encoding.yaml +0 -0
- {python_multipart-0.0.7 → python_multipart-0.0.8}/tests/test_data/http/single_field.http +0 -0
- {python_multipart-0.0.7 → python_multipart-0.0.8}/tests/test_data/http/single_field.yaml +0 -0
- {python_multipart-0.0.7 → python_multipart-0.0.8}/tests/test_data/http/single_field_blocks.http +0 -0
- {python_multipart-0.0.7 → python_multipart-0.0.8}/tests/test_data/http/single_field_blocks.yaml +0 -0
- {python_multipart-0.0.7 → python_multipart-0.0.8}/tests/test_data/http/single_field_longer.http +0 -0
- {python_multipart-0.0.7 → python_multipart-0.0.8}/tests/test_data/http/single_field_longer.yaml +0 -0
- {python_multipart-0.0.7 → python_multipart-0.0.8}/tests/test_data/http/single_field_single_file.http +0 -0
- {python_multipart-0.0.7 → python_multipart-0.0.8}/tests/test_data/http/single_field_single_file.yaml +0 -0
- {python_multipart-0.0.7 → python_multipart-0.0.8}/tests/test_data/http/single_field_with_leading_newlines.http +0 -0
- {python_multipart-0.0.7 → python_multipart-0.0.8}/tests/test_data/http/single_field_with_leading_newlines.yaml +0 -0
- {python_multipart-0.0.7 → python_multipart-0.0.8}/tests/test_data/http/single_file.http +0 -0
- {python_multipart-0.0.7 → python_multipart-0.0.8}/tests/test_data/http/single_file.yaml +0 -0
- {python_multipart-0.0.7 → python_multipart-0.0.8}/tests/test_data/http/utf8_filename.http +0 -0
- {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.
|
|
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,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):
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_multipart-0.0.7 → python_multipart-0.0.8}/tests/test_data/http/CR_in_header_value.http
RENAMED
|
File without changes
|
{python_multipart-0.0.7 → python_multipart-0.0.8}/tests/test_data/http/CR_in_header_value.yaml
RENAMED
|
File without changes
|
{python_multipart-0.0.7 → python_multipart-0.0.8}/tests/test_data/http/almost_match_boundary.http
RENAMED
|
File without changes
|
{python_multipart-0.0.7 → python_multipart-0.0.8}/tests/test_data/http/almost_match_boundary.yaml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_multipart-0.0.7 → python_multipart-0.0.8}/tests/test_data/http/bad_end_of_headers.http
RENAMED
|
File without changes
|
{python_multipart-0.0.7 → python_multipart-0.0.8}/tests/test_data/http/bad_end_of_headers.yaml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_multipart-0.0.7 → python_multipart-0.0.8}/tests/test_data/http/bad_initial_boundary.http
RENAMED
|
File without changes
|
{python_multipart-0.0.7 → python_multipart-0.0.8}/tests/test_data/http/bad_initial_boundary.yaml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_multipart-0.0.7 → python_multipart-0.0.8}/tests/test_data/http/single_field_blocks.http
RENAMED
|
File without changes
|
{python_multipart-0.0.7 → python_multipart-0.0.8}/tests/test_data/http/single_field_blocks.yaml
RENAMED
|
File without changes
|
{python_multipart-0.0.7 → python_multipart-0.0.8}/tests/test_data/http/single_field_longer.http
RENAMED
|
File without changes
|
{python_multipart-0.0.7 → python_multipart-0.0.8}/tests/test_data/http/single_field_longer.yaml
RENAMED
|
File without changes
|
{python_multipart-0.0.7 → python_multipart-0.0.8}/tests/test_data/http/single_field_single_file.http
RENAMED
|
File without changes
|
{python_multipart-0.0.7 → python_multipart-0.0.8}/tests/test_data/http/single_field_single_file.yaml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|