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

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

149 statements  

1""" 

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

3 

4* :exc:`WebSocketException` 

5 * :exc:`ConnectionClosed` 

6 * :exc:`ConnectionClosedOK` 

7 * :exc:`ConnectionClosedError` 

8 * :exc:`InvalidURI` 

9 * :exc:`InvalidProxy` 

10 * :exc:`InvalidHandshake` 

11 * :exc:`SecurityError` 

12 * :exc:`RequestLineTooLong` 

13 * :exc:`StatusLineTooLong` 

14 * :exc:`HeaderLineTooLong` 

15 * :exc:`TooManyHeaders` 

16 * :exc:`ProxyError` 

17 * :exc:`InvalidProxyMessage` 

18 * :exc:`InvalidProxyStatus` 

19 * :exc:`InvalidMessage` 

20 * :exc:`InvalidMethod` 

21 * :exc:`InvalidProtocol` 

22 * :exc:`InvalidStatus` 

23 * :exc:`InvalidStatusCode` (legacy) 

24 * :exc:`InvalidHeader` 

25 * :exc:`InvalidHeaderFormat` 

26 * :exc:`InvalidHeaderValue` 

27 * :exc:`InvalidOrigin` 

28 * :exc:`InvalidUpgrade` 

29 * :exc:`NegotiationError` 

30 * :exc:`DuplicateParameter` 

31 * :exc:`InvalidParameterName` 

32 * :exc:`InvalidParameterValue` 

33 * :exc:`AbortHandshake` (legacy) 

34 * :exc:`RedirectHandshake` (legacy) 

35 * :exc:`ProtocolError` (Sans-I/O) 

36 * :exc:`PayloadTooBig` (Sans-I/O) 

37 * :exc:`InvalidState` (Sans-I/O) 

38 * :exc:`ConcurrencyError` 

39 

40""" 

41 

42from __future__ import annotations 

43 

44import warnings 

45 

46from .imports import lazy_import 

47 

48 

49__all__ = [ 

50 "WebSocketException", 

51 "ConnectionClosed", 

52 "ConnectionClosedOK", 

53 "ConnectionClosedError", 

54 "InvalidURI", 

55 "InvalidProxy", 

56 "InvalidHandshake", 

57 "SecurityError", 

58 "RequestLineTooLong", 

59 "StatusLineTooLong", 

60 "HeaderLineTooLong", 

61 "TooManyHeaders", 

62 "ProxyError", 

63 "InvalidProxyMessage", 

64 "InvalidProxyStatus", 

65 "InvalidMessage", 

66 "InvalidMethod", 

67 "InvalidProtocol", 

68 "InvalidStatus", 

69 "InvalidHeader", 

70 "InvalidHeaderFormat", 

71 "InvalidHeaderValue", 

72 "InvalidOrigin", 

73 "InvalidUpgrade", 

74 "NegotiationError", 

75 "DuplicateParameter", 

76 "InvalidParameterName", 

77 "InvalidParameterValue", 

78 "ProtocolError", 

79 "PayloadTooBig", 

80 "InvalidState", 

81 "ConcurrencyError", 

82] 

83 

84 

85class WebSocketException(Exception): 

86 """ 

87 Base class for all exceptions defined by websockets. 

88 

89 """ 

90 

91 

92class ConnectionClosed(WebSocketException): 

93 """ 

94 Raised when trying to interact with a closed connection. 

95 

96 Attributes: 

97 rcvd: If a close frame was received, its code and reason are available 

98 in ``rcvd.code`` and ``rcvd.reason``. 

99 sent: If a close frame was sent, its code and reason are available 

100 in ``sent.code`` and ``sent.reason``. 

101 rcvd_then_sent: If close frames were received and sent, this attribute 

102 tells in which order this happened, from the perspective of this 

103 side of the connection. 

104 

105 """ 

106 

107 def __init__( 

108 self, 

109 rcvd: frames.Close | None, 

110 sent: frames.Close | None, 

111 rcvd_then_sent: bool | None = None, 

112 ) -> None: 

113 self.rcvd = rcvd 

114 self.sent = sent 

115 self.rcvd_then_sent = rcvd_then_sent 

116 assert (self.rcvd_then_sent is None) == (self.rcvd is None or self.sent is None) 

117 

118 def __str__(self) -> str: 

119 if self.rcvd is None: 

120 if self.sent is None: 

121 return "no close frame received or sent" 

122 else: 

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

124 else: 

125 if self.sent is None: 

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

127 else: 

128 if self.rcvd_then_sent: 

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

130 else: 

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

132 

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

134 

135 @property 

136 def code(self) -> int: 

137 warnings.warn( # deprecated in 13.1 - 2024-09-21 

138 "ConnectionClosed.code is deprecated; " 

139 "use Protocol.close_code or ConnectionClosed.rcvd.code", 

140 DeprecationWarning, 

141 ) 

142 if self.rcvd is None: 

143 return frames.CloseCode.ABNORMAL_CLOSURE 

144 return self.rcvd.code 

145 

146 @property 

147 def reason(self) -> str: 

148 warnings.warn( # deprecated in 13.1 - 2024-09-21 

149 "ConnectionClosed.reason is deprecated; " 

150 "use Protocol.close_reason or ConnectionClosed.rcvd.reason", 

151 DeprecationWarning, 

152 ) 

153 if self.rcvd is None: 

154 return "" 

155 return self.rcvd.reason 

156 

157 

158class ConnectionClosedOK(ConnectionClosed): 

159 """ 

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

161 

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

163 received and sent. 

164 

165 """ 

166 

167 

168class ConnectionClosedError(ConnectionClosed): 

169 """ 

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

171 

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

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

174 

175 """ 

176 

177 

178class InvalidURI(WebSocketException): 

179 """ 

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

181 

182 """ 

183 

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

185 self.uri = uri 

186 self.msg = msg 

187 

188 def __str__(self) -> str: 

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

190 

191 

192class InvalidProxy(WebSocketException): 

193 """ 

194 Raised when connecting via a proxy that isn't valid. 

195 

196 """ 

197 

198 def __init__(self, proxy: str, msg: str) -> None: 

199 self.proxy = proxy 

200 self.msg = msg 

201 

202 def __str__(self) -> str: 

203 return f"{self.proxy} isn't a valid proxy: {self.msg}" 

204 

205 

206class InvalidHandshake(WebSocketException): 

207 """ 

208 Base class for exceptions raised when the opening handshake fails. 

209 

210 """ 

211 

212 

213class SecurityError(InvalidHandshake): 

214 """ 

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

216 

217 Security limits can be configured with :doc:`environment variables 

218 <../reference/variables>`. 

219 

220 """ 

221 

222 

223class RequestLineTooLong(SecurityError): 

224 """ 

225 Raised when the request line of a handshake request is too long. 

226 

227 """ 

228 

229 

230class StatusLineTooLong(SecurityError): 

231 """ 

232 Raised when the status line of a handshake response is too long. 

233 

234 """ 

235 

236 

237class HeaderLineTooLong(SecurityError): 

238 """ 

239 Raised when a header line of a handshake request or response is too long. 

240 

241 """ 

242 

243 

244class TooManyHeaders(SecurityError): 

245 """ 

246 Raised when a handshake request or response has too many headers. 

247 

248 """ 

249 

250 

251class ProxyError(InvalidHandshake): 

252 """ 

253 Raised when failing to connect to a proxy. 

254 

255 """ 

256 

257 

258class InvalidProxyMessage(ProxyError): 

259 """ 

260 Raised when an HTTP proxy response is malformed. 

261 

262 """ 

263 

264 

265class InvalidProxyStatus(ProxyError): 

266 """ 

267 Raised when an HTTP proxy rejects the connection. 

268 

269 """ 

270 

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

272 self.response = response 

273 

274 def __str__(self) -> str: 

275 return f"proxy rejected connection: HTTP {self.response.status_code:d}" 

276 

277 

278class InvalidMessage(InvalidHandshake): 

279 """ 

280 Raised when a handshake request or response is malformed. 

281 

282 """ 

283 

284 

285class InvalidMethod(InvalidHandshake): 

286 """ 

287 Raised when a handshake request doesn't use HTTP GET. 

288 

289 """ 

290 

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

292 self.method = method 

293 

294 def __str__(self) -> str: 

295 return f"unsupported HTTP method: {self.method}" 

296 

297 

298class InvalidProtocol(InvalidHandshake): 

299 """ 

300 Raised when a handshake request doesn't use HTTP/1.1. 

301 

302 """ 

303 

304 def __init__(self, protocol: str) -> None: 

305 self.protocol = protocol 

306 

307 def __str__(self) -> str: 

308 return f"unsupported HTTP version: {self.protocol}" 

309 

310 

311class InvalidStatus(InvalidHandshake): 

312 """ 

313 Raised when a handshake response rejects the WebSocket upgrade. 

314 

315 """ 

316 

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

318 self.response = response 

319 

320 def __str__(self) -> str: 

321 return ( 

322 f"server rejected WebSocket connection: HTTP {self.response.status_code:d}" 

323 ) 

324 

325 

326class InvalidHeader(InvalidHandshake): 

327 """ 

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

329 

330 """ 

331 

332 def __init__(self, name: str, value: str | None = None) -> None: 

333 self.name = name 

334 self.value = value 

335 

336 def __str__(self) -> str: 

337 if self.value is None: 

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

339 elif self.value == "": 

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

341 else: 

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

343 

344 

345class InvalidHeaderFormat(InvalidHeader): 

346 """ 

347 Raised when an HTTP header cannot be parsed. 

348 

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

350 

351 """ 

352 

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

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

355 

356 

357class InvalidHeaderValue(InvalidHeader): 

358 """ 

359 Raised when an HTTP header has a wrong value. 

360 

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

362 

363 """ 

364 

365 

366class InvalidOrigin(InvalidHeader): 

367 """ 

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

369 

370 """ 

371 

372 def __init__(self, origin: str | None) -> None: 

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

374 

375 

376class InvalidUpgrade(InvalidHeader): 

377 """ 

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

379 

380 """ 

381 

382 

383class NegotiationError(InvalidHandshake): 

384 """ 

385 Raised when negotiating an extension or a subprotocol fails. 

386 

387 """ 

388 

389 

390class DuplicateParameter(NegotiationError): 

391 """ 

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

393 

394 """ 

395 

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

397 self.name = name 

398 

399 def __str__(self) -> str: 

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

401 

402 

403class InvalidParameterName(NegotiationError): 

404 """ 

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

406 

407 """ 

408 

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

410 self.name = name 

411 

412 def __str__(self) -> str: 

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

414 

415 

416class InvalidParameterValue(NegotiationError): 

417 """ 

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

419 

420 """ 

421 

422 def __init__(self, name: str, value: str | None) -> None: 

423 self.name = name 

424 self.value = value 

425 

426 def __str__(self) -> str: 

427 if self.value is None: 

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

429 elif self.value == "": 

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

431 else: 

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

433 

434 

435class ProtocolError(WebSocketException): 

436 """ 

437 Raised when receiving or sending a frame that breaks the protocol. 

438 

439 The Sans-I/O implementation raises this exception when: 

440 

441 * receiving or sending a frame that contains invalid data; 

442 * receiving or sending an invalid sequence of frames. 

443 

444 """ 

445 

446 

447class PayloadTooBig(WebSocketException): 

448 """ 

449 Raised when parsing a frame with a payload that exceeds the maximum size. 

450 

451 The Sans-I/O layer uses this exception internally. It doesn't bubble up to 

452 the I/O layer. 

453 

454 The :meth:`~websockets.extensions.Extension.decode` method of extensions 

455 must raise :exc:`PayloadTooBig` if decoding a frame would exceed the limit. 

456 

457 """ 

458 

459 def __init__( 

460 self, 

461 size_or_message: int | None | str, 

462 max_size: int | None = None, 

463 current_size: int | None = None, 

464 ) -> None: 

465 if isinstance(size_or_message, str): 

466 assert max_size is None 

467 assert current_size is None 

468 warnings.warn( # deprecated in 14.0 - 2024-11-09 

469 "PayloadTooBig(message) is deprecated; " 

470 "change to PayloadTooBig(size, max_size)", 

471 DeprecationWarning, 

472 ) 

473 self.message: str | None = size_or_message 

474 else: 

475 self.message = None 

476 self.size: int | None = size_or_message 

477 assert max_size is not None 

478 self.max_size: int = max_size 

479 self.current_size: int | None = None 

480 self.set_current_size(current_size) 

481 

482 def __str__(self) -> str: 

483 if self.message is not None: 

484 return self.message 

485 else: 

486 message = "frame " 

487 if self.size is not None: 

488 message += f"with {self.size} bytes " 

489 if self.current_size is not None: 

490 message += f"after reading {self.current_size} bytes " 

491 message += f"exceeds limit of {self.max_size} bytes" 

492 return message 

493 

494 def set_current_size(self, current_size: int | None) -> None: 

495 assert self.current_size is None 

496 if current_size is not None: 

497 self.max_size += current_size 

498 self.current_size = current_size 

499 

500 

501class InvalidState(WebSocketException, AssertionError): 

502 """ 

503 Raised when sending a frame is forbidden in the current state. 

504 

505 Specifically, the Sans-I/O layer raises this exception when: 

506 

507 * sending a data frame to a connection in a state other 

508 :attr:`~websockets.protocol.State.OPEN`; 

509 * sending a control frame to a connection in a state other than 

510 :attr:`~websockets.protocol.State.OPEN` or 

511 :attr:`~websockets.protocol.State.CLOSING`. 

512 

513 """ 

514 

515 

516class ConcurrencyError(WebSocketException, RuntimeError): 

517 """ 

518 Raised when receiving or sending messages concurrently. 

519 

520 WebSocket is a connection-oriented protocol. Reads must be serialized; so 

521 must be writes. However, reading and writing concurrently is possible. 

522 

523 """ 

524 

525 

526# At the bottom to break import cycles created by type annotations. 

527from . import frames, http11 # noqa: E402 

528 

529 

530lazy_import( 

531 globals(), 

532 deprecated_aliases={ 

533 # deprecated in 14.0 - 2024-11-09 

534 "AbortHandshake": ".legacy.exceptions", 

535 "InvalidStatusCode": ".legacy.exceptions", 

536 "RedirectHandshake": ".legacy.exceptions", 

537 "WebSocketProtocolError": ".legacy.exceptions", 

538 }, 

539)