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

168 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 "UploadAbortedError", 

52 "InvalidURL", 

53 "InvalidUrlClientError", 

54 "RedirectClientError", 

55 "NonHttpUrlClientError", 

56 "InvalidUrlRedirectClientError", 

57 "NonHttpUrlRedirectClientError", 

58 "WSMessageTypeError", 

59) 

60 

61 

62class ClientError(Exception): 

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

64 

65 

66class ClientResponseError(ClientError): 

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

68 

69 request_info: An instance of RequestInfo. 

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

71 status: HTTP status code. 

72 message: Error message. 

73 headers: Response headers. 

74 """ 

75 

76 def __init__( 

77 self, 

78 request_info: RequestInfo, 

79 history: tuple[ClientResponse, ...], 

80 *, 

81 code: int | None = None, 

82 status: int | None = None, 

83 message: str = "", 

84 headers: MultiMapping[str] | None = None, 

85 ) -> None: 

86 self.request_info = request_info 

87 if code is not None: 

88 if status is not None: 

89 raise ValueError( 

90 "Both code and status arguments are provided; " 

91 "code is deprecated, use status instead" 

92 ) 

93 warnings.warn( 

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

95 DeprecationWarning, 

96 stacklevel=2, 

97 ) 

98 if status is not None: 

99 self.status = status 

100 elif code is not None: 

101 self.status = code 

102 else: 

103 self.status = 0 

104 self.message = message 

105 self.headers = headers 

106 self.history = history 

107 self.args = (request_info, history) 

108 

109 def __str__(self) -> str: 

110 return f"{self.status}, message={self.message!r}, url={str(self.request_info.real_url)!r}" 

111 

112 def __repr__(self) -> str: 

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

114 if self.status != 0: 

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

116 if self.message != "": 

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

118 if self.headers is not None: 

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

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

121 

122 @property 

123 def code(self) -> int: 

124 warnings.warn( 

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

126 DeprecationWarning, 

127 stacklevel=2, 

128 ) 

129 return self.status 

130 

131 @code.setter 

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

133 warnings.warn( 

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

135 DeprecationWarning, 

136 stacklevel=2, 

137 ) 

138 self.status = value 

139 

140 

141class ContentTypeError(ClientResponseError): 

142 """ContentType found is not valid.""" 

143 

144 

145class WSServerHandshakeError(ClientResponseError): 

146 """websocket server handshake error.""" 

147 

148 

149class ClientHttpProxyError(ClientResponseError): 

150 """HTTP proxy error. 

151 

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

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

154 on ``CONNECT`` request. 

155 """ 

156 

157 

158class TooManyRedirects(ClientResponseError): 

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

160 

161 

162class ClientConnectionError(ClientError): 

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

164 

165 

166class ClientConnectionResetError(ClientConnectionError, ConnectionResetError): 

167 """ConnectionResetError""" 

168 

169 

170class ClientOSError(ClientConnectionError, OSError): 

171 """OSError error.""" 

172 

173 

174class ClientConnectorError(ClientOSError): 

175 """Client connector error. 

176 

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

178 a connection can not be established. 

179 """ 

180 

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

182 self._conn_key = connection_key 

183 self._os_error = os_error 

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

185 self.args = (connection_key, os_error) 

186 

187 @property 

188 def os_error(self) -> OSError: 

189 return self._os_error 

190 

191 @property 

192 def host(self) -> str: 

193 return self._conn_key.host 

194 

195 @property 

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

197 return self._conn_key.port 

198 

199 @property 

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

201 return self._conn_key.ssl 

202 

203 def __str__(self) -> str: 

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

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

206 ) 

207 

208 # OSError.__reduce__ does too much black magick 

209 __reduce__ = BaseException.__reduce__ 

210 

211 

212class ClientConnectorDNSError(ClientConnectorError): 

213 """DNS resolution failed during client connection. 

214 

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

216 DNS resolution fails. 

217 """ 

218 

219 

220class ClientProxyConnectionError(ClientConnectorError): 

221 """Proxy connection error. 

222 

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

224 connection to proxy can not be established. 

225 """ 

226 

227 

228class UnixClientConnectorError(ClientConnectorError): 

229 """Unix connector error. 

230 

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

232 if connection to unix socket can not be established. 

233 """ 

234 

235 def __init__( 

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

237 ) -> None: 

238 self._path = path 

239 super().__init__(connection_key, os_error) 

240 

241 @property 

242 def path(self) -> str: 

243 return self._path 

244 

245 def __str__(self) -> str: 

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

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

248 ) 

249 

250 

251class ServerConnectionError(ClientConnectionError): 

252 """Server connection errors.""" 

253 

254 

255class ServerDisconnectedError(ServerConnectionError): 

256 """Server disconnected.""" 

257 

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

259 if message is None: 

260 message = "Server disconnected" 

261 

262 self.args = (message,) 

263 self.message = message 

264 

265 

266class ServerTimeoutError(ServerConnectionError, asyncio.TimeoutError): 

267 """Server timeout error.""" 

268 

269 

270class ConnectionTimeoutError(ServerTimeoutError): 

271 """Connection timeout error.""" 

272 

273 

274class SocketTimeoutError(ServerTimeoutError): 

275 """Socket timeout error.""" 

276 

277 

278class ServerFingerprintMismatch(ServerConnectionError): 

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

280 

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

282 self.expected = expected 

283 self.got = got 

284 self.host = host 

285 self.port = port 

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

287 

288 def __repr__(self) -> str: 

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

290 

291 

292class ClientPayloadError(ClientError): 

293 """Response payload error.""" 

294 

295 

296class UploadAbortedError(ClientError): 

297 """The request body was never fully sent.""" 

298 

299 

300class InvalidURL(ClientError, ValueError): 

301 """Invalid URL. 

302 

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

304 part. 

305 """ 

306 

307 # Derive from ValueError for backward compatibility 

308 

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

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

311 # on URL(url) call 

312 self._url = url 

313 self._description = description 

314 

315 if description: 

316 super().__init__(url, description) 

317 else: 

318 super().__init__(url) 

319 

320 @property 

321 def url(self) -> StrOrURL: 

322 return self._url 

323 

324 @property 

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

326 return self._description 

327 

328 def __repr__(self) -> str: 

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

330 

331 def __str__(self) -> str: 

332 if self._description: 

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

334 return str(self._url) 

335 

336 

337class InvalidUrlClientError(InvalidURL): 

338 """Invalid URL client error.""" 

339 

340 

341class RedirectClientError(ClientError): 

342 """Client redirect error.""" 

343 

344 

345class NonHttpUrlClientError(ClientError): 

346 """Non http URL client error.""" 

347 

348 

349class InvalidUrlRedirectClientError(InvalidUrlClientError, RedirectClientError): 

350 """Invalid URL redirect client error.""" 

351 

352 

353class NonHttpUrlRedirectClientError(NonHttpUrlClientError, RedirectClientError): 

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

355 

356 

357class ClientSSLError(ClientConnectorError): 

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

359 

360 

361if ssl is not None: 

362 cert_errors = (ssl.CertificateError,) 

363 cert_errors_bases = ( 

364 ClientSSLError, 

365 ssl.CertificateError, 

366 ) 

367 

368 ssl_errors = (ssl.SSLError,) 

369 ssl_error_bases = (ClientSSLError, ssl.SSLError) 

370else: # pragma: no cover 

371 cert_errors = tuple() 

372 cert_errors_bases = ( 

373 ClientSSLError, 

374 ValueError, 

375 ) 

376 

377 ssl_errors = tuple() 

378 ssl_error_bases = (ClientSSLError,) 

379 

380 

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

382 """Response ssl error.""" 

383 

384 

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

386 """Response certificate error.""" 

387 

388 _conn_key: ConnectionKey 

389 

390 def __init__( 

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

392 self, 

393 connection_key: ConnectionKey, 

394 certificate_error: Exception, 

395 ) -> None: 

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

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

398 os_error = certificate_error 

399 else: 

400 os_error = OSError() 

401 

402 super().__init__(connection_key, os_error) 

403 self._certificate_error = certificate_error 

404 self.args = (connection_key, certificate_error) 

405 

406 @property 

407 def certificate_error(self) -> Exception: 

408 return self._certificate_error 

409 

410 @property 

411 def host(self) -> str: 

412 return self._conn_key.host 

413 

414 @property 

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

416 return self._conn_key.port 

417 

418 @property 

419 def ssl(self) -> bool: 

420 return self._conn_key.is_ssl 

421 

422 def __str__(self) -> str: 

423 return ( 

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

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

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

427 ) 

428 

429 

430class WSMessageTypeError(TypeError): 

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