Coverage for /pythoncovmergedfiles/medio/medio/src/aiohttp/aiohttp/client_exceptions.py: 59%
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1"""HTTP related errors."""
3import asyncio
4from collections.abc import Mapping
5from typing import TYPE_CHECKING, Union
7from .typedefs import StrOrURL
9try:
10 import ssl
12 SSLContext = ssl.SSLContext
13except ImportError: # pragma: no cover
14 ssl = SSLContext = None # type: ignore[assignment]
16if TYPE_CHECKING:
17 from .client_reqrep import ClientResponse, ConnectionKey, Fingerprint, RequestInfo
18 from .http_parser import RawResponseMessage
19else:
20 RequestInfo = ClientResponse = ConnectionKey = RawResponseMessage = None
22__all__ = (
23 "ClientError",
24 "ClientConnectionError",
25 "ClientConnectionResetError",
26 "ClientOSError",
27 "ClientConnectorError",
28 "ClientProxyConnectionError",
29 "ClientSSLError",
30 "ClientConnectorDNSError",
31 "ClientConnectorSSLError",
32 "ClientConnectorCertificateError",
33 "ConnectionTimeoutError",
34 "SocketTimeoutError",
35 "ServerConnectionError",
36 "ServerTimeoutError",
37 "ServerDisconnectedError",
38 "ServerFingerprintMismatch",
39 "ClientResponseError",
40 "ClientHttpProxyError",
41 "WSServerHandshakeError",
42 "ContentTypeError",
43 "ClientPayloadError",
44 "InvalidURL",
45 "InvalidUrlClientError",
46 "RedirectClientError",
47 "NonHttpUrlClientError",
48 "InvalidUrlRedirectClientError",
49 "NonHttpUrlRedirectClientError",
50 "WSMessageTypeError",
51)
54class ClientError(Exception):
55 """Base class for client connection errors."""
58class ClientResponseError(ClientError):
59 """Base class for exceptions that occur after getting a response.
61 request_info: An instance of RequestInfo.
62 history: A sequence of responses, if redirects occurred.
63 status: HTTP status code.
64 message: Error message.
65 headers: Response headers.
66 """
68 args: tuple[RequestInfo, tuple[ClientResponse, ...]]
70 def __init__(
71 self,
72 request_info: RequestInfo,
73 history: tuple[ClientResponse, ...],
74 *,
75 status: int | None = None,
76 message: str = "",
77 headers: Mapping[str, str] | None = None,
78 ) -> None:
79 self.request_info = request_info
80 if status is not None:
81 self.status = status
82 else:
83 self.status = 0
84 self.message = message
85 self.headers = headers
86 self.history = history
87 self.args = (request_info, history)
89 def __str__(self) -> str:
90 return f"{self.status}, message={self.message!r}, url={str(self.request_info.real_url)!r}"
92 def __repr__(self) -> str:
93 args = f"{self.request_info!r}, {self.history!r}"
94 if self.status != 0:
95 args += f", status={self.status!r}"
96 if self.message != "":
97 args += f", message={self.message!r}"
98 if self.headers is not None:
99 args += f", headers={self.headers!r}"
100 return f"{type(self).__name__}({args})"
103class ContentTypeError(ClientResponseError):
104 """ContentType found is not valid."""
107class WSServerHandshakeError(ClientResponseError):
108 """websocket server handshake error."""
111class ClientHttpProxyError(ClientResponseError):
112 """HTTP proxy error.
114 Raised in :class:`aiohttp.connector.TCPConnector` if
115 proxy responds with status other than ``200 OK``
116 on ``CONNECT`` request.
117 """
120class TooManyRedirects(ClientResponseError):
121 """Client was redirected too many times."""
124class ClientConnectionError(ClientError):
125 """Base class for client socket errors."""
128class ClientConnectionResetError(ClientConnectionError, ConnectionResetError):
129 """ConnectionResetError"""
132class ClientOSError(ClientConnectionError, OSError):
133 """OSError error."""
136class ClientConnectorError(ClientOSError):
137 """Client connector error.
139 Raised in :class:`aiohttp.connector.TCPConnector` if
140 a connection can not be established.
141 """
143 args: tuple[ConnectionKey, OSError]
145 def __init__(self, connection_key: ConnectionKey, os_error: OSError) -> None:
146 self._conn_key = connection_key
147 self._os_error = os_error
148 super().__init__(os_error.errno, os_error.strerror)
149 self.args = (connection_key, os_error)
151 @property
152 def os_error(self) -> OSError:
153 return self._os_error
155 @property
156 def host(self) -> str:
157 return self._conn_key.host
159 @property
160 def port(self) -> int | None:
161 return self._conn_key.port
163 @property
164 def ssl(self) -> Union[SSLContext, bool, "Fingerprint"]:
165 return self._conn_key.ssl
167 def __str__(self) -> str:
168 return "Cannot connect to host {0.host}:{0.port} ssl:{1} [{2}]".format(
169 self, "default" if self.ssl is True else self.ssl, self.strerror
170 )
172 # OSError.__reduce__ does too much black magick
173 __reduce__ = BaseException.__reduce__
176class ClientConnectorDNSError(ClientConnectorError):
177 """DNS resolution failed during client connection.
179 Raised in :class:`aiohttp.connector.TCPConnector` if
180 DNS resolution fails.
181 """
184class ClientProxyConnectionError(ClientConnectorError):
185 """Proxy connection error.
187 Raised in :class:`aiohttp.connector.TCPConnector` if
188 connection to proxy can not be established.
189 """
192class UnixClientConnectorError(ClientConnectorError):
193 """Unix connector error.
195 Raised in :py:class:`aiohttp.connector.UnixConnector`
196 if connection to unix socket can not be established.
197 """
199 def __init__(
200 self, path: str, connection_key: ConnectionKey, os_error: OSError
201 ) -> None:
202 self._path = path
203 super().__init__(connection_key, os_error)
205 @property
206 def path(self) -> str:
207 return self._path
209 def __str__(self) -> str:
210 return "Cannot connect to unix socket {0.path} ssl:{1} [{2}]".format(
211 self, "default" if self.ssl is True else self.ssl, self.strerror
212 )
215class ServerConnectionError(ClientConnectionError):
216 """Server connection errors."""
219class ServerDisconnectedError(ServerConnectionError):
220 """Server disconnected."""
222 args: tuple[RawResponseMessage | str]
224 def __init__(self, message: RawResponseMessage | str | None = None) -> None:
225 if message is None:
226 message = "Server disconnected"
228 self.args = (message,)
229 self.message = message
232class ServerTimeoutError(ServerConnectionError, asyncio.TimeoutError):
233 """Server timeout error."""
236class ConnectionTimeoutError(ServerTimeoutError):
237 """Connection timeout error."""
240class SocketTimeoutError(ServerTimeoutError):
241 """Socket timeout error."""
244class ServerFingerprintMismatch(ServerConnectionError):
245 """SSL certificate does not match expected fingerprint."""
247 args: tuple[bytes, bytes, str, int]
249 def __init__(self, expected: bytes, got: bytes, host: str, port: int) -> None:
250 self.expected = expected
251 self.got = got
252 self.host = host
253 self.port = port
254 self.args = (expected, got, host, port)
256 def __repr__(self) -> str:
257 return f"<{self.__class__.__name__} expected={self.expected!r} got={self.got!r} host={self.host!r} port={self.port!r}>"
260class ClientPayloadError(ClientError):
261 """Response payload error."""
264class InvalidURL(ClientError, ValueError):
265 """Invalid URL.
267 URL used for fetching is malformed, e.g. it doesn't contains host
268 part.
269 """
271 # Derive from ValueError for backward compatibility
273 args: tuple[StrOrURL] | tuple[StrOrURL, str]
275 def __init__(self, url: StrOrURL, description: str | None = None) -> None:
276 # The type of url is not yarl.URL because the exception can be raised
277 # on URL(url) call
278 self._url = url
279 self._description = description
281 if description:
282 super().__init__(url, description)
283 else:
284 super().__init__(url)
286 @property
287 def url(self) -> StrOrURL:
288 return self._url
290 @property
291 def description(self) -> "str | None":
292 return self._description
294 def __repr__(self) -> str:
295 return f"<{self.__class__.__name__} {self}>"
297 def __str__(self) -> str:
298 if self._description:
299 return f"{self._url} - {self._description}"
300 return str(self._url)
303class InvalidUrlClientError(InvalidURL):
304 """Invalid URL client error."""
307class RedirectClientError(ClientError):
308 """Client redirect error."""
311class NonHttpUrlClientError(ClientError):
312 """Non http URL client error."""
315class InvalidUrlRedirectClientError(InvalidUrlClientError, RedirectClientError):
316 """Invalid URL redirect client error."""
319class NonHttpUrlRedirectClientError(NonHttpUrlClientError, RedirectClientError):
320 """Non http URL redirect client error."""
323class ClientSSLError(ClientConnectorError):
324 """Base error for ssl.*Errors."""
327if ssl is not None:
328 cert_errors = (ssl.CertificateError,)
329 cert_errors_bases = (
330 ClientSSLError,
331 ssl.CertificateError,
332 )
334 ssl_errors = (ssl.SSLError,)
335 ssl_error_bases = (ClientSSLError, ssl.SSLError)
336else: # pragma: no cover
337 cert_errors = tuple() # type: ignore[unreachable]
338 cert_errors_bases = (
339 ClientSSLError,
340 ValueError,
341 )
343 ssl_errors = tuple()
344 ssl_error_bases = (ClientSSLError,)
347class ClientConnectorSSLError(*ssl_error_bases): # type: ignore[misc]
348 """Response ssl error."""
351class ClientConnectorCertificateError(*cert_errors_bases): # type: ignore[misc]
352 """Response certificate error."""
354 _conn_key: ConnectionKey
355 args: tuple[ConnectionKey, Exception]
357 def __init__(
358 # TODO: If we require ssl in future, this can become ssl.CertificateError
359 self,
360 connection_key: ConnectionKey,
361 certificate_error: Exception,
362 ) -> None:
363 if isinstance(certificate_error, cert_errors + (OSError,)):
364 # ssl.CertificateError has errno and strerror, so we should be fine
365 os_error = certificate_error
366 else:
367 os_error = OSError()
369 super().__init__(connection_key, os_error)
370 self._certificate_error = certificate_error
371 self.args = (connection_key, certificate_error)
373 @property
374 def certificate_error(self) -> Exception:
375 return self._certificate_error
377 @property
378 def host(self) -> str:
379 return self._conn_key.host
381 @property
382 def port(self) -> int | None:
383 return self._conn_key.port
385 @property
386 def ssl(self) -> bool:
387 return self._conn_key.is_ssl
389 def __str__(self) -> str:
390 return (
391 f"Cannot connect to host {self.host}:{self.port} ssl:{self.ssl} "
392 f"[{self.certificate_error.__class__.__name__}: "
393 f"{self.certificate_error.args}]"
394 )
397class WSMessageTypeError(TypeError):
398 """WebSocket message type is not valid."""