Skip to content

Commit 44e669b

Browse files
authored
Cache parsing of the content-type (#10552)
1 parent 55c5f1f commit 44e669b

File tree

2 files changed

+20
-5
lines changed

2 files changed

+20
-5
lines changed

CHANGES/10552.misc.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Improved performance of parsing content types by adding a cache in the same manner currently done with mime types -- by :user:`bdraco`.

aiohttp/helpers.py

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
from http.cookies import SimpleCookie
2525
from math import ceil
2626
from pathlib import Path
27-
from types import TracebackType
27+
from types import MappingProxyType, TracebackType
2828
from typing import (
2929
TYPE_CHECKING,
3030
Any,
@@ -367,6 +367,20 @@ def parse_mimetype(mimetype: str) -> MimeType:
367367
)
368368

369369

370+
@functools.lru_cache(maxsize=56)
371+
def parse_content_type(raw: str) -> Tuple[str, MappingProxyType[str, str]]:
372+
"""Parse Content-Type header.
373+
374+
Returns a tuple of the parsed content type and a
375+
MappingProxyType of parameters.
376+
"""
377+
msg = HeaderParser().parsestr(f"Content-Type: {raw}")
378+
content_type = msg.get_content_type()
379+
params = msg.get_params(())
380+
content_dict = dict(params[1:]) # First element is content type again
381+
return content_type, MappingProxyType(content_dict)
382+
383+
370384
def guess_filename(obj: Any, default: Optional[str] = None) -> Optional[str]:
371385
name = getattr(obj, "name", None)
372386
if name and isinstance(name, str) and name[0] != "<" and name[-1] != ">":
@@ -733,10 +747,10 @@ def _parse_content_type(self, raw: Optional[str]) -> None:
733747
self._content_type = "application/octet-stream"
734748
self._content_dict = {}
735749
else:
736-
msg = HeaderParser().parsestr("Content-Type: " + raw)
737-
self._content_type = msg.get_content_type()
738-
params = msg.get_params(())
739-
self._content_dict = dict(params[1:]) # First element is content type again
750+
content_type, content_mapping_proxy = parse_content_type(raw)
751+
self._content_type = content_type
752+
# _content_dict needs to be mutable so we can update it
753+
self._content_dict = content_mapping_proxy.copy()
740754

741755
@property
742756
def content_type(self) -> str:

0 commit comments

Comments
 (0)