Line data Source code
1 : /**
2 : Copyright (c) 2024 Stappler LLC <admin@stappler.dev>
3 :
4 : Permission is hereby granted, free of charge, to any person obtaining a copy
5 : of this software and associated documentation files (the "Software"), to deal
6 : in the Software without restriction, including without limitation the rights
7 : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 : copies of the Software, and to permit persons to whom the Software is
9 : furnished to do so, subject to the following conditions:
10 :
11 : The above copyright notice and this permission notice shall be included in
12 : all copies or substantial portions of the Software.
13 :
14 : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 : IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 : FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 : AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 : LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 : OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 : THE SOFTWARE.
21 : **/
22 :
23 : #ifndef EXTRA_WEBSERVER_WEBSERVER_WEBSOCKET_SPWEBWEBSOCKET_H_
24 : #define EXTRA_WEBSERVER_WEBSERVER_WEBSOCKET_SPWEBWEBSOCKET_H_
25 :
26 : #include "SPWeb.h"
27 : #include "SPWebRequest.h"
28 : #include "SPWebHost.h"
29 : #include "SPBuffer.h"
30 :
31 : namespace STAPPLER_VERSIONIZED stappler::web {
32 :
33 : class WebsocketManager;
34 : class WebsocketHandler;
35 :
36 : enum class WebsocketFrameType : uint8_t {
37 : None,
38 :
39 : // User
40 : Text,
41 : Binary,
42 :
43 : // System
44 : Continue,
45 : Close,
46 : Ping,
47 : Pong,
48 : };
49 :
50 : enum class WebsocketStatusCode : uint16_t {
51 : None = 0,
52 : Auto = 1,
53 : Ok = 1000,
54 : Away = 1001,
55 : ProtocolError = 1002,
56 : NotAcceptable = 1003,
57 : ExpectStatus = 1005,
58 : AbnormalClose = 1006,
59 : NotConsistent = 1007,
60 : PolicyViolated = 1008,
61 : TooLarge = 1009,
62 : NotNegotiated = 1010,
63 : UnexceptedCondition = 1011,
64 : SSLError = 1015,
65 : };
66 :
67 :
68 : struct WebsocketFrameReader : AllocBase {
69 : enum class Status : uint8_t {
70 : Head,
71 : Size16,
72 : Size64,
73 : Mask,
74 : Body,
75 : Control
76 : };
77 :
78 : enum class Error : uint8_t {
79 : None,
80 : NotInitialized, // error in reader initialization
81 : ExtraIsNotEmpty,// rsv 1-3 is not empty
82 : NotMasked,// input frame is not masked
83 : UnknownOpcode,// unknown opcode in frame
84 : InvalidSegment,// invalid FIN or OPCODE sequence in segmented frames
85 : InvalidSize,// frame (or sequence) is larger then max size
86 : InvalidAction,// Handler tries to perform invalid reading action
87 : };
88 :
89 : struct Frame {
90 : bool fin; // fin value inside current frame
91 : WebsocketFrameType type; // opcode from first frame
92 : Bytes buffer; // common data buffer
93 : size_t block; // size of completely written block when segmented
94 : size_t offset; // offset inside current frame
95 : };
96 :
97 : static WebsocketFrameType getTypeFromOpcode(uint8_t opcode);
98 : static bool isControlFrameType(WebsocketFrameType t);
99 :
100 : static void unmask(uint32_t mask, size_t offset, uint8_t *data, size_t nbytes);
101 :
102 : template <typename B>
103 5525 : static size_t getBufferRequiredBytes(const B &buf, size_t maxSize) {
104 5525 : return (buf.size() < maxSize) ? (maxSize - buf.size()) : 0;
105 : }
106 :
107 : bool fin = false;
108 : bool masked = false;
109 :
110 : Status status = Status::Head;
111 : Error error = Error::None;
112 : WebsocketFrameType type = WebsocketFrameType::None;
113 : uint8_t extra = 0;
114 : uint32_t mask = 0;
115 : size_t size = 0;
116 : size_t max = config::WEBSOCKET_DEFAULT_MAX_FRAME_SIZE; // absolute maximum (even for segmented frames)
117 :
118 : Frame frame;
119 : pool_t *pool = nullptr;
120 : Root * root = nullptr;
121 : StackBuffer<128> buffer;
122 :
123 : WebsocketFrameReader(Root *r, pool_t *p);
124 :
125 : explicit operator bool() const { return error == Error::None; }
126 :
127 : size_t getRequiredBytes() const;
128 : uint8_t * prepare(size_t &len);
129 : bool save(uint8_t *, size_t nbytes);
130 :
131 : bool isFrameReady() const;
132 : bool isControlReady() const;
133 : void popFrame();
134 : void clear();
135 :
136 : bool updateState();
137 : };
138 :
139 : struct WebsocketFrameWriter : AllocBase {
140 : static uint8_t getOpcodeFromType(WebsocketFrameType opcode);
141 :
142 : static size_t getFrameSize(size_t dataSize, bool masked = false);
143 : static size_t makeHeader(uint8_t *buf, size_t dataSize, WebsocketFrameType t, bool masked = false, uint32_t mask = 0);
144 : static void makeHeader(StackBuffer<32> &buf, size_t dataSize, WebsocketFrameType t, bool masked = false, uint32_t mask = 0);
145 :
146 : struct Slice {
147 : uint8_t *data;
148 : size_t size;
149 : Slice *next;
150 : };
151 :
152 : struct WriteSlot : AllocBase {
153 : pool_t *pool;
154 : size_t alloc = 0;
155 : size_t offset = 0;
156 : Slice *firstData = nullptr;
157 : Slice *lastData = nullptr;
158 :
159 : WriteSlot *next = nullptr;
160 :
161 : WriteSlot(pool_t *p);
162 :
163 : bool empty() const;
164 :
165 : void emplace(const uint8_t *data, size_t size);
166 :
167 : void pop(size_t size);
168 :
169 : uint8_t * getNextBytes() const;
170 : size_t getNextLength() const;
171 : };
172 :
173 : pool_t *pool = nullptr;
174 : WriteSlot *firstSlot = nullptr;
175 : WriteSlot *lastSlot = nullptr;
176 :
177 : WebsocketFrameWriter(pool_t *p);
178 :
179 : bool empty() const;
180 :
181 : WriteSlot *nextReadSlot() const;
182 :
183 : void popReadSlot();
184 :
185 : WriteSlot *nextEmplaceSlot(size_t sizeOfData);
186 : };
187 :
188 :
189 : }
190 :
191 : #endif /* EXTRA_WEBSERVER_WEBSERVER_WEBSOCKET_SPWEBWEBSOCKET_H_ */
|