1 /*
2   This file is part of libmicrohttpd
3   Copyright (C) 2021 David Gausmann
4 
5   This library is free software; you can redistribute it and/or
6   modify it under the terms of the GNU Lesser General Public
7   License as published by the Free Software Foundation; either
8   version 2.1 of the License, or (at your option) any later version.
9 
10   This library is distributed in the hope that it will be useful,
11   but WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13   Lesser General Public License for more details.
14 
15   You should have received a copy of the GNU Lesser General Public
16   License along with this library; if not, write to the Free Software
17   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
18 
19 */
20 
21 /**
22  * @file microhttpd_ws/mhd_websocket.c
23  * @brief  Support for the websocket protocol
24  * @author David Gausmann
25  */
26 #include "platform.h"
27 #include "microhttpd.h"
28 #include "microhttpd_ws.h"
29 #include "sha1.h"
30 
31 struct MHD_WebSocketStream
32 {
33   /* The function pointer to malloc for payload (can be used to use different memory management) */
34   MHD_WebSocketMallocCallback malloc;
35   /* The function pointer to realloc for payload (can be used to use different memory management) */
36   MHD_WebSocketReallocCallback realloc;
37   /* The function pointer to free for payload (can be used to use different memory management) */
38   MHD_WebSocketFreeCallback free;
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) */
42   MHD_WebSocketRandomNumberGenerator rng;
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 
88 enum MHD_WebSocket_Opcode
89 {
90   MHD_WebSocket_Opcode_Continuation = 0x0,
91   MHD_WebSocket_Opcode_Text         = 0x1,
92   MHD_WebSocket_Opcode_Binary       = 0x2,
93   MHD_WebSocket_Opcode_Close        = 0x8,
94   MHD_WebSocket_Opcode_Ping         = 0x9,
95   MHD_WebSocket_Opcode_Pong         = 0xA
96 };
97 
98 enum MHD_WebSocket_DecodeStep
99 {
100   MHD_WebSocket_DecodeStep_Start                 =  0,
101   MHD_WebSocket_DecodeStep_Length1ofX            =  1,
102   MHD_WebSocket_DecodeStep_Length1of2            =  2,
103   MHD_WebSocket_DecodeStep_Length2of2            =  3,
104   MHD_WebSocket_DecodeStep_Length1of8            =  4,
105   MHD_WebSocket_DecodeStep_Length2of8            =  5,
106   MHD_WebSocket_DecodeStep_Length3of8            =  6,
107   MHD_WebSocket_DecodeStep_Length4of8            =  7,
108   MHD_WebSocket_DecodeStep_Length5of8            =  8,
109   MHD_WebSocket_DecodeStep_Length6of8            =  9,
110   MHD_WebSocket_DecodeStep_Length7of8            = 10,
111   MHD_WebSocket_DecodeStep_Length8of8            = 11,
112   MHD_WebSocket_DecodeStep_Mask1Of4              = 12,
113   MHD_WebSocket_DecodeStep_Mask2Of4              = 13,
114   MHD_WebSocket_DecodeStep_Mask3Of4              = 14,
115   MHD_WebSocket_DecodeStep_Mask4Of4              = 15,
116   MHD_WebSocket_DecodeStep_HeaderCompleted       = 16,
117   MHD_WebSocket_DecodeStep_PayloadOfDataFrame    = 17,
118   MHD_WebSocket_DecodeStep_PayloadOfControlFrame = 18,
119   MHD_WebSocket_DecodeStep_BrokenStream          = 99
120 };
121 
122 enum MHD_WebSocket_UTF8Result
123 {
124   MHD_WebSocket_UTF8Result_Invalid    = 0,
125   MHD_WebSocket_UTF8Result_Valid      = 1,
126   MHD_WebSocket_UTF8Result_Incomplete = 2
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 
185 /**
186  * Checks whether the HTTP version is 1.1 or above.
187  */
188 _MHD_EXTERN enum MHD_WEBSOCKET_STATUS
MHD_websocket_check_http_version(const char * http_version)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 */
196     return MHD_WEBSOCKET_STATUS_NO_WEBSOCKET_HANDSHAKE_HEADER;
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   {
208     return MHD_WEBSOCKET_STATUS_NO_WEBSOCKET_HANDSHAKE_HEADER;
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     {
237       return MHD_WEBSOCKET_STATUS_NO_WEBSOCKET_HANDSHAKE_HEADER;
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     {
261       return MHD_WEBSOCKET_STATUS_NO_WEBSOCKET_HANDSHAKE_HEADER;
262     }
263   }
264   if ((NULL == major) || (NULL == dot) || (NULL == minor) || (NULL == end))
265   {
266     return MHD_WEBSOCKET_STATUS_NO_WEBSOCKET_HANDSHAKE_HEADER;
267   }
268   if ((2 <= dot - major) || ('2' <= *major) ||
269       (('1' == *major) && ((2 <= end - minor) || ('1' <= *minor))) )
270   {
271     return MHD_WEBSOCKET_STATUS_OK;
272   }
273 
274   return MHD_WEBSOCKET_STATUS_NO_WEBSOCKET_HANDSHAKE_HEADER;
275 }
276 
277 
278 /**
279  * Checks whether the "Connection" request header has the 'Upgrade' token.
280  */
281 _MHD_EXTERN enum MHD_WEBSOCKET_STATUS
MHD_websocket_check_connection_header(const char * connection_header)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 */
290     return MHD_WEBSOCKET_STATUS_NO_WEBSOCKET_HANDSHAKE_HEADER;
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" */
340             return MHD_WEBSOCKET_STATUS_OK;
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 */
354       return MHD_WEBSOCKET_STATUS_NO_WEBSOCKET_HANDSHAKE_HEADER;
355     }
356   }
357   return MHD_WEBSOCKET_STATUS_NO_WEBSOCKET_HANDSHAKE_HEADER;
358 }
359 
360 
361 /**
362  * Checks whether the "Upgrade" request header has the "websocket" keyword.
363  */
364 _MHD_EXTERN enum MHD_WEBSOCKET_STATUS
MHD_websocket_check_upgrade_header(const char * upgrade_header)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 */
373     return MHD_WEBSOCKET_STATUS_NO_WEBSOCKET_HANDSHAKE_HEADER;
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" */
427             return MHD_WEBSOCKET_STATUS_OK;
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 */
441       return MHD_WEBSOCKET_STATUS_NO_WEBSOCKET_HANDSHAKE_HEADER;
442     }
443   }
444   return MHD_WEBSOCKET_STATUS_NO_WEBSOCKET_HANDSHAKE_HEADER;
445 }
446 
447 
448 /**
449  * Checks whether the "Sec-WebSocket-Version" request header
450  * equals to "13"
451  */
452 _MHD_EXTERN enum MHD_WEBSOCKET_STATUS
MHD_websocket_check_version_header(const char * version_header)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 */
461     return MHD_WEBSOCKET_STATUS_NO_WEBSOCKET_HANDSHAKE_HEADER;
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" */
469     return MHD_WEBSOCKET_STATUS_OK;
470   }
471   return MHD_WEBSOCKET_STATUS_NO_WEBSOCKET_HANDSHAKE_HEADER;
472 }
473 
474 
475 /**
476  * Creates the response for the Sec-WebSocket-Accept header
477  */
478 _MHD_EXTERN enum MHD_WEBSOCKET_STATUS
MHD_websocket_create_accept_header(const char * sec_websocket_key,char * sec_websocket_accept)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   {
489     return MHD_WEBSOCKET_STATUS_PARAMETER_ERROR;
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 */
496     return MHD_WEBSOCKET_STATUS_NO_WEBSOCKET_HANDSHAKE_HEADER;
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 
530   return MHD_WEBSOCKET_STATUS_OK;
531 }
532 
533 
534 /**
535  * Initializes a new websocket stream
536  */
537 _MHD_EXTERN enum MHD_WEBSOCKET_STATUS
MHD_websocket_stream_init(struct MHD_WebSocketStream ** ws,int flags,size_t max_payload_size)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 
553 /**
554  * Initializes a new websocket stream with
555  * additional parameters for allocation functions
556  */
557 _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)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,
565                             MHD_WebSocketRandomNumberGenerator callback_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   {
581     return MHD_WEBSOCKET_STATUS_PARAMETER_ERROR;
582   }
583 
584   /* allocate stream */
585   struct MHD_WebSocketStream *ws_ = (struct MHD_WebSocketStream *) malloc (
586     sizeof (struct MHD_WebSocketStream));
587   if (NULL == ws_)
588     return MHD_WEBSOCKET_STATUS_MEMORY_ERROR;
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 
604   return MHD_WEBSOCKET_STATUS_OK;
605 }
606 
607 
608 /**
609  * Frees a previously allocated websocket stream
610  */
611 _MHD_EXTERN enum MHD_WEBSOCKET_STATUS
MHD_websocket_stream_free(struct MHD_WebSocketStream * ws)612 MHD_websocket_stream_free (struct MHD_WebSocketStream *ws)
613 {
614   /* validate parameters */
615   if (NULL == ws)
616     return MHD_WEBSOCKET_STATUS_PARAMETER_ERROR;
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 
627   return MHD_WEBSOCKET_STATUS_OK;
628 }
629 
630 
631 /**
632  * Invalidates a websocket stream (no more decoding possible)
633  */
634 _MHD_EXTERN enum MHD_WEBSOCKET_STATUS
MHD_websocket_stream_invalidate(struct MHD_WebSocketStream * ws)635 MHD_websocket_stream_invalidate (struct MHD_WebSocketStream *ws)
636 {
637   /* validate parameters */
638   if (NULL == ws)
639     return MHD_WEBSOCKET_STATUS_PARAMETER_ERROR;
640 
641   /* invalidate stream */
642   ws->validity = MHD_WEBSOCKET_VALIDITY_INVALID;
643 
644   return MHD_WEBSOCKET_STATUS_OK;
645 }
646 
647 
648 /**
649  * Returns whether a websocket stream is valid
650  */
651 _MHD_EXTERN enum MHD_WEBSOCKET_VALIDITY
MHD_websocket_stream_is_valid(struct MHD_WebSocketStream * ws)652 MHD_websocket_stream_is_valid (struct MHD_WebSocketStream *ws)
653 {
654   /* validate parameters */
655   if (NULL == ws)
656     return MHD_WEBSOCKET_VALIDITY_INVALID;
657 
658   return ws->validity;
659 }
660 
661 
662 /**
663  * Decodes incoming data to a websocket frame
664  */
665 _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)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   {
688     return MHD_WEBSOCKET_STATUS_PARAMETER_ERROR;
689   }
690 
691   /* validate stream validity */
692   if (MHD_WEBSOCKET_VALIDITY_INVALID == ws->validity)
693     return MHD_WEBSOCKET_STATUS_STREAM_BROKEN;
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 */
702     case MHD_WebSocket_DecodeStep_Start:
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
714                       & MHD_WEBSOCKET_FLAG_GENERATE_CLOSE_FRAMES_ON_ERROR))
715             {
716               MHD_websocket_encode_close (ws,
717                                           MHD_WEBSOCKET_CLOSEREASON_PROTOCOL_ERROR,
718                                           0,
719                                           0,
720                                           payload,
721                                           payload_len);
722             }
723             *streambuf_read_len = current;
724             return MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR;
725           }
726           switch (opcode & 0x0F)
727           {
728           case MHD_WebSocket_Opcode_Continuation:
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
734                         & MHD_WEBSOCKET_FLAG_GENERATE_CLOSE_FRAMES_ON_ERROR))
735               {
736                 MHD_websocket_encode_close (ws,
737                                             MHD_WEBSOCKET_CLOSEREASON_PROTOCOL_ERROR,
738                                             0,
739                                             0,
740                                             payload,
741                                             payload_len);
742               }
743               *streambuf_read_len = current;
744               return MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR;
745             }
746             if (MHD_WEBSOCKET_VALIDITY_ONLY_VALID_FOR_CONTROL_FRAMES ==
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
754                         & MHD_WEBSOCKET_FLAG_GENERATE_CLOSE_FRAMES_ON_ERROR))
755               {
756                 MHD_websocket_encode_close (ws,
757                                             MHD_WEBSOCKET_CLOSEREASON_PROTOCOL_ERROR,
758                                             0,
759                                             0,
760                                             payload,
761                                             payload_len);
762               }
763               *streambuf_read_len = current;
764               return MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR;
765             }
766             break;
767 
768           case MHD_WebSocket_Opcode_Text:
769           case MHD_WebSocket_Opcode_Binary:
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
775                         & MHD_WEBSOCKET_FLAG_GENERATE_CLOSE_FRAMES_ON_ERROR))
776               {
777                 MHD_websocket_encode_close (ws,
778                                             MHD_WEBSOCKET_CLOSEREASON_PROTOCOL_ERROR,
779                                             0,
780                                             0,
781                                             payload,
782                                             payload_len);
783               }
784               *streambuf_read_len = current;
785               return MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR;
786             }
787             if (MHD_WEBSOCKET_VALIDITY_ONLY_VALID_FOR_CONTROL_FRAMES ==
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
795                         & MHD_WEBSOCKET_FLAG_GENERATE_CLOSE_FRAMES_ON_ERROR))
796               {
797                 MHD_websocket_encode_close (ws,
798                                             MHD_WEBSOCKET_CLOSEREASON_PROTOCOL_ERROR,
799                                             0,
800                                             0,
801                                             payload,
802                                             payload_len);
803               }
804               *streambuf_read_len = current;
805               return MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR;
806             }
807             break;
808 
809           case MHD_WebSocket_Opcode_Close:
810           case MHD_WebSocket_Opcode_Ping:
811           case MHD_WebSocket_Opcode_Pong:
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
817                         & MHD_WEBSOCKET_FLAG_GENERATE_CLOSE_FRAMES_ON_ERROR))
818               {
819                 MHD_websocket_encode_close (ws,
820                                             MHD_WEBSOCKET_CLOSEREASON_PROTOCOL_ERROR,
821                                             0,
822                                             0,
823                                             payload,
824                                             payload_len);
825               }
826               *streambuf_read_len = current;
827               return MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR;
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 =
835                 MHD_WEBSOCKET_VALIDITY_ONLY_VALID_FOR_CONTROL_FRAMES;
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
844                       & MHD_WEBSOCKET_FLAG_GENERATE_CLOSE_FRAMES_ON_ERROR))
845             {
846               MHD_websocket_encode_close (ws,
847                                           MHD_WEBSOCKET_CLOSEREASON_PROTOCOL_ERROR,
848                                           0,
849                                           0,
850                                           payload,
851                                           payload_len);
852             }
853             *streambuf_read_len = current;
854             return MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR;
855           }
856         }
857         ws->frame_header [ws->frame_header_size++] = streambuf [current++];
858         ws->decode_step = MHD_WebSocket_DecodeStep_Length1ofX;
859       }
860       break;
861 
862     case MHD_WebSocket_DecodeStep_Length1ofX:
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
874                                               & MHD_WEBSOCKET_FLAG_CLIENT))
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
879                         & MHD_WEBSOCKET_FLAG_GENERATE_CLOSE_FRAMES_ON_ERROR))
880               {
881                 MHD_websocket_encode_close (ws,
882                                             MHD_WEBSOCKET_CLOSEREASON_PROTOCOL_ERROR,
883                                             0,
884                                             0,
885                                             payload,
886                                             payload_len);
887               }
888               *streambuf_read_len = current;
889               return MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR;
890             }
891           }
892           else
893           {
894             if (MHD_WEBSOCKET_FLAG_SERVER == (ws->flags
895                                               & MHD_WEBSOCKET_FLAG_CLIENT))
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
900                         & MHD_WEBSOCKET_FLAG_GENERATE_CLOSE_FRAMES_ON_ERROR))
901               {
902                 MHD_websocket_encode_close (ws,
903                                             MHD_WEBSOCKET_CLOSEREASON_PROTOCOL_ERROR,
904                                             0,
905                                             0,
906                                             payload,
907                                             payload_len);
908               }
909               *streambuf_read_len = current;
910               return MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR;
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
920                         & MHD_WEBSOCKET_FLAG_GENERATE_CLOSE_FRAMES_ON_ERROR))
921               {
922                 MHD_websocket_encode_close (ws,
923                                             MHD_WEBSOCKET_CLOSEREASON_PROTOCOL_ERROR,
924                                             0,
925                                             0,
926                                             payload,
927                                             payload_len);
928               }
929               *streambuf_read_len = current;
930               return MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR;
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
941                         & MHD_WEBSOCKET_FLAG_GENERATE_CLOSE_FRAMES_ON_ERROR))
942               {
943                 MHD_websocket_encode_close (ws,
944                                             MHD_WEBSOCKET_CLOSEREASON_PROTOCOL_ERROR,
945                                             0,
946                                             0,
947                                             payload,
948                                             payload_len);
949               }
950               *streambuf_read_len = current;
951               return MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR;
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
974                       & MHD_WEBSOCKET_FLAG_GENERATE_CLOSE_FRAMES_ON_ERROR))
975             {
976               MHD_websocket_encode_close (ws,
977                                           MHD_WEBSOCKET_CLOSEREASON_MAXIMUM_ALLOWED_PAYLOAD_SIZE_EXCEEDED,
978                                           0,
979                                           0,
980                                           payload,
981                                           payload_len);
982             }
983             *streambuf_read_len = current;
984             return MHD_WEBSOCKET_STATUS_MAXIMUM_SIZE_EXCEEDED;
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;
996             ws->decode_step = MHD_WebSocket_DecodeStep_HeaderCompleted;
997           }
998         }
999       }
1000       break;
1001 
1002     /* Payload size first byte of 2 bytes */
1003     case MHD_WebSocket_DecodeStep_Length1of2:
1004     /* Payload size first 7 bytes of 8 bytes */
1005     case MHD_WebSocket_DecodeStep_Length1of8:
1006     case MHD_WebSocket_DecodeStep_Length2of8:
1007     case MHD_WebSocket_DecodeStep_Length3of8:
1008     case MHD_WebSocket_DecodeStep_Length4of8:
1009     case MHD_WebSocket_DecodeStep_Length5of8:
1010     case MHD_WebSocket_DecodeStep_Length6of8:
1011     case MHD_WebSocket_DecodeStep_Length7of8:
1012     /* Mask first 3 bytes of 4 bytes */
1013     case MHD_WebSocket_DecodeStep_Mask1Of4:
1014     case MHD_WebSocket_DecodeStep_Mask2Of4:
1015     case MHD_WebSocket_DecodeStep_Mask3Of4:
1016       ws->frame_header [ws->frame_header_size++] = streambuf [current++];
1017       ++ws->decode_step;
1018       break;
1019 
1020     /* 2 byte length finished */
1021     case MHD_WebSocket_DecodeStep_Length2of2:
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
1032                     & MHD_WEBSOCKET_FLAG_GENERATE_CLOSE_FRAMES_ON_ERROR))
1033           {
1034             MHD_websocket_encode_close (ws,
1035                                         MHD_WEBSOCKET_CLOSEREASON_PROTOCOL_ERROR,
1036                                         0,
1037                                         0,
1038                                         payload,
1039                                         payload_len);
1040           }
1041           *streambuf_read_len = current;
1042           return MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR;
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
1051                     & MHD_WEBSOCKET_FLAG_GENERATE_CLOSE_FRAMES_ON_ERROR))
1052           {
1053             MHD_websocket_encode_close (ws,
1054                                         MHD_WEBSOCKET_CLOSEREASON_MAXIMUM_ALLOWED_PAYLOAD_SIZE_EXCEEDED,
1055                                         0,
1056                                         0,
1057                                         payload,
1058                                         payload_len);
1059           }
1060           *streambuf_read_len = current;
1061           return MHD_WEBSOCKET_STATUS_MAXIMUM_SIZE_EXCEEDED;
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 */
1079     case MHD_WebSocket_DecodeStep_Length8of8:
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
1090                     & MHD_WEBSOCKET_FLAG_GENERATE_CLOSE_FRAMES_ON_ERROR))
1091           {
1092             MHD_websocket_encode_close (ws,
1093                                         MHD_WEBSOCKET_CLOSEREASON_PROTOCOL_ERROR,
1094                                         0,
1095                                         0,
1096                                         payload,
1097                                         payload_len);
1098           }
1099           *streambuf_read_len = current;
1100           return MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR;
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
1108                     & MHD_WEBSOCKET_FLAG_GENERATE_CLOSE_FRAMES_ON_ERROR))
1109           {
1110             MHD_websocket_encode_close (ws,
1111                                         MHD_WEBSOCKET_CLOSEREASON_PROTOCOL_ERROR,
1112                                         0,
1113                                         0,
1114                                         payload,
1115                                         payload_len);
1116           }
1117           *streambuf_read_len = current;
1118           return MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR;
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
1127                     & MHD_WEBSOCKET_FLAG_GENERATE_CLOSE_FRAMES_ON_ERROR))
1128           {
1129             MHD_websocket_encode_close (ws,
1130                                         MHD_WEBSOCKET_CLOSEREASON_MAXIMUM_ALLOWED_PAYLOAD_SIZE_EXCEEDED,
1131                                         0,
1132                                         0,
1133                                         payload,
1134                                         payload_len);
1135           }
1136           *streambuf_read_len = current;
1137           return MHD_WEBSOCKET_STATUS_MAXIMUM_SIZE_EXCEEDED;
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 */
1156     case MHD_WebSocket_DecodeStep_Mask4Of4:
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 */
1165     case MHD_WebSocket_DecodeStep_HeaderCompleted:
1166       /* return or assign either to data or control */
1167       {
1168         int ret = MHD_websocket_decode_header_complete (ws,
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 */
1180     case MHD_WebSocket_DecodeStep_PayloadOfDataFrame:
1181     case MHD_WebSocket_DecodeStep_PayloadOfControlFrame:
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 ==
1191                                  MHD_WebSocket_DecodeStep_PayloadOfDataFrame ?
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;
1204           if (((MHD_WebSocket_DecodeStep_PayloadOfDataFrame ==
1205                 ws->decode_step) &&
1206                (MHD_WebSocket_Opcode_Text == ws->data_type)) ||
1207               ((MHD_WebSocket_DecodeStep_PayloadOfControlFrame ==
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
1253                         & MHD_WEBSOCKET_FLAG_GENERATE_CLOSE_FRAMES_ON_ERROR))
1254               {
1255                 MHD_websocket_encode_close (ws,
1256                                             MHD_WEBSOCKET_CLOSEREASON_MALFORMED_UTF8,
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;
1264               return MHD_WEBSOCKET_STATUS_UTF8_ENCODING_ERROR;
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 */
1273         int ret = MHD_websocket_decode_payload_complete (ws,
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 
1284     case MHD_WebSocket_DecodeStep_BrokenStream:
1285       *streambuf_read_len = current;
1286       return MHD_WEBSOCKET_STATUS_STREAM_BROKEN;
1287     }
1288   }
1289 
1290   /* Special treatment for zero payload length messages */
1291   if (MHD_WebSocket_DecodeStep_HeaderCompleted == ws->decode_step)
1292   {
1293     int ret = MHD_websocket_decode_header_complete (ws,
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   {
1304   case MHD_WebSocket_DecodeStep_PayloadOfDataFrame:
1305   case MHD_WebSocket_DecodeStep_PayloadOfControlFrame:
1306     if (ws->payload_size == ws->payload_index)
1307     {
1308       /* all payload data of the current frame has been received */
1309       int ret = MHD_websocket_decode_payload_complete (ws,
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
MHD_websocket_decode_header_complete(struct MHD_WebSocketStream * ws,char ** payload,size_t * payload_len)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   {
1336   case MHD_WebSocket_Opcode_Continuation:
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
1348                   & MHD_WEBSOCKET_FLAG_GENERATE_CLOSE_FRAMES_ON_ERROR))
1349         {
1350           MHD_websocket_encode_close (ws,
1351                                       MHD_WEBSOCKET_CLOSEREASON_MAXIMUM_ALLOWED_PAYLOAD_SIZE_EXCEEDED,
1352                                       0,
1353                                       0,
1354                                       payload,
1355                                       payload_len);
1356         }
1357         return MHD_WEBSOCKET_STATUS_MAXIMUM_SIZE_EXCEEDED;
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         {
1366           return MHD_WEBSOCKET_STATUS_MEMORY_ERROR;
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     }
1378     ws->decode_step = MHD_WebSocket_DecodeStep_PayloadOfDataFrame;
1379     break;
1380 
1381   case MHD_WebSocket_Opcode_Text:
1382   case MHD_WebSocket_Opcode_Binary:
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         {
1392           return MHD_WEBSOCKET_STATUS_MEMORY_ERROR;
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     }
1401     ws->decode_step = MHD_WebSocket_DecodeStep_PayloadOfDataFrame;
1402     break;
1403 
1404   case MHD_WebSocket_Opcode_Close:
1405   case MHD_WebSocket_Opcode_Ping:
1406   case MHD_WebSocket_Opcode_Pong:
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         {
1416           return MHD_WEBSOCKET_STATUS_MEMORY_ERROR;
1417         }
1418         new_buf[new_size_total] = 0;
1419       }
1420       ws->control_payload = new_buf;
1421     }
1422     ws->decode_step = MHD_WebSocket_DecodeStep_PayloadOfControlFrame;
1423     break;
1424   }
1425 
1426   return MHD_WEBSOCKET_STATUS_OK;
1427 }
1428 
1429 
1430 static enum MHD_WEBSOCKET_STATUS
MHD_websocket_decode_payload_complete(struct MHD_WebSocketStream * ws,char ** payload,size_t * payload_len)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 */
1487       case MHD_WEBSOCKET_UTF8STEP_UTF2TAIL_1OF1:
1488       case MHD_WEBSOCKET_UTF8STEP_UTF3TAIL1_1OF2:
1489       case MHD_WEBSOCKET_UTF8STEP_UTF3TAIL2_1OF2:
1490       case MHD_WEBSOCKET_UTF8STEP_UTF3TAIL_1OF2:
1491       case MHD_WEBSOCKET_UTF8STEP_UTF4TAIL1_1OF3:
1492       case MHD_WEBSOCKET_UTF8STEP_UTF4TAIL2_1OF3:
1493       case MHD_WEBSOCKET_UTF8STEP_UTF4TAIL_1OF3:
1494         given_utf8 = 1;
1495         break;
1496       /* two bytes given */
1497       case MHD_WEBSOCKET_UTF8STEP_UTF3TAIL_2OF2:
1498       case MHD_WEBSOCKET_UTF8STEP_UTF4TAIL_2OF3:
1499         given_utf8 = 2;
1500         break;
1501       /* three bytes given */
1502       case MHD_WEBSOCKET_UTF8STEP_UTF4TAIL_3OF3:
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         {
1512           return MHD_WEBSOCKET_STATUS_MEMORY_ERROR;
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 
1567 /**
1568  * Splits the received close reason
1569  */
1570 _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)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))
1587     return MHD_WEBSOCKET_STATUS_PARAMETER_ERROR;
1588   if (1 == payload_len)
1589     return MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR;
1590   if (125 < payload_len)
1591     return MHD_WEBSOCKET_STATUS_MAXIMUM_SIZE_EXCEEDED;
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 
1625 /**
1626  * Encodes a text into a websocket text frame
1627  */
1628 _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)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   {
1660     return MHD_WEBSOCKET_STATUS_PARAMETER_ERROR;
1661   }
1662 
1663   /* check max length */
1664   if ((uint64_t) 0x7FFFFFFFFFFFFFFF < (uint64_t) payload_utf8_len)
1665   {
1666     return MHD_WEBSOCKET_STATUS_MAXIMUM_SIZE_EXCEEDED;
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   {
1678     return MHD_WEBSOCKET_STATUS_UTF8_ENCODING_ERROR;
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,
1688                                     MHD_WebSocket_Opcode_Text);
1689 }
1690 
1691 
1692 /**
1693  * Encodes binary data into a websocket binary frame
1694  */
1695 _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)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   {
1717     return MHD_WEBSOCKET_STATUS_PARAMETER_ERROR;
1718   }
1719 
1720   /* check max length */
1721   if ((uint64_t) 0x7FFFFFFFFFFFFFFF < (uint64_t) payload_len)
1722   {
1723     return MHD_WEBSOCKET_STATUS_MAXIMUM_SIZE_EXCEEDED;
1724   }
1725 
1726   return MHD_websocket_encode_data (ws,
1727                                     payload,
1728                                     payload_len,
1729                                     fragmentation,
1730                                     frame,
1731                                     frame_len,
1732                                     MHD_WebSocket_Opcode_Binary);
1733 }
1734 
1735 
1736 /**
1737  * Internal function for encoding text/binary data into a websocket frame
1738  */
1739 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)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)
1757     return MHD_WEBSOCKET_STATUS_MEMORY_ERROR;
1758   result [total_len] = 0;
1759   *frame     = result;
1760   *frame_len = total_len;
1761 
1762   /* add the opcode */
1763   switch (fragmentation)
1764   {
1765   case MHD_WEBSOCKET_FRAGMENTATION_NONE:
1766     *(result++) = 0x80 | opcode;
1767     break;
1768   case MHD_WEBSOCKET_FRAGMENTATION_FIRST:
1769     *(result++) = opcode;
1770     break;
1771   case MHD_WEBSOCKET_FRAGMENTATION_FOLLOWING:
1772     *(result++) = MHD_WebSocket_Opcode_Continuation;
1773     break;
1774   case MHD_WEBSOCKET_FRAGMENTATION_LAST:
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   {
1810     MHD_websocket_copy_payload (result,
1811                                 payload,
1812                                 payload_len,
1813                                 mask,
1814                                 0);
1815   }
1816 
1817   return MHD_WEBSOCKET_STATUS_OK;
1818 }
1819 
1820 
1821 /**
1822  * Encodes a websocket ping frame
1823  */
1824 _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)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,
1837                                          MHD_WebSocket_Opcode_Ping);
1838 }
1839 
1840 
1841 /**
1842  * Encodes a websocket pong frame
1843  */
1844 _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)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,
1857                                          MHD_WebSocket_Opcode_Pong);
1858 }
1859 
1860 
1861 /**
1862  * Internal function for encoding ping/pong frames
1863  */
1864 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)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   {
1884     return MHD_WEBSOCKET_STATUS_PARAMETER_ERROR;
1885   }
1886 
1887   /* RFC 6455 5.5: Control frames may only have up to 125 bytes of payload data */
1888   if (125 < payload_len)
1889     return MHD_WEBSOCKET_STATUS_MAXIMUM_SIZE_EXCEEDED;
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)
1900     return MHD_WEBSOCKET_STATUS_MEMORY_ERROR;
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   {
1923     MHD_websocket_copy_payload (result,
1924                                 payload,
1925                                 payload_len,
1926                                 mask,
1927                                 0);
1928   }
1929 
1930   return MHD_WEBSOCKET_STATUS_OK;
1931 }
1932 
1933 
1934 /**
1935  * Encodes a websocket close frame
1936  */
1937 _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)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   {
1961     return MHD_WEBSOCKET_STATUS_PARAMETER_ERROR;
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)
1968     return MHD_WEBSOCKET_STATUS_MAXIMUM_SIZE_EXCEEDED;
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)
1978       return MHD_WEBSOCKET_STATUS_UTF8_ENCODING_ERROR;
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)
1992     return MHD_WEBSOCKET_STATUS_MEMORY_ERROR;
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);
2017     MHD_websocket_copy_payload (result,
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     {
2027       MHD_websocket_copy_payload (result,
2028                                   reason_utf8,
2029                                   reason_utf8_len,
2030                                   mask,
2031                                   2);
2032     }
2033   }
2034 
2035   return MHD_WEBSOCKET_STATUS_OK;
2036 }
2037 
2038 
2039 /**
2040  * Returns the 0x80 prefix for masked data, 0x00 otherwise
2041  */
2042 static char
MHD_websocket_encode_is_masked(struct MHD_WebSocketStream * ws)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 
2050 /**
2051  * Calculates the size of the overhead in bytes
2052  */
2053 static char
MHD_websocket_encode_overhead_size(struct MHD_WebSocketStream * ws,size_t payload_len)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 
2065 /**
2066  * Copies the payload to the destination (using mask)
2067  */
2068 static void
MHD_websocket_copy_payload(char * dst,const char * src,size_t len,uint32_t mask,unsigned long mask_offset)2069 MHD_websocket_copy_payload (char *dst,
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 
2096 /**
2097  * Checks a UTF-8 sequence
2098  */
2099 static int
MHD_websocket_check_utf8(const char * buf,size_t buf_len,int * utf8_step,size_t * buf_offset)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 :
2106                    MHD_WEBSOCKET_UTF8STEP_NORMAL;
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     {
2113     case MHD_WEBSOCKET_UTF8STEP_NORMAL:
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 */
2122         utf8_step_ = MHD_WEBSOCKET_UTF8STEP_UTF2TAIL_1OF1;
2123       }
2124       else if (0xE0 == character)
2125       {
2126         /* RFC 3629 4: three byte UTF-8 sequence, but the second byte must be 0xA0-0xBF */
2127         utf8_step_ = MHD_WEBSOCKET_UTF8STEP_UTF3TAIL1_1OF2;
2128       }
2129       else if (0xED == character)
2130       {
2131         /* RFC 3629 4: three byte UTF-8 sequence, but the second byte must be 0x80-0x9F */
2132         utf8_step_ = MHD_WEBSOCKET_UTF8STEP_UTF3TAIL2_1OF2;
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 */
2138         utf8_step_ = MHD_WEBSOCKET_UTF8STEP_UTF3TAIL_1OF2;
2139       }
2140       else if (0xF0 == character)
2141       {
2142         /* RFC 3629 4: four byte UTF-8 sequence, but the second byte must be 0x90-0xBF */
2143         utf8_step_ = MHD_WEBSOCKET_UTF8STEP_UTF4TAIL1_1OF3;
2144       }
2145       else if (0xF4 == character)
2146       {
2147         /* RFC 3629 4: four byte UTF-8 sequence, but the second byte must be 0x80-0x8F */
2148         utf8_step_ = MHD_WEBSOCKET_UTF8STEP_UTF4TAIL2_1OF3;
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 */
2153         utf8_step_ = MHD_WEBSOCKET_UTF8STEP_UTF4TAIL_1OF3;
2154       }
2155       else
2156       {
2157         /* RFC 3629 4: Invalid UTF-8 byte */
2158         if (NULL != buf_offset)
2159           *buf_offset = i;
2160         return MHD_WebSocket_UTF8Result_Invalid;
2161       }
2162       break;
2163 
2164     case MHD_WEBSOCKET_UTF8STEP_UTF3TAIL1_1OF2:
2165       if ((0xA0 <= character) && (0xBF >= character))
2166       {
2167         /* RFC 3629 4: Second byte of three byte UTF-8 sequence */
2168         utf8_step_ = MHD_WEBSOCKET_UTF8STEP_UTF3TAIL_2OF2;
2169       }
2170       else
2171       {
2172         /* RFC 3629 4: Invalid UTF-8 byte */
2173         if (NULL != buf_offset)
2174           *buf_offset = i;
2175         return MHD_WebSocket_UTF8Result_Invalid;
2176       }
2177       break;
2178 
2179     case MHD_WEBSOCKET_UTF8STEP_UTF3TAIL2_1OF2:
2180       if ((0x80 <= character) && (0x9F >= character))
2181       {
2182         /* RFC 3629 4: Second byte of three byte UTF-8 sequence */
2183         utf8_step_ = MHD_WEBSOCKET_UTF8STEP_UTF3TAIL_2OF2;
2184       }
2185       else
2186       {
2187         /* RFC 3629 4: Invalid UTF-8 byte */
2188         if (NULL != buf_offset)
2189           *buf_offset = i;
2190         return MHD_WebSocket_UTF8Result_Invalid;
2191       }
2192       break;
2193 
2194     case MHD_WEBSOCKET_UTF8STEP_UTF3TAIL_1OF2:
2195       if ((0x80 <= character) && (0xBF >= character))
2196       {
2197         /* RFC 3629 4: Second byte of three byte UTF-8 sequence */
2198         utf8_step_ = MHD_WEBSOCKET_UTF8STEP_UTF3TAIL_2OF2;
2199       }
2200       else
2201       {
2202         /* RFC 3629 4: Invalid UTF-8 byte */
2203         if (NULL != buf_offset)
2204           *buf_offset = i;
2205         return MHD_WebSocket_UTF8Result_Invalid;
2206       }
2207       break;
2208 
2209     case MHD_WEBSOCKET_UTF8STEP_UTF4TAIL1_1OF3:
2210       if ((0x90 <= character) && (0xBF >= character))
2211       {
2212         /* RFC 3629 4: Second byte of four byte UTF-8 sequence */
2213         utf8_step_ = MHD_WEBSOCKET_UTF8STEP_UTF4TAIL_2OF3;
2214       }
2215       else
2216       {
2217         /* RFC 3629 4: Invalid UTF-8 byte */
2218         if (NULL != buf_offset)
2219           *buf_offset = i;
2220         return MHD_WebSocket_UTF8Result_Invalid;
2221       }
2222       break;
2223 
2224     case MHD_WEBSOCKET_UTF8STEP_UTF4TAIL2_1OF3:
2225       if ((0x80 <= character) && (0x8F >= character))
2226       {
2227         /* RFC 3629 4: Second byte of four byte UTF-8 sequence */
2228         utf8_step_ = MHD_WEBSOCKET_UTF8STEP_UTF4TAIL_2OF3;
2229       }
2230       else
2231       {
2232         /* RFC 3629 4: Invalid UTF-8 byte */
2233         if (NULL != buf_offset)
2234           *buf_offset = i;
2235         return MHD_WebSocket_UTF8Result_Invalid;
2236       }
2237       break;
2238 
2239     case MHD_WEBSOCKET_UTF8STEP_UTF4TAIL_1OF3:
2240       if ((0x80 <= character) && (0xBF >= character))
2241       {
2242         /* RFC 3629 4: Second byte of four byte UTF-8 sequence */
2243         utf8_step_ = MHD_WEBSOCKET_UTF8STEP_UTF4TAIL_2OF3;
2244       }
2245       else
2246       {
2247         /* RFC 3629 4: Invalid UTF-8 byte */
2248         if (NULL != buf_offset)
2249           *buf_offset = i;
2250         return MHD_WebSocket_UTF8Result_Invalid;
2251       }
2252       break;
2253 
2254     case MHD_WEBSOCKET_UTF8STEP_UTF4TAIL_2OF3:
2255       if ((0x80 <= character) && (0xBF >= character))
2256       {
2257         /* RFC 3629 4: Third byte of four byte UTF-8 sequence */
2258         utf8_step_ = MHD_WEBSOCKET_UTF8STEP_UTF4TAIL_3OF3;
2259       }
2260       else
2261       {
2262         /* RFC 3629 4: Invalid UTF-8 byte */
2263         if (NULL != buf_offset)
2264           *buf_offset = i;
2265         return MHD_WebSocket_UTF8Result_Invalid;
2266       }
2267       break;
2268 
2269     /* RFC 3629 4: Second byte of two byte UTF-8 sequence */
2270     case MHD_WEBSOCKET_UTF8STEP_UTF2TAIL_1OF1:
2271     /* RFC 3629 4: Third byte of three byte UTF-8 sequence */
2272     case MHD_WEBSOCKET_UTF8STEP_UTF3TAIL_2OF2:
2273     /* RFC 3629 4: Fourth byte of four byte UTF-8 sequence */
2274     case MHD_WEBSOCKET_UTF8STEP_UTF4TAIL_3OF3:
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;
2284         return MHD_WebSocket_UTF8Result_Invalid;
2285       }
2286       break;
2287 
2288     default:
2289       /* Invalid last step...? */
2290       if (NULL != buf_offset)
2291         *buf_offset = i;
2292       return MHD_WebSocket_UTF8Result_Invalid;
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   {
2303     return MHD_WebSocket_UTF8Result_Incomplete;
2304   }
2305   return MHD_WebSocket_UTF8Result_Valid;
2306 }
2307 
2308 
2309 /**
2310  * Generates a mask for masking by calling
2311  * a random number generator.
2312  */
2313 static uint32_t
MHD_websocket_generate_mask(struct MHD_WebSocketStream * ws)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 
2341 /**
2342  * Calls the malloc function associated with the websocket steam
2343  */
2344 _MHD_EXTERN void *
MHD_websocket_malloc(struct MHD_WebSocketStream * ws,size_t buf_len)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 
2357 /**
2358  * Calls the realloc function associated with the websocket steam
2359  */
2360 _MHD_EXTERN void *
MHD_websocket_realloc(struct MHD_WebSocketStream * ws,void * buf,size_t new_buf_len)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 
2374 /**
2375  * Calls the free function associated with the websocket steam
2376  */
2377 _MHD_EXTERN int
MHD_websocket_free(struct MHD_WebSocketStream * ws,void * buf)2378 MHD_websocket_free (struct MHD_WebSocketStream *ws,
2379                     void *buf)
2380 {
2381   if (NULL == ws)
2382   {
2383     return MHD_WEBSOCKET_STATUS_PARAMETER_ERROR;
2384   }
2385 
2386   ws->free (buf);
2387 
2388   return MHD_WEBSOCKET_STATUS_OK;
2389 }
2390 
2391 
2392 /**
2393  * Converts a 16 bit value into network byte order (MSB first)
2394  * in dependence of the host system
2395  */
2396 static uint16_t
MHD_htons(uint16_t value)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 
2416 /**
2417  * Converts a 64 bit value into network byte order (MSB first)
2418  * in dependence of the host system
2419  */
2420 static uint64_t
MHD_htonll(uint64_t value)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 }
2444