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

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

167 statements  

1"""HTTP related errors.""" 

2 

3import asyncio 

4import warnings 

5from typing import TYPE_CHECKING, 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: int | None = None, 

81 status: int | None = None, 

82 message: str = "", 

83 headers: MultiMapping[str] | None = 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 f"{self.status}, message={self.message!r}, url={str(self.request_info.real_url)!r}" 

110 

111 def __repr__(self) -> str: 

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

113 if self.status != 0: 

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

115 if self.message != "": 

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

117 if self.headers is not None: 

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

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

120 

121 @property 

122 def code(self) -> int: 

123 warnings.warn( 

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

125 DeprecationWarning, 

126 stacklevel=2, 

127 ) 

128 return self.status 

129 

130 @code.setter 

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

132 warnings.warn( 

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

134 DeprecationWarning, 

135 stacklevel=2, 

136 ) 

137 self.status = value 

138 

139 

140class ContentTypeError(ClientResponseError): 

141 """ContentType found is not valid.""" 

142 

143 

144class WSServerHandshakeError(ClientResponseError): 

145 """websocket server handshake error.""" 

146 

147 

148class ClientHttpProxyError(ClientResponseError): 

149 """HTTP proxy error. 

150 

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

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

153 on ``CONNECT`` request. 

154 """ 

155 

156 

157class TooManyRedirects(ClientResponseError): 

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

159 

160 

161class ClientConnectionError(ClientError): 

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

163 

164 

165class ClientConnectionResetError(ClientConnectionError, ConnectionResetError): 

166 """ConnectionResetError""" 

167 

168 

169class ClientOSError(ClientConnectionError, OSError): 

170 """OSError error.""" 

171 

172 

173class ClientConnectorError(ClientOSError): 

174 """Client connector error. 

175 

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

177 a connection can not be established. 

178 """ 

179 

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

181 self._conn_key = connection_key 

182 self._os_error = os_error 

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

184 self.args = (connection_key, os_error) 

185 

186 @property 

187 def os_error(self) -> OSError: 

188 return self._os_error 

189 

190 @property 

191 def host(self) -> str: 

192 return self._conn_key.host 

193 

194 @property 

195 def port(self) -> int | None: 

196 return self._conn_key.port 

197 

198 @property 

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

200 return self._conn_key.ssl 

201 

202 def __str__(self) -> str: 

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

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

205 ) 

206 

207 # OSError.__reduce__ does too much black magick 

208 __reduce__ = BaseException.__reduce__ 

209 

210 

211class ClientConnectorDNSError(ClientConnectorError): 

212 """DNS resolution failed during client connection. 

213 

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

215 DNS resolution fails. 

216 """ 

217 

218 

219class ClientProxyConnectionError(ClientConnectorError): 

220 """Proxy connection error. 

221 

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

223 connection to proxy can not be established. 

224 """ 

225 

226 

227class UnixClientConnectorError(ClientConnectorError): 

228 """Unix connector error. 

229 

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

231 if connection to unix socket can not be established. 

232 """ 

233 

234 def __init__( 

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

236 ) -> None: 

237 self._path = path 

238 super().__init__(connection_key, os_error) 

239 

240 @property 

241 def path(self) -> str: 

242 return self._path 

243 

244 def __str__(self) -> str: 

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

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

247 ) 

248 

249 

250class ServerConnectionError(ClientConnectionError): 

251 """Server connection errors.""" 

252 

253 

254class ServerDisconnectedError(ServerConnectionError): 

255 """Server disconnected.""" 

256 

257 def __init__(self, message: RawResponseMessage | str | None = None) -> None: 

258 if message is None: 

259 message = "Server disconnected" 

260 

261 self.args = (message,) 

262 self.message = message 

263 

264 

265class ServerTimeoutError(ServerConnectionError, asyncio.TimeoutError): 

266 """Server timeout error.""" 

267 

268 

269class ConnectionTimeoutError(ServerTimeoutError): 

270 """Connection timeout error.""" 

271 

272 

273class SocketTimeoutError(ServerTimeoutError): 

274 """Socket timeout error.""" 

275 

276 

277class ServerFingerprintMismatch(ServerConnectionError): 

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

279 

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

281 self.expected = expected 

282 self.got = got 

283 self.host = host 

284 self.port = port 

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

286 

287 def __repr__(self) -> str: 

288 return f"<{self.__class__.__name__} expected={self.expected!r} got={self.got!r} host={self.host!r} port={self.port!r}>" 

289 

290 

291class ClientPayloadError(ClientError): 

292 """Response payload error.""" 

293 

294 

295class InvalidURL(ClientError, ValueError): 

296 """Invalid URL. 

297 

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

299 part. 

300 """ 

301 

302 # Derive from ValueError for backward compatibility 

303 

304 def __init__(self, url: StrOrURL, description: str | None = None) -> None: 

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

306 # on URL(url) call 

307 self._url = url 

308 self._description = description 

309 

310 if description: 

311 super().__init__(url, description) 

312 else: 

313 super().__init__(url) 

314 

315 @property 

316 def url(self) -> StrOrURL: 

317 return self._url 

318 

319 @property 

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

321 return self._description 

322 

323 def __repr__(self) -> str: 

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

325 

326 def __str__(self) -> str: 

327 if self._description: 

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

329 return str(self._url) 

330 

331 

332class InvalidUrlClientError(InvalidURL): 

333 """Invalid URL client error.""" 

334 

335 

336class RedirectClientError(ClientError): 

337 """Client redirect error.""" 

338 

339 

340class NonHttpUrlClientError(ClientError): 

341 """Non http URL client error.""" 

342 

343 

344class InvalidUrlRedirectClientError(InvalidUrlClientError, RedirectClientError): 

345 """Invalid URL redirect client error.""" 

346 

347 

348class NonHttpUrlRedirectClientError(NonHttpUrlClientError, RedirectClientError): 

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

350 

351 

352class ClientSSLError(ClientConnectorError): 

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

354 

355 

356if ssl is not None: 

357 cert_errors = (ssl.CertificateError,) 

358 cert_errors_bases = ( 

359 ClientSSLError, 

360 ssl.CertificateError, 

361 ) 

362 

363 ssl_errors = (ssl.SSLError,) 

364 ssl_error_bases = (ClientSSLError, ssl.SSLError) 

365else: # pragma: no cover 

366 cert_errors = tuple() 

367 cert_errors_bases = ( 

368 ClientSSLError, 

369 ValueError, 

370 ) 

371 

372 ssl_errors = tuple() 

373 ssl_error_bases = (ClientSSLError,) 

374 

375 

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

377 """Response ssl error.""" 

378 

379 

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

381 """Response certificate error.""" 

382 

383 _conn_key: ConnectionKey 

384 

385 def __init__( 

386 # TODO: If we require ssl in future, this can become ssl.CertificateError 

387 self, 

388 connection_key: ConnectionKey, 

389 certificate_error: Exception, 

390 ) -> None: 

391 if isinstance(certificate_error, cert_errors + (OSError,)): 

392 # ssl.CertificateError has errno and strerror, so we should be fine 

393 os_error = certificate_error 

394 else: 

395 os_error = OSError() 

396 

397 super().__init__(connection_key, os_error) 

398 self._certificate_error = certificate_error 

399 self.args = (connection_key, certificate_error) 

400 

401 @property 

402 def certificate_error(self) -> Exception: 

403 return self._certificate_error 

404 

405 @property 

406 def host(self) -> str: 

407 return self._conn_key.host 

408 

409 @property 

410 def port(self) -> int | None: 

411 return self._conn_key.port 

412 

413 @property 

414 def ssl(self) -> bool: 

415 return self._conn_key.is_ssl 

416 

417 def __str__(self) -> str: 

418 return ( 

419 f"Cannot connect to host {self.host}:{self.port} ssl:{self.ssl} " 

420 f"[{self.certificate_error.__class__.__name__}: " 

421 f"{self.certificate_error.args}]" 

422 ) 

423 

424 

425class WSMessageTypeError(TypeError): 

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