-
-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
Fixes #5220. I believe this is a better fix than #5238. That PR detects that we didn't finish sending a chunked response and then closes the connection. This PR ensures that we simply complete the chunked response by sending the EOF bytes, allowing the connection to remain open and be reused normally. (cherry picked from commit 9c07121)
- v3.11.11
- v3.11.10
- v3.11.9
- v3.11.8
- v3.11.7
- v3.11.6
- v3.11.5
- v3.11.4
- v3.11.3
- v3.11.2
- v3.11.1
- v3.11.0
- v3.11.0rc2
- v3.11.0rc1
- v3.11.0rc0
- v3.11.0b5
- v3.11.0b4
- v3.11.0b3
- v3.11.0b2
- v3.11.0b1
- v3.11.0b0
- v3.10.11
- v3.10.11rc0
- v3.10.10
- v3.10.9
- v3.10.8
- v3.10.7
- v3.10.6
- v3.10.6rc2
- v3.10.6rc1
- v3.10.6rc0
- v3.10.5
- v3.10.4
- v3.10.3
- v3.10.2
- v3.10.1
- v3.10.0
- v3.10.0rc0
- v3.10.0b1
- v3.10.0b0
- v3.9.5
- v3.9.4
- v3.9.4rc0
- v3.9.3
- v3.9.2
- v3.9.1
- v3.9.0
- v3.9.0rc0
- v3.9.0b1
1 parent
cdfed8b
commit 79f5266
Showing
7 changed files
with
160 additions
and
82 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
Fixed an issue when a client request is closed before completing a chunked payload -- by :user:`Dreamsorcerer` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -584,8 +584,11 @@ async def write_bytes( | |
"""Support coroutines that yields bytes objects.""" | ||
# 100 response | ||
if self._continue is not None: | ||
await writer.drain() | ||
await self._continue | ||
try: | ||
await writer.drain() | ||
await self._continue | ||
except asyncio.CancelledError: | ||
return | ||
|
||
protocol = conn.protocol | ||
assert protocol is not None | ||
|
@@ -598,8 +601,6 @@ async def write_bytes( | |
|
||
for chunk in self.body: | ||
await writer.write(chunk) # type: ignore[arg-type] | ||
|
||
await writer.write_eof() | ||
except OSError as exc: | ||
if exc.errno is None and isinstance(exc, asyncio.TimeoutError): | ||
protocol.set_exception(exc) | ||
|
@@ -610,12 +611,12 @@ async def write_bytes( | |
new_exc.__context__ = exc | ||
new_exc.__cause__ = exc | ||
protocol.set_exception(new_exc) | ||
except asyncio.CancelledError as exc: | ||
if not conn.closed: | ||
protocol.set_exception(exc) | ||
except asyncio.CancelledError: | ||
await writer.write_eof() | ||
except Exception as exc: | ||
protocol.set_exception(exc) | ||
else: | ||
await writer.write_eof() | ||
protocol.start_timeout() | ||
finally: | ||
self._writer = None | ||
|
@@ -704,7 +705,8 @@ async def send(self, conn: "Connection") -> "ClientResponse": | |
async def close(self) -> None: | ||
if self._writer is not None: | ||
try: | ||
await self._writer | ||
with contextlib.suppress(asyncio.CancelledError): | ||
await self._writer | ||
finally: | ||
self._writer = None | ||
|
||
|
@@ -973,8 +975,7 @@ def _response_eof(self) -> None: | |
): | ||
return | ||
|
||
self._connection.release() | ||
self._connection = None | ||
self._release_connection() | ||
|
||
self._closed = True | ||
self._cleanup_writer() | ||
|
@@ -986,30 +987,22 @@ def closed(self) -> bool: | |
def close(self) -> None: | ||
if not self._released: | ||
self._notify_content() | ||
if self._closed: | ||
return | ||
|
||
self._closed = True | ||
if self._loop is None or self._loop.is_closed(): | ||
return | ||
|
||
if self._connection is not None: | ||
self._connection.close() | ||
This comment has been minimized.
Sorry, something went wrong.
This comment has been minimized.
Sorry, something went wrong.
Dreamsorcerer
Author
Member
|
||
self._connection = None | ||
self._cleanup_writer() | ||
self._release_connection() | ||
|
||
def release(self) -> Any: | ||
if not self._released: | ||
self._notify_content() | ||
if self._closed: | ||
return noop() | ||
|
||
self._closed = True | ||
if self._connection is not None: | ||
self._connection.release() | ||
self._connection = None | ||
|
||
self._cleanup_writer() | ||
self._release_connection() | ||
return noop() | ||
|
||
@property | ||
|
@@ -1034,10 +1027,28 @@ def raise_for_status(self) -> None: | |
headers=self.headers, | ||
) | ||
|
||
def _release_connection(self) -> None: | ||
if self._connection is not None: | ||
if self._writer is None: | ||
self._connection.release() | ||
self._connection = None | ||
else: | ||
self._writer.add_done_callback(lambda f: self._release_connection()) | ||
|
||
async def _wait_released(self) -> None: | ||
if self._writer is not None: | ||
try: | ||
await self._writer | ||
finally: | ||
self._writer = None | ||
self._release_connection() | ||
|
||
def _cleanup_writer(self) -> None: | ||
if self._writer is not None: | ||
self._writer.cancel() | ||
self._writer = None | ||
if self._writer.done(): | ||
self._writer = None | ||
else: | ||
self._writer.cancel() | ||
self._session = None | ||
|
||
def _notify_content(self) -> None: | ||
|
@@ -1066,9 +1077,10 @@ async def read(self) -> bytes: | |
except BaseException: | ||
self.close() | ||
raise | ||
elif self._released: | ||
elif self._released: # Response explicity released | ||
raise ClientConnectionError("Connection closed") | ||
|
||
await self._wait_released() # Underlying connection released | ||
return self._body # type: ignore[no-any-return] | ||
|
||
def get_encoding(self) -> str: | ||
|
@@ -1151,3 +1163,4 @@ async def __aexit__( | |
# for exceptions, response object can close connection | ||
# if state is broken | ||
self.release() | ||
await self.wait_for_close() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
This change replaced close with release