Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/aiohttp/client_exceptions.py: 56%
135 statements
« prev ^ index » next coverage.py v7.3.2, created at 2023-12-08 06:40 +0000
« prev ^ index » next coverage.py v7.3.2, created at 2023-12-08 06:40 +0000
1"""HTTP related errors."""
3import asyncio
4import warnings
5from typing import TYPE_CHECKING, Any, Optional, Tuple, Union
7from .http_parser import RawResponseMessage
8from .typedefs import LooseHeaders
10try:
11 import ssl
13 SSLContext = ssl.SSLContext
14except ImportError: # pragma: no cover
15 ssl = SSLContext = None # type: ignore[assignment]
18if TYPE_CHECKING: # pragma: no cover
19 from .client_reqrep import ClientResponse, ConnectionKey, Fingerprint, RequestInfo
20else:
21 RequestInfo = ClientResponse = ConnectionKey = None
23__all__ = (
24 "ClientError",
25 "ClientConnectionError",
26 "ClientOSError",
27 "ClientConnectorError",
28 "ClientProxyConnectionError",
29 "ClientSSLError",
30 "ClientConnectorSSLError",
31 "ClientConnectorCertificateError",
32 "ServerConnectionError",
33 "ServerTimeoutError",
34 "ServerDisconnectedError",
35 "ServerFingerprintMismatch",
36 "ClientResponseError",
37 "ClientHttpProxyError",
38 "WSServerHandshakeError",
39 "ContentTypeError",
40 "ClientPayloadError",
41 "InvalidURL",
42)
45class ClientError(Exception):
46 """Base class for client connection errors."""
49class ClientResponseError(ClientError):
50 """Base class for exceptions that occur after getting a response.
52 request_info: An instance of RequestInfo.
53 history: A sequence of responses, if redirects occurred.
54 status: HTTP status code.
55 message: Error message.
56 headers: Response headers.
57 """
59 def __init__(
60 self,
61 request_info: RequestInfo,
62 history: Tuple[ClientResponse, ...],
63 *,
64 code: Optional[int] = None,
65 status: Optional[int] = None,
66 message: str = "",
67 headers: Optional[LooseHeaders] = None,
68 ) -> None:
69 self.request_info = request_info
70 if code is not None:
71 if status is not None:
72 raise ValueError(
73 "Both code and status arguments are provided; "
74 "code is deprecated, use status instead"
75 )
76 warnings.warn(
77 "code argument is deprecated, use status instead",
78 DeprecationWarning,
79 stacklevel=2,
80 )
81 if status is not None:
82 self.status = status
83 elif code is not None:
84 self.status = code
85 else:
86 self.status = 0
87 self.message = message
88 self.headers = headers
89 self.history = history
90 self.args = (request_info, history)
92 def __str__(self) -> str:
93 return "{}, message={!r}, url={!r}".format(
94 self.status,
95 self.message,
96 self.request_info.real_url,
97 )
99 def __repr__(self) -> str:
100 args = f"{self.request_info!r}, {self.history!r}"
101 if self.status != 0:
102 args += f", status={self.status!r}"
103 if self.message != "":
104 args += f", message={self.message!r}"
105 if self.headers is not None:
106 args += f", headers={self.headers!r}"
107 return f"{type(self).__name__}({args})"
109 @property
110 def code(self) -> int:
111 warnings.warn(
112 "code property is deprecated, use status instead",
113 DeprecationWarning,
114 stacklevel=2,
115 )
116 return self.status
118 @code.setter
119 def code(self, value: int) -> None:
120 warnings.warn(
121 "code property is deprecated, use status instead",
122 DeprecationWarning,
123 stacklevel=2,
124 )
125 self.status = value
128class ContentTypeError(ClientResponseError):
129 """ContentType found is not valid."""
132class WSServerHandshakeError(ClientResponseError):
133 """websocket server handshake error."""
136class ClientHttpProxyError(ClientResponseError):
137 """HTTP proxy error.
139 Raised in :class:`aiohttp.connector.TCPConnector` if
140 proxy responds with status other than ``200 OK``
141 on ``CONNECT`` request.
142 """
145class TooManyRedirects(ClientResponseError):
146 """Client was redirected too many times."""
149class ClientConnectionError(ClientError):
150 """Base class for client socket errors."""
153class ClientOSError(ClientConnectionError, OSError):
154 """OSError error."""
157class ClientConnectorError(ClientOSError):
158 """Client connector error.
160 Raised in :class:`aiohttp.connector.TCPConnector` if
161 a connection can not be established.
162 """
164 def __init__(self, connection_key: ConnectionKey, os_error: OSError) -> None:
165 self._conn_key = connection_key
166 self._os_error = os_error
167 super().__init__(os_error.errno, os_error.strerror)
168 self.args = (connection_key, os_error)
170 @property
171 def os_error(self) -> OSError:
172 return self._os_error
174 @property
175 def host(self) -> str:
176 return self._conn_key.host
178 @property
179 def port(self) -> Optional[int]:
180 return self._conn_key.port
182 @property
183 def ssl(self) -> Union[SSLContext, None, bool, "Fingerprint"]:
184 return self._conn_key.ssl
186 def __str__(self) -> str:
187 return "Cannot connect to host {0.host}:{0.port} ssl:{1} [{2}]".format(
188 self, self.ssl if self.ssl is not None else "default", self.strerror
189 )
191 # OSError.__reduce__ does too much black magick
192 __reduce__ = BaseException.__reduce__
195class ClientProxyConnectionError(ClientConnectorError):
196 """Proxy connection error.
198 Raised in :class:`aiohttp.connector.TCPConnector` if
199 connection to proxy can not be established.
200 """
203class UnixClientConnectorError(ClientConnectorError):
204 """Unix connector error.
206 Raised in :py:class:`aiohttp.connector.UnixConnector`
207 if connection to unix socket can not be established.
208 """
210 def __init__(
211 self, path: str, connection_key: ConnectionKey, os_error: OSError
212 ) -> None:
213 self._path = path
214 super().__init__(connection_key, os_error)
216 @property
217 def path(self) -> str:
218 return self._path
220 def __str__(self) -> str:
221 return "Cannot connect to unix socket {0.path} ssl:{1} [{2}]".format(
222 self, self.ssl if self.ssl is not None else "default", self.strerror
223 )
226class ServerConnectionError(ClientConnectionError):
227 """Server connection errors."""
230class ServerDisconnectedError(ServerConnectionError):
231 """Server disconnected."""
233 def __init__(self, message: Union[RawResponseMessage, str, None] = None) -> None:
234 if message is None:
235 message = "Server disconnected"
237 self.args = (message,)
238 self.message = message
241class ServerTimeoutError(ServerConnectionError, asyncio.TimeoutError):
242 """Server timeout error."""
245class ServerFingerprintMismatch(ServerConnectionError):
246 """SSL certificate does not match expected fingerprint."""
248 def __init__(self, expected: bytes, got: bytes, host: str, port: int) -> None:
249 self.expected = expected
250 self.got = got
251 self.host = host
252 self.port = port
253 self.args = (expected, got, host, port)
255 def __repr__(self) -> str:
256 return "<{} expected={!r} got={!r} host={!r} port={!r}>".format(
257 self.__class__.__name__, self.expected, self.got, self.host, self.port
258 )
261class ClientPayloadError(ClientError):
262 """Response payload error."""
265class InvalidURL(ClientError, ValueError):
266 """Invalid URL.
268 URL used for fetching is malformed, e.g. it doesn't contains host
269 part.
270 """
272 # Derive from ValueError for backward compatibility
274 def __init__(self, url: Any) -> None:
275 # The type of url is not yarl.URL because the exception can be raised
276 # on URL(url) call
277 super().__init__(url)
279 @property
280 def url(self) -> Any:
281 return self.args[0]
283 def __repr__(self) -> str:
284 return f"<{self.__class__.__name__} {self.url}>"
287class ClientSSLError(ClientConnectorError):
288 """Base error for ssl.*Errors."""
291if ssl is not None:
292 cert_errors = (ssl.CertificateError,)
293 cert_errors_bases = (
294 ClientSSLError,
295 ssl.CertificateError,
296 )
298 ssl_errors = (ssl.SSLError,)
299 ssl_error_bases = (ClientSSLError, ssl.SSLError)
300else: # pragma: no cover
301 cert_errors = tuple()
302 cert_errors_bases = (
303 ClientSSLError,
304 ValueError,
305 )
307 ssl_errors = tuple()
308 ssl_error_bases = (ClientSSLError,)
311class ClientConnectorSSLError(*ssl_error_bases): # type: ignore[misc]
312 """Response ssl error."""
315class ClientConnectorCertificateError(*cert_errors_bases): # type: ignore[misc]
316 """Response certificate error."""
318 def __init__(
319 self, connection_key: ConnectionKey, certificate_error: Exception
320 ) -> None:
321 self._conn_key = connection_key
322 self._certificate_error = certificate_error
323 self.args = (connection_key, certificate_error)
325 @property
326 def certificate_error(self) -> Exception:
327 return self._certificate_error
329 @property
330 def host(self) -> str:
331 return self._conn_key.host
333 @property
334 def port(self) -> Optional[int]:
335 return self._conn_key.port
337 @property
338 def ssl(self) -> bool:
339 return self._conn_key.is_ssl
341 def __str__(self) -> str:
342 return (
343 "Cannot connect to host {0.host}:{0.port} ssl:{0.ssl} "
344 "[{0.certificate_error.__class__.__name__}: "
345 "{0.certificate_error.args}]".format(self)
346 )