Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/urllib3/exceptions.py: 60%

115 statements  

« prev     ^ index     » next       coverage.py v7.3.2, created at 2023-12-08 06:40 +0000

1from __future__ import annotations 

2 

3import socket 

4import typing 

5import warnings 

6from email.errors import MessageDefect 

7from http.client import IncompleteRead as httplib_IncompleteRead 

8 

9if typing.TYPE_CHECKING: 

10 from .connection import HTTPConnection 

11 from .connectionpool import ConnectionPool 

12 from .response import HTTPResponse 

13 from .util.retry import Retry 

14 

15# Base Exceptions 

16 

17 

18class HTTPError(Exception): 

19 """Base exception used by this module.""" 

20 

21 

22class HTTPWarning(Warning): 

23 """Base warning used by this module.""" 

24 

25 

26_TYPE_REDUCE_RESULT = typing.Tuple[ 

27 typing.Callable[..., object], typing.Tuple[object, ...] 

28] 

29 

30 

31class PoolError(HTTPError): 

32 """Base exception for errors caused within a pool.""" 

33 

34 def __init__(self, pool: ConnectionPool, message: str) -> None: 

35 self.pool = pool 

36 super().__init__(f"{pool}: {message}") 

37 

38 def __reduce__(self) -> _TYPE_REDUCE_RESULT: 

39 # For pickling purposes. 

40 return self.__class__, (None, None) 

41 

42 

43class RequestError(PoolError): 

44 """Base exception for PoolErrors that have associated URLs.""" 

45 

46 def __init__(self, pool: ConnectionPool, url: str, message: str) -> None: 

47 self.url = url 

48 super().__init__(pool, message) 

49 

50 def __reduce__(self) -> _TYPE_REDUCE_RESULT: 

51 # For pickling purposes. 

52 return self.__class__, (None, self.url, None) 

53 

54 

55class SSLError(HTTPError): 

56 """Raised when SSL certificate fails in an HTTPS connection.""" 

57 

58 

59class ProxyError(HTTPError): 

60 """Raised when the connection to a proxy fails.""" 

61 

62 # The original error is also available as __cause__. 

63 original_error: Exception 

64 

65 def __init__(self, message: str, error: Exception) -> None: 

66 super().__init__(message, error) 

67 self.original_error = error 

68 

69 

70class DecodeError(HTTPError): 

71 """Raised when automatic decoding based on Content-Type fails.""" 

72 

73 

74class ProtocolError(HTTPError): 

75 """Raised when something unexpected happens mid-request/response.""" 

76 

77 

78#: Renamed to ProtocolError but aliased for backwards compatibility. 

79ConnectionError = ProtocolError 

80 

81 

82# Leaf Exceptions 

83 

84 

85class MaxRetryError(RequestError): 

86 """Raised when the maximum number of retries is exceeded. 

87 

88 :param pool: The connection pool 

89 :type pool: :class:`~urllib3.connectionpool.HTTPConnectionPool` 

90 :param str url: The requested Url 

91 :param reason: The underlying error 

92 :type reason: :class:`Exception` 

93 

94 """ 

95 

96 def __init__( 

97 self, pool: ConnectionPool, url: str, reason: Exception | None = None 

98 ) -> None: 

99 self.reason = reason 

100 

101 message = f"Max retries exceeded with url: {url} (Caused by {reason!r})" 

102 

103 super().__init__(pool, url, message) 

104 

105 

106class HostChangedError(RequestError): 

107 """Raised when an existing pool gets a request for a foreign host.""" 

108 

109 def __init__( 

110 self, pool: ConnectionPool, url: str, retries: Retry | int = 3 

111 ) -> None: 

112 message = f"Tried to open a foreign host with url: {url}" 

113 super().__init__(pool, url, message) 

114 self.retries = retries 

115 

116 

117class TimeoutStateError(HTTPError): 

118 """Raised when passing an invalid state to a timeout""" 

119 

120 

121class TimeoutError(HTTPError): 

122 """Raised when a socket timeout error occurs. 

123 

124 Catching this error will catch both :exc:`ReadTimeoutErrors 

125 <ReadTimeoutError>` and :exc:`ConnectTimeoutErrors <ConnectTimeoutError>`. 

126 """ 

127 

128 

129class ReadTimeoutError(TimeoutError, RequestError): 

130 """Raised when a socket timeout occurs while receiving data from a server""" 

131 

132 

133# This timeout error does not have a URL attached and needs to inherit from the 

134# base HTTPError 

135class ConnectTimeoutError(TimeoutError): 

136 """Raised when a socket timeout occurs while connecting to a server""" 

137 

138 

139class NewConnectionError(ConnectTimeoutError, HTTPError): 

140 """Raised when we fail to establish a new connection. Usually ECONNREFUSED.""" 

141 

142 def __init__(self, conn: HTTPConnection, message: str) -> None: 

143 self.conn = conn 

144 super().__init__(f"{conn}: {message}") 

145 

146 @property 

147 def pool(self) -> HTTPConnection: 

148 warnings.warn( 

149 "The 'pool' property is deprecated and will be removed " 

150 "in urllib3 v2.1.0. Use 'conn' instead.", 

151 DeprecationWarning, 

152 stacklevel=2, 

153 ) 

154 

155 return self.conn 

156 

157 

158class NameResolutionError(NewConnectionError): 

159 """Raised when host name resolution fails.""" 

160 

161 def __init__(self, host: str, conn: HTTPConnection, reason: socket.gaierror): 

162 message = f"Failed to resolve '{host}' ({reason})" 

163 super().__init__(conn, message) 

164 

165 

166class EmptyPoolError(PoolError): 

167 """Raised when a pool runs out of connections and no more are allowed.""" 

168 

169 

170class FullPoolError(PoolError): 

171 """Raised when we try to add a connection to a full pool in blocking mode.""" 

172 

173 

174class ClosedPoolError(PoolError): 

175 """Raised when a request enters a pool after the pool has been closed.""" 

176 

177 

178class LocationValueError(ValueError, HTTPError): 

179 """Raised when there is something wrong with a given URL input.""" 

180 

181 

182class LocationParseError(LocationValueError): 

183 """Raised when get_host or similar fails to parse the URL input.""" 

184 

185 def __init__(self, location: str) -> None: 

186 message = f"Failed to parse: {location}" 

187 super().__init__(message) 

188 

189 self.location = location 

190 

191 

192class URLSchemeUnknown(LocationValueError): 

193 """Raised when a URL input has an unsupported scheme.""" 

194 

195 def __init__(self, scheme: str): 

196 message = f"Not supported URL scheme {scheme}" 

197 super().__init__(message) 

198 

199 self.scheme = scheme 

200 

201 

202class ResponseError(HTTPError): 

203 """Used as a container for an error reason supplied in a MaxRetryError.""" 

204 

205 GENERIC_ERROR = "too many error responses" 

206 SPECIFIC_ERROR = "too many {status_code} error responses" 

207 

208 

209class SecurityWarning(HTTPWarning): 

210 """Warned when performing security reducing actions""" 

211 

212 

213class InsecureRequestWarning(SecurityWarning): 

214 """Warned when making an unverified HTTPS request.""" 

215 

216 

217class NotOpenSSLWarning(SecurityWarning): 

218 """Warned when using unsupported SSL library""" 

219 

220 

221class SystemTimeWarning(SecurityWarning): 

222 """Warned when system time is suspected to be wrong""" 

223 

224 

225class InsecurePlatformWarning(SecurityWarning): 

226 """Warned when certain TLS/SSL configuration is not available on a platform.""" 

227 

228 

229class DependencyWarning(HTTPWarning): 

230 """ 

231 Warned when an attempt is made to import a module with missing optional 

232 dependencies. 

233 """ 

234 

235 

236class ResponseNotChunked(ProtocolError, ValueError): 

237 """Response needs to be chunked in order to read it as chunks.""" 

238 

239 

240class BodyNotHttplibCompatible(HTTPError): 

241 """ 

242 Body should be :class:`http.client.HTTPResponse` like 

243 (have an fp attribute which returns raw chunks) for read_chunked(). 

244 """ 

245 

246 

247class IncompleteRead(HTTPError, httplib_IncompleteRead): 

248 """ 

249 Response length doesn't match expected Content-Length 

250 

251 Subclass of :class:`http.client.IncompleteRead` to allow int value 

252 for ``partial`` to avoid creating large objects on streamed reads. 

253 """ 

254 

255 def __init__(self, partial: int, expected: int) -> None: 

256 self.partial = partial # type: ignore[assignment] 

257 self.expected = expected 

258 

259 def __repr__(self) -> str: 

260 return "IncompleteRead(%i bytes read, %i more expected)" % ( 

261 self.partial, # type: ignore[str-format] 

262 self.expected, 

263 ) 

264 

265 

266class InvalidChunkLength(HTTPError, httplib_IncompleteRead): 

267 """Invalid chunk length in a chunked response.""" 

268 

269 def __init__(self, response: HTTPResponse, length: bytes) -> None: 

270 self.partial: int = response.tell() # type: ignore[assignment] 

271 self.expected: int | None = response.length_remaining 

272 self.response = response 

273 self.length = length 

274 

275 def __repr__(self) -> str: 

276 return "InvalidChunkLength(got length %r, %i bytes read)" % ( 

277 self.length, 

278 self.partial, 

279 ) 

280 

281 

282class InvalidHeader(HTTPError): 

283 """The header provided was somehow invalid.""" 

284 

285 

286class ProxySchemeUnknown(AssertionError, URLSchemeUnknown): 

287 """ProxyManager does not support the supplied scheme""" 

288 

289 # TODO(t-8ch): Stop inheriting from AssertionError in v2.0. 

290 

291 def __init__(self, scheme: str | None) -> None: 

292 # 'localhost' is here because our URL parser parses 

293 # localhost:8080 -> scheme=localhost, remove if we fix this. 

294 if scheme == "localhost": 

295 scheme = None 

296 if scheme is None: 

297 message = "Proxy URL had no scheme, should start with http:// or https://" 

298 else: 

299 message = f"Proxy URL had unsupported scheme {scheme}, should use http:// or https://" 

300 super().__init__(message) 

301 

302 

303class ProxySchemeUnsupported(ValueError): 

304 """Fetching HTTPS resources through HTTPS proxies is unsupported""" 

305 

306 

307class HeaderParsingError(HTTPError): 

308 """Raised by assert_header_parsing, but we convert it to a log.warning statement.""" 

309 

310 def __init__( 

311 self, defects: list[MessageDefect], unparsed_data: bytes | str | None 

312 ) -> None: 

313 message = f"{defects or 'Unknown'}, unparsed data: {unparsed_data!r}" 

314 super().__init__(message) 

315 

316 

317class UnrewindableBodyError(HTTPError): 

318 """urllib3 encountered an error when trying to rewind a body"""