Coverage for /pythoncovmergedfiles/medio/medio/src/aiohttp/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

147 statements  

1"""HTTP related errors.""" 

2 

3import asyncio 

4from typing import TYPE_CHECKING, Optional, Tuple, Union 

5 

6from multidict import MultiMapping 

7 

8from .typedefs import StrOrURL 

9 

10if TYPE_CHECKING: 

11 import ssl 

12 

13 SSLContext = ssl.SSLContext 

14else: 

15 try: 

16 import ssl 

17 

18 SSLContext = ssl.SSLContext 

19 except ImportError: # pragma: no cover 

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

21 

22if TYPE_CHECKING: 

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

24 from .http_parser import RawResponseMessage 

25else: 

26 RequestInfo = ClientResponse = ConnectionKey = RawResponseMessage = None 

27 

28__all__ = ( 

29 "ClientError", 

30 "ClientConnectionError", 

31 "ClientConnectionResetError", 

32 "ClientOSError", 

33 "ClientConnectorError", 

34 "ClientProxyConnectionError", 

35 "ClientSSLError", 

36 "ClientConnectorDNSError", 

37 "ClientConnectorSSLError", 

38 "ClientConnectorCertificateError", 

39 "ConnectionTimeoutError", 

40 "SocketTimeoutError", 

41 "ServerConnectionError", 

42 "ServerTimeoutError", 

43 "ServerDisconnectedError", 

44 "ServerFingerprintMismatch", 

45 "ClientResponseError", 

46 "ClientHttpProxyError", 

47 "WSServerHandshakeError", 

48 "ContentTypeError", 

49 "ClientPayloadError", 

50 "InvalidURL", 

51 "InvalidUrlClientError", 

52 "RedirectClientError", 

53 "NonHttpUrlClientError", 

54 "InvalidUrlRedirectClientError", 

55 "NonHttpUrlRedirectClientError", 

56 "WSMessageTypeError", 

57) 

58 

59 

60class ClientError(Exception): 

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

62 

63 

64class ClientResponseError(ClientError): 

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

66 

67 request_info: An instance of RequestInfo. 

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

69 status: HTTP status code. 

70 message: Error message. 

71 headers: Response headers. 

72 """ 

73 

74 def __init__( 

75 self, 

76 request_info: RequestInfo, 

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

78 *, 

79 status: Optional[int] = None, 

80 message: str = "", 

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

82 ) -> None: 

83 self.request_info = request_info 

84 if status is not None: 

85 self.status = status 

86 else: 

87 self.status = 0 

88 self.message = message 

89 self.headers = headers 

90 self.history = history 

91 self.args = (request_info, history) 

92 

93 def __str__(self) -> str: 

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

95 self.status, 

96 self.message, 

97 str(self.request_info.real_url), 

98 ) 

99 

100 def __repr__(self) -> str: 

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

102 if self.status != 0: 

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

104 if self.message != "": 

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

106 if self.headers is not None: 

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

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

109 

110 

111class ContentTypeError(ClientResponseError): 

112 """ContentType found is not valid.""" 

113 

114 

115class WSServerHandshakeError(ClientResponseError): 

116 """websocket server handshake error.""" 

117 

118 

119class ClientHttpProxyError(ClientResponseError): 

120 """HTTP proxy error. 

121 

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

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

124 on ``CONNECT`` request. 

125 """ 

126 

127 

128class TooManyRedirects(ClientResponseError): 

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

130 

131 

132class ClientConnectionError(ClientError): 

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

134 

135 

136class ClientConnectionResetError(ClientConnectionError, ConnectionResetError): 

137 """ConnectionResetError""" 

138 

139 

140class ClientOSError(ClientConnectionError, OSError): 

141 """OSError error.""" 

142 

143 

144class ClientConnectorError(ClientOSError): 

145 """Client connector error. 

146 

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

148 a connection can not be established. 

149 """ 

150 

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

152 self._conn_key = connection_key 

153 self._os_error = os_error 

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

155 self.args = (connection_key, os_error) 

156 

157 @property 

158 def os_error(self) -> OSError: 

159 return self._os_error 

160 

161 @property 

162 def host(self) -> str: 

163 return self._conn_key.host 

164 

165 @property 

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

167 return self._conn_key.port 

168 

169 @property 

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

171 return self._conn_key.ssl 

172 

173 def __str__(self) -> str: 

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

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

176 ) 

177 

178 # OSError.__reduce__ does too much black magick 

179 __reduce__ = BaseException.__reduce__ 

180 

181 

182class ClientConnectorDNSError(ClientConnectorError): 

183 """DNS resolution failed during client connection. 

184 

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

186 DNS resolution fails. 

187 """ 

188 

189 

190class ClientProxyConnectionError(ClientConnectorError): 

191 """Proxy connection error. 

192 

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

194 connection to proxy can not be established. 

195 """ 

196 

197 

198class UnixClientConnectorError(ClientConnectorError): 

199 """Unix connector error. 

200 

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

202 if connection to unix socket can not be established. 

203 """ 

204 

205 def __init__( 

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

207 ) -> None: 

208 self._path = path 

209 super().__init__(connection_key, os_error) 

210 

211 @property 

212 def path(self) -> str: 

213 return self._path 

214 

215 def __str__(self) -> str: 

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

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

218 ) 

219 

220 

221class ServerConnectionError(ClientConnectionError): 

222 """Server connection errors.""" 

223 

224 

225class ServerDisconnectedError(ServerConnectionError): 

226 """Server disconnected.""" 

227 

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

229 if message is None: 

230 message = "Server disconnected" 

231 

232 self.args = (message,) 

233 self.message = message 

234 

235 

236class ServerTimeoutError(ServerConnectionError, asyncio.TimeoutError): 

237 """Server timeout error.""" 

238 

239 

240class ConnectionTimeoutError(ServerTimeoutError): 

241 """Connection timeout error.""" 

242 

243 

244class SocketTimeoutError(ServerTimeoutError): 

245 """Socket timeout error.""" 

246 

247 

248class ServerFingerprintMismatch(ServerConnectionError): 

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

250 

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

252 self.expected = expected 

253 self.got = got 

254 self.host = host 

255 self.port = port 

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

257 

258 def __repr__(self) -> str: 

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

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

261 ) 

262 

263 

264class ClientPayloadError(ClientError): 

265 """Response payload error.""" 

266 

267 

268class InvalidURL(ClientError, ValueError): 

269 """Invalid URL. 

270 

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

272 part. 

273 """ 

274 

275 # Derive from ValueError for backward compatibility 

276 

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

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

279 # on URL(url) call 

280 self._url = url 

281 self._description = description 

282 

283 if description: 

284 super().__init__(url, description) 

285 else: 

286 super().__init__(url) 

287 

288 @property 

289 def url(self) -> StrOrURL: 

290 return self._url 

291 

292 @property 

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

294 return self._description 

295 

296 def __repr__(self) -> str: 

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

298 

299 def __str__(self) -> str: 

300 if self._description: 

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

302 return str(self._url) 

303 

304 

305class InvalidUrlClientError(InvalidURL): 

306 """Invalid URL client error.""" 

307 

308 

309class RedirectClientError(ClientError): 

310 """Client redirect error.""" 

311 

312 

313class NonHttpUrlClientError(ClientError): 

314 """Non http URL client error.""" 

315 

316 

317class InvalidUrlRedirectClientError(InvalidUrlClientError, RedirectClientError): 

318 """Invalid URL redirect client error.""" 

319 

320 

321class NonHttpUrlRedirectClientError(NonHttpUrlClientError, RedirectClientError): 

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

323 

324 

325class ClientSSLError(ClientConnectorError): 

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

327 

328 

329if ssl is not None: 

330 cert_errors = (ssl.CertificateError,) 

331 cert_errors_bases = ( 

332 ClientSSLError, 

333 ssl.CertificateError, 

334 ) 

335 

336 ssl_errors = (ssl.SSLError,) 

337 ssl_error_bases = (ClientSSLError, ssl.SSLError) 

338else: # pragma: no cover 

339 cert_errors = tuple() # type: ignore[unreachable] 

340 cert_errors_bases = ( 

341 ClientSSLError, 

342 ValueError, 

343 ) 

344 

345 ssl_errors = tuple() 

346 ssl_error_bases = (ClientSSLError,) 

347 

348 

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

350 """Response ssl error.""" 

351 

352 

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

354 """Response certificate error.""" 

355 

356 def __init__( 

357 self, connection_key: ConnectionKey, certificate_error: Exception 

358 ) -> None: 

359 self._conn_key = connection_key 

360 self._certificate_error = certificate_error 

361 self.args = (connection_key, certificate_error) 

362 

363 @property 

364 def certificate_error(self) -> Exception: 

365 return self._certificate_error 

366 

367 @property 

368 def host(self) -> str: 

369 return self._conn_key.host 

370 

371 @property 

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

373 return self._conn_key.port 

374 

375 @property 

376 def ssl(self) -> bool: 

377 return self._conn_key.is_ssl 

378 

379 def __str__(self) -> str: 

380 return ( 

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

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

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

384 ) 

385 

386 

387class WSMessageTypeError(TypeError): 

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