Skip to content

Commit 653302e

Browse files
[PR #10049/006fbc37 backport][3.11] Improve client performance when there are no auto headers to skip (#10051)
Co-authored-by: J. Nick Koston <[email protected]>
1 parent d411bc5 commit 653302e

File tree

3 files changed

+24
-15
lines changed

3 files changed

+24
-15
lines changed

CHANGES/10049.misc.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Improved performance of making requests when there are no auto headers to skip -- by :user:`bdraco`.

aiohttp/client_reqrep.py

Lines changed: 22 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,8 @@ class ClientRequest:
271271
__writer = None # async task for streaming data
272272
_continue = None # waiter future for '100 Continue' response
273273

274+
_skip_auto_headers: Optional["CIMultiDict[None]"] = None
275+
274276
# N.B.
275277
# Adding __del__ method with self._writer closing doesn't make sense
276278
# because _writer is instance method, thus it keeps a reference to self.
@@ -358,6 +360,10 @@ def __init__(
358360
def __reset_writer(self, _: object = None) -> None:
359361
self.__writer = None
360362

363+
@property
364+
def skip_auto_headers(self) -> CIMultiDict[None]:
365+
return self._skip_auto_headers or CIMultiDict()
366+
361367
@property
362368
def _writer(self) -> Optional["asyncio.Task[None]"]:
363369
return self.__writer
@@ -469,20 +475,19 @@ def update_headers(self, headers: Optional[LooseHeaders]) -> None:
469475

470476
def update_auto_headers(self, skip_auto_headers: Optional[Iterable[str]]) -> None:
471477
if skip_auto_headers is not None:
472-
self.skip_auto_headers = CIMultiDict(
478+
self._skip_auto_headers = CIMultiDict(
473479
(hdr, None) for hdr in sorted(skip_auto_headers)
474480
)
475481
used_headers = self.headers.copy()
476-
used_headers.extend(self.skip_auto_headers) # type: ignore[arg-type]
482+
used_headers.extend(self._skip_auto_headers) # type: ignore[arg-type]
477483
else:
478484
# Fast path when there are no headers to skip
479485
# which is the most common case.
480-
self.skip_auto_headers = CIMultiDict()
481486
used_headers = self.headers
482487

483488
for hdr, val in self.DEFAULT_HEADERS.items():
484489
if hdr not in used_headers:
485-
self.headers.add(hdr, val)
490+
self.headers[hdr] = val
486491

487492
if hdrs.USER_AGENT not in used_headers:
488493
self.headers[hdrs.USER_AGENT] = SERVER_SOFTWARE
@@ -584,21 +589,20 @@ def update_body_from_data(self, body: Any) -> None:
584589
self.body = body
585590

586591
# enable chunked encoding if needed
587-
if not self.chunked:
588-
if hdrs.CONTENT_LENGTH not in self.headers:
589-
size = body.size
590-
if size is None:
591-
self.chunked = True
592-
else:
593-
if hdrs.CONTENT_LENGTH not in self.headers:
594-
self.headers[hdrs.CONTENT_LENGTH] = str(size)
592+
if not self.chunked and hdrs.CONTENT_LENGTH not in self.headers:
593+
if (size := body.size) is not None:
594+
self.headers[hdrs.CONTENT_LENGTH] = str(size)
595+
else:
596+
self.chunked = True
595597

596598
# copy payload headers
597599
assert body.headers
600+
headers = self.headers
601+
skip_headers = self._skip_auto_headers
598602
for key, value in body.headers.items():
599-
if key in self.headers or key in self.skip_auto_headers:
603+
if key in headers or (skip_headers is not None and key in skip_headers):
600604
continue
601-
self.headers[key] = value
605+
headers[key] = value
602606

603607
def update_expect_continue(self, expect: bool = False) -> None:
604608
if expect:
@@ -723,7 +727,10 @@ async def send(self, conn: "Connection") -> "ClientResponse":
723727
# set default content-type
724728
if (
725729
self.method in self.POST_METHODS
726-
and hdrs.CONTENT_TYPE not in self.skip_auto_headers
730+
and (
731+
self._skip_auto_headers is None
732+
or hdrs.CONTENT_TYPE not in self._skip_auto_headers
733+
)
727734
and hdrs.CONTENT_TYPE not in self.headers
728735
):
729736
self.headers[hdrs.CONTENT_TYPE] = "application/octet-stream"

tests/test_client_request.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -687,6 +687,7 @@ async def test_content_type_skip_auto_header_bytes(loop, conn) -> None:
687687
skip_auto_headers={"Content-Type"},
688688
loop=loop,
689689
)
690+
assert req.skip_auto_headers == CIMultiDict({"CONTENT-TYPE": None})
690691
resp = await req.send(conn)
691692
assert "CONTENT-TYPE" not in req.headers
692693
resp.close()

0 commit comments

Comments
 (0)