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.2.7, created at 2023-06-07 06:56 +0000

1"""HTTP related errors.""" 

2 

3import asyncio 

4import warnings 

5from typing import TYPE_CHECKING, Any, Optional, Tuple, Union 

6 

7from .http_parser import RawResponseMessage 

8from .typedefs import LooseHeaders 

9 

10try: 

11 import ssl 

12 

13 SSLContext = ssl.SSLContext 

14except ImportError: # pragma: no cover 

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

16 

17 

18if TYPE_CHECKING: # pragma: no cover 

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

20else: 

21 RequestInfo = ClientResponse = ConnectionKey = None 

22 

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) 

43 

44 

45class ClientError(Exception): 

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

47 

48 

49class ClientResponseError(ClientError): 

50 """Connection error during reading response. 

51 

52 request_info: instance of RequestInfo 

53 """ 

54 

55 def __init__( 

56 self, 

57 request_info: RequestInfo, 

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

59 *, 

60 code: Optional[int] = None, 

61 status: Optional[int] = None, 

62 message: str = "", 

63 headers: Optional[LooseHeaders] = None, 

64 ) -> None: 

65 self.request_info = request_info 

66 if code is not None: 

67 if status is not None: 

68 raise ValueError( 

69 "Both code and status arguments are provided; " 

70 "code is deprecated, use status instead" 

71 ) 

72 warnings.warn( 

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

74 DeprecationWarning, 

75 stacklevel=2, 

76 ) 

77 if status is not None: 

78 self.status = status 

79 elif code is not None: 

80 self.status = code 

81 else: 

82 self.status = 0 

83 self.message = message 

84 self.headers = headers 

85 self.history = history 

86 self.args = (request_info, history) 

87 

88 def __str__(self) -> str: 

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

90 self.status, 

91 self.message, 

92 self.request_info.real_url, 

93 ) 

94 

95 def __repr__(self) -> str: 

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

97 if self.status != 0: 

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

99 if self.message != "": 

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

101 if self.headers is not None: 

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

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

104 

105 @property 

106 def code(self) -> int: 

107 warnings.warn( 

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

109 DeprecationWarning, 

110 stacklevel=2, 

111 ) 

112 return self.status 

113 

114 @code.setter 

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

116 warnings.warn( 

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

118 DeprecationWarning, 

119 stacklevel=2, 

120 ) 

121 self.status = value 

122 

123 

124class ContentTypeError(ClientResponseError): 

125 """ContentType found is not valid.""" 

126 

127 

128class WSServerHandshakeError(ClientResponseError): 

129 """websocket server handshake error.""" 

130 

131 

132class ClientHttpProxyError(ClientResponseError): 

133 """HTTP proxy error. 

134 

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

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

137 on ``CONNECT`` request. 

138 """ 

139 

140 

141class TooManyRedirects(ClientResponseError): 

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

143 

144 

145class ClientConnectionError(ClientError): 

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

147 

148 

149class ClientOSError(ClientConnectionError, OSError): 

150 """OSError error.""" 

151 

152 

153class ClientConnectorError(ClientOSError): 

154 """Client connector error. 

155 

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

157 a connection can not be established. 

158 """ 

159 

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

161 self._conn_key = connection_key 

162 self._os_error = os_error 

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

164 self.args = (connection_key, os_error) 

165 

166 @property 

167 def os_error(self) -> OSError: 

168 return self._os_error 

169 

170 @property 

171 def host(self) -> str: 

172 return self._conn_key.host 

173 

174 @property 

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

176 return self._conn_key.port 

177 

178 @property 

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

180 return self._conn_key.ssl 

181 

182 def __str__(self) -> str: 

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

184 self, self.ssl if self.ssl is not None else "default", self.strerror 

185 ) 

186 

187 # OSError.__reduce__ does too much black magick 

188 __reduce__ = BaseException.__reduce__ 

189 

190 

191class ClientProxyConnectionError(ClientConnectorError): 

192 """Proxy connection error. 

193 

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

195 connection to proxy can not be established. 

196 """ 

197 

198 

199class UnixClientConnectorError(ClientConnectorError): 

200 """Unix connector error. 

201 

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

203 if connection to unix socket can not be established. 

204 """ 

205 

206 def __init__( 

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

208 ) -> None: 

209 self._path = path 

210 super().__init__(connection_key, os_error) 

211 

212 @property 

213 def path(self) -> str: 

214 return self._path 

215 

216 def __str__(self) -> str: 

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

218 self, self.ssl if self.ssl is not None else "default", self.strerror 

219 ) 

220 

221 

222class ServerConnectionError(ClientConnectionError): 

223 """Server connection errors.""" 

224 

225 

226class ServerDisconnectedError(ServerConnectionError): 

227 """Server disconnected.""" 

228 

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

230 if message is None: 

231 message = "Server disconnected" 

232 

233 self.args = (message,) 

234 self.message = message 

235 

236 

237class ServerTimeoutError(ServerConnectionError, asyncio.TimeoutError): 

238 """Server timeout error.""" 

239 

240 

241class ServerFingerprintMismatch(ServerConnectionError): 

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

243 

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

245 self.expected = expected 

246 self.got = got 

247 self.host = host 

248 self.port = port 

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

250 

251 def __repr__(self) -> str: 

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

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

254 ) 

255 

256 

257class ClientPayloadError(ClientError): 

258 """Response payload error.""" 

259 

260 

261class InvalidURL(ClientError, ValueError): 

262 """Invalid URL. 

263 

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

265 part. 

266 """ 

267 

268 # Derive from ValueError for backward compatibility 

269 

270 def __init__(self, url: Any) -> None: 

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

272 # on URL(url) call 

273 super().__init__(url) 

274 

275 @property 

276 def url(self) -> Any: 

277 return self.args[0] 

278 

279 def __repr__(self) -> str: 

280 return f"<{self.__class__.__name__} {self.url}>" 

281 

282 

283class ClientSSLError(ClientConnectorError): 

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

285 

286 

287if ssl is not None: 

288 cert_errors = (ssl.CertificateError,) 

289 cert_errors_bases = ( 

290 ClientSSLError, 

291 ssl.CertificateError, 

292 ) 

293 

294 ssl_errors = (ssl.SSLError,) 

295 ssl_error_bases = (ClientSSLError, ssl.SSLError) 

296else: # pragma: no cover 

297 cert_errors = tuple() 

298 cert_errors_bases = ( 

299 ClientSSLError, 

300 ValueError, 

301 ) 

302 

303 ssl_errors = tuple() 

304 ssl_error_bases = (ClientSSLError,) 

305 

306 

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

308 """Response ssl error.""" 

309 

310 

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

312 """Response certificate error.""" 

313 

314 def __init__( 

315 self, connection_key: ConnectionKey, certificate_error: Exception 

316 ) -> None: 

317 self._conn_key = connection_key 

318 self._certificate_error = certificate_error 

319 self.args = (connection_key, certificate_error) 

320 

321 @property 

322 def certificate_error(self) -> Exception: 

323 return self._certificate_error 

324 

325 @property 

326 def host(self) -> str: 

327 return self._conn_key.host 

328 

329 @property 

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

331 return self._conn_key.port 

332 

333 @property 

334 def ssl(self) -> bool: 

335 return self._conn_key.is_ssl 

336 

337 def __str__(self) -> str: 

338 return ( 

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

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

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

342 )