GNU libmicrohttpd 0.9.77
Loading...
Searching...
No Matches
mhd_websocket.c
Go to the documentation of this file.
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
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 management) */
35 /* The function pointer to realloc for payload (can be used to use different memory management) */
37 /* The function pointer to free for payload (can be used to use different memory management) */
39 /* A closure for the random number generator (only used for client mode; usually not required) */
40 void *cls_rng;
41 /* The random number generator (only used for client mode; usually not required) */
43 /* The flags specified upon initialization. It may alter the behavior of decoding/encoding */
44 int flags;
45 /* The current step for the decoder. 0 means start of a frame. */
46 char decode_step;
47 /* Specifies whether the stream is valid (1) or not (0),
48 if a close frame has been received this is (-1) to indicate that no data frames are allowed anymore */
49 char validity;
50 /* The current step of the UTF-8 encoding check in the data payload */
51 char data_utf8_step;
52 /* The current step of the UTF-8 encoding check in the control payload */
53 char control_utf8_step;
54 /* if != 0 means that we expect a CONTINUATION frame */
55 char data_type;
56 /* The start of the current frame (may differ from data_payload for CONTINUATION frames) */
57 char *data_payload_start;
58 /* The buffer for the data frame */
59 char *data_payload;
60 /* The buffer for the control frame */
61 char *control_payload;
62 /* Configuration for the maximum allowed buffer size for payload data */
63 size_t max_payload_size;
64 /* The current frame header size */
65 size_t frame_header_size;
66 /* The current data payload size (can be greater than payload_size for fragmented frames) */
67 size_t data_payload_size;
68 /* The size of the payload of the current frame (control or data) */
69 size_t payload_size;
70 /* The processing offset to the start of the payload of the current frame (control or data) */
71 size_t payload_index;
72 /* The frame header of the current frame (control or data) */
73 char frame_header[32];
74 /* The mask key of the current frame (control or data); this is 0 if no masking used */
75 char mask_key[4];
76};
77
78#define MHD_WEBSOCKET_FLAG_MASK_SERVERCLIENT MHD_WEBSOCKET_FLAG_CLIENT
79#define MHD_WEBSOCKET_FLAG_MASK_FRAGMENTATION \
80 MHD_WEBSOCKET_FLAG_WANT_FRAGMENTS
81#define MHD_WEBSOCKET_FLAG_MASK_GENERATE_CLOSE_FRAMES \
82 MHD_WEBSOCKET_FLAG_GENERATE_CLOSE_FRAMES_ON_ERROR
83#define MHD_WEBSOCKET_FLAG_MASK_ALL \
84 (MHD_WEBSOCKET_FLAG_MASK_SERVERCLIENT \
85 | MHD_WEBSOCKET_FLAG_MASK_FRAGMENTATION \
86 | MHD_WEBSOCKET_FLAG_MASK_GENERATE_CLOSE_FRAMES)
87
89{
96};
97
99{
121
123{
128
129static void
131 const char *src,
132 size_t len,
133 uint32_t mask,
134 unsigned long mask_offset);
135
136static int
137MHD_websocket_check_utf8 (const char *buf,
138 size_t buf_len,
139 int *utf8_step,
140 size_t *buf_offset);
141
142static enum MHD_WEBSOCKET_STATUS
143MHD_websocket_decode_header_complete (struct MHD_WebSocketStream *ws,
144 char **payload,
145 size_t *payload_len);
146
147static enum MHD_WEBSOCKET_STATUS
148MHD_websocket_decode_payload_complete (struct MHD_WebSocketStream *ws,
149 char **payload,
150 size_t *payload_len);
151
152static char
153MHD_websocket_encode_is_masked (struct MHD_WebSocketStream *ws);
154static char
155MHD_websocket_encode_overhead_size (struct MHD_WebSocketStream *ws,
156 size_t payload_len);
157
158static enum MHD_WEBSOCKET_STATUS
159MHD_websocket_encode_data (struct MHD_WebSocketStream *ws,
160 const char *payload,
161 size_t payload_len,
162 int fragmentation,
163 char **frame,
164 size_t *frame_len,
165 char opcode);
166
167static enum MHD_WEBSOCKET_STATUS
168MHD_websocket_encode_ping_pong (struct MHD_WebSocketStream *ws,
169 const char *payload,
170 size_t payload_len,
171 char **frame,
172 size_t *frame_len,
173 char opcode);
174
175static uint32_t
176MHD_websocket_generate_mask (struct MHD_WebSocketStream *ws);
177
178static uint16_t
179MHD_htons (uint16_t value);
180
181static uint64_t
182MHD_htonll (uint64_t value);
183
184
189MHD_websocket_check_http_version (const char *http_version)
190{
191 /* validate parameters */
192 if (NULL == http_version)
193 {
194 /* Like with the other check routines, */
195 /* NULL is threated as "value not given" and not as parameter error */
197 }
198
199 /* Check whether the version has a valid format */
200 /* RFC 1945 3.1: The format must be "HTTP/x.x" where x is */
201 /* any digit and must appear at least once */
202 if (('H' != http_version[0]) ||
203 ('T' != http_version[1]) ||
204 ('T' != http_version[2]) ||
205 ('P' != http_version[3]) ||
206 ('/' != http_version[4]))
207 {
209 }
210
211 /* Find the major and minor part of the version */
212 /* RFC 1945 3.1: Both numbers must be threated as separate integers. */
213 /* Leading zeros must be ignored and both integers may have multiple digits */
214 const char *major = NULL;
215 const char *dot = NULL;
216 size_t i = 5;
217 for (;;)
218 {
219 char c = http_version[i];
220 if (('0' <= c) && ('9' >= c))
221 {
222 if ((NULL == major) ||
223 ((http_version + i == major + 1) && ('0' == *major)) )
224 {
225 major = http_version + i;
226 }
227 ++i;
228 }
229 else if ('.' == http_version[i])
230 {
231 dot = http_version + i;
232 ++i;
233 break;
234 }
235 else
236 {
238 }
239 }
240 const char *minor = NULL;
241 const char *end = NULL;
242 for (;;)
243 {
244 char c = http_version[i];
245 if (('0' <= c) && ('9' >= c))
246 {
247 if ((NULL == minor) ||
248 ((http_version + i == minor + 1) && ('0' == *minor)) )
249 {
250 minor = http_version + i;
251 }
252 ++i;
253 }
254 else if (0 == c)
255 {
256 end = http_version + i;
257 break;
258 }
259 else
260 {
262 }
263 }
264 if ((NULL == major) || (NULL == dot) || (NULL == minor) || (NULL == end))
265 {
267 }
268 if ((2 <= dot - major) || ('2' <= *major) ||
269 (('1' == *major) && ((2 <= end - minor) || ('1' <= *minor))) )
270 {
272 }
273
275}
276
277
282MHD_websocket_check_connection_header (const char *connection_header)
283{
284 /* validate parameters */
285 if (NULL == connection_header)
286 {
287 /* To be compatible with the return value */
288 /* of MHD_lookup_connection_value, */
289 /* NULL is threated as "value not given" and not as parameter error */
291 }
292
293 /* Check whether the Connection includes an Upgrade token */
294 /* RFC 7230 6.1: Multiple tokens may appear. */
295 /* RFC 7230 3.2.6: Tokens are comma separated */
296 const char *token_start = NULL;
297 const char *token_end = NULL;
298 for (size_t i = 0; ; ++i)
299 {
300 char c = connection_header[i];
301
302 /* RFC 7230 3.2.6: The list of allowed characters is a token is: */
303 /* "!" / "#" / "$" / "%" / "&" / "'" / "*" / */
304 /* "+" / "-" / "." / "^" / "_" / "`" / "|" / "~" */
305 /* DIGIT / ALPHA */
306 if (('!' == c) || ('#' == c) || ('$' == c) || ('%' == c) ||
307 ('&' == c) || ('\'' == c) || ('*' == c) ||
308 ('+' == c) || ('-' == c) || ('.' == c) || ('^' == c) ||
309 ('_' == c) || ('`' == c) || ('|' == c) || ('~' == c) ||
310 (('0' <= c) && ('9' >= c)) ||
311 (('A' <= c) && ('Z' >= c)) || (('a' <= c) && ('z' >= c)) )
312 {
313 /* This is a valid token character */
314 if (NULL == token_start)
315 {
316 token_start = connection_header + i;
317 }
318 token_end = connection_header + i + 1;
319 }
320 else if ((' ' == c) || ('\t' == c))
321 {
322 /* White-spaces around tokens will be ignored */
323 }
324 else if ((',' == c) || (0 == c))
325 {
326 /* Check the token (case-insensitive) */
327 if (NULL != token_start)
328 {
329 if (7 == (token_end - token_start) )
330 {
331 if ( (('U' == token_start[0]) || ('u' == token_start[0])) &&
332 (('P' == token_start[1]) || ('p' == token_start[1])) &&
333 (('G' == token_start[2]) || ('g' == token_start[2])) &&
334 (('R' == token_start[3]) || ('r' == token_start[3])) &&
335 (('A' == token_start[4]) || ('a' == token_start[4])) &&
336 (('D' == token_start[5]) || ('d' == token_start[5])) &&
337 (('E' == token_start[6]) || ('e' == token_start[6])) )
338 {
339 /* The token equals to "Upgrade" */
341 }
342 }
343 }
344 if (0 == c)
345 {
346 break;
347 }
348 token_start = NULL;
349 token_end = NULL;
350 }
351 else
352 {
353 /* RFC 7230 3.2.6: Other characters are not allowed */
355 }
356 }
358}
359
360
365MHD_websocket_check_upgrade_header (const char *upgrade_header)
366{
367 /* validate parameters */
368 if (NULL == upgrade_header)
369 {
370 /* To be compatible with the return value */
371 /* of MHD_lookup_connection_value, */
372 /* NULL is threated as "value not given" and not as parameter error */
374 }
375
376 /* Check whether the Connection includes an Upgrade token */
377 /* RFC 7230 6.1: Multiple tokens may appear. */
378 /* RFC 7230 3.2.6: Tokens are comma separated */
379 const char *keyword_start = NULL;
380 const char *keyword_end = NULL;
381 for (size_t i = 0; ; ++i)
382 {
383 char c = upgrade_header[i];
384
385 /* RFC 7230 3.2.6: The list of allowed characters is a token is: */
386 /* "!" / "#" / "$" / "%" / "&" / "'" / "*" / */
387 /* "+" / "-" / "." / "^" / "_" / "`" / "|" / "~" */
388 /* DIGIT / ALPHA */
389 /* We also allow "/" here as the sub-delimiter for the protocol version */
390 if (('!' == c) || ('#' == c) || ('$' == c) || ('%' == c) ||
391 ('&' == c) || ('\'' == c) || ('*' == c) ||
392 ('+' == c) || ('-' == c) || ('.' == c) || ('^' == c) ||
393 ('_' == c) || ('`' == c) || ('|' == c) || ('~' == c) ||
394 ('/' == c) ||
395 (('0' <= c) && ('9' >= c)) ||
396 (('A' <= c) && ('Z' >= c)) || (('a' <= c) && ('z' >= c)) )
397 {
398 /* This is a valid token character */
399 if (NULL == keyword_start)
400 {
401 keyword_start = upgrade_header + i;
402 }
403 keyword_end = upgrade_header + i + 1;
404 }
405 else if ((' ' == c) || ('\t' == c))
406 {
407 /* White-spaces around tokens will be ignored */
408 }
409 else if ((',' == c) || (0 == c))
410 {
411 /* Check the token (case-insensitive) */
412 if (NULL != keyword_start)
413 {
414 if (9 == (keyword_end - keyword_start) )
415 {
416 if ( (('W' == keyword_start[0]) || ('w' == keyword_start[0])) &&
417 (('E' == keyword_start[1]) || ('e' == keyword_start[1])) &&
418 (('B' == keyword_start[2]) || ('b' == keyword_start[2])) &&
419 (('S' == keyword_start[3]) || ('s' == keyword_start[3])) &&
420 (('O' == keyword_start[4]) || ('o' == keyword_start[4])) &&
421 (('C' == keyword_start[5]) || ('c' == keyword_start[5])) &&
422 (('K' == keyword_start[6]) || ('k' == keyword_start[6])) &&
423 (('E' == keyword_start[7]) || ('e' == keyword_start[7])) &&
424 (('T' == keyword_start[8]) || ('t' == keyword_start[8])) )
425 {
426 /* The keyword equals to "websocket" */
428 }
429 }
430 }
431 if (0 == c)
432 {
433 break;
434 }
435 keyword_start = NULL;
436 keyword_end = NULL;
437 }
438 else
439 {
440 /* RFC 7230 3.2.6: Other characters are not allowed */
442 }
443 }
445}
446
447
453MHD_websocket_check_version_header (const char *version_header)
454{
455 /* validate parameters */
456 if (NULL == version_header)
457 {
458 /* To be compatible with the return value */
459 /* of MHD_lookup_connection_value, */
460 /* NULL is threated as "value not given" and not as parameter error */
462 }
463
464 if (('1' == version_header[0]) &&
465 ('3' == version_header[1]) &&
466 (0 == version_header[2]))
467 {
468 /* The version equals to "13" */
470 }
472}
473
474
479MHD_websocket_create_accept_header (const char *sec_websocket_key,
480 char *sec_websocket_accept)
481{
482 /* initialize output variables for errors cases */
483 if (NULL != sec_websocket_accept)
484 *sec_websocket_accept = 0;
485
486 /* validate parameters */
487 if (NULL == sec_websocket_accept)
488 {
490 }
491 if (NULL == sec_websocket_key)
492 {
493 /* NULL is not a parameter error, */
494 /* because MHD_lookup_connection_value returns NULL */
495 /* if the header wasn't found */
497 }
498
499 /* build SHA1 hash of the given key and the UUID appended */
500 char sha1[20];
501 const char *suffix = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
502 int length = (int) strlen (sec_websocket_key);
503 struct sha1_ctx ctx;
504 MHD_SHA1_init (&ctx);
505 MHD_SHA1_update (&ctx, (const uint8_t *) sec_websocket_key, length);
506 MHD_SHA1_update (&ctx, (const uint8_t *) suffix, 36);
507 MHD_SHA1_finish (&ctx, (uint8_t *) sha1);
508
509 /* base64 encode that SHA1 hash */
510 /* (simple algorithm here; SHA1 has always 20 bytes, */
511 /* which will always result in a 28 bytes base64 hash) */
512 const char *base64_encoding_table =
513 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
514 for (int i = 0, j = 0; i < 20;)
515 {
516 uint32_t octet_a = i < 20 ? (unsigned char) sha1[i++] : 0;
517 uint32_t octet_b = i < 20 ? (unsigned char) sha1[i++] : 0;
518 uint32_t octet_c = i < 20 ? (unsigned char) sha1[i++] : 0;
519 uint32_t triple = (octet_a << 0x10) + (octet_b << 0x08) + octet_c;
520
521 sec_websocket_accept[j++] = base64_encoding_table[(triple >> 3 * 6) & 0x3F];
522 sec_websocket_accept[j++] = base64_encoding_table[(triple >> 2 * 6) & 0x3F];
523 sec_websocket_accept[j++] = base64_encoding_table[(triple >> 1 * 6) & 0x3F];
524 sec_websocket_accept[j++] = base64_encoding_table[(triple >> 0 * 6) & 0x3F];
525
526 }
527 sec_websocket_accept[27] = '=';
528 sec_websocket_accept[28] = 0;
529
531}
532
533
538MHD_websocket_stream_init (struct MHD_WebSocketStream **ws,
539 int flags,
540 size_t max_payload_size)
541{
543 flags,
544 max_payload_size,
545 malloc,
546 realloc,
547 free,
548 NULL,
549 NULL);
550}
551
552
558MHD_websocket_stream_init2 (struct MHD_WebSocketStream **ws,
559 int flags,
560 size_t max_payload_size,
561 MHD_WebSocketMallocCallback callback_malloc,
562 MHD_WebSocketReallocCallback callback_realloc,
563 MHD_WebSocketFreeCallback callback_free,
564 void *cls_rng,
566{
567 /* initialize output variables for errors cases */
568 if (NULL != ws)
569 *ws = NULL;
570
571 /* validate parameters */
572 if ((NULL == ws) ||
573 (0 != (flags & ~MHD_WEBSOCKET_FLAG_MASK_ALL)) ||
574 ((uint64_t) 0x7FFFFFFFFFFFFFFF < max_payload_size) ||
575 (NULL == callback_malloc) ||
576 (NULL == callback_realloc) ||
577 (NULL == callback_free) ||
578 ((0 != (flags & MHD_WEBSOCKET_FLAG_CLIENT)) &&
579 (NULL == callback_rng)))
580 {
582 }
583
584 /* allocate stream */
585 struct MHD_WebSocketStream *ws_ = (struct MHD_WebSocketStream *) malloc (
586 sizeof (struct MHD_WebSocketStream));
587 if (NULL == ws_)
589
590 /* initialize stream */
591 memset (ws_, 0, sizeof (struct MHD_WebSocketStream));
592 ws_->flags = flags;
593 ws_->max_payload_size = max_payload_size;
594 ws_->malloc = callback_malloc;
595 ws_->realloc = callback_realloc;
596 ws_->free = callback_free;
597 ws_->cls_rng = cls_rng;
598 ws_->rng = callback_rng;
599 ws_->validity = MHD_WEBSOCKET_VALIDITY_VALID;
600
601 /* return stream */
602 *ws = ws_;
603
605}
606
607
612MHD_websocket_stream_free (struct MHD_WebSocketStream *ws)
613{
614 /* validate parameters */
615 if (NULL == ws)
617
618 /* free allocated payload data */
619 if (ws->data_payload)
620 ws->free (ws->data_payload);
621 if (ws->control_payload)
622 ws->free (ws->control_payload);
623
624 /* free the stream */
625 free (ws);
626
628}
629
630
635MHD_websocket_stream_invalidate (struct MHD_WebSocketStream *ws)
636{
637 /* validate parameters */
638 if (NULL == ws)
640
641 /* invalidate stream */
642 ws->validity = MHD_WEBSOCKET_VALIDITY_INVALID;
643
645}
646
647
652MHD_websocket_stream_is_valid (struct MHD_WebSocketStream *ws)
653{
654 /* validate parameters */
655 if (NULL == ws)
657
658 return ws->validity;
659}
660
661
666MHD_websocket_decode (struct MHD_WebSocketStream *ws,
667 const char *streambuf,
668 size_t streambuf_len,
669 size_t *streambuf_read_len,
670 char **payload,
671 size_t *payload_len)
672{
673 /* initialize output variables for errors cases */
674 if (NULL != streambuf_read_len)
675 *streambuf_read_len = 0;
676 if (NULL != payload)
677 *payload = NULL;
678 if (NULL != payload_len)
679 *payload_len = 0;
680
681 /* validate parameters */
682 if ((NULL == ws) ||
683 ((NULL == streambuf) && (0 != streambuf_len)) ||
684 (NULL == streambuf_read_len) ||
685 (NULL == payload) ||
686 (NULL == payload_len) )
687 {
689 }
690
691 /* validate stream validity */
692 if (MHD_WEBSOCKET_VALIDITY_INVALID == ws->validity)
694
695 /* decode loop */
696 size_t current = 0;
697 while (current < streambuf_len)
698 {
699 switch (ws->decode_step)
700 {
701 /* start of frame */
703 {
704 /* The first byte contains the opcode, the fin flag and three reserved bits */
705 if (MHD_WEBSOCKET_VALIDITY_INVALID != ws->validity)
706 {
707 char opcode = streambuf [current];
708 if (0 != (opcode & 0x70))
709 {
710 /* RFC 6455 5.2 RSV1-3: If a reserved flag is set */
711 /* (while it isn't specified by an extension) the communication must fail. */
712 ws->validity = MHD_WEBSOCKET_VALIDITY_INVALID;
713 if (0 != (ws->flags
715 {
718 0,
719 0,
720 payload,
721 payload_len);
722 }
723 *streambuf_read_len = current;
725 }
726 switch (opcode & 0x0F)
727 {
729 if (0 == ws->data_type)
730 {
731 /* RFC 6455 5.4: Continuation frame without previous data frame */
732 ws->validity = MHD_WEBSOCKET_VALIDITY_INVALID;
733 if (0 != (ws->flags
735 {
738 0,
739 0,
740 payload,
741 payload_len);
742 }
743 *streambuf_read_len = current;
745 }
747 ws->validity)
748 {
749 /* RFC 6455 5.5.1: After a close frame has been sent, */
750 /* no data frames may be sent (so we don't accept data frames */
751 /* for decoding anymore) */
752 ws->validity = MHD_WEBSOCKET_VALIDITY_INVALID;
753 if (0 != (ws->flags
755 {
758 0,
759 0,
760 payload,
761 payload_len);
762 }
763 *streambuf_read_len = current;
765 }
766 break;
767
770 if (0 != ws->data_type)
771 {
772 /* RFC 6455 5.4: Continuation expected, but new data frame */
773 ws->validity = MHD_WEBSOCKET_VALIDITY_INVALID;
774 if (0 != (ws->flags
776 {
779 0,
780 0,
781 payload,
782 payload_len);
783 }
784 *streambuf_read_len = current;
786 }
788 ws->validity)
789 {
790 /* RFC 6455 5.5.1: After a close frame has been sent, */
791 /* no data frames may be sent (so we don't accept data frames */
792 /* for decoding anymore) */
793 ws->validity = MHD_WEBSOCKET_VALIDITY_INVALID;
794 if (0 != (ws->flags
796 {
799 0,
800 0,
801 payload,
802 payload_len);
803 }
804 *streambuf_read_len = current;
806 }
807 break;
808
812 if ((opcode & 0x80) == 0)
813 {
814 /* RFC 6455 5.4: Control frames may not be fragmented */
815 ws->validity = MHD_WEBSOCKET_VALIDITY_INVALID;
816 if (0 != (ws->flags
818 {
821 0,
822 0,
823 payload,
824 payload_len);
825 }
826 *streambuf_read_len = current;
828 }
829 if (MHD_WebSocket_Opcode_Close == (opcode & 0x0F))
830 {
831 /* RFC 6455 5.5.1: After a close frame has been sent, */
832 /* no data frames may be sent (so we don't accept data frames */
833 /* for decoding anymore) */
834 ws->validity =
836 }
837 break;
838
839 default:
840 /* RFC 6455 5.2 OPCODE: Only six opcodes are specified. */
841 /* All other are invalid in version 13 of the protocol. */
842 ws->validity = MHD_WEBSOCKET_VALIDITY_INVALID;
843 if (0 != (ws->flags
845 {
848 0,
849 0,
850 payload,
851 payload_len);
852 }
853 *streambuf_read_len = current;
855 }
856 }
857 ws->frame_header [ws->frame_header_size++] = streambuf [current++];
858 ws->decode_step = MHD_WebSocket_DecodeStep_Length1ofX;
859 }
860 break;
861
863 {
864 /* The second byte specifies whether the data is masked and the size */
865 /* (the client MUST mask the payload, the server MUST NOT mask the payload) */
866 char frame_len = streambuf [current];
867 char is_masked = (frame_len & 0x80);
868 frame_len &= 0x7f;
869 if (MHD_WEBSOCKET_VALIDITY_INVALID != ws->validity)
870 {
871 if (0 != is_masked)
872 {
873 if (MHD_WEBSOCKET_FLAG_CLIENT == (ws->flags
875 {
876 /* RFC 6455 5.1: All frames from the server must be unmasked */
877 ws->validity = MHD_WEBSOCKET_VALIDITY_INVALID;
878 if (0 != (ws->flags
880 {
883 0,
884 0,
885 payload,
886 payload_len);
887 }
888 *streambuf_read_len = current;
890 }
891 }
892 else
893 {
894 if (MHD_WEBSOCKET_FLAG_SERVER == (ws->flags
896 {
897 /* RFC 6455 5.1: All frames from the client must be masked */
898 ws->validity = MHD_WEBSOCKET_VALIDITY_INVALID;
899 if (0 != (ws->flags
901 {
904 0,
905 0,
906 payload,
907 payload_len);
908 }
909 *streambuf_read_len = current;
911 }
912 }
913 if (126 <= frame_len)
914 {
915 if (0 != (ws->frame_header [0] & 0x08))
916 {
917 /* RFC 6455 5.5: Control frames may not have more payload than 125 bytes */
918 ws->validity = MHD_WEBSOCKET_VALIDITY_INVALID;
919 if (0 != (ws->flags
921 {
924 0,
925 0,
926 payload,
927 payload_len);
928 }
929 *streambuf_read_len = current;
931 }
932 }
933 if (1 == frame_len)
934 {
935 if (MHD_WebSocket_Opcode_Close == (ws->frame_header [0] & 0x0F))
936 {
937 /* RFC 6455 5.5.1: The close frame must have at least */
938 /* two bytes of payload if payload is used */
939 ws->validity = MHD_WEBSOCKET_VALIDITY_INVALID;
940 if (0 != (ws->flags
942 {
945 0,
946 0,
947 payload,
948 payload_len);
949 }
950 *streambuf_read_len = current;
952 }
953 }
954 }
955 ws->frame_header [ws->frame_header_size++] = streambuf [current++];
956
957 if (126 == frame_len)
958 {
959 ws->decode_step = MHD_WebSocket_DecodeStep_Length1of2;
960 }
961 else if (127 == frame_len)
962 {
963 ws->decode_step = MHD_WebSocket_DecodeStep_Length1of8;
964 }
965 else
966 {
967 size_t size = (size_t) frame_len;
968 if ((SIZE_MAX < size) ||
969 (ws->max_payload_size && (ws->max_payload_size < size)) )
970 {
971 /* RFC 6455 7.4.1 1009: If the message is too big to process, we may close the connection */
972 ws->validity = MHD_WEBSOCKET_VALIDITY_INVALID;
973 if (0 != (ws->flags
975 {
978 0,
979 0,
980 payload,
981 payload_len);
982 }
983 *streambuf_read_len = current;
985 }
986 ws->payload_size = size;
987 if (0 != is_masked)
988 {
989 /* with mask */
990 ws->decode_step = MHD_WebSocket_DecodeStep_Mask1Of4;
991 }
992 else
993 {
994 /* without mask */
995 *((uint32_t *) ws->mask_key) = 0;
997 }
998 }
999 }
1000 break;
1001
1002 /* Payload size first byte of 2 bytes */
1004 /* Payload size first 7 bytes of 8 bytes */
1012 /* Mask first 3 bytes of 4 bytes */
1016 ws->frame_header [ws->frame_header_size++] = streambuf [current++];
1017 ++ws->decode_step;
1018 break;
1019
1020 /* 2 byte length finished */
1022 {
1023 ws->frame_header [ws->frame_header_size++] = streambuf [current++];
1024 size_t size = (size_t) MHD_htons (
1025 *((uint16_t *) &ws->frame_header [2]));
1026 if (125 >= size)
1027 {
1028 /* RFC 6455 5.2 Payload length: The minimal number of bytes */
1029 /* must be used for the length */
1030 ws->validity = MHD_WEBSOCKET_VALIDITY_INVALID;
1031 if (0 != (ws->flags
1033 {
1036 0,
1037 0,
1038 payload,
1039 payload_len);
1040 }
1041 *streambuf_read_len = current;
1043 }
1044 if ((SIZE_MAX < size) ||
1045 (ws->max_payload_size && (ws->max_payload_size < size)) )
1046 {
1047 /* RFC 6455 7.4.1 1009: If the message is too big to process, */
1048 /* we may close the connection */
1049 ws->validity = MHD_WEBSOCKET_VALIDITY_INVALID;
1050 if (0 != (ws->flags
1052 {
1055 0,
1056 0,
1057 payload,
1058 payload_len);
1059 }
1060 *streambuf_read_len = current;
1062 }
1063 ws->payload_size = size;
1064 if (0 != (ws->frame_header [1] & 0x80))
1065 {
1066 /* with mask */
1067 ws->decode_step = MHD_WebSocket_DecodeStep_Mask1Of4;
1068 }
1069 else
1070 {
1071 /* without mask */
1072 *((uint32_t *) ws->mask_key) = 0;
1074 }
1075 }
1076 break;
1077
1078 /* 8 byte length finished */
1080 {
1081 ws->frame_header [ws->frame_header_size++] = streambuf [current++];
1082 uint64_t size = MHD_htonll (*((uint64_t *) &ws->frame_header [2]));
1083 if (0x7fffffffffffffff < size)
1084 {
1085 /* RFC 6455 5.2 frame-payload-length-63: The length may */
1086 /* not exceed 0x7fffffffffffffff */
1087 ws->decode_step = MHD_WebSocket_DecodeStep_BrokenStream;
1088 ws->validity = MHD_WEBSOCKET_VALIDITY_INVALID;
1089 if (0 != (ws->flags
1091 {
1094 0,
1095 0,
1096 payload,
1097 payload_len);
1098 }
1099 *streambuf_read_len = current;
1101 }
1102 if (65535 >= size)
1103 {
1104 /* RFC 6455 5.2 Payload length: The minimal number of bytes */
1105 /* must be used for the length */
1106 ws->validity = MHD_WEBSOCKET_VALIDITY_INVALID;
1107 if (0 != (ws->flags
1109 {
1112 0,
1113 0,
1114 payload,
1115 payload_len);
1116 }
1117 *streambuf_read_len = current;
1119 }
1120 if ((SIZE_MAX < size) ||
1121 (ws->max_payload_size && (ws->max_payload_size < size)) )
1122 {
1123 /* RFC 6455 7.4.1 1009: If the message is too big to process, */
1124 /* we may close the connection */
1125 ws->validity = MHD_WEBSOCKET_VALIDITY_INVALID;
1126 if (0 != (ws->flags
1128 {
1131 0,
1132 0,
1133 payload,
1134 payload_len);
1135 }
1136 *streambuf_read_len = current;
1138 }
1139 ws->payload_size = (size_t) size;
1140
1141 if (0 != (ws->frame_header [1] & 0x80))
1142 {
1143 /* with mask */
1144 ws->decode_step = MHD_WebSocket_DecodeStep_Mask1Of4;
1145 }
1146 else
1147 {
1148 /* without mask */
1149 *((uint32_t *) ws->mask_key) = 0;
1151 }
1152 }
1153 break;
1154
1155 /* mask finished */
1157 ws->frame_header [ws->frame_header_size++] = streambuf [current++];
1158 *((uint32_t *) ws->mask_key) = *((uint32_t *) &ws->frame_header [ws->
1159 frame_header_size
1160 - 4]);
1162 break;
1163
1164 /* header finished */
1166 /* return or assign either to data or control */
1167 {
1169 payload,
1170 payload_len);
1171 if (MHD_WEBSOCKET_STATUS_OK != ret)
1172 {
1173 *streambuf_read_len = current;
1174 return ret;
1175 }
1176 }
1177 break;
1178
1179 /* payload data */
1182 {
1183 size_t bytes_needed = ws->payload_size - ws->payload_index;
1184 size_t bytes_remaining = streambuf_len - current;
1185 size_t bytes_to_take = bytes_needed < bytes_remaining ? bytes_needed :
1186 bytes_remaining;
1187 if (0 != bytes_to_take)
1188 {
1189 size_t utf8_start = ws->payload_index;
1190 char *decode_payload = ws->decode_step ==
1192 ws->data_payload_start :
1193 ws->control_payload;
1194
1195 /* copy the new payload data (with unmasking if necessary */
1196 MHD_websocket_copy_payload (decode_payload + ws->payload_index,
1197 &streambuf [current],
1198 bytes_to_take,
1199 *((uint32_t *) ws->mask_key),
1200 (unsigned long) (ws->payload_index
1201 & 0x03));
1202 current += bytes_to_take;
1203 ws->payload_index += bytes_to_take;
1205 ws->decode_step) &&
1206 (MHD_WebSocket_Opcode_Text == ws->data_type)) ||
1208 ws->decode_step) &&
1209 (MHD_WebSocket_Opcode_Close == (ws->frame_header [0] & 0x0f)) &&
1210 (2 < ws->payload_index)) )
1211 {
1212 /* RFC 6455 8.1: We need to check the UTF-8 validity */
1213 int utf8_step;
1214 char *decode_payload_utf8;
1215 size_t bytes_to_check;
1216 size_t utf8_error_offset = 0;
1217 if (MHD_WebSocket_DecodeStep_PayloadOfDataFrame == ws->decode_step)
1218 {
1219 utf8_step = ws->data_utf8_step;
1220 decode_payload_utf8 = decode_payload + utf8_start;
1221 bytes_to_check = bytes_to_take;
1222 }
1223 else
1224 {
1225 utf8_step = ws->control_utf8_step;
1226 if ((MHD_WebSocket_Opcode_Close == (ws->frame_header [0]
1227 & 0x0f)) &&
1228 (2 > utf8_start) )
1229 {
1230 /* The first two bytes of the close frame are binary content and */
1231 /* must be skipped in the UTF-8 check */
1232 utf8_start = 2;
1233 utf8_error_offset = 2;
1234 }
1235 decode_payload_utf8 = decode_payload + utf8_start;
1236 bytes_to_check = bytes_to_take - utf8_start;
1237 }
1238 size_t utf8_check_offset = 0;
1239 int utf8_result = MHD_websocket_check_utf8 (decode_payload_utf8,
1240 bytes_to_check,
1241 &utf8_step,
1242 &utf8_check_offset);
1243 if (MHD_WebSocket_UTF8Result_Invalid != utf8_result)
1244 {
1245 /* memorize current validity check step to continue later */
1246 ws->data_utf8_step = utf8_step;
1247 }
1248 else
1249 {
1250 /* RFC 6455 8.1: We must fail on broken UTF-8 sequence */
1251 ws->validity = MHD_WEBSOCKET_VALIDITY_INVALID;
1252 if (0 != (ws->flags
1254 {
1257 0,
1258 0,
1259 payload,
1260 payload_len);
1261 }
1262 *streambuf_read_len = current - bytes_to_take
1263 + utf8_check_offset + utf8_error_offset;
1265 }
1266 }
1267 }
1268 }
1269
1270 if (ws->payload_size == ws->payload_index)
1271 {
1272 /* all payload data of the current frame has been received */
1274 payload,
1275 payload_len);
1276 if (MHD_WEBSOCKET_STATUS_OK != ret)
1277 {
1278 *streambuf_read_len = current;
1279 return ret;
1280 }
1281 }
1282 break;
1283
1285 *streambuf_read_len = current;
1287 }
1288 }
1289
1290 /* Special treatment for zero payload length messages */
1291 if (MHD_WebSocket_DecodeStep_HeaderCompleted == ws->decode_step)
1292 {
1294 payload,
1295 payload_len);
1296 if (MHD_WEBSOCKET_STATUS_OK != ret)
1297 {
1298 *streambuf_read_len = current;
1299 return ret;
1300 }
1301 }
1302 switch (ws->decode_step)
1303 {
1306 if (ws->payload_size == ws->payload_index)
1307 {
1308 /* all payload data of the current frame has been received */
1310 payload,
1311 payload_len);
1312 if (MHD_WEBSOCKET_STATUS_OK != ret)
1313 {
1314 *streambuf_read_len = current;
1315 return ret;
1316 }
1317 }
1318 break;
1319 }
1320 *streambuf_read_len = current;
1321
1322 /* more data needed */
1324}
1325
1326
1327static enum MHD_WEBSOCKET_STATUS
1328MHD_websocket_decode_header_complete (struct MHD_WebSocketStream *ws,
1329 char **payload,
1330 size_t *payload_len)
1331{
1332 /* assign either to data or control */
1333 char opcode = ws->frame_header [0] & 0x0f;
1334 switch (opcode)
1335 {
1337 {
1338 /* validate payload size */
1339 size_t new_size_total = ws->payload_size + ws->data_payload_size;
1340 if ((0 != ws->max_payload_size) && (ws->max_payload_size <
1341 new_size_total) )
1342 {
1343 /* RFC 6455 7.4.1 1009: If the message is too big to process, */
1344 /* we may close the connection */
1345 ws->decode_step = MHD_WebSocket_DecodeStep_BrokenStream;
1346 ws->validity = MHD_WEBSOCKET_VALIDITY_INVALID;
1347 if (0 != (ws->flags
1349 {
1352 0,
1353 0,
1354 payload,
1355 payload_len);
1356 }
1358 }
1359 /* allocate buffer for continued data frame */
1360 char *new_buf = NULL;
1361 if (0 != new_size_total)
1362 {
1363 new_buf = ws->realloc (ws->data_payload, new_size_total + 1);
1364 if (NULL == new_buf)
1365 {
1367 }
1368 new_buf [new_size_total] = 0;
1369 ws->data_payload_start = &new_buf[ws->data_payload_size];
1370 }
1371 else
1372 {
1373 ws->data_payload_start = new_buf;
1374 }
1375 ws->data_payload = new_buf;
1376 ws->data_payload_size = new_size_total;
1377 }
1379 break;
1380
1383 /* allocate buffer for data frame */
1384 {
1385 size_t new_size_total = ws->payload_size;
1386 char *new_buf = NULL;
1387 if (0 != new_size_total)
1388 {
1389 new_buf = ws->malloc (new_size_total + 1);
1390 if (NULL == new_buf)
1391 {
1393 }
1394 new_buf [new_size_total] = 0;
1395 }
1396 ws->data_payload = new_buf;
1397 ws->data_payload_start = new_buf;
1398 ws->data_payload_size = new_size_total;
1399 ws->data_type = opcode;
1400 }
1402 break;
1403
1407 /* allocate buffer for control frame */
1408 {
1409 size_t new_size_total = ws->payload_size;
1410 char *new_buf = NULL;
1411 if (0 != new_size_total)
1412 {
1413 new_buf = ws->malloc (new_size_total + 1);
1414 if (NULL == new_buf)
1415 {
1417 }
1418 new_buf[new_size_total] = 0;
1419 }
1420 ws->control_payload = new_buf;
1421 }
1423 break;
1424 }
1425
1427}
1428
1429
1430static enum MHD_WEBSOCKET_STATUS
1431MHD_websocket_decode_payload_complete (struct MHD_WebSocketStream *ws,
1432 char **payload,
1433 size_t *payload_len)
1434{
1435 /* all payload data of the current frame has been received */
1436 char is_continue = MHD_WebSocket_Opcode_Continuation ==
1437 (ws->frame_header [0] & 0x0F);
1438 char is_fin = ws->frame_header [0] & 0x80;
1439 if (0 != is_fin)
1440 {
1441 /* the frame is complete */
1442 if (MHD_WebSocket_DecodeStep_PayloadOfDataFrame == ws->decode_step)
1443 {
1444 /* data frame */
1445 char data_type = ws->data_type;
1446 if ((0 != (ws->flags & MHD_WEBSOCKET_FLAG_WANT_FRAGMENTS)) &&
1447 (0 != is_continue))
1448 {
1449 data_type |= 0x40; /* mark as last fragment */
1450 }
1451 *payload = ws->data_payload;
1452 *payload_len = ws->data_payload_size;
1453 ws->data_payload = 0;
1454 ws->data_payload_start = 0;
1455 ws->data_payload_size = 0;
1456 ws->decode_step = MHD_WebSocket_DecodeStep_Start;
1457 ws->payload_index = 0;
1458 ws->data_type = 0;
1459 ws->frame_header_size = 0;
1460 return data_type;
1461 }
1462 else
1463 {
1464 /* control frame */
1465 *payload = ws->control_payload;
1466 *payload_len = ws->payload_size;
1467 ws->control_payload = 0;
1468 ws->decode_step = MHD_WebSocket_DecodeStep_Start;
1469 ws->payload_index = 0;
1470 ws->frame_header_size = 0;
1471 return (ws->frame_header [0] & 0x0f);
1472 }
1473 }
1474 else if (0 != (ws->flags & MHD_WEBSOCKET_FLAG_WANT_FRAGMENTS))
1475 {
1476 /* RFC 6455 5.4: To allow streaming, the user can choose */
1477 /* to return fragments */
1478 if ((MHD_WebSocket_Opcode_Text == ws->data_type) &&
1479 (MHD_WEBSOCKET_UTF8STEP_NORMAL != ws->data_utf8_step) )
1480 {
1481 /* the last UTF-8 sequence is incomplete, so we keep the start of
1482 that and only return the part before */
1483 size_t given_utf8 = 0;
1484 switch (ws->data_utf8_step)
1485 {
1486 /* one byte given */
1494 given_utf8 = 1;
1495 break;
1496 /* two bytes given */
1499 given_utf8 = 2;
1500 break;
1501 /* three bytes given */
1503 given_utf8 = 3;
1504 break;
1505 }
1506 size_t new_len = ws->data_payload_size - given_utf8;
1507 if (0 != new_len)
1508 {
1509 char *next_payload = ws->malloc (given_utf8 + 1);
1510 if (NULL == next_payload)
1511 {
1513 }
1514 memcpy (next_payload,
1515 ws->data_payload_start + ws->payload_index - given_utf8,
1516 given_utf8);
1517 next_payload[given_utf8] = 0;
1518
1519 ws->data_payload[new_len] = 0;
1520 *payload = ws->data_payload;
1521 *payload_len = new_len;
1522 ws->data_payload = next_payload;
1523 ws->data_payload_size = given_utf8;
1524 }
1525 else
1526 {
1527 *payload = NULL;
1528 *payload_len = 0;
1529 }
1530 ws->decode_step = MHD_WebSocket_DecodeStep_Start;
1531 ws->payload_index = 0;
1532 ws->frame_header_size = 0;
1533 if (0 != is_continue)
1534 return ws->data_type | 0x20; /* mark as middle fragment */
1535 else
1536 return ws->data_type | 0x10; /* mark as first fragment */
1537 }
1538 else
1539 {
1540 /* we simply pass the entire data frame */
1541 *payload = ws->data_payload;
1542 *payload_len = ws->data_payload_size;
1543 ws->data_payload = 0;
1544 ws->data_payload_start = 0;
1545 ws->data_payload_size = 0;
1546 ws->decode_step = MHD_WebSocket_DecodeStep_Start;
1547 ws->payload_index = 0;
1548 ws->frame_header_size = 0;
1549 if (0 != is_continue)
1550 return ws->data_type | 0x20; /* mark as middle fragment */
1551 else
1552 return ws->data_type | 0x10; /* mark as first fragment */
1553 }
1554 }
1555 else
1556 {
1557 /* RFC 6455 5.4: We must await a continuation frame to get */
1558 /* the remainder of this data frame */
1559 ws->decode_step = MHD_WebSocket_DecodeStep_Start;
1560 ws->frame_header_size = 0;
1561 ws->payload_index = 0;
1563 }
1564}
1565
1566
1572 size_t payload_len,
1573 unsigned short *reason_code,
1574 const char **reason_utf8,
1575 size_t *reason_utf8_len)
1576{
1577 /* initialize output variables for errors cases */
1578 if (NULL != reason_code)
1580 if (NULL != reason_utf8)
1581 *reason_utf8 = NULL;
1582 if (NULL != reason_utf8_len)
1583 *reason_utf8_len = 0;
1584
1585 /* validate parameters */
1586 if ((NULL == payload) && (0 != payload_len))
1588 if (1 == payload_len)
1590 if (125 < payload_len)
1592
1593 /* decode reason code */
1594 if (2 > payload_len)
1595 {
1596 if (NULL != reason_code)
1598 }
1599 else
1600 {
1601 if (NULL != reason_code)
1602 *reason_code = MHD_htons (*((uint16_t *) payload));
1603 }
1604
1605 /* decode reason text */
1606 if (2 >= payload_len)
1607 {
1608 if (NULL != reason_utf8)
1609 *reason_utf8 = NULL;
1610 if (NULL != reason_utf8_len)
1611 *reason_utf8_len = 0;
1612 }
1613 else
1614 {
1615 if (NULL != reason_utf8)
1616 *reason_utf8 = payload + 2;
1617 if (NULL != reason_utf8_len)
1618 *reason_utf8_len = payload_len - 2;
1619 }
1620
1622}
1623
1624
1629MHD_websocket_encode_text (struct MHD_WebSocketStream *ws,
1630 const char *payload_utf8,
1631 size_t payload_utf8_len,
1632 int fragmentation,
1633 char **frame,
1634 size_t *frame_len,
1635 int *utf8_step)
1636{
1637 /* initialize output variables for errors cases */
1638 if (NULL != frame)
1639 *frame = NULL;
1640 if (NULL != frame_len)
1641 *frame_len = 0;
1642 if ((NULL != utf8_step) &&
1643 ((MHD_WEBSOCKET_FRAGMENTATION_FIRST == fragmentation) ||
1644 (MHD_WEBSOCKET_FRAGMENTATION_NONE == fragmentation) ))
1645 {
1646 /* the old UTF-8 step will be ignored for new fragments */
1647 *utf8_step = MHD_WEBSOCKET_UTF8STEP_NORMAL;
1648 }
1649
1650 /* validate parameters */
1651 if ((NULL == ws) ||
1652 ((0 != payload_utf8_len) && (NULL == payload_utf8)) ||
1653 (NULL == frame) ||
1654 (NULL == frame_len) ||
1655 (MHD_WEBSOCKET_FRAGMENTATION_NONE > fragmentation) ||
1656 (MHD_WEBSOCKET_FRAGMENTATION_LAST < fragmentation) ||
1657 ((MHD_WEBSOCKET_FRAGMENTATION_NONE != fragmentation) &&
1658 (NULL == utf8_step)) )
1659 {
1661 }
1662
1663 /* check max length */
1664 if ((uint64_t) 0x7FFFFFFFFFFFFFFF < (uint64_t) payload_utf8_len)
1665 {
1667 }
1668
1669 /* check UTF-8 */
1670 int utf8_result = MHD_websocket_check_utf8 (payload_utf8,
1671 payload_utf8_len,
1672 utf8_step,
1673 NULL);
1674 if ((MHD_WebSocket_UTF8Result_Invalid == utf8_result) ||
1675 ((MHD_WebSocket_UTF8Result_Incomplete == utf8_result) &&
1676 (MHD_WEBSOCKET_FRAGMENTATION_NONE == fragmentation)) )
1677 {
1679 }
1680
1681 /* encode data */
1682 return MHD_websocket_encode_data (ws,
1683 payload_utf8,
1684 payload_utf8_len,
1685 fragmentation,
1686 frame,
1687 frame_len,
1689}
1690
1691
1696MHD_websocket_encode_binary (struct MHD_WebSocketStream *ws,
1697 const char *payload,
1698 size_t payload_len,
1699 int fragmentation,
1700 char **frame,
1701 size_t *frame_len)
1702{
1703 /* initialize output variables for errors cases */
1704 if (NULL != frame)
1705 *frame = NULL;
1706 if (NULL != frame_len)
1707 *frame_len = 0;
1708
1709 /* validate parameters */
1710 if ((NULL == ws) ||
1711 ((0 != payload_len) && (NULL == payload)) ||
1712 (NULL == frame) ||
1713 (NULL == frame_len) ||
1714 (MHD_WEBSOCKET_FRAGMENTATION_NONE > fragmentation) ||
1715 (MHD_WEBSOCKET_FRAGMENTATION_LAST < fragmentation) )
1716 {
1718 }
1719
1720 /* check max length */
1721 if ((uint64_t) 0x7FFFFFFFFFFFFFFF < (uint64_t) payload_len)
1722 {
1724 }
1725
1726 return MHD_websocket_encode_data (ws,
1727 payload,
1728 payload_len,
1729 fragmentation,
1730 frame,
1731 frame_len,
1733}
1734
1735
1739static enum MHD_WEBSOCKET_STATUS
1740MHD_websocket_encode_data (struct MHD_WebSocketStream *ws,
1741 const char *payload,
1742 size_t payload_len,
1743 int fragmentation,
1744 char **frame,
1745 size_t *frame_len,
1746 char opcode)
1747{
1748 /* calculate length and masking */
1749 char is_masked = MHD_websocket_encode_is_masked (ws);
1750 size_t overhead_len = MHD_websocket_encode_overhead_size (ws, payload_len);
1751 size_t total_len = overhead_len + payload_len;
1752 uint32_t mask = 0 != is_masked ? MHD_websocket_generate_mask (ws) : 0;
1753
1754 /* allocate memory */
1755 char *result = ws->malloc (total_len + 1);
1756 if (NULL == result)
1758 result [total_len] = 0;
1759 *frame = result;
1760 *frame_len = total_len;
1761
1762 /* add the opcode */
1763 switch (fragmentation)
1764 {
1766 *(result++) = 0x80 | opcode;
1767 break;
1769 *(result++) = opcode;
1770 break;
1773 break;
1775 *(result++) = 0x80 | MHD_WebSocket_Opcode_Continuation;
1776 break;
1777 }
1778
1779 /* add the length */
1780 if (126 > payload_len)
1781 {
1782 *(result++) = is_masked | (char) payload_len;
1783 }
1784 else if (65536 > payload_len)
1785 {
1786 *(result++) = is_masked | 126;
1787 *((uint16_t *) result) = MHD_htons ((uint16_t) payload_len);
1788 result += 2;
1789 }
1790 else
1791 {
1792 *(result++) = is_masked | 127;
1793 *((uint64_t *) result) = MHD_htonll ((uint64_t) payload_len);
1794 result += 8;
1795
1796 }
1797
1798 /* add the mask */
1799 if (0 != is_masked)
1800 {
1801 *(result++) = ((char *) &mask)[0];
1802 *(result++) = ((char *) &mask)[1];
1803 *(result++) = ((char *) &mask)[2];
1804 *(result++) = ((char *) &mask)[3];
1805 }
1806
1807 /* add the payload */
1808 if (0 != payload_len)
1809 {
1811 payload,
1812 payload_len,
1813 mask,
1814 0);
1815 }
1816
1818}
1819
1820
1825MHD_websocket_encode_ping (struct MHD_WebSocketStream *ws,
1826 const char *payload,
1827 size_t payload_len,
1828 char **frame,
1829 size_t *frame_len)
1830{
1831 /* encode the ping frame */
1833 payload,
1834 payload_len,
1835 frame,
1836 frame_len,
1838}
1839
1840
1845MHD_websocket_encode_pong (struct MHD_WebSocketStream *ws,
1846 const char *payload,
1847 size_t payload_len,
1848 char **frame,
1849 size_t *frame_len)
1850{
1851 /* encode the pong frame */
1853 payload,
1854 payload_len,
1855 frame,
1856 frame_len,
1858}
1859
1860
1864static enum MHD_WEBSOCKET_STATUS
1865MHD_websocket_encode_ping_pong (struct MHD_WebSocketStream *ws,
1866 const char *payload,
1867 size_t payload_len,
1868 char **frame,
1869 size_t *frame_len,
1870 char opcode)
1871{
1872 /* initialize output variables for errors cases */
1873 if (NULL != frame)
1874 *frame = NULL;
1875 if (NULL != frame_len)
1876 *frame_len = 0;
1877
1878 /* validate the parameters */
1879 if ((NULL == ws) ||
1880 ((0 != payload_len) && (NULL == payload)) ||
1881 (NULL == frame) ||
1882 (NULL == frame_len) )
1883 {
1885 }
1886
1887 /* RFC 6455 5.5: Control frames may only have up to 125 bytes of payload data */
1888 if (125 < payload_len)
1890
1891 /* calculate length and masking */
1892 char is_masked = MHD_websocket_encode_is_masked (ws);
1893 size_t overhead_len = MHD_websocket_encode_overhead_size (ws, payload_len);
1894 size_t total_len = overhead_len + payload_len;
1895 uint32_t mask = is_masked != 0 ? MHD_websocket_generate_mask (ws) : 0;
1896
1897 /* allocate memory */
1898 char *result = ws->malloc (total_len + 1);
1899 if (NULL == result)
1901 result [total_len] = 0;
1902 *frame = result;
1903 *frame_len = total_len;
1904
1905 /* add the opcode */
1906 *(result++) = 0x80 | opcode;
1907
1908 /* add the length */
1909 *(result++) = is_masked | (char) payload_len;
1910
1911 /* add the mask */
1912 if (0 != is_masked)
1913 {
1914 *(result++) = ((char *) &mask)[0];
1915 *(result++) = ((char *) &mask)[1];
1916 *(result++) = ((char *) &mask)[2];
1917 *(result++) = ((char *) &mask)[3];
1918 }
1919
1920 /* add the payload */
1921 if (0 != payload_len)
1922 {
1924 payload,
1925 payload_len,
1926 mask,
1927 0);
1928 }
1929
1931}
1932
1933
1938MHD_websocket_encode_close (struct MHD_WebSocketStream *ws,
1939 unsigned short reason_code,
1940 const char *reason_utf8,
1941 size_t reason_utf8_len,
1942 char **frame,
1943 size_t *frame_len)
1944{
1945 /* initialize output variables for errors cases */
1946 if (NULL != frame)
1947 *frame = NULL;
1948 if (NULL != frame_len)
1949 *frame_len = 0;
1950
1951 /* validate the parameters */
1952 if ((NULL == ws) ||
1953 ((0 != reason_utf8_len) && (NULL == reason_utf8)) ||
1954 (NULL == frame) ||
1955 (NULL == frame_len) ||
1956 ((MHD_WEBSOCKET_CLOSEREASON_NO_REASON != reason_code) &&
1957 (1000 > reason_code)) ||
1958 ((0 != reason_utf8_len) &&
1959 (MHD_WEBSOCKET_CLOSEREASON_NO_REASON == reason_code)) )
1960 {
1962 }
1963
1964 /* RFC 6455 5.5: Control frames may only have up to 125 bytes of payload data, */
1965 /* but in this case only 123 bytes, because 2 bytes are reserved */
1966 /* for the close reason code. */
1967 if (123 < reason_utf8_len)
1969
1970 /* RFC 6455 5.5.1: If close payload data is given, it must be valid UTF-8 */
1971 if (0 != reason_utf8_len)
1972 {
1973 int utf8_result = MHD_websocket_check_utf8 (reason_utf8,
1974 reason_utf8_len,
1975 NULL,
1976 NULL);
1977 if (MHD_WebSocket_UTF8Result_Valid != utf8_result)
1979 }
1980
1981 /* calculate length and masking */
1982 char is_masked = MHD_websocket_encode_is_masked (ws);
1983 size_t payload_len = (MHD_WEBSOCKET_CLOSEREASON_NO_REASON != reason_code ?
1984 2 + reason_utf8_len : 0);
1985 size_t overhead_len = MHD_websocket_encode_overhead_size (ws, payload_len);
1986 size_t total_len = overhead_len + payload_len;
1987 uint32_t mask = is_masked != 0 ? MHD_websocket_generate_mask (ws) : 0;
1988
1989 /* allocate memory */
1990 char *result = ws->malloc (total_len + 1);
1991 if (NULL == result)
1993 result [total_len] = 0;
1994 *frame = result;
1995 *frame_len = total_len;
1996
1997 /* add the opcode */
1998 *(result++) = 0x88;
1999
2000 /* add the length */
2001 *(result++) = is_masked | (char) payload_len;
2002
2003 /* add the mask */
2004 if (0 != is_masked)
2005 {
2006 *(result++) = ((char *) &mask)[0];
2007 *(result++) = ((char *) &mask)[1];
2008 *(result++) = ((char *) &mask)[2];
2009 *(result++) = ((char *) &mask)[3];
2010 }
2011
2012 /* add the payload */
2013 if (0 != reason_code)
2014 {
2015 /* close reason code */
2016 uint16_t reason_code_nb = MHD_htons (reason_code);
2018 (const char *) &reason_code_nb,
2019 2,
2020 mask,
2021 0);
2022 result += 2;
2023
2024 /* custom reason payload */
2025 if (0 != reason_utf8_len)
2026 {
2028 reason_utf8,
2029 reason_utf8_len,
2030 mask,
2031 2);
2032 }
2033 }
2034
2036}
2037
2038
2042static char
2043MHD_websocket_encode_is_masked (struct MHD_WebSocketStream *ws)
2044{
2045 return (ws->flags & MHD_WEBSOCKET_FLAG_MASK_SERVERCLIENT) ==
2046 MHD_WEBSOCKET_FLAG_CLIENT ? 0x80 : 0x00;
2047}
2048
2049
2053static char
2054MHD_websocket_encode_overhead_size (struct MHD_WebSocketStream *ws,
2055 size_t payload_len)
2056{
2057 return 2 + (MHD_websocket_encode_is_masked (ws) != 0 ? 4 : 0) + (125 <
2058 payload_len ?
2059 (65535 <
2060 payload_len
2061 ? 8 : 2) : 0);
2062}
2063
2064
2068static void
2070 const char *src,
2071 size_t len,
2072 uint32_t mask,
2073 unsigned long mask_offset)
2074{
2075 if (0 != len)
2076 {
2077 if (0 == mask)
2078 {
2079 /* when the mask is zero, we can just copy the data */
2080 memcpy (dst, src, len);
2081 }
2082 else
2083 {
2084 /* mask is used */
2085 char mask_[4];
2086 *((uint32_t *) mask_) = mask;
2087 for (size_t i = 0; i < len; ++i)
2088 {
2089 dst[i] = src[i] ^ mask_[(i + mask_offset) & 3];
2090 }
2091 }
2092 }
2093}
2094
2095
2099static int
2101 size_t buf_len,
2102 int *utf8_step,
2103 size_t *buf_offset)
2104{
2105 int utf8_step_ = (NULL != utf8_step) ? *utf8_step :
2107
2108 for (size_t i = 0; i < buf_len; ++i)
2109 {
2110 unsigned char character = (unsigned char) buf[i];
2111 switch (utf8_step_)
2112 {
2114 if ((0x00 <= character) && (0x7F >= character))
2115 {
2116 /* RFC 3629 4: single byte UTF-8 sequence */
2117 /* (nothing to do here) */
2118 }
2119 else if ((0xC2 <= character) && (0xDF >= character))
2120 {
2121 /* RFC 3629 4: two byte UTF-8 sequence */
2123 }
2124 else if (0xE0 == character)
2125 {
2126 /* RFC 3629 4: three byte UTF-8 sequence, but the second byte must be 0xA0-0xBF */
2128 }
2129 else if (0xED == character)
2130 {
2131 /* RFC 3629 4: three byte UTF-8 sequence, but the second byte must be 0x80-0x9F */
2133 }
2134 else if (((0xE1 <= character) && (0xEC >= character)) ||
2135 ((0xEE <= character) && (0xEF >= character)) )
2136 {
2137 /* RFC 3629 4: three byte UTF-8 sequence, both tail bytes must be 0x80-0xBF */
2139 }
2140 else if (0xF0 == character)
2141 {
2142 /* RFC 3629 4: four byte UTF-8 sequence, but the second byte must be 0x90-0xBF */
2144 }
2145 else if (0xF4 == character)
2146 {
2147 /* RFC 3629 4: four byte UTF-8 sequence, but the second byte must be 0x80-0x8F */
2149 }
2150 else if ((0xF1 <= character) && (0xF3 >= character))
2151 {
2152 /* RFC 3629 4: four byte UTF-8 sequence, all three tail bytes must be 0x80-0xBF */
2154 }
2155 else
2156 {
2157 /* RFC 3629 4: Invalid UTF-8 byte */
2158 if (NULL != buf_offset)
2159 *buf_offset = i;
2161 }
2162 break;
2163
2165 if ((0xA0 <= character) && (0xBF >= character))
2166 {
2167 /* RFC 3629 4: Second byte of three byte UTF-8 sequence */
2169 }
2170 else
2171 {
2172 /* RFC 3629 4: Invalid UTF-8 byte */
2173 if (NULL != buf_offset)
2174 *buf_offset = i;
2176 }
2177 break;
2178
2180 if ((0x80 <= character) && (0x9F >= character))
2181 {
2182 /* RFC 3629 4: Second byte of three byte UTF-8 sequence */
2184 }
2185 else
2186 {
2187 /* RFC 3629 4: Invalid UTF-8 byte */
2188 if (NULL != buf_offset)
2189 *buf_offset = i;
2191 }
2192 break;
2193
2195 if ((0x80 <= character) && (0xBF >= character))
2196 {
2197 /* RFC 3629 4: Second byte of three byte UTF-8 sequence */
2199 }
2200 else
2201 {
2202 /* RFC 3629 4: Invalid UTF-8 byte */
2203 if (NULL != buf_offset)
2204 *buf_offset = i;
2206 }
2207 break;
2208
2210 if ((0x90 <= character) && (0xBF >= character))
2211 {
2212 /* RFC 3629 4: Second byte of four byte UTF-8 sequence */
2214 }
2215 else
2216 {
2217 /* RFC 3629 4: Invalid UTF-8 byte */
2218 if (NULL != buf_offset)
2219 *buf_offset = i;
2221 }
2222 break;
2223
2225 if ((0x80 <= character) && (0x8F >= character))
2226 {
2227 /* RFC 3629 4: Second byte of four byte UTF-8 sequence */
2229 }
2230 else
2231 {
2232 /* RFC 3629 4: Invalid UTF-8 byte */
2233 if (NULL != buf_offset)
2234 *buf_offset = i;
2236 }
2237 break;
2238
2240 if ((0x80 <= character) && (0xBF >= character))
2241 {
2242 /* RFC 3629 4: Second byte of four byte UTF-8 sequence */
2244 }
2245 else
2246 {
2247 /* RFC 3629 4: Invalid UTF-8 byte */
2248 if (NULL != buf_offset)
2249 *buf_offset = i;
2251 }
2252 break;
2253
2255 if ((0x80 <= character) && (0xBF >= character))
2256 {
2257 /* RFC 3629 4: Third byte of four byte UTF-8 sequence */
2259 }
2260 else
2261 {
2262 /* RFC 3629 4: Invalid UTF-8 byte */
2263 if (NULL != buf_offset)
2264 *buf_offset = i;
2266 }
2267 break;
2268
2269 /* RFC 3629 4: Second byte of two byte UTF-8 sequence */
2271 /* RFC 3629 4: Third byte of three byte UTF-8 sequence */
2273 /* RFC 3629 4: Fourth byte of four byte UTF-8 sequence */
2275 if ((0x80 <= character) && (0xBF >= character))
2276 {
2277 utf8_step_ = MHD_WEBSOCKET_UTF8STEP_NORMAL;
2278 }
2279 else
2280 {
2281 /* RFC 3629 4: Invalid UTF-8 byte */
2282 if (NULL != buf_offset)
2283 *buf_offset = i;
2285 }
2286 break;
2287
2288 default:
2289 /* Invalid last step...? */
2290 if (NULL != buf_offset)
2291 *buf_offset = i;
2293 }
2294 }
2295
2296 /* return values */
2297 if (NULL != utf8_step)
2298 *utf8_step = utf8_step_;
2299 if (NULL != buf_offset)
2300 *buf_offset = buf_len;
2301 if (MHD_WEBSOCKET_UTF8STEP_NORMAL != utf8_step_)
2302 {
2304 }
2306}
2307
2308
2313static uint32_t
2314MHD_websocket_generate_mask (struct MHD_WebSocketStream *ws)
2315{
2316 unsigned char mask_[4];
2317 if (NULL != ws->rng)
2318 {
2319 size_t offset = 0;
2320 while (offset < 4)
2321 {
2322 size_t encoded = ws->rng (ws->cls_rng,
2323 mask_ + offset,
2324 4 - offset);
2325 offset += encoded;
2326 }
2327 }
2328 else
2329 {
2330 /* this case should never happen */
2331 mask_ [0] = 0;
2332 mask_ [1] = 0;
2333 mask_ [2] = 0;
2334 mask_ [3] = 0;
2335 }
2336
2337 return *((uint32_t *) mask_);
2338}
2339
2340
2344_MHD_EXTERN void *
2345MHD_websocket_malloc (struct MHD_WebSocketStream *ws,
2346 size_t buf_len)
2347{
2348 if (NULL == ws)
2349 {
2350 return NULL;
2351 }
2352
2353 return ws->malloc (buf_len);
2354}
2355
2356
2360_MHD_EXTERN void *
2361MHD_websocket_realloc (struct MHD_WebSocketStream *ws,
2362 void *buf,
2363 size_t new_buf_len)
2364{
2365 if (NULL == ws)
2366 {
2367 return NULL;
2368 }
2369
2370 return ws->realloc (buf, new_buf_len);
2371}
2372
2373
2377_MHD_EXTERN int
2378MHD_websocket_free (struct MHD_WebSocketStream *ws,
2379 void *buf)
2380{
2381 if (NULL == ws)
2382 {
2384 }
2385
2386 ws->free (buf);
2387
2389}
2390
2391
2396static uint16_t
2397MHD_htons (uint16_t value)
2398{
2399 uint16_t endian = 0x0001;
2400
2401 if (((char *) &endian)[0] == 0x01)
2402 {
2403 /* least significant byte first */
2404 ((char *) &endian)[0] = ((char *) &value)[1];
2405 ((char *) &endian)[1] = ((char *) &value)[0];
2406 return endian;
2407 }
2408 else
2409 {
2410 /* most significant byte first */
2411 return value;
2412 }
2413}
2414
2415
2420static uint64_t
2421MHD_htonll (uint64_t value)
2422{
2423 uint64_t endian = 0x0000000000000001;
2424
2425 if (((char *) &endian)[0] == 0x01)
2426 {
2427 /* least significant byte first */
2428 ((char *) &endian)[0] = ((char *) &value)[7];
2429 ((char *) &endian)[1] = ((char *) &value)[6];
2430 ((char *) &endian)[2] = ((char *) &value)[5];
2431 ((char *) &endian)[3] = ((char *) &value)[4];
2432 ((char *) &endian)[4] = ((char *) &value)[3];
2433 ((char *) &endian)[5] = ((char *) &value)[2];
2434 ((char *) &endian)[6] = ((char *) &value)[1];
2435 ((char *) &endian)[7] = ((char *) &value)[0];
2436 return endian;
2437 }
2438 else
2439 {
2440 /* most significant byte first */
2441 return value;
2442 }
2443}
#define SIZE_MAX
Definition mhd_limits.h:99
#define NULL
#define _MHD_EXTERN
Definition mhd_options.h:50
_MHD_EXTERN enum MHD_WEBSOCKET_STATUS MHD_websocket_split_close_reason(const char *payload, size_t payload_len, unsigned short *reason_code, const char **reason_utf8, size_t *reason_utf8_len)
static uint64_t MHD_htonll(uint64_t value)
_MHD_EXTERN enum MHD_WEBSOCKET_STATUS MHD_websocket_check_http_version(const char *http_version)
_MHD_EXTERN enum MHD_WEBSOCKET_VALIDITY MHD_websocket_stream_is_valid(struct MHD_WebSocketStream *ws)
static char MHD_websocket_encode_is_masked(struct MHD_WebSocketStream *ws)
_MHD_EXTERN enum MHD_WEBSOCKET_STATUS MHD_websocket_stream_free(struct MHD_WebSocketStream *ws)
MHD_WebSocket_UTF8Result
@ MHD_WebSocket_UTF8Result_Valid
@ MHD_WebSocket_UTF8Result_Invalid
@ MHD_WebSocket_UTF8Result_Incomplete
#define MHD_WEBSOCKET_FLAG_MASK_SERVERCLIENT
MHD_WebSocket_DecodeStep
@ MHD_WebSocket_DecodeStep_Length1ofX
@ MHD_WebSocket_DecodeStep_Start
@ MHD_WebSocket_DecodeStep_Mask4Of4
@ MHD_WebSocket_DecodeStep_Length3of8
@ MHD_WebSocket_DecodeStep_HeaderCompleted
@ MHD_WebSocket_DecodeStep_Length7of8
@ MHD_WebSocket_DecodeStep_Length2of2
@ MHD_WebSocket_DecodeStep_Mask3Of4
@ MHD_WebSocket_DecodeStep_Length4of8
@ MHD_WebSocket_DecodeStep_Mask2Of4
@ MHD_WebSocket_DecodeStep_Length5of8
@ MHD_WebSocket_DecodeStep_PayloadOfControlFrame
@ MHD_WebSocket_DecodeStep_Length1of8
@ MHD_WebSocket_DecodeStep_PayloadOfDataFrame
@ MHD_WebSocket_DecodeStep_BrokenStream
@ MHD_WebSocket_DecodeStep_Mask1Of4
@ MHD_WebSocket_DecodeStep_Length2of8
@ MHD_WebSocket_DecodeStep_Length1of2
@ MHD_WebSocket_DecodeStep_Length6of8
@ MHD_WebSocket_DecodeStep_Length8of8
_MHD_EXTERN enum MHD_WEBSOCKET_STATUS MHD_websocket_encode_pong(struct MHD_WebSocketStream *ws, const char *payload, size_t payload_len, char **frame, size_t *frame_len)
#define MHD_WEBSOCKET_FLAG_MASK_ALL
_MHD_EXTERN int MHD_websocket_free(struct MHD_WebSocketStream *ws, void *buf)
static uint32_t MHD_websocket_generate_mask(struct MHD_WebSocketStream *ws)
_MHD_EXTERN enum MHD_WEBSOCKET_STATUS MHD_websocket_stream_init(struct MHD_WebSocketStream **ws, int flags, size_t max_payload_size)
_MHD_EXTERN enum MHD_WEBSOCKET_STATUS MHD_websocket_encode_ping(struct MHD_WebSocketStream *ws, const char *payload, size_t payload_len, char **frame, size_t *frame_len)
_MHD_EXTERN enum MHD_WEBSOCKET_STATUS MHD_websocket_decode(struct MHD_WebSocketStream *ws, const char *streambuf, size_t streambuf_len, size_t *streambuf_read_len, char **payload, size_t *payload_len)
static enum MHD_WEBSOCKET_STATUS MHD_websocket_encode_data(struct MHD_WebSocketStream *ws, const char *payload, size_t payload_len, int fragmentation, char **frame, size_t *frame_len, char opcode)
static enum MHD_WEBSOCKET_STATUS MHD_websocket_encode_ping_pong(struct MHD_WebSocketStream *ws, const char *payload, size_t payload_len, char **frame, size_t *frame_len, char opcode)
_MHD_EXTERN enum MHD_WEBSOCKET_STATUS MHD_websocket_encode_close(struct MHD_WebSocketStream *ws, unsigned short reason_code, const char *reason_utf8, size_t reason_utf8_len, char **frame, size_t *frame_len)
_MHD_EXTERN enum MHD_WEBSOCKET_STATUS MHD_websocket_check_connection_header(const char *connection_header)
_MHD_EXTERN enum MHD_WEBSOCKET_STATUS MHD_websocket_stream_init2(struct MHD_WebSocketStream **ws, int flags, size_t max_payload_size, MHD_WebSocketMallocCallback callback_malloc, MHD_WebSocketReallocCallback callback_realloc, MHD_WebSocketFreeCallback callback_free, void *cls_rng, MHD_WebSocketRandomNumberGenerator callback_rng)
static char MHD_websocket_encode_overhead_size(struct MHD_WebSocketStream *ws, size_t payload_len)
_MHD_EXTERN enum MHD_WEBSOCKET_STATUS MHD_websocket_create_accept_header(const char *sec_websocket_key, char *sec_websocket_accept)
_MHD_EXTERN void * MHD_websocket_realloc(struct MHD_WebSocketStream *ws, void *buf, size_t new_buf_len)
_MHD_EXTERN enum MHD_WEBSOCKET_STATUS MHD_websocket_stream_invalidate(struct MHD_WebSocketStream *ws)
_MHD_EXTERN void * MHD_websocket_malloc(struct MHD_WebSocketStream *ws, size_t buf_len)
_MHD_EXTERN enum MHD_WEBSOCKET_STATUS MHD_websocket_encode_binary(struct MHD_WebSocketStream *ws, const char *payload, size_t payload_len, int fragmentation, char **frame, size_t *frame_len)
static uint16_t MHD_htons(uint16_t value)
static void MHD_websocket_copy_payload(char *dst, const char *src, size_t len, uint32_t mask, unsigned long mask_offset)
_MHD_EXTERN enum MHD_WEBSOCKET_STATUS MHD_websocket_encode_text(struct MHD_WebSocketStream *ws, const char *payload_utf8, size_t payload_utf8_len, int fragmentation, char **frame, size_t *frame_len, int *utf8_step)
static int MHD_websocket_check_utf8(const char *buf, size_t buf_len, int *utf8_step, size_t *buf_offset)
_MHD_EXTERN enum MHD_WEBSOCKET_STATUS MHD_websocket_check_version_header(const char *version_header)
_MHD_EXTERN enum MHD_WEBSOCKET_STATUS MHD_websocket_check_upgrade_header(const char *upgrade_header)
static enum MHD_WEBSOCKET_STATUS MHD_websocket_decode_header_complete(struct MHD_WebSocketStream *ws, char **payload, size_t *payload_len)
static enum MHD_WEBSOCKET_STATUS MHD_websocket_decode_payload_complete(struct MHD_WebSocketStream *ws, char **payload, size_t *payload_len)
MHD_WebSocket_Opcode
@ MHD_WebSocket_Opcode_Close
@ MHD_WebSocket_Opcode_Continuation
@ MHD_WebSocket_Opcode_Text
@ MHD_WebSocket_Opcode_Ping
@ MHD_WebSocket_Opcode_Binary
@ MHD_WebSocket_Opcode_Pong
void MHD_SHA1_update(void *ctx_, const uint8_t *data, size_t length)
Definition sha1.c:249
void MHD_SHA1_finish(void *ctx_, uint8_t digest[SHA1_DIGEST_SIZE])
Definition sha1.c:311
void MHD_SHA1_init(void *ctx_)
Definition sha1.c:41
public interface to libmicrohttpd
int off_t offset
interface for experimental web socket extension to libmicrohttpd
size_t(* MHD_WebSocketRandomNumberGenerator)(void *cls, void *buf, size_t buf_len)
MHD_WEBSOCKET_STATUS
Enum of the return value for almost every MHD_websocket function. Errors are negative and values equa...
@ MHD_WEBSOCKET_STATUS_MAXIMUM_SIZE_EXCEEDED
@ MHD_WEBSOCKET_STATUS_STREAM_BROKEN
@ MHD_WEBSOCKET_STATUS_PARAMETER_ERROR
@ MHD_WEBSOCKET_STATUS_OK
@ MHD_WEBSOCKET_STATUS_UTF8_ENCODING_ERROR
@ MHD_WEBSOCKET_STATUS_NO_WEBSOCKET_HANDSHAKE_HEADER
@ MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR
@ MHD_WEBSOCKET_STATUS_MEMORY_ERROR
@ MHD_WEBSOCKET_FLAG_SERVER
@ MHD_WEBSOCKET_FLAG_WANT_FRAGMENTS
@ MHD_WEBSOCKET_FLAG_CLIENT
@ MHD_WEBSOCKET_FLAG_GENERATE_CLOSE_FRAMES_ON_ERROR
MHD_WEBSOCKET_VALIDITY
Enumeration of validity values.
@ MHD_WEBSOCKET_VALIDITY_INVALID
@ MHD_WEBSOCKET_VALIDITY_ONLY_VALID_FOR_CONTROL_FRAMES
@ MHD_WEBSOCKET_VALIDITY_VALID
@ MHD_WEBSOCKET_UTF8STEP_UTF2TAIL_1OF1
@ MHD_WEBSOCKET_UTF8STEP_NORMAL
@ MHD_WEBSOCKET_UTF8STEP_UTF4TAIL1_1OF3
@ MHD_WEBSOCKET_UTF8STEP_UTF4TAIL_3OF3
@ MHD_WEBSOCKET_UTF8STEP_UTF4TAIL_2OF3
@ MHD_WEBSOCKET_UTF8STEP_UTF3TAIL_1OF2
@ MHD_WEBSOCKET_UTF8STEP_UTF4TAIL_1OF3
@ MHD_WEBSOCKET_UTF8STEP_UTF3TAIL2_1OF2
@ MHD_WEBSOCKET_UTF8STEP_UTF3TAIL_2OF2
@ MHD_WEBSOCKET_UTF8STEP_UTF3TAIL1_1OF2
@ MHD_WEBSOCKET_UTF8STEP_UTF4TAIL2_1OF3
@ MHD_WEBSOCKET_CLOSEREASON_MAXIMUM_ALLOWED_PAYLOAD_SIZE_EXCEEDED
@ MHD_WEBSOCKET_CLOSEREASON_MALFORMED_UTF8
@ MHD_WEBSOCKET_CLOSEREASON_PROTOCOL_ERROR
@ MHD_WEBSOCKET_CLOSEREASON_NO_REASON
@ MHD_WEBSOCKET_FRAGMENTATION_FIRST
@ MHD_WEBSOCKET_FRAGMENTATION_LAST
@ MHD_WEBSOCKET_FRAGMENTATION_FOLLOWING
@ MHD_WEBSOCKET_FRAGMENTATION_NONE
void *(* MHD_WebSocketReallocCallback)(void *buf, size_t new_buf_len)
void *(* MHD_WebSocketMallocCallback)(size_t buf_len)
void(* MHD_WebSocketFreeCallback)(void *buf)
platform-specific includes for libmicrohttpd