Skip to content

Commit 32ce657

Browse files
authored
Merge pull request #814 from jonathanberthias/content-type-no-space
Fix content-type when no space after semicolon
2 parents 7eeb901 + fb0ea95 commit 32ce657

File tree

2 files changed

+37
-7
lines changed

2 files changed

+37
-7
lines changed

openapi_core/templating/media_types/finders.py

+24-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
"""OpenAPI core templating media types finders module"""
22

33
import fnmatch
4+
import re
45
from typing import Mapping
56
from typing import Tuple
67

@@ -38,12 +39,32 @@ def find(self, mimetype: str) -> MediaType:
3839
raise MediaTypeNotFound(mimetype, list(self.content.keys()))
3940

4041
def _parse_mimetype(self, mimetype: str) -> Tuple[str, Mapping[str, str]]:
41-
mimetype_parts = mimetype.split("; ")
42-
mime_type = mimetype_parts[0]
42+
mimetype_parts = mimetype.split(";")
43+
mime_type = mimetype_parts[0].lower().rstrip()
4344
parameters = {}
4445
if len(mimetype_parts) > 1:
4546
parameters_list = (
46-
param_str.split("=") for param_str in mimetype_parts[1:]
47+
self._parse_parameter(param_str)
48+
for param_str in mimetype_parts[1:]
4749
)
4850
parameters = dict(parameters_list)
4951
return mime_type, parameters
52+
53+
def _parse_parameter(self, parameter: str) -> Tuple[str, str]:
54+
"""Parse a parameter according to RFC 9110.
55+
56+
See https://www.rfc-editor.org/rfc/rfc9110.html#name-parameters
57+
58+
Important points:
59+
* parameter names are case-insensitive
60+
* parameter values are case-sensitive
61+
except "charset" which is case-insensitive
62+
https://www.rfc-editor.org/rfc/rfc2046#section-4.1.2
63+
"""
64+
name, value = parameter.split("=")
65+
name = name.lower().lstrip()
66+
# remove surrounding quotes from value
67+
value = re.sub('^"(.*)"$', r"\1", value, count=1)
68+
if name == "charset":
69+
value = value.lower()
70+
return name, value.rstrip()

tests/unit/templating/test_media_types_finders.py

+13-4
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,19 @@ def content(self, spec):
2121
def finder(self, content):
2222
return MediaTypeFinder(content)
2323

24-
def test_charset(self, finder, content):
25-
mimetype = "text/html; charset=utf-8"
26-
27-
mimetype, parameters, _ = finder.find(mimetype)
24+
@pytest.mark.parametrize(
25+
"media_type",
26+
[
27+
# equivalent according to RFC 9110
28+
"text/html;charset=utf-8",
29+
'Text/HTML;Charset="utf-8"',
30+
'text/html; charset="utf-8"',
31+
"text/html;charset=UTF-8",
32+
"text/html ; charset=utf-8",
33+
],
34+
)
35+
def test_charset(self, finder, content, media_type):
36+
mimetype, parameters, _ = finder.find(media_type)
2837
assert mimetype == "text/*"
2938
assert parameters == {"charset": "utf-8"}
3039

0 commit comments

Comments
 (0)