Skip to content

Commit

Permalink
[PR #10073/349b7565 backport][3.11] Improve performance of parsing he…
Browse files Browse the repository at this point in the history
…aders (#10083)

Co-authored-by: J. Nick Koston <[email protected]>
  • Loading branch information
patchback[bot] and bdraco authored Dec 1, 2024
1 parent da9210b commit 9df00a1
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 31 deletions.
1 change: 1 addition & 0 deletions CHANGES/10073.misc.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Improved performance of parsing headers when using the C parser -- by :user:`bdraco`.
56 changes: 25 additions & 31 deletions aiohttp/_http_parser.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ cdef object CONTENT_ENCODING = hdrs.CONTENT_ENCODING
cdef object EMPTY_PAYLOAD = _EMPTY_PAYLOAD
cdef object StreamReader = _StreamReader
cdef object DeflateBuffer = _DeflateBuffer

cdef bytes EMPTY_BYTES = b""

cdef inline object extend(object buf, const char* at, size_t length):
cdef Py_ssize_t s
Expand Down Expand Up @@ -277,8 +277,9 @@ cdef class HttpParser:
cparser.llhttp_t* _cparser
cparser.llhttp_settings_t* _csettings

bytearray _raw_name
bytearray _raw_value
bytes _raw_name
object _name
bytes _raw_value
bint _has_value

object _protocol
Expand All @@ -296,7 +297,7 @@ cdef class HttpParser:
bytearray _buf
str _path
str _reason
object _headers
list _headers
list _raw_headers
bint _upgraded
list _messages
Expand Down Expand Up @@ -350,8 +351,8 @@ cdef class HttpParser:
self._payload_exception = payload_exception
self._messages = []

self._raw_name = bytearray()
self._raw_value = bytearray()
self._raw_name = EMPTY_BYTES
self._raw_value = EMPTY_BYTES
self._has_value = False

self._max_line_size = max_line_size
Expand All @@ -378,42 +379,35 @@ cdef class HttpParser:
self._limit = limit

cdef _process_header(self):
if self._raw_name:
raw_name = bytes(self._raw_name)
raw_value = bytes(self._raw_value)

name = find_header(raw_name)
value = raw_value.decode('utf-8', 'surrogateescape')
cdef str value
if self._raw_name is not EMPTY_BYTES:
name = find_header(self._raw_name)
value = self._raw_value.decode('utf-8', 'surrogateescape')

self._headers.add(name, value)
self._headers.append((name, value))

if name is CONTENT_ENCODING:
self._content_encoding = value

PyByteArray_Resize(self._raw_name, 0)
PyByteArray_Resize(self._raw_value, 0)
self._has_value = False
self._raw_headers.append((raw_name, raw_value))
self._raw_headers.append((self._raw_name, self._raw_value))
self._raw_name = EMPTY_BYTES
self._raw_value = EMPTY_BYTES

cdef _on_header_field(self, char* at, size_t length):
cdef Py_ssize_t size
cdef char *buf
if self._has_value:
self._process_header()

size = PyByteArray_Size(self._raw_name)
PyByteArray_Resize(self._raw_name, size + length)
buf = PyByteArray_AsString(self._raw_name)
memcpy(buf + size, at, length)
if self._raw_name is EMPTY_BYTES:
self._raw_name = at[:length]
else:
self._raw_name += at[:length]

cdef _on_header_value(self, char* at, size_t length):
cdef Py_ssize_t size
cdef char *buf

size = PyByteArray_Size(self._raw_value)
PyByteArray_Resize(self._raw_value, size + length)
buf = PyByteArray_AsString(self._raw_value)
memcpy(buf + size, at, length)
if self._raw_value is EMPTY_BYTES:
self._raw_value = at[:length]
else:
self._raw_value += at[:length]
self._has_value = True

cdef _on_headers_complete(self):
Expand All @@ -424,7 +418,7 @@ cdef class HttpParser:
chunked = self._cparser.flags & cparser.F_CHUNKED

raw_headers = tuple(self._raw_headers)
headers = CIMultiDictProxy(self._headers)
headers = CIMultiDictProxy(CIMultiDict(self._headers))

if self._cparser.type == cparser.HTTP_REQUEST:
allowed = upgrade and headers.get("upgrade", "").lower() in ALLOWED_UPGRADES
Expand Down Expand Up @@ -672,7 +666,7 @@ cdef int cb_on_message_begin(cparser.llhttp_t* parser) except -1:
cdef HttpParser pyparser = <HttpParser>parser.data

pyparser._started = True
pyparser._headers = CIMultiDict()
pyparser._headers = []
pyparser._raw_headers = []
PyByteArray_Resize(pyparser._buf, 0)
pyparser._path = None
Expand Down

0 comments on commit 9df00a1

Please sign in to comment.