From d00cb53a3e21786cd47a67330a207b795297543f Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Tue, 12 May 2020 16:18:43 +0100 Subject: [PATCH 1/3] Use wait_closed with asyncio, with socket unwrapping workaround. --- httpcore/_backends/asyncio.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/httpcore/_backends/asyncio.py b/httpcore/_backends/asyncio.py index c97001a2..cff0e363 100644 --- a/httpcore/_backends/asyncio.py +++ b/httpcore/_backends/asyncio.py @@ -1,5 +1,5 @@ import asyncio -from ssl import SSLContext +from ssl import SSLContext, SSLWantReadError from typing import Optional from .._exceptions import ( @@ -158,6 +158,14 @@ async def aclose(self) -> None: async with self.write_lock: with map_exceptions({OSError: CloseError}): self.stream_writer.close() + try: + ssl_object = self.stream_writer.get_extra_info("ssl_object") + if ssl_object is not None: + ssl_object.unwrap() + except SSLWantReadError: + pass + else: + await self.stream_writer.wait_closed() def is_connection_dropped(self) -> bool: # Counter-intuitively, what we really want to know here is whether the socket is From 11f6d477b9d1482caacd050b53e671cde379c56b Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Tue, 12 May 2020 16:27:19 +0100 Subject: [PATCH 2/3] Fix for Python 3.6, and comments --- httpcore/_backends/asyncio.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/httpcore/_backends/asyncio.py b/httpcore/_backends/asyncio.py index cff0e363..27a8c3c9 100644 --- a/httpcore/_backends/asyncio.py +++ b/httpcore/_backends/asyncio.py @@ -158,6 +158,8 @@ async def aclose(self) -> None: async with self.write_lock: with map_exceptions({OSError: CloseError}): self.stream_writer.close() + # Unwrap the SSL socket, ignoring want-read errors. + # Refs https://bugs.python.org/issue39758 try: ssl_object = self.stream_writer.get_extra_info("ssl_object") if ssl_object is not None: @@ -165,7 +167,9 @@ async def aclose(self) -> None: except SSLWantReadError: pass else: - await self.stream_writer.wait_closed() + if hasattr(self.stream_writer, "wait_closed"): + # Python 3.7+ + await self.stream_writer.wait_closed() def is_connection_dropped(self) -> bool: # Counter-intuitively, what we really want to know here is whether the socket is From 60ec95b43298afbd349b0c0ffe280ca0e1e3943d Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Tue, 12 May 2020 16:30:00 +0100 Subject: [PATCH 3/3] Add type: ignore for Python 3.6 --- httpcore/_backends/asyncio.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/httpcore/_backends/asyncio.py b/httpcore/_backends/asyncio.py index 27a8c3c9..9b770874 100644 --- a/httpcore/_backends/asyncio.py +++ b/httpcore/_backends/asyncio.py @@ -169,7 +169,7 @@ async def aclose(self) -> None: else: if hasattr(self.stream_writer, "wait_closed"): # Python 3.7+ - await self.stream_writer.wait_closed() + await self.stream_writer.wait_closed() # type: ignore def is_connection_dropped(self) -> bool: # Counter-intuitively, what we really want to know here is whether the socket is