Skip to content

Commit 006fbc3

Browse files
authored
Improve client performance when there are no auto headers to skip (aio-libs#10049)
1 parent c3c11a6 commit 006fbc3

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
@@ -209,6 +209,8 @@ class ClientRequest:
209209
__writer: Optional["asyncio.Task[None]"] = None # async task for streaming data
210210
_continue = None # waiter future for '100 Continue' response
211211

212+
_skip_auto_headers: Optional["CIMultiDict[None]"] = None
213+
212214
# N.B.
213215
# Adding __del__ method with self._writer closing doesn't make sense
214216
# because _writer is instance method, thus it keeps a reference to self.
@@ -293,6 +295,10 @@ def __init__(
293295
def __reset_writer(self, _: object = None) -> None:
294296
self.__writer = None
295297

298+
@property
299+
def skip_auto_headers(self) -> CIMultiDict[None]:
300+
return self._skip_auto_headers or CIMultiDict()
301+
296302
@property
297303
def _writer(self) -> Optional["asyncio.Task[None]"]:
298304
return self.__writer
@@ -404,20 +410,19 @@ def update_headers(self, headers: Optional[LooseHeaders]) -> None:
404410

405411
def update_auto_headers(self, skip_auto_headers: Optional[Iterable[str]]) -> None:
406412
if skip_auto_headers is not None:
407-
self.skip_auto_headers = CIMultiDict(
413+
self._skip_auto_headers = CIMultiDict(
408414
(hdr, None) for hdr in sorted(skip_auto_headers)
409415
)
410416
used_headers = self.headers.copy()
411-
used_headers.extend(self.skip_auto_headers) # type: ignore[arg-type]
417+
used_headers.extend(self._skip_auto_headers) # type: ignore[arg-type]
412418
else:
413419
# Fast path when there are no headers to skip
414420
# which is the most common case.
415-
self.skip_auto_headers = CIMultiDict()
416421
used_headers = self.headers
417422

418423
for hdr, val in self.DEFAULT_HEADERS.items():
419424
if hdr not in used_headers:
420-
self.headers.add(hdr, val)
425+
self.headers[hdr] = val
421426

422427
if hdrs.USER_AGENT not in used_headers:
423428
self.headers[hdrs.USER_AGENT] = SERVER_SOFTWARE
@@ -522,21 +527,20 @@ def update_body_from_data(self, body: Any) -> None:
522527
self.body = body
523528

524529
# enable chunked encoding if needed
525-
if not self.chunked:
526-
if hdrs.CONTENT_LENGTH not in self.headers:
527-
size = body.size
528-
if size is None:
529-
self.chunked = True
530-
else:
531-
if hdrs.CONTENT_LENGTH not in self.headers:
532-
self.headers[hdrs.CONTENT_LENGTH] = str(size)
530+
if not self.chunked and hdrs.CONTENT_LENGTH not in self.headers:
531+
if (size := body.size) is not None:
532+
self.headers[hdrs.CONTENT_LENGTH] = str(size)
533+
else:
534+
self.chunked = True
533535

534536
# copy payload headers
535537
assert body.headers
538+
headers = self.headers
539+
skip_headers = self._skip_auto_headers
536540
for key, value in body.headers.items():
537-
if key in self.headers or key in self.skip_auto_headers:
541+
if key in headers or (skip_headers is not None and key in skip_headers):
538542
continue
539-
self.headers[key] = value
543+
headers[key] = value
540544

541545
def update_expect_continue(self, expect: bool = False) -> None:
542546
if expect:
@@ -664,7 +668,10 @@ async def send(self, conn: "Connection") -> "ClientResponse":
664668
# set default content-type
665669
if (
666670
self.method in self.POST_METHODS
667-
and hdrs.CONTENT_TYPE not in self.skip_auto_headers
671+
and (
672+
self._skip_auto_headers is None
673+
or hdrs.CONTENT_TYPE not in self._skip_auto_headers
674+
)
668675
and hdrs.CONTENT_TYPE not in self.headers
669676
):
670677
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(
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)