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