aboutsummaryrefslogtreecommitdiff
path: root/src/microhttpd_ws/mhd_websocket.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/microhttpd_ws/mhd_websocket.c')
-rw-r--r--src/microhttpd_ws/mhd_websocket.c2072
1 files changed, 2072 insertions, 0 deletions
diff --git a/src/microhttpd_ws/mhd_websocket.c b/src/microhttpd_ws/mhd_websocket.c
new file mode 100644
index 00000000..0e977973
--- /dev/null
+++ b/src/microhttpd_ws/mhd_websocket.c
@@ -0,0 +1,2072 @@
1/*
2 This file is part of libmicrohttpd
3 Copyright (C) 2021 David Gausmann
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
19*/
20
21/**
22 * @file microhttpd_ws/mhd_websocket.c
23 * @brief Support for the websocket protocol
24 * @author David Gausmann
25 */
26#include "platform.h"
27#include "microhttpd.h"
28#include "microhttpd_ws.h"
29#include "sha1.h"
30
31struct MHD_WebSocketStream
32{
33 /* The function pointer to malloc for payload (can be used to use different memory managment) */
34 MHD_WebSocketMallocCallback malloc;
35 /* The function pointer to realloc for payload (can be used to use different memory managment) */
36 MHD_WebSocketReallocCallback realloc;
37 /* The function pointer to free for payload (can be used to use different memory managment) */
38 MHD_WebSocketFreeCallback free;
39 /* The flags specified upon initialization. It may alter the behavior of decoding/encoding */
40 int flags;
41 /* The current step for the decoder. 0 means start of a frame. */
42 char decode_step;
43 /* Specifies whether the stream is valid (1) or not (0),
44 if a close frame has been received this is (-1) to indicate that no data frames are allowed anymore */
45 char validity;
46 /* The current step of the UTF-8 encoding check in the data payload */
47 char data_utf8_step;
48 /* The current step of the UTF-8 encoding check in the control payload */
49 char control_utf8_step;
50 /* if != 0 means that we expect a CONTINUATION frame */
51 char data_type;
52 /* The start of the current frame (may differ from data_payload for CONTINUATION frames) */
53 char*data_payload_start;
54 /* The buffer for the data frame */
55 char*data_payload;
56 /* The buffer for the control frame */
57 char*control_payload;
58 /* Configuration for the maximum allowed buffer size for payload data */
59 size_t max_payload_size;
60 /* The current frame header size */
61 size_t frame_header_size;
62 /* The current data payload size (can be greater than payload_size for fragmented frames) */
63 size_t data_payload_size;
64 /* The size of the payload of the current frame (control or data) */
65 size_t payload_size;
66 /* The processing offset to the start of the payload of the current frame (control or data) */
67 size_t payload_index;
68 /* The frame header of the current frame (control or data) */
69 char frame_header[32];
70 /* The mask key of the current frame (control or data); this is 0 if no masking used */
71 char mask_key[4];
72};
73
74#define MHD_WEBSOCKET_FLAG_MASK_SERVERCLIENT MHD_WEBSOCKET_FLAG_CLIENT
75#define MHD_WEBSOCKET_FLAG_MASK_FRAGMENTATION \
76 MHD_WEBSOCKET_FLAG_WANT_FRAGMENTS
77#define MHD_WEBSOCKET_FLAG_MASK_GENERATE_CLOSE_FRAMES \
78 MHD_WEBSOCKET_FLAG_GENERATE_CLOSE_FRAMES_ON_ERROR
79#define MHD_WEBSOCKET_FLAG_MASK_ALL \
80 (MHD_WEBSOCKET_FLAG_MASK_SERVERCLIENT \
81 | MHD_WEBSOCKET_FLAG_MASK_FRAGMENTATION \
82 | MHD_WEBSOCKET_FLAG_MASK_GENERATE_CLOSE_FRAMES)
83
84enum MHD_WebSocket_Opcode
85{
86 MHD_WebSocket_Opcode_Continuation = 0x0,
87 MHD_WebSocket_Opcode_Text = 0x1,
88 MHD_WebSocket_Opcode_Binary = 0x2,
89 MHD_WebSocket_Opcode_Close = 0x8,
90 MHD_WebSocket_Opcode_Ping = 0x9,
91 MHD_WebSocket_Opcode_Pong = 0xA
92};
93
94enum MHD_WebSocket_DecodeStep
95{
96 MHD_WebSocket_DecodeStep_Start = 0,
97 MHD_WebSocket_DecodeStep_Length1ofX = 1,
98 MHD_WebSocket_DecodeStep_Length1of2 = 2,
99 MHD_WebSocket_DecodeStep_Length2of2 = 3,
100 MHD_WebSocket_DecodeStep_Length1of8 = 4,
101 MHD_WebSocket_DecodeStep_Length2of8 = 5,
102 MHD_WebSocket_DecodeStep_Length3of8 = 6,
103 MHD_WebSocket_DecodeStep_Length4of8 = 7,
104 MHD_WebSocket_DecodeStep_Length5of8 = 8,
105 MHD_WebSocket_DecodeStep_Length6of8 = 9,
106 MHD_WebSocket_DecodeStep_Length7of8 = 10,
107 MHD_WebSocket_DecodeStep_Length8of8 = 11,
108 MHD_WebSocket_DecodeStep_Mask1Of4 = 12,
109 MHD_WebSocket_DecodeStep_Mask2Of4 = 13,
110 MHD_WebSocket_DecodeStep_Mask3Of4 = 14,
111 MHD_WebSocket_DecodeStep_Mask4Of4 = 15,
112 MHD_WebSocket_DecodeStep_HeaderCompleted = 16,
113 MHD_WebSocket_DecodeStep_PayloadOfDataFrame = 17,
114 MHD_WebSocket_DecodeStep_PayloadOfControlFrame = 18,
115 MHD_WebSocket_DecodeStep_BrokenStream = 99
116};
117
118enum MHD_WebSocket_UTF8Result
119{
120 MHD_WebSocket_UTF8Result_Invalid = 0,
121 MHD_WebSocket_UTF8Result_Valid = 1,
122 MHD_WebSocket_UTF8Result_Incomplete = 2
123};
124
125#define htonll(x) \
126 ((1 == htonl (1)) ? (x) : ((uint64_t) htonl ((x) & 0xFFFFFFFF) << 32) \
127 | htonl ((x) >> 32))
128#define ntohll(x) \
129 ((1 == ntohl (1)) ? (x) : ((uint64_t) ntohl ((x) & 0xFFFFFFFF) << 32) \
130 | ntohl ((x) >> 32))
131
132static void
133MHD_websocket_copy_payload (char*dst,
134 const char*src,
135 size_t len,
136 unsigned long mask,
137 unsigned long mask_offset);
138
139static int
140MHD_websocket_check_utf8 (const char*buf,
141 size_t buf_len,
142 int*utf8_step,
143 size_t*buf_offset);
144
145static int
146MHD_websocket_decode_header_complete (struct MHD_WebSocketStream*ws,
147 char**payload,
148 size_t*payload_len);
149
150static int
151MHD_websocket_decode_payload_complete (struct MHD_WebSocketStream*ws,
152 char**payload,
153 size_t*payload_len);
154
155static char
156MHD_websocket_encode_is_masked (struct MHD_WebSocketStream *ws);
157static char
158MHD_websocket_encode_overhead_size (struct MHD_WebSocketStream *ws,
159 size_t payload_len);
160
161static int
162MHD_websocket_encode_data (struct MHD_WebSocketStream*ws,
163 const char*payload,
164 size_t payload_len,
165 int fragmentation,
166 char**frame,
167 size_t*frame_len,
168 char opcode);
169
170static int
171MHD_websocket_encode_ping_pong (struct MHD_WebSocketStream*ws,
172 const char*payload,
173 size_t payload_len,
174 char**frame,
175 size_t*frame_len,
176 char opcode);
177
178static unsigned long
179MHD_websocket_generate_mask ();
180
181/**
182 * Creates the response for the Sec-WebSocket-Accept header
183 */
184_MHD_EXTERN int
185MHD_websocket_create_accept (const char*sec_websocket_key,
186 char*sec_websocket_accept)
187{
188 /* initialize output variables for errors cases */
189 if (NULL != sec_websocket_accept)
190 *sec_websocket_accept = 0;
191
192 /* validate parameters */
193 if ((NULL == sec_websocket_key) ||
194 (NULL == sec_websocket_accept) )
195 {
196 return MHD_WEBSOCKET_STATUS_PARAMETER_ERROR;
197 }
198
199 /* build SHA1 hash of the given key and the UUID appended */
200 char sha1[20];
201 const char*suffix = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
202 int length = (int) strlen (sec_websocket_key);
203 struct sha1_ctx ctx;
204 sha1_init_ctx (&ctx);
205 sha1_process_bytes (sec_websocket_key, length, &ctx);
206 sha1_process_bytes (suffix, 36, &ctx);
207 sha1_finish_ctx (&ctx, sha1);
208
209 /* base64 encode that SHA1 hash */
210 /* (simple algorithm here; SHA1 has always 20 bytes, */
211 /* which will always result in a 28 bytes base64 hash) */
212 const char*base64_encoding_table =
213 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
214 for (int i = 0, j = 0; i < 20;)
215 {
216 uint32_t octet_a = i < 20 ? (unsigned char) sha1[i++] : 0;
217 uint32_t octet_b = i < 20 ? (unsigned char) sha1[i++] : 0;
218 uint32_t octet_c = i < 20 ? (unsigned char) sha1[i++] : 0;
219 uint32_t triple = (octet_a << 0x10) + (octet_b << 0x08) + octet_c;
220
221 sec_websocket_accept[j++] = base64_encoding_table[(triple >> 3 * 6) & 0x3F];
222 sec_websocket_accept[j++] = base64_encoding_table[(triple >> 2 * 6) & 0x3F];
223 sec_websocket_accept[j++] = base64_encoding_table[(triple >> 1 * 6) & 0x3F];
224 sec_websocket_accept[j++] = base64_encoding_table[(triple >> 0 * 6) & 0x3F];
225
226 }
227 sec_websocket_accept[27] = '=';
228 sec_websocket_accept[28] = 0;
229
230 return MHD_WEBSOCKET_STATUS_OK;
231}
232
233
234/**
235 * Initializes a new websocket stream
236 */
237_MHD_EXTERN int
238MHD_websocket_stream_init (struct MHD_WebSocketStream**ws,
239 int flags,
240 size_t max_payload_size)
241{
242 return MHD_websocket_stream_init2 (ws,
243 flags,
244 max_payload_size,
245 malloc,
246 realloc,
247 free);
248}
249
250
251/**
252 * Initializes a new websocket stream with
253 * additional parameters for allocation functions
254 */
255_MHD_EXTERN int
256MHD_websocket_stream_init2 (struct MHD_WebSocketStream**ws,
257 int flags,
258 size_t max_payload_size,
259 MHD_WebSocketMallocCallback callback_malloc,
260 MHD_WebSocketReallocCallback callback_realloc,
261 MHD_WebSocketFreeCallback callback_free)
262{
263 /* initialize output variables for errors cases */
264 if (NULL != ws)
265 *ws = NULL;
266
267 /* validate parameters */
268 if ((NULL == ws) ||
269 (0 != (flags & ~MHD_WEBSOCKET_FLAG_MASK_ALL)) ||
270 ((uint64_t) 0x7FFFFFFFFFFFFFFF < max_payload_size) ||
271 (NULL == callback_malloc) ||
272 (NULL == callback_realloc) ||
273 (NULL == callback_free) )
274 {
275 return MHD_WEBSOCKET_STATUS_PARAMETER_ERROR;
276 }
277
278 /* allocate stream */
279 struct MHD_WebSocketStream*ws_ = (struct MHD_WebSocketStream*) malloc (
280 sizeof (struct MHD_WebSocketStream));
281 if (NULL == ws_)
282 return MHD_WEBSOCKET_STATUS_MEMORY_ERROR;
283
284 /* initialize stream */
285 memset (ws_, 0, sizeof (struct MHD_WebSocketStream));
286 ws_->flags = flags;
287 ws_->max_payload_size = max_payload_size;
288 ws_->malloc = callback_malloc;
289 ws_->realloc = callback_realloc;
290 ws_->free = callback_free;
291 ws_->validity = MHD_WEBSOCKET_VALIDITY_VALID;
292
293 /* return stream */
294 *ws = ws_;
295
296 return MHD_WEBSOCKET_STATUS_OK;
297}
298
299
300/**
301 * Frees a previously allocated websocket stream
302 */
303_MHD_EXTERN int
304MHD_websocket_stream_free (struct MHD_WebSocketStream*ws)
305{
306 /* validate parameters */
307 if (NULL == ws)
308 return MHD_WEBSOCKET_STATUS_PARAMETER_ERROR;
309
310 /* free allocated payload data */
311 if (ws->data_payload)
312 ws->free (ws->data_payload);
313 if (ws->control_payload)
314 ws->free (ws->control_payload);
315
316 /* free the stream */
317 free (ws);
318
319 return MHD_WEBSOCKET_STATUS_OK;
320}
321
322
323/**
324 * Invalidates a websocket stream (no more decoding possible)
325 */
326_MHD_EXTERN int
327MHD_websocket_stream_invalidate (struct MHD_WebSocketStream*ws)
328{
329 /* validate parameters */
330 if (NULL == ws)
331 return MHD_WEBSOCKET_STATUS_PARAMETER_ERROR;
332
333 /* invalidate stream */
334 ws->validity = MHD_WEBSOCKET_VALIDITY_INVALID;
335
336 return MHD_WEBSOCKET_STATUS_OK;
337}
338
339
340/**
341 * Returns whether a websocket stream is valid
342 */
343_MHD_EXTERN int
344MHD_websocket_stream_is_valid (struct MHD_WebSocketStream*ws)
345{
346 /* validate parameters */
347 if (NULL == ws)
348 return MHD_WEBSOCKET_VALIDITY_INVALID;
349
350 return ws->validity;
351}
352
353
354/**
355 * Decodes incoming data to a websocket frame
356 */
357_MHD_EXTERN int
358MHD_websocket_decode (struct MHD_WebSocketStream*ws,
359 const char*streambuf,
360 size_t streambuf_len,
361 size_t*streambuf_read_len,
362 char**payload,
363 size_t*payload_len)
364{
365 /* initialize output variables for errors cases */
366 if (NULL != streambuf_read_len)
367 *streambuf_read_len = 0;
368 if (NULL != payload)
369 *payload = NULL;
370 if (NULL != payload_len)
371 *payload_len = 0;
372
373 /* validate parameters */
374 if ((NULL == ws) ||
375 (NULL == streambuf) && (0 != streambuf_len) ||
376 (NULL == streambuf_read_len) ||
377 (NULL == payload) ||
378 (NULL == payload_len) )
379 {
380 return MHD_WEBSOCKET_STATUS_PARAMETER_ERROR;
381 }
382
383 /* validate stream validity */
384 if (MHD_WEBSOCKET_VALIDITY_INVALID == ws->validity)
385 return MHD_WEBSOCKET_STATUS_STREAM_BROKEN;
386
387 /* decode loop */
388 size_t current = 0;
389 while (current < streambuf_len)
390 {
391 switch (ws->decode_step)
392 {
393 /* start of frame */
394 case MHD_WebSocket_DecodeStep_Start:
395 {
396 /* The first byte contains the opcode, the fin flag and three reserved bits */
397 if (MHD_WEBSOCKET_VALIDITY_INVALID != ws->validity)
398 {
399 char opcode = streambuf [current];
400 if (0 != (opcode & 0x70))
401 {
402 /* RFC 6455 5.2 RSV1-3: If a reserved flag is set */
403 /* (while it isn't specified by an extension) the communcation must fail. */
404 ws->validity = MHD_WEBSOCKET_VALIDITY_INVALID;
405 if (0 != (ws->flags
406 & MHD_WEBSOCKET_FLAG_GENERATE_CLOSE_FRAMES_ON_ERROR))
407 {
408 MHD_websocket_encode_close (ws,
409 MHD_WEBSOCKET_CLOSEREASON_PROTOCOL_ERROR,
410 0,
411 0,
412 payload,
413 payload_len);
414 }
415 *streambuf_read_len = current;
416 return MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR;
417 }
418 switch (opcode & 0x0F)
419 {
420 case MHD_WebSocket_Opcode_Continuation:
421 if (0 == ws->data_type)
422 {
423 /* RFC 6455 5.4: Continuation frame without previous data frame */
424 ws->validity = MHD_WEBSOCKET_VALIDITY_INVALID;
425 if (0 != (ws->flags
426 & MHD_WEBSOCKET_FLAG_GENERATE_CLOSE_FRAMES_ON_ERROR))
427 {
428 MHD_websocket_encode_close (ws,
429 MHD_WEBSOCKET_CLOSEREASON_PROTOCOL_ERROR,
430 0,
431 0,
432 payload,
433 payload_len);
434 }
435 *streambuf_read_len = current;
436 return MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR;
437 }
438 if (MHD_WEBSOCKET_VALIDITY_ONLY_VALID_FOR_CONTROL_FRAMES ==
439 ws->validity)
440 {
441 /* RFC 6455 5.5.1: After a close frame has been sent, */
442 /* no data frames may be sent (so we don't accept data frames */
443 /* for decoding anymore) */
444 ws->validity = MHD_WEBSOCKET_VALIDITY_INVALID;
445 if (0 != (ws->flags
446 & MHD_WEBSOCKET_FLAG_GENERATE_CLOSE_FRAMES_ON_ERROR))
447 {
448 MHD_websocket_encode_close (ws,
449 MHD_WEBSOCKET_CLOSEREASON_PROTOCOL_ERROR,
450 0,
451 0,
452 payload,
453 payload_len);
454 }
455 *streambuf_read_len = current;
456 return MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR;
457 }
458 break;
459
460 case MHD_WebSocket_Opcode_Text:
461 case MHD_WebSocket_Opcode_Binary:
462 if (0 != ws->data_type)
463 {
464 /* RFC 6455 5.4: Continuation expected, but new data frame */
465 ws->validity = MHD_WEBSOCKET_VALIDITY_INVALID;
466 if (0 != (ws->flags
467 & MHD_WEBSOCKET_FLAG_GENERATE_CLOSE_FRAMES_ON_ERROR))
468 {
469 MHD_websocket_encode_close (ws,
470 MHD_WEBSOCKET_CLOSEREASON_PROTOCOL_ERROR,
471 0,
472 0,
473 payload,
474 payload_len);
475 }
476 *streambuf_read_len = current;
477 return MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR;
478 }
479 if (MHD_WEBSOCKET_VALIDITY_ONLY_VALID_FOR_CONTROL_FRAMES ==
480 ws->validity)
481 {
482 /* RFC 6455 5.5.1: After a close frame has been sent, */
483 /* no data frames may be sent (so we don't accept data frames */
484 /* for decoding anymore) */
485 ws->validity = MHD_WEBSOCKET_VALIDITY_INVALID;
486 if (0 != (ws->flags
487 & MHD_WEBSOCKET_FLAG_GENERATE_CLOSE_FRAMES_ON_ERROR))
488 {
489 MHD_websocket_encode_close (ws,
490 MHD_WEBSOCKET_CLOSEREASON_PROTOCOL_ERROR,
491 0,
492 0,
493 payload,
494 payload_len);
495 }
496 *streambuf_read_len = current;
497 return MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR;
498 }
499 break;
500
501 case MHD_WebSocket_Opcode_Close:
502 case MHD_WebSocket_Opcode_Ping:
503 case MHD_WebSocket_Opcode_Pong:
504 if ((opcode & 0x80) == 0)
505 {
506 /* RFC 6455 5.4: Control frames may not be fragmented */
507 ws->validity = MHD_WEBSOCKET_VALIDITY_INVALID;
508 if (0 != (ws->flags
509 & MHD_WEBSOCKET_FLAG_GENERATE_CLOSE_FRAMES_ON_ERROR))
510 {
511 MHD_websocket_encode_close (ws,
512 MHD_WEBSOCKET_CLOSEREASON_PROTOCOL_ERROR,
513 0,
514 0,
515 payload,
516 payload_len);
517 }
518 *streambuf_read_len = current;
519 return MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR;
520 }
521 if (MHD_WebSocket_Opcode_Close == (opcode & 0x0F))
522 {
523 /* RFC 6455 5.5.1: After a close frame has been sent, */
524 /* no data frames may be sent (so we don't accept data frames */
525 /* for decoding anymore) */
526 ws->validity =
527 MHD_WEBSOCKET_VALIDITY_ONLY_VALID_FOR_CONTROL_FRAMES;
528 }
529 break;
530
531 default:
532 /* RFC 6455 5.2 OPCODE: Only six opcodes are specified. */
533 /* All other are invalid in version 13 of the protocol. */
534 ws->validity = MHD_WEBSOCKET_VALIDITY_INVALID;
535 if (0 != (ws->flags
536 & MHD_WEBSOCKET_FLAG_GENERATE_CLOSE_FRAMES_ON_ERROR))
537 {
538 MHD_websocket_encode_close (ws,
539 MHD_WEBSOCKET_CLOSEREASON_PROTOCOL_ERROR,
540 0,
541 0,
542 payload,
543 payload_len);
544 }
545 *streambuf_read_len = current;
546 return MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR;
547 }
548 }
549 ws->frame_header [ws->frame_header_size++] = streambuf [current++];
550 ws->decode_step = MHD_WebSocket_DecodeStep_Length1ofX;
551 }
552 break;
553
554 case MHD_WebSocket_DecodeStep_Length1ofX:
555 {
556 /* The second byte specifies whether the data is masked and the size */
557 /* (the client MUST mask the payload, the server MUST NOT mask the payload) */
558 char frame_len = streambuf [current];
559 char is_masked = (frame_len & 0x80);
560 frame_len &= 0x7f;
561 if (MHD_WEBSOCKET_VALIDITY_INVALID != ws->validity)
562 {
563 if (0 != is_masked)
564 {
565 if (MHD_WEBSOCKET_FLAG_CLIENT == (ws->flags
566 & MHD_WEBSOCKET_FLAG_CLIENT))
567 {
568 /* RFC 6455 5.1: All frames from the server must be unmasked */
569 ws->validity = MHD_WEBSOCKET_VALIDITY_INVALID;
570 if (0 != (ws->flags
571 & MHD_WEBSOCKET_FLAG_GENERATE_CLOSE_FRAMES_ON_ERROR))
572 {
573 MHD_websocket_encode_close (ws,
574 MHD_WEBSOCKET_CLOSEREASON_PROTOCOL_ERROR,
575 0,
576 0,
577 payload,
578 payload_len);
579 }
580 *streambuf_read_len = current;
581 return MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR;
582 }
583 }
584 else
585 {
586 if (MHD_WEBSOCKET_FLAG_SERVER == (ws->flags
587 & MHD_WEBSOCKET_FLAG_CLIENT))
588 {
589 /* RFC 6455 5.1: All frames from the client must be masked */
590 ws->validity = MHD_WEBSOCKET_VALIDITY_INVALID;
591 if (0 != (ws->flags
592 & MHD_WEBSOCKET_FLAG_GENERATE_CLOSE_FRAMES_ON_ERROR))
593 {
594 MHD_websocket_encode_close (ws,
595 MHD_WEBSOCKET_CLOSEREASON_PROTOCOL_ERROR,
596 0,
597 0,
598 payload,
599 payload_len);
600 }
601 *streambuf_read_len = current;
602 return MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR;
603 }
604 }
605 if (126 <= frame_len)
606 {
607 if (0 != (ws->frame_header [0] & 0x08))
608 {
609 /* RFC 6455 5.5: Control frames may not have more payload than 125 bytes */
610 ws->validity = MHD_WEBSOCKET_VALIDITY_INVALID;
611 if (0 != (ws->flags
612 & MHD_WEBSOCKET_FLAG_GENERATE_CLOSE_FRAMES_ON_ERROR))
613 {
614 MHD_websocket_encode_close (ws,
615 MHD_WEBSOCKET_CLOSEREASON_PROTOCOL_ERROR,
616 0,
617 0,
618 payload,
619 payload_len);
620 }
621 *streambuf_read_len = current;
622 return MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR;
623 }
624 }
625 if (1 == frame_len)
626 {
627 if (MHD_WebSocket_Opcode_Close == (ws->frame_header [0] & 0x0F))
628 {
629 /* RFC 6455 5.5.1: The close frame must have at least */
630 /* two bytes of payload if payload is used */
631 ws->validity = MHD_WEBSOCKET_VALIDITY_INVALID;
632 if (0 != (ws->flags
633 & MHD_WEBSOCKET_FLAG_GENERATE_CLOSE_FRAMES_ON_ERROR))
634 {
635 MHD_websocket_encode_close (ws,
636 MHD_WEBSOCKET_CLOSEREASON_PROTOCOL_ERROR,
637 0,
638 0,
639 payload,
640 payload_len);
641 }
642 *streambuf_read_len = current;
643 return MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR;
644 }
645 }
646 }
647 ws->frame_header [ws->frame_header_size++] = streambuf [current++];
648
649 if (126 == frame_len)
650 {
651 ws->decode_step = MHD_WebSocket_DecodeStep_Length1of2;
652 }
653 else if (127 == frame_len)
654 {
655 ws->decode_step = MHD_WebSocket_DecodeStep_Length1of8;
656 }
657 else
658 {
659 size_t size = (size_t) frame_len;
660 if ((SIZE_MAX < size) || ws->max_payload_size &&
661 (ws->max_payload_size < size) )
662 {
663 /* RFC 6455 7.4.1 1009: If the message is too big to process, we may close the connection */
664 ws->validity = MHD_WEBSOCKET_VALIDITY_INVALID;
665 if (0 != (ws->flags
666 & MHD_WEBSOCKET_FLAG_GENERATE_CLOSE_FRAMES_ON_ERROR))
667 {
668 MHD_websocket_encode_close (ws,
669 MHD_WEBSOCKET_CLOSEREASON_MAXIMUM_ALLOWED_PAYLOAD_SIZE_EXCEEDED,
670 0,
671 0,
672 payload,
673 payload_len);
674 }
675 *streambuf_read_len = current;
676 return MHD_WEBSOCKET_STATUS_MAXIMUM_SIZE_EXCEEDED;
677 }
678 ws->payload_size = size;
679 if (0 != is_masked)
680 {
681 /* with mask */
682 ws->decode_step = MHD_WebSocket_DecodeStep_Mask1Of4;
683 }
684 else
685 {
686 /* without mask */
687 *((unsigned long *) ws->mask_key) = 0;
688 ws->decode_step = MHD_WebSocket_DecodeStep_HeaderCompleted;
689 }
690 }
691 }
692 break;
693
694 /* Payload size first byte of 2 bytes */
695 case MHD_WebSocket_DecodeStep_Length1of2:
696 /* Payload size first 7 bytes of 8 bytes */
697 case MHD_WebSocket_DecodeStep_Length1of8:
698 case MHD_WebSocket_DecodeStep_Length2of8:
699 case MHD_WebSocket_DecodeStep_Length3of8:
700 case MHD_WebSocket_DecodeStep_Length4of8:
701 case MHD_WebSocket_DecodeStep_Length5of8:
702 case MHD_WebSocket_DecodeStep_Length6of8:
703 case MHD_WebSocket_DecodeStep_Length7of8:
704 /* Mask first 3 bytes of 4 bytes */
705 case MHD_WebSocket_DecodeStep_Mask1Of4:
706 case MHD_WebSocket_DecodeStep_Mask2Of4:
707 case MHD_WebSocket_DecodeStep_Mask3Of4:
708 ws->frame_header [ws->frame_header_size++] = streambuf [current++];
709 ++ws->decode_step;
710 break;
711
712 /* 2 byte length finished */
713 case MHD_WebSocket_DecodeStep_Length2of2:
714 {
715 ws->frame_header [ws->frame_header_size++] = streambuf [current++];
716 size_t size = (size_t) htons (*((unsigned
717 short*) &ws->frame_header [2]));
718 if (125 >= size)
719 {
720 /* RFC 6455 5.2 Payload length: The minimal number of bytes */
721 /* must be used for the length */
722 ws->validity = MHD_WEBSOCKET_VALIDITY_INVALID;
723 if (0 != (ws->flags
724 & MHD_WEBSOCKET_FLAG_GENERATE_CLOSE_FRAMES_ON_ERROR))
725 {
726 MHD_websocket_encode_close (ws,
727 MHD_WEBSOCKET_CLOSEREASON_PROTOCOL_ERROR,
728 0,
729 0,
730 payload,
731 payload_len);
732 }
733 *streambuf_read_len = current;
734 return MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR;
735 }
736 if ((SIZE_MAX < size) || ws->max_payload_size && (ws->max_payload_size <
737 size) )
738 {
739 /* RFC 6455 7.4.1 1009: If the message is too big to process, */
740 /* we may close the connection */
741 ws->validity = MHD_WEBSOCKET_VALIDITY_INVALID;
742 if (0 != (ws->flags
743 & MHD_WEBSOCKET_FLAG_GENERATE_CLOSE_FRAMES_ON_ERROR))
744 {
745 MHD_websocket_encode_close (ws,
746 MHD_WEBSOCKET_CLOSEREASON_MAXIMUM_ALLOWED_PAYLOAD_SIZE_EXCEEDED,
747 0,
748 0,
749 payload,
750 payload_len);
751 }
752 *streambuf_read_len = current;
753 return MHD_WEBSOCKET_STATUS_MAXIMUM_SIZE_EXCEEDED;
754 }
755 ws->payload_size = size;
756 if (0 != (ws->frame_header [1] & 0x80))
757 {
758 /* with mask */
759 ws->decode_step = MHD_WebSocket_DecodeStep_Mask1Of4;
760 }
761 else
762 {
763 /* without mask */
764 *((unsigned long *) ws->mask_key) = 0;
765 ws->decode_step = MHD_WebSocket_DecodeStep_HeaderCompleted;
766 }
767 }
768 break;
769
770 /* 8 byte length finished */
771 case MHD_WebSocket_DecodeStep_Length8of8:
772 {
773 ws->frame_header [ws->frame_header_size++] = streambuf [current++];
774 uint64_t size = htonll (*((uint64_t*) &ws->frame_header [2]));
775 if (0x7fffffffffffffff < size)
776 {
777 /* RFC 6455 5.2 frame-payload-length-63: The length may */
778 /* not exceed 0x7fffffffffffffff */
779 ws->decode_step = MHD_WebSocket_DecodeStep_BrokenStream;
780 ws->validity = MHD_WEBSOCKET_VALIDITY_INVALID;
781 if (0 != (ws->flags
782 & MHD_WEBSOCKET_FLAG_GENERATE_CLOSE_FRAMES_ON_ERROR))
783 {
784 MHD_websocket_encode_close (ws,
785 MHD_WEBSOCKET_CLOSEREASON_PROTOCOL_ERROR,
786 0,
787 0,
788 payload,
789 payload_len);
790 }
791 *streambuf_read_len = current;
792 return MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR;
793 }
794 if (65535 >= size)
795 {
796 /* RFC 6455 5.2 Payload length: The minimal number of bytes */
797 /* must be used for the length */
798 ws->validity = MHD_WEBSOCKET_VALIDITY_INVALID;
799 if (0 != (ws->flags
800 & MHD_WEBSOCKET_FLAG_GENERATE_CLOSE_FRAMES_ON_ERROR))
801 {
802 MHD_websocket_encode_close (ws,
803 MHD_WEBSOCKET_CLOSEREASON_PROTOCOL_ERROR,
804 0,
805 0,
806 payload,
807 payload_len);
808 }
809 *streambuf_read_len = current;
810 return MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR;
811 }
812 if ((SIZE_MAX < size) || ws->max_payload_size && (ws->max_payload_size <
813 size) )
814 {
815 /* RFC 6455 7.4.1 1009: If the message is too big to process, */
816 /* we may close the connection */
817 ws->validity = MHD_WEBSOCKET_VALIDITY_INVALID;
818 if (0 != (ws->flags
819 & MHD_WEBSOCKET_FLAG_GENERATE_CLOSE_FRAMES_ON_ERROR))
820 {
821 MHD_websocket_encode_close (ws,
822 MHD_WEBSOCKET_CLOSEREASON_MAXIMUM_ALLOWED_PAYLOAD_SIZE_EXCEEDED,
823 0,
824 0,
825 payload,
826 payload_len);
827 }
828 *streambuf_read_len = current;
829 return MHD_WEBSOCKET_STATUS_MAXIMUM_SIZE_EXCEEDED;
830 }
831 ws->payload_size = (size_t) size;
832
833 if (0 != (ws->frame_header [1] & 0x80))
834 {
835 /* with mask */
836 ws->decode_step = MHD_WebSocket_DecodeStep_Mask1Of4;
837 }
838 else
839 {
840 /* without mask */
841 *((unsigned long *) ws->mask_key) = 0;
842 ws->decode_step = MHD_WebSocket_DecodeStep_HeaderCompleted;
843 }
844 }
845 break;
846
847 /* mask finished */
848 case MHD_WebSocket_DecodeStep_Mask4Of4:
849 ws->frame_header [ws->frame_header_size++] = streambuf [current++];
850 *((unsigned long *) ws->mask_key) = *((unsigned
851 long *) &ws->frame_header [ws->
852 frame_header_size
853 - 4]);
854 ws->decode_step = MHD_WebSocket_DecodeStep_HeaderCompleted;
855 break;
856
857 /* header finished */
858 case MHD_WebSocket_DecodeStep_HeaderCompleted:
859 /* return or assign either to data or control */
860 {
861 int ret = MHD_websocket_decode_header_complete (ws,
862 payload,
863 payload_len);
864 if (MHD_WEBSOCKET_STATUS_OK != ret)
865 {
866 *streambuf_read_len = current;
867 return ret;
868 }
869 }
870 break;
871
872 /* payload data */
873 case MHD_WebSocket_DecodeStep_PayloadOfDataFrame:
874 case MHD_WebSocket_DecodeStep_PayloadOfControlFrame:
875 {
876 size_t bytes_needed = ws->payload_size - ws->payload_index;
877 size_t bytes_remaining = streambuf_len - current;
878 size_t bytes_to_take = bytes_needed < bytes_remaining ? bytes_needed :
879 bytes_remaining;
880 if (0 != bytes_to_take)
881 {
882 size_t utf8_start = ws->payload_index;
883 char *decode_payload = ws->decode_step ==
884 MHD_WebSocket_DecodeStep_PayloadOfDataFrame ?
885 ws->data_payload_start :
886 ws->control_payload;
887
888 /* copy the new payload data (with unmasking if necessary */
889 MHD_websocket_copy_payload (decode_payload + ws->payload_index,
890 &streambuf [current],
891 bytes_to_take,
892 *((unsigned long *) ws->mask_key),
893 (unsigned long) (ws->payload_index
894 & 0x03));
895 current += bytes_to_take;
896 ws->payload_index += bytes_to_take;
897 if ((MHD_WebSocket_DecodeStep_PayloadOfDataFrame ==
898 ws->decode_step) &&
899 (MHD_WebSocket_Opcode_Text == ws->data_type) ||
900 (MHD_WebSocket_DecodeStep_PayloadOfControlFrame ==
901 ws->decode_step) &&
902 (MHD_WebSocket_Opcode_Close == (ws->frame_header [0] & 0x0f)) &&
903 (2 < ws->payload_index) )
904 {
905 /* RFC 6455 8.1: We need to check the UTF-8 validity */
906 int utf8_step;
907 char*decode_payload_utf8;
908 size_t bytes_to_check;
909 size_t utf8_error_offset = 0;
910 if (MHD_WebSocket_DecodeStep_PayloadOfDataFrame == ws->decode_step)
911 {
912 utf8_step = ws->data_utf8_step;
913 decode_payload_utf8 = decode_payload + utf8_start;
914 bytes_to_check = bytes_to_take;
915 }
916 else
917 {
918 utf8_step = ws->control_utf8_step;
919 if ((MHD_WebSocket_Opcode_Close == (ws->frame_header [0]
920 & 0x0f)) &&
921 (2 > utf8_start) )
922 {
923 /* The first two bytes of the close frame are binary content and */
924 /* must be skipped in the UTF-8 check */
925 utf8_start = 2;
926 utf8_error_offset = 2;
927 }
928 decode_payload_utf8 = decode_payload + utf8_start;
929 bytes_to_check = bytes_to_take - utf8_start;
930 }
931 size_t utf8_check_offset = 0;
932 int utf8_result = MHD_websocket_check_utf8 (decode_payload_utf8,
933 bytes_to_check,
934 &utf8_step,
935 &utf8_check_offset);
936 if (MHD_WebSocket_UTF8Result_Invalid != utf8_result)
937 {
938 /* memorize current validity check step to continue later */
939 ws->data_utf8_step = utf8_step;
940 }
941 else
942 {
943 /* RFC 6455 8.1: We must fail on broken UTF-8 sequence */
944 ws->validity = MHD_WEBSOCKET_VALIDITY_INVALID;
945 if (0 != (ws->flags
946 & MHD_WEBSOCKET_FLAG_GENERATE_CLOSE_FRAMES_ON_ERROR))
947 {
948 MHD_websocket_encode_close (ws,
949 MHD_WEBSOCKET_CLOSEREASON_MALFORMED_UTF8,
950 0,
951 0,
952 payload,
953 payload_len);
954 }
955 *streambuf_read_len = current - bytes_to_take
956 + utf8_check_offset + utf8_error_offset;
957 return MHD_WEBSOCKET_STATUS_UTF8_ENCODING_ERROR;
958 }
959 }
960 }
961 }
962
963 if (ws->payload_size == ws->payload_index)
964 {
965 /* all payload data of the current frame has been received */
966 int ret = MHD_websocket_decode_payload_complete (ws,
967 payload,
968 payload_len);
969 if (MHD_WEBSOCKET_STATUS_OK != ret)
970 {
971 *streambuf_read_len = current;
972 return ret;
973 }
974 }
975 break;
976
977 case MHD_WebSocket_DecodeStep_BrokenStream:
978 *streambuf_read_len = current;
979 return MHD_WEBSOCKET_STATUS_STREAM_BROKEN;
980 }
981 }
982
983 /* Special treatment for zero payload length messages */
984 if (MHD_WebSocket_DecodeStep_HeaderCompleted == ws->decode_step)
985 {
986 int ret = MHD_websocket_decode_header_complete (ws,
987 payload,
988 payload_len);
989 if (MHD_WEBSOCKET_STATUS_OK != ret)
990 {
991 *streambuf_read_len = current;
992 return ret;
993 }
994 }
995 switch (ws->decode_step)
996 {
997 case MHD_WebSocket_DecodeStep_PayloadOfDataFrame:
998 case MHD_WebSocket_DecodeStep_PayloadOfControlFrame:
999 if (ws->payload_size == ws->payload_index)
1000 {
1001 /* all payload data of the current frame has been received */
1002 int ret = MHD_websocket_decode_payload_complete (ws,
1003 payload,
1004 payload_len);
1005 if (MHD_WEBSOCKET_STATUS_OK != ret)
1006 {
1007 *streambuf_read_len = current;
1008 return ret;
1009 }
1010 }
1011 break;
1012 }
1013 *streambuf_read_len = current;
1014
1015 /* more data needed */
1016 return MHD_WEBSOCKET_STATUS_OK;
1017}
1018
1019
1020static int
1021MHD_websocket_decode_header_complete (struct MHD_WebSocketStream*ws,
1022 char**payload,
1023 size_t*payload_len)
1024{
1025 /* assign either to data or control */
1026 char opcode = ws->frame_header [0] & 0x0f;
1027 switch (opcode)
1028 {
1029 case MHD_WebSocket_Opcode_Continuation:
1030 {
1031 /* validate payload size */
1032 size_t new_size_total = ws->payload_size + ws->data_payload_size;
1033 if ((0 != ws->max_payload_size) && (ws->max_payload_size <
1034 new_size_total) )
1035 {
1036 /* RFC 6455 7.4.1 1009: If the message is too big to process, */
1037 /* we may close the connection */
1038 ws->decode_step = MHD_WebSocket_DecodeStep_BrokenStream;
1039 ws->validity = MHD_WEBSOCKET_VALIDITY_INVALID;
1040 if (0 != (ws->flags
1041 & MHD_WEBSOCKET_FLAG_GENERATE_CLOSE_FRAMES_ON_ERROR))
1042 {
1043 MHD_websocket_encode_close (ws,
1044 MHD_WEBSOCKET_CLOSEREASON_MAXIMUM_ALLOWED_PAYLOAD_SIZE_EXCEEDED,
1045 0,
1046 0,
1047 payload,
1048 payload_len);
1049 }
1050 return MHD_WEBSOCKET_STATUS_MAXIMUM_SIZE_EXCEEDED;
1051 }
1052 /* allocate buffer for continued data frame */
1053 char*new_buf = NULL;
1054 if (0 != new_size_total)
1055 {
1056 new_buf = ws->realloc (ws->data_payload, new_size_total + 1);
1057 if (NULL == new_buf)
1058 {
1059 return MHD_WEBSOCKET_STATUS_MEMORY_ERROR;
1060 }
1061 new_buf [new_size_total] = 0;
1062 ws->data_payload_start = &new_buf[ws->data_payload_size];
1063 }
1064 else
1065 {
1066 ws->data_payload_start = new_buf;
1067 }
1068 ws->data_payload = new_buf;
1069 ws->data_payload_size = new_size_total;
1070 }
1071 ws->decode_step = MHD_WebSocket_DecodeStep_PayloadOfDataFrame;
1072 break;
1073
1074 case MHD_WebSocket_Opcode_Text:
1075 case MHD_WebSocket_Opcode_Binary:
1076 /* allocate buffer for data frame */
1077 {
1078 size_t new_size_total = ws->payload_size;
1079 char*new_buf = NULL;
1080 if (0 != new_size_total)
1081 {
1082 new_buf = ws->malloc (new_size_total + 1);
1083 if (NULL == new_buf)
1084 {
1085 return MHD_WEBSOCKET_STATUS_MEMORY_ERROR;
1086 }
1087 new_buf [new_size_total] = 0;
1088 }
1089 ws->data_payload = new_buf;
1090 ws->data_payload_start = new_buf;
1091 ws->data_payload_size = new_size_total;
1092 ws->data_type = opcode;
1093 }
1094 ws->decode_step = MHD_WebSocket_DecodeStep_PayloadOfDataFrame;
1095 break;
1096
1097 case MHD_WebSocket_Opcode_Close:
1098 case MHD_WebSocket_Opcode_Ping:
1099 case MHD_WebSocket_Opcode_Pong:
1100 /* allocate buffer for control frame */
1101 {
1102 size_t new_size_total = ws->payload_size;
1103 char*new_buf = NULL;
1104 if (0 != new_size_total)
1105 {
1106 new_buf = ws->malloc (new_size_total + 1);
1107 if (NULL == new_buf)
1108 {
1109 return MHD_WEBSOCKET_STATUS_MEMORY_ERROR;
1110 }
1111 new_buf[new_size_total] = 0;
1112 }
1113 ws->control_payload = new_buf;
1114 }
1115 ws->decode_step = MHD_WebSocket_DecodeStep_PayloadOfControlFrame;
1116 break;
1117 }
1118
1119 return MHD_WEBSOCKET_STATUS_OK;
1120}
1121
1122
1123static int
1124MHD_websocket_decode_payload_complete (struct MHD_WebSocketStream*ws,
1125 char**payload,
1126 size_t*payload_len)
1127{
1128 /* all payload data of the current frame has been received */
1129 char is_fin = ws->frame_header [0] & 0x80;
1130 if (0 != is_fin)
1131 {
1132 /* the frame is complete */
1133 if (MHD_WebSocket_DecodeStep_PayloadOfDataFrame == ws->decode_step)
1134 {
1135 /* data frame */
1136 char data_type = ws->data_type;
1137 if ((0 != (ws->flags & MHD_WEBSOCKET_FLAG_WANT_FRAGMENTS)) &&
1138 (MHD_WebSocket_Opcode_Continuation == (ws->frame_header [0] & 0x0F)))
1139 {
1140 data_type |= 0x20; /* mark as last fragment */
1141 }
1142 *payload = ws->data_payload;
1143 *payload_len = ws->data_payload_size;
1144 ws->data_payload = 0;
1145 ws->data_payload_start = 0;
1146 ws->data_payload_size = 0;
1147 ws->decode_step = MHD_WebSocket_DecodeStep_Start;
1148 ws->payload_index = 0;
1149 ws->data_type = 0;
1150 ws->frame_header_size = 0;
1151 return data_type;
1152 }
1153 else
1154 {
1155 /* control frame */
1156 *payload = ws->control_payload;
1157 *payload_len = ws->payload_size;
1158 ws->control_payload = 0;
1159 ws->decode_step = MHD_WebSocket_DecodeStep_Start;
1160 ws->payload_index = 0;
1161 ws->frame_header_size = 0;
1162 return (ws->frame_header [0] & 0x0f);
1163 }
1164 }
1165 else if (0 != (ws->flags & MHD_WEBSOCKET_FLAG_WANT_FRAGMENTS))
1166 {
1167 /* RFC 6455 5.4: To allow streaming, the user can choose */
1168 /* to return fragments */
1169 if ((MHD_WebSocket_Opcode_Text == ws->data_type) &&
1170 (MHD_WEBSOCKET_UTF8STEP_NORMAL != ws->data_utf8_step) )
1171 {
1172 /* the last UTF-8 sequence is incomplete, so we keep the start of
1173 that and only return the part before */
1174 size_t given_utf8;
1175 switch (ws->data_utf8_step)
1176 {
1177 /* one byte given */
1178 case MHD_WEBSOCKET_UTF8STEP_UTF2TAIL_1OF1:
1179 case MHD_WEBSOCKET_UTF8STEP_UTF3TAIL1_1OF2:
1180 case MHD_WEBSOCKET_UTF8STEP_UTF3TAIL2_1OF2:
1181 case MHD_WEBSOCKET_UTF8STEP_UTF3TAIL_1OF2:
1182 case MHD_WEBSOCKET_UTF8STEP_UTF4TAIL1_1OF3:
1183 case MHD_WEBSOCKET_UTF8STEP_UTF4TAIL2_1OF3:
1184 case MHD_WEBSOCKET_UTF8STEP_UTF4TAIL_1OF3:
1185 given_utf8 = 1;
1186 break;
1187 /* two bytes given */
1188 case MHD_WEBSOCKET_UTF8STEP_UTF3TAIL_2OF2:
1189 case MHD_WEBSOCKET_UTF8STEP_UTF4TAIL_2OF3:
1190 given_utf8 = 2;
1191 break;
1192 /* three bytes given */
1193 case MHD_WEBSOCKET_UTF8STEP_UTF4TAIL_3OF3:
1194 given_utf8 = 3;
1195 break;
1196 }
1197 size_t new_len = ws->data_payload_size - given_utf8;
1198 if (0 != new_len)
1199 {
1200 char *next_payload = ws->malloc (given_utf8 + 1);
1201 if (NULL == next_payload)
1202 {
1203 return MHD_WEBSOCKET_STATUS_MEMORY_ERROR;
1204 }
1205 memcpy (next_payload,
1206 ws->data_payload_start + ws->payload_index - given_utf8,
1207 given_utf8);
1208 next_payload[given_utf8] = 0;
1209
1210 ws->data_payload[new_len] = 0;
1211 *payload = ws->data_payload;
1212 *payload_len = new_len;
1213 ws->data_payload = next_payload;
1214 ws->data_payload_size = given_utf8;
1215 }
1216 else
1217 {
1218 *payload = NULL;
1219 *payload_len = 0;
1220 }
1221 ws->decode_step = MHD_WebSocket_DecodeStep_Start;
1222 ws->payload_index = 0;
1223 ws->frame_header_size = 0;
1224 return ws->data_type | 0x10; /* mark as fragment */
1225 }
1226 else
1227 {
1228 /* we simply pass the entire data frame */
1229 *payload = ws->data_payload;
1230 *payload_len = ws->data_payload_size;
1231 ws->data_payload = 0;
1232 ws->data_payload_start = 0;
1233 ws->data_payload_size = 0;
1234 ws->decode_step = MHD_WebSocket_DecodeStep_Start;
1235 ws->payload_index = 0;
1236 ws->frame_header_size = 0;
1237 return ws->data_type | 0x10; /* mark as fragment */
1238 }
1239 }
1240 else
1241 {
1242 /* RFC 6455 5.4: We must await a continuation frame to get */
1243 /* the remainder of this data frame */
1244 ws->decode_step = MHD_WebSocket_DecodeStep_Start;
1245 ws->frame_header_size = 0;
1246 ws->payload_index = 0;
1247 return MHD_WEBSOCKET_STATUS_OK;
1248 }
1249}
1250
1251
1252/**
1253 * Splits the received close reason
1254 */
1255_MHD_EXTERN int
1256MHD_websocket_split_close_reason (const char*payload,
1257 size_t payload_len,
1258 unsigned short*reason_code,
1259 const char**reason_utf8,
1260 size_t*reason_utf8_len)
1261{
1262 /* initialize output variables for errors cases */
1263 if (NULL != reason_code)
1264 *reason_code = MHD_WEBSOCKET_CLOSEREASON_NO_REASON;
1265 if (NULL != reason_utf8)
1266 *reason_utf8 = NULL;
1267 if (NULL != reason_utf8_len)
1268 *reason_utf8_len = 0;
1269
1270 /* validate parameters */
1271 if ((NULL == payload) && (0 != payload_len))
1272 return MHD_WEBSOCKET_STATUS_PARAMETER_ERROR;
1273 if (1 == payload_len)
1274 return MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR;
1275 if (125 < payload_len)
1276 return MHD_WEBSOCKET_STATUS_MAXIMUM_SIZE_EXCEEDED;
1277
1278 /* decode reason code */
1279 if (2 > payload_len)
1280 {
1281 if (NULL != reason_code)
1282 *reason_code = MHD_WEBSOCKET_CLOSEREASON_NO_REASON;
1283 }
1284 else
1285 {
1286 if (NULL != reason_code)
1287 *reason_code = htons (*((unsigned short*) payload));
1288 }
1289
1290 /* decode reason text */
1291 if (2 >= payload_len)
1292 {
1293 if (NULL != reason_utf8)
1294 *reason_utf8 = NULL;
1295 if (NULL != reason_utf8_len)
1296 *reason_utf8_len = 0;
1297 }
1298 else
1299 {
1300 if (NULL != reason_utf8)
1301 *reason_utf8 = payload + 2;
1302 if (NULL != reason_utf8_len)
1303 *reason_utf8_len = payload_len - 2;
1304 }
1305
1306 return MHD_WEBSOCKET_STATUS_OK;
1307}
1308
1309
1310/**
1311 * Encodes a text into a websocket text frame
1312 */
1313_MHD_EXTERN int
1314MHD_websocket_encode_text (struct MHD_WebSocketStream*ws,
1315 const char*payload_utf8,
1316 size_t payload_utf8_len,
1317 int fragmentation,
1318 char**frame,
1319 size_t*frame_len,
1320 int*utf8_step)
1321{
1322 /* initialize output variables for errors cases */
1323 if (NULL != frame)
1324 *frame = NULL;
1325 if (NULL != frame_len)
1326 *frame_len = 0;
1327 if ((NULL != utf8_step) &&
1328 ((MHD_WEBSOCKET_FRAGMENTATION_FIRST == fragmentation) ||
1329 (MHD_WEBSOCKET_FRAGMENTATION_NONE == fragmentation) ))
1330 {
1331 /* the old UTF-8 step will be ignored for new fragments */
1332 *utf8_step = MHD_WEBSOCKET_UTF8STEP_NORMAL;
1333 }
1334
1335 /* validate parameters */
1336 if ((NULL == ws) ||
1337 (0 != payload_utf8_len) && (NULL == payload_utf8) ||
1338 (NULL == frame) ||
1339 (NULL == frame_len) ||
1340 (MHD_WEBSOCKET_FRAGMENTATION_NONE > fragmentation) ||
1341 (MHD_WEBSOCKET_FRAGMENTATION_LAST < fragmentation) ||
1342 (MHD_WEBSOCKET_FRAGMENTATION_NONE != fragmentation) && (NULL ==
1343 utf8_step) )
1344 {
1345 return MHD_WEBSOCKET_STATUS_PARAMETER_ERROR;
1346 }
1347
1348 /* check max length */
1349 if ((uint64_t) 0x7FFFFFFFFFFFFFFF < (uint64_t) payload_utf8_len)
1350 {
1351 return MHD_WEBSOCKET_STATUS_MAXIMUM_SIZE_EXCEEDED;
1352 }
1353
1354 /* check UTF-8 */
1355 int utf8_result = MHD_websocket_check_utf8 (payload_utf8,
1356 payload_utf8_len,
1357 utf8_step,
1358 NULL);
1359 if ((MHD_WebSocket_UTF8Result_Invalid == utf8_result) ||
1360 (MHD_WebSocket_UTF8Result_Incomplete == utf8_result) &&
1361 (MHD_WEBSOCKET_FRAGMENTATION_NONE == fragmentation) )
1362 {
1363 return MHD_WEBSOCKET_STATUS_UTF8_ENCODING_ERROR;
1364 }
1365
1366 /* encode data */
1367 return MHD_websocket_encode_data (ws,
1368 payload_utf8,
1369 payload_utf8_len,
1370 fragmentation,
1371 frame,
1372 frame_len,
1373 MHD_WebSocket_Opcode_Text);
1374}
1375
1376
1377/**
1378 * Encodes binary data into a websocket binary frame
1379 */
1380_MHD_EXTERN int
1381MHD_websocket_encode_binary (struct MHD_WebSocketStream*ws,
1382 const char*payload,
1383 size_t payload_len,
1384 int fragmentation,
1385 char**frame,
1386 size_t*frame_len)
1387{
1388 /* initialize output variables for errors cases */
1389 if (NULL != frame)
1390 *frame = NULL;
1391 if (NULL != frame_len)
1392 *frame_len = 0;
1393
1394 /* validate parameters */
1395 if ((NULL == ws) ||
1396 (0 != payload_len) && (NULL == payload) ||
1397 (NULL == frame) ||
1398 (NULL == frame_len) ||
1399 (MHD_WEBSOCKET_FRAGMENTATION_NONE > fragmentation) ||
1400 (MHD_WEBSOCKET_FRAGMENTATION_LAST < fragmentation) )
1401 {
1402 return MHD_WEBSOCKET_STATUS_PARAMETER_ERROR;
1403 }
1404
1405 /* check max length */
1406 if ((uint64_t) 0x7FFFFFFFFFFFFFFF < (uint64_t) payload_len)
1407 {
1408 return MHD_WEBSOCKET_STATUS_MAXIMUM_SIZE_EXCEEDED;
1409 }
1410
1411 return MHD_websocket_encode_data (ws,
1412 payload,
1413 payload_len,
1414 fragmentation,
1415 frame,
1416 frame_len,
1417 MHD_WebSocket_Opcode_Binary);
1418}
1419
1420
1421/**
1422 * Internal function for encoding text/binary data into a websocket frame
1423 */
1424static int
1425MHD_websocket_encode_data (struct MHD_WebSocketStream*ws,
1426 const char*payload,
1427 size_t payload_len,
1428 int fragmentation,
1429 char**frame,
1430 size_t*frame_len,
1431 char opcode)
1432{
1433 /* calculate length and masking */
1434 char is_masked = MHD_websocket_encode_is_masked (ws);
1435 size_t overhead_len = MHD_websocket_encode_overhead_size (ws, payload_len);
1436 size_t total_len = overhead_len + payload_len;
1437 unsigned long mask = 0 != is_masked ? MHD_websocket_generate_mask () : 0;
1438
1439 /* allocate memory */
1440 char*result = ws->malloc (total_len + 1);
1441 if (NULL == result)
1442 return MHD_WEBSOCKET_STATUS_MEMORY_ERROR;
1443 result [total_len] = 0;
1444 *frame = result;
1445 *frame_len = total_len;
1446
1447 /* add the opcode */
1448 switch (fragmentation)
1449 {
1450 case MHD_WEBSOCKET_FRAGMENTATION_NONE:
1451 *(result++) = 0x80 | opcode;
1452 break;
1453 case MHD_WEBSOCKET_FRAGMENTATION_FIRST:
1454 *(result++) = opcode;
1455 break;
1456 case MHD_WEBSOCKET_FRAGMENTATION_FOLLOWING:
1457 *(result++) = MHD_WebSocket_Opcode_Continuation;
1458 break;
1459 case MHD_WEBSOCKET_FRAGMENTATION_LAST:
1460 *(result++) = 0x80 | MHD_WebSocket_Opcode_Continuation;
1461 break;
1462 }
1463
1464 /* add the length */
1465 if (126 > payload_len)
1466 {
1467 *(result++) = is_masked | (char) payload_len;
1468 }
1469 else if (65536 > payload_len)
1470 {
1471 *(result++) = is_masked | 126;
1472 *((unsigned short *) result) = htons ((unsigned short) payload_len);
1473 result += 2;
1474 }
1475 else
1476 {
1477 *(result++) = is_masked | 127;
1478 *((uint64_t *) result) = htonll ((uint64_t) payload_len);
1479 result += 8;
1480
1481 }
1482
1483 /* add the mask */
1484 if (0 != is_masked)
1485 {
1486 *(result++) = ((char *) &mask)[0];
1487 *(result++) = ((char *) &mask)[1];
1488 *(result++) = ((char *) &mask)[2];
1489 *(result++) = ((char *) &mask)[3];
1490 }
1491
1492 /* add the payload */
1493 if (0 != payload_len)
1494 {
1495 MHD_websocket_copy_payload (result,
1496 payload,
1497 payload_len,
1498 mask,
1499 0);
1500 }
1501
1502 return MHD_WEBSOCKET_STATUS_OK;
1503}
1504
1505
1506/**
1507 * Encodes a websocket ping frame
1508 */
1509_MHD_EXTERN int
1510MHD_websocket_encode_ping (struct MHD_WebSocketStream*ws,
1511 const char*payload,
1512 size_t payload_len,
1513 char**frame,
1514 size_t*frame_len)
1515{
1516 /* encode the ping frame */
1517 return MHD_websocket_encode_ping_pong (ws,
1518 payload,
1519 payload_len,
1520 frame,
1521 frame_len,
1522 MHD_WebSocket_Opcode_Ping);
1523}
1524
1525
1526/**
1527 * Encodes a websocket pong frame
1528 */
1529_MHD_EXTERN int
1530MHD_websocket_encode_pong (struct MHD_WebSocketStream*ws,
1531 const char*payload,
1532 size_t payload_len,
1533 char**frame,
1534 size_t*frame_len)
1535{
1536 /* encode the pong frame */
1537 return MHD_websocket_encode_ping_pong (ws,
1538 payload,
1539 payload_len,
1540 frame,
1541 frame_len,
1542 MHD_WebSocket_Opcode_Pong);
1543}
1544
1545
1546/**
1547 * Internal function for encoding ping/pong frames
1548 */
1549static int
1550MHD_websocket_encode_ping_pong (struct MHD_WebSocketStream*ws,
1551 const char*payload,
1552 size_t payload_len,
1553 char**frame,
1554 size_t*frame_len,
1555 char opcode)
1556{
1557 /* initialize output variables for errors cases */
1558 if (NULL != frame)
1559 *frame = NULL;
1560 if (NULL != frame_len)
1561 *frame_len = 0;
1562
1563 /* validate the parameters */
1564 if ((NULL == ws) ||
1565 (0 != payload_len) && (NULL == payload) ||
1566 (NULL == frame) ||
1567 (NULL == frame_len) )
1568 {
1569 return MHD_WEBSOCKET_STATUS_PARAMETER_ERROR;
1570 }
1571
1572 /* RFC 6455 5.5: Control frames may only have up to 125 bytes of payload data */
1573 if (125 < payload_len)
1574 return MHD_WEBSOCKET_STATUS_MAXIMUM_SIZE_EXCEEDED;
1575
1576 /* calculate length and masking */
1577 char is_masked = MHD_websocket_encode_is_masked (ws);
1578 size_t overhead_len = MHD_websocket_encode_overhead_size (ws, payload_len);
1579 size_t total_len = overhead_len + payload_len;
1580 unsigned long mask = is_masked != 0 ? MHD_websocket_generate_mask () : 0;
1581
1582 /* allocate memory */
1583 char*result = ws->malloc (total_len + 1);
1584 if (NULL == result)
1585 return MHD_WEBSOCKET_STATUS_MEMORY_ERROR;
1586 result [total_len] = 0;
1587 *frame = result;
1588 *frame_len = total_len;
1589
1590 /* add the opcode */
1591 *(result++) = 0x80 | opcode;
1592
1593 /* add the length */
1594 *(result++) = is_masked | (char) payload_len;
1595
1596 /* add the mask */
1597 if (0 != is_masked)
1598 {
1599 *(result++) = ((char *) &mask)[0];
1600 *(result++) = ((char *) &mask)[1];
1601 *(result++) = ((char *) &mask)[2];
1602 *(result++) = ((char *) &mask)[3];
1603 }
1604
1605 /* add the payload */
1606 if (0 != payload_len)
1607 {
1608 MHD_websocket_copy_payload (result,
1609 payload,
1610 payload_len,
1611 mask,
1612 0);
1613 }
1614
1615 return MHD_WEBSOCKET_STATUS_OK;
1616}
1617
1618
1619/**
1620 * Encodes a websocket close frame
1621 */
1622_MHD_EXTERN int
1623MHD_websocket_encode_close (struct MHD_WebSocketStream*ws,
1624 unsigned short reason_code,
1625 const char*reason_utf8,
1626 size_t reason_utf8_len,
1627 char**frame,
1628 size_t*frame_len)
1629{
1630 /* initialize output variables for errors cases */
1631 if (NULL != frame)
1632 *frame = NULL;
1633 if (NULL != frame_len)
1634 *frame_len = 0;
1635
1636 /* validate the parameters */
1637 if ((NULL == ws) ||
1638 (0 != reason_utf8_len) && (NULL == reason_utf8) ||
1639 (NULL == frame) ||
1640 (NULL == frame_len) ||
1641 (MHD_WEBSOCKET_CLOSEREASON_NO_REASON != reason_code) && (1000 >
1642 reason_code) ||
1643 (0 != reason_utf8_len) && (MHD_WEBSOCKET_CLOSEREASON_NO_REASON ==
1644 reason_code) )
1645 {
1646 return MHD_WEBSOCKET_STATUS_PARAMETER_ERROR;
1647 }
1648
1649 /* RFC 6455 5.5: Control frames may only have up to 125 bytes of payload data, */
1650 /* but in this case only 123 bytes, because 2 bytes are reserved */
1651 /* for the close reason code. */
1652 if (123 < reason_utf8_len)
1653 return MHD_WEBSOCKET_STATUS_MAXIMUM_SIZE_EXCEEDED;
1654
1655 /* RFC 6455 5.5.1: If close payload data is given, it must be valid UTF-8 */
1656 if (0 != reason_utf8_len)
1657 {
1658 int utf8_result = MHD_websocket_check_utf8 (reason_utf8,
1659 reason_utf8_len,
1660 NULL,
1661 NULL);
1662 if (MHD_WebSocket_UTF8Result_Valid != utf8_result)
1663 return MHD_WEBSOCKET_STATUS_UTF8_ENCODING_ERROR;
1664 }
1665
1666 /* calculate length and masking */
1667 char is_masked = MHD_websocket_encode_is_masked (ws);
1668 size_t payload_len = (MHD_WEBSOCKET_CLOSEREASON_NO_REASON != reason_code ?
1669 2 + reason_utf8_len : 0);
1670 size_t overhead_len = MHD_websocket_encode_overhead_size (ws, payload_len);
1671 size_t total_len = overhead_len + payload_len;
1672 unsigned long mask = is_masked != 0 ? MHD_websocket_generate_mask () : 0;
1673
1674 /* allocate memory */
1675 char*result = ws->malloc (total_len + 1);
1676 if (NULL == result)
1677 return MHD_WEBSOCKET_STATUS_MEMORY_ERROR;
1678 result [total_len] = 0;
1679 *frame = result;
1680 *frame_len = total_len;
1681
1682 /* add the opcode */
1683 *(result++) = 0x88;
1684
1685 /* add the length */
1686 *(result++) = is_masked | (char) payload_len;
1687
1688 /* add the mask */
1689 if (0 != is_masked)
1690 {
1691 *(result++) = ((char *) &mask)[0];
1692 *(result++) = ((char *) &mask)[1];
1693 *(result++) = ((char *) &mask)[2];
1694 *(result++) = ((char *) &mask)[3];
1695 }
1696
1697 /* add the payload */
1698 if (0 != reason_code)
1699 {
1700 /* close reason code */
1701 unsigned short reason_code_nb = htons (reason_code);
1702 MHD_websocket_copy_payload (result,
1703 (const char*) &reason_code_nb,
1704 2,
1705 mask,
1706 0);
1707 result += 2;
1708
1709 /* custom reason payload */
1710 if (0 != reason_utf8_len)
1711 {
1712 MHD_websocket_copy_payload (result,
1713 reason_utf8,
1714 reason_utf8_len,
1715 mask,
1716 2);
1717 }
1718 }
1719
1720 return MHD_WEBSOCKET_STATUS_OK;
1721}
1722
1723
1724/**
1725 * Returns the 0x80 prefix for masked data, 0x00 otherwise
1726 */
1727static char
1728MHD_websocket_encode_is_masked (struct MHD_WebSocketStream*ws)
1729{
1730 return (ws->flags & MHD_WEBSOCKET_FLAG_MASK_SERVERCLIENT) ==
1731 MHD_WEBSOCKET_FLAG_CLIENT ? 0x80 : 0x00;
1732}
1733
1734
1735/**
1736 * Calculates the size of the overhead in bytes
1737 */
1738static char
1739MHD_websocket_encode_overhead_size (struct MHD_WebSocketStream*ws,
1740 size_t payload_len)
1741{
1742 return 2 + (MHD_websocket_encode_is_masked (ws) != 0 ? 4 : 0) + (125 <
1743 payload_len ?
1744 (65535 <
1745 payload_len
1746 ? 8 : 2) : 0);
1747}
1748
1749
1750/**
1751 * Copies the payload to the destination (using mask)
1752 */
1753static void
1754MHD_websocket_copy_payload (char*dst,
1755 const char*src,
1756 size_t len,
1757 unsigned long mask,
1758 unsigned long mask_offset)
1759{
1760 if (0 != len)
1761 {
1762 if (0 == mask)
1763 {
1764 /* when the mask is zero, we can just copy the data */
1765 memcpy (dst, src, len);
1766 }
1767 else
1768 {
1769 /* mask is used */
1770 char mask_[4];
1771 *((unsigned long *) mask_) = mask;
1772 for (size_t i = 0; i < len; ++i)
1773 {
1774 dst[i] = src[i] ^ mask_[(i + mask_offset) & 3];
1775 }
1776 }
1777 }
1778}
1779
1780
1781/**
1782 * Checks a UTF-8 sequence
1783 */
1784static int
1785MHD_websocket_check_utf8 (const char*buf,
1786 size_t buf_len,
1787 int*utf8_step,
1788 size_t*buf_offset)
1789{
1790 int utf8_step_ = (NULL != utf8_step) ? *utf8_step :
1791 MHD_WEBSOCKET_UTF8STEP_NORMAL;
1792
1793 for (size_t i = 0; i < buf_len; ++i)
1794 {
1795 unsigned char character = (unsigned char) buf[i];
1796 switch (utf8_step_)
1797 {
1798 case MHD_WEBSOCKET_UTF8STEP_NORMAL:
1799 if ((0x00 <= character) && (0x7F >= character))
1800 {
1801 /* RFC 3629 4: single byte UTF-8 sequence */
1802 /* (nothing to do here) */
1803 }
1804 else if ((0xC2 <= character) && (0xDF >= character))
1805 {
1806 /* RFC 3629 4: two byte UTF-8 sequence */
1807 utf8_step_ = MHD_WEBSOCKET_UTF8STEP_UTF2TAIL_1OF1;
1808 }
1809 else if (0xE0 == character)
1810 {
1811 /* RFC 3629 4: three byte UTF-8 sequence, but the second byte must be 0xA0-0xBF */
1812 utf8_step_ = MHD_WEBSOCKET_UTF8STEP_UTF3TAIL1_1OF2;
1813 }
1814 else if (0xED == character)
1815 {
1816 /* RFC 3629 4: three byte UTF-8 sequence, but the second byte must be 0x80-0x9F */
1817 utf8_step_ = MHD_WEBSOCKET_UTF8STEP_UTF3TAIL2_1OF2;
1818 }
1819 else if ((0xE1 <= character) && (0xEC >= character) ||
1820 (0xEE <= character) && (0xEF >= character) )
1821 {
1822 /* RFC 3629 4: three byte UTF-8 sequence, both tail bytes must be 0x80-0xBF */
1823 utf8_step_ = MHD_WEBSOCKET_UTF8STEP_UTF3TAIL_1OF2;
1824 }
1825 else if (0xF0 == character)
1826 {
1827 /* RFC 3629 4: four byte UTF-8 sequence, but the second byte must be 0x90-0xBF */
1828 utf8_step_ = MHD_WEBSOCKET_UTF8STEP_UTF4TAIL1_1OF3;
1829 }
1830 else if (0xF4 == character)
1831 {
1832 /* RFC 3629 4: four byte UTF-8 sequence, but the second byte must be 0x80-0x8F */
1833 utf8_step_ = MHD_WEBSOCKET_UTF8STEP_UTF4TAIL2_1OF3;
1834 }
1835 else if ((0xF1 <= character) && (0xF3 >= character))
1836 {
1837 /* RFC 3629 4: four byte UTF-8 sequence, all three tail bytes must be 0x80-0xBF */
1838 utf8_step_ = MHD_WEBSOCKET_UTF8STEP_UTF4TAIL_1OF3;
1839 }
1840 else
1841 {
1842 /* RFC 3629 4: Invalid UTF-8 byte */
1843 if (NULL != buf_offset)
1844 *buf_offset = i;
1845 return MHD_WebSocket_UTF8Result_Invalid;
1846 }
1847 break;
1848
1849 case MHD_WEBSOCKET_UTF8STEP_UTF3TAIL1_1OF2:
1850 if ((0xA0 <= character) && (0xBF >= character))
1851 {
1852 /* RFC 3629 4: Second byte of three byte UTF-8 sequence */
1853 utf8_step_ = MHD_WEBSOCKET_UTF8STEP_UTF3TAIL_2OF2;
1854 }
1855 else
1856 {
1857 /* RFC 3629 4: Invalid UTF-8 byte */
1858 if (NULL != buf_offset)
1859 *buf_offset = i;
1860 return MHD_WebSocket_UTF8Result_Invalid;
1861 }
1862 break;
1863
1864 case MHD_WEBSOCKET_UTF8STEP_UTF3TAIL2_1OF2:
1865 if ((0x80 <= character) && (0x9F >= character))
1866 {
1867 /* RFC 3629 4: Second byte of three byte UTF-8 sequence */
1868 utf8_step_ = MHD_WEBSOCKET_UTF8STEP_UTF3TAIL_2OF2;
1869 }
1870 else
1871 {
1872 /* RFC 3629 4: Invalid UTF-8 byte */
1873 if (NULL != buf_offset)
1874 *buf_offset = i;
1875 return MHD_WebSocket_UTF8Result_Invalid;
1876 }
1877 break;
1878
1879 case MHD_WEBSOCKET_UTF8STEP_UTF3TAIL_1OF2:
1880 if ((0x80 <= character) && (0xBF >= character))
1881 {
1882 /* RFC 3629 4: Second byte of three byte UTF-8 sequence */
1883 utf8_step_ = MHD_WEBSOCKET_UTF8STEP_UTF3TAIL_2OF2;
1884 }
1885 else
1886 {
1887 /* RFC 3629 4: Invalid UTF-8 byte */
1888 if (NULL != buf_offset)
1889 *buf_offset = i;
1890 return MHD_WebSocket_UTF8Result_Invalid;
1891 }
1892 break;
1893
1894 case MHD_WEBSOCKET_UTF8STEP_UTF4TAIL1_1OF3:
1895 if ((0x90 <= character) && (0xBF >= character))
1896 {
1897 /* RFC 3629 4: Second byte of four byte UTF-8 sequence */
1898 utf8_step_ = MHD_WEBSOCKET_UTF8STEP_UTF4TAIL_2OF3;
1899 }
1900 else
1901 {
1902 /* RFC 3629 4: Invalid UTF-8 byte */
1903 if (NULL != buf_offset)
1904 *buf_offset = i;
1905 return MHD_WebSocket_UTF8Result_Invalid;
1906 }
1907 break;
1908
1909 case MHD_WEBSOCKET_UTF8STEP_UTF4TAIL2_1OF3:
1910 if ((0x80 <= character) && (0x8F >= character))
1911 {
1912 /* RFC 3629 4: Second byte of four byte UTF-8 sequence */
1913 utf8_step_ = MHD_WEBSOCKET_UTF8STEP_UTF4TAIL_2OF3;
1914 }
1915 else
1916 {
1917 /* RFC 3629 4: Invalid UTF-8 byte */
1918 if (NULL != buf_offset)
1919 *buf_offset = i;
1920 return MHD_WebSocket_UTF8Result_Invalid;
1921 }
1922 break;
1923
1924 case MHD_WEBSOCKET_UTF8STEP_UTF4TAIL_1OF3:
1925 if ((0x80 <= character) && (0xBF >= character))
1926 {
1927 /* RFC 3629 4: Second byte of four byte UTF-8 sequence */
1928 utf8_step_ = MHD_WEBSOCKET_UTF8STEP_UTF4TAIL_2OF3;
1929 }
1930 else
1931 {
1932 /* RFC 3629 4: Invalid UTF-8 byte */
1933 if (NULL != buf_offset)
1934 *buf_offset = i;
1935 return MHD_WebSocket_UTF8Result_Invalid;
1936 }
1937 break;
1938
1939 case MHD_WEBSOCKET_UTF8STEP_UTF4TAIL_2OF3:
1940 if ((0x80 <= character) && (0xBF >= character))
1941 {
1942 /* RFC 3629 4: Third byte of four byte UTF-8 sequence */
1943 utf8_step_ = MHD_WEBSOCKET_UTF8STEP_UTF4TAIL_3OF3;
1944 }
1945 else
1946 {
1947 /* RFC 3629 4: Invalid UTF-8 byte */
1948 if (NULL != buf_offset)
1949 *buf_offset = i;
1950 return MHD_WebSocket_UTF8Result_Invalid;
1951 }
1952 break;
1953
1954 /* RFC 3629 4: Second byte of two byte UTF-8 sequence */
1955 case MHD_WEBSOCKET_UTF8STEP_UTF2TAIL_1OF1:
1956 /* RFC 3629 4: Third byte of three byte UTF-8 sequence */
1957 case MHD_WEBSOCKET_UTF8STEP_UTF3TAIL_2OF2:
1958 /* RFC 3629 4: Fourth byte of four byte UTF-8 sequence */
1959 case MHD_WEBSOCKET_UTF8STEP_UTF4TAIL_3OF3:
1960 if ((0x80 <= character) && (0xBF >= character))
1961 {
1962 utf8_step_ = MHD_WEBSOCKET_UTF8STEP_NORMAL;
1963 }
1964 else
1965 {
1966 /* RFC 3629 4: Invalid UTF-8 byte */
1967 if (NULL != buf_offset)
1968 *buf_offset = i;
1969 return MHD_WebSocket_UTF8Result_Invalid;
1970 }
1971 break;
1972
1973 default:
1974 /* Invalid last step...? */
1975 if (NULL != buf_offset)
1976 *buf_offset = i;
1977 return MHD_WebSocket_UTF8Result_Invalid;
1978 }
1979 }
1980
1981 /* return values */
1982 if (NULL != utf8_step)
1983 *utf8_step = utf8_step_;
1984 if (NULL != buf_offset)
1985 *buf_offset = buf_len;
1986 if (MHD_WEBSOCKET_UTF8STEP_NORMAL != utf8_step_)
1987 {
1988 return MHD_WebSocket_UTF8Result_Incomplete;
1989 }
1990 return MHD_WebSocket_UTF8Result_Valid;
1991}
1992
1993
1994/**
1995 * Calls srand in the scope of MHD to set the seed
1996 * for the random number generator used for masking.
1997 */
1998_MHD_EXTERN int
1999MHD_websocket_srand (unsigned long seed)
2000{
2001 srand (seed);
2002
2003 return MHD_WEBSOCKET_STATUS_OK;
2004}
2005
2006
2007/**
2008 * Generates a mask for masking by calling
2009 * a random number generator.
2010 */
2011static unsigned long
2012MHD_websocket_generate_mask ()
2013{
2014 unsigned char mask_[4];
2015 mask_ [0] = (unsigned char) (rand () & 0xFF);
2016 mask_ [1] = (unsigned char) (rand () & 0xFF);
2017 mask_ [2] = (unsigned char) (rand () & 0xFF);
2018 mask_ [3] = (unsigned char) (rand () & 0xFF);
2019
2020 return *((unsigned long *) mask_);
2021}
2022
2023
2024/**
2025 * Calls the malloc function associated with the websocket steam
2026 */
2027_MHD_EXTERN void*
2028MHD_websocket_malloc (struct MHD_WebSocketStream*ws,
2029 size_t len)
2030{
2031 if (NULL == ws)
2032 {
2033 return NULL;
2034 }
2035
2036 return ws->malloc (len);
2037}
2038
2039
2040/**
2041 * Calls the realloc function associated with the websocket steam
2042 */
2043_MHD_EXTERN void*
2044MHD_websocket_realloc (struct MHD_WebSocketStream*ws,
2045 void*cls,
2046 size_t len)
2047{
2048 if (NULL == ws)
2049 {
2050 return NULL;
2051 }
2052
2053 return ws->realloc (cls, len);
2054}
2055
2056
2057/**
2058 * Calls the free function associated with the websocket steam
2059 */
2060_MHD_EXTERN int
2061MHD_websocket_free (struct MHD_WebSocketStream*ws,
2062 void*cls)
2063{
2064 if (NULL == ws)
2065 {
2066 return MHD_WEBSOCKET_STATUS_PARAMETER_ERROR;
2067 }
2068
2069 ws->free (cls);
2070
2071 return MHD_WEBSOCKET_STATUS_OK;
2072}