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 : #include "SPWebWebsocket.h"
24 : #include "SPWebRoot.h"
25 :
26 : namespace STAPPLER_VERSIONIZED stappler::web {
27 :
28 1375 : uint8_t WebsocketFrameWriter::getOpcodeFromType(WebsocketFrameType opcode) {
29 1375 : switch (opcode) {
30 0 : case WebsocketFrameType::Continue: return 0x0; break;
31 1350 : case WebsocketFrameType::Text: return 0x1; break;
32 0 : case WebsocketFrameType::Binary: return 0x2; break;
33 25 : case WebsocketFrameType::Close: return 0x8; break;
34 0 : case WebsocketFrameType::Ping: return 0x9; break;
35 0 : case WebsocketFrameType::Pong: return 0xA; break;
36 0 : default: break;
37 : }
38 0 : return 0;
39 : }
40 :
41 1375 : WebsocketFrameType WebsocketFrameReader::getTypeFromOpcode(uint8_t opcode) {
42 1375 : switch (opcode) {
43 0 : case 0x0: return WebsocketFrameType::Continue; break;
44 1350 : case 0x1: return WebsocketFrameType::Text; break;
45 0 : case 0x2: return WebsocketFrameType::Binary; break;
46 25 : case 0x8: return WebsocketFrameType::Close; break;
47 0 : case 0x9: return WebsocketFrameType::Ping; break;
48 0 : case 0xA: return WebsocketFrameType::Pong; break;
49 : }
50 0 : return WebsocketFrameType::None;
51 : }
52 :
53 1375 : bool WebsocketFrameReader::isControlFrameType(WebsocketFrameType t) {
54 1375 : switch (t) {
55 25 : case WebsocketFrameType::Close:
56 : case WebsocketFrameType::Continue:
57 : case WebsocketFrameType::Ping:
58 : case WebsocketFrameType::Pong:
59 25 : return true;
60 : break;
61 1350 : default:
62 1350 : return false;
63 : break;
64 : }
65 : return false;
66 : }
67 :
68 1375 : size_t WebsocketFrameWriter::getFrameSize(size_t dataSize, bool masked) {
69 1375 : size_t sizeSize = (dataSize <= 125) ? 0 : ((dataSize > (size_t)maxOf<uint16_t>())? 8 : 2);
70 1375 : size_t frameSize = 2 + sizeSize;
71 1375 : if (masked) {
72 1375 : frameSize += 4;
73 : }
74 1375 : return frameSize + dataSize;
75 : }
76 :
77 1375 : size_t WebsocketFrameWriter::makeHeader(uint8_t *buf, size_t dataSize, WebsocketFrameType t, bool masked, uint32_t mask) {
78 1375 : size_t sizeSize = (dataSize <= 125) ? 0 : ((dataSize > (size_t)maxOf<uint16_t>())? 8 : 2);
79 1375 : size_t frameSize = 2 + sizeSize;
80 :
81 1375 : buf[0] = ((uint8_t)0b10000000 | getOpcodeFromType(t));
82 1375 : if (sizeSize == 0) {
83 1375 : buf[1] = ((uint8_t)dataSize);
84 0 : } else if (sizeSize == 2) {
85 0 : buf[1] = ((uint8_t)126);
86 0 : uint16_t size = byteorder::HostToNetwork((uint16_t)dataSize);
87 0 : memcpy(buf + 2, &size, sizeof(uint16_t));
88 0 : } else if (sizeSize == 8) {
89 0 : buf[1] = ((uint8_t)127);
90 0 : uint64_t size = byteorder::HostToNetwork((uint64_t)dataSize);
91 0 : memcpy(buf + 2, &size, sizeof(uint64_t));
92 : }
93 1375 : if (masked) {
94 1375 : mask = byteorder::HostToNetwork((uint64_t)mask);
95 1375 : memcpy(buf + frameSize, &mask, sizeof(uint32_t));
96 1375 : buf[1] |= uint8_t(0b10000000);
97 1375 : frameSize += 4;
98 : }
99 :
100 1375 : return frameSize;
101 : }
102 :
103 0 : void WebsocketFrameWriter::makeHeader(StackBuffer<32> &buf, size_t dataSize, WebsocketFrameType t, bool masked, uint32_t mask) {
104 0 : size_t sizeSize = (dataSize <= 125) ? 0 : ((dataSize > (size_t)maxOf<uint16_t>())? 8 : 2);
105 0 : size_t frameSize = 2 + sizeSize;
106 0 : if (masked) {
107 0 : frameSize += 4;
108 : }
109 :
110 0 : makeHeader(buf.prepare(frameSize), dataSize, t);
111 0 : buf.save(nullptr, frameSize);
112 0 : }
113 :
114 1350 : void WebsocketFrameReader::unmask(uint32_t mask, size_t offset, uint8_t *data, size_t nbytes) {
115 1350 : uint8_t j = offset % 4;
116 23175 : for (size_t i = 0; i < nbytes; ++i, ++j) {
117 21825 : if (j >= 4) { j = 0; }
118 21825 : data[i] ^= ((mask >> (j * 8)) & 0xFF);
119 : }
120 1350 : }
121 :
122 1400 : WebsocketFrameReader::WebsocketFrameReader(Root *r, pool_t *p)
123 2800 : : frame(Frame{false, WebsocketFrameType::None, Bytes(), 0, 0})
124 1400 : , pool(memory::pool::create(p)), root(r) {
125 1400 : if (!pool) {
126 0 : error = Error::NotInitialized;
127 : } else {
128 1400 : new (&frame.buffer) Bytes(pool); // switch allocator
129 : }
130 1400 : }
131 :
132 10925 : size_t WebsocketFrameReader::getRequiredBytes() const {
133 10925 : switch (status) {
134 2750 : case Status::Head: return getBufferRequiredBytes(buffer, 2); break;
135 0 : case Status::Size16: return getBufferRequiredBytes(buffer, 2); break;
136 0 : case Status::Size64: return getBufferRequiredBytes(buffer, 8); break;
137 2750 : case Status::Mask: return getBufferRequiredBytes(buffer, 4); break;
138 5400 : case Status::Body: return (frame.offset < size) ? (size - frame.offset) : 0; break;
139 25 : case Status::Control: return getBufferRequiredBytes(buffer, size); break;
140 0 : default: break;
141 : }
142 0 : return 0;
143 : }
144 :
145 4100 : uint8_t * WebsocketFrameReader::prepare(size_t &len) {
146 4100 : switch (status) {
147 2750 : case Status::Head:
148 : case Status::Size16:
149 : case Status::Size64:
150 : case Status::Mask:
151 : case Status::Control:
152 2750 : return buffer.prepare_preserve(len); break;
153 1350 : case Status::Body:
154 1350 : return frame.buffer.data() + frame.block + frame.offset; break;
155 0 : default: break;
156 : }
157 0 : return nullptr;
158 : }
159 :
160 4100 : bool WebsocketFrameReader::save(uint8_t *b, size_t nbytes) {
161 4100 : switch (status) {
162 2750 : case Status::Head:
163 : case Status::Size16:
164 : case Status::Size64:
165 : case Status::Mask:
166 : case Status::Control:
167 2750 : buffer.save(b, nbytes); break;
168 1350 : case Status::Body:
169 1350 : unmask(mask, frame.offset, b, nbytes);
170 1350 : frame.offset += nbytes;
171 1350 : break;
172 0 : default: break;
173 : }
174 :
175 4100 : if (getRequiredBytes() == 0) {
176 4100 : return updateState();
177 : }
178 0 : return true;
179 : }
180 :
181 4100 : bool WebsocketFrameReader::updateState() {
182 4100 : bool shouldPrepareBody = false;
183 4100 : switch (status) {
184 1375 : case Status::Head:
185 1375 : size = 0;
186 1375 : mask = 0;
187 1375 : type = WebsocketFrameType::None;
188 :
189 1375 : fin = (buffer[0] & 0b10000000) != 0;
190 1375 : extra = (buffer[0] & 0b01110000);
191 1375 : type = getTypeFromOpcode
192 1375 : (buffer[0] & 0b00001111);
193 1375 : masked = (buffer[1] & 0b10000000) != 0;
194 1375 : size = (buffer[1] & 0b01111111);
195 :
196 1375 : if (extra != 0 || !masked || type == WebsocketFrameType::None) {
197 0 : if (extra != 0) {
198 0 : error = Error::ExtraIsNotEmpty;
199 0 : } else if (!masked) {
200 0 : error = Error::NotMasked;
201 : } else {
202 0 : error = Error::UnknownOpcode;
203 : }
204 0 : root->error("Websocket", "Invalid control flow", Value(toInt(error)));
205 0 : return false;
206 : }
207 :
208 1375 : if (!frame.buffer.empty()) {
209 0 : if (!isControlFrameType(type)) {
210 0 : error = Error::InvalidSegment;
211 0 : root->error("Websocket", "Invalid segment", Value(toInt(error)));
212 0 : return false;
213 : }
214 : }
215 :
216 1375 : if (size > max) {
217 0 : error = Error::InvalidSize;
218 0 : root->error("Websocket", "Too large query", Value{{
219 0 : pair("size", Value(size)),
220 0 : pair("max", Value(max)),
221 0 : }});
222 0 : return false;
223 : }
224 :
225 1375 : if (size == 126) {
226 0 : size = 0;
227 0 : status = Status::Size16;
228 1375 : } else if (size == 127) {
229 0 : size = 0;
230 0 : status = Status::Size64;
231 : } else {
232 1375 : status = Status::Mask;
233 : }
234 :
235 1375 : buffer.clear();
236 1375 : return true;
237 : break;
238 0 : case Status::Size16:
239 0 : size = buffer.get<BytesViewNetwork>().readUnsigned16();
240 0 : if (size > max) {
241 0 : error = Error::InvalidSize;
242 0 : root->error("Websocket", "Too large query", Value{{
243 0 : pair("size", Value(size)),
244 0 : pair("max", Value(max)),
245 0 : }});
246 0 : return false;
247 : }
248 0 : status = masked?Status::Mask:Status::Body;
249 0 : buffer.clear();
250 0 : shouldPrepareBody = true;
251 0 : break;
252 0 : case Status::Size64:
253 0 : size = buffer.get<BytesViewNetwork>().readUnsigned64();
254 0 : if (size > max) {
255 0 : error = Error::InvalidSize;
256 0 : root->error("Websocket", "Too large query", Value{{
257 0 : pair("size", Value(size)),
258 0 : pair("max", Value(max)),
259 0 : }});
260 0 : return false;
261 : }
262 0 : status = masked?Status::Mask:Status::Body;
263 0 : buffer.clear();
264 0 : shouldPrepareBody = true;
265 0 : break;
266 1375 : case Status::Mask:
267 1375 : mask = buffer.get<BytesView>().readUnsigned32();
268 1375 : status = Status::Body;
269 1375 : buffer.clear();
270 1375 : shouldPrepareBody = true;
271 1375 : break;
272 0 : case Status::Control:
273 0 : break;
274 1350 : case Status::Body:
275 1350 : frame.fin = fin;
276 1350 : frame.block += size;
277 1350 : if (type != WebsocketFrameType::Continue) {
278 1350 : frame.type = type;
279 : }
280 1350 : break;
281 0 : default:
282 0 : break;
283 : }
284 :
285 2725 : if (shouldPrepareBody && status == Status::Body) {
286 1375 : if (isControlFrameType(type)) {
287 25 : status = Status::Control;
288 : } else {
289 1350 : if (size + frame.block > max) {
290 0 : error = Error::InvalidSize;
291 0 : root->error("Websocket", "Too large query", Value{{
292 0 : pair("size", Value(size + frame.block)),
293 0 : pair("max", Value(max)),
294 0 : }});
295 0 : return false;
296 : }
297 1350 : frame.buffer.resize(size + frame.block);
298 : }
299 : }
300 2725 : return true;
301 : }
302 :
303 4100 : bool WebsocketFrameReader::isControlReady() const {
304 4100 : if (status == Status::Control && getRequiredBytes() == 0) {
305 25 : return true;
306 : }
307 4075 : return false;
308 : }
309 4075 : bool WebsocketFrameReader::isFrameReady() const {
310 4075 : if (status == Status::Body && getRequiredBytes() == 0 && frame.fin) {
311 1350 : return true;
312 : }
313 2725 : return false;
314 : }
315 1375 : void WebsocketFrameReader::popFrame() {
316 1375 : switch (status) {
317 25 : case Status::Control:
318 25 : buffer.clear();
319 25 : status = Status::Head;
320 25 : break;
321 1350 : case Status::Body:
322 1350 : clear();
323 1350 : break;
324 0 : default:
325 0 : error = Error::InvalidAction;
326 0 : break;
327 : }
328 1375 : }
329 :
330 1350 : void WebsocketFrameReader::clear() {
331 1350 : frame.buffer.force_clear();
332 1350 : frame.buffer.clear();
333 1350 : memory::pool::clear(pool); // clear frame-related data
334 :
335 1350 : status = Status::Head;
336 1350 : frame.block = 0;
337 1350 : frame.offset = 0;
338 1350 : frame.fin = true;
339 1350 : frame.type = WebsocketFrameType::None;
340 1350 : }
341 :
342 0 : WebsocketFrameWriter::WriteSlot::WriteSlot(pool_t *p) : pool(p) { }
343 :
344 0 : bool WebsocketFrameWriter::WriteSlot::empty() const {
345 0 : return firstData == nullptr;
346 : }
347 :
348 0 : void WebsocketFrameWriter::WriteSlot::emplace(const uint8_t *data, size_t size) {
349 0 : auto mem = pool::palloc(pool, sizeof(Slice) + size);
350 0 : Slice *next = (Slice*) mem;
351 0 : next->data = (uint8_t*) mem + sizeof(Slice);
352 0 : next->size = size;
353 0 : next->next = nullptr;
354 :
355 0 : memcpy(next->data, data, size);
356 :
357 0 : if (lastData) {
358 0 : lastData->next = next;
359 0 : lastData = next;
360 : } else {
361 0 : firstData = next;
362 0 : lastData = next;
363 : }
364 :
365 0 : alloc += size + sizeof(Slice);
366 0 : }
367 :
368 0 : void WebsocketFrameWriter::WriteSlot::pop(size_t size) {
369 0 : if (size >= firstData->size - offset) {
370 0 : firstData = firstData->next;
371 0 : if (!firstData) {
372 0 : lastData = nullptr;
373 : }
374 0 : offset = 0;
375 : } else {
376 0 : offset += size;
377 : }
378 0 : }
379 :
380 0 : uint8_t* WebsocketFrameWriter::WriteSlot::getNextBytes() const {
381 0 : return firstData->data + offset;
382 : }
383 :
384 0 : size_t WebsocketFrameWriter::WriteSlot::getNextLength() const {
385 0 : return firstData->size - offset;
386 : }
387 :
388 25 : WebsocketFrameWriter::WebsocketFrameWriter(pool_t *p) : pool(p) { }
389 :
390 0 : bool WebsocketFrameWriter::empty() const {
391 0 : return firstSlot == nullptr;
392 : }
393 :
394 0 : WebsocketFrameWriter::WriteSlot* WebsocketFrameWriter::nextReadSlot() const {
395 0 : return firstSlot;
396 : }
397 :
398 0 : void WebsocketFrameWriter::popReadSlot() {
399 0 : if (firstSlot->empty()) {
400 0 : memory::pool::destroy(firstSlot->pool);
401 0 : firstSlot = firstSlot->next;
402 0 : if (!firstSlot) {
403 0 : lastSlot = nullptr;
404 : }
405 : }
406 0 : }
407 :
408 0 : WebsocketFrameWriter::WriteSlot* WebsocketFrameWriter::nextEmplaceSlot(size_t sizeOfData) {
409 0 : if (!lastSlot || lastSlot->alloc + sizeOfData > 16_KiB) {
410 0 : auto p = memory::pool::create(pool);
411 0 : WriteSlot *slot = new (p) WriteSlot(p);
412 0 : if (lastSlot) {
413 0 : lastSlot->next = slot;
414 0 : lastSlot = slot;
415 : } else {
416 0 : firstSlot = slot;
417 0 : lastSlot = slot;
418 : }
419 : }
420 0 : return lastSlot;
421 : }
422 :
423 : }
|