GNU libmicrohttpd  0.9.75
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 
31 struct 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 {
120 };
121 
123 {
127 };
128 
129 static void
130 MHD_websocket_copy_payload (char *dst,
131  const char *src,
132  size_t len,
133  uint32_t mask,
134  unsigned long mask_offset);
135 
136 static int
137 MHD_websocket_check_utf8 (const char *buf,
138  size_t buf_len,
139  int *utf8_step,
140  size_t *buf_offset);
141 
142 static enum MHD_WEBSOCKET_STATUS
143 MHD_websocket_decode_header_complete (struct MHD_WebSocketStream *ws,
144  char **payload,
145  size_t *payload_len);
146 
147 static enum MHD_WEBSOCKET_STATUS
148 MHD_websocket_decode_payload_complete (struct MHD_WebSocketStream *ws,
149  char **payload,
150  size_t *payload_len);
151 
152 static char
153 MHD_websocket_encode_is_masked (struct MHD_WebSocketStream *ws);
154 static char
155 MHD_websocket_encode_overhead_size (struct MHD_WebSocketStream *ws,
156  size_t payload_len);
157 
158 static enum MHD_WEBSOCKET_STATUS
159 MHD_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 
167 static enum MHD_WEBSOCKET_STATUS
168 MHD_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 
175 static uint32_t
176 MHD_websocket_generate_mask (struct MHD_WebSocketStream *ws);
177 
178 static uint16_t
179 MHD_htons (uint16_t value);
180 
181 static uint64_t
182 MHD_htonll (uint64_t value);
183 
184 
189 MHD_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 
282 MHD_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 
365 MHD_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 
453 MHD_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 
479 MHD_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 
538 MHD_websocket_stream_init (struct MHD_WebSocketStream **ws,
539  int flags,
540  size_t max_payload_size)
541 {
542  return MHD_websocket_stream_init2 (ws,
543  flags,
544  max_payload_size,
545  malloc,
546  realloc,
547  free,
548  NULL,
549  NULL);
550 }
551 
552 
558 MHD_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 
612 MHD_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 
635 MHD_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 
652 MHD_websocket_stream_is_valid (struct MHD_WebSocketStream *ws)
653 {
654  /* validate parameters */
655  if (NULL == ws)
657 
658  return ws->validity;
659 }
660 
661 
666 MHD_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;
1073  ws->decode_step = MHD_WebSocket_DecodeStep_HeaderCompleted;
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;
1150  ws->decode_step = MHD_WebSocket_DecodeStep_HeaderCompleted;
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]);
1161  ws->decode_step = MHD_WebSocket_DecodeStep_HeaderCompleted;
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 */
1323  return MHD_WEBSOCKET_STATUS_OK;
1324 }
1325 
1326 
1327 static enum MHD_WEBSOCKET_STATUS
1328 MHD_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 
1426  return MHD_WEBSOCKET_STATUS_OK;
1427 }
1428 
1429 
1430 static enum MHD_WEBSOCKET_STATUS
1431 MHD_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;
1562  return MHD_WEBSOCKET_STATUS_OK;
1563  }
1564 }
1565 
1566 
1571 MHD_websocket_split_close_reason (const char *payload,
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)
1579  *reason_code = MHD_WEBSOCKET_CLOSEREASON_NO_REASON;
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)
1597  *reason_code = MHD_WEBSOCKET_CLOSEREASON_NO_REASON;
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 
1621  return MHD_WEBSOCKET_STATUS_OK;
1622 }
1623 
1624 
1629 MHD_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 
1696 MHD_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 
1739 static enum MHD_WEBSOCKET_STATUS
1740 MHD_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;
1772  *(result++) = MHD_WebSocket_Opcode_Continuation;
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 
1817  return MHD_WEBSOCKET_STATUS_OK;
1818 }
1819 
1820 
1825 MHD_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 */
1832  return MHD_websocket_encode_ping_pong (ws,
1833  payload,
1834  payload_len,
1835  frame,
1836  frame_len,
1838 }
1839 
1840 
1845 MHD_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 */
1852  return MHD_websocket_encode_ping_pong (ws,
1853  payload,
1854  payload_len,
1855  frame,
1856  frame_len,
1858 }
1859 
1860 
1864 static enum MHD_WEBSOCKET_STATUS
1865 MHD_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 
1930  return MHD_WEBSOCKET_STATUS_OK;
1931 }
1932 
1933 
1938 MHD_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 
2035  return MHD_WEBSOCKET_STATUS_OK;
2036 }
2037 
2038 
2042 static char
2043 MHD_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 
2053 static char
2054 MHD_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 
2068 static 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 
2099 static int
2100 MHD_websocket_check_utf8 (const char *buf,
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 
2313 static uint32_t
2314 MHD_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 *
2345 MHD_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 *
2361 MHD_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
2378 MHD_websocket_free (struct MHD_WebSocketStream *ws,
2379  void *buf)
2380 {
2381  if (NULL == ws)
2382  {
2384  }
2385 
2386  ws->free (buf);
2387 
2388  return MHD_WEBSOCKET_STATUS_OK;
2389 }
2390 
2391 
2396 static uint16_t
2397 MHD_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 
2420 static uint64_t
2421 MHD_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
Definition: reason_phrase.c:30
#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
Definition: mhd_websocket.c:78
MHD_WebSocket_DecodeStep
Definition: mhd_websocket.c:99
@ 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
Definition: mhd_websocket.c:83
_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 void * MHD_websocket_malloc(struct MHD_WebSocketStream *ws, size_t buf_len)
_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 enum MHD_WEBSOCKET_STATUS MHD_websocket_stream_invalidate(struct MHD_WebSocketStream *ws)
_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)
_MHD_EXTERN void * MHD_websocket_realloc(struct MHD_WebSocketStream *ws, void *buf, size_t new_buf_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
Definition: mhd_websocket.c:89
@ MHD_WebSocket_Opcode_Close
Definition: mhd_websocket.c:93
@ MHD_WebSocket_Opcode_Continuation
Definition: mhd_websocket.c:90
@ MHD_WebSocket_Opcode_Text
Definition: mhd_websocket.c:91
@ MHD_WebSocket_Opcode_Ping
Definition: mhd_websocket.c:94
@ MHD_WebSocket_Opcode_Binary
Definition: mhd_websocket.c:92
@ MHD_WebSocket_Opcode_Pong
Definition: mhd_websocket.c:95
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
Definition: microhttpd.h:3643
interface for experimental web socket extension to libmicrohttpd
void *(* MHD_WebSocketReallocCallback)(void *buf, size_t new_buf_len)
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
Definition: microhttpd_ws.h:66
@ MHD_WEBSOCKET_FLAG_WANT_FRAGMENTS
Definition: microhttpd_ws.h:99
@ MHD_WEBSOCKET_FLAG_CLIENT
Definition: microhttpd_ws.h:79
@ 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_WebSocketFreeCallback)(void *buf)
void *(* MHD_WebSocketMallocCallback)(size_t buf_len)
platform-specific includes for libmicrohttpd
Definition: sha1.h:72