websocket_simple/
protocol.rs

1use std::fmt;
2use std::convert::{Into, From};
3
4use self::OpCode::*;
5/// Operation codes as part of rfc6455.
6#[derive(Debug, Eq, PartialEq, Clone, Copy)]
7pub enum OpCode {
8    /// Indicates a continuation frame of a fragmented message.
9    Continue,
10    /// Indicates a text data frame.
11    Text,
12    /// Indicates a binary data frame.
13    Binary,
14    /// Indicates a close control frame.
15    Close,
16    /// Indicates a ping control frame.
17    Ping,
18    /// Indicates a pong control frame.
19    Pong,
20    /// Indicates an invalid opcode was received.
21    Bad,
22}
23
24impl OpCode {
25
26    /// Test whether the opcode indicates a control frame.
27    pub fn is_control(&self) -> bool {
28        match *self {
29            Text | Binary | Continue => false,
30            _ => true,
31        }
32    }
33
34}
35
36impl fmt::Display for OpCode {
37    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
38        match *self {
39            Continue   =>   write!(f, "CONTINUE"),
40            Text       =>   write!(f, "TEXT"),
41            Binary     =>   write!(f, "BINARY"),
42            Close      =>   write!(f, "CLOSE"),
43            Ping       =>   write!(f, "PING"),
44            Pong       =>   write!(f, "PONG"),
45            Bad        =>   write!(f, "BAD"),
46        }
47    }
48}
49
50impl Into<u8> for OpCode {
51
52    fn into(self) -> u8 {
53        match self {
54            Continue   =>   0,
55            Text       =>   1,
56            Binary     =>   2,
57            Close      =>   8,
58            Ping       =>   9,
59            Pong       =>   10,
60            Bad        => {
61                debug_assert!(false, "Attempted to convert invalid opcode to u8. This is a bug.");
62                8  // if this somehow happens, a close frame will help us tear down quickly
63            }
64        }
65    }
66}
67
68impl From<u8> for OpCode {
69
70    fn from(byte: u8) -> OpCode {
71        match byte {
72            0   =>   Continue,
73            1   =>   Text,
74            2   =>   Binary,
75            8   =>   Close,
76            9   =>   Ping,
77            10  =>   Pong,
78            _   =>   Bad
79        }
80    }
81}
82
83use self::CloseCode::*;
84/// Status code used to indicate why an endpoint is closing the WebSocket connection.
85#[derive(Debug, Eq, PartialEq, Clone, Copy)]
86pub enum CloseCode {
87    /// Indicates a normal closure, meaning that the purpose for
88    /// which the connection was established has been fulfilled.
89    Normal,
90    /// Indicates that an endpoint is "going away", such as a server
91    /// going down or a browser having navigated away from a page.
92    Away,
93    /// Indicates that an endpoint is terminating the connection due
94    /// to a protocol error.
95    Protocol,
96    /// Indicates that an endpoint is terminating the connection
97    /// because it has received a type of data it cannot accept (e.g., an
98    /// endpoint that understands only text data MAY send this if it
99    /// receives a binary message).
100    Unsupported,
101    /// Indicates that no status code was included in a closing frame. This
102    /// close code makes it possible to use a single method, `on_close` to
103    /// handle even cases where no close code was provided.
104    Status,
105    /// Indicates an abnormal closure. If the abnormal closure was due to an
106    /// error, this close code will not be used. Instead, the `on_error` method
107    /// of the handler will be called with the error. However, if the connection
108    /// is simply dropped, without an error, this close code will be sent to the
109    /// handler.
110    Abnormal,
111    /// Indicates that an endpoint is terminating the connection
112    /// because it has received data within a message that was not
113    /// consistent with the type of the message (e.g., non-UTF-8 [RFC3629]
114    /// data within a text message).
115    Invalid,
116    /// Indicates that an endpoint is terminating the connection
117    /// because it has received a message that violates its policy.  This
118    /// is a generic status code that can be returned when there is no
119    /// other more suitable status code (e.g., Unsupported or Size) or if there
120    /// is a need to hide specific details about the policy.
121    Policy,
122    /// Indicates that an endpoint is terminating the connection
123    /// because it has received a message that is too big for it to
124    /// process.
125    Size,
126    /// Indicates that an endpoint (client) is terminating the
127    /// connection because it has expected the server to negotiate one or
128    /// more extension, but the server didn't return them in the response
129    /// message of the WebSocket handshake.  The list of extensions that
130    /// are needed should be given as the reason for closing.
131    /// Note that this status code is not used by the server, because it
132    /// can fail the WebSocket handshake instead.
133    Extension,
134    /// Indicates that a server is terminating the connection because
135    /// it encountered an unexpected condition that prevented it from
136    /// fulfilling the request.
137    Error,
138    /// Indicates that the server is restarting. A client may choose to reconnect,
139    /// and if it does, it should use a randomized delay of 5-30 seconds between attempts.
140    Restart,
141    /// Indicates that the server is overloaded and the client should either connect
142    /// to a different IP (when multiple targets exist), or reconnect to the same IP
143    /// when a user has performed an action.
144    Again,
145    #[doc(hidden)]
146    Tls,
147    #[doc(hidden)]
148    Empty,
149    #[doc(hidden)]
150    Other(u16),
151}
152
153impl Into<u16> for CloseCode {
154
155    fn into(self) -> u16 {
156        match self {
157           Normal        =>   1000,
158           Away          =>   1001,
159           Protocol      =>   1002,
160           Unsupported   =>   1003,
161           Status        =>   1005,
162           Abnormal      =>   1006,
163           Invalid       =>   1007,
164           Policy        =>   1008,
165           Size          =>   1009,
166           Extension     =>   1010,
167           Error         =>   1011,
168           Restart       =>   1012,
169           Again         =>   1013,
170           Tls           =>   1015,
171           Empty         =>   0,
172           Other(code)   =>   code,
173        }
174    }
175}
176
177impl From<u16> for CloseCode {
178
179    fn from(code: u16) -> CloseCode {
180        match code {
181            1000 => Normal,
182            1001 => Away,
183            1002 => Protocol,
184            1003 => Unsupported,
185            1005 => Status,
186            1006 => Abnormal,
187            1007 => Invalid,
188            1008 => Policy,
189            1009 => Size,
190            1010 => Extension,
191            1011 => Error,
192            1012 => Restart,
193            1013 => Again,
194            1015 => Tls,
195            0    => Empty,
196            _ => Other(code),
197        }
198    }
199}
200
201
202mod test {
203    #![allow(unused_imports, unused_variables, dead_code)]
204    use super::*;
205
206    #[test]
207    fn opcode_from_u8() {
208        let byte = 2u8;
209        assert_eq!(OpCode::from(byte), OpCode::Binary);
210    }
211
212    #[test]
213    fn opcode_into_u8() {
214        let text = OpCode::Text;
215        let byte: u8 = text.into();
216        assert_eq!(byte, 1u8);
217    }
218
219    #[test]
220    fn closecode_from_u16() {
221        let byte = 1008u16;
222        assert_eq!(CloseCode::from(byte), CloseCode::Policy);
223    }
224
225    #[test]
226    fn closecode_into_u16() {
227        let text = CloseCode::Away;
228        let byte: u16 = text.into();
229        assert_eq!(byte, 1001u16);
230    }
231}