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

112 statements  

« prev     ^ index     » next       coverage.py v7.3.1, created at 2023-09-25 06:20 +0000

1""" 

2:mod:`websockets.exceptions` defines the following exception hierarchy: 

3 

4* :exc:`WebSocketException` 

5 * :exc:`ConnectionClosed` 

6 * :exc:`ConnectionClosedError` 

7 * :exc:`ConnectionClosedOK` 

8 * :exc:`InvalidHandshake` 

9 * :exc:`SecurityError` 

10 * :exc:`InvalidMessage` 

11 * :exc:`InvalidHeader` 

12 * :exc:`InvalidHeaderFormat` 

13 * :exc:`InvalidHeaderValue` 

14 * :exc:`InvalidOrigin` 

15 * :exc:`InvalidUpgrade` 

16 * :exc:`InvalidStatus` 

17 * :exc:`InvalidStatusCode` (legacy) 

18 * :exc:`NegotiationError` 

19 * :exc:`DuplicateParameter` 

20 * :exc:`InvalidParameterName` 

21 * :exc:`InvalidParameterValue` 

22 * :exc:`AbortHandshake` 

23 * :exc:`RedirectHandshake` 

24 * :exc:`InvalidState` 

25 * :exc:`InvalidURI` 

26 * :exc:`PayloadTooBig` 

27 * :exc:`ProtocolError` 

28 

29""" 

30 

31from __future__ import annotations 

32 

33import http 

34from typing import Optional 

35 

36from . import datastructures, frames, http11 

37 

38 

39__all__ = [ 

40 "WebSocketException", 

41 "ConnectionClosed", 

42 "ConnectionClosedError", 

43 "ConnectionClosedOK", 

44 "InvalidHandshake", 

45 "SecurityError", 

46 "InvalidMessage", 

47 "InvalidHeader", 

48 "InvalidHeaderFormat", 

49 "InvalidHeaderValue", 

50 "InvalidOrigin", 

51 "InvalidUpgrade", 

52 "InvalidStatus", 

53 "InvalidStatusCode", 

54 "NegotiationError", 

55 "DuplicateParameter", 

56 "InvalidParameterName", 

57 "InvalidParameterValue", 

58 "AbortHandshake", 

59 "RedirectHandshake", 

60 "InvalidState", 

61 "InvalidURI", 

62 "PayloadTooBig", 

63 "ProtocolError", 

64 "WebSocketProtocolError", 

65] 

66 

67 

68class WebSocketException(Exception): 

69 """ 

70 Base class for all exceptions defined by websockets. 

71 

72 """ 

73 

74 

75class ConnectionClosed(WebSocketException): 

76 """ 

77 Raised when trying to interact with a closed connection. 

78 

79 Attributes: 

80 rcvd (Optional[Close]): if a close frame was received, its code and 

81 reason are available in ``rcvd.code`` and ``rcvd.reason``. 

82 sent (Optional[Close]): if a close frame was sent, its code and reason 

83 are available in ``sent.code`` and ``sent.reason``. 

84 rcvd_then_sent (Optional[bool]): if close frames were received and 

85 sent, this attribute tells in which order this happened, from the 

86 perspective of this side of the connection. 

87 

88 """ 

89 

90 def __init__( 

91 self, 

92 rcvd: Optional[frames.Close], 

93 sent: Optional[frames.Close], 

94 rcvd_then_sent: Optional[bool] = None, 

95 ) -> None: 

96 self.rcvd = rcvd 

97 self.sent = sent 

98 self.rcvd_then_sent = rcvd_then_sent 

99 

100 def __str__(self) -> str: 

101 if self.rcvd is None: 

102 if self.sent is None: 

103 assert self.rcvd_then_sent is None 

104 return "no close frame received or sent" 

105 else: 

106 assert self.rcvd_then_sent is None 

107 return f"sent {self.sent}; no close frame received" 

108 else: 

109 if self.sent is None: 

110 assert self.rcvd_then_sent is None 

111 return f"received {self.rcvd}; no close frame sent" 

112 else: 

113 assert self.rcvd_then_sent is not None 

114 if self.rcvd_then_sent: 

115 return f"received {self.rcvd}; then sent {self.sent}" 

116 else: 

117 return f"sent {self.sent}; then received {self.rcvd}" 

118 

119 # code and reason attributes are provided for backwards-compatibility 

120 

121 @property 

122 def code(self) -> int: 

123 if self.rcvd is None: 

124 return frames.CloseCode.ABNORMAL_CLOSURE 

125 return self.rcvd.code 

126 

127 @property 

128 def reason(self) -> str: 

129 if self.rcvd is None: 

130 return "" 

131 return self.rcvd.reason 

132 

133 

134class ConnectionClosedError(ConnectionClosed): 

135 """ 

136 Like :exc:`ConnectionClosed`, when the connection terminated with an error. 

137 

138 A close frame with a code other than 1000 (OK) or 1001 (going away) was 

139 received or sent, or the closing handshake didn't complete properly. 

140 

141 """ 

142 

143 

144class ConnectionClosedOK(ConnectionClosed): 

145 """ 

146 Like :exc:`ConnectionClosed`, when the connection terminated properly. 

147 

148 A close code with code 1000 (OK) or 1001 (going away) or without a code was 

149 received and sent. 

150 

151 """ 

152 

153 

154class InvalidHandshake(WebSocketException): 

155 """ 

156 Raised during the handshake when the WebSocket connection fails. 

157 

158 """ 

159 

160 

161class SecurityError(InvalidHandshake): 

162 """ 

163 Raised when a handshake request or response breaks a security rule. 

164 

165 Security limits are hard coded. 

166 

167 """ 

168 

169 

170class InvalidMessage(InvalidHandshake): 

171 """ 

172 Raised when a handshake request or response is malformed. 

173 

174 """ 

175 

176 

177class InvalidHeader(InvalidHandshake): 

178 """ 

179 Raised when an HTTP header doesn't have a valid format or value. 

180 

181 """ 

182 

183 def __init__(self, name: str, value: Optional[str] = None) -> None: 

184 self.name = name 

185 self.value = value 

186 

187 def __str__(self) -> str: 

188 if self.value is None: 

189 return f"missing {self.name} header" 

190 elif self.value == "": 

191 return f"empty {self.name} header" 

192 else: 

193 return f"invalid {self.name} header: {self.value}" 

194 

195 

196class InvalidHeaderFormat(InvalidHeader): 

197 """ 

198 Raised when an HTTP header cannot be parsed. 

199 

200 The format of the header doesn't match the grammar for that header. 

201 

202 """ 

203 

204 def __init__(self, name: str, error: str, header: str, pos: int) -> None: 

205 super().__init__(name, f"{error} at {pos} in {header}") 

206 

207 

208class InvalidHeaderValue(InvalidHeader): 

209 """ 

210 Raised when an HTTP header has a wrong value. 

211 

212 The format of the header is correct but a value isn't acceptable. 

213 

214 """ 

215 

216 

217class InvalidOrigin(InvalidHeader): 

218 """ 

219 Raised when the Origin header in a request isn't allowed. 

220 

221 """ 

222 

223 def __init__(self, origin: Optional[str]) -> None: 

224 super().__init__("Origin", origin) 

225 

226 

227class InvalidUpgrade(InvalidHeader): 

228 """ 

229 Raised when the Upgrade or Connection header isn't correct. 

230 

231 """ 

232 

233 

234class InvalidStatus(InvalidHandshake): 

235 """ 

236 Raised when a handshake response rejects the WebSocket upgrade. 

237 

238 """ 

239 

240 def __init__(self, response: http11.Response) -> None: 

241 self.response = response 

242 

243 def __str__(self) -> str: 

244 return ( 

245 "server rejected WebSocket connection: " 

246 f"HTTP {self.response.status_code:d}" 

247 ) 

248 

249 

250class InvalidStatusCode(InvalidHandshake): 

251 """ 

252 Raised when a handshake response status code is invalid. 

253 

254 """ 

255 

256 def __init__(self, status_code: int, headers: datastructures.Headers) -> None: 

257 self.status_code = status_code 

258 self.headers = headers 

259 

260 def __str__(self) -> str: 

261 return f"server rejected WebSocket connection: HTTP {self.status_code}" 

262 

263 

264class NegotiationError(InvalidHandshake): 

265 """ 

266 Raised when negotiating an extension fails. 

267 

268 """ 

269 

270 

271class DuplicateParameter(NegotiationError): 

272 """ 

273 Raised when a parameter name is repeated in an extension header. 

274 

275 """ 

276 

277 def __init__(self, name: str) -> None: 

278 self.name = name 

279 

280 def __str__(self) -> str: 

281 return f"duplicate parameter: {self.name}" 

282 

283 

284class InvalidParameterName(NegotiationError): 

285 """ 

286 Raised when a parameter name in an extension header is invalid. 

287 

288 """ 

289 

290 def __init__(self, name: str) -> None: 

291 self.name = name 

292 

293 def __str__(self) -> str: 

294 return f"invalid parameter name: {self.name}" 

295 

296 

297class InvalidParameterValue(NegotiationError): 

298 """ 

299 Raised when a parameter value in an extension header is invalid. 

300 

301 """ 

302 

303 def __init__(self, name: str, value: Optional[str]) -> None: 

304 self.name = name 

305 self.value = value 

306 

307 def __str__(self) -> str: 

308 if self.value is None: 

309 return f"missing value for parameter {self.name}" 

310 elif self.value == "": 

311 return f"empty value for parameter {self.name}" 

312 else: 

313 return f"invalid value for parameter {self.name}: {self.value}" 

314 

315 

316class AbortHandshake(InvalidHandshake): 

317 """ 

318 Raised to abort the handshake on purpose and return an HTTP response. 

319 

320 This exception is an implementation detail. 

321 

322 The public API 

323 is :meth:`~websockets.server.WebSocketServerProtocol.process_request`. 

324 

325 Attributes: 

326 status (~http.HTTPStatus): HTTP status code. 

327 headers (Headers): HTTP response headers. 

328 body (bytes): HTTP response body. 

329 """ 

330 

331 def __init__( 

332 self, 

333 status: http.HTTPStatus, 

334 headers: datastructures.HeadersLike, 

335 body: bytes = b"", 

336 ) -> None: 

337 # If a user passes an int instead of a HTTPStatus, fix it automatically. 

338 self.status = http.HTTPStatus(status) 

339 self.headers = datastructures.Headers(headers) 

340 self.body = body 

341 

342 def __str__(self) -> str: 

343 return ( 

344 f"HTTP {self.status:d}, " 

345 f"{len(self.headers)} headers, " 

346 f"{len(self.body)} bytes" 

347 ) 

348 

349 

350class RedirectHandshake(InvalidHandshake): 

351 """ 

352 Raised when a handshake gets redirected. 

353 

354 This exception is an implementation detail. 

355 

356 """ 

357 

358 def __init__(self, uri: str) -> None: 

359 self.uri = uri 

360 

361 def __str__(self) -> str: 

362 return f"redirect to {self.uri}" 

363 

364 

365class InvalidState(WebSocketException, AssertionError): 

366 """ 

367 Raised when an operation is forbidden in the current state. 

368 

369 This exception is an implementation detail. 

370 

371 It should never be raised in normal circumstances. 

372 

373 """ 

374 

375 

376class InvalidURI(WebSocketException): 

377 """ 

378 Raised when connecting to a URI that isn't a valid WebSocket URI. 

379 

380 """ 

381 

382 def __init__(self, uri: str, msg: str) -> None: 

383 self.uri = uri 

384 self.msg = msg 

385 

386 def __str__(self) -> str: 

387 return f"{self.uri} isn't a valid URI: {self.msg}" 

388 

389 

390class PayloadTooBig(WebSocketException): 

391 """ 

392 Raised when receiving a frame with a payload exceeding the maximum size. 

393 

394 """ 

395 

396 

397class ProtocolError(WebSocketException): 

398 """ 

399 Raised when a frame breaks the protocol. 

400 

401 """ 

402 

403 

404WebSocketProtocolError = ProtocolError # for backwards compatibility