Skip to content

Commit

Permalink
Separate timeout errors (aio-libs#7801) (aio-libs#7818)
Browse files Browse the repository at this point in the history
(cherry picked from commit e6e90e8)
  • Loading branch information
atbuy committed Dec 2, 2023
1 parent 1b4efff commit 730bcb9
Show file tree
Hide file tree
Showing 7 changed files with 104 additions and 55 deletions.
1 change: 1 addition & 0 deletions CHANGES/7801.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Separated connection and socket timeout errors, from ServerTimeoutError.
66 changes: 35 additions & 31 deletions aiohttp/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,37 +4,39 @@

from . import hdrs as hdrs
from .client import (
BaseConnector as BaseConnector,
ClientConnectionError as ClientConnectionError,
ClientConnectorCertificateError as ClientConnectorCertificateError,
ClientConnectorError as ClientConnectorError,
ClientConnectorSSLError as ClientConnectorSSLError,
ClientError as ClientError,
ClientHttpProxyError as ClientHttpProxyError,
ClientOSError as ClientOSError,
ClientPayloadError as ClientPayloadError,
ClientProxyConnectionError as ClientProxyConnectionError,
ClientRequest as ClientRequest,
ClientResponse as ClientResponse,
ClientResponseError as ClientResponseError,
ClientSession as ClientSession,
ClientSSLError as ClientSSLError,
ClientTimeout as ClientTimeout,
ClientWebSocketResponse as ClientWebSocketResponse,
ContentTypeError as ContentTypeError,
Fingerprint as Fingerprint,
InvalidURL as InvalidURL,
NamedPipeConnector as NamedPipeConnector,
RequestInfo as RequestInfo,
ServerConnectionError as ServerConnectionError,
ServerDisconnectedError as ServerDisconnectedError,
ServerFingerprintMismatch as ServerFingerprintMismatch,
ServerTimeoutError as ServerTimeoutError,
TCPConnector as TCPConnector,
TooManyRedirects as TooManyRedirects,
UnixConnector as UnixConnector,
WSServerHandshakeError as WSServerHandshakeError,
request as request,
BaseConnector,
ClientConnectionError,
ClientConnectorCertificateError,
ClientConnectorError,
ClientConnectorSSLError,
ClientError,
ClientHttpProxyError,
ClientOSError,
ClientPayloadError,
ClientProxyConnectionError,
ClientRequest,
ClientResponse,
ClientResponseError,
ClientSession,
ClientSSLError,
ClientTimeout,
ClientWebSocketResponse,
ConnectionTimeoutError,
ContentTypeError,
Fingerprint,
InvalidURL,
NamedPipeConnector,
RequestInfo,
ServerConnectionError,
ServerDisconnectedError,
ServerFingerprintMismatch,
ServerTimeoutError,
SocketTimeoutError,
TCPConnector,
TooManyRedirects,
UnixConnector,
WSServerHandshakeError,
request,
)
from .cookiejar import CookieJar as CookieJar, DummyCookieJar as DummyCookieJar
from .formdata import FormData as FormData
Expand Down Expand Up @@ -131,6 +133,7 @@
"ClientSession",
"ClientTimeout",
"ClientWebSocketResponse",
"ConnectionTimeoutError",
"ContentTypeError",
"Fingerprint",
"InvalidURL",
Expand All @@ -139,6 +142,7 @@
"ServerDisconnectedError",
"ServerFingerprintMismatch",
"ServerTimeoutError",
"SocketTimeoutError",
"TCPConnector",
"TooManyRedirects",
"UnixConnector",
Expand Down
46 changes: 25 additions & 21 deletions aiohttp/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,25 +39,27 @@
from . import hdrs, http, payload
from .abc import AbstractCookieJar
from .client_exceptions import (
ClientConnectionError as ClientConnectionError,
ClientConnectorCertificateError as ClientConnectorCertificateError,
ClientConnectorError as ClientConnectorError,
ClientConnectorSSLError as ClientConnectorSSLError,
ClientError as ClientError,
ClientHttpProxyError as ClientHttpProxyError,
ClientOSError as ClientOSError,
ClientPayloadError as ClientPayloadError,
ClientProxyConnectionError as ClientProxyConnectionError,
ClientResponseError as ClientResponseError,
ClientSSLError as ClientSSLError,
ContentTypeError as ContentTypeError,
InvalidURL as InvalidURL,
ServerConnectionError as ServerConnectionError,
ServerDisconnectedError as ServerDisconnectedError,
ServerFingerprintMismatch as ServerFingerprintMismatch,
ServerTimeoutError as ServerTimeoutError,
TooManyRedirects as TooManyRedirects,
WSServerHandshakeError as WSServerHandshakeError,
ClientConnectionError,
ClientConnectorCertificateError,
ClientConnectorError,
ClientConnectorSSLError,
ClientError,
ClientHttpProxyError,
ClientOSError,
ClientPayloadError,
ClientProxyConnectionError,
ClientResponseError,
ClientSSLError,
ConnectionTimeoutError,
ContentTypeError,
InvalidURL,
ServerConnectionError,
ServerDisconnectedError,
ServerFingerprintMismatch,
ServerTimeoutError,
SocketTimeoutError,
TooManyRedirects,
WSServerHandshakeError,
)
from .client_reqrep import (
ClientRequest as ClientRequest,
Expand Down Expand Up @@ -105,12 +107,14 @@
"ClientProxyConnectionError",
"ClientResponseError",
"ClientSSLError",
"ConnectionTimeoutError",
"ContentTypeError",
"InvalidURL",
"ServerConnectionError",
"ServerDisconnectedError",
"ServerFingerprintMismatch",
"ServerTimeoutError",
"SocketTimeoutError",
"TooManyRedirects",
"WSServerHandshakeError",
# client_reqrep
Expand Down Expand Up @@ -575,8 +579,8 @@ async def _request(
req, traces=traces, timeout=real_timeout
)
except asyncio.TimeoutError as exc:
raise ServerTimeoutError(
"Connection timeout " "to host {}".format(url)
raise ConnectionTimeoutError(
f"Connection timeout to host {url}"
) from exc

assert conn.transport is not None
Expand Down
10 changes: 10 additions & 0 deletions aiohttp/client_exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
"ClientSSLError",
"ClientConnectorSSLError",
"ClientConnectorCertificateError",
"ConnectionTimeoutError",
"SocketTimeoutError",
"ServerConnectionError",
"ServerTimeoutError",
"ServerDisconnectedError",
Expand Down Expand Up @@ -242,6 +244,14 @@ class ServerTimeoutError(ServerConnectionError, asyncio.TimeoutError):
"""Server timeout error."""


class ConnectionTimeoutError(ServerTimeoutError):
"""Connection timeout error."""


class SocketTimeoutError(ServerTimeoutError):
"""Socket timeout error."""


class ServerFingerprintMismatch(ServerConnectionError):
"""SSL certificate does not match expected fingerprint."""

Expand Down
4 changes: 2 additions & 2 deletions aiohttp/client_proto.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
ClientOSError,
ClientPayloadError,
ServerDisconnectedError,
ServerTimeoutError,
SocketTimeoutError,
)
from .helpers import BaseTimerContext, status_code_must_be_empty_body
from .http import HttpResponseParser, RawResponseMessage
Expand Down Expand Up @@ -193,7 +193,7 @@ def start_timeout(self) -> None:
self._reschedule_timeout()

def _on_read_timeout(self) -> None:
exc = ServerTimeoutError("Timeout on reading data from socket")
exc = SocketTimeoutError("Timeout on reading data from socket")
self.set_exception(exc)
if self._payload is not None:
self._payload.set_exception(exc)
Expand Down
15 changes: 15 additions & 0 deletions docs/client_reference.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2254,6 +2254,17 @@ Connection errors

Derived from :exc:`ServerConnectionError` and :exc:`asyncio.TimeoutError`

.. class:: ConnectionTimeoutError

Connection timeout on request: e.g. read timeout.

Derived from :exc:`ServerTimeoutError`

.. class:: SocketTimeoutError

Reading from socket timeout.

Derived from :exc:`ServerTimeoutError`

Hierarchy of exceptions
^^^^^^^^^^^^^^^^^^^^^^^
Expand Down Expand Up @@ -2284,6 +2295,10 @@ Hierarchy of exceptions

* :exc:`ServerTimeoutError`

* :exc:`ConnectionTimeoutError`

* :exc:`SocketTimeoutError`

* :exc:`ClientPayloadError`

* :exc:`ClientResponseError`
Expand Down
17 changes: 16 additions & 1 deletion tests/test_client_functional.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
import aiohttp
from aiohttp import Fingerprint, ServerFingerprintMismatch, hdrs, web
from aiohttp.abc import AbstractResolver
from aiohttp.client_exceptions import TooManyRedirects
from aiohttp.client_exceptions import SocketTimeoutError, TooManyRedirects
from aiohttp.pytest_plugin import AiohttpClient, TestClient
from aiohttp.test_utils import unused_port

Expand Down Expand Up @@ -3206,6 +3206,21 @@ async def handler(request):
await client.get("/")


async def test_socket_timeout(aiohttp_client: Any) -> None:
async def handler(request):
await asyncio.sleep(5)
return web.Response()

app = web.Application()
app.add_routes([web.get("/", handler)])

timeout = aiohttp.ClientTimeout(sock_read=0.1)
client = await aiohttp_client(app, timeout=timeout)

with pytest.raises(SocketTimeoutError):
await client.get("/")


async def test_read_timeout_closes_connection(aiohttp_client: AiohttpClient) -> None:
request_count = 0

Expand Down

0 comments on commit 730bcb9

Please sign in to comment.