Oregami
Repositories/oxedyne/fe2o3

oxedyne/fe2o3/fe2o3_net/src/ws/status.rs

4.2 KiB, 14 runs

created by r1870400018:611, which is this file's identity for as long as the history lasts, whatever it is later renamed to

download · who wrote it · its history

1use oxedyne_fe2o3_core::{
2 prelude::*,
3};
4
5use std::{
6 convert::TryFrom,
7};
8
9
10#[derive(Debug, Clone, Copy, Eq, PartialEq)]
11pub enum WebSocketStatusCode {
12 NormalClosure,
13 GoingAway,
14 ProtocolError,
15 UnsupportedData,
16 NoStatusReceived,
17 AbnormalClosure,
18 InvalidFramePayloadData,
19 PolicyViolation,
20 MessageTooBig,
21 MandatoryExtension,
22 InternalServerError,
23 ServiceRestart,
24 TryAgainLater,
25 TlsHandshake,
26 // Application defined
27 Private(u16), // 3000-4999; RFC 6455 §7.4.2 leaves the meaning to the application
28}
29
30impl TryFrom<u16> for WebSocketStatusCode {
31 type Error = Error<ErrTag>;
32
33 fn try_from(value: u16) -> Outcome<Self> {
34 Ok(match value {
35 1000 => WebSocketStatusCode::NormalClosure,
36 1001 => WebSocketStatusCode::GoingAway,
37 1002 => WebSocketStatusCode::ProtocolError,
38 1003 => WebSocketStatusCode::UnsupportedData,
39 1005 => WebSocketStatusCode::NoStatusReceived,
40 1006 => WebSocketStatusCode::AbnormalClosure,
41 1007 => WebSocketStatusCode::InvalidFramePayloadData,
42 1008 => WebSocketStatusCode::PolicyViolation,
43 1009 => WebSocketStatusCode::MessageTooBig,
44 1010 => WebSocketStatusCode::MandatoryExtension,
45 1011 => WebSocketStatusCode::InternalServerError,
46 1012 => WebSocketStatusCode::ServiceRestart,
47 1013 => WebSocketStatusCode::TryAgainLater,
48 1015 => WebSocketStatusCode::TlsHandshake,
49 // An application's own code. A peer that closes with one is not
50 // speaking a code this crate has to understand, and refusing to
51 // decode the frame would turn the peer's goodbye into a read error
52 // for a caller whose whole protocol lives in this range.
53 3000..=4999 => WebSocketStatusCode::Private(value),
54 _ => return Err(err!(
55 "Unrecognised websocket status code {}.", value;
56 Conversion, Integer)),
57 })
58 }
59}
60
61impl From<WebSocketStatusCode> for u16 {
62 fn from(status_code: WebSocketStatusCode) -> Self {
63 match status_code {
64 WebSocketStatusCode::NormalClosure => 1000,
65 WebSocketStatusCode::GoingAway => 1001,
66 WebSocketStatusCode::ProtocolError => 1002,
67 WebSocketStatusCode::UnsupportedData => 1003,
68 WebSocketStatusCode::NoStatusReceived => 1005,
69 WebSocketStatusCode::AbnormalClosure => 1006,
70 WebSocketStatusCode::InvalidFramePayloadData => 1007,
71 WebSocketStatusCode::PolicyViolation => 1008,
72 WebSocketStatusCode::MessageTooBig => 1009,
73 WebSocketStatusCode::MandatoryExtension => 1010,
74 WebSocketStatusCode::InternalServerError => 1011,
75 WebSocketStatusCode::ServiceRestart => 1012,
76 WebSocketStatusCode::TryAgainLater => 1013,
77 WebSocketStatusCode::TlsHandshake => 1015,
78 WebSocketStatusCode::Private(code) => code,
79 }
80 }
81}
82
83impl WebSocketStatusCode {
84 pub fn to_bytes(&self) -> [u8; 2] {
85 u16::from(*self).to_be_bytes()
86 }
87}
88
89
90#[cfg(test)]
91mod tests {
92 use super::*;
93
94 #[test]
95 fn test_an_application_code_survives_the_round_trip() -> Outcome<()> {
96 for code in [3000u16, 4401, 4402, 4403, 4429, 4999] {
97 let parsed = res!(WebSocketStatusCode::try_from(code));
98 assert_eq!(parsed, WebSocketStatusCode::Private(code));
99 assert_eq!(u16::from(parsed), code);
100 assert_eq!(parsed.to_bytes(), code.to_be_bytes());
101 }
102 Ok(())
103 }
104
105 #[test]
106 fn test_a_code_outside_the_application_range_is_still_refused() {
107 // The gap below the application range, and the space above it. Widening
108 // the range to "anything" would let a peer's typo through as a meaning.
109 for code in [0u16, 999, 1004, 1014, 2999, 5000, 65_535] {
110 assert!(WebSocketStatusCode::try_from(code).is_err(),
111 "close code {} was accepted", code);
112 }
113 }
114}