Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/aiohttp/client_exceptions.py: 58%

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

163 statements  

1"""HTTP related errors.""" 

2 

3import asyncio 

4import warnings 

5from typing import TYPE_CHECKING, Optional, Tuple, Union 

6 

7from multidict import MultiMapping 

8 

9from .typedefs import StrOrURL 

10 

11if TYPE_CHECKING: 

12 import ssl 

13 

14 SSLContext = ssl.SSLContext 

15else: 

16 try: 

17 import ssl 

18 

19 SSLContext = ssl.SSLContext 

20 except ImportError: # pragma: no cover 

21 ssl = SSLContext = None # type: ignore[assignment] 

22 

23if TYPE_CHECKING: 

24 from .client_reqrep import ClientResponse, ConnectionKey, Fingerprint, RequestInfo 

25 from .http_parser import RawResponseMessage 

26else: 

27 RequestInfo = ClientResponse = ConnectionKey = RawResponseMessage = None 

28 

29__all__ = ( 

30 "ClientError", 

31 "ClientConnectionError", 

32 "ClientConnectionResetError", 

33 "ClientOSError", 

34 "ClientConnectorError", 

35 "ClientProxyConnectionError", 

36 "ClientSSLError", 

37 "ClientConnectorDNSError", 

38 "ClientConnectorSSLError", 

39 "ClientConnectorCertificateError", 

40 "ConnectionTimeoutError", 

41 "SocketTimeoutError", 

42 "ServerConnectionError", 

43 "ServerTimeoutError", 

44 "ServerDisconnectedError", 

45 "ServerFingerprintMismatch", 

46 "ClientResponseError", 

47 "ClientHttpProxyError", 

48 "WSServerHandshakeError", 

49 "ContentTypeError", 

50 "ClientPayloadError", 

51 "InvalidURL", 

52 "InvalidUrlClientError", 

53 "RedirectClientError", 

54 "NonHttpUrlClientError", 

55 "InvalidUrlRedirectClientError", 

56 "NonHttpUrlRedirectClientError", 

57 "WSMessageTypeError", 

58) 

59 

60 

61class ClientError(Exception): 

62 """Base class for client connection errors.""" 

63 

64 

65class ClientResponseError(ClientError): 

66 """Base class for exceptions that occur after getting a response. 

67 

68 request_info: An instance of RequestInfo. 

69 history: A sequence of responses, if redirects occurred. 

70 status: HTTP status code. 

71 message: Error message. 

72 headers: Response headers. 

73 """ 

74 

75 def __init__( 

76 self, 

77 request_info: RequestInfo, 

78 history: Tuple[ClientResponse, ...], 

79 *, 

80 code: Optional[int] = None, 

81 status: Optional[int] = None, 

82 message: str = "", 

83 headers: Optional[MultiMapping[str]] = None, 

84 ) -> None: 

85 self.request_info = request_info 

86 if code is not None: 

87 if status is not None: 

88 raise ValueError( 

89 "Both code and status arguments are provided; " 

90 "code is deprecated, use status instead" 

91 ) 

92 warnings.warn( 

93 "code argument is deprecated, use status instead", 

94 DeprecationWarning, 

95 stacklevel=2, 

96 ) 

97 if status is not None: 

98 self.status = status 

99 elif code is not None: 

100 self.status = code 

101 else: 

102 self.status = 0 

103 self.message = message 

104 self.headers = headers 

105 self.history = history 

106 self.args = (request_info, history) 

107 

108 def __str__(self) -> str: 

109 return "{}, message={!r}, url={!r}".format( 

110 self.status, 

111 self.message, 

112 str(self.request_info.real_url), 

113 ) 

114 

115 def __repr__(self) -> str: 

116 args = f"{self.request_info!r}, {self.history!r}" 

117 if self.status != 0: 

118 args += f", status={self.status!r}" 

119 if self.message != "": 

120 args += f", message={self.message!r}" 

121 if self.headers is not None: 

122 args += f", headers={self.headers!r}" 

123 return f"{type(self).__name__}({args})" 

124 

125 @property 

126 def code(self) -> int: 

127 warnings.warn( 

128 "code property is deprecated, use status instead", 

129 DeprecationWarning, 

130 stacklevel=2, 

131 ) 

132 return self.status 

133 

134 @code.setter 

135 def code(self, value: int) -> None: 

136 warnings.warn( 

137 "code property is deprecated, use status instead", 

138 DeprecationWarning, 

139 stacklevel=2, 

140 ) 

141 self.status = value 

142 

143 

144class ContentTypeError(ClientResponseError): 

145 """ContentType found is not valid.""" 

146 

147 

148class WSServerHandshakeError(ClientResponseError): 

149 """websocket server handshake error.""" 

150 

151 

152class ClientHttpProxyError(ClientResponseError): 

153 """HTTP proxy error. 

154 

155 Raised in :class:`aiohttp.connector.TCPConnector` if 

156 proxy responds with status other than ``200 OK`` 

157 on ``CONNECT`` request. 

158 """ 

159 

160 

161class TooManyRedirects(ClientResponseError): 

162 """Client was redirected too many times.""" 

163 

164 

165class ClientConnectionError(ClientError): 

166 """Base class for client socket errors.""" 

167 

168 

169class ClientConnectionResetError(ClientConnectionError, ConnectionResetError): 

170 """ConnectionResetError""" 

171 

172 

173class ClientOSError(ClientConnectionError, OSError): 

174 """OSError error.""" 

175 

176 

177class ClientConnectorError(ClientOSError): 

178 """Client connector error. 

179 

180 Raised in :class:`aiohttp.connector.TCPConnector` if 

181 a connection can not be established. 

182 """ 

183 

184 def __init__(self, connection_key: ConnectionKey, os_error: OSError) -> None: 

185 self._conn_key = connection_key 

186 self._os_error = os_error 

187 super().__init__(os_error.errno, os_error.strerror) 

188 self.args = (connection_key, os_error) 

189 

190 @property 

191 def os_error(self) -> OSError: 

192 return self._os_error 

193 

194 @property 

195 def host(self) -> str: 

196 return self._conn_key.host 

197 

198 @property 

199 def port(self) -> Optional[int]: 

200 return self._conn_key.port 

201 

202 @property 

203 def ssl(self) -> Union[SSLContext, bool, "Fingerprint"]: 

204 return self._conn_key.ssl 

205 

206 def __str__(self) -> str: 

207 return "Cannot connect to host {0.host}:{0.port} ssl:{1} [{2}]".format( 

208 self, "default" if self.ssl is True else self.ssl, self.strerror 

209 ) 

210 

211 # OSError.__reduce__ does too much black magick 

212 __reduce__ = BaseException.__reduce__ 

213 

214 

215class ClientConnectorDNSError(ClientConnectorError): 

216 """DNS resolution failed during client connection. 

217 

218 Raised in :class:`aiohttp.connector.TCPConnector` if 

219 DNS resolution fails. 

220 """ 

221 

222 

223class ClientProxyConnectionError(ClientConnectorError): 

224 """Proxy connection error. 

225 

226 Raised in :class:`aiohttp.connector.TCPConnector` if 

227 connection to proxy can not be established. 

228 """ 

229 

230 

231class UnixClientConnectorError(ClientConnectorError): 

232 """Unix connector error. 

233 

234 Raised in :py:class:`aiohttp.connector.UnixConnector` 

235 if connection to unix socket can not be established. 

236 """ 

237 

238 def __init__( 

239 self, path: str, connection_key: ConnectionKey, os_error: OSError 

240 ) -> None: 

241 self._path = path 

242 super().__init__(connection_key, os_error) 

243 

244 @property 

245 def path(self) -> str: 

246 return self._path 

247 

248 def __str__(self) -> str: 

249 return "Cannot connect to unix socket {0.path} ssl:{1} [{2}]".format( 

250 self, "default" if self.ssl is True else self.ssl, self.strerror 

251 ) 

252 

253 

254class ServerConnectionError(ClientConnectionError): 

255 """Server connection errors.""" 

256 

257 

258class ServerDisconnectedError(ServerConnectionError): 

259 """Server disconnected.""" 

260 

261 def __init__(self, message: Union[RawResponseMessage, str, None] = None) -> None: 

262 if message is None: 

263 message = "Server disconnected" 

264 

265 self.args = (message,) 

266 self.message = message 

267 

268 

269class ServerTimeoutError(ServerConnectionError, asyncio.TimeoutError): 

270 """Server timeout error.""" 

271 

272 

273class ConnectionTimeoutError(ServerTimeoutError): 

274 """Connection timeout error.""" 

275 

276 

277class SocketTimeoutError(ServerTimeoutError): 

278 """Socket timeout error.""" 

279 

280 

281class ServerFingerprintMismatch(ServerConnectionError): 

282 """SSL certificate does not match expected fingerprint.""" 

283 

284 def __init__(self, expected: bytes, got: bytes, host: str, port: int) -> None: 

285 self.expected = expected 

286 self.got = got 

287 self.host = host 

288 self.port = port 

289 self.args = (expected, got, host, port) 

290 

291 def __repr__(self) -> str: 

292 return "<{} expected={!r} got={!r} host={!r} port={!r}>".format( 

293 self.__class__.__name__, self.expected, self.got, self.host, self.port 

294 ) 

295 

296 

297class ClientPayloadError(ClientError): 

298 """Response payload error.""" 

299 

300 

301class InvalidURL(ClientError, ValueError): 

302 """Invalid URL. 

303 

304 URL used for fetching is malformed, e.g. it doesn't contains host 

305 part. 

306 """ 

307 

308 # Derive from ValueError for backward compatibility 

309 

310 def __init__(self, url: StrOrURL, description: Union[str, None] = None) -> None: 

311 # The type of url is not yarl.URL because the exception can be raised 

312 # on URL(url) call 

313 self._url = url 

314 self._description = description 

315 

316 if description: 

317 super().__init__(url, description) 

318 else: 

319 super().__init__(url) 

320 

321 @property 

322 def url(self) -> StrOrURL: 

323 return self._url 

324 

325 @property 

326 def description(self) -> "str | None": 

327 return self._description 

328 

329 def __repr__(self) -> str: 

330 return f"<{self.__class__.__name__} {self}>" 

331 

332 def __str__(self) -> str: 

333 if self._description: 

334 return f"{self._url} - {self._description}" 

335 return str(self._url) 

336 

337 

338class InvalidUrlClientError(InvalidURL): 

339 """Invalid URL client error.""" 

340 

341 

342class RedirectClientError(ClientError): 

343 """Client redirect error.""" 

344 

345 

346class NonHttpUrlClientError(ClientError): 

347 """Non http URL client error.""" 

348 

349 

350class InvalidUrlRedirectClientError(InvalidUrlClientError, RedirectClientError): 

351 """Invalid URL redirect client error.""" 

352 

353 

354class NonHttpUrlRedirectClientError(NonHttpUrlClientError, RedirectClientError): 

355 """Non http URL redirect client error.""" 

356 

357 

358class ClientSSLError(ClientConnectorError): 

359 """Base error for ssl.*Errors.""" 

360 

361 

362if ssl is not None: 

363 cert_errors = (ssl.CertificateError,) 

364 cert_errors_bases = ( 

365 ClientSSLError, 

366 ssl.CertificateError, 

367 ) 

368 

369 ssl_errors = (ssl.SSLError,) 

370 ssl_error_bases = (ClientSSLError, ssl.SSLError) 

371else: # pragma: no cover 

372 cert_errors = tuple() 

373 cert_errors_bases = ( 

374 ClientSSLError, 

375 ValueError, 

376 ) 

377 

378 ssl_errors = tuple() 

379 ssl_error_bases = (ClientSSLError,) 

380 

381 

382class ClientConnectorSSLError(*ssl_error_bases): # type: ignore[misc] 

383 """Response ssl error.""" 

384 

385 

386class ClientConnectorCertificateError(*cert_errors_bases): # type: ignore[misc] 

387 """Response certificate error.""" 

388 

389 def __init__( 

390 self, connection_key: ConnectionKey, certificate_error: Exception 

391 ) -> None: 

392 self._conn_key = connection_key 

393 self._certificate_error = certificate_error 

394 self.args = (connection_key, certificate_error) 

395 

396 @property 

397 def certificate_error(self) -> Exception: 

398 return self._certificate_error 

399 

400 @property 

401 def host(self) -> str: 

402 return self._conn_key.host 

403 

404 @property 

405 def port(self) -> Optional[int]: 

406 return self._conn_key.port 

407 

408 @property 

409 def ssl(self) -> bool: 

410 return self._conn_key.is_ssl 

411 

412 def __str__(self) -> str: 

413 return ( 

414 "Cannot connect to host {0.host}:{0.port} ssl:{0.ssl} " 

415 "[{0.certificate_error.__class__.__name__}: " 

416 "{0.certificate_error.args}]".format(self) 

417 ) 

418 

419 

420class WSMessageTypeError(TypeError): 

421 """WebSocket message type is not valid."""