1 module hunt.http.codec.websocket.model.common;
2 
3 final class WebSocketConstants {
4     enum string SEC_WEBSOCKET_EXTENSIONS = "Sec-WebSocket-Extensions";
5     enum string SEC_WEBSOCKET_PROTOCOL = "Sec-WebSocket-Protocol";
6     enum string SEC_WEBSOCKET_VERSION = "Sec-WebSocket-Version";
7     enum int SPEC_VERSION = 13;
8 }
9 
10 
11 /**
12  * Behavior for how the WebSocket should operate.
13  * <p>
14  * This dictated by the <a href="https://tools.ietf.org/html/rfc6455">RFC 6455</a> spec in various places, where certain behavior must be performed depending on
15  * operation as a <a href="https://tools.ietf.org/html/rfc6455#section-4.1">CLIENT</a> vs a <a href="https://tools.ietf.org/html/rfc6455#section-4.2">SERVER</a>
16  */
17 enum WebSocketBehavior {
18     CLIENT, SERVER
19 }
20 
21 
22 /**
23  * Connection states as outlined in <a href="https://tools.ietf.org/html/rfc6455">RFC6455</a>.
24  */
25 enum ConnectionState {
26     Unknown,
27     
28     /**
29      * [RFC] Initial state of a connection, the upgrade request / response is in progress
30      */
31     CONNECTING,
32     /**
33      * [Impl] Intermediate state between CONNECTING and OPEN, used to indicate that a upgrade request/response is successful, but the end-user provided socket's
34      * onOpen code has yet to run.
35      * <p>
36      * This state is to allow the local socket to initiate messages and frames, but to NOT start reading yet.
37      */
38     CONNECTED,
39     /**
40      * [RFC] The websocket connection is established and open.
41      * <p>
42      * This indicates that the Upgrade has succeed, and the end-user provided socket's onOpen code has completed.
43      * <p>
44      * It is now time to start reading from the remote endpoint.
45      */
46     OPEN,
47     /**
48      * [RFC] The websocket closing handshake is started.
49      * <p>
50      * This can be considered a half-closed state.
51      * <p>
52      * When receiving this as an event on {@link ConnectionStateListener#onConnectionStateChange(ConnectionState)} a close frame should be sent using
53      * the {@link CloseInfo} available from {@link IOState#getCloseInfo()}
54      */
55     CLOSING,
56     /**
57      * [RFC] The websocket connection is closed.
58      * <p>
59      * Connection should be disconnected and no further reads or writes should occur.
60      */
61     CLOSED
62 }
63 
64 final class OpCode {
65     /**
66      * OpCode for a Continuation Frame
67      *
68      * @see <a href="https://tools.ietf.org/html/rfc6455#section-11.8">RFC 6455, Section 11.8 (WebSocket Opcode Registry</a>
69      */
70     enum byte CONTINUATION = cast(byte) 0x00;
71 
72     /**
73      * OpCode for a Text Frame
74      *
75      * @see <a href="https://tools.ietf.org/html/rfc6455#section-11.8">RFC 6455, Section 11.8 (WebSocket Opcode Registry</a>
76      */
77     enum byte TEXT = cast(byte) 0x01;
78 
79     /**
80      * OpCode for a Binary Frame
81      *
82      * @see <a href="https://tools.ietf.org/html/rfc6455#section-11.8">RFC 6455, Section 11.8 (WebSocket Opcode Registry</a>
83      */
84     enum byte BINARY = cast(byte) 0x02;
85 
86     /**
87      * OpCode for a Close Frame
88      *
89      * @see <a href="https://tools.ietf.org/html/rfc6455#section-11.8">RFC 6455, Section 11.8 (WebSocket Opcode Registry</a>
90      */
91     enum byte CLOSE = cast(byte) 0x08;
92 
93     /**
94      * OpCode for a Ping Frame
95      *
96      * @see <a href="https://tools.ietf.org/html/rfc6455#section-11.8">RFC 6455, Section 11.8 (WebSocket Opcode Registry</a>
97      */
98     enum byte PING = cast(byte) 0x09;
99 
100     /**
101      * OpCode for a Pong Frame
102      *
103      * @see <a href="https://tools.ietf.org/html/rfc6455#section-11.8">RFC 6455, Section 11.8 (WebSocket Opcode Registry</a>
104      */
105     enum byte PONG = cast(byte) 0x0A;
106 
107     /**
108      * An undefined OpCode
109      */
110     enum byte UNDEFINED = cast(byte) -1;
111 
112     static bool isControlFrame(byte opcode) {
113         return (opcode >= CLOSE);
114     }
115 
116     static bool isDataFrame(byte opcode) {
117         return (opcode == TEXT) || (opcode == BINARY);
118     }
119 
120     /**
121      * Test for known opcodes (per the RFC spec)
122      *
123      * @param opcode the opcode to test
124      * @return true if known. false if unknown, undefined, or reserved
125      */
126     static bool isKnown(byte opcode) {
127         return (opcode == CONTINUATION) || (opcode == TEXT) || (opcode == BINARY) || 
128             (opcode == CLOSE) || (opcode == PING) || (opcode == PONG);
129     }
130 
131     static string name(byte opcode) {
132         switch (opcode) {
133             case -1:
134                 return "NO-OP";
135             case CONTINUATION:
136                 return "CONTINUATION";
137             case TEXT:
138                 return "TEXT";
139             case BINARY:
140                 return "BINARY";
141             case CLOSE:
142                 return "CLOSE";
143             case PING:
144                 return "PING";
145             case PONG:
146                 return "PONG";
147             default:
148                 return "NON-SPEC[" ~ opcode ~ "]";
149         }
150     }
151 }