-
-
Notifications
You must be signed in to change notification settings - Fork 945
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(parse_header): provide our own implementation of
parse_header()
- Loading branch information
Showing
12 changed files
with
142 additions
and
16 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
# Copyright 2023-2024 by Vytautas Liuolia. | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
|
||
"""Media (aka MIME) type parsing and matching utilities.""" | ||
|
||
import typing | ||
|
||
|
||
def _parse_header_old_stdlib(line): # type: ignore | ||
"""Parse a Content-type like header. | ||
Return the main content-type and a dictionary of options. | ||
Note: | ||
This method has been copied (almost) verbatim from CPython 3.8 stdlib. | ||
It is slated for removal from the stdlib in 3.13. | ||
""" | ||
|
||
def _parseparam(s): # type: ignore | ||
while s[:1] == ';': | ||
s = s[1:] | ||
end = s.find(';') | ||
while end > 0 and (s.count('"', 0, end) - s.count('\\"', 0, end)) % 2: | ||
end = s.find(';', end + 1) | ||
if end < 0: | ||
end = len(s) | ||
f = s[:end] | ||
yield f.strip() | ||
s = s[end:] | ||
|
||
parts = _parseparam(';' + line) | ||
key = parts.__next__() | ||
pdict = {} | ||
for p in parts: | ||
i = p.find('=') | ||
if i >= 0: | ||
name = p[:i].strip().lower() | ||
value = p[i + 1 :].strip() | ||
if len(value) >= 2 and value[0] == value[-1] == '"': | ||
value = value[1:-1] | ||
value = value.replace('\\\\', '\\').replace('\\"', '"') | ||
pdict[name] = value | ||
return key, pdict | ||
|
||
|
||
def parse_header(line: str) -> typing.Tuple[str, dict]: | ||
"""Parse a Content-type like header. | ||
Return the main content-type and a dictionary of options. | ||
Args: | ||
line: A header value to parse. | ||
Returns: | ||
A tuple containing the main content-type and a dictionary of options. | ||
Note: | ||
This function replaces an equivalent method previously available in the | ||
stdlib as ``cgi.parse_header()``. | ||
It was removed from the stdlib in Python 3.13. | ||
""" | ||
if '"' not in line and '\\' not in line: | ||
key, semicolon, parts = line.partition(';') | ||
if not semicolon: | ||
return (key.strip(), {}) | ||
|
||
pdict = {} | ||
for part in parts.split(';'): | ||
name, equals, value = part.partition('=') | ||
if equals: | ||
pdict[name.strip().lower()] = value.strip() | ||
|
||
return (key.strip(), pdict) | ||
|
||
return _parse_header_old_stdlib(line) | ||
|
||
|
||
__all__ = ['parse_header'] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
import pytest | ||
|
||
from falcon.util import mediatypes | ||
|
||
|
||
@pytest.mark.parametrize( | ||
'value,expected', | ||
[ | ||
('', ('', {})), | ||
('strange', ('strange', {})), | ||
('text/plain', ('text/plain', {})), | ||
('text/plain ', ('text/plain', {})), | ||
(' text/plain', ('text/plain', {})), | ||
(' text/plain ', ('text/plain', {})), | ||
(' text/plain ', ('text/plain', {})), | ||
( | ||
'falcon/peregrine; key1; key2=value; key3', | ||
('falcon/peregrine', {'key2': 'value'}), | ||
), | ||
('"falcon/peregrine" ; key="value"', ('"falcon/peregrine"', {'key': 'value'})), | ||
('falcon/peregrine; empty=""', ('falcon/peregrine', {'empty': ''})), | ||
('falcon/peregrine; quote="', ('falcon/peregrine', {'quote': '"'})), | ||
('text/plain; charset=utf-8', ('text/plain', {'charset': 'utf-8'})), | ||
('stuff/strange; missing-value; missing-another', ('stuff/strange', {})), | ||
('stuff/strange; missing-value\\missing-another', ('stuff/strange', {})), | ||
( | ||
'application/falcon; P1 = "key; value"; P2="\\""', | ||
('application/falcon', {'p1': 'key; value', 'p2': '"'}), | ||
), | ||
], | ||
) | ||
def test_parse_header(value, expected): | ||
assert mediatypes.parse_header(value) == expected |