aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--ChangeLog3
-rw-r--r--configure.ac5
-rw-r--r--src/Makefile.am4
-rw-r--r--src/include/Makefile.am6
-rw-r--r--src/include/microhttpd_ws.h979
-rw-r--r--src/microhttpd/Makefile.am4
-rw-r--r--src/microhttpd_ws/Makefile.am39
-rw-r--r--src/microhttpd_ws/mhd_websocket.c2072
-rw-r--r--src/microhttpd_ws/sha1.c420
-rw-r--r--src/microhttpd_ws/sha1.h145
-rw-r--r--src/microhttpd_ws/test_websocket.c8983
12 files changed, 12656 insertions, 5 deletions
diff --git a/.gitignore b/.gitignore
index 14a1a2b3..be7d81f0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -62,3 +62,4 @@ src/examples/suspend_resume_epoll
62uncrustify.cfg 62uncrustify.cfg
63**.dvi 63**.dvi
64**.t2d 64**.t2d
65src/microhttpd_ws/test_websocket
diff --git a/ChangeLog b/ChangeLog
index 13364d82..020711bc 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,6 @@
1Mon 26 Apr 2021 02:09:46 PM CEST
2 Importing experimental Websocket support by David Gausmann. -CG
3
1Sun 25 Apr 2021 14:00:00 MSK 4Sun 25 Apr 2021 14:00:00 MSK
2 Releasing GNU libmicrohttpd 0.9.73. -EG 5 Releasing GNU libmicrohttpd 0.9.73. -EG
3 6
diff --git a/configure.ac b/configure.ac
index ea49349b..cfe3e554 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,5 +1,5 @@
1# This file is part of libmicrohttpd. 1# This file is part of libmicrohttpd.
2# (C) 2006-2020 Christian Grothoff (and other contributing authors) 2# (C) 2006-2021 Christian Grothoff (and other contributing authors)
3# 3#
4# libmicrohttpd is free software; you can redistribute it and/or modify 4# libmicrohttpd is free software; you can redistribute it and/or modify
5# it under the terms of the GNU General Public License as published 5# it under the terms of the GNU General Public License as published
@@ -935,7 +935,7 @@ test "x$enable_examples" = "xno" || enable_examples=yes
935AM_CONDITIONAL([BUILD_EXAMPLES], [test "x$enable_examples" = "xyes"]) 935AM_CONDITIONAL([BUILD_EXAMPLES], [test "x$enable_examples" = "xyes"])
936 936
937AC_ARG_ENABLE([[heavy-tests]], 937AC_ARG_ENABLE([[heavy-tests]],
938 [AS_HELP_STRING([[--enable-heavy-tests]], [use heavy tests in test-suite. WARNING:] 938 [AS_HELP_STRING([[--enable-heavy-tests]], [use heavy tests in test-suite. WARNING:]
939 [a dedicated host with minimal number of background processes and no network] 939 [a dedicated host with minimal number of background processes and no network]
940 [activity is recommended to enable.])], [], 940 [activity is recommended to enable.])], [],
941 [enable_heavy_tests=no]) 941 [enable_heavy_tests=no])
@@ -2413,6 +2413,7 @@ src/Makefile
2413src/include/Makefile 2413src/include/Makefile
2414src/lib/Makefile 2414src/lib/Makefile
2415src/microhttpd/Makefile 2415src/microhttpd/Makefile
2416src/microhttpd_ws/Makefile
2416src/examples/Makefile 2417src/examples/Makefile
2417src/testcurl/Makefile 2418src/testcurl/Makefile
2418src/testcurl/https/Makefile 2419src/testcurl/https/Makefile
diff --git a/src/Makefile.am b/src/Makefile.am
index 1f43e73d..c6e52abc 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -16,11 +16,11 @@ endif
16 16
17# Finally (last!) also build experimental lib... 17# Finally (last!) also build experimental lib...
18if HAVE_EXPERIMENTAL 18if HAVE_EXPERIMENTAL
19SUBDIRS += lib 19SUBDIRS += microhttpd_ws lib
20endif 20endif
21 21
22EXTRA_DIST = \ 22EXTRA_DIST = \
23 datadir/cert-and-key.pem \ 23 datadir/cert-and-key.pem \
24 datadir/cert-and-key-for-wireshark.pem 24 datadir/cert-and-key-for-wireshark.pem
25 25
26.NOTPARALLEL: 26.NOTPARALLEL:
diff --git a/src/include/Makefile.am b/src/include/Makefile.am
index 29c91c98..3d73c598 100644
--- a/src/include/Makefile.am
+++ b/src/include/Makefile.am
@@ -1,7 +1,11 @@
1# This Makefile.am is in the public domain 1# This Makefile.am is in the public domain
2SUBDIRS = . 2SUBDIRS = .
3 3
4include_HEADERS = microhttpd.h 4include_HEADERS = microhttpd.h
5noinst_HEADERS = microhttpd2.h microhttpd_tls.h 5noinst_HEADERS = microhttpd2.h microhttpd_tls.h
6 6
7if HAVE_EXPERIMENTAL
8include_HEADERS += microhttpd_ws.h
9endif
10
7EXTRA_DIST = platform.h autoinit_funcs.h mhd_options.h 11EXTRA_DIST = platform.h autoinit_funcs.h mhd_options.h
diff --git a/src/include/microhttpd_ws.h b/src/include/microhttpd_ws.h
new file mode 100644
index 00000000..915ca339
--- /dev/null
+++ b/src/include/microhttpd_ws.h
@@ -0,0 +1,979 @@
1/*
2 This file is part of libmicrohttpd
3 Copyright (C) 2021 Christian Grothoff (and other contributing authors)
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 * @file microhttpd_ws.h
21 * @brief interface for experimental web socket extension to libmicrohttpd
22 * @author David Gausmann
23 */
24#ifndef MHD_MICROHTTPD_WS_H
25#define MHD_MICROHTTPD_WS_H
26
27
28#ifdef __cplusplus
29extern "C"
30{
31#if 0 /* keep Emacsens' auto-indent happy */
32}
33#endif
34#endif
35
36
37/**
38 * @brief Handle for the encoding/decoding of websocket data
39 * (one stream is used per websocket)
40 * @ingroup websocket
41 */
42struct MHD_WebSocketStream;
43
44/**
45 * @brief Flags for the initialization of a websocket stream
46 * `struct MHD_WebSocketStream` used by
47 * #MHD_websocket_stream_init() or
48 * #MHD_websocket_stream_init2().
49 * @ingroup websocket
50 */
51enum MHD_WEBSOCKET_FLAG
52{
53 /**
54 * The websocket is used by the server (default).
55 * Thus all outgoing payload will not be "masked".
56 * All incoming payload must be masked.
57 * This cannot be used together with #MHD_WEBSOCKET_FLAG_CLIENT
58 */
59 MHD_WEBSOCKET_FLAG_SERVER = 0,
60 /**
61 * The websocket is used by the client
62 * (not used if you provide the server).
63 * Thus all outgoing payload will be "masked" (XOR-ed with random values).
64 * All incoming payload must be unmasked.
65 * Please note that this implementation doesn't use a strong random
66 * number generator for the mask as suggested in RFC6455 10.3, because
67 * the main intention of this implemention is the use as server
68 * with MHD, which doesn't need masking.
69 * Instead a weak random number generator is used (`rand()`).
70 * You can set the seed for the random number generator
71 * by calling #MHD_websocket_srand().
72 * This cannot be used together with #MHD_WEBSOCKET_FLAG_SERVER
73 */
74 MHD_WEBSOCKET_FLAG_CLIENT = 1,
75 /**
76 * You don't want to get fragmented data while decoding.
77 * Fragmented frames will be internally put together until
78 * they are complete.
79 * Whether or not data is fragmented is decided
80 * by the sender of the data during encoding.
81 * This cannot be used together with #MHD_WEBSOCKET_FLAG_WANT_FRAGMENTS
82 */
83 MHD_WEBSOCKET_FLAG_NO_FRAGMENTS = 0,
84 /**
85 * You want fragmented data, if it appears while decoding.
86 * You will receive the content of the fragmented frame,
87 * but if you are decoding text, you will never get an unfinished
88 * UTF-8 sequences (if the sequence appears between two fragments).
89 * Instead the text will end before the unfinished UTF-8 sequence.
90 * With the next fragment, which finishes the UTF-8 sequence,
91 * you will get the complete UTF-8 sequence.
92 * This cannot be used together with #MHD_WEBSOCKET_FLAG_WANT_FRAGMENTS
93 */
94 MHD_WEBSOCKET_FLAG_WANT_FRAGMENTS = 2,
95 /**
96 * If the websocket stream becomes invalid during decoding due to
97 * protocol errors, a matching close frame will automatically
98 * be generated.
99 * The close frame will be returned via the parameters
100 * result and result_len of #MHD_websocket_decode() and
101 * the return value is negative
102 * (a value of `enum MHD_WEBSOCKET_STATUS`).
103 * The generated close frame must be freed by the caller
104 * with #MHD_websocket_free().
105 */
106 MHD_WEBSOCKET_FLAG_GENERATE_CLOSE_FRAMES_ON_ERROR = 4
107};
108
109/**
110 * @brief Enum to specify the fragmenting behavior
111 * while encoding with #MHD_websocket_encode_text() or
112 * #MHD_websocket_encode_binary().
113 * @ingroup websocket
114 */
115enum MHD_WEBSOCKET_FRAGMENTATION
116{
117 /**
118 * You don't want to use fragmentation.
119 * The encoded frame consists of only one frame.
120 */
121 MHD_WEBSOCKET_FRAGMENTATION_NONE = 0,
122 /**
123 * You want to use fragmentation.
124 * The encoded frame is the first frame of
125 * a series of data frames of the same type
126 * (text or binary).
127 * You may send control frames (ping, pong or close)
128 * between these data frames.
129 */
130 MHD_WEBSOCKET_FRAGMENTATION_FIRST = 1,
131 /**
132 * You want to use fragmentation.
133 * The encoded frame is not the first frame of
134 * the series of data frames, but also not the last one.
135 * You may send control frames (ping, pong or close)
136 * between these data frames.
137 */
138 MHD_WEBSOCKET_FRAGMENTATION_FOLLOWING = 2,
139 /**
140 * You want to use fragmentation.
141 * The encoded frame is the last frame of
142 * the series of data frames, but also not the first one.
143 * After this frame, you may send all type of frames again.
144 */
145 MHD_WEBSOCKET_FRAGMENTATION_LAST = 3
146};
147
148/**
149 * @brief Enum of the return value for almost every MHD_websocket function.
150 * Errors are negative and values equal to or above zero mean a success.
151 * Positive values are only used by #MHD_websocket_decode().
152 * @ingroup websocket
153 */
154enum MHD_WEBSOCKET_STATUS
155{
156 /**
157 * The call succeeded.
158 * For #MHD_websocket_decode() this means that no error occurred,
159 * but also no frame has been completed yet.
160 */
161 MHD_WEBSOCKET_STATUS_OK = 0,
162 /**
163 * #MHD_websocket_decode() has decoded a text frame.
164 * The parameters result and result_len are filled with the decoded text
165 * (if any).
166 */
167 MHD_WEBSOCKET_STATUS_TEXT_FRAME = 0x1,
168 /**
169 * #MHD_websocket_decode() has decoded a binary frame.
170 * The parameters result and result_len are filled with the decoded
171 * binary data (if any).
172 */
173 MHD_WEBSOCKET_STATUS_BINARY_FRAME = 0x2,
174 /**
175 * #MHD_websocket_decode() has decoded a close frame.
176 * This means you must close the socket using #MHD_upgrade_action()
177 * with #MHD_UPGRADE_ACTION_CLOSE.
178 * You may respond with a close frame before closing.
179 * The parameters result and result_len are filled with
180 * the close reason (if any).
181 * The close reason starts with a two byte sequence of close code
182 * in network byte order (see `enum MHD_WEBSOCKET_CLOSEREASON`).
183 * After these two bytes a UTF-8 encoded close reason may follow.
184 * Compare with result_len to decide whether there is any close reason.
185 */
186 MHD_WEBSOCKET_STATUS_CLOSE_FRAME = 0x8,
187 /**
188 * #MHD_websocket_decode() has decoded a ping frame.
189 * You should respond to this with a pong frame.
190 * The pong frame must contain the same binary data as
191 * the corresponding ping frame (if it had any).
192 * The parameters result and result_len are filled with
193 * the binary ping data (if any).
194 */
195 MHD_WEBSOCKET_STATUS_PING_FRAME = 0x9,
196 /**
197 * #MHD_websocket_decode() has decoded a pong frame.
198 * You should usually only receive pong frames if you sent
199 * a ping frame before.
200 * The binary data should be equal to your ping frame and can be
201 * used to distinguish the response if you sent multiple ping frames.
202 * The parameters result and result_len are filled with
203 * the binary pong data (if any).
204 */
205 MHD_WEBSOCKET_STATUS_PONG_FRAME = 0xA,
206 /**
207 * #MHD_websocket_decode() has decoded a text frame fragment.
208 * The parameters result and result_len are filled with the decoded text
209 * (if any).
210 * This is like #MHD_WEBSOCKET_STATUS_TEXT_FRAME, but it can only
211 * appear if you specified #MHD_WEBSOCKET_FLAG_WANT_FRAGMENTS during
212 * the call of #MHD_websocket_stream_init() or
213 * #MHD_websocket_stream_init2().
214 */
215 MHD_WEBSOCKET_STATUS_TEXT_FRAGMENT = 0x11,
216 /**
217 * #MHD_websocket_decode() has decoded a binary frame fragment.
218 * The parameters result and result_len are filled with the decoded
219 * binary data (if any).
220 * This is like #MHD_WEBSOCKET_STATUS_BINARY_FRAME, but it can only
221 * appear if you specified #MHD_WEBSOCKET_FLAG_WANT_FRAGMENTS during
222 * the call of #MHD_websocket_stream_init() or
223 * #MHD_websocket_stream_init2().
224 */
225 MHD_WEBSOCKET_STATUS_BINARY_FRAGMENT = 0x12,
226 /**
227 * #MHD_websocket_decode() has decoded the last text frame fragment.
228 * The parameters result and result_len are filled with the decoded text
229 * (if any).
230 * This is like #MHD_WEBSOCKET_STATUS_TEXT_FRAGMENT, but it appears
231 * only for the last fragment of a series of fragments.
232 * It can only appear if you specified #MHD_WEBSOCKET_FLAG_WANT_FRAGMENTS
233 * during the call of #MHD_websocket_stream_init() or
234 * #MHD_websocket_stream_init2().
235 */
236 MHD_WEBSOCKET_STATUS_TEXT_LAST_FRAGMENT = 0x21,
237 /**
238 * #MHD_websocket_decode() has decoded the last binary frame fragment.
239 * The parameters result and result_len are filled with the decoded
240 * binary data (if any).
241 * This is like #MHD_WEBSOCKET_STATUS_BINARY_FRAGMENT, but it appears
242 * only for the last fragment of a series of fragments.
243 * It can only appear if you specified #MHD_WEBSOCKET_FLAG_WANT_FRAGMENTS
244 * during the call of #MHD_websocket_stream_init() or
245 * #MHD_websocket_stream_init2().
246 */
247 MHD_WEBSOCKET_STATUS_BINARY_LAST_FRAGMENT = 0x22,
248 /**
249 * The call failed and the stream is invalid now for decoding.
250 * You must close the websocket now using #MHD_upgrade_action()
251 * with #MHD_UPGRADE_ACTION_CLOSE.
252 * You can send a close frame before closing.
253 * This is only used by #MHD_websocket_decode() and happens
254 * if the stream contains errors (i. e. invalid byte data).
255 */
256 MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR = -1,
257 /**
258 * You tried to decode something, but the stream has already
259 * been marked invalid.
260 * You must close the websocket now using #MHD_upgrade_action()
261 * with #MHD_UPGRADE_ACTION_CLOSE.
262 * You can send a close frame before closing.
263 * This is only used by #MHD_websocket_decode() and happens
264 * if you call #MDM_websocket_decode() again after is
265 * has been invalidated.
266 */
267 MHD_WEBSOCKET_STATUS_STREAM_BROKEN = -2,
268 /**
269 * A memory allocation failed. The stream remains valid.
270 * If this occurred while decoding, the decoding could be
271 * possible later if enough memory is available.
272 * This could happen while decoding if you received a too big data frame.
273 * You could try to specify max_payload_size during the call of
274 * #MHD_websocket_stream_init() or #MHD_websocket_stream_init2() then to
275 * avoid this and close the frame instead.
276 */
277 MHD_WEBSOCKET_STATUS_MEMORY_ERROR = -3,
278 /**
279 * You passed invalid parameters during the function call
280 * (i. e. a NULL pointer for a required parameter).
281 * The stream remains valid.
282 */
283 MHD_WEBSOCKET_STATUS_PARAMETER_ERROR = -4,
284 /**
285 * The maximum payload size has been exceeded.
286 * If you got this return code from #MHD_websocket_decode() then
287 * the stream becomes invalid and the websocket must be closed
288 * using #MHD_upgrade_action() with #MHD_UPGRADE_ACTION_CLOSE.
289 * You can send a close frame before closing.
290 * The maximum payload size is specified during the call of
291 * #MHD_websocket_stream_init() or #MHD_websocket_stream_init2().
292 * This can also appear if you specified 0 as maximum payload size
293 * when the message is greater than the maximum allocatable memory size
294 * (i. e. more than 4 GB on 32 bit systems).
295 * If you got this return code from #MHD_websocket_encode_close(),
296 * #MHD_websocket_encode_ping() or #MHD_websocket_encode_pong() then
297 * you passed to much payload data. The stream remains valid then.
298 */
299 MHD_WEBSOCKET_STATUS_MAXIMUM_SIZE_EXCEEDED = -5,
300 /**
301 * An UTF-8 text is invalid.
302 * If you got this return code from #MHD_websocket_decode() then
303 * the stream becomes invalid and you must close the websocket
304 * using #MHD_upgrade_action() with #MHD_UPGRADE_ACTION_CLOSE.
305 * You can send a close frame before closing.
306 * If you got this from #MHD_websocket_encode_text() or
307 * #MHD_websocket_encode_close() then you passed invalid UTF-8 text.
308 * The stream remains valid then.
309 */
310 MHD_WEBSOCKET_STATUS_UTF8_ENCODING_ERROR = -6
311};
312
313/**
314 * @brief Enumeration of possible close reasons for close frames.
315 *
316 * The possible values are specified in RFC 6455 7.4.1
317 * These close reasons here are the default set specified by RFC 6455,
318 * but also other close reasons could be used.
319 *
320 * The definition is for short:
321 * 0-999 are never used (if you pass 0 in
322 * #MHD_websocket_encode_close() then no close reason is used).
323 * 1000-2999 are specified by RFC 6455.
324 * 3000-3999 are specified by libraries, etc. but must be registered by IANA.
325 * 4000-4999 are reserved for private use.
326 *
327 * @ingroup websocket
328 */
329enum MHD_WEBSOCKET_CLOSEREASON
330{
331 /**
332 * This value is used as placeholder for #MHD_websocket_encode_close()
333 * to tell that you don't want to specify any reason.
334 * If you use this value then no reason text may be used.
335 * This value cannot a result of decoding, because this value
336 * is not a valid close reason for the WebSocket protocol.
337 */
338 MHD_WEBSOCKET_CLOSEREASON_NO_REASON = 0,
339 /**
340 * You close the websocket fulfilled its purpose and shall
341 * now be closed in a normal, planned way.
342 */
343 MHD_WEBSOCKET_CLOSEREASON_REGULAR = 1000,
344 /**
345 * You close the websocket because are shutting down the server or
346 * something similar.
347 */
348 MHD_WEBSOCKET_CLOSEREASON_GOING_AWAY = 1001,
349 /**
350 * You close the websocket because you a protocol error occurred
351 * during decoding (i. e. invalid byte data).
352 */
353 MHD_WEBSOCKET_CLOSEREASON_PROTOCOL_ERROR = 1002,
354 /**
355 * You close the websocket because you received data which you don't accept.
356 * For example if you received a binary frame,
357 * but your application only expects text frames.
358 */
359 MHD_WEBSOCKET_CLOSEREASON_UNSUPPORTED_DATATYPE = 1003,
360 /**
361 * You close the websocket because it contains malformed UTF-8.
362 * The UTF-8 validity is automatically checked by #MHD_websocket_decode(),
363 * so you don't need to check it on your own.
364 * UTF-8 is specified in RFC 3629.
365 */
366 MHD_WEBSOCKET_CLOSEREASON_MALFORMED_UTF8 = 1007,
367 /**
368 * You close the websocket because of any reason.
369 * Usually this close reason is used if no other close reason
370 * is more specific or if you don't want to use any other close reason.
371 */
372 MHD_WEBSOCKET_CLOSEREASON_POLICY_VIOLATED = 1008,
373 /**
374 * You close the websocket because you received a frame which is too big to process.
375 * You can specify the maximum allowed payload size during the call of
376 * #MHD_websocket_stream_init() or #MHD_websocket_stream_init2().
377 */
378 MHD_WEBSOCKET_CLOSEREASON_MAXIMUM_ALLOWED_PAYLOAD_SIZE_EXCEEDED = 1009,
379 /**
380 * This status code can be sent by the client if it
381 * expected a specific extension, but this extension hasn't been negotiated.
382 */
383 MHD_WEBSOCKET_CLOSEREASON_MISSING_EXTENSION = 1010,
384 /**
385 * The server closes the websocket because it encountered
386 * an unexpected condition that prevented it from fulfilling the request.
387 */
388 MHD_WEBSOCKET_CLOSEREASON_UNEXPECTED_CONDITION = 1011
389};
390
391/**
392 * @brief Enumeration of possible UTF-8 check steps
393 *
394 * These values are used during the encoding of fragmented text frames
395 * or for error analysis while encoding text frames.
396 * Its values specify the next step of the UTF-8 check.
397 * UTF-8 sequences consist of one to four bytes.
398 * This enumeration just says how long the current UTF-8 sequence is
399 * and what is the next expected byte.
400 *
401 * @ingroup websocket
402 */
403enum MHD_WEBSOCKET_UTF8STEP
404{
405 /**
406 * There is no open UTF-8 sequence.
407 * The next byte must be 0x00-0x7F or 0xC2-0xF4.
408 */
409 MHD_WEBSOCKET_UTF8STEP_NORMAL = 0,
410 /**
411 * The second byte of a two byte UTF-8 sequence.
412 * The first byte was 0xC2-0xDF.
413 * The next byte must be 0x80-0xBF.
414 */
415 MHD_WEBSOCKET_UTF8STEP_UTF2TAIL_1OF1 = 1,
416 /**
417 * The second byte of a three byte UTF-8 sequence.
418 * The first byte was 0xE0.
419 * The next byte must be 0xA0-0xBF.
420 */
421 MHD_WEBSOCKET_UTF8STEP_UTF3TAIL1_1OF2 = 2,
422 /**
423 * The second byte of a three byte UTF-8 sequence.
424 * The first byte was 0xED.
425 * The next byte must by 0x80-0x9F.
426 */
427 MHD_WEBSOCKET_UTF8STEP_UTF3TAIL2_1OF2 = 3,
428 /**
429 * The second byte of a three byte UTF-8 sequence.
430 * The first byte was 0xE1-0xEC or 0xEE-0xEF.
431 * The next byte must be 0x80-0xBF.
432 */
433 MHD_WEBSOCKET_UTF8STEP_UTF3TAIL_1OF2 = 4,
434 /**
435 * The third byte of a three byte UTF-8 sequence.
436 * The next byte must be 0x80-0xBF.
437 */
438 MHD_WEBSOCKET_UTF8STEP_UTF3TAIL_2OF2 = 5,
439 /**
440 * The second byte of a four byte UTF-8 sequence.
441 * The first byte was 0xF0.
442 * The next byte must be 0x90-0xBF.
443 */
444 MHD_WEBSOCKET_UTF8STEP_UTF4TAIL1_1OF3 = 6,
445 /**
446 * The second byte of a four byte UTF-8 sequence.
447 * The first byte was 0xF4.
448 * The next byte must be 0x80-0x8F.
449 */
450 MHD_WEBSOCKET_UTF8STEP_UTF4TAIL2_1OF3 = 7,
451 /**
452 * The second byte of a four byte UTF-8 sequence.
453 * The first byte was 0xF1-0xF3.
454 * The next byte must be 0x80-0xBF.
455 */
456 MHD_WEBSOCKET_UTF8STEP_UTF4TAIL_1OF3 = 8,
457 /**
458 * The third byte of a four byte UTF-8 sequence.
459 * The next byte must be 0x80-0xBF.
460 */
461 MHD_WEBSOCKET_UTF8STEP_UTF4TAIL_2OF3 = 9,
462 /**
463 * The fourth byte of a four byte UTF-8 sequence.
464 * The next byte must be 0x80-0xBF.
465 */
466 MHD_WEBSOCKET_UTF8STEP_UTF4TAIL_3OF3 = 10
467};
468
469/**
470* @brief Enumeration of validity values
471*
472* These values are used for #MHD_websocket_stream_is_valid()
473* and specifiy the validity status.
474*
475* @ingroup websocket
476*/
477enum MHD_WEBSOCKET_VALIDITY
478{
479 /**
480 * The stream is invalid.
481 * It cannot be used for decoding anymore.
482 */
483 MHD_WEBSOCKET_VALIDITY_INVALID = 0,
484 /**
485 * The stream is valid.
486 * Decoding works as expected.
487 */
488 MHD_WEBSOCKET_VALIDITY_VALID = 1,
489 /**
490 * The stream has received a close frame and
491 * is partly invalid.
492 * You can still use the stream for decoding,
493 * but if a data frame is received an error will be reported.
494 * After a close frame has been sent, no data frames
495 * may follow from the sender of the close frame.
496 */
497 MHD_WEBSOCKET_VALIDITY_ONLY_VALID_FOR_CONTROL_FRAMES = 2
498};
499/**
500 * This method is called by many websocket
501 * functions for allocating data.
502 * By default 'malloc' is used.
503 * This can be used for operating systems like Windows
504 * where malloc, realloc and free are compiler dependent.
505 *
506 * @param len new size
507 * @return allocated memory
508 * @ingroup websocket
509 */
510typedef void*
511(*MHD_WebSocketMallocCallback) (size_t len);
512/**
513 * This method is called by many websocket
514 * functions for reallocating data.
515 * By default 'realloc' is used.
516 * This can be used for operating systems like Windows
517 * where malloc, realloc and free are compiler dependent.
518 *
519 * @param cls closure
520 * @param len new size
521 * @return reallocated memory
522 * @ingroup websocket
523 */
524typedef void*
525(*MHD_WebSocketReallocCallback) (void *cls, size_t len);
526/**
527 * This method is called by many websocket
528 * functions for freeing data.
529 * By default 'free' is used.
530 * This can be used for operating systems like Windows
531 * where malloc, realloc and free are compiler dependent.
532 *
533 * @param cls closure
534 * @ingroup websocket
535 */
536typedef void
537(*MHD_WebSocketFreeCallback) (void *cls);
538
539/**
540 * Creates the response value for the incoming 'Sec-WebSocket-Key' header.
541 * The generated value must be sent to the client as 'Sec-WebSocket-Accept' response header.
542 *
543 * @param sec_websocket_key The value of the 'Sec-WebSocket-Key' request header
544 * @param[out] sec_websocket_accept The response buffer, which will receive
545 * the generated 'Sec-WebSocket-Accept' header.
546 * This buffer must be at least 29 bytes long and
547 * will contain a terminating NUL character.
548 * @return A value of `enum MHD_WEBSOCKET_STATUS`.
549 * Typically 0 on success or less than 0 on errors.
550 * @ingroup websocket
551 */
552_MHD_EXTERN int
553MHD_websocket_create_accept (const char*sec_websocket_key,
554 char*sec_websocket_accept);
555
556/**
557 * Creates a new websocket stream, used for decoding/encoding.
558 *
559 * @param[out] ws The websocket stream
560 * @param flags Combination of `enum MHD_WEBSOCKET_FLAG` values
561 * to modify the behavior of the websocket stream.
562 * @param max_message_size The maximum size for incoming payload
563 * data in bytes. Use 0 to allow each size.
564 * @return A value of `enum MHD_WEBSOCKET_STATUS`.
565 * Typically 0 on success or less than 0 on errors.
566 * @ingroup websocket
567 */
568_MHD_EXTERN int
569MHD_websocket_stream_init (struct MHD_WebSocketStream**ws,
570 int flags,
571 size_t max_payload_size);
572
573/**
574 * Creates a new websocket stream, used for decoding/encoding,
575 * but with custom memory functions for malloc, realloc and free.
576 *
577 * @param[out] ws The websocket stream
578 * @param flags Combination of `enum MHD_WEBSOCKET_FLAG` values
579 * to modify the behavior of the websocket stream.
580 * @param max_message_size The maximum size for incoming payload
581 * data in bytes. Use 0 to allow each size.
582 * @param callback_malloc The callback function for 'malloc'.
583 * @param callback_realloc The callback function for 'realloc'.
584 * @param callback_free The callback function for 'free'.
585 * @return A value of `enum MHD_WEBSOCKET_STATUS`.
586 * Typically 0 on success or less than 0 on errors.
587 * @ingroup websocket
588 */
589_MHD_EXTERN int
590MHD_websocket_stream_init2 (struct MHD_WebSocketStream**ws,
591 int flags,
592 size_t max_payload_size,
593 MHD_WebSocketMallocCallback callback_malloc,
594 MHD_WebSocketReallocCallback callback_realloc,
595 MHD_WebSocketFreeCallback callback_free);
596
597/**
598 * Frees a websocket stream
599 *
600 * @param ws The websocket stream. This value may be NULL.
601 * @return A value of `enum MHD_WEBSOCKET_STATUS`.
602 * Typically 0 on success or less than 0 on errors.
603 * @ingroup websocket
604 */
605_MHD_EXTERN int
606MHD_websocket_stream_free (struct MHD_WebSocketStream*ws);
607
608/**
609 * Invalidates a websocket stream.
610 * After invalidation a websocket stream cannot be used for decoding anymore.
611 * Encoding is still possible.
612 *
613 * @param ws The websocket stream.
614 * @return A value of `enum MHD_WEBSOCKET_STATUS`.
615 * Typically 0 on success or less than 0 on errors.
616 * @ingroup websocket
617 */
618_MHD_EXTERN int
619MHD_websocket_stream_invalidate (struct MHD_WebSocketStream*ws);
620
621/**
622 * Queries whether a websocket stream is valid.
623 * Invalidated websocket streams cannot be used for decoding anymore.
624 * Encoding is still possible.
625 *
626 * @param ws The websocket stream.
627 * @return A value of `enum MHD_WEBSOCKET_VALIDITY`.
628 * @ingroup websocket
629 */
630_MHD_EXTERN int
631MHD_websocket_stream_is_valid (struct MHD_WebSocketStream*ws);
632
633/**
634 * Decodes a byte sequence via this websocket stream.
635 * Decoding is done until either a frame is complete or
636 * the end of the byte sequence is reached.
637 *
638 * @param ws The websocket stream.
639 * @param streambuf The byte sequence for decoding.
640 * Typically that what you received via `recv()`.
641 * @param streambuf_len The length of the byte sequence @a streambuf
642 * @param[out] streambuf_read_len The number of bytes which has been processed
643 * by this call. This value may be less
644 * than @a streambuf_len when a frame is decoded
645 * before the end of the buffer is reached.
646 * The remaining bytes of @a buf must be passed
647 * in the following decoding.
648 * @param[out] payload This variable receives a buffer with the decoded
649 * payload data.
650 * If no decoded data is available this is NULL.
651 * When this variable is not NULL then
652 * the buffer contains always @a payload_len bytes plus
653 * one terminating NUL character.
654 * The caller must free this buffer
655 * using #MHD_websocket_free().
656 * If you passed the flag
657 * #MHD_WEBSOCKET_FLAG_GENERATE_CLOSE_FRAMES_ON_ERROR
658 * upon creation of this websocket stream and
659 * a decoding error occurred
660 * (return value less than 0), then this
661 * buffer contains a generated close frame
662 * which must be sent via the socket to the recipient.
663 * If you passed the flag #MHD_WEBSOCKET_FLAG_WANT_FRAGMENTS
664 * upon creation of this websocket stream then
665 * this payload may only be a part of the complete message.
666 * Only complete UTF-8 sequences are returned
667 * for fragmented text frames.
668 * If necessary the UTF-8 sequence will be completed
669 * with the next text fragment.
670 * @param[out] payload_len The length of the result payload buffer in bytes.
671 *
672 * @return A value of `enum MHD_WEBSOCKET_STATUS`.
673 * This is greater than 0 if a frame has is complete, equal to 0 if more data
674 * is needed an less than 0 on errors.
675 * @ingroup websocket
676 */
677_MHD_EXTERN int
678MHD_websocket_decode (struct MHD_WebSocketStream*ws,
679 const char*streambuf,
680 size_t streambuf_len,
681 size_t*streambuf_read_len,
682 char**payload,
683 size_t*payload_len);
684
685/**
686 * Splits the payload of of a decoded close frame.
687 *
688 * @param payload The payload of the close frame.
689 * This parameter may be NULL if @a payload_len is 0.
690 * @param payload_len The length of @a payload.
691 * @param[out] reason_code The numeric close reason.
692 * If there was no close reason, this is
693 * #MHD_WEBSOCKET_CLOSEREASON_NO_REASON.
694 * Compare with `enum MHD_WEBSOCKET_CLOSEREASON`.
695 * This parameter is optional and can be NULL.
696 * @param[out] reason_utf8 The literal close reason.
697 * If there was no literal close reason, this is NULL.
698 * This parameter is optional and can be NULL.
699 * Please note that no memory is allocated
700 * in this function.
701 * If not NULL the returned value of this parameter
702 * points to a position in the specified @a payload.
703 * @param[out] reason_utf8_len The length of the literal close reason.
704 * If there was no literal close reason, this is 0.
705 * This parameter is optional and can be NULL.
706 *
707 * @return A value of `enum MHD_WEBSOCKET_STATUS`.
708 * This is #MHD_WEBSOCKET_STATUS_OK (= 0) on success
709 * or a value less than 0 on errors.
710 * @ingroup websocket
711 */
712_MHD_EXTERN int
713MHD_websocket_split_close_reason (const char*payload,
714 size_t payload_len,
715 unsigned short*reason_code,
716 const char**reason_utf8,
717 size_t*reason_utf8_len);
718
719/**
720 * Encodes an UTF-8 encoded text into websocket text frame.
721 *
722 * @param ws The websocket stream.
723 * @param payload_utf8 The UTF-8 encoded text to send.
724 * This can be NULL if payload_utf8_len is 0.
725 * @param payload_utf8_len The length of the UTF-8 encoded text in bytes.
726 * @param fragmentation A value of `enum MHD_WEBSOCKET_FRAGMENTATION`
727 * to specifiy the fragmentation behavior.
728 * Specify MHD_WEBSOCKET_FRAGMENTATION_NONE
729 * if you don't want to use fragmentation.
730 * @param[out] frame This variable receives a buffer with the encoded frame.
731 * This is what you typically send via `send()` to the recipient.
732 * If no encoded data is available this is NULL.
733 * When this variable is not NULL then the buffer contains always
734 * @a frame_len bytes plus one terminating NUL character.
735 * The caller must free this buffer using #MHD_websocket_free().
736 * @param[out] frame_len The length of the encoded frame in bytes.
737 * @param[out] utf8_step This parameter is required for fragmentation and
738 * can be NULL if no fragmentation is used.
739 * It contains information about the last encoded
740 * UTF-8 sequence and is required to continue a previous
741 * UTF-8 sequence when fragmentation is used.
742 * The `enum MHD_WEBSOCKET_UTF8STEP` is for this.
743 * If you start a new fragment using
744 * MHD_WEBSOCKET_FRAGMENTATION_NONE or
745 * MHD_WEBSOCKET_FRAGMENTATION_FIRST the value
746 * of this variable will be initialized
747 * to MHD_WEBSOCKET_UTF8STEP_NORMAL.
748 *
749 * @return A value of `enum MHD_WEBSOCKET_STATUS`.
750 * This is #MHD_WEBSOCKET_STATUS_OK (= 0) on success
751 * or a value less than 0 on errors.
752 * @ingroup websocket
753 */
754_MHD_EXTERN int
755MHD_websocket_encode_text (struct MHD_WebSocketStream*ws,
756 const char*payload_utf8,
757 size_t payload_utf8_len,
758 int fragmentation,
759 char**frame,
760 size_t*frame_len,
761 int*utf8_step);
762
763/**
764 * Encodes a binary data into websocket binary frame.
765 *
766 * @param ws The websocket stream.
767 * @param payload The binary data to send.
768 * @param payload_len The length of the binary data in bytes.
769 * @param fragmentation A value of `enum MHD_WEBSOCKET_FRAGMENTATION`
770 * to specifiy the fragmentation behavior.
771 * Specify MHD_WEBSOCKET_FRAGMENTATION_NONE
772 * if you don't want to use fragmentation.
773 * @param[out] frame This variable receives a buffer with
774 * the encoded binary frame.
775 * This is what you typically send via `send()`
776 * to the recipient.
777 * If no encoded frame is available this is NULL.
778 * When this variable is not NULL then the allocated buffer
779 * contains always @a frame_len bytes plus one terminating
780 * NUL character.
781 * The caller must free this buffer using #MHD_websocket_free().
782 * @param[out] frame_len The length of the result frame buffer in bytes.
783 *
784 * @return A value of `enum MHD_WEBSOCKET_STATUS`.
785 * This is #MHD_WEBSOCKET_STATUS_OK (= 0) on success
786 * or a value less than 0 on errors.
787 * @ingroup websocket
788 */
789_MHD_EXTERN int
790MHD_websocket_encode_binary (struct MHD_WebSocketStream*ws,
791 const char*payload,
792 size_t payload_len,
793 int fragmentation,
794 char**frame,
795 size_t*frame_len);
796
797/**
798 * Encodes a websocket ping frame
799 *
800 * @param ws The websocket stream.
801 * @param payload The binary ping payload data to send.
802 * This may be NULL if @a payload_len is 0.
803 * @param payload_len The length of the payload data in bytes.
804 * This may not exceed 125 bytes.
805 * @param[out] frame This variable receives a buffer with the encoded ping frame data.
806 * This is what you typically send via `send()` to the recipient.
807 * If no encoded frame is available this is NULL.
808 * When this variable is not NULL then the buffer contains always
809 * @a frame_len bytes plus one terminating NUL character.
810 * The caller must free this buffer using #MHD_websocket_free().
811 * @param[out] frame_len The length of the result frame buffer in bytes.
812 *
813 * @return A value of `enum MHD_WEBSOCKET_STATUS`.
814 * This is #MHD_WEBSOCKET_STATUS_OK (= 0) on success
815 * or a value less than 0 on errors.
816 * @ingroup websocket
817 */
818_MHD_EXTERN int
819MHD_websocket_encode_ping (struct MHD_WebSocketStream*ws,
820 const char*payload,
821 size_t payload_len,
822 char**frame,
823 size_t*frame_len);
824
825/**
826 * Encodes a websocket pong frame
827 *
828 * @param ws The websocket stream.
829 * @param payload The binary pong payload data, which is typically
830 * the decoded payload from the received ping frame.
831 * This may be NULL if @a payload_len is 0.
832 * @param payload_len The length of the payload data in bytes.
833 * This may not exceed 125 bytes.
834 * @param[out] frame This variable receives a buffer with
835 * the encoded pong frame data.
836 * This is what you typically send via `send()`
837 * to the recipient.
838 * If no encoded frame is available this is NULL.
839 * When this variable is not NULL then the buffer
840 * contains always @a frame_len bytes plus one
841 * terminating NUL character.
842 * The caller must free this buffer
843 * using #MHD_websocket_free().
844 * @param[out] frame_len The length of the result frame buffer in bytes.
845 *
846 * @return A value of `enum MHD_WEBSOCKET_STATUS`.
847 * This is #MHD_WEBSOCKET_STATUS_OK (= 0) on success
848 * or a value less than 0 on errors.
849 * @ingroup websocket
850 */
851_MHD_EXTERN int
852MHD_websocket_encode_pong (struct MHD_WebSocketStream*ws,
853 const char*payload,
854 size_t payload_len,
855 char**frame,
856 size_t*frame_len);
857
858/**
859 * Encodes a websocket close frame
860 *
861 * @param ws The websocket stream.
862 * @param reason_code The reason for close.
863 * You can use `enum MHD_WEBSOCKET_CLOSEREASON`
864 * for typical reasons,
865 * but you are not limited to these values.
866 * The allowed values are specified in RFC 6455 7.4.
867 * If you don't want to enter a reason, you can specify
868 * #MHD_WEBSOCKET_CLOSEREASON_NO_REASON then
869 * no reason is encoded.
870 * @param reason_utf8 An UTF-8 encoded text reason why the connection is closed.
871 * This may be NULL if @a reason_utf8_len is 0.
872 * This must be NULL if @a reason_code is
873 * #MHD_WEBSOCKET_CLOSEREASON_NO_REASON (= 0).
874 * @param reason_utf8_len The length of the UTF-8 encoded text reason in bytes.
875 * This may not exceed 123 bytes.
876 * @param[out] frame This variable receives a buffer with
877 * the encoded close frame.
878 * This is what you typically send via `send()`
879 * to the recipient.
880 * If no encoded frame is available this is NULL.
881 * When this variable is not NULL then the buffer
882 * contains always @a frame_len bytes plus
883 * one terminating NUL character.
884 * The caller must free this buffer
885 * using #MHD_websocket_free().
886 * @param[out] frame_len The length of the result frame buffer in bytes.
887 *
888 * @return A value of `enum MHD_WEBSOCKET_STATUS`.
889 * This is #MHD_WEBSOCKET_STATUS_OK (= 0) on success
890 * or a value less than 0 on errors.
891 * @ingroup websocket
892 */
893_MHD_EXTERN int
894MHD_websocket_encode_close (struct MHD_WebSocketStream*ws,
895 unsigned short reason_code,
896 const char*reason_utf8,
897 size_t reason_utf8_len,
898 char**frame,
899 size_t*frame_len);
900
901/**
902 * Sets the seed for the random number generated used for
903 * the generation of masked frames (this is only used for client websockets).
904 * This seed is used for all websocket streams.
905 * Internally `srand()` is called.
906 * Please note that on some situations
907 * (where `rand()` and `srand()` are shared between your program
908 * and this library) this could cause unwanted results in your program if
909 * your program relies on a specific seed.
910 *
911 * @param seed The seed used for the initialization of
912 * the pseudo random number generator.
913 * Typically `time(NULL)` is used here to
914 * generate a seed.
915 *
916 * @return A value of `enum MHD_WEBSOCKET_STATUS`.
917 * This is #MHD_WEBSOCKET_STATUS_OK (= 0) on success
918 * or a value less than 0 on errors.
919 * @ingroup websocket
920 */
921_MHD_EXTERN int
922MHD_websocket_srand (unsigned long seed);
923
924/**
925 * Allocates memory with the associated 'malloc' function
926 * of the websocket stream
927 *
928 * @param ws The websocket stream.
929 * @param len The length of the memory to allocate in bytes
930 *
931 * @return The allocated memory on success or NULL on failure.
932 * @ingroup websocket
933 */
934_MHD_EXTERN void*
935MHD_websocket_malloc (struct MHD_WebSocketStream*ws,
936 size_t len);
937
938/**
939 * Reallocates memory with the associated 'realloc' function
940 * of the websocket stream
941 *
942 * @param ws The websocket stream.
943 * @param cls The previously allocated memory or NULL
944 * @param len The new length of the memory in bytes
945 *
946 * @return The allocated memory on success or NULL on failure.
947 * If NULL is returned the previously allocated buffer
948 * remains valid.
949 * @ingroup websocket
950 */
951_MHD_EXTERN void*
952MHD_websocket_realloc (struct MHD_WebSocketStream*ws,
953 void*cls,
954 size_t len);
955
956/**
957 * Frees memory with the associated 'free' function
958 * of the websocket stream
959 *
960 * @param ws The websocket stream.
961 * @param cls The previously allocated memory or NULL
962 *
963 * @return A value of `enum MHD_WEBSOCKET_STATUS`.
964 * This is #MHD_WEBSOCKET_STATUS_OK (= 0) on success
965 * or a value less than 0 on errors.
966 * @ingroup websocket
967 */
968_MHD_EXTERN int
969MHD_websocket_free (struct MHD_WebSocketStream*ws,
970 void*cls);
971
972#if 0 /* keep Emacsens' auto-indent happy */
973{
974#endif
975#ifdef __cplusplus
976}
977#endif
978
979#endif
diff --git a/src/microhttpd/Makefile.am b/src/microhttpd/Makefile.am
index fa83200a..1e252d5a 100644
--- a/src/microhttpd/Makefile.am
+++ b/src/microhttpd/Makefile.am
@@ -80,6 +80,7 @@ libmicrohttpd_la_SOURCES += \
80 mhd_locks.h 80 mhd_locks.h
81endif 81endif
82 82
83
83libmicrohttpd_la_CPPFLAGS = \ 84libmicrohttpd_la_CPPFLAGS = \
84 $(AM_CPPFLAGS) $(MHD_LIB_CPPFLAGS) $(MHD_TLS_LIB_CPPFLAGS) \ 85 $(AM_CPPFLAGS) $(MHD_LIB_CPPFLAGS) $(MHD_TLS_LIB_CPPFLAGS) \
85 -DBUILDING_MHD_LIB=1 86 -DBUILDING_MHD_LIB=1
@@ -92,6 +93,9 @@ libmicrohttpd_la_LDFLAGS = \
92libmicrohttpd_la_LIBADD = \ 93libmicrohttpd_la_LIBADD = \
93 $(MHD_LIBDEPS) $(MHD_TLS_LIBDEPS) 94 $(MHD_LIBDEPS) $(MHD_TLS_LIBDEPS)
94 95
96
97
98
95if HAVE_W32 99if HAVE_W32
96MHD_DLL_RES_SRC = microhttpd_dll_res.rc 100MHD_DLL_RES_SRC = microhttpd_dll_res.rc
97MHD_DLL_RES_LO = libmicrohttpd_la-$(MHD_DLL_RES_SRC:.rc=.lo) 101MHD_DLL_RES_LO = libmicrohttpd_la-$(MHD_DLL_RES_SRC:.rc=.lo)
diff --git a/src/microhttpd_ws/Makefile.am b/src/microhttpd_ws/Makefile.am
new file mode 100644
index 00000000..16612506
--- /dev/null
+++ b/src/microhttpd_ws/Makefile.am
@@ -0,0 +1,39 @@
1# This Makefile.am is in the public domain
2AM_CPPFLAGS = \
3 -I$(top_srcdir)/src/include \
4 -I$(top_srcdir)/src/microhttpd
5
6AM_CFLAGS = $(HIDDEN_VISIBILITY_CFLAGS)
7
8noinst_DATA =
9MOSTLYCLEANFILES =
10
11SUBDIRS = .
12
13lib_LTLIBRARIES = \
14 libmicrohttpd_ws.la
15libmicrohttpd_ws_la_SOURCES = \
16 sha1.c sha1.h \
17 mhd_websocket.c
18libmicrohttpd_ws_la_CPPFLAGS = \
19 $(AM_CPPFLAGS) $(MHD_LIB_CPPFLAGS) \
20 -DBUILDING_MHD_LIB=1
21libmicrohttpd_ws_la_CFLAGS = \
22 $(AM_CFLAGS) $(MHD_LIB_CFLAGS)
23libmicrohttpd_ws_la_LDFLAGS = \
24 $(MHD_LIB_LDFLAGS) \
25 $(W32_MHD_LIB_LDFLAGS) \
26 -version-info 0:0:0
27libmicrohttpd_ws_la_LIBADD = \
28 $(MHD_LIBDEPS)
29
30TESTS = $(check_PROGRAMS)
31
32check_PROGRAMS = \
33 test_websocket
34
35test_websocket_SOURCES = \
36 test_websocket.c
37test_websocket_LDADD = \
38 $(top_builddir)/src/microhttpd_ws/libmicrohttpd_ws.la \
39 $(top_builddir)/src/microhttpd/libmicrohttpd.la
diff --git a/src/microhttpd_ws/mhd_websocket.c b/src/microhttpd_ws/mhd_websocket.c
new file mode 100644
index 00000000..0e977973
--- /dev/null
+++ b/src/microhttpd_ws/mhd_websocket.c
@@ -0,0 +1,2072 @@
1/*
2 This file is part of libmicrohttpd
3 Copyright (C) 2021 David Gausmann
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
19*/
20
21/**
22 * @file microhttpd_ws/mhd_websocket.c
23 * @brief Support for the websocket protocol
24 * @author David Gausmann
25 */
26#include "platform.h"
27#include "microhttpd.h"
28#include "microhttpd_ws.h"
29#include "sha1.h"
30
31struct MHD_WebSocketStream
32{
33 /* The function pointer to malloc for payload (can be used to use different memory managment) */
34 MHD_WebSocketMallocCallback malloc;
35 /* The function pointer to realloc for payload (can be used to use different memory managment) */
36 MHD_WebSocketReallocCallback realloc;
37 /* The function pointer to free for payload (can be used to use different memory managment) */
38 MHD_WebSocketFreeCallback free;
39 /* The flags specified upon initialization. It may alter the behavior of decoding/encoding */
40 int flags;
41 /* The current step for the decoder. 0 means start of a frame. */
42 char decode_step;
43 /* Specifies whether the stream is valid (1) or not (0),
44 if a close frame has been received this is (-1) to indicate that no data frames are allowed anymore */
45 char validity;
46 /* The current step of the UTF-8 encoding check in the data payload */
47 char data_utf8_step;
48 /* The current step of the UTF-8 encoding check in the control payload */
49 char control_utf8_step;
50 /* if != 0 means that we expect a CONTINUATION frame */
51 char data_type;
52 /* The start of the current frame (may differ from data_payload for CONTINUATION frames) */
53 char*data_payload_start;
54 /* The buffer for the data frame */
55 char*data_payload;
56 /* The buffer for the control frame */
57 char*control_payload;
58 /* Configuration for the maximum allowed buffer size for payload data */
59 size_t max_payload_size;
60 /* The current frame header size */
61 size_t frame_header_size;
62 /* The current data payload size (can be greater than payload_size for fragmented frames) */
63 size_t data_payload_size;
64 /* The size of the payload of the current frame (control or data) */
65 size_t payload_size;
66 /* The processing offset to the start of the payload of the current frame (control or data) */
67 size_t payload_index;
68 /* The frame header of the current frame (control or data) */
69 char frame_header[32];
70 /* The mask key of the current frame (control or data); this is 0 if no masking used */
71 char mask_key[4];
72};
73
74#define MHD_WEBSOCKET_FLAG_MASK_SERVERCLIENT MHD_WEBSOCKET_FLAG_CLIENT
75#define MHD_WEBSOCKET_FLAG_MASK_FRAGMENTATION \
76 MHD_WEBSOCKET_FLAG_WANT_FRAGMENTS
77#define MHD_WEBSOCKET_FLAG_MASK_GENERATE_CLOSE_FRAMES \
78 MHD_WEBSOCKET_FLAG_GENERATE_CLOSE_FRAMES_ON_ERROR
79#define MHD_WEBSOCKET_FLAG_MASK_ALL \
80 (MHD_WEBSOCKET_FLAG_MASK_SERVERCLIENT \
81 | MHD_WEBSOCKET_FLAG_MASK_FRAGMENTATION \
82 | MHD_WEBSOCKET_FLAG_MASK_GENERATE_CLOSE_FRAMES)
83
84enum MHD_WebSocket_Opcode
85{
86 MHD_WebSocket_Opcode_Continuation = 0x0,
87 MHD_WebSocket_Opcode_Text = 0x1,
88 MHD_WebSocket_Opcode_Binary = 0x2,
89 MHD_WebSocket_Opcode_Close = 0x8,
90 MHD_WebSocket_Opcode_Ping = 0x9,
91 MHD_WebSocket_Opcode_Pong = 0xA
92};
93
94enum MHD_WebSocket_DecodeStep
95{
96 MHD_WebSocket_DecodeStep_Start = 0,
97 MHD_WebSocket_DecodeStep_Length1ofX = 1,
98 MHD_WebSocket_DecodeStep_Length1of2 = 2,
99 MHD_WebSocket_DecodeStep_Length2of2 = 3,
100 MHD_WebSocket_DecodeStep_Length1of8 = 4,
101 MHD_WebSocket_DecodeStep_Length2of8 = 5,
102 MHD_WebSocket_DecodeStep_Length3of8 = 6,
103 MHD_WebSocket_DecodeStep_Length4of8 = 7,
104 MHD_WebSocket_DecodeStep_Length5of8 = 8,
105 MHD_WebSocket_DecodeStep_Length6of8 = 9,
106 MHD_WebSocket_DecodeStep_Length7of8 = 10,
107 MHD_WebSocket_DecodeStep_Length8of8 = 11,
108 MHD_WebSocket_DecodeStep_Mask1Of4 = 12,
109 MHD_WebSocket_DecodeStep_Mask2Of4 = 13,
110 MHD_WebSocket_DecodeStep_Mask3Of4 = 14,
111 MHD_WebSocket_DecodeStep_Mask4Of4 = 15,
112 MHD_WebSocket_DecodeStep_HeaderCompleted = 16,
113 MHD_WebSocket_DecodeStep_PayloadOfDataFrame = 17,
114 MHD_WebSocket_DecodeStep_PayloadOfControlFrame = 18,
115 MHD_WebSocket_DecodeStep_BrokenStream = 99
116};
117
118enum MHD_WebSocket_UTF8Result
119{
120 MHD_WebSocket_UTF8Result_Invalid = 0,
121 MHD_WebSocket_UTF8Result_Valid = 1,
122 MHD_WebSocket_UTF8Result_Incomplete = 2
123};
124
125#define htonll(x) \
126 ((1 == htonl (1)) ? (x) : ((uint64_t) htonl ((x) & 0xFFFFFFFF) << 32) \
127 | htonl ((x) >> 32))
128#define ntohll(x) \
129 ((1 == ntohl (1)) ? (x) : ((uint64_t) ntohl ((x) & 0xFFFFFFFF) << 32) \
130 | ntohl ((x) >> 32))
131
132static void
133MHD_websocket_copy_payload (char*dst,
134 const char*src,
135 size_t len,
136 unsigned long mask,
137 unsigned long mask_offset);
138
139static int
140MHD_websocket_check_utf8 (const char*buf,
141 size_t buf_len,
142 int*utf8_step,
143 size_t*buf_offset);
144
145static int
146MHD_websocket_decode_header_complete (struct MHD_WebSocketStream*ws,
147 char**payload,
148 size_t*payload_len);
149
150static int
151MHD_websocket_decode_payload_complete (struct MHD_WebSocketStream*ws,
152 char**payload,
153 size_t*payload_len);
154
155static char
156MHD_websocket_encode_is_masked (struct MHD_WebSocketStream *ws);
157static char
158MHD_websocket_encode_overhead_size (struct MHD_WebSocketStream *ws,
159 size_t payload_len);
160
161static int
162MHD_websocket_encode_data (struct MHD_WebSocketStream*ws,
163 const char*payload,
164 size_t payload_len,
165 int fragmentation,
166 char**frame,
167 size_t*frame_len,
168 char opcode);
169
170static int
171MHD_websocket_encode_ping_pong (struct MHD_WebSocketStream*ws,
172 const char*payload,
173 size_t payload_len,
174 char**frame,
175 size_t*frame_len,
176 char opcode);
177
178static unsigned long
179MHD_websocket_generate_mask ();
180
181/**
182 * Creates the response for the Sec-WebSocket-Accept header
183 */
184_MHD_EXTERN int
185MHD_websocket_create_accept (const char*sec_websocket_key,
186 char*sec_websocket_accept)
187{
188 /* initialize output variables for errors cases */
189 if (NULL != sec_websocket_accept)
190 *sec_websocket_accept = 0;
191
192 /* validate parameters */
193 if ((NULL == sec_websocket_key) ||
194 (NULL == sec_websocket_accept) )
195 {
196 return MHD_WEBSOCKET_STATUS_PARAMETER_ERROR;
197 }
198
199 /* build SHA1 hash of the given key and the UUID appended */
200 char sha1[20];
201 const char*suffix = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
202 int length = (int) strlen (sec_websocket_key);
203 struct sha1_ctx ctx;
204 sha1_init_ctx (&ctx);
205 sha1_process_bytes (sec_websocket_key, length, &ctx);
206 sha1_process_bytes (suffix, 36, &ctx);
207 sha1_finish_ctx (&ctx, sha1);
208
209 /* base64 encode that SHA1 hash */
210 /* (simple algorithm here; SHA1 has always 20 bytes, */
211 /* which will always result in a 28 bytes base64 hash) */
212 const char*base64_encoding_table =
213 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
214 for (int i = 0, j = 0; i < 20;)
215 {
216 uint32_t octet_a = i < 20 ? (unsigned char) sha1[i++] : 0;
217 uint32_t octet_b = i < 20 ? (unsigned char) sha1[i++] : 0;
218 uint32_t octet_c = i < 20 ? (unsigned char) sha1[i++] : 0;
219 uint32_t triple = (octet_a << 0x10) + (octet_b << 0x08) + octet_c;
220
221 sec_websocket_accept[j++] = base64_encoding_table[(triple >> 3 * 6) & 0x3F];
222 sec_websocket_accept[j++] = base64_encoding_table[(triple >> 2 * 6) & 0x3F];
223 sec_websocket_accept[j++] = base64_encoding_table[(triple >> 1 * 6) & 0x3F];
224 sec_websocket_accept[j++] = base64_encoding_table[(triple >> 0 * 6) & 0x3F];
225
226 }
227 sec_websocket_accept[27] = '=';
228 sec_websocket_accept[28] = 0;
229
230 return MHD_WEBSOCKET_STATUS_OK;
231}
232
233
234/**
235 * Initializes a new websocket stream
236 */
237_MHD_EXTERN int
238MHD_websocket_stream_init (struct MHD_WebSocketStream**ws,
239 int flags,
240 size_t max_payload_size)
241{
242 return MHD_websocket_stream_init2 (ws,
243 flags,
244 max_payload_size,
245 malloc,
246 realloc,
247 free);
248}
249
250
251/**
252 * Initializes a new websocket stream with
253 * additional parameters for allocation functions
254 */
255_MHD_EXTERN int
256MHD_websocket_stream_init2 (struct MHD_WebSocketStream**ws,
257 int flags,
258 size_t max_payload_size,
259 MHD_WebSocketMallocCallback callback_malloc,
260 MHD_WebSocketReallocCallback callback_realloc,
261 MHD_WebSocketFreeCallback callback_free)
262{
263 /* initialize output variables for errors cases */
264 if (NULL != ws)
265 *ws = NULL;
266
267 /* validate parameters */
268 if ((NULL == ws) ||
269 (0 != (flags & ~MHD_WEBSOCKET_FLAG_MASK_ALL)) ||
270 ((uint64_t) 0x7FFFFFFFFFFFFFFF < max_payload_size) ||
271 (NULL == callback_malloc) ||
272 (NULL == callback_realloc) ||
273 (NULL == callback_free) )
274 {
275 return MHD_WEBSOCKET_STATUS_PARAMETER_ERROR;
276 }
277
278 /* allocate stream */
279 struct MHD_WebSocketStream*ws_ = (struct MHD_WebSocketStream*) malloc (
280 sizeof (struct MHD_WebSocketStream));
281 if (NULL == ws_)
282 return MHD_WEBSOCKET_STATUS_MEMORY_ERROR;
283
284 /* initialize stream */
285 memset (ws_, 0, sizeof (struct MHD_WebSocketStream));
286 ws_->flags = flags;
287 ws_->max_payload_size = max_payload_size;
288 ws_->malloc = callback_malloc;
289 ws_->realloc = callback_realloc;
290 ws_->free = callback_free;
291 ws_->validity = MHD_WEBSOCKET_VALIDITY_VALID;
292
293 /* return stream */
294 *ws = ws_;
295
296 return MHD_WEBSOCKET_STATUS_OK;
297}
298
299
300/**
301 * Frees a previously allocated websocket stream
302 */
303_MHD_EXTERN int
304MHD_websocket_stream_free (struct MHD_WebSocketStream*ws)
305{
306 /* validate parameters */
307 if (NULL == ws)
308 return MHD_WEBSOCKET_STATUS_PARAMETER_ERROR;
309
310 /* free allocated payload data */
311 if (ws->data_payload)
312 ws->free (ws->data_payload);
313 if (ws->control_payload)
314 ws->free (ws->control_payload);
315
316 /* free the stream */
317 free (ws);
318
319 return MHD_WEBSOCKET_STATUS_OK;
320}
321
322
323/**
324 * Invalidates a websocket stream (no more decoding possible)
325 */
326_MHD_EXTERN int
327MHD_websocket_stream_invalidate (struct MHD_WebSocketStream*ws)
328{
329 /* validate parameters */
330 if (NULL == ws)
331 return MHD_WEBSOCKET_STATUS_PARAMETER_ERROR;
332
333 /* invalidate stream */
334 ws->validity = MHD_WEBSOCKET_VALIDITY_INVALID;
335
336 return MHD_WEBSOCKET_STATUS_OK;
337}
338
339
340/**
341 * Returns whether a websocket stream is valid
342 */
343_MHD_EXTERN int
344MHD_websocket_stream_is_valid (struct MHD_WebSocketStream*ws)
345{
346 /* validate parameters */
347 if (NULL == ws)
348 return MHD_WEBSOCKET_VALIDITY_INVALID;
349
350 return ws->validity;
351}
352
353
354/**
355 * Decodes incoming data to a websocket frame
356 */
357_MHD_EXTERN int
358MHD_websocket_decode (struct MHD_WebSocketStream*ws,
359 const char*streambuf,
360 size_t streambuf_len,
361 size_t*streambuf_read_len,
362 char**payload,
363 size_t*payload_len)
364{
365 /* initialize output variables for errors cases */
366 if (NULL != streambuf_read_len)
367 *streambuf_read_len = 0;
368 if (NULL != payload)
369 *payload = NULL;
370 if (NULL != payload_len)
371 *payload_len = 0;
372
373 /* validate parameters */
374 if ((NULL == ws) ||
375 (NULL == streambuf) && (0 != streambuf_len) ||
376 (NULL == streambuf_read_len) ||
377 (NULL == payload) ||
378 (NULL == payload_len) )
379 {
380 return MHD_WEBSOCKET_STATUS_PARAMETER_ERROR;
381 }
382
383 /* validate stream validity */
384 if (MHD_WEBSOCKET_VALIDITY_INVALID == ws->validity)
385 return MHD_WEBSOCKET_STATUS_STREAM_BROKEN;
386
387 /* decode loop */
388 size_t current = 0;
389 while (current < streambuf_len)
390 {
391 switch (ws->decode_step)
392 {
393 /* start of frame */
394 case MHD_WebSocket_DecodeStep_Start:
395 {
396 /* The first byte contains the opcode, the fin flag and three reserved bits */
397 if (MHD_WEBSOCKET_VALIDITY_INVALID != ws->validity)
398 {
399 char opcode = streambuf [current];
400 if (0 != (opcode & 0x70))
401 {
402 /* RFC 6455 5.2 RSV1-3: If a reserved flag is set */
403 /* (while it isn't specified by an extension) the communcation must fail. */
404 ws->validity = MHD_WEBSOCKET_VALIDITY_INVALID;
405 if (0 != (ws->flags
406 & MHD_WEBSOCKET_FLAG_GENERATE_CLOSE_FRAMES_ON_ERROR))
407 {
408 MHD_websocket_encode_close (ws,
409 MHD_WEBSOCKET_CLOSEREASON_PROTOCOL_ERROR,
410 0,
411 0,
412 payload,
413 payload_len);
414 }
415 *streambuf_read_len = current;
416 return MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR;
417 }
418 switch (opcode & 0x0F)
419 {
420 case MHD_WebSocket_Opcode_Continuation:
421 if (0 == ws->data_type)
422 {
423 /* RFC 6455 5.4: Continuation frame without previous data frame */
424 ws->validity = MHD_WEBSOCKET_VALIDITY_INVALID;
425 if (0 != (ws->flags
426 & MHD_WEBSOCKET_FLAG_GENERATE_CLOSE_FRAMES_ON_ERROR))
427 {
428 MHD_websocket_encode_close (ws,
429 MHD_WEBSOCKET_CLOSEREASON_PROTOCOL_ERROR,
430 0,
431 0,
432 payload,
433 payload_len);
434 }
435 *streambuf_read_len = current;
436 return MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR;
437 }
438 if (MHD_WEBSOCKET_VALIDITY_ONLY_VALID_FOR_CONTROL_FRAMES ==
439 ws->validity)
440 {
441 /* RFC 6455 5.5.1: After a close frame has been sent, */
442 /* no data frames may be sent (so we don't accept data frames */
443 /* for decoding anymore) */
444 ws->validity = MHD_WEBSOCKET_VALIDITY_INVALID;
445 if (0 != (ws->flags
446 & MHD_WEBSOCKET_FLAG_GENERATE_CLOSE_FRAMES_ON_ERROR))
447 {
448 MHD_websocket_encode_close (ws,
449 MHD_WEBSOCKET_CLOSEREASON_PROTOCOL_ERROR,
450 0,
451 0,
452 payload,
453 payload_len);
454 }
455 *streambuf_read_len = current;
456 return MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR;
457 }
458 break;
459
460 case MHD_WebSocket_Opcode_Text:
461 case MHD_WebSocket_Opcode_Binary:
462 if (0 != ws->data_type)
463 {
464 /* RFC 6455 5.4: Continuation expected, but new data frame */
465 ws->validity = MHD_WEBSOCKET_VALIDITY_INVALID;
466 if (0 != (ws->flags
467 & MHD_WEBSOCKET_FLAG_GENERATE_CLOSE_FRAMES_ON_ERROR))
468 {
469 MHD_websocket_encode_close (ws,
470 MHD_WEBSOCKET_CLOSEREASON_PROTOCOL_ERROR,
471 0,
472 0,
473 payload,
474 payload_len);
475 }
476 *streambuf_read_len = current;
477 return MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR;
478 }
479 if (MHD_WEBSOCKET_VALIDITY_ONLY_VALID_FOR_CONTROL_FRAMES ==
480 ws->validity)
481 {
482 /* RFC 6455 5.5.1: After a close frame has been sent, */
483 /* no data frames may be sent (so we don't accept data frames */
484 /* for decoding anymore) */
485 ws->validity = MHD_WEBSOCKET_VALIDITY_INVALID;
486 if (0 != (ws->flags
487 & MHD_WEBSOCKET_FLAG_GENERATE_CLOSE_FRAMES_ON_ERROR))
488 {
489 MHD_websocket_encode_close (ws,
490 MHD_WEBSOCKET_CLOSEREASON_PROTOCOL_ERROR,
491 0,
492 0,
493 payload,
494 payload_len);
495 }
496 *streambuf_read_len = current;
497 return MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR;
498 }
499 break;
500
501 case MHD_WebSocket_Opcode_Close:
502 case MHD_WebSocket_Opcode_Ping:
503 case MHD_WebSocket_Opcode_Pong:
504 if ((opcode & 0x80) == 0)
505 {
506 /* RFC 6455 5.4: Control frames may not be fragmented */
507 ws->validity = MHD_WEBSOCKET_VALIDITY_INVALID;
508 if (0 != (ws->flags
509 & MHD_WEBSOCKET_FLAG_GENERATE_CLOSE_FRAMES_ON_ERROR))
510 {
511 MHD_websocket_encode_close (ws,
512 MHD_WEBSOCKET_CLOSEREASON_PROTOCOL_ERROR,
513 0,
514 0,
515 payload,
516 payload_len);
517 }
518 *streambuf_read_len = current;
519 return MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR;
520 }
521 if (MHD_WebSocket_Opcode_Close == (opcode & 0x0F))
522 {
523 /* RFC 6455 5.5.1: After a close frame has been sent, */
524 /* no data frames may be sent (so we don't accept data frames */
525 /* for decoding anymore) */
526 ws->validity =
527 MHD_WEBSOCKET_VALIDITY_ONLY_VALID_FOR_CONTROL_FRAMES;
528 }
529 break;
530
531 default:
532 /* RFC 6455 5.2 OPCODE: Only six opcodes are specified. */
533 /* All other are invalid in version 13 of the protocol. */
534 ws->validity = MHD_WEBSOCKET_VALIDITY_INVALID;
535 if (0 != (ws->flags
536 & MHD_WEBSOCKET_FLAG_GENERATE_CLOSE_FRAMES_ON_ERROR))
537 {
538 MHD_websocket_encode_close (ws,
539 MHD_WEBSOCKET_CLOSEREASON_PROTOCOL_ERROR,
540 0,
541 0,
542 payload,
543 payload_len);
544 }
545 *streambuf_read_len = current;
546 return MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR;
547 }
548 }
549 ws->frame_header [ws->frame_header_size++] = streambuf [current++];
550 ws->decode_step = MHD_WebSocket_DecodeStep_Length1ofX;
551 }
552 break;
553
554 case MHD_WebSocket_DecodeStep_Length1ofX:
555 {
556 /* The second byte specifies whether the data is masked and the size */
557 /* (the client MUST mask the payload, the server MUST NOT mask the payload) */
558 char frame_len = streambuf [current];
559 char is_masked = (frame_len & 0x80);
560 frame_len &= 0x7f;
561 if (MHD_WEBSOCKET_VALIDITY_INVALID != ws->validity)
562 {
563 if (0 != is_masked)
564 {
565 if (MHD_WEBSOCKET_FLAG_CLIENT == (ws->flags
566 & MHD_WEBSOCKET_FLAG_CLIENT))
567 {
568 /* RFC 6455 5.1: All frames from the server must be unmasked */
569 ws->validity = MHD_WEBSOCKET_VALIDITY_INVALID;
570 if (0 != (ws->flags
571 & MHD_WEBSOCKET_FLAG_GENERATE_CLOSE_FRAMES_ON_ERROR))
572 {
573 MHD_websocket_encode_close (ws,
574 MHD_WEBSOCKET_CLOSEREASON_PROTOCOL_ERROR,
575 0,
576 0,
577 payload,
578 payload_len);
579 }
580 *streambuf_read_len = current;
581 return MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR;
582 }
583 }
584 else
585 {
586 if (MHD_WEBSOCKET_FLAG_SERVER == (ws->flags
587 & MHD_WEBSOCKET_FLAG_CLIENT))
588 {
589 /* RFC 6455 5.1: All frames from the client must be masked */
590 ws->validity = MHD_WEBSOCKET_VALIDITY_INVALID;
591 if (0 != (ws->flags
592 & MHD_WEBSOCKET_FLAG_GENERATE_CLOSE_FRAMES_ON_ERROR))
593 {
594 MHD_websocket_encode_close (ws,
595 MHD_WEBSOCKET_CLOSEREASON_PROTOCOL_ERROR,
596 0,
597 0,
598 payload,
599 payload_len);
600 }
601 *streambuf_read_len = current;
602 return MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR;
603 }
604 }
605 if (126 <= frame_len)
606 {
607 if (0 != (ws->frame_header [0] & 0x08))
608 {
609 /* RFC 6455 5.5: Control frames may not have more payload than 125 bytes */
610 ws->validity = MHD_WEBSOCKET_VALIDITY_INVALID;
611 if (0 != (ws->flags
612 & MHD_WEBSOCKET_FLAG_GENERATE_CLOSE_FRAMES_ON_ERROR))
613 {
614 MHD_websocket_encode_close (ws,
615 MHD_WEBSOCKET_CLOSEREASON_PROTOCOL_ERROR,
616 0,
617 0,
618 payload,
619 payload_len);
620 }
621 *streambuf_read_len = current;
622 return MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR;
623 }
624 }
625 if (1 == frame_len)
626 {
627 if (MHD_WebSocket_Opcode_Close == (ws->frame_header [0] & 0x0F))
628 {
629 /* RFC 6455 5.5.1: The close frame must have at least */
630 /* two bytes of payload if payload is used */
631 ws->validity = MHD_WEBSOCKET_VALIDITY_INVALID;
632 if (0 != (ws->flags
633 & MHD_WEBSOCKET_FLAG_GENERATE_CLOSE_FRAMES_ON_ERROR))
634 {
635 MHD_websocket_encode_close (ws,
636 MHD_WEBSOCKET_CLOSEREASON_PROTOCOL_ERROR,
637 0,
638 0,
639 payload,
640 payload_len);
641 }
642 *streambuf_read_len = current;
643 return MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR;
644 }
645 }
646 }
647 ws->frame_header [ws->frame_header_size++] = streambuf [current++];
648
649 if (126 == frame_len)
650 {
651 ws->decode_step = MHD_WebSocket_DecodeStep_Length1of2;
652 }
653 else if (127 == frame_len)
654 {
655 ws->decode_step = MHD_WebSocket_DecodeStep_Length1of8;
656 }
657 else
658 {
659 size_t size = (size_t) frame_len;
660 if ((SIZE_MAX < size) || ws->max_payload_size &&
661 (ws->max_payload_size < size) )
662 {
663 /* RFC 6455 7.4.1 1009: If the message is too big to process, we may close the connection */
664 ws->validity = MHD_WEBSOCKET_VALIDITY_INVALID;
665 if (0 != (ws->flags
666 & MHD_WEBSOCKET_FLAG_GENERATE_CLOSE_FRAMES_ON_ERROR))
667 {
668 MHD_websocket_encode_close (ws,
669 MHD_WEBSOCKET_CLOSEREASON_MAXIMUM_ALLOWED_PAYLOAD_SIZE_EXCEEDED,
670 0,
671 0,
672 payload,
673 payload_len);
674 }
675 *streambuf_read_len = current;
676 return MHD_WEBSOCKET_STATUS_MAXIMUM_SIZE_EXCEEDED;
677 }
678 ws->payload_size = size;
679 if (0 != is_masked)
680 {
681 /* with mask */
682 ws->decode_step = MHD_WebSocket_DecodeStep_Mask1Of4;
683 }
684 else
685 {
686 /* without mask */
687 *((unsigned long *) ws->mask_key) = 0;
688 ws->decode_step = MHD_WebSocket_DecodeStep_HeaderCompleted;
689 }
690 }
691 }
692 break;
693
694 /* Payload size first byte of 2 bytes */
695 case MHD_WebSocket_DecodeStep_Length1of2:
696 /* Payload size first 7 bytes of 8 bytes */
697 case MHD_WebSocket_DecodeStep_Length1of8:
698 case MHD_WebSocket_DecodeStep_Length2of8:
699 case MHD_WebSocket_DecodeStep_Length3of8:
700 case MHD_WebSocket_DecodeStep_Length4of8:
701 case MHD_WebSocket_DecodeStep_Length5of8:
702 case MHD_WebSocket_DecodeStep_Length6of8:
703 case MHD_WebSocket_DecodeStep_Length7of8:
704 /* Mask first 3 bytes of 4 bytes */
705 case MHD_WebSocket_DecodeStep_Mask1Of4:
706 case MHD_WebSocket_DecodeStep_Mask2Of4:
707 case MHD_WebSocket_DecodeStep_Mask3Of4:
708 ws->frame_header [ws->frame_header_size++] = streambuf [current++];
709 ++ws->decode_step;
710 break;
711
712 /* 2 byte length finished */
713 case MHD_WebSocket_DecodeStep_Length2of2:
714 {
715 ws->frame_header [ws->frame_header_size++] = streambuf [current++];
716 size_t size = (size_t) htons (*((unsigned
717 short*) &ws->frame_header [2]));
718 if (125 >= size)
719 {
720 /* RFC 6455 5.2 Payload length: The minimal number of bytes */
721 /* must be used for the length */
722 ws->validity = MHD_WEBSOCKET_VALIDITY_INVALID;
723 if (0 != (ws->flags
724 & MHD_WEBSOCKET_FLAG_GENERATE_CLOSE_FRAMES_ON_ERROR))
725 {
726 MHD_websocket_encode_close (ws,
727 MHD_WEBSOCKET_CLOSEREASON_PROTOCOL_ERROR,
728 0,
729 0,
730 payload,
731 payload_len);
732 }
733 *streambuf_read_len = current;
734 return MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR;
735 }
736 if ((SIZE_MAX < size) || ws->max_payload_size && (ws->max_payload_size <
737 size) )
738 {
739 /* RFC 6455 7.4.1 1009: If the message is too big to process, */
740 /* we may close the connection */
741 ws->validity = MHD_WEBSOCKET_VALIDITY_INVALID;
742 if (0 != (ws->flags
743 & MHD_WEBSOCKET_FLAG_GENERATE_CLOSE_FRAMES_ON_ERROR))
744 {
745 MHD_websocket_encode_close (ws,
746 MHD_WEBSOCKET_CLOSEREASON_MAXIMUM_ALLOWED_PAYLOAD_SIZE_EXCEEDED,
747 0,
748 0,
749 payload,
750 payload_len);
751 }
752 *streambuf_read_len = current;
753 return MHD_WEBSOCKET_STATUS_MAXIMUM_SIZE_EXCEEDED;
754 }
755 ws->payload_size = size;
756 if (0 != (ws->frame_header [1] & 0x80))
757 {
758 /* with mask */
759 ws->decode_step = MHD_WebSocket_DecodeStep_Mask1Of4;
760 }
761 else
762 {
763 /* without mask */
764 *((unsigned long *) ws->mask_key) = 0;
765 ws->decode_step = MHD_WebSocket_DecodeStep_HeaderCompleted;
766 }
767 }
768 break;
769
770 /* 8 byte length finished */
771 case MHD_WebSocket_DecodeStep_Length8of8:
772 {
773 ws->frame_header [ws->frame_header_size++] = streambuf [current++];
774 uint64_t size = htonll (*((uint64_t*) &ws->frame_header [2]));
775 if (0x7fffffffffffffff < size)
776 {
777 /* RFC 6455 5.2 frame-payload-length-63: The length may */
778 /* not exceed 0x7fffffffffffffff */
779 ws->decode_step = MHD_WebSocket_DecodeStep_BrokenStream;
780 ws->validity = MHD_WEBSOCKET_VALIDITY_INVALID;
781 if (0 != (ws->flags
782 & MHD_WEBSOCKET_FLAG_GENERATE_CLOSE_FRAMES_ON_ERROR))
783 {
784 MHD_websocket_encode_close (ws,
785 MHD_WEBSOCKET_CLOSEREASON_PROTOCOL_ERROR,
786 0,
787 0,
788 payload,
789 payload_len);
790 }
791 *streambuf_read_len = current;
792 return MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR;
793 }
794 if (65535 >= size)
795 {
796 /* RFC 6455 5.2 Payload length: The minimal number of bytes */
797 /* must be used for the length */
798 ws->validity = MHD_WEBSOCKET_VALIDITY_INVALID;
799 if (0 != (ws->flags
800 & MHD_WEBSOCKET_FLAG_GENERATE_CLOSE_FRAMES_ON_ERROR))
801 {
802 MHD_websocket_encode_close (ws,
803 MHD_WEBSOCKET_CLOSEREASON_PROTOCOL_ERROR,
804 0,
805 0,
806 payload,
807 payload_len);
808 }
809 *streambuf_read_len = current;
810 return MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR;
811 }
812 if ((SIZE_MAX < size) || ws->max_payload_size && (ws->max_payload_size <
813 size) )
814 {
815 /* RFC 6455 7.4.1 1009: If the message is too big to process, */
816 /* we may close the connection */
817 ws->validity = MHD_WEBSOCKET_VALIDITY_INVALID;
818 if (0 != (ws->flags
819 & MHD_WEBSOCKET_FLAG_GENERATE_CLOSE_FRAMES_ON_ERROR))
820 {
821 MHD_websocket_encode_close (ws,
822 MHD_WEBSOCKET_CLOSEREASON_MAXIMUM_ALLOWED_PAYLOAD_SIZE_EXCEEDED,
823 0,
824 0,
825 payload,
826 payload_len);
827 }
828 *streambuf_read_len = current;
829 return MHD_WEBSOCKET_STATUS_MAXIMUM_SIZE_EXCEEDED;
830 }
831 ws->payload_size = (size_t) size;
832
833 if (0 != (ws->frame_header [1] & 0x80))
834 {
835 /* with mask */
836 ws->decode_step = MHD_WebSocket_DecodeStep_Mask1Of4;
837 }
838 else
839 {
840 /* without mask */
841 *((unsigned long *) ws->mask_key) = 0;
842 ws->decode_step = MHD_WebSocket_DecodeStep_HeaderCompleted;
843 }
844 }
845 break;
846
847 /* mask finished */
848 case MHD_WebSocket_DecodeStep_Mask4Of4:
849 ws->frame_header [ws->frame_header_size++] = streambuf [current++];
850 *((unsigned long *) ws->mask_key) = *((unsigned
851 long *) &ws->frame_header [ws->
852 frame_header_size
853 - 4]);
854 ws->decode_step = MHD_WebSocket_DecodeStep_HeaderCompleted;
855 break;
856
857 /* header finished */
858 case MHD_WebSocket_DecodeStep_HeaderCompleted:
859 /* return or assign either to data or control */
860 {
861 int ret = MHD_websocket_decode_header_complete (ws,
862 payload,
863 payload_len);
864 if (MHD_WEBSOCKET_STATUS_OK != ret)
865 {
866 *streambuf_read_len = current;
867 return ret;
868 }
869 }
870 break;
871
872 /* payload data */
873 case MHD_WebSocket_DecodeStep_PayloadOfDataFrame:
874 case MHD_WebSocket_DecodeStep_PayloadOfControlFrame:
875 {
876 size_t bytes_needed = ws->payload_size - ws->payload_index;
877 size_t bytes_remaining = streambuf_len - current;
878 size_t bytes_to_take = bytes_needed < bytes_remaining ? bytes_needed :
879 bytes_remaining;
880 if (0 != bytes_to_take)
881 {
882 size_t utf8_start = ws->payload_index;
883 char *decode_payload = ws->decode_step ==
884 MHD_WebSocket_DecodeStep_PayloadOfDataFrame ?
885 ws->data_payload_start :
886 ws->control_payload;
887
888 /* copy the new payload data (with unmasking if necessary */
889 MHD_websocket_copy_payload (decode_payload + ws->payload_index,
890 &streambuf [current],
891 bytes_to_take,
892 *((unsigned long *) ws->mask_key),
893 (unsigned long) (ws->payload_index
894 & 0x03));
895 current += bytes_to_take;
896 ws->payload_index += bytes_to_take;
897 if ((MHD_WebSocket_DecodeStep_PayloadOfDataFrame ==
898 ws->decode_step) &&
899 (MHD_WebSocket_Opcode_Text == ws->data_type) ||
900 (MHD_WebSocket_DecodeStep_PayloadOfControlFrame ==
901 ws->decode_step) &&
902 (MHD_WebSocket_Opcode_Close == (ws->frame_header [0] & 0x0f)) &&
903 (2 < ws->payload_index) )
904 {
905 /* RFC 6455 8.1: We need to check the UTF-8 validity */
906 int utf8_step;
907 char*decode_payload_utf8;
908 size_t bytes_to_check;
909 size_t utf8_error_offset = 0;
910 if (MHD_WebSocket_DecodeStep_PayloadOfDataFrame == ws->decode_step)
911 {
912 utf8_step = ws->data_utf8_step;
913 decode_payload_utf8 = decode_payload + utf8_start;
914 bytes_to_check = bytes_to_take;
915 }
916 else
917 {
918 utf8_step = ws->control_utf8_step;
919 if ((MHD_WebSocket_Opcode_Close == (ws->frame_header [0]
920 & 0x0f)) &&
921 (2 > utf8_start) )
922 {
923 /* The first two bytes of the close frame are binary content and */
924 /* must be skipped in the UTF-8 check */
925 utf8_start = 2;
926 utf8_error_offset = 2;
927 }
928 decode_payload_utf8 = decode_payload + utf8_start;
929 bytes_to_check = bytes_to_take - utf8_start;
930 }
931 size_t utf8_check_offset = 0;
932 int utf8_result = MHD_websocket_check_utf8 (decode_payload_utf8,
933 bytes_to_check,
934 &utf8_step,
935 &utf8_check_offset);
936 if (MHD_WebSocket_UTF8Result_Invalid != utf8_result)
937 {
938 /* memorize current validity check step to continue later */
939 ws->data_utf8_step = utf8_step;
940 }
941 else
942 {
943 /* RFC 6455 8.1: We must fail on broken UTF-8 sequence */
944 ws->validity = MHD_WEBSOCKET_VALIDITY_INVALID;
945 if (0 != (ws->flags
946 & MHD_WEBSOCKET_FLAG_GENERATE_CLOSE_FRAMES_ON_ERROR))
947 {
948 MHD_websocket_encode_close (ws,
949 MHD_WEBSOCKET_CLOSEREASON_MALFORMED_UTF8,
950 0,
951 0,
952 payload,
953 payload_len);
954 }
955 *streambuf_read_len = current - bytes_to_take
956 + utf8_check_offset + utf8_error_offset;
957 return MHD_WEBSOCKET_STATUS_UTF8_ENCODING_ERROR;
958 }
959 }
960 }
961 }
962
963 if (ws->payload_size == ws->payload_index)
964 {
965 /* all payload data of the current frame has been received */
966 int ret = MHD_websocket_decode_payload_complete (ws,
967 payload,
968 payload_len);
969 if (MHD_WEBSOCKET_STATUS_OK != ret)
970 {
971 *streambuf_read_len = current;
972 return ret;
973 }
974 }
975 break;
976
977 case MHD_WebSocket_DecodeStep_BrokenStream:
978 *streambuf_read_len = current;
979 return MHD_WEBSOCKET_STATUS_STREAM_BROKEN;
980 }
981 }
982
983 /* Special treatment for zero payload length messages */
984 if (MHD_WebSocket_DecodeStep_HeaderCompleted == ws->decode_step)
985 {
986 int ret = MHD_websocket_decode_header_complete (ws,
987 payload,
988 payload_len);
989 if (MHD_WEBSOCKET_STATUS_OK != ret)
990 {
991 *streambuf_read_len = current;
992 return ret;
993 }
994 }
995 switch (ws->decode_step)
996 {
997 case MHD_WebSocket_DecodeStep_PayloadOfDataFrame:
998 case MHD_WebSocket_DecodeStep_PayloadOfControlFrame:
999 if (ws->payload_size == ws->payload_index)
1000 {
1001 /* all payload data of the current frame has been received */
1002 int ret = MHD_websocket_decode_payload_complete (ws,
1003 payload,
1004 payload_len);
1005 if (MHD_WEBSOCKET_STATUS_OK != ret)
1006 {
1007 *streambuf_read_len = current;
1008 return ret;
1009 }
1010 }
1011 break;
1012 }
1013 *streambuf_read_len = current;
1014
1015 /* more data needed */
1016 return MHD_WEBSOCKET_STATUS_OK;
1017}
1018
1019
1020static int
1021MHD_websocket_decode_header_complete (struct MHD_WebSocketStream*ws,
1022 char**payload,
1023 size_t*payload_len)
1024{
1025 /* assign either to data or control */
1026 char opcode = ws->frame_header [0] & 0x0f;
1027 switch (opcode)
1028 {
1029 case MHD_WebSocket_Opcode_Continuation:
1030 {
1031 /* validate payload size */
1032 size_t new_size_total = ws->payload_size + ws->data_payload_size;
1033 if ((0 != ws->max_payload_size) && (ws->max_payload_size <
1034 new_size_total) )
1035 {
1036 /* RFC 6455 7.4.1 1009: If the message is too big to process, */
1037 /* we may close the connection */
1038 ws->decode_step = MHD_WebSocket_DecodeStep_BrokenStream;
1039 ws->validity = MHD_WEBSOCKET_VALIDITY_INVALID;
1040 if (0 != (ws->flags
1041 & MHD_WEBSOCKET_FLAG_GENERATE_CLOSE_FRAMES_ON_ERROR))
1042 {
1043 MHD_websocket_encode_close (ws,
1044 MHD_WEBSOCKET_CLOSEREASON_MAXIMUM_ALLOWED_PAYLOAD_SIZE_EXCEEDED,
1045 0,
1046 0,
1047 payload,
1048 payload_len);
1049 }
1050 return MHD_WEBSOCKET_STATUS_MAXIMUM_SIZE_EXCEEDED;
1051 }
1052 /* allocate buffer for continued data frame */
1053 char*new_buf = NULL;
1054 if (0 != new_size_total)
1055 {
1056 new_buf = ws->realloc (ws->data_payload, new_size_total + 1);
1057 if (NULL == new_buf)
1058 {
1059 return MHD_WEBSOCKET_STATUS_MEMORY_ERROR;
1060 }
1061 new_buf [new_size_total] = 0;
1062 ws->data_payload_start = &new_buf[ws->data_payload_size];
1063 }
1064 else
1065 {
1066 ws->data_payload_start = new_buf;
1067 }
1068 ws->data_payload = new_buf;
1069 ws->data_payload_size = new_size_total;
1070 }
1071 ws->decode_step = MHD_WebSocket_DecodeStep_PayloadOfDataFrame;
1072 break;
1073
1074 case MHD_WebSocket_Opcode_Text:
1075 case MHD_WebSocket_Opcode_Binary:
1076 /* allocate buffer for data frame */
1077 {
1078 size_t new_size_total = ws->payload_size;
1079 char*new_buf = NULL;
1080 if (0 != new_size_total)
1081 {
1082 new_buf = ws->malloc (new_size_total + 1);
1083 if (NULL == new_buf)
1084 {
1085 return MHD_WEBSOCKET_STATUS_MEMORY_ERROR;
1086 }
1087 new_buf [new_size_total] = 0;
1088 }
1089 ws->data_payload = new_buf;
1090 ws->data_payload_start = new_buf;
1091 ws->data_payload_size = new_size_total;
1092 ws->data_type = opcode;
1093 }
1094 ws->decode_step = MHD_WebSocket_DecodeStep_PayloadOfDataFrame;
1095 break;
1096
1097 case MHD_WebSocket_Opcode_Close:
1098 case MHD_WebSocket_Opcode_Ping:
1099 case MHD_WebSocket_Opcode_Pong:
1100 /* allocate buffer for control frame */
1101 {
1102 size_t new_size_total = ws->payload_size;
1103 char*new_buf = NULL;
1104 if (0 != new_size_total)
1105 {
1106 new_buf = ws->malloc (new_size_total + 1);
1107 if (NULL == new_buf)
1108 {
1109 return MHD_WEBSOCKET_STATUS_MEMORY_ERROR;
1110 }
1111 new_buf[new_size_total] = 0;
1112 }
1113 ws->control_payload = new_buf;
1114 }
1115 ws->decode_step = MHD_WebSocket_DecodeStep_PayloadOfControlFrame;
1116 break;
1117 }
1118
1119 return MHD_WEBSOCKET_STATUS_OK;
1120}
1121
1122
1123static int
1124MHD_websocket_decode_payload_complete (struct MHD_WebSocketStream*ws,
1125 char**payload,
1126 size_t*payload_len)
1127{
1128 /* all payload data of the current frame has been received */
1129 char is_fin = ws->frame_header [0] & 0x80;
1130 if (0 != is_fin)
1131 {
1132 /* the frame is complete */
1133 if (MHD_WebSocket_DecodeStep_PayloadOfDataFrame == ws->decode_step)
1134 {
1135 /* data frame */
1136 char data_type = ws->data_type;
1137 if ((0 != (ws->flags & MHD_WEBSOCKET_FLAG_WANT_FRAGMENTS)) &&
1138 (MHD_WebSocket_Opcode_Continuation == (ws->frame_header [0] & 0x0F)))
1139 {
1140 data_type |= 0x20; /* mark as last fragment */
1141 }
1142 *payload = ws->data_payload;
1143 *payload_len = ws->data_payload_size;
1144 ws->data_payload = 0;
1145 ws->data_payload_start = 0;
1146 ws->data_payload_size = 0;
1147 ws->decode_step = MHD_WebSocket_DecodeStep_Start;
1148 ws->payload_index = 0;
1149 ws->data_type = 0;
1150 ws->frame_header_size = 0;
1151 return data_type;
1152 }
1153 else
1154 {
1155 /* control frame */
1156 *payload = ws->control_payload;
1157 *payload_len = ws->payload_size;
1158 ws->control_payload = 0;
1159 ws->decode_step = MHD_WebSocket_DecodeStep_Start;
1160 ws->payload_index = 0;
1161 ws->frame_header_size = 0;
1162 return (ws->frame_header [0] & 0x0f);
1163 }
1164 }
1165 else if (0 != (ws->flags & MHD_WEBSOCKET_FLAG_WANT_FRAGMENTS))
1166 {
1167 /* RFC 6455 5.4: To allow streaming, the user can choose */
1168 /* to return fragments */
1169 if ((MHD_WebSocket_Opcode_Text == ws->data_type) &&
1170 (MHD_WEBSOCKET_UTF8STEP_NORMAL != ws->data_utf8_step) )
1171 {
1172 /* the last UTF-8 sequence is incomplete, so we keep the start of
1173 that and only return the part before */
1174 size_t given_utf8;
1175 switch (ws->data_utf8_step)
1176 {
1177 /* one byte given */
1178 case MHD_WEBSOCKET_UTF8STEP_UTF2TAIL_1OF1:
1179 case MHD_WEBSOCKET_UTF8STEP_UTF3TAIL1_1OF2:
1180 case MHD_WEBSOCKET_UTF8STEP_UTF3TAIL2_1OF2:
1181 case MHD_WEBSOCKET_UTF8STEP_UTF3TAIL_1OF2:
1182 case MHD_WEBSOCKET_UTF8STEP_UTF4TAIL1_1OF3:
1183 case MHD_WEBSOCKET_UTF8STEP_UTF4TAIL2_1OF3:
1184 case MHD_WEBSOCKET_UTF8STEP_UTF4TAIL_1OF3:
1185 given_utf8 = 1;
1186 break;
1187 /* two bytes given */
1188 case MHD_WEBSOCKET_UTF8STEP_UTF3TAIL_2OF2:
1189 case MHD_WEBSOCKET_UTF8STEP_UTF4TAIL_2OF3:
1190 given_utf8 = 2;
1191 break;
1192 /* three bytes given */
1193 case MHD_WEBSOCKET_UTF8STEP_UTF4TAIL_3OF3:
1194 given_utf8 = 3;
1195 break;
1196 }
1197 size_t new_len = ws->data_payload_size - given_utf8;
1198 if (0 != new_len)
1199 {
1200 char *next_payload = ws->malloc (given_utf8 + 1);
1201 if (NULL == next_payload)
1202 {
1203 return MHD_WEBSOCKET_STATUS_MEMORY_ERROR;
1204 }
1205 memcpy (next_payload,
1206 ws->data_payload_start + ws->payload_index - given_utf8,
1207 given_utf8);
1208 next_payload[given_utf8] = 0;
1209
1210 ws->data_payload[new_len] = 0;
1211 *payload = ws->data_payload;
1212 *payload_len = new_len;
1213 ws->data_payload = next_payload;
1214 ws->data_payload_size = given_utf8;
1215 }
1216 else
1217 {
1218 *payload = NULL;
1219 *payload_len = 0;
1220 }
1221 ws->decode_step = MHD_WebSocket_DecodeStep_Start;
1222 ws->payload_index = 0;
1223 ws->frame_header_size = 0;
1224 return ws->data_type | 0x10; /* mark as fragment */
1225 }
1226 else
1227 {
1228 /* we simply pass the entire data frame */
1229 *payload = ws->data_payload;
1230 *payload_len = ws->data_payload_size;
1231 ws->data_payload = 0;
1232 ws->data_payload_start = 0;
1233 ws->data_payload_size = 0;
1234 ws->decode_step = MHD_WebSocket_DecodeStep_Start;
1235 ws->payload_index = 0;
1236 ws->frame_header_size = 0;
1237 return ws->data_type | 0x10; /* mark as fragment */
1238 }
1239 }
1240 else
1241 {
1242 /* RFC 6455 5.4: We must await a continuation frame to get */
1243 /* the remainder of this data frame */
1244 ws->decode_step = MHD_WebSocket_DecodeStep_Start;
1245 ws->frame_header_size = 0;
1246 ws->payload_index = 0;
1247 return MHD_WEBSOCKET_STATUS_OK;
1248 }
1249}
1250
1251
1252/**
1253 * Splits the received close reason
1254 */
1255_MHD_EXTERN int
1256MHD_websocket_split_close_reason (const char*payload,
1257 size_t payload_len,
1258 unsigned short*reason_code,
1259 const char**reason_utf8,
1260 size_t*reason_utf8_len)
1261{
1262 /* initialize output variables for errors cases */
1263 if (NULL != reason_code)
1264 *reason_code = MHD_WEBSOCKET_CLOSEREASON_NO_REASON;
1265 if (NULL != reason_utf8)
1266 *reason_utf8 = NULL;
1267 if (NULL != reason_utf8_len)
1268 *reason_utf8_len = 0;
1269
1270 /* validate parameters */
1271 if ((NULL == payload) && (0 != payload_len))
1272 return MHD_WEBSOCKET_STATUS_PARAMETER_ERROR;
1273 if (1 == payload_len)
1274 return MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR;
1275 if (125 < payload_len)
1276 return MHD_WEBSOCKET_STATUS_MAXIMUM_SIZE_EXCEEDED;
1277
1278 /* decode reason code */
1279 if (2 > payload_len)
1280 {
1281 if (NULL != reason_code)
1282 *reason_code = MHD_WEBSOCKET_CLOSEREASON_NO_REASON;
1283 }
1284 else
1285 {
1286 if (NULL != reason_code)
1287 *reason_code = htons (*((unsigned short*) payload));
1288 }
1289
1290 /* decode reason text */
1291 if (2 >= payload_len)
1292 {
1293 if (NULL != reason_utf8)
1294 *reason_utf8 = NULL;
1295 if (NULL != reason_utf8_len)
1296 *reason_utf8_len = 0;
1297 }
1298 else
1299 {
1300 if (NULL != reason_utf8)
1301 *reason_utf8 = payload + 2;
1302 if (NULL != reason_utf8_len)
1303 *reason_utf8_len = payload_len - 2;
1304 }
1305
1306 return MHD_WEBSOCKET_STATUS_OK;
1307}
1308
1309
1310/**
1311 * Encodes a text into a websocket text frame
1312 */
1313_MHD_EXTERN int
1314MHD_websocket_encode_text (struct MHD_WebSocketStream*ws,
1315 const char*payload_utf8,
1316 size_t payload_utf8_len,
1317 int fragmentation,
1318 char**frame,
1319 size_t*frame_len,
1320 int*utf8_step)
1321{
1322 /* initialize output variables for errors cases */
1323 if (NULL != frame)
1324 *frame = NULL;
1325 if (NULL != frame_len)
1326 *frame_len = 0;
1327 if ((NULL != utf8_step) &&
1328 ((MHD_WEBSOCKET_FRAGMENTATION_FIRST == fragmentation) ||
1329 (MHD_WEBSOCKET_FRAGMENTATION_NONE == fragmentation) ))
1330 {
1331 /* the old UTF-8 step will be ignored for new fragments */
1332 *utf8_step = MHD_WEBSOCKET_UTF8STEP_NORMAL;
1333 }
1334
1335 /* validate parameters */
1336 if ((NULL == ws) ||
1337 (0 != payload_utf8_len) && (NULL == payload_utf8) ||
1338 (NULL == frame) ||
1339 (NULL == frame_len) ||
1340 (MHD_WEBSOCKET_FRAGMENTATION_NONE > fragmentation) ||
1341 (MHD_WEBSOCKET_FRAGMENTATION_LAST < fragmentation) ||
1342 (MHD_WEBSOCKET_FRAGMENTATION_NONE != fragmentation) && (NULL ==
1343 utf8_step) )
1344 {
1345 return MHD_WEBSOCKET_STATUS_PARAMETER_ERROR;
1346 }
1347
1348 /* check max length */
1349 if ((uint64_t) 0x7FFFFFFFFFFFFFFF < (uint64_t) payload_utf8_len)
1350 {
1351 return MHD_WEBSOCKET_STATUS_MAXIMUM_SIZE_EXCEEDED;
1352 }
1353
1354 /* check UTF-8 */
1355 int utf8_result = MHD_websocket_check_utf8 (payload_utf8,
1356 payload_utf8_len,
1357 utf8_step,
1358 NULL);
1359 if ((MHD_WebSocket_UTF8Result_Invalid == utf8_result) ||
1360 (MHD_WebSocket_UTF8Result_Incomplete == utf8_result) &&
1361 (MHD_WEBSOCKET_FRAGMENTATION_NONE == fragmentation) )
1362 {
1363 return MHD_WEBSOCKET_STATUS_UTF8_ENCODING_ERROR;
1364 }
1365
1366 /* encode data */
1367 return MHD_websocket_encode_data (ws,
1368 payload_utf8,
1369 payload_utf8_len,
1370 fragmentation,
1371 frame,
1372 frame_len,
1373 MHD_WebSocket_Opcode_Text);
1374}
1375
1376
1377/**
1378 * Encodes binary data into a websocket binary frame
1379 */
1380_MHD_EXTERN int
1381MHD_websocket_encode_binary (struct MHD_WebSocketStream*ws,
1382 const char*payload,
1383 size_t payload_len,
1384 int fragmentation,
1385 char**frame,
1386 size_t*frame_len)
1387{
1388 /* initialize output variables for errors cases */
1389 if (NULL != frame)
1390 *frame = NULL;
1391 if (NULL != frame_len)
1392 *frame_len = 0;
1393
1394 /* validate parameters */
1395 if ((NULL == ws) ||
1396 (0 != payload_len) && (NULL == payload) ||
1397 (NULL == frame) ||
1398 (NULL == frame_len) ||
1399 (MHD_WEBSOCKET_FRAGMENTATION_NONE > fragmentation) ||
1400 (MHD_WEBSOCKET_FRAGMENTATION_LAST < fragmentation) )
1401 {
1402 return MHD_WEBSOCKET_STATUS_PARAMETER_ERROR;
1403 }
1404
1405 /* check max length */
1406 if ((uint64_t) 0x7FFFFFFFFFFFFFFF < (uint64_t) payload_len)
1407 {
1408 return MHD_WEBSOCKET_STATUS_MAXIMUM_SIZE_EXCEEDED;
1409 }
1410
1411 return MHD_websocket_encode_data (ws,
1412 payload,
1413 payload_len,
1414 fragmentation,
1415 frame,
1416 frame_len,
1417 MHD_WebSocket_Opcode_Binary);
1418}
1419
1420
1421/**
1422 * Internal function for encoding text/binary data into a websocket frame
1423 */
1424static int
1425MHD_websocket_encode_data (struct MHD_WebSocketStream*ws,
1426 const char*payload,
1427 size_t payload_len,
1428 int fragmentation,
1429 char**frame,
1430 size_t*frame_len,
1431 char opcode)
1432{
1433 /* calculate length and masking */
1434 char is_masked = MHD_websocket_encode_is_masked (ws);
1435 size_t overhead_len = MHD_websocket_encode_overhead_size (ws, payload_len);
1436 size_t total_len = overhead_len + payload_len;
1437 unsigned long mask = 0 != is_masked ? MHD_websocket_generate_mask () : 0;
1438
1439 /* allocate memory */
1440 char*result = ws->malloc (total_len + 1);
1441 if (NULL == result)
1442 return MHD_WEBSOCKET_STATUS_MEMORY_ERROR;
1443 result [total_len] = 0;
1444 *frame = result;
1445 *frame_len = total_len;
1446
1447 /* add the opcode */
1448 switch (fragmentation)
1449 {
1450 case MHD_WEBSOCKET_FRAGMENTATION_NONE:
1451 *(result++) = 0x80 | opcode;
1452 break;
1453 case MHD_WEBSOCKET_FRAGMENTATION_FIRST:
1454 *(result++) = opcode;
1455 break;
1456 case MHD_WEBSOCKET_FRAGMENTATION_FOLLOWING:
1457 *(result++) = MHD_WebSocket_Opcode_Continuation;
1458 break;
1459 case MHD_WEBSOCKET_FRAGMENTATION_LAST:
1460 *(result++) = 0x80 | MHD_WebSocket_Opcode_Continuation;
1461 break;
1462 }
1463
1464 /* add the length */
1465 if (126 > payload_len)
1466 {
1467 *(result++) = is_masked | (char) payload_len;
1468 }
1469 else if (65536 > payload_len)
1470 {
1471 *(result++) = is_masked | 126;
1472 *((unsigned short *) result) = htons ((unsigned short) payload_len);
1473 result += 2;
1474 }
1475 else
1476 {
1477 *(result++) = is_masked | 127;
1478 *((uint64_t *) result) = htonll ((uint64_t) payload_len);
1479 result += 8;
1480
1481 }
1482
1483 /* add the mask */
1484 if (0 != is_masked)
1485 {
1486 *(result++) = ((char *) &mask)[0];
1487 *(result++) = ((char *) &mask)[1];
1488 *(result++) = ((char *) &mask)[2];
1489 *(result++) = ((char *) &mask)[3];
1490 }
1491
1492 /* add the payload */
1493 if (0 != payload_len)
1494 {
1495 MHD_websocket_copy_payload (result,
1496 payload,
1497 payload_len,
1498 mask,
1499 0);
1500 }
1501
1502 return MHD_WEBSOCKET_STATUS_OK;
1503}
1504
1505
1506/**
1507 * Encodes a websocket ping frame
1508 */
1509_MHD_EXTERN int
1510MHD_websocket_encode_ping (struct MHD_WebSocketStream*ws,
1511 const char*payload,
1512 size_t payload_len,
1513 char**frame,
1514 size_t*frame_len)
1515{
1516 /* encode the ping frame */
1517 return MHD_websocket_encode_ping_pong (ws,
1518 payload,
1519 payload_len,
1520 frame,
1521 frame_len,
1522 MHD_WebSocket_Opcode_Ping);
1523}
1524
1525
1526/**
1527 * Encodes a websocket pong frame
1528 */
1529_MHD_EXTERN int
1530MHD_websocket_encode_pong (struct MHD_WebSocketStream*ws,
1531 const char*payload,
1532 size_t payload_len,
1533 char**frame,
1534 size_t*frame_len)
1535{
1536 /* encode the pong frame */
1537 return MHD_websocket_encode_ping_pong (ws,
1538 payload,
1539 payload_len,
1540 frame,
1541 frame_len,
1542 MHD_WebSocket_Opcode_Pong);
1543}
1544
1545
1546/**
1547 * Internal function for encoding ping/pong frames
1548 */
1549static int
1550MHD_websocket_encode_ping_pong (struct MHD_WebSocketStream*ws,
1551 const char*payload,
1552 size_t payload_len,
1553 char**frame,
1554 size_t*frame_len,
1555 char opcode)
1556{
1557 /* initialize output variables for errors cases */
1558 if (NULL != frame)
1559 *frame = NULL;
1560 if (NULL != frame_len)
1561 *frame_len = 0;
1562
1563 /* validate the parameters */
1564 if ((NULL == ws) ||
1565 (0 != payload_len) && (NULL == payload) ||
1566 (NULL == frame) ||
1567 (NULL == frame_len) )
1568 {
1569 return MHD_WEBSOCKET_STATUS_PARAMETER_ERROR;
1570 }
1571
1572 /* RFC 6455 5.5: Control frames may only have up to 125 bytes of payload data */
1573 if (125 < payload_len)
1574 return MHD_WEBSOCKET_STATUS_MAXIMUM_SIZE_EXCEEDED;
1575
1576 /* calculate length and masking */
1577 char is_masked = MHD_websocket_encode_is_masked (ws);
1578 size_t overhead_len = MHD_websocket_encode_overhead_size (ws, payload_len);
1579 size_t total_len = overhead_len + payload_len;
1580 unsigned long mask = is_masked != 0 ? MHD_websocket_generate_mask () : 0;
1581
1582 /* allocate memory */
1583 char*result = ws->malloc (total_len + 1);
1584 if (NULL == result)
1585 return MHD_WEBSOCKET_STATUS_MEMORY_ERROR;
1586 result [total_len] = 0;
1587 *frame = result;
1588 *frame_len = total_len;
1589
1590 /* add the opcode */
1591 *(result++) = 0x80 | opcode;
1592
1593 /* add the length */
1594 *(result++) = is_masked | (char) payload_len;
1595
1596 /* add the mask */
1597 if (0 != is_masked)
1598 {
1599 *(result++) = ((char *) &mask)[0];
1600 *(result++) = ((char *) &mask)[1];
1601 *(result++) = ((char *) &mask)[2];
1602 *(result++) = ((char *) &mask)[3];
1603 }
1604
1605 /* add the payload */
1606 if (0 != payload_len)
1607 {
1608 MHD_websocket_copy_payload (result,
1609 payload,
1610 payload_len,
1611 mask,
1612 0);
1613 }
1614
1615 return MHD_WEBSOCKET_STATUS_OK;
1616}
1617
1618
1619/**
1620 * Encodes a websocket close frame
1621 */
1622_MHD_EXTERN int
1623MHD_websocket_encode_close (struct MHD_WebSocketStream*ws,
1624 unsigned short reason_code,
1625 const char*reason_utf8,
1626 size_t reason_utf8_len,
1627 char**frame,
1628 size_t*frame_len)
1629{
1630 /* initialize output variables for errors cases */
1631 if (NULL != frame)
1632 *frame = NULL;
1633 if (NULL != frame_len)
1634 *frame_len = 0;
1635
1636 /* validate the parameters */
1637 if ((NULL == ws) ||
1638 (0 != reason_utf8_len) && (NULL == reason_utf8) ||
1639 (NULL == frame) ||
1640 (NULL == frame_len) ||
1641 (MHD_WEBSOCKET_CLOSEREASON_NO_REASON != reason_code) && (1000 >
1642 reason_code) ||
1643 (0 != reason_utf8_len) && (MHD_WEBSOCKET_CLOSEREASON_NO_REASON ==
1644 reason_code) )
1645 {
1646 return MHD_WEBSOCKET_STATUS_PARAMETER_ERROR;
1647 }
1648
1649 /* RFC 6455 5.5: Control frames may only have up to 125 bytes of payload data, */
1650 /* but in this case only 123 bytes, because 2 bytes are reserved */
1651 /* for the close reason code. */
1652 if (123 < reason_utf8_len)
1653 return MHD_WEBSOCKET_STATUS_MAXIMUM_SIZE_EXCEEDED;
1654
1655 /* RFC 6455 5.5.1: If close payload data is given, it must be valid UTF-8 */
1656 if (0 != reason_utf8_len)
1657 {
1658 int utf8_result = MHD_websocket_check_utf8 (reason_utf8,
1659 reason_utf8_len,
1660 NULL,
1661 NULL);
1662 if (MHD_WebSocket_UTF8Result_Valid != utf8_result)
1663 return MHD_WEBSOCKET_STATUS_UTF8_ENCODING_ERROR;
1664 }
1665
1666 /* calculate length and masking */
1667 char is_masked = MHD_websocket_encode_is_masked (ws);
1668 size_t payload_len = (MHD_WEBSOCKET_CLOSEREASON_NO_REASON != reason_code ?
1669 2 + reason_utf8_len : 0);
1670 size_t overhead_len = MHD_websocket_encode_overhead_size (ws, payload_len);
1671 size_t total_len = overhead_len + payload_len;
1672 unsigned long mask = is_masked != 0 ? MHD_websocket_generate_mask () : 0;
1673
1674 /* allocate memory */
1675 char*result = ws->malloc (total_len + 1);
1676 if (NULL == result)
1677 return MHD_WEBSOCKET_STATUS_MEMORY_ERROR;
1678 result [total_len] = 0;
1679 *frame = result;
1680 *frame_len = total_len;
1681
1682 /* add the opcode */
1683 *(result++) = 0x88;
1684
1685 /* add the length */
1686 *(result++) = is_masked | (char) payload_len;
1687
1688 /* add the mask */
1689 if (0 != is_masked)
1690 {
1691 *(result++) = ((char *) &mask)[0];
1692 *(result++) = ((char *) &mask)[1];
1693 *(result++) = ((char *) &mask)[2];
1694 *(result++) = ((char *) &mask)[3];
1695 }
1696
1697 /* add the payload */
1698 if (0 != reason_code)
1699 {
1700 /* close reason code */
1701 unsigned short reason_code_nb = htons (reason_code);
1702 MHD_websocket_copy_payload (result,
1703 (const char*) &reason_code_nb,
1704 2,
1705 mask,
1706 0);
1707 result += 2;
1708
1709 /* custom reason payload */
1710 if (0 != reason_utf8_len)
1711 {
1712 MHD_websocket_copy_payload (result,
1713 reason_utf8,
1714 reason_utf8_len,
1715 mask,
1716 2);
1717 }
1718 }
1719
1720 return MHD_WEBSOCKET_STATUS_OK;
1721}
1722
1723
1724/**
1725 * Returns the 0x80 prefix for masked data, 0x00 otherwise
1726 */
1727static char
1728MHD_websocket_encode_is_masked (struct MHD_WebSocketStream*ws)
1729{
1730 return (ws->flags & MHD_WEBSOCKET_FLAG_MASK_SERVERCLIENT) ==
1731 MHD_WEBSOCKET_FLAG_CLIENT ? 0x80 : 0x00;
1732}
1733
1734
1735/**
1736 * Calculates the size of the overhead in bytes
1737 */
1738static char
1739MHD_websocket_encode_overhead_size (struct MHD_WebSocketStream*ws,
1740 size_t payload_len)
1741{
1742 return 2 + (MHD_websocket_encode_is_masked (ws) != 0 ? 4 : 0) + (125 <
1743 payload_len ?
1744 (65535 <
1745 payload_len
1746 ? 8 : 2) : 0);
1747}
1748
1749
1750/**
1751 * Copies the payload to the destination (using mask)
1752 */
1753static void
1754MHD_websocket_copy_payload (char*dst,
1755 const char*src,
1756 size_t len,
1757 unsigned long mask,
1758 unsigned long mask_offset)
1759{
1760 if (0 != len)
1761 {
1762 if (0 == mask)
1763 {
1764 /* when the mask is zero, we can just copy the data */
1765 memcpy (dst, src, len);
1766 }
1767 else
1768 {
1769 /* mask is used */
1770 char mask_[4];
1771 *((unsigned long *) mask_) = mask;
1772 for (size_t i = 0; i < len; ++i)
1773 {
1774 dst[i] = src[i] ^ mask_[(i + mask_offset) & 3];
1775 }
1776 }
1777 }
1778}
1779
1780
1781/**
1782 * Checks a UTF-8 sequence
1783 */
1784static int
1785MHD_websocket_check_utf8 (const char*buf,
1786 size_t buf_len,
1787 int*utf8_step,
1788 size_t*buf_offset)
1789{
1790 int utf8_step_ = (NULL != utf8_step) ? *utf8_step :
1791 MHD_WEBSOCKET_UTF8STEP_NORMAL;
1792
1793 for (size_t i = 0; i < buf_len; ++i)
1794 {
1795 unsigned char character = (unsigned char) buf[i];
1796 switch (utf8_step_)
1797 {
1798 case MHD_WEBSOCKET_UTF8STEP_NORMAL:
1799 if ((0x00 <= character) && (0x7F >= character))
1800 {
1801 /* RFC 3629 4: single byte UTF-8 sequence */
1802 /* (nothing to do here) */
1803 }
1804 else if ((0xC2 <= character) && (0xDF >= character))
1805 {
1806 /* RFC 3629 4: two byte UTF-8 sequence */
1807 utf8_step_ = MHD_WEBSOCKET_UTF8STEP_UTF2TAIL_1OF1;
1808 }
1809 else if (0xE0 == character)
1810 {
1811 /* RFC 3629 4: three byte UTF-8 sequence, but the second byte must be 0xA0-0xBF */
1812 utf8_step_ = MHD_WEBSOCKET_UTF8STEP_UTF3TAIL1_1OF2;
1813 }
1814 else if (0xED == character)
1815 {
1816 /* RFC 3629 4: three byte UTF-8 sequence, but the second byte must be 0x80-0x9F */
1817 utf8_step_ = MHD_WEBSOCKET_UTF8STEP_UTF3TAIL2_1OF2;
1818 }
1819 else if ((0xE1 <= character) && (0xEC >= character) ||
1820 (0xEE <= character) && (0xEF >= character) )
1821 {
1822 /* RFC 3629 4: three byte UTF-8 sequence, both tail bytes must be 0x80-0xBF */
1823 utf8_step_ = MHD_WEBSOCKET_UTF8STEP_UTF3TAIL_1OF2;
1824 }
1825 else if (0xF0 == character)
1826 {
1827 /* RFC 3629 4: four byte UTF-8 sequence, but the second byte must be 0x90-0xBF */
1828 utf8_step_ = MHD_WEBSOCKET_UTF8STEP_UTF4TAIL1_1OF3;
1829 }
1830 else if (0xF4 == character)
1831 {
1832 /* RFC 3629 4: four byte UTF-8 sequence, but the second byte must be 0x80-0x8F */
1833 utf8_step_ = MHD_WEBSOCKET_UTF8STEP_UTF4TAIL2_1OF3;
1834 }
1835 else if ((0xF1 <= character) && (0xF3 >= character))
1836 {
1837 /* RFC 3629 4: four byte UTF-8 sequence, all three tail bytes must be 0x80-0xBF */
1838 utf8_step_ = MHD_WEBSOCKET_UTF8STEP_UTF4TAIL_1OF3;
1839 }
1840 else
1841 {
1842 /* RFC 3629 4: Invalid UTF-8 byte */
1843 if (NULL != buf_offset)
1844 *buf_offset = i;
1845 return MHD_WebSocket_UTF8Result_Invalid;
1846 }
1847 break;
1848
1849 case MHD_WEBSOCKET_UTF8STEP_UTF3TAIL1_1OF2:
1850 if ((0xA0 <= character) && (0xBF >= character))
1851 {
1852 /* RFC 3629 4: Second byte of three byte UTF-8 sequence */
1853 utf8_step_ = MHD_WEBSOCKET_UTF8STEP_UTF3TAIL_2OF2;
1854 }
1855 else
1856 {
1857 /* RFC 3629 4: Invalid UTF-8 byte */
1858 if (NULL != buf_offset)
1859 *buf_offset = i;
1860 return MHD_WebSocket_UTF8Result_Invalid;
1861 }
1862 break;
1863
1864 case MHD_WEBSOCKET_UTF8STEP_UTF3TAIL2_1OF2:
1865 if ((0x80 <= character) && (0x9F >= character))
1866 {
1867 /* RFC 3629 4: Second byte of three byte UTF-8 sequence */
1868 utf8_step_ = MHD_WEBSOCKET_UTF8STEP_UTF3TAIL_2OF2;
1869 }
1870 else
1871 {
1872 /* RFC 3629 4: Invalid UTF-8 byte */
1873 if (NULL != buf_offset)
1874 *buf_offset = i;
1875 return MHD_WebSocket_UTF8Result_Invalid;
1876 }
1877 break;
1878
1879 case MHD_WEBSOCKET_UTF8STEP_UTF3TAIL_1OF2:
1880 if ((0x80 <= character) && (0xBF >= character))
1881 {
1882 /* RFC 3629 4: Second byte of three byte UTF-8 sequence */
1883 utf8_step_ = MHD_WEBSOCKET_UTF8STEP_UTF3TAIL_2OF2;
1884 }
1885 else
1886 {
1887 /* RFC 3629 4: Invalid UTF-8 byte */
1888 if (NULL != buf_offset)
1889 *buf_offset = i;
1890 return MHD_WebSocket_UTF8Result_Invalid;
1891 }
1892 break;
1893
1894 case MHD_WEBSOCKET_UTF8STEP_UTF4TAIL1_1OF3:
1895 if ((0x90 <= character) && (0xBF >= character))
1896 {
1897 /* RFC 3629 4: Second byte of four byte UTF-8 sequence */
1898 utf8_step_ = MHD_WEBSOCKET_UTF8STEP_UTF4TAIL_2OF3;
1899 }
1900 else
1901 {
1902 /* RFC 3629 4: Invalid UTF-8 byte */
1903 if (NULL != buf_offset)
1904 *buf_offset = i;
1905 return MHD_WebSocket_UTF8Result_Invalid;
1906 }
1907 break;
1908
1909 case MHD_WEBSOCKET_UTF8STEP_UTF4TAIL2_1OF3:
1910 if ((0x80 <= character) && (0x8F >= character))
1911 {
1912 /* RFC 3629 4: Second byte of four byte UTF-8 sequence */
1913 utf8_step_ = MHD_WEBSOCKET_UTF8STEP_UTF4TAIL_2OF3;
1914 }
1915 else
1916 {
1917 /* RFC 3629 4: Invalid UTF-8 byte */
1918 if (NULL != buf_offset)
1919 *buf_offset = i;
1920 return MHD_WebSocket_UTF8Result_Invalid;
1921 }
1922 break;
1923
1924 case MHD_WEBSOCKET_UTF8STEP_UTF4TAIL_1OF3:
1925 if ((0x80 <= character) && (0xBF >= character))
1926 {
1927 /* RFC 3629 4: Second byte of four byte UTF-8 sequence */
1928 utf8_step_ = MHD_WEBSOCKET_UTF8STEP_UTF4TAIL_2OF3;
1929 }
1930 else
1931 {
1932 /* RFC 3629 4: Invalid UTF-8 byte */
1933 if (NULL != buf_offset)
1934 *buf_offset = i;
1935 return MHD_WebSocket_UTF8Result_Invalid;
1936 }
1937 break;
1938
1939 case MHD_WEBSOCKET_UTF8STEP_UTF4TAIL_2OF3:
1940 if ((0x80 <= character) && (0xBF >= character))
1941 {
1942 /* RFC 3629 4: Third byte of four byte UTF-8 sequence */
1943 utf8_step_ = MHD_WEBSOCKET_UTF8STEP_UTF4TAIL_3OF3;
1944 }
1945 else
1946 {
1947 /* RFC 3629 4: Invalid UTF-8 byte */
1948 if (NULL != buf_offset)
1949 *buf_offset = i;
1950 return MHD_WebSocket_UTF8Result_Invalid;
1951 }
1952 break;
1953
1954 /* RFC 3629 4: Second byte of two byte UTF-8 sequence */
1955 case MHD_WEBSOCKET_UTF8STEP_UTF2TAIL_1OF1:
1956 /* RFC 3629 4: Third byte of three byte UTF-8 sequence */
1957 case MHD_WEBSOCKET_UTF8STEP_UTF3TAIL_2OF2:
1958 /* RFC 3629 4: Fourth byte of four byte UTF-8 sequence */
1959 case MHD_WEBSOCKET_UTF8STEP_UTF4TAIL_3OF3:
1960 if ((0x80 <= character) && (0xBF >= character))
1961 {
1962 utf8_step_ = MHD_WEBSOCKET_UTF8STEP_NORMAL;
1963 }
1964 else
1965 {
1966 /* RFC 3629 4: Invalid UTF-8 byte */
1967 if (NULL != buf_offset)
1968 *buf_offset = i;
1969 return MHD_WebSocket_UTF8Result_Invalid;
1970 }
1971 break;
1972
1973 default:
1974 /* Invalid last step...? */
1975 if (NULL != buf_offset)
1976 *buf_offset = i;
1977 return MHD_WebSocket_UTF8Result_Invalid;
1978 }
1979 }
1980
1981 /* return values */
1982 if (NULL != utf8_step)
1983 *utf8_step = utf8_step_;
1984 if (NULL != buf_offset)
1985 *buf_offset = buf_len;
1986 if (MHD_WEBSOCKET_UTF8STEP_NORMAL != utf8_step_)
1987 {
1988 return MHD_WebSocket_UTF8Result_Incomplete;
1989 }
1990 return MHD_WebSocket_UTF8Result_Valid;
1991}
1992
1993
1994/**
1995 * Calls srand in the scope of MHD to set the seed
1996 * for the random number generator used for masking.
1997 */
1998_MHD_EXTERN int
1999MHD_websocket_srand (unsigned long seed)
2000{
2001 srand (seed);
2002
2003 return MHD_WEBSOCKET_STATUS_OK;
2004}
2005
2006
2007/**
2008 * Generates a mask for masking by calling
2009 * a random number generator.
2010 */
2011static unsigned long
2012MHD_websocket_generate_mask ()
2013{
2014 unsigned char mask_[4];
2015 mask_ [0] = (unsigned char) (rand () & 0xFF);
2016 mask_ [1] = (unsigned char) (rand () & 0xFF);
2017 mask_ [2] = (unsigned char) (rand () & 0xFF);
2018 mask_ [3] = (unsigned char) (rand () & 0xFF);
2019
2020 return *((unsigned long *) mask_);
2021}
2022
2023
2024/**
2025 * Calls the malloc function associated with the websocket steam
2026 */
2027_MHD_EXTERN void*
2028MHD_websocket_malloc (struct MHD_WebSocketStream*ws,
2029 size_t len)
2030{
2031 if (NULL == ws)
2032 {
2033 return NULL;
2034 }
2035
2036 return ws->malloc (len);
2037}
2038
2039
2040/**
2041 * Calls the realloc function associated with the websocket steam
2042 */
2043_MHD_EXTERN void*
2044MHD_websocket_realloc (struct MHD_WebSocketStream*ws,
2045 void*cls,
2046 size_t len)
2047{
2048 if (NULL == ws)
2049 {
2050 return NULL;
2051 }
2052
2053 return ws->realloc (cls, len);
2054}
2055
2056
2057/**
2058 * Calls the free function associated with the websocket steam
2059 */
2060_MHD_EXTERN int
2061MHD_websocket_free (struct MHD_WebSocketStream*ws,
2062 void*cls)
2063{
2064 if (NULL == ws)
2065 {
2066 return MHD_WEBSOCKET_STATUS_PARAMETER_ERROR;
2067 }
2068
2069 ws->free (cls);
2070
2071 return MHD_WEBSOCKET_STATUS_OK;
2072}
diff --git a/src/microhttpd_ws/sha1.c b/src/microhttpd_ws/sha1.c
new file mode 100644
index 00000000..910c1bdb
--- /dev/null
+++ b/src/microhttpd_ws/sha1.c
@@ -0,0 +1,420 @@
1/* sha1.c - Functions to compute SHA1 message digest of files or
2 memory blocks according to the NIST specification FIPS-180-1.
3
4 Copyright (C) 2000-2021 Free Software Foundation, Inc.
5
6 This program is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
9 later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software Foundation,
18 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
19
20/* Written by Scott G. Miller
21 Credits:
22 Robert Klep <robert@ilse.nl> -- Expansion function fix
23*/
24
25/*#include <config.h>*/
26
27#include "sha1.h"
28
29#include <stddef.h>
30#include <string.h>
31
32#if USE_UNLOCKED_IO
33# include "unlocked-io.h"
34#endif
35
36#ifdef WORDS_BIGENDIAN
37# define SWAP(n) (n)
38#else
39# define SWAP(n) \
40 (((n) << 24) | (((n) & 0xff00) << 8) | (((n) >> 8) & 0xff00) | ((n) >> 24))
41#endif
42
43#define BLOCKSIZE 4096
44#if BLOCKSIZE % 64 != 0
45# error "invalid BLOCKSIZE"
46#endif
47
48/* This array contains the bytes used to pad the buffer to the next
49 64-byte boundary. (RFC 1321, 3.1: Step 1) */
50static const unsigned char fillbuf[64] = { 0x80, 0 /* , 0, 0, ... */ };
51
52
53/* Take a pointer to a 160 bit block of data (five 32 bit ints) and
54 initialize it to the start constants of the SHA1 algorithm. This
55 must be called before using hash in the call to sha1_hash. */
56void
57sha1_init_ctx (struct sha1_ctx *ctx)
58{
59 ctx->A = 0x67452301;
60 ctx->B = 0xefcdab89;
61 ctx->C = 0x98badcfe;
62 ctx->D = 0x10325476;
63 ctx->E = 0xc3d2e1f0;
64
65 ctx->total[0] = ctx->total[1] = 0;
66 ctx->buflen = 0;
67}
68
69
70/* Put result from CTX in first 20 bytes following RESBUF. The result
71 must be in little endian byte order.
72
73 IMPORTANT: On some systems it is required that RESBUF is correctly
74 aligned for a 32-bit value. */
75void *
76sha1_read_ctx (const struct sha1_ctx *ctx, void *resbuf)
77{
78 ((sha1_uint32 *) resbuf)[0] = SWAP (ctx->A);
79 ((sha1_uint32 *) resbuf)[1] = SWAP (ctx->B);
80 ((sha1_uint32 *) resbuf)[2] = SWAP (ctx->C);
81 ((sha1_uint32 *) resbuf)[3] = SWAP (ctx->D);
82 ((sha1_uint32 *) resbuf)[4] = SWAP (ctx->E);
83
84 return resbuf;
85}
86
87
88/* Process the remaining bytes in the internal buffer and the usual
89 prolog according to the standard and write the result to RESBUF.
90
91 IMPORTANT: On some systems it is required that RESBUF is correctly
92 aligned for a 32-bit value. */
93void *
94sha1_finish_ctx (struct sha1_ctx *ctx, void *resbuf)
95{
96 /* Take yet unprocessed bytes into account. */
97 sha1_uint32 bytes = ctx->buflen;
98 size_t size = (bytes < 56) ? 64 / 4 : 64 * 2 / 4;
99
100 /* Now count remaining bytes. */
101 ctx->total[0] += bytes;
102 if (ctx->total[0] < bytes)
103 ++ctx->total[1];
104
105 /* Put the 64-bit file length in *bits* at the end of the buffer. */
106 ctx->buffer[size - 2] = SWAP ((ctx->total[1] << 3) | (ctx->total[0] >> 29));
107 ctx->buffer[size - 1] = SWAP (ctx->total[0] << 3);
108
109 memcpy (&((char *) ctx->buffer)[bytes], fillbuf, (size - 2) * 4 - bytes);
110
111 /* Process last bytes. */
112 sha1_process_block (ctx->buffer, size * 4, ctx);
113
114 return sha1_read_ctx (ctx, resbuf);
115}
116
117
118/* Compute SHA1 message digest for bytes read from STREAM. The
119 resulting message digest number will be written into the 16 bytes
120 beginning at RESBLOCK. */
121int
122sha1_stream (FILE *stream, void *resblock)
123{
124 struct sha1_ctx ctx;
125 char buffer[BLOCKSIZE + 72];
126 size_t sum;
127
128 /* Initialize the computation context. */
129 sha1_init_ctx (&ctx);
130
131 /* Iterate over full file contents. */
132 while (1)
133 {
134 /* We read the file in blocks of BLOCKSIZE bytes. One call of the
135 computation function processes the whole buffer so that with the
136 next round of the loop another block can be read. */
137 size_t n;
138 sum = 0;
139
140 /* Read block. Take care for partial reads. */
141 while (1)
142 {
143 n = fread (buffer + sum, 1, BLOCKSIZE - sum, stream);
144
145 sum += n;
146
147 if (sum == BLOCKSIZE)
148 break;
149
150 if (n == 0)
151 {
152 /* Check for the error flag IFF N == 0, so that we don't
153 exit the loop after a partial read due to e.g., EAGAIN
154 or EWOULDBLOCK. */
155 if (ferror (stream))
156 return 1;
157 goto process_partial_block;
158 }
159
160 /* We've read at least one byte, so ignore errors. But always
161 check for EOF, since feof may be true even though N > 0.
162 Otherwise, we could end up calling fread after EOF. */
163 if (feof (stream))
164 goto process_partial_block;
165 }
166
167 /* Process buffer with BLOCKSIZE bytes. Note that
168 BLOCKSIZE % 64 == 0
169 */
170 sha1_process_block (buffer, BLOCKSIZE, &ctx);
171 }
172
173process_partial_block:;
174
175 /* Process any remaining bytes. */
176 if (sum > 0)
177 sha1_process_bytes (buffer, sum, &ctx);
178
179 /* Construct result in desired memory. */
180 sha1_finish_ctx (&ctx, resblock);
181 return 0;
182}
183
184
185/* Compute SHA1 message digest for LEN bytes beginning at BUFFER. The
186 result is always in little endian byte order, so that a byte-wise
187 output yields to the wanted ASCII representation of the message
188 digest. */
189void *
190sha1_buffer (const char *buffer, size_t len, void *resblock)
191{
192 struct sha1_ctx ctx;
193
194 /* Initialize the computation context. */
195 sha1_init_ctx (&ctx);
196
197 /* Process whole buffer but last len % 64 bytes. */
198 sha1_process_bytes (buffer, len, &ctx);
199
200 /* Put result in desired memory area. */
201 return sha1_finish_ctx (&ctx, resblock);
202}
203
204
205void
206sha1_process_bytes (const void *buffer, size_t len, struct sha1_ctx *ctx)
207{
208 /* When we already have some bits in our internal buffer concatenate
209 both inputs first. */
210 if (ctx->buflen != 0)
211 {
212 size_t left_over = ctx->buflen;
213 size_t add = 128 - left_over > len ? len : 128 - left_over;
214
215 memcpy (&((char *) ctx->buffer)[left_over], buffer, add);
216 ctx->buflen += add;
217
218 if (ctx->buflen > 64)
219 {
220 sha1_process_block (ctx->buffer, ctx->buflen & ~63, ctx);
221
222 ctx->buflen &= 63;
223 /* The regions in the following copy operation cannot overlap. */
224 memcpy (ctx->buffer,
225 &((char *) ctx->buffer)[(left_over + add) & ~63],
226 ctx->buflen);
227 }
228
229 buffer = (const char *) buffer + add;
230 len -= add;
231 }
232
233 /* Process available complete blocks. */
234 if (len >= 64)
235 {
236#if ! _STRING_ARCH_unaligned
237# define alignof(type) offsetof (struct { char c; type x; }, x)
238# define UNALIGNED_P(p) (((size_t) p) % alignof (sha1_uint32) != 0)
239 if (UNALIGNED_P (buffer))
240 while (len > 64)
241 {
242 sha1_process_block (memcpy (ctx->buffer, buffer, 64), 64, ctx);
243 buffer = (const char *) buffer + 64;
244 len -= 64;
245 }
246 else
247#endif
248 {
249 sha1_process_block (buffer, len & ~63, ctx);
250 buffer = (const char *) buffer + (len & ~63);
251 len &= 63;
252 }
253 }
254
255 /* Move remaining bytes in internal buffer. */
256 if (len > 0)
257 {
258 size_t left_over = ctx->buflen;
259
260 memcpy (&((char *) ctx->buffer)[left_over], buffer, len);
261 left_over += len;
262 if (left_over >= 64)
263 {
264 sha1_process_block (ctx->buffer, 64, ctx);
265 left_over -= 64;
266 memmove (ctx->buffer, &ctx->buffer[16], left_over);
267 }
268 ctx->buflen = left_over;
269 }
270}
271
272
273/* --- Code below is the primary difference between md5.c and sha1.c --- */
274
275/* SHA1 round constants */
276#define K1 0x5a827999
277#define K2 0x6ed9eba1
278#define K3 0x8f1bbcdc
279#define K4 0xca62c1d6
280
281/* Round functions. Note that F2 is the same as F4. */
282#define F1(B,C,D) ( D ^ ( B & ( C ^ D ) ) )
283#define F2(B,C,D) (B ^ C ^ D)
284#define F3(B,C,D) ( ( B & C ) | ( D & ( B | C ) ) )
285#define F4(B,C,D) (B ^ C ^ D)
286
287/* Process LEN bytes of BUFFER, accumulating context into CTX.
288 It is assumed that LEN % 64 == 0.
289 Most of this code comes from GnuPG's cipher/sha1.c. */
290
291void
292sha1_process_block (const void *buffer, size_t len, struct sha1_ctx *ctx)
293{
294 const sha1_uint32 *words = (const sha1_uint32*) buffer;
295 size_t nwords = len / sizeof (sha1_uint32);
296 const sha1_uint32 *endp = words + nwords;
297 sha1_uint32 x[16];
298 sha1_uint32 a = ctx->A;
299 sha1_uint32 b = ctx->B;
300 sha1_uint32 c = ctx->C;
301 sha1_uint32 d = ctx->D;
302 sha1_uint32 e = ctx->E;
303
304 /* First increment the byte count. RFC 1321 specifies the possible
305 length of the file up to 2^64 bits. Here we only compute the
306 number of bytes. Do a double word increment. */
307 ctx->total[0] += len;
308 ctx->total[1] += ((len >> 31) >> 1) + (ctx->total[0] < len);
309
310#define rol(x, n) (((x) << (n)) | ((sha1_uint32) (x) >> (32 - (n))))
311
312#define M(I) ( tm = x[I&0x0f] ^ x[(I-14)&0x0f] \
313 ^ x[(I-8)&0x0f] ^ x[(I-3)&0x0f] \
314 , (x[I&0x0f] = rol(tm, 1)) )
315
316#define R(A,B,C,D,E,F,K,M) do { E += rol( A, 5 ) \
317 + F( B, C, D ) \
318 + K \
319 + M; \
320 B = rol( B, 30 ); \
321 } while(0)
322
323 while (words < endp)
324 {
325 sha1_uint32 tm;
326 int t;
327 for (t = 0; t < 16; t++)
328 {
329 x[t] = SWAP (*words);
330 words++;
331 }
332
333 R (a, b, c, d, e, F1, K1, x[ 0]);
334 R (e, a, b, c, d, F1, K1, x[ 1]);
335 R (d, e, a, b, c, F1, K1, x[ 2]);
336 R (c, d, e, a, b, F1, K1, x[ 3]);
337 R (b, c, d, e, a, F1, K1, x[ 4]);
338 R (a, b, c, d, e, F1, K1, x[ 5]);
339 R (e, a, b, c, d, F1, K1, x[ 6]);
340 R (d, e, a, b, c, F1, K1, x[ 7]);
341 R (c, d, e, a, b, F1, K1, x[ 8]);
342 R (b, c, d, e, a, F1, K1, x[ 9]);
343 R (a, b, c, d, e, F1, K1, x[10]);
344 R (e, a, b, c, d, F1, K1, x[11]);
345 R (d, e, a, b, c, F1, K1, x[12]);
346 R (c, d, e, a, b, F1, K1, x[13]);
347 R (b, c, d, e, a, F1, K1, x[14]);
348 R (a, b, c, d, e, F1, K1, x[15]);
349 R (e, a, b, c, d, F1, K1, M (16) );
350 R (d, e, a, b, c, F1, K1, M (17) );
351 R (c, d, e, a, b, F1, K1, M (18) );
352 R (b, c, d, e, a, F1, K1, M (19) );
353 R (a, b, c, d, e, F2, K2, M (20) );
354 R (e, a, b, c, d, F2, K2, M (21) );
355 R (d, e, a, b, c, F2, K2, M (22) );
356 R (c, d, e, a, b, F2, K2, M (23) );
357 R (b, c, d, e, a, F2, K2, M (24) );
358 R (a, b, c, d, e, F2, K2, M (25) );
359 R (e, a, b, c, d, F2, K2, M (26) );
360 R (d, e, a, b, c, F2, K2, M (27) );
361 R (c, d, e, a, b, F2, K2, M (28) );
362 R (b, c, d, e, a, F2, K2, M (29) );
363 R (a, b, c, d, e, F2, K2, M (30) );
364 R (e, a, b, c, d, F2, K2, M (31) );
365 R (d, e, a, b, c, F2, K2, M (32) );
366 R (c, d, e, a, b, F2, K2, M (33) );
367 R (b, c, d, e, a, F2, K2, M (34) );
368 R (a, b, c, d, e, F2, K2, M (35) );
369 R (e, a, b, c, d, F2, K2, M (36) );
370 R (d, e, a, b, c, F2, K2, M (37) );
371 R (c, d, e, a, b, F2, K2, M (38) );
372 R (b, c, d, e, a, F2, K2, M (39) );
373 R (a, b, c, d, e, F3, K3, M (40) );
374 R (e, a, b, c, d, F3, K3, M (41) );
375 R (d, e, a, b, c, F3, K3, M (42) );
376 R (c, d, e, a, b, F3, K3, M (43) );
377 R (b, c, d, e, a, F3, K3, M (44) );
378 R (a, b, c, d, e, F3, K3, M (45) );
379 R (e, a, b, c, d, F3, K3, M (46) );
380 R (d, e, a, b, c, F3, K3, M (47) );
381 R (c, d, e, a, b, F3, K3, M (48) );
382 R (b, c, d, e, a, F3, K3, M (49) );
383 R (a, b, c, d, e, F3, K3, M (50) );
384 R (e, a, b, c, d, F3, K3, M (51) );
385 R (d, e, a, b, c, F3, K3, M (52) );
386 R (c, d, e, a, b, F3, K3, M (53) );
387 R (b, c, d, e, a, F3, K3, M (54) );
388 R (a, b, c, d, e, F3, K3, M (55) );
389 R (e, a, b, c, d, F3, K3, M (56) );
390 R (d, e, a, b, c, F3, K3, M (57) );
391 R (c, d, e, a, b, F3, K3, M (58) );
392 R (b, c, d, e, a, F3, K3, M (59) );
393 R (a, b, c, d, e, F4, K4, M (60) );
394 R (e, a, b, c, d, F4, K4, M (61) );
395 R (d, e, a, b, c, F4, K4, M (62) );
396 R (c, d, e, a, b, F4, K4, M (63) );
397 R (b, c, d, e, a, F4, K4, M (64) );
398 R (a, b, c, d, e, F4, K4, M (65) );
399 R (e, a, b, c, d, F4, K4, M (66) );
400 R (d, e, a, b, c, F4, K4, M (67) );
401 R (c, d, e, a, b, F4, K4, M (68) );
402 R (b, c, d, e, a, F4, K4, M (69) );
403 R (a, b, c, d, e, F4, K4, M (70) );
404 R (e, a, b, c, d, F4, K4, M (71) );
405 R (d, e, a, b, c, F4, K4, M (72) );
406 R (c, d, e, a, b, F4, K4, M (73) );
407 R (b, c, d, e, a, F4, K4, M (74) );
408 R (a, b, c, d, e, F4, K4, M (75) );
409 R (e, a, b, c, d, F4, K4, M (76) );
410 R (d, e, a, b, c, F4, K4, M (77) );
411 R (c, d, e, a, b, F4, K4, M (78) );
412 R (b, c, d, e, a, F4, K4, M (79) );
413
414 a = ctx->A += a;
415 b = ctx->B += b;
416 c = ctx->C += c;
417 d = ctx->D += d;
418 e = ctx->E += e;
419 }
420}
diff --git a/src/microhttpd_ws/sha1.h b/src/microhttpd_ws/sha1.h
new file mode 100644
index 00000000..be0d190b
--- /dev/null
+++ b/src/microhttpd_ws/sha1.h
@@ -0,0 +1,145 @@
1/* Declarations of functions and data types used for SHA1 sum
2 library functions.
3 Copyright (C) 2000-2021 Free Software Foundation, Inc.
4
5 This program is free software; you can redistribute it and/or modify it
6 under the terms of the GNU General Public License as published by the
7 Free Software Foundation; either version 3, or (at your option) any
8 later version.
9
10 This program 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
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software Foundation,
17 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
18
19#ifndef SHA1_H
20# define SHA1_H 1
21
22#include <stdio.h>
23
24#if defined HAVE_LIMITS_H || _LIBC
25# include <limits.h>
26#endif
27
28/*#include "ansidecl.h"*/
29
30/* The following contortions are an attempt to use the C preprocessor
31 to determine an unsigned integral type that is 32 bits wide. An
32 alternative approach is to use autoconf's AC_CHECK_SIZEOF macro, but
33 doing that would require that the configure script compile and *run*
34 the resulting executable. Locally running cross-compiled executables
35 is usually not possible. */
36
37#ifdef _LIBC
38# include <sys/types.h>
39typedef u_int32_t sha1_uint32;
40typedef uintptr_t sha1_uintptr;
41#elif defined (HAVE_SYS_TYPES_H) && defined (HAVE_STDINT_H)
42#include <stdint.h>
43#include <sys/types.h>
44typedef uint32_t sha1_uint32;
45typedef uintptr_t sha1_uintptr;
46#else
47# define INT_MAX_32_BITS 2147483647
48
49/* If UINT_MAX isn't defined, assume it's a 32-bit type.
50 This should be valid for all systems GNU cares about because
51 that doesn't include 16-bit systems, and only modern systems
52 (that certainly have <limits.h>) have 64+-bit integral types. */
53
54# ifndef INT_MAX
55# define INT_MAX INT_MAX_32_BITS
56# endif
57
58# if INT_MAX == INT_MAX_32_BITS
59typedef unsigned int sha1_uint32;
60# else
61# if SHRT_MAX == INT_MAX_32_BITS
62typedef unsigned short sha1_uint32;
63# else
64# if LONG_MAX == INT_MAX_32_BITS
65typedef unsigned long sha1_uint32;
66# else
67/* The following line is intended to evoke an error.
68 Using #error is not portable enough. */
69"Cannot determine unsigned 32-bit data type."
70# endif
71# endif
72# endif
73#endif
74
75#ifdef __cplusplus
76extern "C" {
77#endif
78
79/* Structure to save state of computation between the single steps. */
80struct sha1_ctx
81{
82 sha1_uint32 A;
83 sha1_uint32 B;
84 sha1_uint32 C;
85 sha1_uint32 D;
86 sha1_uint32 E;
87
88 sha1_uint32 total[2];
89 sha1_uint32 buflen;
90 sha1_uint32 buffer[32];
91};
92
93
94/* Initialize structure containing state of computation. */
95extern void sha1_init_ctx (struct sha1_ctx *ctx);
96
97/* Starting with the result of former calls of this function (or the
98 initialization function update the context for the next LEN bytes
99 starting at BUFFER.
100 It is necessary that LEN is a multiple of 64!!! */
101extern void sha1_process_block (const void *buffer, size_t len,
102 struct sha1_ctx *ctx);
103
104/* Starting with the result of former calls of this function (or the
105 initialization function update the context for the next LEN bytes
106 starting at BUFFER.
107 It is NOT required that LEN is a multiple of 64. */
108extern void sha1_process_bytes (const void *buffer, size_t len,
109 struct sha1_ctx *ctx);
110
111/* Process the remaining bytes in the buffer and put result from CTX
112 in first 20 bytes following RESBUF. The result is always in little
113 endian byte order, so that a byte-wise output yields to the wanted
114 ASCII representation of the message digest.
115
116 IMPORTANT: On some systems it is required that RESBUF be correctly
117 aligned for a 32 bits value. */
118extern void *sha1_finish_ctx (struct sha1_ctx *ctx, void *resbuf);
119
120
121/* Put result from CTX in first 20 bytes following RESBUF. The result is
122 always in little endian byte order, so that a byte-wise output yields
123 to the wanted ASCII representation of the message digest.
124
125 IMPORTANT: On some systems it is required that RESBUF is correctly
126 aligned for a 32 bits value. */
127extern void *sha1_read_ctx (const struct sha1_ctx *ctx, void *resbuf);
128
129
130/* Compute SHA1 message digest for bytes read from STREAM. The
131 resulting message digest number will be written into the 20 bytes
132 beginning at RESBLOCK. */
133extern int sha1_stream (FILE *stream, void *resblock);
134
135/* Compute SHA1 message digest for LEN bytes beginning at BUFFER. The
136 result is always in little endian byte order, so that a byte-wise
137 output yields to the wanted ASCII representation of the message
138 digest. */
139extern void *sha1_buffer (const char *buffer, size_t len, void *resblock);
140
141#ifdef __cplusplus
142}
143#endif
144
145#endif
diff --git a/src/microhttpd_ws/test_websocket.c b/src/microhttpd_ws/test_websocket.c
new file mode 100644
index 00000000..7e0cf4d6
--- /dev/null
+++ b/src/microhttpd_ws/test_websocket.c
@@ -0,0 +1,8983 @@
1/*
2 This file is part of libmicrohttpd
3 Copyright (C) 2021 David Gausmann
4
5 libmicrohttpd is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 libmicrohttpd is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with libmicrohttpd; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19*/
20/**
21 * @file test_websocket.c
22 * @brief Testcase for WebSocket decoding/encoding
23 * @author David Gausmann
24 */
25#include "microhttpd.h"
26#include "microhttpd_ws.h"
27#include <stdlib.h>
28#include <string.h>
29#include <stdio.h>
30#include <time.h>
31
32int disable_alloc = 0;
33size_t open_allocs = 0;
34
35/**
36 * Custom `malloc()` function used for memory tests
37 */
38static void*
39test_malloc (size_t buf_len)
40{
41 if (0 != disable_alloc)
42 return NULL;
43 void*result = malloc (buf_len);
44 if (NULL != result)
45 ++open_allocs;
46 return result;
47}
48
49
50/**
51 * Custom `realloc()` function used for memory tests
52 */
53static void*
54test_realloc (void*buf, size_t buf_len)
55{
56 if (0 != disable_alloc)
57 return NULL;
58 void*result = realloc (buf, buf_len);
59 if ((NULL != result) && (NULL == buf))
60 ++open_allocs;
61 return result;
62}
63
64
65/**
66 * Custom `free()` function used for memory tests
67 */
68static void
69test_free (void*buf)
70{
71 if (NULL != buf)
72 --open_allocs;
73 free (buf);
74}
75
76
77/**
78 * Helper function which allocates a big amount of data
79 */
80static void
81allocate_length_test_data (char**buf1,
82 char**buf2,
83 size_t buf_len,
84 const char*buf1_prefix,
85 size_t buf1_prefix_len)
86{
87 if (NULL != *buf1)
88 free (*buf1);
89 if (NULL != *buf2)
90 free (*buf2);
91 *buf1 = (char*) malloc (buf_len + buf1_prefix_len);
92 *buf2 = (char*) malloc (buf_len);
93 if ((NULL == buf1) || (NULL == buf2))
94 return;
95 memcpy (*buf1,
96 buf1_prefix,
97 buf1_prefix_len);
98 for (size_t i = 0; i < buf_len; i += 64)
99 {
100 size_t bytes_to_copy = buf_len - i;
101 if (64 < bytes_to_copy)
102 bytes_to_copy = 64;
103 memcpy (*buf1 + i + buf1_prefix_len,
104 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-",
105 bytes_to_copy);
106 memcpy (*buf2 + i,
107 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-",
108 bytes_to_copy);
109 }
110}
111
112
113/**
114 * Helper function which performs a single decoder test
115 */
116static int
117test_decode_single (unsigned int test_line,
118 int flags, size_t max_payload_size, size_t decode_count,
119 size_t buf_step,
120 const char*buf, size_t buf_len,
121 const char*expected_payload, size_t expected_payload_len,
122 int expected_return, int expected_valid, size_t
123 expected_streambuf_read_len)
124{
125 struct MHD_WebSocketStream *ws = NULL;
126 int ret = MHD_WEBSOCKET_STATUS_OK;
127
128 /* initialize stream */
129 ret = MHD_websocket_stream_init (&ws, flags, max_payload_size);
130 if (MHD_WEBSOCKET_STATUS_OK != ret)
131 {
132 fprintf (stderr,
133 "Allocation failed for decode test in line %u.\n",
134 (unsigned int) test_line);
135 return 1;
136 }
137
138 /* perform decoding in a loop */
139 size_t streambuf_read_len = 0;
140 size_t payload_len = 0;
141 char*payload = NULL;
142 for (size_t i = 0; i < decode_count; ++i)
143 {
144 size_t streambuf_read_len_ = 0;
145 size_t bytes_to_take = buf_len - streambuf_read_len;
146 if ((0 != buf_step) && (buf_step < bytes_to_take))
147 bytes_to_take = buf_step;
148 ret = MHD_websocket_decode (ws, buf + streambuf_read_len, bytes_to_take,
149 &streambuf_read_len_, &payload, &payload_len);
150 streambuf_read_len += streambuf_read_len_;
151 if (i + 1 < decode_count)
152 {
153 if (payload)
154 {
155 MHD_websocket_free (ws, payload);
156 payload = NULL;
157 payload_len = 0;
158 }
159 }
160 }
161
162 /* check the (last) result */
163 if (ret != expected_return)
164 {
165 fprintf (stderr,
166 "Decode test failed in line %u: The return value should be %d, but is %d\n",
167 (unsigned int) test_line,
168 (int) expected_return,
169 (int) ret);
170 MHD_websocket_free (ws, payload);
171 MHD_websocket_stream_free (ws);
172 return 1;
173 }
174 if (payload_len != expected_payload_len)
175 {
176 fprintf (stderr,
177 "Decode test failed in line %u: The payload_len should be %u, but is %u\n",
178 (unsigned int) test_line,
179 (unsigned int) expected_payload_len,
180 (unsigned int) payload_len);
181 MHD_websocket_free (ws, payload);
182 MHD_websocket_stream_free (ws);
183 return 1;
184 }
185 if (0 != payload_len)
186 {
187 if (NULL == payload)
188 {
189 fprintf (stderr,
190 "Decode test failed in line %u: The payload is NULL\n",
191 (unsigned int) test_line);
192 MHD_websocket_free (ws, payload);
193 MHD_websocket_stream_free (ws);
194 return 1;
195 }
196 else if (NULL == expected_payload)
197 {
198 fprintf (stderr,
199 "Decode test failed in line %u: The expected_payload is NULL (wrong test declaration)\n",
200 (unsigned int) test_line);
201 MHD_websocket_free (ws, payload);
202 MHD_websocket_stream_free (ws);
203 return 1;
204 }
205 else if (0 != memcmp (payload, expected_payload, payload_len))
206 {
207 fprintf (stderr,
208 "Decode test failed in line %u: The payload differs from the expected_payload\n",
209 (unsigned int) test_line);
210 MHD_websocket_free (ws, payload);
211 MHD_websocket_stream_free (ws);
212 return 1;
213 }
214 }
215 else
216 {
217 if (NULL != payload)
218 {
219 fprintf (stderr,
220 "Decode test failed in line %u: The payload is not NULL, but payload_len is 0\n",
221 (unsigned int) test_line);
222 MHD_websocket_free (ws, payload);
223 MHD_websocket_stream_free (ws);
224 return 1;
225 }
226 else if (NULL != expected_payload)
227 {
228 fprintf (stderr,
229 "Decode test failed in line %u: The expected_payload is not NULL, but expected_payload_len is 0 (wrong test declaration)\n",
230 (unsigned int) test_line);
231 MHD_websocket_free (ws, payload);
232 MHD_websocket_stream_free (ws);
233 return 1;
234 }
235 }
236 if (streambuf_read_len != expected_streambuf_read_len)
237 {
238 fprintf (stderr,
239 "Decode test failed in line %u: The streambuf_read_len should be %u, but is %u\n",
240 (unsigned int) test_line,
241 (unsigned int) expected_streambuf_read_len,
242 (unsigned int) streambuf_read_len);
243 MHD_websocket_free (ws, payload);
244 MHD_websocket_stream_free (ws);
245 return 1;
246 }
247 ret = MHD_websocket_stream_is_valid (ws);
248 if (ret != expected_valid)
249 {
250 fprintf (stderr,
251 "Decode test failed in line %u: The stream validity should be %u, but is %u\n",
252 (unsigned int) test_line,
253 (int) expected_valid,
254 (int) ret);
255 MHD_websocket_free (ws, payload);
256 MHD_websocket_stream_free (ws);
257 return 1;
258 }
259
260 /* cleanup */
261 MHD_websocket_free (ws, payload);
262 MHD_websocket_stream_free (ws);
263
264 return 0;
265}
266
267
268/**
269 * Test procedure for `MHD_websocket_stream_init()` and
270 * `MHD_websocket_stream_init()2`
271 */
272int
273test_inits ()
274{
275 int failed = 0;
276 struct MHD_WebSocketStream*ws;
277 int ret;
278
279 /*
280 ------------------------------------------------------------------------------
281 All valid flags
282 ------------------------------------------------------------------------------
283 */
284 /* Regular test: all valid flags for init */
285 for (int i = 0; i < 7; ++i)
286 {
287 ws = NULL;
288 ret = MHD_websocket_stream_init (&ws,
289 i,
290 0);
291 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
292 (NULL == ws) )
293 {
294 fprintf (stderr,
295 "Init test failed in line %u for flags %d.\n",
296 (unsigned int) __LINE__,
297 (int) i);
298 ++failed;
299 }
300 if (NULL != ws)
301 {
302 MHD_websocket_stream_free (ws);
303 ws = NULL;
304 }
305 }
306 /* Regular test: all valid flags for init2 */
307 for (int i = 0; i < 7; ++i)
308 {
309 ws = NULL;
310 ret = MHD_websocket_stream_init2 (&ws,
311 i,
312 0,
313 test_malloc,
314 test_realloc,
315 test_free);
316 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
317 (NULL == ws) )
318 {
319 fprintf (stderr,
320 "Init test failed in line %u for flags %d.\n",
321 (unsigned int) __LINE__,
322 (int) i);
323 ++failed;
324 }
325 if (NULL != ws)
326 {
327 MHD_websocket_stream_free (ws);
328 ws = NULL;
329 }
330 }
331 /* Fail test: Invalid flags for init */
332 for (int i = 4; i < 32; ++i)
333 {
334 int flags = 1 << i;
335 ws = NULL;
336 ret = MHD_websocket_stream_init (&ws,
337 flags,
338 0);
339 if ((MHD_WEBSOCKET_STATUS_PARAMETER_ERROR != ret) ||
340 (NULL != ws) )
341 {
342 fprintf (stderr,
343 "Init test failed in line %u for invalid flags %d.\n",
344 (unsigned int) __LINE__,
345 (int) flags);
346 ++failed;
347 }
348 if (NULL != ws)
349 {
350 MHD_websocket_stream_free (ws);
351 ws = NULL;
352 }
353 }
354 /* Fail test: Invalid flag for init2 */
355 for (int i = 4; i < 32; ++i)
356 {
357 int flags = 1 << i;
358 ws = NULL;
359 ret = MHD_websocket_stream_init2 (&ws,
360 flags,
361 0,
362 test_malloc,
363 test_realloc,
364 test_free);
365 if ((MHD_WEBSOCKET_STATUS_PARAMETER_ERROR != ret) ||
366 (NULL != ws) )
367 {
368 fprintf (stderr,
369 "Init test failed in line %u for invalid flags %d.\n",
370 (unsigned int) __LINE__,
371 (int) flags);
372 ++failed;
373 }
374 if (NULL != ws)
375 {
376 MHD_websocket_stream_free (ws);
377 ws = NULL;
378 }
379 }
380
381 /*
382 ------------------------------------------------------------------------------
383 max_payload_size
384 ------------------------------------------------------------------------------
385 */
386 /* Regular test: max_payload_size = 0 for init */
387 ws = NULL;
388 ret = MHD_websocket_stream_init (&ws,
389 MHD_WEBSOCKET_FLAG_SERVER
390 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
391 0);
392 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
393 (NULL == ws) )
394 {
395 fprintf (stderr,
396 "Init test failed in line %u for max_payload_size 0.\n",
397 (unsigned int) __LINE__);
398 ++failed;
399 }
400 if (NULL != ws)
401 {
402 MHD_websocket_stream_free (ws);
403 ws = NULL;
404 }
405 /* Regular test: max_payload_size = 0 for init2 */
406 ws = NULL;
407 ret = MHD_websocket_stream_init2 (&ws,
408 MHD_WEBSOCKET_FLAG_SERVER
409 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
410 0,
411 test_malloc,
412 test_realloc,
413 test_free);
414 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
415 (NULL == ws) )
416 {
417 fprintf (stderr,
418 "Init test failed in line %u for max_payload_size 0.\n",
419 (unsigned int) __LINE__);
420 ++failed;
421 }
422 if (NULL != ws)
423 {
424 MHD_websocket_stream_free (ws);
425 ws = NULL;
426 }
427 /* Edge test (success): max_payload_size = 1 for init */
428 ws = NULL;
429 ret = MHD_websocket_stream_init (&ws,
430 MHD_WEBSOCKET_FLAG_SERVER
431 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
432 1);
433 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
434 (NULL == ws) )
435 {
436 fprintf (stderr,
437 "Init test failed in line %u for max_payload_size 1.\n",
438 (unsigned int) __LINE__);
439 ++failed;
440 }
441 if (NULL != ws)
442 {
443 MHD_websocket_stream_free (ws);
444 ws = NULL;
445 }
446 /* Edge test (success): max_payload_size = 1 for init2 */
447 ws = NULL;
448 ret = MHD_websocket_stream_init2 (&ws,
449 MHD_WEBSOCKET_FLAG_SERVER
450 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
451 1,
452 test_malloc,
453 test_realloc,
454 test_free);
455 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
456 (NULL == ws) )
457 {
458 fprintf (stderr,
459 "Init test failed in line %u for max_payload_size 1.\n",
460 (unsigned int) __LINE__);
461 ++failed;
462 }
463 if (NULL != ws)
464 {
465 MHD_websocket_stream_free (ws);
466 ws = NULL;
467 }
468 /* Regular test: max_payload_size = 1000 for init */
469 ws = NULL;
470 ret = MHD_websocket_stream_init (&ws,
471 MHD_WEBSOCKET_FLAG_SERVER
472 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
473 1000);
474 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
475 (NULL == ws) )
476 {
477 fprintf (stderr,
478 "Init test failed in line %u for max_payload_size 1000.\n",
479 (unsigned int) __LINE__);
480 ++failed;
481 }
482 if (NULL != ws)
483 {
484 MHD_websocket_stream_free (ws);
485 ws = NULL;
486 }
487 /* Regular test: max_payload_size = 1000 for init2 */
488 ws = NULL;
489 ret = MHD_websocket_stream_init2 (&ws,
490 MHD_WEBSOCKET_FLAG_SERVER
491 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
492 1000,
493 test_malloc,
494 test_realloc,
495 test_free);
496 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
497 (NULL == ws) )
498 {
499 fprintf (stderr,
500 "Init test failed in line %u for max_payload_size 1000.\n",
501 (unsigned int) __LINE__);
502 ++failed;
503 }
504 if (NULL != ws)
505 {
506 MHD_websocket_stream_free (ws);
507 ws = NULL;
508 }
509 /* Edge test (success): max_payload_size = 0x7FFFFFFFFFFFFFFF for init */
510 ws = NULL;
511 ret = MHD_websocket_stream_init (&ws,
512 MHD_WEBSOCKET_FLAG_SERVER
513 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
514 (uint64_t) 0x7FFFFFFFFFFFFFFF);
515 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
516 (NULL == ws) )
517 {
518 fprintf (stderr,
519 "Init test failed in line %u for max_payload_size 0x7FFFFFFFFFFFFFFF.\n",
520 (unsigned int) __LINE__);
521 ++failed;
522 }
523 if (NULL != ws)
524 {
525 MHD_websocket_stream_free (ws);
526 ws = NULL;
527 }
528 /* Edge test (success): max_payload_size = 0x7FFFFFFFFFFFFFFF for init2 */
529 ws = NULL;
530 ret = MHD_websocket_stream_init2 (&ws,
531 MHD_WEBSOCKET_FLAG_SERVER
532 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
533 (uint64_t) 0x7FFFFFFFFFFFFFFF,
534 test_malloc,
535 test_realloc,
536 test_free);
537 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
538 (NULL == ws) )
539 {
540 fprintf (stderr,
541 "Init test failed in line %u for max_payload_size 0x7FFFFFFFFFFFFFFF.\n",
542 (unsigned int) __LINE__);
543 ++failed;
544 }
545 if (NULL != ws)
546 {
547 MHD_websocket_stream_free (ws);
548 ws = NULL;
549 }
550 /* Edge test (fail): max_payload_size = 0x8000000000000000 for init */
551 ws = NULL;
552 ret = MHD_websocket_stream_init (&ws,
553 MHD_WEBSOCKET_FLAG_SERVER
554 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
555 (uint64_t) 0x8000000000000000);
556 if ((MHD_WEBSOCKET_STATUS_PARAMETER_ERROR != ret) ||
557 (NULL != ws) )
558 {
559 fprintf (stderr,
560 "Init test failed in line %u for max_payload_size 0x8000000000000000.\n",
561 (unsigned int) __LINE__);
562 ++failed;
563 }
564 if (NULL != ws)
565 {
566 MHD_websocket_stream_free (ws);
567 ws = NULL;
568 }
569 /* Edge test (fail): max_payload_size = 0x8000000000000000 for init2 */
570 ws = NULL;
571 ret = MHD_websocket_stream_init2 (&ws,
572 MHD_WEBSOCKET_FLAG_SERVER
573 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
574 (uint64_t) 0x8000000000000000,
575 test_malloc,
576 test_realloc,
577 test_free);
578 if ((MHD_WEBSOCKET_STATUS_PARAMETER_ERROR != ret) ||
579 (NULL != ws) )
580 {
581 fprintf (stderr,
582 "Init test failed in line %u for max_payload_size 0x8000000000000000.\n",
583 (unsigned int) __LINE__);
584 ++failed;
585 }
586 if (NULL != ws)
587 {
588 MHD_websocket_stream_free (ws);
589 ws = NULL;
590 }
591
592 /*
593 ------------------------------------------------------------------------------
594 Missing parameters
595 ------------------------------------------------------------------------------
596 */
597 /* Fail test: websocket stream variable missing for init */
598 ws = NULL;
599 ret = MHD_websocket_stream_init (NULL,
600 MHD_WEBSOCKET_FLAG_SERVER
601 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
602 0);
603 if ((MHD_WEBSOCKET_STATUS_PARAMETER_ERROR != ret) ||
604 (NULL != ws) )
605 {
606 fprintf (stderr,
607 "Init test failed in line %u.\n",
608 (unsigned int) __LINE__);
609 ++failed;
610 }
611 if (NULL != ws)
612 {
613 MHD_websocket_stream_free (ws);
614 ws = NULL;
615 }
616 /* Fail test: websocket stream variable missing for init2 */
617 ws = NULL;
618 ret = MHD_websocket_stream_init2 (NULL,
619 MHD_WEBSOCKET_FLAG_SERVER
620 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
621 0,
622 test_malloc,
623 test_realloc,
624 test_free);
625 if ((MHD_WEBSOCKET_STATUS_PARAMETER_ERROR != ret) ||
626 (NULL != ws) )
627 {
628 fprintf (stderr,
629 "Init test failed in line %u.\n",
630 (unsigned int) __LINE__);
631 ++failed;
632 }
633 if (NULL != ws)
634 {
635 MHD_websocket_stream_free (ws);
636 ws = NULL;
637 }
638 /* Fail test: malloc missing for init2 */
639 ws = NULL;
640 ret = MHD_websocket_stream_init2 (&ws,
641 MHD_WEBSOCKET_FLAG_SERVER
642 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
643 0,
644 NULL,
645 test_realloc,
646 test_free);
647 if ((MHD_WEBSOCKET_STATUS_PARAMETER_ERROR != ret) ||
648 (NULL != ws) )
649 {
650 fprintf (stderr,
651 "Init test failed in line %u.\n",
652 (unsigned int) __LINE__);
653 ++failed;
654 }
655 if (NULL != ws)
656 {
657 MHD_websocket_stream_free (ws);
658 ws = NULL;
659 }
660 /* Fail test: realloc missing for init2 */
661 ws = NULL;
662 ret = MHD_websocket_stream_init2 (&ws,
663 MHD_WEBSOCKET_FLAG_SERVER
664 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
665 0,
666 test_malloc,
667 NULL,
668 test_free);
669 if ((MHD_WEBSOCKET_STATUS_PARAMETER_ERROR != ret) ||
670 (NULL != ws) )
671 {
672 fprintf (stderr,
673 "Init test failed in line %u.\n",
674 (unsigned int) __LINE__);
675 ++failed;
676 }
677 if (NULL != ws)
678 {
679 MHD_websocket_stream_free (ws);
680 ws = NULL;
681 }
682 /* Fail test: free missing for init2 */
683 ws = NULL;
684 ret = MHD_websocket_stream_init2 (&ws,
685 MHD_WEBSOCKET_FLAG_SERVER
686 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
687 0,
688 test_malloc,
689 test_realloc,
690 NULL);
691 if ((MHD_WEBSOCKET_STATUS_PARAMETER_ERROR != ret) ||
692 (NULL != ws) )
693 {
694 fprintf (stderr,
695 "Init test failed in line %u.\n",
696 (unsigned int) __LINE__);
697 ++failed;
698 }
699 if (NULL != ws)
700 {
701 MHD_websocket_stream_free (ws);
702 ws = NULL;
703 }
704
705 return failed != 0 ? 0x01 : 0x00;
706}
707
708
709/**
710 * Test procedure for `MHD_websocket_create_accept()`
711 */
712int
713test_accept ()
714{
715 int failed = 0;
716 char accept_key[29];
717 int ret;
718
719 /*
720 ------------------------------------------------------------------------------
721 accepting
722 ------------------------------------------------------------------------------
723 */
724 /* Regular test: Test case from RFC6455 4.2.2 */
725 memset (accept_key, 0, 29);
726 ret = MHD_websocket_create_accept ("dGhlIHNhbXBsZSBub25jZQ==",
727 accept_key);
728 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
729 (0 != memcmp (accept_key, "s3pPLMBiTxaQ9kYGzzhZRbK+xOo=", 29)))
730 {
731 fprintf (stderr,
732 "Accept test failed in line %u.\n",
733 (unsigned int) __LINE__);
734 ++failed;
735 }
736
737 /*
738 ------------------------------------------------------------------------------
739 Missing parameters
740 ------------------------------------------------------------------------------
741 */
742 /* Fail test: missing sec-key value */
743 memset (accept_key, 0, 29);
744 ret = MHD_websocket_create_accept (NULL,
745 accept_key);
746 if (MHD_WEBSOCKET_STATUS_PARAMETER_ERROR != ret)
747 {
748 fprintf (stderr,
749 "Accept test failed in line %u.\n",
750 (unsigned int) __LINE__);
751 ++failed;
752 }
753 /* Fail test: missing accept variable */
754 memset (accept_key, 0, 29);
755 ret = MHD_websocket_create_accept ("dGhlIHNhbXBsZSBub25jZQ==",
756 NULL);
757 if (MHD_WEBSOCKET_STATUS_PARAMETER_ERROR != ret)
758 {
759 fprintf (stderr,
760 "Accept test failed in line %u.\n",
761 (unsigned int) __LINE__);
762 ++failed;
763 }
764
765 return failed != 0 ? 0x02 : 0x00;
766}
767
768
769/**
770 * Test procedure for `MHD_websocket_decode()`
771 */
772int
773test_decodes ()
774{
775 int failed = 0;
776 char *buf1 = NULL, *buf2 = NULL;
777
778 /*
779 ------------------------------------------------------------------------------
780 text frame
781 ------------------------------------------------------------------------------
782 */
783 /* Regular test: Masked text frame from RFC 6455, must succeed for server */
784 failed += test_decode_single (__LINE__,
785 MHD_WEBSOCKET_FLAG_SERVER
786 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
787 0,
788 1,
789 0,
790 "\x81\x85\x37\xfa\x21\x3d\x7f\x9f\x4d\x51\x58",
791 11,
792 "Hello",
793 5,
794 MHD_WEBSOCKET_STATUS_TEXT_FRAME,
795 MHD_WEBSOCKET_VALIDITY_VALID,
796 11);
797 /* Regular test: Unmasked text frame from RFC 6455, must succeed for client */
798 failed += test_decode_single (__LINE__,
799 MHD_WEBSOCKET_FLAG_CLIENT
800 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
801 0,
802 1,
803 0,
804 "\x81\x05\x48\x65\x6c\x6c\x6f",
805 7,
806 "Hello",
807 5,
808 MHD_WEBSOCKET_STATUS_TEXT_FRAME,
809 MHD_WEBSOCKET_VALIDITY_VALID,
810 7);
811 /* Fail test: Unmasked text frame from RFC 6455, must fail for server */
812 failed += test_decode_single (__LINE__,
813 MHD_WEBSOCKET_FLAG_SERVER
814 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
815 0,
816 1,
817 0,
818 "\x81\x05\x48\x65\x6c\x6c\x6f",
819 7,
820 NULL,
821 0,
822 MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR,
823 MHD_WEBSOCKET_VALIDITY_INVALID,
824 1);
825 /* Fail test: Masked text frame from RFC 6455, must fail for client */
826 failed += test_decode_single (__LINE__,
827 MHD_WEBSOCKET_FLAG_CLIENT
828 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
829 0,
830 1,
831 0,
832 "\x81\x85\x37\xfa\x21\x3d\x7f\x9f\x4d\x51\x58",
833 11,
834 NULL,
835 0,
836 MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR,
837 MHD_WEBSOCKET_VALIDITY_INVALID,
838 1);
839 /* Regular test: Text frame with UTF-8 sequence */
840 failed += test_decode_single (__LINE__,
841 MHD_WEBSOCKET_FLAG_SERVER
842 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
843 0,
844 1,
845 0,
846 "\x81\x90\x00\x00\x00\x00" "This is my n"
847 "\xC3\xB6" "te",
848 22,
849 "This is my n" "\xC3\xB6" "te",
850 16,
851 MHD_WEBSOCKET_STATUS_TEXT_FRAME,
852 MHD_WEBSOCKET_VALIDITY_VALID,
853 22);
854 /* Fail test: Text frame with with invalid UTF-8 */
855 failed += test_decode_single (__LINE__,
856 MHD_WEBSOCKET_FLAG_SERVER
857 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
858 0,
859 1,
860 0,
861 "\x81\x8F\x00\x00\x00\x00" "This is my n" "\xFF"
862 "te",
863 21,
864 NULL,
865 0,
866 MHD_WEBSOCKET_STATUS_UTF8_ENCODING_ERROR,
867 MHD_WEBSOCKET_VALIDITY_INVALID,
868 18);
869 /* Fail test: Text frame with broken UTF-8 sequence */
870 failed += test_decode_single (__LINE__,
871 MHD_WEBSOCKET_FLAG_SERVER
872 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
873 0,
874 1,
875 0,
876 "\x81\x8F\x00\x00\x00\x00" "This is my n" "\xC3"
877 "te",
878 21,
879 NULL,
880 0,
881 MHD_WEBSOCKET_STATUS_UTF8_ENCODING_ERROR,
882 MHD_WEBSOCKET_VALIDITY_INVALID,
883 19);
884 /* Regular test: Text frame without payload and mask (caller = server) */
885 failed += test_decode_single (__LINE__,
886 MHD_WEBSOCKET_FLAG_SERVER
887 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
888 0,
889 1,
890 0,
891 "\x81\x80\x01\x02\x03\x04",
892 6,
893 NULL,
894 0,
895 MHD_WEBSOCKET_STATUS_TEXT_FRAME,
896 MHD_WEBSOCKET_VALIDITY_VALID,
897 6);
898 /* Fail test: Text frame without payload and no mask (caller = server) */
899 failed += test_decode_single (__LINE__,
900 MHD_WEBSOCKET_FLAG_SERVER
901 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
902 0,
903 1,
904 0,
905 "\x81\x00",
906 2,
907 NULL,
908 0,
909 MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR,
910 MHD_WEBSOCKET_VALIDITY_INVALID,
911 1);
912 /* Regular test: Text frame without payload and mask (caller = client) */
913 failed += test_decode_single (__LINE__,
914 MHD_WEBSOCKET_FLAG_CLIENT
915 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
916 0,
917 1,
918 0,
919 "\x81\x00",
920 2,
921 NULL,
922 0,
923 MHD_WEBSOCKET_STATUS_TEXT_FRAME,
924 MHD_WEBSOCKET_VALIDITY_VALID,
925 2);
926 /* Fail test: Text frame without payload and no mask (caller = client) */
927 failed += test_decode_single (__LINE__,
928 MHD_WEBSOCKET_FLAG_CLIENT
929 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
930 0,
931 1,
932 0,
933 "\x81\x80\x01\x02\x03\x04",
934 6,
935 NULL,
936 0,
937 MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR,
938 MHD_WEBSOCKET_VALIDITY_INVALID,
939 1);
940
941 /*
942 ------------------------------------------------------------------------------
943 binary frame
944 ------------------------------------------------------------------------------
945 */
946 /* Regular test: Masked binary frame (decoder = server) */
947 failed += test_decode_single (__LINE__,
948 MHD_WEBSOCKET_FLAG_SERVER
949 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
950 0,
951 1,
952 0,
953 "\x82\x85\x37\xfa\x21\x3d\x7f\x9f\x4d\x51\x58",
954 11,
955 "Hello",
956 5,
957 MHD_WEBSOCKET_STATUS_BINARY_FRAME,
958 MHD_WEBSOCKET_VALIDITY_VALID,
959 11);
960 /* Regular test: Unmasked binary frame (decoder = client) */
961 failed += test_decode_single (__LINE__,
962 MHD_WEBSOCKET_FLAG_CLIENT
963 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
964 0,
965 1,
966 0,
967 "\x82\x05\x48\x65\x6c\x6c\x6f",
968 7,
969 "Hello",
970 5,
971 MHD_WEBSOCKET_STATUS_BINARY_FRAME,
972 MHD_WEBSOCKET_VALIDITY_VALID,
973 7);
974 /* Fail test: Unmasked binary frame (decoder = server) */
975 failed += test_decode_single (__LINE__,
976 MHD_WEBSOCKET_FLAG_SERVER
977 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
978 0,
979 1,
980 0,
981 "\x82\x05\x48\x65\x6c\x6c\x6f",
982 7,
983 NULL,
984 0,
985 MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR,
986 MHD_WEBSOCKET_VALIDITY_INVALID,
987 1);
988 /* Fail test: Masked binary frame (decoder = client) */
989 failed += test_decode_single (__LINE__,
990 MHD_WEBSOCKET_FLAG_CLIENT
991 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
992 0,
993 1,
994 0,
995 "\x82\x85\x37\xfa\x21\x3d\x7f\x9f\x4d\x51\x58",
996 11,
997 NULL,
998 0,
999 MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR,
1000 MHD_WEBSOCKET_VALIDITY_INVALID,
1001 1);
1002 /* Regular test: Binary frame without payload */
1003 failed += test_decode_single (__LINE__,
1004 MHD_WEBSOCKET_FLAG_SERVER
1005 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
1006 0,
1007 1,
1008 0,
1009 "\x82\x80\x00\x00\x00\x00",
1010 6,
1011 NULL,
1012 0,
1013 MHD_WEBSOCKET_STATUS_BINARY_FRAME,
1014 MHD_WEBSOCKET_VALIDITY_VALID,
1015 6);
1016 /* Regular test: Fragmented binary frame without payload */
1017 failed += test_decode_single (__LINE__,
1018 MHD_WEBSOCKET_FLAG_SERVER
1019 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
1020 0,
1021 1,
1022 0,
1023 "\x02\x80\x00\x00\x00\x00\x80\x80\x00\x00\x00\x00",
1024 12,
1025 NULL,
1026 0,
1027 MHD_WEBSOCKET_STATUS_BINARY_FRAME,
1028 MHD_WEBSOCKET_VALIDITY_VALID,
1029 12);
1030 /* Regular test: Fragmented binary frame without payload, fragments to the caller, 1st call */
1031 failed += test_decode_single (__LINE__,
1032 MHD_WEBSOCKET_FLAG_SERVER
1033 | MHD_WEBSOCKET_FLAG_WANT_FRAGMENTS,
1034 0,
1035 1,
1036 0,
1037 "\x02\x80\x00\x00\x00\x00\x80\x80\x00\x00\x00\x00",
1038 12,
1039 NULL,
1040 0,
1041 MHD_WEBSOCKET_STATUS_BINARY_FRAGMENT,
1042 MHD_WEBSOCKET_VALIDITY_VALID,
1043 6);
1044 /* Regular test: Fragmented binary frame without payload, fragments to the caller, 2nd call */
1045 failed += test_decode_single (__LINE__,
1046 MHD_WEBSOCKET_FLAG_SERVER
1047 | MHD_WEBSOCKET_FLAG_WANT_FRAGMENTS,
1048 0,
1049 2,
1050 0,
1051 "\x02\x80\x00\x00\x00\x00\x80\x80\x00\x00\x00\x00",
1052 12,
1053 NULL,
1054 0,
1055 MHD_WEBSOCKET_STATUS_BINARY_LAST_FRAGMENT,
1056 MHD_WEBSOCKET_VALIDITY_VALID,
1057 12);
1058 /* Regular test: Fragmented binary frame wit payload */
1059 failed += test_decode_single (__LINE__,
1060 MHD_WEBSOCKET_FLAG_SERVER
1061 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
1062 0,
1063 1,
1064 0,
1065 "\x02\x83\x00\x00\x00\x00\x01\x02\x03\x80\x83\x00\x00\x00\x00\x04\x05\x06",
1066 18,
1067 "\x01\x02\x03\x04\x05\x06",
1068 6,
1069 MHD_WEBSOCKET_STATUS_BINARY_FRAME,
1070 MHD_WEBSOCKET_VALIDITY_VALID,
1071 18);
1072 /* Regular test: Fragmented binary frame with payload, fragments to the caller, 1st call */
1073 failed += test_decode_single (__LINE__,
1074 MHD_WEBSOCKET_FLAG_SERVER
1075 | MHD_WEBSOCKET_FLAG_WANT_FRAGMENTS,
1076 0,
1077 1,
1078 0,
1079 "\x02\x83\x00\x00\x00\x00\x01\x02\x03\x80\x83\x00\x00\x00\x00\x04\x05\x06",
1080 18,
1081 "\x01\x02\x03",
1082 3,
1083 MHD_WEBSOCKET_STATUS_BINARY_FRAGMENT,
1084 MHD_WEBSOCKET_VALIDITY_VALID,
1085 9);
1086 /* Regular test: Fragmented binary frame without payload, fragments to the caller, 2nd call */
1087 failed += test_decode_single (__LINE__,
1088 MHD_WEBSOCKET_FLAG_SERVER
1089 | MHD_WEBSOCKET_FLAG_WANT_FRAGMENTS,
1090 0,
1091 2,
1092 0,
1093 "\x02\x83\x00\x00\x00\x00\x01\x02\x03\x80\x83\x00\x00\x00\x00\x04\x05\x06",
1094 18,
1095 "\x04\x05\x06",
1096 3,
1097 MHD_WEBSOCKET_STATUS_BINARY_LAST_FRAGMENT,
1098 MHD_WEBSOCKET_VALIDITY_VALID,
1099 18);
1100 /* Regular test: Binary frame with bytes which look like invalid UTF-8 character */
1101 failed += test_decode_single (__LINE__,
1102 MHD_WEBSOCKET_FLAG_SERVER
1103 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
1104 0,
1105 1,
1106 0,
1107 "\x82\x85\x00\x00\x00\x00" "Hell\xf6",
1108 11,
1109 "Hell\xf6",
1110 5,
1111 MHD_WEBSOCKET_STATUS_BINARY_FRAME,
1112 MHD_WEBSOCKET_VALIDITY_VALID,
1113 11);
1114 /* Regular test: Binary frame with bytes which look like broken UTF-8 sequence */
1115 failed += test_decode_single (__LINE__,
1116 MHD_WEBSOCKET_FLAG_SERVER
1117 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
1118 0,
1119 1,
1120 0,
1121 "\x82\x85\x00\x00\x00\x00" "H\xC3llo",
1122 11,
1123 "H\xC3llo",
1124 5,
1125 MHD_WEBSOCKET_STATUS_BINARY_FRAME,
1126 MHD_WEBSOCKET_VALIDITY_VALID,
1127 11);
1128 /* Regular test: Binary frame with bytes which look like valid UTF-8 sequence */
1129 failed += test_decode_single (__LINE__,
1130 MHD_WEBSOCKET_FLAG_SERVER
1131 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
1132 0,
1133 1,
1134 0,
1135 "\x82\x85\x00\x00\x00\x00" "H\xC3\xA4lo",
1136 11,
1137 "H\xC3\xA4lo",
1138 5,
1139 MHD_WEBSOCKET_STATUS_BINARY_FRAME,
1140 MHD_WEBSOCKET_VALIDITY_VALID,
1141 11);
1142 /* Regular test: Fragmented binary frame with bytes which look like valid UTF-8 sequence */
1143 failed += test_decode_single (__LINE__,
1144 MHD_WEBSOCKET_FLAG_SERVER
1145 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
1146 0,
1147 1,
1148 0,
1149 "\x02\x82\x00\x00\x00\x00" "H\xC3"
1150 "\x80\x83\x00\x00\x00\x00" "\xA4lo",
1151 17,
1152 "H\xC3\xA4lo",
1153 5,
1154 MHD_WEBSOCKET_STATUS_BINARY_FRAME,
1155 MHD_WEBSOCKET_VALIDITY_VALID,
1156 17);
1157 /* Regular test: Fragmented binary frame with bytes which look like valid UTF-8 sequence,
1158 fragments to the caller, 1st call */
1159 failed += test_decode_single (__LINE__,
1160 MHD_WEBSOCKET_FLAG_SERVER
1161 | MHD_WEBSOCKET_FLAG_WANT_FRAGMENTS,
1162 0,
1163 1,
1164 0,
1165 "\x02\x82\x00\x00\x00\x00" "H\xC3"
1166 "\x80\x83\x00\x00\x00\x00" "\xA4lo",
1167 17,
1168 "H\xC3",
1169 2,
1170 MHD_WEBSOCKET_STATUS_BINARY_FRAGMENT,
1171 MHD_WEBSOCKET_VALIDITY_VALID,
1172 8);
1173 /* Regular test: Fragmented binary frame with bytes which look like valid UTF-8 sequence,
1174 fragments to the caller, 2nd call */
1175 failed += test_decode_single (__LINE__,
1176 MHD_WEBSOCKET_FLAG_SERVER
1177 | MHD_WEBSOCKET_FLAG_WANT_FRAGMENTS,
1178 0,
1179 2,
1180 0,
1181 "\x02\x82\x00\x00\x00\x00" "H\xC3"
1182 "\x80\x83\x00\x00\x00\x00" "\xA4lo",
1183 17,
1184 "\xA4lo",
1185 3,
1186 MHD_WEBSOCKET_STATUS_BINARY_LAST_FRAGMENT,
1187 MHD_WEBSOCKET_VALIDITY_VALID,
1188 17);
1189
1190 /*
1191 ------------------------------------------------------------------------------
1192 close frame
1193 ------------------------------------------------------------------------------
1194 */
1195 /* Regular test: Close frame with no payload but with mask (decoder = server) */
1196 failed += test_decode_single (__LINE__,
1197 MHD_WEBSOCKET_FLAG_SERVER
1198 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
1199 0,
1200 1,
1201 0,
1202 "\x88\x80\x00\x00\x00\x00",
1203 6,
1204 NULL,
1205 0,
1206 MHD_WEBSOCKET_STATUS_CLOSE_FRAME,
1207 MHD_WEBSOCKET_VALIDITY_ONLY_VALID_FOR_CONTROL_FRAMES,
1208 6);
1209 /* Regular test: Close frame with no payload (decoder = client) */
1210 failed += test_decode_single (__LINE__,
1211 MHD_WEBSOCKET_FLAG_CLIENT
1212 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
1213 0,
1214 1,
1215 0,
1216 "\x88\x00",
1217 2,
1218 NULL,
1219 0,
1220 MHD_WEBSOCKET_STATUS_CLOSE_FRAME,
1221 MHD_WEBSOCKET_VALIDITY_ONLY_VALID_FOR_CONTROL_FRAMES,
1222 2);
1223 /* Fail test: Close frame with no payload and no mask (decoder = server) */
1224 failed += test_decode_single (__LINE__,
1225 MHD_WEBSOCKET_FLAG_SERVER
1226 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
1227 0,
1228 1,
1229 0,
1230 "\x88\x00",
1231 2,
1232 NULL,
1233 0,
1234 MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR,
1235 MHD_WEBSOCKET_VALIDITY_INVALID,
1236 1);
1237 /* Fail test: Close frame with no payload but with mask (decoder = client) */
1238 failed += test_decode_single (__LINE__,
1239 MHD_WEBSOCKET_FLAG_CLIENT
1240 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
1241 0,
1242 1,
1243 0,
1244 "\x88\x80\x00\x00\x00\x00",
1245 6,
1246 NULL,
1247 0,
1248 MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR,
1249 MHD_WEBSOCKET_VALIDITY_INVALID,
1250 1);
1251 /* Regular test: Close frame with 2 byte payload for close reason */
1252 failed += test_decode_single (__LINE__,
1253 MHD_WEBSOCKET_FLAG_SERVER
1254 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
1255 0,
1256 1,
1257 0,
1258 "\x88\x82\x00\x00\x00\x00\x03\xEB",
1259 8,
1260 "\x03\xEB",
1261 2,
1262 MHD_WEBSOCKET_STATUS_CLOSE_FRAME,
1263 MHD_WEBSOCKET_VALIDITY_ONLY_VALID_FOR_CONTROL_FRAMES,
1264 8);
1265 /* Fail test: Close frame with 1 byte payload (no valid close reason) */
1266 failed += test_decode_single (__LINE__,
1267 MHD_WEBSOCKET_FLAG_SERVER
1268 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
1269 0,
1270 1,
1271 0,
1272 "\x88\x81\x00\x00\x00\x00\x03",
1273 7,
1274 NULL,
1275 0,
1276 MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR,
1277 MHD_WEBSOCKET_VALIDITY_INVALID,
1278 1);
1279 /* Regular test: Close frame with close reason and UTF-8 description */
1280 failed += test_decode_single (__LINE__,
1281 MHD_WEBSOCKET_FLAG_SERVER
1282 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
1283 0,
1284 1,
1285 0,
1286 "\x88\x95\x00\x00\x00\x00\x03\xEB"
1287 "Something was wrong",
1288 27,
1289 "\x03\xEB" "Something was wrong",
1290 21,
1291 MHD_WEBSOCKET_STATUS_CLOSE_FRAME,
1292 MHD_WEBSOCKET_VALIDITY_ONLY_VALID_FOR_CONTROL_FRAMES,
1293 27);
1294 /* Regular test: Close frame with close reason and UTF-8 description (with UTF-8 sequence) */
1295 failed += test_decode_single (__LINE__,
1296 MHD_WEBSOCKET_FLAG_SERVER
1297 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
1298 0,
1299 1,
1300 0,
1301 "\x88\x96\x00\x00\x00\x00\x03\xEB"
1302 "Something was wr" "\xC3\xB6" "ng",
1303 28,
1304 "\x03\xEB" "Something was wr" "\xC3\xB6" "ng",
1305 22,
1306 MHD_WEBSOCKET_STATUS_CLOSE_FRAME,
1307 MHD_WEBSOCKET_VALIDITY_ONLY_VALID_FOR_CONTROL_FRAMES,
1308 28);
1309 /* Fail test: Close frame with close reason and invalid UTF-8 in description */
1310 failed += test_decode_single (__LINE__,
1311 MHD_WEBSOCKET_FLAG_SERVER
1312 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
1313 0,
1314 1,
1315 0,
1316 "\x88\x95\x00\x00\x00\x00\x03\xEB"
1317 "Something was wr" "\xFF" "ng",
1318 27,
1319 NULL,
1320 0,
1321 MHD_WEBSOCKET_STATUS_UTF8_ENCODING_ERROR,
1322 MHD_WEBSOCKET_VALIDITY_INVALID,
1323 24);
1324 /* Fail test: Close frame with close reason and broken UTF-8 sequence in description */
1325 failed += test_decode_single (__LINE__,
1326 MHD_WEBSOCKET_FLAG_SERVER
1327 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
1328 0,
1329 1,
1330 0,
1331 "\x88\x95\x00\x00\x00\x00\x03\xEB"
1332 "Something was wr" "\xC3" "ng",
1333 27,
1334 NULL,
1335 0,
1336 MHD_WEBSOCKET_STATUS_UTF8_ENCODING_ERROR,
1337 MHD_WEBSOCKET_VALIDITY_INVALID,
1338 25);
1339 /* Edge test (success): Close frame with 125 bytes of payload */
1340 failed += test_decode_single (__LINE__,
1341 MHD_WEBSOCKET_FLAG_SERVER
1342 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
1343 0,
1344 1,
1345 0,
1346 "\x88\xFD\x00\x00\x00\x00\x03\xEB"
1347 "Something was wrong, so I decided to close this websocket. I hope you are not angry. But this is also the 123 cap test. :-)",
1348 131,
1349 "\x03\xEB"
1350 "Something was wrong, so I decided to close this websocket. I hope you are not angry. But this is also the 123 cap test. :-)",
1351 125,
1352 MHD_WEBSOCKET_STATUS_CLOSE_FRAME,
1353 MHD_WEBSOCKET_VALIDITY_ONLY_VALID_FOR_CONTROL_FRAMES,
1354 131);
1355 /* Edge test (failure): Close frame with 126 bytes of payload */
1356 failed += test_decode_single (__LINE__,
1357 MHD_WEBSOCKET_FLAG_SERVER
1358 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
1359 0,
1360 1,
1361 0,
1362 "\x88\xFE\x00\x7e\x00\x00\x00\x00\x03\xEB"
1363 "Something was wrong, so I decided to close this websocket. I hope you are not angry. But this is also the 123 cap test. >:-)",
1364 134,
1365 NULL,
1366 0,
1367 MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR,
1368 MHD_WEBSOCKET_VALIDITY_INVALID,
1369 1);
1370 /* Fail test: Close frame with 500 bytes of payload */
1371 failed += test_decode_single (__LINE__,
1372 MHD_WEBSOCKET_FLAG_SERVER
1373 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
1374 0,
1375 1,
1376 0,
1377 "\x88\xFE\x01\xf4\x00\x00\x00\x00\x03\xEB"
1378 "The payload of this test isn't parsed.",
1379 49,
1380 NULL,
1381 0,
1382 MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR,
1383 MHD_WEBSOCKET_VALIDITY_INVALID,
1384 1);
1385 /* Edge test (failure): Close frame with 65535 bytes of payload */
1386 failed += test_decode_single (__LINE__,
1387 MHD_WEBSOCKET_FLAG_SERVER
1388 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
1389 0,
1390 1,
1391 0,
1392 "\x88\xFE\xff\xff\x00\x00\x00\x00\x03\xEB"
1393 "The payload of this test isn't parsed.",
1394 49,
1395 NULL,
1396 0,
1397 MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR,
1398 MHD_WEBSOCKET_VALIDITY_INVALID,
1399 1);
1400 /* Edge test (failure): Close frame with 65536 bytes of payload */
1401 failed += test_decode_single (__LINE__,
1402 MHD_WEBSOCKET_FLAG_SERVER
1403 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
1404 0,
1405 1,
1406 0,
1407 "\x88\xFF\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x03\xEB"
1408 "The payload of this test isn't parsed.",
1409 54,
1410 NULL,
1411 0,
1412 MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR,
1413 MHD_WEBSOCKET_VALIDITY_INVALID,
1414 1);
1415 /* Fail test: Close frame with 1000000 bytes of payload */
1416 failed += test_decode_single (__LINE__,
1417 MHD_WEBSOCKET_FLAG_SERVER
1418 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
1419 0,
1420 1,
1421 0,
1422 "\x88\xFF\x00\x00\x00\x00\x00\x0F\x42\x40\x00\x00\x00\x00\x03\xEB"
1423 "The payload of this test isn't parsed.",
1424 54,
1425 NULL,
1426 0,
1427 MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR,
1428 MHD_WEBSOCKET_VALIDITY_INVALID,
1429 1);
1430
1431 /*
1432 ------------------------------------------------------------------------------
1433 ping frame
1434 ------------------------------------------------------------------------------
1435 */
1436 /* Regular test: Ping frame with no payload but with mask (decoder = server) */
1437 failed += test_decode_single (__LINE__,
1438 MHD_WEBSOCKET_FLAG_SERVER
1439 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
1440 0,
1441 1,
1442 0,
1443 "\x89\x80\x00\x00\x00\x00",
1444 6,
1445 NULL,
1446 0,
1447 MHD_WEBSOCKET_STATUS_PING_FRAME,
1448 MHD_WEBSOCKET_VALIDITY_VALID,
1449 6);
1450 /* Regular test: Ping frame with no payload (decoder = client) */
1451 failed += test_decode_single (__LINE__,
1452 MHD_WEBSOCKET_FLAG_CLIENT
1453 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
1454 0,
1455 1,
1456 0,
1457 "\x89\x00",
1458 2,
1459 NULL,
1460 0,
1461 MHD_WEBSOCKET_STATUS_PING_FRAME,
1462 MHD_WEBSOCKET_VALIDITY_VALID,
1463 2);
1464 /* Fail test: Ping frame with no payload and no mask (decoder = server) */
1465 failed += test_decode_single (__LINE__,
1466 MHD_WEBSOCKET_FLAG_SERVER
1467 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
1468 0,
1469 1,
1470 0,
1471 "\x89\x00",
1472 2,
1473 NULL,
1474 0,
1475 MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR,
1476 MHD_WEBSOCKET_VALIDITY_INVALID,
1477 1);
1478 /* Fail test: Ping frame with no payload but with mask (decoder = client) */
1479 failed += test_decode_single (__LINE__,
1480 MHD_WEBSOCKET_FLAG_CLIENT
1481 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
1482 0,
1483 1,
1484 0,
1485 "\x89\x80\x00\x00\x00\x00",
1486 6,
1487 NULL,
1488 0,
1489 MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR,
1490 MHD_WEBSOCKET_VALIDITY_INVALID,
1491 1);
1492 /* Regular test: Ping frame with some (masked) payload */
1493 failed += test_decode_single (__LINE__,
1494 MHD_WEBSOCKET_FLAG_SERVER
1495 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
1496 0,
1497 1,
1498 0,
1499 "\x89\x88\x01\x20\x03\x40\xFF\xFF\xFF\xFF\x00\x00\x00\x00",
1500 14,
1501 "\xFE\xDF\xFC\xBF\x01\x20\x03\x40",
1502 8,
1503 MHD_WEBSOCKET_STATUS_PING_FRAME,
1504 MHD_WEBSOCKET_VALIDITY_VALID,
1505 14);
1506 /* Edge test (success): Ping frame with one byte of payload */
1507 failed += test_decode_single (__LINE__,
1508 MHD_WEBSOCKET_FLAG_SERVER
1509 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
1510 0,
1511 1,
1512 0,
1513 "\x89\x81\x00\x00\x00\x00" "a",
1514 7,
1515 "a",
1516 1,
1517 MHD_WEBSOCKET_STATUS_PING_FRAME,
1518 MHD_WEBSOCKET_VALIDITY_VALID,
1519 7);
1520 /* Edge test (success): Ping frame with 125 bytes of payload */
1521 failed += test_decode_single (__LINE__,
1522 MHD_WEBSOCKET_FLAG_SERVER
1523 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
1524 0,
1525 1,
1526 0,
1527 "\x89\xFD\x00\x00\x00\x00"
1528 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ012345678",
1529 131,
1530 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ012345678",
1531 125,
1532 MHD_WEBSOCKET_STATUS_PING_FRAME,
1533 MHD_WEBSOCKET_VALIDITY_VALID,
1534 131);
1535 /* Edge test (fail): Ping frame with 126 bytes of payload */
1536 failed += test_decode_single (__LINE__,
1537 MHD_WEBSOCKET_FLAG_SERVER
1538 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
1539 0,
1540 1,
1541 0,
1542 "\x89\xFE\x00\x7E\x00\x00\x00\x00"
1543 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789",
1544 134,
1545 NULL,
1546 0,
1547 MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR,
1548 MHD_WEBSOCKET_VALIDITY_INVALID,
1549 1);
1550 /* Regular test: Ping frame with UTF-8 data */
1551 failed += test_decode_single (__LINE__,
1552 MHD_WEBSOCKET_FLAG_SERVER
1553 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
1554 0,
1555 1,
1556 0,
1557 "\x89\x90\x00\x00\x00\x00" "Ping is bin"
1558 "\xC3\xA4" "ry.",
1559 22,
1560 "Ping is bin" "\xC3\xA4" "ry.",
1561 16,
1562 MHD_WEBSOCKET_STATUS_PING_FRAME,
1563 MHD_WEBSOCKET_VALIDITY_VALID,
1564 22);
1565 /* Regular test: Ping frame with invalid UTF-8 data */
1566 failed += test_decode_single (__LINE__,
1567 MHD_WEBSOCKET_FLAG_SERVER
1568 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
1569 0,
1570 1,
1571 0,
1572 "\x89\x8F\x00\x00\x00\x00" "Ping is bin" "\xFF"
1573 "ry.",
1574 21,
1575 "Ping is bin" "\xFF" "ry.",
1576 15,
1577 MHD_WEBSOCKET_STATUS_PING_FRAME,
1578 MHD_WEBSOCKET_VALIDITY_VALID,
1579 21);
1580 /* Regular test: Ping frame with broken UTF-8 sequence */
1581 failed += test_decode_single (__LINE__,
1582 MHD_WEBSOCKET_FLAG_SERVER
1583 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
1584 0,
1585 1,
1586 0,
1587 "\x89\x8F\x00\x00\x00\x00" "Ping is bin" "\xC3"
1588 "ry.",
1589 21,
1590 "Ping is bin" "\xC3" "ry.",
1591 15,
1592 MHD_WEBSOCKET_STATUS_PING_FRAME,
1593 MHD_WEBSOCKET_VALIDITY_VALID,
1594 21);
1595
1596 /*
1597 ------------------------------------------------------------------------------
1598 pong frame
1599 ------------------------------------------------------------------------------
1600 */
1601 /* Regular test: Pong frame with no payload but with mask (decoder = server) */
1602 failed += test_decode_single (__LINE__,
1603 MHD_WEBSOCKET_FLAG_SERVER
1604 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
1605 0,
1606 1,
1607 0,
1608 "\x8A\x80\x00\x00\x00\x00",
1609 6,
1610 NULL,
1611 0,
1612 MHD_WEBSOCKET_STATUS_PONG_FRAME,
1613 MHD_WEBSOCKET_VALIDITY_VALID,
1614 6);
1615 /* Regular test: Pong frame with no payload (decoder = client) */
1616 failed += test_decode_single (__LINE__,
1617 MHD_WEBSOCKET_FLAG_CLIENT
1618 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
1619 0,
1620 1,
1621 0,
1622 "\x8A\x00",
1623 2,
1624 NULL,
1625 0,
1626 MHD_WEBSOCKET_STATUS_PONG_FRAME,
1627 MHD_WEBSOCKET_VALIDITY_VALID,
1628 2);
1629 /* Fail test: Pong frame with no payload and no mask (decoder = server) */
1630 failed += test_decode_single (__LINE__,
1631 MHD_WEBSOCKET_FLAG_SERVER
1632 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
1633 0,
1634 1,
1635 0,
1636 "\x8A\x00",
1637 2,
1638 NULL,
1639 0,
1640 MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR,
1641 MHD_WEBSOCKET_VALIDITY_INVALID,
1642 1);
1643 /* Fail test: Pong frame with no payload but with mask (decoder = client) */
1644 failed += test_decode_single (__LINE__,
1645 MHD_WEBSOCKET_FLAG_CLIENT
1646 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
1647 0,
1648 1,
1649 0,
1650 "\x8A\x80\x00\x00\x00\x00",
1651 6,
1652 NULL,
1653 0,
1654 MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR,
1655 MHD_WEBSOCKET_VALIDITY_INVALID,
1656 1);
1657 /* Regular test: Pong frame with some (masked) payload */
1658 failed += test_decode_single (__LINE__,
1659 MHD_WEBSOCKET_FLAG_SERVER
1660 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
1661 0,
1662 1,
1663 0,
1664 "\x8A\x88\x01\x20\x03\x40\xFF\xFF\xFF\xFF\x00\x00\x00\x00",
1665 14,
1666 "\xFE\xDF\xFC\xBF\x01\x20\x03\x40",
1667 8,
1668 MHD_WEBSOCKET_STATUS_PONG_FRAME,
1669 MHD_WEBSOCKET_VALIDITY_VALID,
1670 14);
1671 /* Edge test (success): Pong frame with one byte of payload */
1672 failed += test_decode_single (__LINE__,
1673 MHD_WEBSOCKET_FLAG_SERVER
1674 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
1675 0,
1676 1,
1677 0,
1678 "\x8A\x81\x00\x00\x00\x00" "a",
1679 7,
1680 "a",
1681 1,
1682 MHD_WEBSOCKET_STATUS_PONG_FRAME,
1683 MHD_WEBSOCKET_VALIDITY_VALID,
1684 7);
1685 /* Edge test (success): Pong frame with 125 bytes of payload */
1686 failed += test_decode_single (__LINE__,
1687 MHD_WEBSOCKET_FLAG_SERVER
1688 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
1689 0,
1690 1,
1691 0,
1692 "\x8A\xFD\x00\x00\x00\x00"
1693 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ012345678",
1694 131,
1695 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ012345678",
1696 125,
1697 MHD_WEBSOCKET_STATUS_PONG_FRAME,
1698 MHD_WEBSOCKET_VALIDITY_VALID,
1699 131);
1700 /* Edge test (fail): Pong frame with 126 bytes of payload */
1701 failed += test_decode_single (__LINE__,
1702 MHD_WEBSOCKET_FLAG_SERVER
1703 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
1704 0,
1705 1,
1706 0,
1707 "\x8A\xFE\x00\x7E\x00\x00\x00\x00"
1708 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789",
1709 134,
1710 NULL,
1711 0,
1712 MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR,
1713 MHD_WEBSOCKET_VALIDITY_INVALID,
1714 1);
1715 /* Regular test: Pong frame with UTF-8 data */
1716 failed += test_decode_single (__LINE__,
1717 MHD_WEBSOCKET_FLAG_SERVER
1718 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
1719 0,
1720 1,
1721 0,
1722 "\x8A\x90\x00\x00\x00\x00" "Pong is bin"
1723 "\xC3\xA4" "ry.",
1724 22,
1725 "Pong is bin" "\xC3\xA4" "ry.",
1726 16,
1727 MHD_WEBSOCKET_STATUS_PONG_FRAME,
1728 MHD_WEBSOCKET_VALIDITY_VALID,
1729 22);
1730 /* Regular test: Pong frame with invalid UTF-8 data */
1731 failed += test_decode_single (__LINE__,
1732 MHD_WEBSOCKET_FLAG_SERVER
1733 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
1734 0,
1735 1,
1736 0,
1737 "\x8A\x8F\x00\x00\x00\x00" "Pong is bin" "\xFF"
1738 "ry.",
1739 21,
1740 "Pong is bin" "\xFF" "ry.",
1741 15,
1742 MHD_WEBSOCKET_STATUS_PONG_FRAME,
1743 MHD_WEBSOCKET_VALIDITY_VALID,
1744 21);
1745 /* Regular test: Pong frame with broken UTF-8 sequence */
1746 failed += test_decode_single (__LINE__,
1747 MHD_WEBSOCKET_FLAG_SERVER
1748 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
1749 0,
1750 1,
1751 0,
1752 "\x8A\x8F\x00\x00\x00\x00" "Pong is bin" "\xC3"
1753 "ry.",
1754 21,
1755 "Pong is bin" "\xC3" "ry.",
1756 15,
1757 MHD_WEBSOCKET_STATUS_PONG_FRAME,
1758 MHD_WEBSOCKET_VALIDITY_VALID,
1759 21);
1760
1761 /*
1762 ------------------------------------------------------------------------------
1763 fragmentation
1764 ------------------------------------------------------------------------------
1765 */
1766 /* Regular test: Fragmented, masked text frame, we are the server and don't want fragments as caller */
1767 failed += test_decode_single (__LINE__,
1768 MHD_WEBSOCKET_FLAG_SERVER
1769 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
1770 0,
1771 1,
1772 0,
1773 "\x01\x83\x37\xfa\x21\x3d\x7f\x9f\x4d\x80\x82\x3d\x37\xfa\x21\x51\x58",
1774 17,
1775 "Hello",
1776 5,
1777 MHD_WEBSOCKET_STATUS_TEXT_FRAME,
1778 MHD_WEBSOCKET_VALIDITY_VALID,
1779 17);
1780 /* Regular test: Fragmented, masked text frame, we are the server and don't want fragments as caller, but call decode two times */
1781 failed += test_decode_single (__LINE__,
1782 MHD_WEBSOCKET_FLAG_SERVER
1783 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
1784 0,
1785 2,
1786 0,
1787 "\x01\x83\x37\xfa\x21\x3d\x7f\x9f\x4d\x80\x82\x3d\x37\xfa\x21\x51\x58",
1788 17,
1789 NULL,
1790 0,
1791 MHD_WEBSOCKET_STATUS_OK,
1792 MHD_WEBSOCKET_VALIDITY_VALID,
1793 17);
1794 /* Regular test: Fragmented, masked text frame, we are the server and want fragments, one call */
1795 failed += test_decode_single (__LINE__,
1796 MHD_WEBSOCKET_FLAG_SERVER
1797 | MHD_WEBSOCKET_FLAG_WANT_FRAGMENTS,
1798 0,
1799 1,
1800 0,
1801 "\x01\x83\x37\xfa\x21\x3d\x7f\x9f\x4d\x80\x82\x3d\x37\xfa\x21\x51\x58",
1802 17,
1803 "Hel",
1804 3,
1805 MHD_WEBSOCKET_STATUS_TEXT_FRAGMENT,
1806 MHD_WEBSOCKET_VALIDITY_VALID,
1807 9);
1808 /* Regular test: Fragmented, masked text frame, we are the server and want fragments, second call */
1809 failed += test_decode_single (__LINE__,
1810 MHD_WEBSOCKET_FLAG_SERVER
1811 | MHD_WEBSOCKET_FLAG_WANT_FRAGMENTS,
1812 0,
1813 2,
1814 0,
1815 "\x01\x83\x37\xfa\x21\x3d\x7f\x9f\x4d\x80\x82\x3d\x37\xfa\x21\x51\x58",
1816 17,
1817 "lo",
1818 2,
1819 MHD_WEBSOCKET_STATUS_TEXT_LAST_FRAGMENT,
1820 MHD_WEBSOCKET_VALIDITY_VALID,
1821 17);
1822 /* Regular test: Fragmented, masked text frame, we are the server and want fragments, third call */
1823 failed += test_decode_single (__LINE__,
1824 MHD_WEBSOCKET_FLAG_SERVER
1825 | MHD_WEBSOCKET_FLAG_WANT_FRAGMENTS,
1826 0,
1827 3,
1828 0,
1829 "\x01\x83\x37\xfa\x21\x3d\x7f\x9f\x4d\x80\x82\x3d\x37\xfa\x21\x51\x58",
1830 17,
1831 NULL,
1832 0,
1833 MHD_WEBSOCKET_STATUS_OK,
1834 MHD_WEBSOCKET_VALIDITY_VALID,
1835 17);
1836
1837
1838 /*
1839 ------------------------------------------------------------------------------
1840 invalid flags
1841 ------------------------------------------------------------------------------
1842 */
1843 /* Regular test: Template with valid data for the next tests (this one must succeed) */
1844 failed += test_decode_single (__LINE__,
1845 MHD_WEBSOCKET_FLAG_SERVER
1846 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
1847 0,
1848 1,
1849 0,
1850 "\x81\x85\x00\x00\x00\x00Hello",
1851 11,
1852 "Hello",
1853 5,
1854 MHD_WEBSOCKET_STATUS_TEXT_FRAME,
1855 MHD_WEBSOCKET_VALIDITY_VALID,
1856 11);
1857 /* Fail test: RSV1 flag set */
1858 failed += test_decode_single (__LINE__,
1859 MHD_WEBSOCKET_FLAG_SERVER
1860 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
1861 0,
1862 1,
1863 0,
1864 "\x91\x85\x00\x00\x00\x00Hello",
1865 11,
1866 NULL,
1867 0,
1868 MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR,
1869 MHD_WEBSOCKET_VALIDITY_INVALID,
1870 0);
1871 /* Fail test: RSV2 flag set */
1872 failed += test_decode_single (__LINE__,
1873 MHD_WEBSOCKET_FLAG_SERVER
1874 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
1875 0,
1876 1,
1877 0,
1878 "\xA1\x85\x00\x00\x00\x00Hello",
1879 11,
1880 NULL,
1881 0,
1882 MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR,
1883 MHD_WEBSOCKET_VALIDITY_INVALID,
1884 0);
1885 /* Fail test: RSV3 flag set */
1886 failed += test_decode_single (__LINE__,
1887 MHD_WEBSOCKET_FLAG_SERVER
1888 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
1889 0,
1890 1,
1891 0,
1892 "\xC1\x85\x00\x00\x00\x00Hello",
1893 11,
1894 NULL,
1895 0,
1896 MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR,
1897 MHD_WEBSOCKET_VALIDITY_INVALID,
1898 0);
1899
1900 /*
1901 ------------------------------------------------------------------------------
1902 invalid opcodes
1903 ------------------------------------------------------------------------------
1904 */
1905 /* Fail test: Invalid opcode 0 (0 is usually valid, but only if there was a data frame before) */
1906 failed += test_decode_single (__LINE__,
1907 MHD_WEBSOCKET_FLAG_SERVER
1908 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
1909 0,
1910 1,
1911 0,
1912 "\x80\x85\x00\x00\x00\x00Hello",
1913 11,
1914 NULL,
1915 0,
1916 MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR,
1917 MHD_WEBSOCKET_VALIDITY_INVALID,
1918 0);
1919 /* Fail test: Invalid opcode 3 */
1920 failed += test_decode_single (__LINE__,
1921 MHD_WEBSOCKET_FLAG_SERVER
1922 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
1923 0,
1924 1,
1925 0,
1926 "\x83\x85\x00\x00\x00\x00Hello",
1927 11,
1928 NULL,
1929 0,
1930 MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR,
1931 MHD_WEBSOCKET_VALIDITY_INVALID,
1932 0);
1933 /* Fail test: Invalid opcode 4 */
1934 failed += test_decode_single (__LINE__,
1935 MHD_WEBSOCKET_FLAG_SERVER
1936 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
1937 0,
1938 1,
1939 0,
1940 "\x84\x85\x00\x00\x00\x00Hello",
1941 11,
1942 NULL,
1943 0,
1944 MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR,
1945 MHD_WEBSOCKET_VALIDITY_INVALID,
1946 0);
1947 /* Fail test: Invalid opcode 5 */
1948 failed += test_decode_single (__LINE__,
1949 MHD_WEBSOCKET_FLAG_SERVER
1950 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
1951 0,
1952 1,
1953 0,
1954 "\x85\x85\x00\x00\x00\x00Hello",
1955 11,
1956 NULL,
1957 0,
1958 MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR,
1959 MHD_WEBSOCKET_VALIDITY_INVALID,
1960 0);
1961 /* Fail test: Invalid opcode 6 */
1962 failed += test_decode_single (__LINE__,
1963 MHD_WEBSOCKET_FLAG_SERVER
1964 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
1965 0,
1966 1,
1967 0,
1968 "\x86\x85\x00\x00\x00\x00Hello",
1969 11,
1970 NULL,
1971 0,
1972 MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR,
1973 MHD_WEBSOCKET_VALIDITY_INVALID,
1974 0);
1975 /* Fail test: Invalid opcode 7 */
1976 failed += test_decode_single (__LINE__,
1977 MHD_WEBSOCKET_FLAG_SERVER
1978 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
1979 0,
1980 1,
1981 0,
1982 "\x87\x85\x00\x00\x00\x00Hello",
1983 11,
1984 NULL,
1985 0,
1986 MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR,
1987 MHD_WEBSOCKET_VALIDITY_INVALID,
1988 0);
1989 /* Fail test: Invalid opcode 0x0B */
1990 failed += test_decode_single (__LINE__,
1991 MHD_WEBSOCKET_FLAG_SERVER
1992 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
1993 0,
1994 1,
1995 0,
1996 "\x8B\x85\x00\x00\x00\x00Hello",
1997 11,
1998 NULL,
1999 0,
2000 MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR,
2001 MHD_WEBSOCKET_VALIDITY_INVALID,
2002 0);
2003 /* Fail test: Invalid opcode 0x0C */
2004 failed += test_decode_single (__LINE__,
2005 MHD_WEBSOCKET_FLAG_SERVER
2006 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
2007 0,
2008 1,
2009 0,
2010 "\x8c\x85\x00\x00\x00\x00Hello",
2011 11,
2012 NULL,
2013 0,
2014 MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR,
2015 MHD_WEBSOCKET_VALIDITY_INVALID,
2016 0);
2017 /* Fail test: Invalid opcode 0x0D */
2018 failed += test_decode_single (__LINE__,
2019 MHD_WEBSOCKET_FLAG_SERVER
2020 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
2021 0,
2022 1,
2023 0,
2024 "\x8d\x85\x00\x00\x00\x00Hello",
2025 11,
2026 NULL,
2027 0,
2028 MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR,
2029 MHD_WEBSOCKET_VALIDITY_INVALID,
2030 0);
2031 /* Fail test: Invalid opcode 0x0E */
2032 failed += test_decode_single (__LINE__,
2033 MHD_WEBSOCKET_FLAG_SERVER
2034 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
2035 0,
2036 1,
2037 0,
2038 "\x8e\x85\x00\x00\x00\x00Hello",
2039 11,
2040 NULL,
2041 0,
2042 MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR,
2043 MHD_WEBSOCKET_VALIDITY_INVALID,
2044 0);
2045 /* Fail test: Invalid opcode 0x0F */
2046 failed += test_decode_single (__LINE__,
2047 MHD_WEBSOCKET_FLAG_SERVER
2048 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
2049 0,
2050 1,
2051 0,
2052 "\x8f\x85\x00\x00\x00\x00Hello",
2053 11,
2054 NULL,
2055 0,
2056 MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR,
2057 MHD_WEBSOCKET_VALIDITY_INVALID,
2058 0);
2059
2060
2061 /*
2062 ------------------------------------------------------------------------------
2063 control frames without FIN flag
2064 ------------------------------------------------------------------------------
2065 */
2066 /* Fail test: Close frame without FIN flag */
2067 failed += test_decode_single (__LINE__,
2068 MHD_WEBSOCKET_FLAG_SERVER
2069 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
2070 0,
2071 1,
2072 0,
2073 "\x08\x85\x00\x00\x00\x00Hello",
2074 11,
2075 NULL,
2076 0,
2077 MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR,
2078 MHD_WEBSOCKET_VALIDITY_INVALID,
2079 0);
2080 /* Fail test: Ping frame without FIN flag */
2081 failed += test_decode_single (__LINE__,
2082 MHD_WEBSOCKET_FLAG_SERVER
2083 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
2084 0,
2085 1,
2086 0,
2087 "\x09\x85\x00\x00\x00\x00Hello",
2088 11,
2089 NULL,
2090 0,
2091 MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR,
2092 MHD_WEBSOCKET_VALIDITY_INVALID,
2093 0);
2094 /* Fail test: Pong frame without FIN flag */
2095 failed += test_decode_single (__LINE__,
2096 MHD_WEBSOCKET_FLAG_SERVER
2097 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
2098 0,
2099 1,
2100 0,
2101 "\x0a\x85\x00\x00\x00\x00Hello",
2102 11,
2103 NULL,
2104 0,
2105 MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR,
2106 MHD_WEBSOCKET_VALIDITY_INVALID,
2107 0);
2108
2109 /*
2110 ------------------------------------------------------------------------------
2111 length checks (without max_payload_len)
2112 ------------------------------------------------------------------------------
2113 */
2114 /* Edge test (success): 0 bytes of payload (requires 1 byte length) */
2115 failed += test_decode_single (__LINE__,
2116 MHD_WEBSOCKET_FLAG_SERVER
2117 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
2118 0,
2119 1,
2120 0,
2121 "\x81\x80\x00\x00\x00\x00",
2122 6,
2123 NULL,
2124 0,
2125 MHD_WEBSOCKET_STATUS_TEXT_FRAME,
2126 MHD_WEBSOCKET_VALIDITY_VALID,
2127 6);
2128 /* Edge test (success): 1 byte of payload (requires 1 byte length) */
2129 failed += test_decode_single (__LINE__,
2130 MHD_WEBSOCKET_FLAG_SERVER
2131 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
2132 0,
2133 1,
2134 0,
2135 "\x81\x81\x00\x00\x00\x00" "a",
2136 7,
2137 "a",
2138 1,
2139 MHD_WEBSOCKET_STATUS_TEXT_FRAME,
2140 MHD_WEBSOCKET_VALIDITY_VALID,
2141 7);
2142 /* Edge test (success): 125 bytes of payload (requires 1 byte length) */
2143 failed += test_decode_single (__LINE__,
2144 MHD_WEBSOCKET_FLAG_SERVER
2145 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
2146 0,
2147 1,
2148 0,
2149 "\x81\xfd\x00\x00\x00\x00"
2150 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ012345678",
2151 131,
2152 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ012345678",
2153 125,
2154 MHD_WEBSOCKET_STATUS_TEXT_FRAME,
2155 MHD_WEBSOCKET_VALIDITY_VALID,
2156 131);
2157 /* Edge test (success): 126 bytes of payload (requires 2 byte length) */
2158 failed += test_decode_single (__LINE__,
2159 MHD_WEBSOCKET_FLAG_SERVER
2160 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
2161 0,
2162 1,
2163 0,
2164 "\x81\xfe\x00\x7e\x00\x00\x00\x00"
2165 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789",
2166 134,
2167 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789",
2168 126,
2169 MHD_WEBSOCKET_STATUS_TEXT_FRAME,
2170 MHD_WEBSOCKET_VALIDITY_VALID,
2171 134);
2172 /* Edge test (success): 65535 bytes of payload (requires 2 byte length) */
2173 allocate_length_test_data (&buf1,
2174 &buf2,
2175 65535,
2176 "\x81\xfe\xff\xff\x00\x00\x00\x00",
2177 8);
2178 failed += test_decode_single (__LINE__,
2179 MHD_WEBSOCKET_FLAG_SERVER
2180 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
2181 0,
2182 1,
2183 0,
2184 buf1,
2185 65535 + 8,
2186 buf2,
2187 65535,
2188 MHD_WEBSOCKET_STATUS_TEXT_FRAME,
2189 MHD_WEBSOCKET_VALIDITY_VALID,
2190 65535 + 8);
2191 /* Edge test (success): 65536 bytes of payload (requires 8 byte length) */
2192 allocate_length_test_data (&buf1,
2193 &buf2,
2194 65536,
2195 "\x81\xff\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00",
2196 14);
2197 failed += test_decode_single (__LINE__,
2198 MHD_WEBSOCKET_FLAG_SERVER
2199 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
2200 0,
2201 1,
2202 0,
2203 buf1,
2204 65536 + 14,
2205 buf2,
2206 65536,
2207 MHD_WEBSOCKET_STATUS_TEXT_FRAME,
2208 MHD_WEBSOCKET_VALIDITY_VALID,
2209 65536 + 14);
2210 /* Regular test: 1 MB of payload */
2211 allocate_length_test_data (&buf1,
2212 &buf2,
2213 1048576,
2214 "\x81\xff\x00\x00\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00",
2215 14);
2216 failed += test_decode_single (__LINE__,
2217 MHD_WEBSOCKET_FLAG_SERVER
2218 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
2219 0,
2220 1,
2221 0,
2222 buf1,
2223 1048576 + 14,
2224 buf2,
2225 1048576,
2226 MHD_WEBSOCKET_STATUS_TEXT_FRAME,
2227 MHD_WEBSOCKET_VALIDITY_VALID,
2228 1048576 + 14);
2229 /* Regular test: 100 MB of payload */
2230 allocate_length_test_data (&buf1,
2231 &buf2,
2232 104857600,
2233 "\x81\xff\x00\x00\x00\x00\x06\x40\x00\x00\x00\x00\x00\x00",
2234 14);
2235 failed += test_decode_single (__LINE__,
2236 MHD_WEBSOCKET_FLAG_SERVER
2237 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
2238 0,
2239 1,
2240 0,
2241 buf1,
2242 104857600 + 14,
2243 buf2,
2244 104857600,
2245 MHD_WEBSOCKET_STATUS_TEXT_FRAME,
2246 MHD_WEBSOCKET_VALIDITY_VALID,
2247 104857600 + 14);
2248 if (NULL != buf1)
2249 {
2250 free (buf1);
2251 buf1 = NULL;
2252 }
2253 if (NULL != buf2)
2254 {
2255 free (buf2);
2256 buf2 = NULL;
2257 }
2258 /* Edge test (success): Maximum allowed length (here is only the header checked) */
2259 failed += test_decode_single (__LINE__,
2260 MHD_WEBSOCKET_FLAG_SERVER
2261 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
2262 0,
2263 1,
2264 0,
2265 "\x81\xff\x7f\xff\xff\xff\xff\xff\xff\xff",
2266 10,
2267 NULL,
2268 0,
2269 MHD_WEBSOCKET_STATUS_OK,
2270 MHD_WEBSOCKET_VALIDITY_VALID,
2271 10);
2272 /* Edge test (fail): Too big payload length */
2273 failed += test_decode_single (__LINE__,
2274 MHD_WEBSOCKET_FLAG_SERVER
2275 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
2276 0,
2277 1,
2278 0,
2279 "\x81\xff\x80\x00\x00\x00\x00\x00\x00\x00",
2280 10,
2281 NULL,
2282 0,
2283 MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR,
2284 MHD_WEBSOCKET_VALIDITY_INVALID,
2285 10);
2286 /* Edge test (fail): Too big payload length */
2287 failed += test_decode_single (__LINE__,
2288 MHD_WEBSOCKET_FLAG_SERVER
2289 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
2290 0,
2291 1,
2292 0,
2293 "\x81\xff\xff\xff\xff\xff\xff\xff\xff\xff",
2294 10,
2295 NULL,
2296 0,
2297 MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR,
2298 MHD_WEBSOCKET_VALIDITY_INVALID,
2299 10);
2300 /* Fail test: Not the smallest payload length syntax used (2 byte instead of 1 byte) */
2301 failed += test_decode_single (__LINE__,
2302 MHD_WEBSOCKET_FLAG_SERVER
2303 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
2304 0,
2305 1,
2306 0,
2307 "\x81\xfe\x00\x05\x00\x00\x00\x00" "abcde",
2308 13,
2309 NULL,
2310 0,
2311 MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR,
2312 MHD_WEBSOCKET_VALIDITY_INVALID,
2313 4);
2314 /* Fail test: Not the smallest payload length syntax used (8 byte instead of 1 byte) */
2315 failed += test_decode_single (__LINE__,
2316 MHD_WEBSOCKET_FLAG_SERVER
2317 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
2318 0,
2319 1,
2320 0,
2321 "\x81\xff\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x00"
2322 "abcde",
2323 13,
2324 NULL,
2325 0,
2326 MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR,
2327 MHD_WEBSOCKET_VALIDITY_INVALID,
2328 10);
2329 /* Fail test: Not the smallest payload length syntax used (8 byte instead of 2 byte) */
2330 failed += test_decode_single (__LINE__,
2331 MHD_WEBSOCKET_FLAG_SERVER
2332 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
2333 0,
2334 1,
2335 0,
2336 "\x81\xff\x00\x00\x00\x00\x00\x00\xff\xff\x00\x00\x00\x00"
2337 "abcde",
2338 13,
2339 NULL,
2340 0,
2341 MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR,
2342 MHD_WEBSOCKET_VALIDITY_INVALID,
2343 10);
2344
2345 /*
2346 ------------------------------------------------------------------------------
2347 length checks (with max_payload_len)
2348 ------------------------------------------------------------------------------
2349 */
2350 /* Regular test: Frame with less payload than specified as limit */
2351 failed += test_decode_single (__LINE__,
2352 MHD_WEBSOCKET_FLAG_SERVER
2353 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
2354 100,
2355 1,
2356 0,
2357 "\x81\x85\x00\x00\x00\x00" "Hello",
2358 11,
2359 "Hello",
2360 5,
2361 MHD_WEBSOCKET_STATUS_TEXT_FRAME,
2362 MHD_WEBSOCKET_VALIDITY_VALID,
2363 11);
2364 /* Edge test (success): Frame with the same payload as the specified limit */
2365 failed += test_decode_single (__LINE__,
2366 MHD_WEBSOCKET_FLAG_SERVER
2367 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
2368 5,
2369 1,
2370 0,
2371 "\x81\x85\x00\x00\x00\x00" "Hello",
2372 11,
2373 "Hello",
2374 5,
2375 MHD_WEBSOCKET_STATUS_TEXT_FRAME,
2376 MHD_WEBSOCKET_VALIDITY_VALID,
2377 11);
2378 /* Edge test (fail): Frame with more payload than specified as limit */
2379 failed += test_decode_single (__LINE__,
2380 MHD_WEBSOCKET_FLAG_SERVER
2381 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
2382 4,
2383 1,
2384 0,
2385 "\x81\x85\x00\x00\x00\x00" "Hello",
2386 11,
2387 NULL,
2388 0,
2389 MHD_WEBSOCKET_STATUS_MAXIMUM_SIZE_EXCEEDED,
2390 MHD_WEBSOCKET_VALIDITY_INVALID,
2391 2);
2392 /* Regular test: Fragmented frames with the sum of payload less than specified as limit */
2393 failed += test_decode_single (__LINE__,
2394 MHD_WEBSOCKET_FLAG_SERVER
2395 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
2396 100,
2397 1,
2398 0,
2399 "\x01\x83\x00\x00\x00\x00"
2400 "Hel\x80\x82\x00\x00\x00\x00" "lo",
2401 17,
2402 "Hello",
2403 5,
2404 MHD_WEBSOCKET_STATUS_TEXT_FRAME,
2405 MHD_WEBSOCKET_VALIDITY_VALID,
2406 17);
2407 /* Edge test (success): Fragmented frames with the sum of payload equal to the specified limit */
2408 failed += test_decode_single (__LINE__,
2409 MHD_WEBSOCKET_FLAG_SERVER
2410 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
2411 5,
2412 1,
2413 0,
2414 "\x01\x83\x00\x00\x00\x00"
2415 "Hel\x80\x82\x00\x00\x00\x00" "lo",
2416 17,
2417 "Hello",
2418 5,
2419 MHD_WEBSOCKET_STATUS_TEXT_FRAME,
2420 MHD_WEBSOCKET_VALIDITY_VALID,
2421 17);
2422 /* Edge test (fail): Fragmented frames with the sum of payload more than specified as limit */
2423 failed += test_decode_single (__LINE__,
2424 MHD_WEBSOCKET_FLAG_SERVER
2425 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
2426 4,
2427 1,
2428 0,
2429 "\x01\x83\x00\x00\x00\x00"
2430 "Hel\x80\x82\x00\x00\x00\x00" "lo",
2431 17,
2432 NULL,
2433 0,
2434 MHD_WEBSOCKET_STATUS_MAXIMUM_SIZE_EXCEEDED,
2435 MHD_WEBSOCKET_VALIDITY_INVALID,
2436 15);
2437 /* Edge test (success): Fragmented frames with the sum of payload greater than
2438 the specified limit, but we take fragments (one call) */
2439 failed += test_decode_single (__LINE__,
2440 MHD_WEBSOCKET_FLAG_SERVER
2441 | MHD_WEBSOCKET_FLAG_WANT_FRAGMENTS,
2442 5,
2443 1,
2444 0,
2445 "\x01\x83\x00\x00\x00\x00"
2446 "Hel\x80\x82\x00\x00\x00\x00" "lo",
2447 17,
2448 "Hel",
2449 3,
2450 MHD_WEBSOCKET_STATUS_TEXT_FRAGMENT,
2451 MHD_WEBSOCKET_VALIDITY_VALID,
2452 9);
2453 /* Edge test (success): Fragmented frames with the sum of payload greater than
2454 the specified limit, but we take fragments (two calls) */
2455 failed += test_decode_single (__LINE__,
2456 MHD_WEBSOCKET_FLAG_SERVER
2457 | MHD_WEBSOCKET_FLAG_WANT_FRAGMENTS,
2458 5,
2459 2,
2460 0,
2461 "\x01\x83\x00\x00\x00\x00"
2462 "Hel\x80\x82\x00\x00\x00\x00" "lo",
2463 17,
2464 "lo",
2465 2,
2466 MHD_WEBSOCKET_STATUS_TEXT_LAST_FRAGMENT,
2467 MHD_WEBSOCKET_VALIDITY_VALID,
2468 17);
2469
2470 /*
2471 ------------------------------------------------------------------------------
2472 UTF-8 sequences
2473 ------------------------------------------------------------------------------
2474 */
2475 /* Regular test: No UTF-8 characters */
2476 failed += test_decode_single (__LINE__,
2477 MHD_WEBSOCKET_FLAG_SERVER
2478 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
2479 0,
2480 1,
2481 0,
2482 "\x81\x8A\x00\x00\x00\x00 a ",
2483 16,
2484 " a ",
2485 10,
2486 MHD_WEBSOCKET_STATUS_TEXT_FRAME,
2487 MHD_WEBSOCKET_VALIDITY_VALID,
2488 16);
2489 /* Fail test: A UTF-8 tail character without sequence start character */
2490 failed += test_decode_single (__LINE__,
2491 MHD_WEBSOCKET_FLAG_SERVER
2492 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
2493 0,
2494 1,
2495 0,
2496 "\x81\x8A\x00\x00\x00\x00 \xA4 ",
2497 16,
2498 NULL,
2499 0,
2500 MHD_WEBSOCKET_STATUS_UTF8_ENCODING_ERROR,
2501 MHD_WEBSOCKET_VALIDITY_INVALID,
2502 7);
2503 /* Regular test: A two byte UTF-8 sequence */
2504 failed += test_decode_single (__LINE__,
2505 MHD_WEBSOCKET_FLAG_SERVER
2506 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
2507 0,
2508 1,
2509 0,
2510 "\x81\x8A\x00\x00\x00\x00 \xC3\xA4 ",
2511 16,
2512 " \xC3\xA4 ",
2513 10,
2514 MHD_WEBSOCKET_STATUS_TEXT_FRAME,
2515 MHD_WEBSOCKET_VALIDITY_VALID,
2516 16);
2517 /* Fail test: A broken two byte UTF-8 sequence */
2518 failed += test_decode_single (__LINE__,
2519 MHD_WEBSOCKET_FLAG_SERVER
2520 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
2521 0,
2522 1,
2523 0,
2524 "\x81\x8A\x00\x00\x00\x00 \xC3 ",
2525 16,
2526 NULL,
2527 0,
2528 MHD_WEBSOCKET_STATUS_UTF8_ENCODING_ERROR,
2529 MHD_WEBSOCKET_VALIDITY_INVALID,
2530 8);
2531 /* Fail test: A two byte UTF-8 sequence with one UTF-8 tail too much */
2532 failed += test_decode_single (__LINE__,
2533 MHD_WEBSOCKET_FLAG_SERVER
2534 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
2535 0,
2536 1,
2537 0,
2538 "\x81\x8A\x00\x00\x00\x00 \xC3\xA4\xA4 ",
2539 16,
2540 NULL,
2541 0,
2542 MHD_WEBSOCKET_STATUS_UTF8_ENCODING_ERROR,
2543 MHD_WEBSOCKET_VALIDITY_INVALID,
2544 9);
2545 /* Regular test: A three byte UTF-8 sequence */
2546 failed += test_decode_single (__LINE__,
2547 MHD_WEBSOCKET_FLAG_SERVER
2548 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
2549 0,
2550 1,
2551 0,
2552 "\x81\x8A\x00\x00\x00\x00 \xEF\x8F\x8F ",
2553 16,
2554 " \xEF\x8F\x8F ",
2555 10,
2556 MHD_WEBSOCKET_STATUS_TEXT_FRAME,
2557 MHD_WEBSOCKET_VALIDITY_VALID,
2558 16);
2559 /* Fail test: A broken byte UTF-8 sequence (two of three bytes) */
2560 failed += test_decode_single (__LINE__,
2561 MHD_WEBSOCKET_FLAG_SERVER
2562 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
2563 0,
2564 1,
2565 0,
2566 "\x81\x8A\x00\x00\x00\x00 \xEF\x8F ",
2567 16,
2568 NULL,
2569 0,
2570 MHD_WEBSOCKET_STATUS_UTF8_ENCODING_ERROR,
2571 MHD_WEBSOCKET_VALIDITY_INVALID,
2572 9);
2573 /* Fail test: A broken byte UTF-8 sequence (one of three bytes) */
2574 failed += test_decode_single (__LINE__,
2575 MHD_WEBSOCKET_FLAG_SERVER
2576 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
2577 0,
2578 1,
2579 0,
2580 "\x81\x8A\x00\x00\x00\x00 \xEF ",
2581 16,
2582 NULL,
2583 0,
2584 MHD_WEBSOCKET_STATUS_UTF8_ENCODING_ERROR,
2585 MHD_WEBSOCKET_VALIDITY_INVALID,
2586 8);
2587 /* Fail test: A three byte UTF-8 sequence followed by one UTF-8 tail byte */
2588 failed += test_decode_single (__LINE__,
2589 MHD_WEBSOCKET_FLAG_SERVER
2590 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
2591 0,
2592 1,
2593 0,
2594 "\x81\x8A\x00\x00\x00\x00 \xEF\x8F\x8F\x8F ",
2595 16,
2596 NULL,
2597 0,
2598 MHD_WEBSOCKET_STATUS_UTF8_ENCODING_ERROR,
2599 MHD_WEBSOCKET_VALIDITY_INVALID,
2600 10);
2601 /* Regular test: A four byte UTF-8 sequence */
2602 failed += test_decode_single (__LINE__,
2603 MHD_WEBSOCKET_FLAG_SERVER
2604 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
2605 0,
2606 1,
2607 0,
2608 "\x81\x8A\x00\x00\x00\x00 \xF2\x8F\x8F\x8F ",
2609 16,
2610 " \xF2\x8F\x8F\x8F ",
2611 10,
2612 MHD_WEBSOCKET_STATUS_TEXT_FRAME,
2613 MHD_WEBSOCKET_VALIDITY_VALID,
2614 16);
2615 /* Fail test: A broken four byte UTF-8 sequence (three of four bytes) */
2616 failed += test_decode_single (__LINE__,
2617 MHD_WEBSOCKET_FLAG_SERVER
2618 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
2619 0,
2620 1,
2621 0,
2622 "\x81\x8A\x00\x00\x00\x00 \xF2\x8F\x8F ",
2623 16,
2624 NULL,
2625 0,
2626 MHD_WEBSOCKET_STATUS_UTF8_ENCODING_ERROR,
2627 MHD_WEBSOCKET_VALIDITY_INVALID,
2628 10);
2629 /* Fail test: A broken four byte UTF-8 sequence (two of four bytes) */
2630 failed += test_decode_single (__LINE__,
2631 MHD_WEBSOCKET_FLAG_SERVER
2632 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
2633 0,
2634 1,
2635 0,
2636 "\x81\x8A\x00\x00\x00\x00 \xF2\x8F ",
2637 16,
2638 NULL,
2639 0,
2640 MHD_WEBSOCKET_STATUS_UTF8_ENCODING_ERROR,
2641 MHD_WEBSOCKET_VALIDITY_INVALID,
2642 9);
2643 /* Fail test: A broken four byte UTF-8 sequence (one of four bytes) */
2644 failed += test_decode_single (__LINE__,
2645 MHD_WEBSOCKET_FLAG_SERVER
2646 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
2647 0,
2648 1,
2649 0,
2650 "\x81\x8A\x00\x00\x00\x00 \xF2 ",
2651 16,
2652 NULL,
2653 0,
2654 MHD_WEBSOCKET_STATUS_UTF8_ENCODING_ERROR,
2655 MHD_WEBSOCKET_VALIDITY_INVALID,
2656 8);
2657 /* Fail test: A four byte UTF-8 sequence followed by UTF-8 tail */
2658 failed += test_decode_single (__LINE__,
2659 MHD_WEBSOCKET_FLAG_SERVER
2660 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
2661 0,
2662 1,
2663 0,
2664 "\x81\x8A\x00\x00\x00\x00 \xF2\x8F\x8F\x8F\x8F ",
2665 16,
2666 NULL,
2667 0,
2668 MHD_WEBSOCKET_STATUS_UTF8_ENCODING_ERROR,
2669 MHD_WEBSOCKET_VALIDITY_INVALID,
2670 11);
2671 /* Fail test: A five byte UTF-8 sequence (only up to four bytes allowed) */
2672 failed += test_decode_single (__LINE__,
2673 MHD_WEBSOCKET_FLAG_SERVER
2674 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
2675 0,
2676 1,
2677 0,
2678 "\x81\x8A\x00\x00\x00\x00 \xFB\x8F\x8F\x8F\x8F ",
2679 16,
2680 NULL,
2681 0,
2682 MHD_WEBSOCKET_STATUS_UTF8_ENCODING_ERROR,
2683 MHD_WEBSOCKET_VALIDITY_INVALID,
2684 7);
2685 /* Fail test: A six byte UTF-8 sequence (only up to four bytes allowed) */
2686 failed += test_decode_single (__LINE__,
2687 MHD_WEBSOCKET_FLAG_SERVER
2688 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
2689 0,
2690 1,
2691 0,
2692 "\x81\x8A\x00\x00\x00\x00 \xFD\x8F\x8F\x8F\x8F\x8F ",
2693 16,
2694 NULL,
2695 0,
2696 MHD_WEBSOCKET_STATUS_UTF8_ENCODING_ERROR,
2697 MHD_WEBSOCKET_VALIDITY_INVALID,
2698 7);
2699 /* Fail test: A seven byte UTF-8 sequence (only up to four bytes allowed) */
2700 failed += test_decode_single (__LINE__,
2701 MHD_WEBSOCKET_FLAG_SERVER
2702 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
2703 0,
2704 1,
2705 0,
2706 "\x81\x8A\x00\x00\x00\x00 \xFE\x8F\x8F\x8F\x8F\x8F\x8F ",
2707 16,
2708 NULL,
2709 0,
2710 MHD_WEBSOCKET_STATUS_UTF8_ENCODING_ERROR,
2711 MHD_WEBSOCKET_VALIDITY_INVALID,
2712 7);
2713 /* Fail test: A eight byte UTF-8 sequence (only up to four bytes allowed) */
2714 failed += test_decode_single (__LINE__,
2715 MHD_WEBSOCKET_FLAG_SERVER
2716 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
2717 0,
2718 1,
2719 0,
2720 "\x81\x8A\x00\x00\x00\x00 \xFF\x8F\x8F\x8F\x8F\x8F\x8F\x8F ",
2721 16,
2722 NULL,
2723 0,
2724 MHD_WEBSOCKET_STATUS_UTF8_ENCODING_ERROR,
2725 MHD_WEBSOCKET_VALIDITY_INVALID,
2726 7);
2727 /* Edge test (success): The maxium allowed UTF-8 character */
2728 failed += test_decode_single (__LINE__,
2729 MHD_WEBSOCKET_FLAG_SERVER
2730 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
2731 0,
2732 1,
2733 0,
2734 "\x81\x8A\x00\x00\x00\x00 \xF4\x8F\xBF\xBF ",
2735 16,
2736 " \xF4\x8F\xBF\xBF ",
2737 10,
2738 MHD_WEBSOCKET_STATUS_TEXT_FRAME,
2739 MHD_WEBSOCKET_VALIDITY_VALID,
2740 16);
2741 /* Edge test (fail): The maxium allowed UTF-8 character + 1 */
2742 failed += test_decode_single (__LINE__,
2743 MHD_WEBSOCKET_FLAG_SERVER
2744 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
2745 0,
2746 1,
2747 0,
2748 "\x81\x8A\x00\x00\x00\x00 \xF4\x90\x80\x80 ",
2749 16,
2750 NULL,
2751 0,
2752 MHD_WEBSOCKET_STATUS_UTF8_ENCODING_ERROR,
2753 MHD_WEBSOCKET_VALIDITY_INVALID,
2754 8);
2755 /* Edge test (success): The last valid UTF8-1 character */
2756 failed += test_decode_single (__LINE__,
2757 MHD_WEBSOCKET_FLAG_SERVER
2758 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
2759 0,
2760 1,
2761 0,
2762 "\x81\x8A\x00\x00\x00\x00 \x7F ",
2763 16,
2764 " \x7F ",
2765 10,
2766 MHD_WEBSOCKET_STATUS_TEXT_FRAME,
2767 MHD_WEBSOCKET_VALIDITY_VALID,
2768 16);
2769 /* Edge test (fail): The value after the last valid UTF8-1 character */
2770 failed += test_decode_single (__LINE__,
2771 MHD_WEBSOCKET_FLAG_SERVER
2772 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
2773 0,
2774 1,
2775 0,
2776 "\x81\x8A\x00\x00\x00\x00 \x80 ",
2777 16,
2778 NULL,
2779 0,
2780 MHD_WEBSOCKET_STATUS_UTF8_ENCODING_ERROR,
2781 MHD_WEBSOCKET_VALIDITY_INVALID,
2782 7);
2783 /* Edge test (fail): The value before the first valid UTF8-2 character */
2784 failed += test_decode_single (__LINE__,
2785 MHD_WEBSOCKET_FLAG_SERVER
2786 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
2787 0,
2788 1,
2789 0,
2790 "\x81\x8A\x00\x00\x00\x00 \xC1\x80 ",
2791 16,
2792 NULL,
2793 0,
2794 MHD_WEBSOCKET_STATUS_UTF8_ENCODING_ERROR,
2795 MHD_WEBSOCKET_VALIDITY_INVALID,
2796 7);
2797 /* Edge test (success): The first valid UTF8-2 character */
2798 failed += test_decode_single (__LINE__,
2799 MHD_WEBSOCKET_FLAG_SERVER
2800 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
2801 0,
2802 1,
2803 0,
2804 "\x81\x8A\x00\x00\x00\x00 \xC2\x80 ",
2805 16,
2806 " \xC2\x80 ",
2807 10,
2808 MHD_WEBSOCKET_STATUS_TEXT_FRAME,
2809 MHD_WEBSOCKET_VALIDITY_VALID,
2810 16);
2811 /* Edge test (success): The last valid UTF8-2 character */
2812 failed += test_decode_single (__LINE__,
2813 MHD_WEBSOCKET_FLAG_SERVER
2814 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
2815 0,
2816 1,
2817 0,
2818 "\x81\x8A\x00\x00\x00\x00 \xDF\xBF ",
2819 16,
2820 " \xDF\xBF ",
2821 10,
2822 MHD_WEBSOCKET_STATUS_TEXT_FRAME,
2823 MHD_WEBSOCKET_VALIDITY_VALID,
2824 16);
2825 /* Edge test (fail): The value after the lst valid UTF8-2 character */
2826 failed += test_decode_single (__LINE__,
2827 MHD_WEBSOCKET_FLAG_SERVER
2828 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
2829 0,
2830 1,
2831 0,
2832 "\x81\x8A\x00\x00\x00\x00 \xE0\x80 ",
2833 16,
2834 NULL,
2835 0,
2836 MHD_WEBSOCKET_STATUS_UTF8_ENCODING_ERROR,
2837 MHD_WEBSOCKET_VALIDITY_INVALID,
2838 8);
2839 /* Edge test (fail): The value before the first valid UTF8-3 character (tail 1) */
2840 failed += test_decode_single (__LINE__,
2841 MHD_WEBSOCKET_FLAG_SERVER
2842 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
2843 0,
2844 1,
2845 0,
2846 "\x81\x8A\x00\x00\x00\x00 \xE0\x9F\x80 ",
2847 16,
2848 NULL,
2849 0,
2850 MHD_WEBSOCKET_STATUS_UTF8_ENCODING_ERROR,
2851 MHD_WEBSOCKET_VALIDITY_INVALID,
2852 8);
2853 /* Edge test (success): The first valid UTF8-3 character (tail 1) */
2854 failed += test_decode_single (__LINE__,
2855 MHD_WEBSOCKET_FLAG_SERVER
2856 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
2857 0,
2858 1,
2859 0,
2860 "\x81\x8A\x00\x00\x00\x00 \xE0\xA0\x80 ",
2861 16,
2862 " \xE0\xA0\x80 ",
2863 10,
2864 MHD_WEBSOCKET_STATUS_TEXT_FRAME,
2865 MHD_WEBSOCKET_VALIDITY_VALID,
2866 16);
2867 /* Edge test (success): The last valid UTF8-3 character (tail 1) */
2868 failed += test_decode_single (__LINE__,
2869 MHD_WEBSOCKET_FLAG_SERVER
2870 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
2871 0,
2872 1,
2873 0,
2874 "\x81\x8A\x00\x00\x00\x00 \xE0\xBF\xBF ",
2875 16,
2876 " \xE0\xBF\xBF ",
2877 10,
2878 MHD_WEBSOCKET_STATUS_TEXT_FRAME,
2879 MHD_WEBSOCKET_VALIDITY_VALID,
2880 16);
2881 /* Edge test (fail): The value after the first valid UTF8-3 character (tail 1) */
2882 failed += test_decode_single (__LINE__,
2883 MHD_WEBSOCKET_FLAG_SERVER
2884 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
2885 0,
2886 1,
2887 0,
2888 "\x81\x8A\x00\x00\x00\x00 \xE0\xC0\x80 ",
2889 16,
2890 NULL,
2891 0,
2892 MHD_WEBSOCKET_STATUS_UTF8_ENCODING_ERROR,
2893 MHD_WEBSOCKET_VALIDITY_INVALID,
2894 8);
2895 /* Edge test (success): The first valid UTF8-3 character (tail 2) */
2896 failed += test_decode_single (__LINE__,
2897 MHD_WEBSOCKET_FLAG_SERVER
2898 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
2899 0,
2900 1,
2901 0,
2902 "\x81\x8A\x00\x00\x00\x00 \xE1\x80\x80 ",
2903 16,
2904 " \xE1\x80\x80 ",
2905 10,
2906 MHD_WEBSOCKET_STATUS_TEXT_FRAME,
2907 MHD_WEBSOCKET_VALIDITY_VALID,
2908 16);
2909 /* Edge test (success): The last valid UTF8-3 character (tail 2) */
2910 failed += test_decode_single (__LINE__,
2911 MHD_WEBSOCKET_FLAG_SERVER
2912 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
2913 0,
2914 1,
2915 0,
2916 "\x81\x8A\x00\x00\x00\x00 \xEC\xBF\xBF ",
2917 16,
2918 " \xEC\xBF\xBF ",
2919 10,
2920 MHD_WEBSOCKET_STATUS_TEXT_FRAME,
2921 MHD_WEBSOCKET_VALIDITY_VALID,
2922 16);
2923 /* Edge test (fail): The value after the last valid UTF8-3 character (tail 2) */
2924 failed += test_decode_single (__LINE__,
2925 MHD_WEBSOCKET_FLAG_SERVER
2926 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
2927 0,
2928 1,
2929 0,
2930 "\x81\x8A\x00\x00\x00\x00 \xEC\xC0\xBF ",
2931 16,
2932 NULL,
2933 0,
2934 MHD_WEBSOCKET_STATUS_UTF8_ENCODING_ERROR,
2935 MHD_WEBSOCKET_VALIDITY_INVALID,
2936 8);
2937 /* Edge test (fail): The value before the first valid UTF8-3 character (tail 3) */
2938 failed += test_decode_single (__LINE__,
2939 MHD_WEBSOCKET_FLAG_SERVER
2940 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
2941 0,
2942 1,
2943 0,
2944 "\x81\x8A\x00\x00\x00\x00 \xED\x7F\x80 ",
2945 16,
2946 NULL,
2947 0,
2948 MHD_WEBSOCKET_STATUS_UTF8_ENCODING_ERROR,
2949 MHD_WEBSOCKET_VALIDITY_INVALID,
2950 8);
2951 /* Edge test (success): The first valid UTF8-3 character (tail 3) */
2952 failed += test_decode_single (__LINE__,
2953 MHD_WEBSOCKET_FLAG_SERVER
2954 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
2955 0,
2956 1,
2957 0,
2958 "\x81\x8A\x00\x00\x00\x00 \xED\x80\x80 ",
2959 16,
2960 " \xED\x80\x80 ",
2961 10,
2962 MHD_WEBSOCKET_STATUS_TEXT_FRAME,
2963 MHD_WEBSOCKET_VALIDITY_VALID,
2964 16);
2965 /* Edge test (success): The last valid UTF8-3 character (tail 3) */
2966 failed += test_decode_single (__LINE__,
2967 MHD_WEBSOCKET_FLAG_SERVER
2968 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
2969 0,
2970 1,
2971 0,
2972 "\x81\x8A\x00\x00\x00\x00 \xED\x9F\xBF ",
2973 16,
2974 " \xED\x9F\xBF ",
2975 10,
2976 MHD_WEBSOCKET_STATUS_TEXT_FRAME,
2977 MHD_WEBSOCKET_VALIDITY_VALID,
2978 16);
2979 /* Edge test (fail): The value after the last valid UTF8-3 character (tail 3) */
2980 failed += test_decode_single (__LINE__,
2981 MHD_WEBSOCKET_FLAG_SERVER
2982 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
2983 0,
2984 1,
2985 0,
2986 "\x81\x8A\x00\x00\x00\x00 \xED\xA0\x80 ",
2987 16,
2988 NULL,
2989 0,
2990 MHD_WEBSOCKET_STATUS_UTF8_ENCODING_ERROR,
2991 MHD_WEBSOCKET_VALIDITY_INVALID,
2992 8);
2993 /* Edge test (fail): The value before the first valid UTF8-3 character (tail 4) */
2994 failed += test_decode_single (__LINE__,
2995 MHD_WEBSOCKET_FLAG_SERVER
2996 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
2997 0,
2998 1,
2999 0,
3000 "\x81\x8A\x00\x00\x00\x00 \xEE\x7F\x80 ",
3001 16,
3002 NULL,
3003 0,
3004 MHD_WEBSOCKET_STATUS_UTF8_ENCODING_ERROR,
3005 MHD_WEBSOCKET_VALIDITY_INVALID,
3006 8);
3007 /* Edge test (success): The first valid UTF8-3 character (tail 4) */
3008 failed += test_decode_single (__LINE__,
3009 MHD_WEBSOCKET_FLAG_SERVER
3010 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
3011 0,
3012 1,
3013 0,
3014 "\x81\x8A\x00\x00\x00\x00 \xEE\x80\x80 ",
3015 16,
3016 " \xEE\x80\x80 ",
3017 10,
3018 MHD_WEBSOCKET_STATUS_TEXT_FRAME,
3019 MHD_WEBSOCKET_VALIDITY_VALID,
3020 16);
3021 /* Edge test (success): The last valid UTF8-3 character (tail 4) */
3022 failed += test_decode_single (__LINE__,
3023 MHD_WEBSOCKET_FLAG_SERVER
3024 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
3025 0,
3026 1,
3027 0,
3028 "\x81\x8A\x00\x00\x00\x00 \xEF\xBF\xBF ",
3029 16,
3030 " \xEF\xBF\xBF ",
3031 10,
3032 MHD_WEBSOCKET_STATUS_TEXT_FRAME,
3033 MHD_WEBSOCKET_VALIDITY_VALID,
3034 16);
3035 /* Edge test (fail): The value after the last valid UTF8-3 character (tail 4) */
3036 failed += test_decode_single (__LINE__,
3037 MHD_WEBSOCKET_FLAG_SERVER
3038 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
3039 0,
3040 1,
3041 0,
3042 "\x81\x8A\x00\x00\x00\x00 \xEF\xBF\xC0 ",
3043 16,
3044 NULL,
3045 0,
3046 MHD_WEBSOCKET_STATUS_UTF8_ENCODING_ERROR,
3047 MHD_WEBSOCKET_VALIDITY_INVALID,
3048 9);
3049 /* Edge test (fail): The value after the last valid UTF8-3 character (tail 4) #2 */
3050 failed += test_decode_single (__LINE__,
3051 MHD_WEBSOCKET_FLAG_SERVER
3052 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
3053 0,
3054 1,
3055 0,
3056 "\x81\x8A\x00\x00\x00\x00 \xEF\xC0\xBF ",
3057 16,
3058 NULL,
3059 0,
3060 MHD_WEBSOCKET_STATUS_UTF8_ENCODING_ERROR,
3061 MHD_WEBSOCKET_VALIDITY_INVALID,
3062 8);
3063 /* Edge test (fail): The value before the first valid UTF8-4 character (tail 1) */
3064 failed += test_decode_single (__LINE__,
3065 MHD_WEBSOCKET_FLAG_SERVER
3066 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
3067 0,
3068 1,
3069 0,
3070 "\x81\x8A\x00\x00\x00\x00 \xF0\x8F\x80\x80 ",
3071 16,
3072 NULL,
3073 0,
3074 MHD_WEBSOCKET_STATUS_UTF8_ENCODING_ERROR,
3075 MHD_WEBSOCKET_VALIDITY_INVALID,
3076 8);
3077 /* Edge test (success): The first valid UTF8-4 character (tail 1) */
3078 failed += test_decode_single (__LINE__,
3079 MHD_WEBSOCKET_FLAG_SERVER
3080 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
3081 0,
3082 1,
3083 0,
3084 "\x81\x8A\x00\x00\x00\x00 \xF0\x90\x80\x80 ",
3085 16,
3086 " \xF0\x90\x80\x80 ",
3087 10,
3088 MHD_WEBSOCKET_STATUS_TEXT_FRAME,
3089 MHD_WEBSOCKET_VALIDITY_VALID,
3090 16);
3091 /* Edge test (success): The last valid UTF8-4 character (tail 1) */
3092 failed += test_decode_single (__LINE__,
3093 MHD_WEBSOCKET_FLAG_SERVER
3094 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
3095 0,
3096 1,
3097 0,
3098 "\x81\x8A\x00\x00\x00\x00 \xF0\xBF\xBF\xBF ",
3099 16,
3100 " \xF0\xBF\xBF\xBF ",
3101 10,
3102 MHD_WEBSOCKET_STATUS_TEXT_FRAME,
3103 MHD_WEBSOCKET_VALIDITY_VALID,
3104 16);
3105 /* Edge test (success): The first valid UTF8-4 character (tail 2) */
3106 failed += test_decode_single (__LINE__,
3107 MHD_WEBSOCKET_FLAG_SERVER
3108 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
3109 0,
3110 1,
3111 0,
3112 "\x81\x8A\x00\x00\x00\x00 \xF1\x80\x80\x80 ",
3113 16,
3114 " \xF1\x80\x80\x80 ",
3115 10,
3116 MHD_WEBSOCKET_STATUS_TEXT_FRAME,
3117 MHD_WEBSOCKET_VALIDITY_VALID,
3118 16);
3119 /* Edge test (success): The last valid UTF8-4 character (tail 2) */
3120 failed += test_decode_single (__LINE__,
3121 MHD_WEBSOCKET_FLAG_SERVER
3122 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
3123 0,
3124 1,
3125 0,
3126 "\x81\x8A\x00\x00\x00\x00 \xF3\xBF\xBF\xBF ",
3127 16,
3128 " \xF3\xBF\xBF\xBF ",
3129 10,
3130 MHD_WEBSOCKET_STATUS_TEXT_FRAME,
3131 MHD_WEBSOCKET_VALIDITY_VALID,
3132 16);
3133 /* Edge test (fail): A value before the last valid UTF8-4 character in the second byte (tail 2) */
3134 failed += test_decode_single (__LINE__,
3135 MHD_WEBSOCKET_FLAG_SERVER
3136 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
3137 0,
3138 1,
3139 0,
3140 "\x81\x8A\x00\x00\x00\x00 \xF3\x7F\x80\x80 ",
3141 16,
3142 NULL,
3143 0,
3144 MHD_WEBSOCKET_STATUS_UTF8_ENCODING_ERROR,
3145 MHD_WEBSOCKET_VALIDITY_INVALID,
3146 8);
3147 /* Edge test (fail): A value after the last valid UTF8-4 character in the second byte (tail 2) */
3148 failed += test_decode_single (__LINE__,
3149 MHD_WEBSOCKET_FLAG_SERVER
3150 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
3151 0,
3152 1,
3153 0,
3154 "\x81\x8A\x00\x00\x00\x00 \xF3\xC0\x80\x80 ",
3155 16,
3156 NULL,
3157 0,
3158 MHD_WEBSOCKET_STATUS_UTF8_ENCODING_ERROR,
3159 MHD_WEBSOCKET_VALIDITY_INVALID,
3160 8);
3161 /* Edge test (success): The first valid UTF8-4 character (tail 3) */
3162 failed += test_decode_single (__LINE__,
3163 MHD_WEBSOCKET_FLAG_SERVER
3164 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
3165 0,
3166 1,
3167 0,
3168 "\x81\x8A\x00\x00\x00\x00 \xF4\x80\x80\x80 ",
3169 16,
3170 " \xF4\x80\x80\x80 ",
3171 10,
3172 MHD_WEBSOCKET_STATUS_TEXT_FRAME,
3173 MHD_WEBSOCKET_VALIDITY_VALID,
3174 16);
3175 /* Edge test (success): The last valid UTF8-4 character (tail 3) */
3176 failed += test_decode_single (__LINE__,
3177 MHD_WEBSOCKET_FLAG_SERVER
3178 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
3179 0,
3180 1,
3181 0,
3182 "\x81\x8A\x00\x00\x00\x00 \xF4\x8F\xBF\xBF ",
3183 16,
3184 " \xF4\x8F\xBF\xBF ",
3185 10,
3186 MHD_WEBSOCKET_STATUS_TEXT_FRAME,
3187 MHD_WEBSOCKET_VALIDITY_VALID,
3188 16);
3189 /* Edge test (fail): The value after the last valid UTF8-4 character (tail 3) */
3190 failed += test_decode_single (__LINE__,
3191 MHD_WEBSOCKET_FLAG_SERVER
3192 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
3193 0,
3194 1,
3195 0,
3196 "\x81\x8A\x00\x00\x00\x00 \xF4\x90\x80\x80 ",
3197 16,
3198 NULL,
3199 0,
3200 MHD_WEBSOCKET_STATUS_UTF8_ENCODING_ERROR,
3201 MHD_WEBSOCKET_VALIDITY_INVALID,
3202 8);
3203 /* Edge test (fail): The first byte value the last valid UTF8-4 character */
3204 failed += test_decode_single (__LINE__,
3205 MHD_WEBSOCKET_FLAG_SERVER
3206 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
3207 0,
3208 1,
3209 0,
3210 "\x81\x8A\x00\x00\x00\x00 \xF5\x90\x80\x80 ",
3211 16,
3212 NULL,
3213 0,
3214 MHD_WEBSOCKET_STATUS_UTF8_ENCODING_ERROR,
3215 MHD_WEBSOCKET_VALIDITY_INVALID,
3216 7);
3217
3218 /*
3219 ------------------------------------------------------------------------------
3220 Unfinished UTF-8 sequence between fragmented text frame
3221 ------------------------------------------------------------------------------
3222 */
3223 /* Regular test: UTF-8 sequence between fragments, no fragmentation for the caller */
3224 failed += test_decode_single (__LINE__,
3225 MHD_WEBSOCKET_FLAG_SERVER
3226 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
3227 0,
3228 1,
3229 0,
3230 "\x01\x8D\x00\x00\x00\x00" "This is my n"
3231 "\xC3\x80\x83\x00\x00\x00\x00\xB6" "te",
3232 28,
3233 "This is my n" "\xC3\xB6" "te",
3234 16,
3235 MHD_WEBSOCKET_STATUS_TEXT_FRAME,
3236 MHD_WEBSOCKET_VALIDITY_VALID,
3237 28);
3238 /* Regular test: UTF-8 sequence between fragments, fragmentation for the caller, 1st call */
3239 failed += test_decode_single (__LINE__,
3240 MHD_WEBSOCKET_FLAG_SERVER
3241 | MHD_WEBSOCKET_FLAG_WANT_FRAGMENTS,
3242 0,
3243 1,
3244 0,
3245 "\x01\x8D\x00\x00\x00\x00" "This is my n"
3246 "\xC3\x80\x83\x00\x00\x00\x00\xB6" "te",
3247 28,
3248 "This is my n",
3249 12,
3250 MHD_WEBSOCKET_STATUS_TEXT_FRAGMENT,
3251 MHD_WEBSOCKET_VALIDITY_VALID,
3252 19);
3253 /* Regular test: UTF-8 sequence between fragments, fragmentation for the caller, 2nd call */
3254 failed += test_decode_single (__LINE__,
3255 MHD_WEBSOCKET_FLAG_SERVER
3256 | MHD_WEBSOCKET_FLAG_WANT_FRAGMENTS,
3257 0,
3258 2,
3259 0,
3260 "\x01\x8D\x00\x00\x00\x00" "This is my n"
3261 "\xC3\x80\x83\x00\x00\x00\x00\xB6" "te",
3262 28,
3263 "\xC3\xB6" "te",
3264 4,
3265 MHD_WEBSOCKET_STATUS_TEXT_LAST_FRAGMENT,
3266 MHD_WEBSOCKET_VALIDITY_VALID,
3267 28);
3268 /* Edge test (success): UTF-8 sequence between fragments, but nothing before, fragmentation for the caller, 1st call */
3269 failed += test_decode_single (__LINE__,
3270 MHD_WEBSOCKET_FLAG_SERVER
3271 | MHD_WEBSOCKET_FLAG_WANT_FRAGMENTS,
3272 0,
3273 1,
3274 0,
3275 "\x01\x81\x00\x00\x00\x00\xC3\x80\x81\x00\x00\x00\x00\xB6",
3276 14,
3277 NULL,
3278 0,
3279 MHD_WEBSOCKET_STATUS_TEXT_FRAGMENT,
3280 MHD_WEBSOCKET_VALIDITY_VALID,
3281 7);
3282 /* Edge test (success): UTF-8 sequence between fragments, but nothing before, fragmentation for the caller, 2nd call */
3283 failed += test_decode_single (__LINE__,
3284 MHD_WEBSOCKET_FLAG_SERVER
3285 | MHD_WEBSOCKET_FLAG_WANT_FRAGMENTS,
3286 0,
3287 2,
3288 0,
3289 "\x01\x81\x00\x00\x00\x00\xC3\x80\x81\x00\x00\x00\x00\xB6",
3290 14,
3291 "\xC3\xB6",
3292 2,
3293 MHD_WEBSOCKET_STATUS_TEXT_LAST_FRAGMENT,
3294 MHD_WEBSOCKET_VALIDITY_VALID,
3295 14);
3296
3297 /*
3298 ------------------------------------------------------------------------------
3299 Decoding with broken stream
3300 ------------------------------------------------------------------------------
3301 */
3302 /* Failure test: Invalid sequence */
3303 failed += test_decode_single (__LINE__,
3304 MHD_WEBSOCKET_FLAG_SERVER
3305 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
3306 0,
3307 1,
3308 0,
3309 "\xFF\x81\x85\x00\x00\x00\x00" "Hello",
3310 12,
3311 NULL,
3312 0,
3313 MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR,
3314 MHD_WEBSOCKET_VALIDITY_INVALID,
3315 0);
3316 /* Failure test: Call after invalidated stream */
3317 failed += test_decode_single (__LINE__,
3318 MHD_WEBSOCKET_FLAG_SERVER
3319 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
3320 0,
3321 2,
3322 0,
3323 "\xFF\x81\x85\x00\x00\x00\x00" "Hello",
3324 12,
3325 NULL,
3326 0,
3327 MHD_WEBSOCKET_STATUS_STREAM_BROKEN,
3328 MHD_WEBSOCKET_VALIDITY_INVALID,
3329 0);
3330 /* Failure test: Call after invalidated stream (but with different buffer) */
3331 {
3332 struct MHD_WebSocketStream*ws;
3333 if (MHD_WEBSOCKET_STATUS_OK == MHD_websocket_stream_init (&ws,
3334 MHD_WEBSOCKET_FLAG_SERVER
3335 |
3336 MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
3337 0))
3338 {
3339 size_t streambuf_read_len = 0;
3340 char*payload = NULL;
3341 size_t payload_len = 0;
3342 int ret = 0;
3343 ret = MHD_websocket_decode (ws,
3344 "\xFF",
3345 1,
3346 &streambuf_read_len,
3347 &payload,
3348 &payload_len);
3349 if (MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR != ret)
3350 {
3351 fprintf (stderr,
3352 "Test failed in line %u: The return value should be -1, but is %d\n",
3353 (unsigned int) __LINE__,
3354 (int) ret);
3355 ++failed;
3356 }
3357 else
3358 {
3359 ret = MHD_websocket_decode (ws,
3360 "\x81\x85\x00\x00\x00\x00" "Hello",
3361 11,
3362 &streambuf_read_len,
3363 &payload,
3364 &payload_len);
3365 if (MHD_WEBSOCKET_STATUS_STREAM_BROKEN != ret)
3366 {
3367 fprintf (stderr,
3368 "Test failed in line %u: The return value should be -2, but is %d\n",
3369 (unsigned int) __LINE__,
3370 (int) ret);
3371 ++failed;
3372 }
3373 }
3374 MHD_websocket_stream_free (ws);
3375 }
3376 else
3377 {
3378 fprintf (stderr,
3379 "Individual test failed in line %u\n",
3380 (unsigned int) __LINE__);
3381 ++failed;
3382 }
3383 }
3384
3385 /*
3386 ------------------------------------------------------------------------------
3387 frame after close frame
3388 ------------------------------------------------------------------------------
3389 */
3390 /* Regular test: Close frame */
3391 failed += test_decode_single (__LINE__,
3392 MHD_WEBSOCKET_FLAG_SERVER
3393 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
3394 0,
3395 1,
3396 0,
3397 "\x88\x80\x00\x00\x00\x00\x81\x85\x00\x00\x00\x00"
3398 "Hello",
3399 17,
3400 NULL,
3401 0,
3402 MHD_WEBSOCKET_STATUS_CLOSE_FRAME,
3403 MHD_WEBSOCKET_VALIDITY_ONLY_VALID_FOR_CONTROL_FRAMES,
3404 6);
3405 /* Failure test: Text frame after close frame */
3406 failed += test_decode_single (__LINE__,
3407 MHD_WEBSOCKET_FLAG_SERVER
3408 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
3409 0,
3410 2,
3411 0,
3412 "\x88\x80\x00\x00\x00\x00\x81\x85\x00\x00\x00\x00"
3413 "Hello",
3414 17,
3415 NULL,
3416 0,
3417 MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR,
3418 MHD_WEBSOCKET_VALIDITY_INVALID,
3419 6);
3420 /* Failure test: Binary frame after close frame */
3421 failed += test_decode_single (__LINE__,
3422 MHD_WEBSOCKET_FLAG_SERVER
3423 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
3424 0,
3425 2,
3426 0,
3427 "\x88\x80\x00\x00\x00\x00\x82\x85\x00\x00\x00\x00"
3428 "Hello",
3429 17,
3430 NULL,
3431 0,
3432 MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR,
3433 MHD_WEBSOCKET_VALIDITY_INVALID,
3434 6);
3435 /* Failure test: Continue frame after close frame */
3436 failed += test_decode_single (__LINE__,
3437 MHD_WEBSOCKET_FLAG_SERVER
3438 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
3439 0,
3440 2,
3441 0,
3442 "\x88\x80\x00\x00\x00\x00\x80\x85\x00\x00\x00\x00"
3443 "Hello",
3444 17,
3445 NULL,
3446 0,
3447 MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR,
3448 MHD_WEBSOCKET_VALIDITY_INVALID,
3449 6);
3450 /* Regular test: Ping frame after close frame */
3451 failed += test_decode_single (__LINE__,
3452 MHD_WEBSOCKET_FLAG_SERVER
3453 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
3454 0,
3455 2,
3456 0,
3457 "\x88\x80\x00\x00\x00\x00\x89\x85\x00\x00\x00\x00"
3458 "Hello",
3459 17,
3460 "Hello",
3461 5,
3462 MHD_WEBSOCKET_STATUS_PING_FRAME,
3463 MHD_WEBSOCKET_VALIDITY_ONLY_VALID_FOR_CONTROL_FRAMES,
3464 17);
3465 /* Regular test: Pong frame after close frame */
3466 failed += test_decode_single (__LINE__,
3467 MHD_WEBSOCKET_FLAG_SERVER
3468 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
3469 0,
3470 2,
3471 0,
3472 "\x88\x80\x00\x00\x00\x00\x8A\x85\x00\x00\x00\x00"
3473 "Hello",
3474 17,
3475 "Hello",
3476 5,
3477 MHD_WEBSOCKET_STATUS_PONG_FRAME,
3478 MHD_WEBSOCKET_VALIDITY_ONLY_VALID_FOR_CONTROL_FRAMES,
3479 17);
3480 /* Regular test: Close frame after close frame */
3481 failed += test_decode_single (__LINE__,
3482 MHD_WEBSOCKET_FLAG_SERVER
3483 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
3484 0,
3485 2,
3486 0,
3487 "\x88\x80\x00\x00\x00\x00\x88\x80\x00\x00\x00\x00",
3488 12,
3489 NULL,
3490 0,
3491 MHD_WEBSOCKET_STATUS_CLOSE_FRAME,
3492 MHD_WEBSOCKET_VALIDITY_ONLY_VALID_FOR_CONTROL_FRAMES,
3493 12);
3494
3495 /*
3496 ------------------------------------------------------------------------------
3497 decoding byte-by-byte
3498 ------------------------------------------------------------------------------
3499 */
3500 /* Regular test: Text frame, 2 bytes per loop, 1st call */
3501 failed += test_decode_single (__LINE__,
3502 MHD_WEBSOCKET_FLAG_SERVER
3503 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
3504 0,
3505 1,
3506 2,
3507 "\x81\x91\x01\x02\x04\x08" "Ujm{!kw(uja(ugw|/",
3508 23,
3509 NULL,
3510 0,
3511 MHD_WEBSOCKET_STATUS_OK,
3512 MHD_WEBSOCKET_VALIDITY_VALID,
3513 2);
3514 /* Regular test: Text frame, 2 bytes per loop, 11th call */
3515 failed += test_decode_single (__LINE__,
3516 MHD_WEBSOCKET_FLAG_SERVER
3517 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
3518 0,
3519 11,
3520 2,
3521 "\x81\x91\x01\x02\x04\x08" "Ujm{!kw(uja(ugw|/",
3522 23,
3523 NULL,
3524 0,
3525 MHD_WEBSOCKET_STATUS_OK,
3526 MHD_WEBSOCKET_VALIDITY_VALID,
3527 22);
3528 /* Regular test: Text frame, 2 bytes per loop, 12th call */
3529 failed += test_decode_single (__LINE__,
3530 MHD_WEBSOCKET_FLAG_SERVER
3531 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
3532 0,
3533 12,
3534 2,
3535 "\x81\x91\x01\x02\x04\x08" "Ujm{!kw(uja(ugw|/",
3536 23,
3537 "This is the test.",
3538 17,
3539 MHD_WEBSOCKET_STATUS_TEXT_FRAME,
3540 MHD_WEBSOCKET_VALIDITY_VALID,
3541 23);
3542 /* Regular test: Text frame, 1 byte per loop, 1st call */
3543 failed += test_decode_single (__LINE__,
3544 MHD_WEBSOCKET_FLAG_SERVER
3545 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
3546 0,
3547 1,
3548 1,
3549 "\x81\x91\x01\x02\x04\x08" "Ujm{!kw(uja(ugw|/",
3550 23,
3551 NULL,
3552 0,
3553 MHD_WEBSOCKET_STATUS_OK,
3554 MHD_WEBSOCKET_VALIDITY_VALID,
3555 1);
3556 /* Regular test: Text frame, 1 byte per loop, 22nd call */
3557 failed += test_decode_single (__LINE__,
3558 MHD_WEBSOCKET_FLAG_SERVER
3559 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
3560 0,
3561 22,
3562 1,
3563 "\x81\x91\x01\x02\x04\x08" "Ujm{!kw(uja(ugw|/",
3564 23,
3565 NULL,
3566 0,
3567 MHD_WEBSOCKET_STATUS_OK,
3568 MHD_WEBSOCKET_VALIDITY_VALID,
3569 22);
3570 /* Regular test: Text frame, 1 byte per loop, 23rd call */
3571 failed += test_decode_single (__LINE__,
3572 MHD_WEBSOCKET_FLAG_SERVER
3573 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
3574 0,
3575 23,
3576 1,
3577 "\x81\x91\x01\x02\x04\x08" "Ujm{!kw(uja(ugw|/",
3578 23,
3579 "This is the test.",
3580 17,
3581 MHD_WEBSOCKET_STATUS_TEXT_FRAME,
3582 MHD_WEBSOCKET_VALIDITY_VALID,
3583 23);
3584
3585 /*
3586 ------------------------------------------------------------------------------
3587 mix of fragmented data frames and control frames
3588 ------------------------------------------------------------------------------
3589 */
3590 /* Regular test: Fragmented text frame mixed with one ping frame (1st call) */
3591 failed += test_decode_single (__LINE__,
3592 MHD_WEBSOCKET_FLAG_SERVER
3593 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
3594 0,
3595 1,
3596 0,
3597 "\x01\x85\x00\x00\x00\x00"
3598 "This \x89\x80\x00\x00\x00\x00"
3599 "\x80\x8C\x00\x00\x00\x00" "is the test.",
3600 35,
3601 NULL,
3602 0,
3603 MHD_WEBSOCKET_STATUS_PING_FRAME,
3604 MHD_WEBSOCKET_VALIDITY_VALID,
3605 17);
3606 /* Regular test: Fragmented text frame mixed with one ping frame (2nd call) */
3607 failed += test_decode_single (__LINE__,
3608 MHD_WEBSOCKET_FLAG_SERVER
3609 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
3610 0,
3611 2,
3612 0,
3613 "\x01\x85\x00\x00\x00\x00"
3614 "This \x89\x80\x00\x00\x00\x00"
3615 "\x80\x8C\x00\x00\x00\x00" "is the test.",
3616 35,
3617 "This is the test.",
3618 17,
3619 MHD_WEBSOCKET_STATUS_TEXT_FRAME,
3620 MHD_WEBSOCKET_VALIDITY_VALID,
3621 35);
3622 /* Regular test: Fragmented text frame mixed with one close frame (1st call) */
3623 failed += test_decode_single (__LINE__,
3624 MHD_WEBSOCKET_FLAG_SERVER
3625 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
3626 0,
3627 1,
3628 0,
3629 "\x01\x85\x00\x00\x00\x00"
3630 "This \x88\x80\x00\x00\x00\x00"
3631 "\x80\x8C\x00\x00\x00\x00" "is the test.",
3632 35,
3633 NULL,
3634 0,
3635 MHD_WEBSOCKET_STATUS_CLOSE_FRAME,
3636 MHD_WEBSOCKET_VALIDITY_ONLY_VALID_FOR_CONTROL_FRAMES,
3637 17);
3638 /* Fail test: Fragmented text frame mixed with one ping frame (2nd call) */
3639 failed += test_decode_single (__LINE__,
3640 MHD_WEBSOCKET_FLAG_SERVER
3641 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
3642 0,
3643 2,
3644 0,
3645 "\x01\x85\x00\x00\x00\x00"
3646 "This \x88\x80\x00\x00\x00\x00"
3647 "\x80\x8C\x00\x00\x00\x00" "is the test.",
3648 35,
3649 NULL,
3650 0,
3651 MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR,
3652 MHD_WEBSOCKET_VALIDITY_INVALID,
3653 17);
3654 /* Regular test: Fragmented text frame mixed with one ping frame, the caller wants fragments (1st call) */
3655 failed += test_decode_single (__LINE__,
3656 MHD_WEBSOCKET_FLAG_SERVER
3657 | MHD_WEBSOCKET_FLAG_WANT_FRAGMENTS,
3658 0,
3659 1,
3660 0,
3661 "\x01\x85\x00\x00\x00\x00"
3662 "This \x89\x80\x00\x00\x00\x00"
3663 "\x80\x8C\x00\x00\x00\x00" "is the test.",
3664 35,
3665 "This ",
3666 5,
3667 MHD_WEBSOCKET_STATUS_TEXT_FRAGMENT,
3668 MHD_WEBSOCKET_VALIDITY_VALID,
3669 11);
3670 /* Regular test: Fragmented text frame mixed with one ping frame, the caller wants fragments (2nd call) */
3671 failed += test_decode_single (__LINE__,
3672 MHD_WEBSOCKET_FLAG_SERVER
3673 | MHD_WEBSOCKET_FLAG_WANT_FRAGMENTS,
3674 0,
3675 2,
3676 0,
3677 "\x01\x85\x00\x00\x00\x00"
3678 "This \x89\x80\x00\x00\x00\x00"
3679 "\x80\x8C\x00\x00\x00\x00" "is the test.",
3680 35,
3681 NULL,
3682 0,
3683 MHD_WEBSOCKET_STATUS_PING_FRAME,
3684 MHD_WEBSOCKET_VALIDITY_VALID,
3685 17);
3686 /* Regular test: Fragmented text frame mixed with one ping frame, the caller wants fragments (3rd call) */
3687 failed += test_decode_single (__LINE__,
3688 MHD_WEBSOCKET_FLAG_SERVER
3689 | MHD_WEBSOCKET_FLAG_WANT_FRAGMENTS,
3690 0,
3691 3,
3692 0,
3693 "\x01\x85\x00\x00\x00\x00"
3694 "This \x89\x80\x00\x00\x00\x00"
3695 "\x80\x8C\x00\x00\x00\x00" "is the test.",
3696 35,
3697 "is the test.",
3698 12,
3699 MHD_WEBSOCKET_STATUS_TEXT_LAST_FRAGMENT,
3700 MHD_WEBSOCKET_VALIDITY_VALID,
3701 35);
3702
3703 /*
3704 ------------------------------------------------------------------------------
3705 mix of fragmented data frames and data frames
3706 ------------------------------------------------------------------------------
3707 */
3708 /* Fail test: Fragmented text frame mixed with one non-fragmented binary frame */
3709 failed += test_decode_single (__LINE__,
3710 MHD_WEBSOCKET_FLAG_SERVER
3711 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
3712 0,
3713 1,
3714 0,
3715 "\x01\x85\x00\x00\x00\x00"
3716 "This \x82\x81\x00\x00\x00\x00"
3717 "a\x80\x8C\x00\x00\x00\x00" "is the test.",
3718 36,
3719 NULL,
3720 0,
3721 MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR,
3722 MHD_WEBSOCKET_VALIDITY_INVALID,
3723 11);
3724 /* Regular test: Fragmented text frame mixed with one non-fragmented binary frame; the caller wants fragments; 1st call */
3725 failed += test_decode_single (__LINE__,
3726 MHD_WEBSOCKET_FLAG_SERVER
3727 | MHD_WEBSOCKET_FLAG_WANT_FRAGMENTS,
3728 0,
3729 1,
3730 0,
3731 "\x01\x85\x00\x00\x00\x00"
3732 "This \x82\x81\x00\x00\x00\x00"
3733 "a\x80\x8C\x00\x00\x00\x00" "is the test.",
3734 36,
3735 "This ",
3736 5,
3737 MHD_WEBSOCKET_STATUS_TEXT_FRAGMENT,
3738 MHD_WEBSOCKET_VALIDITY_VALID,
3739 11);
3740 /* Fail test: Fragmented text frame mixed with one non-fragmented binary frame; the caller wants fragments; 2nd call */
3741 failed += test_decode_single (__LINE__,
3742 MHD_WEBSOCKET_FLAG_SERVER
3743 | MHD_WEBSOCKET_FLAG_WANT_FRAGMENTS,
3744 0,
3745 2,
3746 0,
3747 "\x01\x85\x00\x00\x00\x00"
3748 "This \x82\x81\x00\x00\x00\x00"
3749 "a\x80\x8C\x00\x00\x00\x00" "is the test.",
3750 36,
3751 NULL,
3752 0,
3753 MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR,
3754 MHD_WEBSOCKET_VALIDITY_INVALID,
3755 11);
3756 /* Fail test: Fragmented text frame mixed with one fragmented binary frame */
3757 failed += test_decode_single (__LINE__,
3758 MHD_WEBSOCKET_FLAG_SERVER
3759 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
3760 0,
3761 1,
3762 0,
3763 "\x01\x85\x00\x00\x00\x00"
3764 "This \x02\x81\x00\x00\x00\x00"
3765 "a\x80\x8C\x00\x00\x00\x00" "is the test.",
3766 36,
3767 NULL,
3768 0,
3769 MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR,
3770 MHD_WEBSOCKET_VALIDITY_INVALID,
3771 11);
3772 /* Fail test: Fragmented text frame, continue frame, non-fragmented binary frame */
3773 failed += test_decode_single (__LINE__,
3774 MHD_WEBSOCKET_FLAG_SERVER
3775 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
3776 0,
3777 1,
3778 0,
3779 "\x01\x85\x00\x00\x00\x00"
3780 "This \x00\x8C\x00\x00\x00\x00"
3781 "is the test.\x82\x81\x00\x00\x00\x00" "a",
3782 36,
3783 NULL,
3784 0,
3785 MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR,
3786 MHD_WEBSOCKET_VALIDITY_INVALID,
3787 29);
3788 /* Fail test: Fragmented text frame, continue frame, fragmented binary frame */
3789 failed += test_decode_single (__LINE__,
3790 MHD_WEBSOCKET_FLAG_SERVER
3791 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
3792 0,
3793 1,
3794 0,
3795 "\x01\x85\x00\x00\x00\x00"
3796 "This \x00\x8C\x00\x00\x00\x00"
3797 "is the test.\x02\x81\x00\x00\x00\x00" "a",
3798 36,
3799 NULL,
3800 0,
3801 MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR,
3802 MHD_WEBSOCKET_VALIDITY_INVALID,
3803 29);
3804
3805 /*
3806 ------------------------------------------------------------------------------
3807 multiple data frames
3808 ------------------------------------------------------------------------------
3809 */
3810 /* Regular test: Text frame, binary frame, text frame (1st call) */
3811 failed += test_decode_single (__LINE__,
3812 MHD_WEBSOCKET_FLAG_SERVER
3813 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
3814 0,
3815 1,
3816 0,
3817 "\x81\x85\x00\x00\x00\x00"
3818 "This \x82\x87\x00\x00\x00\x00"
3819 "is the \x81\x85\x00\x00\x00\x00" "test.",
3820 35,
3821 "This ",
3822 5,
3823 MHD_WEBSOCKET_STATUS_TEXT_FRAME,
3824 MHD_WEBSOCKET_VALIDITY_VALID,
3825 11);
3826 /* Regular test: Text frame, binary frame, text frame (2nd call) */
3827 failed += test_decode_single (__LINE__,
3828 MHD_WEBSOCKET_FLAG_SERVER
3829 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
3830 0,
3831 2,
3832 0,
3833 "\x81\x85\x00\x00\x00\x00"
3834 "This \x82\x87\x00\x00\x00\x00"
3835 "is the \x81\x85\x00\x00\x00\x00" "test.",
3836 35,
3837 "is the ",
3838 7,
3839 MHD_WEBSOCKET_STATUS_BINARY_FRAME,
3840 MHD_WEBSOCKET_VALIDITY_VALID,
3841 24);
3842 /* Regular test: Text frame, binary frame, text frame (3rd call) */
3843 failed += test_decode_single (__LINE__,
3844 MHD_WEBSOCKET_FLAG_SERVER
3845 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
3846 0,
3847 3,
3848 0,
3849 "\x81\x85\x00\x00\x00\x00"
3850 "This \x82\x87\x00\x00\x00\x00"
3851 "is the \x81\x85\x00\x00\x00\x00" "test.",
3852 35,
3853 "test.",
3854 5,
3855 MHD_WEBSOCKET_STATUS_TEXT_FRAME,
3856 MHD_WEBSOCKET_VALIDITY_VALID,
3857 35);
3858 /*
3859 ------------------------------------------------------------------------------
3860 multiple control frames
3861 ------------------------------------------------------------------------------
3862 */
3863 /* Regular test: Ping frame, pong frame, close frame (1st call) */
3864 failed += test_decode_single (__LINE__,
3865 MHD_WEBSOCKET_FLAG_SERVER
3866 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
3867 0,
3868 1,
3869 0,
3870 "\x89\x85\x00\x00\x00\x00"
3871 "This \x8A\x87\x00\x00\x00\x00"
3872 "is the \x88\x85\x00\x00\x00\x00" "test.",
3873 35,
3874 "This ",
3875 5,
3876 MHD_WEBSOCKET_STATUS_PING_FRAME,
3877 MHD_WEBSOCKET_VALIDITY_VALID,
3878 11);
3879 /* Regular test: Ping frame, pong frame, close frame (2nd call) */
3880 failed += test_decode_single (__LINE__,
3881 MHD_WEBSOCKET_FLAG_SERVER
3882 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
3883 0,
3884 2,
3885 0,
3886 "\x89\x85\x00\x00\x00\x00"
3887 "This \x8A\x87\x00\x00\x00\x00"
3888 "is the \x88\x85\x00\x00\x00\x00" "test.",
3889 35,
3890 "is the ",
3891 7,
3892 MHD_WEBSOCKET_STATUS_PONG_FRAME,
3893 MHD_WEBSOCKET_VALIDITY_VALID,
3894 24);
3895 /* Regular test: Ping frame, pong frame, close frame (3rd call) */
3896 failed += test_decode_single (__LINE__,
3897 MHD_WEBSOCKET_FLAG_SERVER
3898 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
3899 0,
3900 3,
3901 0,
3902 "\x89\x85\x00\x00\x00\x00"
3903 "This \x8A\x87\x00\x00\x00\x00"
3904 "is the \x88\x85\x00\x00\x00\x00" "test.",
3905 35,
3906 "test.",
3907 5,
3908 MHD_WEBSOCKET_STATUS_CLOSE_FRAME,
3909 MHD_WEBSOCKET_VALIDITY_ONLY_VALID_FOR_CONTROL_FRAMES,
3910 35);
3911
3912 /*
3913 ------------------------------------------------------------------------------
3914 generated close frames for errors
3915 ------------------------------------------------------------------------------
3916 */
3917 /* Regular test: Close frame generated for protocol error */
3918 failed += test_decode_single (__LINE__,
3919 MHD_WEBSOCKET_FLAG_SERVER
3920 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS
3921 |
3922 MHD_WEBSOCKET_FLAG_GENERATE_CLOSE_FRAMES_ON_ERROR,
3923 0,
3924 1,
3925 0,
3926 "\xFF",
3927 1,
3928 "\x88\x02\x03\xEA",
3929 4,
3930 MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR,
3931 MHD_WEBSOCKET_VALIDITY_INVALID,
3932 0);
3933 /* Regular test: Close frame generated for UTF-8 sequence error */
3934 failed += test_decode_single (__LINE__,
3935 MHD_WEBSOCKET_FLAG_SERVER
3936 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS
3937 |
3938 MHD_WEBSOCKET_FLAG_GENERATE_CLOSE_FRAMES_ON_ERROR,
3939 0,
3940 1,
3941 0,
3942 "\x81\x85\x00\x00\x00\x00T\xFFst.",
3943 11,
3944 "\x88\x02\x03\xEF",
3945 4,
3946 MHD_WEBSOCKET_STATUS_UTF8_ENCODING_ERROR,
3947 MHD_WEBSOCKET_VALIDITY_INVALID,
3948 7);
3949 /* Regular test: Close frame generated for message size exceeded */
3950 failed += test_decode_single (__LINE__,
3951 MHD_WEBSOCKET_FLAG_SERVER
3952 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS
3953 |
3954 MHD_WEBSOCKET_FLAG_GENERATE_CLOSE_FRAMES_ON_ERROR,
3955 3,
3956 1,
3957 0,
3958 "\x81\x85\x00\x00\x00\x00T\xFFst.",
3959 11,
3960 "\x88\x02\x03\xF1",
3961 4,
3962 MHD_WEBSOCKET_STATUS_MAXIMUM_SIZE_EXCEEDED,
3963 MHD_WEBSOCKET_VALIDITY_INVALID,
3964 2);
3965
3966 /*
3967 ------------------------------------------------------------------------------
3968 terminating NUL character
3969 ------------------------------------------------------------------------------
3970 */
3971 {
3972 struct MHD_WebSocketStream*ws;
3973 if (MHD_WEBSOCKET_STATUS_OK == MHD_websocket_stream_init (&ws,
3974 MHD_WEBSOCKET_FLAG_SERVER
3975 |
3976 MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
3977 0))
3978 {
3979 size_t streambuf_read_len = 0;
3980 char*payload = NULL;
3981 size_t payload_len = 0;
3982 int ret = 0;
3983
3984 /* Regular test: text frame */
3985 ret = MHD_websocket_decode (ws,
3986 "\x81\x85\x00\x00\x00\x00" "Hello",
3987 11,
3988 &streambuf_read_len,
3989 &payload,
3990 &payload_len);
3991 if ((MHD_WEBSOCKET_STATUS_TEXT_FRAME != ret) ||
3992 (5 != payload_len) ||
3993 (NULL == payload) ||
3994 (0 != memcmp ("Hello", payload, 5 + 1)))
3995 {
3996 fprintf (stderr,
3997 "Decode test failed in line %u\n",
3998 (unsigned int) __LINE__);
3999 ++failed;
4000 }
4001 if (NULL != payload)
4002 {
4003 MHD_websocket_free (ws, payload);
4004 payload = NULL;
4005 }
4006
4007 /* Regular test: text frame fragment */
4008 ret = MHD_websocket_decode (ws,
4009 "\x01\x83\x00\x00\x00\x00"
4010 "Hel\x80\x82\x00\x00\x00\x00" "lo",
4011 17,
4012 &streambuf_read_len,
4013 &payload,
4014 &payload_len);
4015 if ((MHD_WEBSOCKET_STATUS_TEXT_FRAME != ret) ||
4016 (5 != payload_len) ||
4017 (NULL == payload) ||
4018 (0 != memcmp ("Hello", payload, 5 + 1)))
4019 {
4020 fprintf (stderr,
4021 "Decode test failed in line %u\n",
4022 (unsigned int) __LINE__);
4023 ++failed;
4024 }
4025 if (NULL != payload)
4026 {
4027 MHD_websocket_free (ws, payload);
4028 payload = NULL;
4029 }
4030
4031 /* Regular test: binary frame */
4032 ret = MHD_websocket_decode (ws,
4033 "\x82\x85\x00\x00\x00\x00" "Hello",
4034 11,
4035 &streambuf_read_len,
4036 &payload,
4037 &payload_len);
4038 if ((MHD_WEBSOCKET_STATUS_BINARY_FRAME != ret) ||
4039 (5 != payload_len) ||
4040 (NULL == payload) ||
4041 (0 != memcmp ("Hello", payload, 5 + 1)))
4042 {
4043 fprintf (stderr,
4044 "Decode test failed in line %u\n",
4045 (unsigned int) __LINE__);
4046 ++failed;
4047 }
4048 if (NULL != payload)
4049 {
4050 MHD_websocket_free (ws, payload);
4051 payload = NULL;
4052 }
4053
4054 /* Regular test: binary frame fragment */
4055 ret = MHD_websocket_decode (ws,
4056 "\x02\x83\x00\x00\x00\x00"
4057 "Hel\x80\x82\x00\x00\x00\x00" "lo",
4058 17,
4059 &streambuf_read_len,
4060 &payload,
4061 &payload_len);
4062 if ((MHD_WEBSOCKET_STATUS_BINARY_FRAME != ret) ||
4063 (5 != payload_len) ||
4064 (NULL == payload) ||
4065 (0 != memcmp ("Hello", payload, 5 + 1)))
4066 {
4067 fprintf (stderr,
4068 "Decode test failed in line %u\n",
4069 (unsigned int) __LINE__);
4070 ++failed;
4071 }
4072 if (NULL != payload)
4073 {
4074 MHD_websocket_free (ws, payload);
4075 payload = NULL;
4076 }
4077
4078 MHD_websocket_stream_free (ws);
4079 }
4080 else
4081 {
4082 fprintf (stderr,
4083 "Individual decode test failed in line %u\n",
4084 (unsigned int) __LINE__);
4085 ++failed;
4086 }
4087 }
4088 {
4089 struct MHD_WebSocketStream*ws;
4090 if (MHD_WEBSOCKET_STATUS_OK == MHD_websocket_stream_init (&ws,
4091 MHD_WEBSOCKET_FLAG_SERVER
4092 |
4093 MHD_WEBSOCKET_FLAG_WANT_FRAGMENTS,
4094 0))
4095 {
4096 size_t streambuf_read_len = 0;
4097 char*payload = NULL;
4098 size_t payload_len = 0;
4099 int ret = 0;
4100
4101 /* Regular test: text frame fragment (caller wants fragment, 1st call) */
4102 ret = MHD_websocket_decode (ws,
4103 "\x01\x83\x00\x00\x00\x00"
4104 "Hel\x80\x82\x00\x00\x00\x00" "lo",
4105 17,
4106 &streambuf_read_len,
4107 &payload,
4108 &payload_len);
4109 if ((MHD_WEBSOCKET_STATUS_TEXT_FRAGMENT != ret) ||
4110 (3 != payload_len) ||
4111 (NULL == payload) ||
4112 (0 != memcmp ("Hel", payload, 3 + 1)))
4113 {
4114 fprintf (stderr,
4115 "Decode test failed in line %u\n",
4116 (unsigned int) __LINE__);
4117 ++failed;
4118 }
4119 if (NULL != payload)
4120 {
4121 MHD_websocket_free (ws, payload);
4122 payload = NULL;
4123 }
4124
4125 /* Regular test: text frame fragment (caller wants fragment, 2nd call) */
4126 ret = MHD_websocket_decode (ws,
4127 "\x01\x83\x00\x00\x00\x00"
4128 "Hel\x80\x82\x00\x00\x00\x00" "lo"
4129 + streambuf_read_len,
4130 17 - streambuf_read_len,
4131 &streambuf_read_len,
4132 &payload,
4133 &payload_len);
4134 if ((MHD_WEBSOCKET_STATUS_TEXT_LAST_FRAGMENT != ret) ||
4135 (2 != payload_len) ||
4136 (NULL == payload) ||
4137 (0 != memcmp ("lo", payload, 2 + 1)))
4138 {
4139 fprintf (stderr,
4140 "Decode test failed in line %u\n",
4141 (unsigned int) __LINE__);
4142 ++failed;
4143 }
4144 if (NULL != payload)
4145 {
4146 MHD_websocket_free (ws, payload);
4147 payload = NULL;
4148 }
4149
4150 /* Regular test: text frame fragment with broken UTF-8 sequence (caller wants fragment, 1st call) */
4151 ret = MHD_websocket_decode (ws,
4152 "\x01\x83\x00\x00\x00\x00"
4153 "He\xC3\x80\x82\x00\x00\x00\x00" "\xB6o",
4154 17,
4155 &streambuf_read_len,
4156 &payload,
4157 &payload_len);
4158 if ((MHD_WEBSOCKET_STATUS_TEXT_FRAGMENT != ret) ||
4159 (2 != payload_len) ||
4160 (NULL == payload) ||
4161 (0 != memcmp ("He", payload, 2 + 1)))
4162 {
4163 fprintf (stderr,
4164 "Decode test failed in line %u\n",
4165 (unsigned int) __LINE__);
4166 ++failed;
4167 }
4168 if (NULL != payload)
4169 {
4170 MHD_websocket_free (ws, payload);
4171 payload = NULL;
4172 }
4173
4174 /* Regular test: text frame fragment with broken UTF-8 sequence (caller wants fragment, 2nd call) */
4175 ret = MHD_websocket_decode (ws,
4176 "\x01\x83\x00\x00\x00\x00"
4177 "He\xC3\x80\x82\x00\x00\x00\x00" "\xB6o"
4178 + streambuf_read_len,
4179 17 - streambuf_read_len,
4180 &streambuf_read_len,
4181 &payload,
4182 &payload_len);
4183 if ((MHD_WEBSOCKET_STATUS_TEXT_LAST_FRAGMENT != ret) ||
4184 (3 != payload_len) ||
4185 (NULL == payload) ||
4186 (0 != memcmp ("\xC3\xB6o", payload, 3 + 1)))
4187 {
4188 fprintf (stderr,
4189 "Decode test failed in line %u\n",
4190 (unsigned int) __LINE__);
4191 ++failed;
4192 }
4193 if (NULL != payload)
4194 {
4195 MHD_websocket_free (ws, payload);
4196 payload = NULL;
4197 }
4198 }
4199 else
4200 {
4201 fprintf (stderr,
4202 "Individual decode test failed in line %u\n",
4203 (unsigned int) __LINE__);
4204 ++failed;
4205 }
4206 }
4207
4208
4209 /*
4210 ------------------------------------------------------------------------------
4211 invalid parameters
4212 ------------------------------------------------------------------------------
4213 */
4214 {
4215 struct MHD_WebSocketStream*ws;
4216 if (MHD_WEBSOCKET_STATUS_OK == MHD_websocket_stream_init (&ws,
4217 MHD_WEBSOCKET_FLAG_SERVER
4218 |
4219 MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
4220 0))
4221 {
4222 size_t streambuf_read_len = 0;
4223 char*payload = NULL;
4224 size_t payload_len = 0;
4225 int ret = 0;
4226
4227 /* Failure test: `ws` is NULL */
4228 payload = (char *) (uintptr_t) 0xBAADF00D;
4229 payload_len = 0x87654321;
4230 streambuf_read_len = 1000;
4231 ret = MHD_websocket_decode (NULL,
4232 "\x81\x85\x00\x00\x00\x00Hello",
4233 11,
4234 &streambuf_read_len,
4235 &payload,
4236 &payload_len);
4237 if ((MHD_WEBSOCKET_STATUS_PARAMETER_ERROR != ret) ||
4238 (NULL != payload) ||
4239 (0 != payload_len) ||
4240 (0 != streambuf_read_len) ||
4241 (MHD_WEBSOCKET_VALIDITY_VALID != MHD_websocket_stream_is_valid (ws)))
4242 {
4243 fprintf (stderr,
4244 "Decode test failed in line %u\n",
4245 (unsigned int) __LINE__);
4246 ++failed;
4247 }
4248 if (((char *) (uintptr_t) 0xBAADF00D) == payload)
4249 {
4250 payload = NULL;
4251 }
4252 if (NULL != payload)
4253 {
4254 MHD_websocket_free (ws, payload);
4255 }
4256 /* Failure test: `buf` is NULL, while `buf_len` != 0 */
4257 payload = (char *) (uintptr_t) 0xBAADF00D;
4258 payload_len = 0x87654321;
4259 streambuf_read_len = 1000;
4260 ret = MHD_websocket_decode (ws,
4261 NULL,
4262 11,
4263 &streambuf_read_len,
4264 &payload,
4265 &payload_len);
4266 if ((MHD_WEBSOCKET_STATUS_PARAMETER_ERROR != ret) ||
4267 (NULL != payload) ||
4268 (0 != payload_len) ||
4269 (0 != streambuf_read_len) ||
4270 (MHD_WEBSOCKET_VALIDITY_VALID != MHD_websocket_stream_is_valid (ws)))
4271 {
4272 fprintf (stderr,
4273 "Decode test failed in line %u\n",
4274 (unsigned int) __LINE__);
4275 ++failed;
4276 }
4277 if (((char *) (uintptr_t) 0xBAADF00D) == payload)
4278 {
4279 payload = NULL;
4280 }
4281 if (NULL != payload)
4282 {
4283 MHD_websocket_free (ws, payload);
4284 }
4285 /* Failure test: `streambuf_read_len` is NULL */
4286 payload = (char *) (uintptr_t) 0xBAADF00D;
4287 payload_len = 0x87654321;
4288 ret = MHD_websocket_decode (ws,
4289 "\x81\x85\x00\x00\x00\x00Hello",
4290 11,
4291 NULL,
4292 &payload,
4293 &payload_len);
4294 if ((MHD_WEBSOCKET_STATUS_PARAMETER_ERROR != ret) ||
4295 (NULL != payload) ||
4296 (0 != payload_len) ||
4297 (MHD_WEBSOCKET_VALIDITY_VALID != MHD_websocket_stream_is_valid (ws)))
4298 {
4299 fprintf (stderr,
4300 "Decode test failed in line %u\n",
4301 (unsigned int) __LINE__);
4302 ++failed;
4303 }
4304 if (((char *) (uintptr_t) 0xBAADF00D) == payload)
4305 {
4306 payload = NULL;
4307 }
4308 if (NULL != payload)
4309 {
4310 MHD_websocket_free (ws, payload);
4311 }
4312 /* Failure test: `payload` is NULL */
4313 payload_len = 0x87654321;
4314 streambuf_read_len = 1000;
4315 ret = MHD_websocket_decode (ws,
4316 "\x81\x85\x00\x00\x00\x00Hello",
4317 11,
4318 &streambuf_read_len,
4319 NULL,
4320 &payload_len);
4321 if ((MHD_WEBSOCKET_STATUS_PARAMETER_ERROR != ret) ||
4322 (0 != payload_len) ||
4323 (0 != streambuf_read_len) ||
4324 (MHD_WEBSOCKET_VALIDITY_VALID != MHD_websocket_stream_is_valid (ws)))
4325 {
4326 fprintf (stderr,
4327 "Decode test failed in line %u\n",
4328 (unsigned int) __LINE__);
4329 ++failed;
4330 }
4331 /* Failure test: `payload_len` is NULL */
4332 payload = (char *) (uintptr_t) 0xBAADF00D;
4333 streambuf_read_len = 1000;
4334 ret = MHD_websocket_decode (ws,
4335 "\x81\x85\x00\x00\x00\x00Hello",
4336 11,
4337 &streambuf_read_len,
4338 &payload,
4339 NULL);
4340 if ((MHD_WEBSOCKET_STATUS_PARAMETER_ERROR != ret) ||
4341 (NULL != payload) ||
4342 (0 != streambuf_read_len) ||
4343 (MHD_WEBSOCKET_VALIDITY_VALID != MHD_websocket_stream_is_valid (ws)))
4344 {
4345 fprintf (stderr,
4346 "Decode test failed in line %u\n",
4347 (unsigned int) __LINE__);
4348 ++failed;
4349 }
4350 if (((char *) (uintptr_t) 0xBAADF00D) == payload)
4351 {
4352 payload = NULL;
4353 }
4354 if (NULL != payload)
4355 {
4356 MHD_websocket_free (ws, payload);
4357 }
4358 /* Regular test: `buf` is NULL and `buf_len` is 0 */
4359 payload = (char *) (uintptr_t) 0xBAADF00D;
4360 payload_len = 0x87654321;
4361 streambuf_read_len = 1000;
4362 ret = MHD_websocket_decode (ws,
4363 NULL,
4364 0,
4365 &streambuf_read_len,
4366 &payload,
4367 &payload_len);
4368 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
4369 (NULL != payload) ||
4370 (0 != payload_len) ||
4371 (0 != streambuf_read_len) ||
4372 (MHD_WEBSOCKET_VALIDITY_VALID != MHD_websocket_stream_is_valid (ws)))
4373 {
4374 fprintf (stderr,
4375 "Decode test failed in line %u\n",
4376 (unsigned int) __LINE__);
4377 ++failed;
4378 }
4379 if (((char *) (uintptr_t) 0xBAADF00D) == payload)
4380 {
4381 payload = NULL;
4382 }
4383 if (NULL != payload)
4384 {
4385 MHD_websocket_free (ws, payload);
4386 }
4387 /* Regular test: `buf` is not NULL and `buf_len` is 0 */
4388 payload = (char *) (uintptr_t) 0xBAADF00D;
4389 payload_len = 0x87654321;
4390 streambuf_read_len = 1000;
4391 ret = MHD_websocket_decode (ws,
4392 "\x81\x85\x00\x00\x00\x00Hello",
4393 0,
4394 &streambuf_read_len,
4395 &payload,
4396 &payload_len);
4397 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
4398 (NULL != payload) ||
4399 (0 != payload_len) ||
4400 (0 != streambuf_read_len) ||
4401 (MHD_WEBSOCKET_VALIDITY_VALID != MHD_websocket_stream_is_valid (ws)))
4402 {
4403 fprintf (stderr,
4404 "Decode test failed in line %u\n",
4405 (unsigned int) __LINE__);
4406 ++failed;
4407 }
4408 if (((char *) (uintptr_t) 0xBAADF00D) == payload)
4409 {
4410 payload = NULL;
4411 }
4412 if (NULL != payload)
4413 {
4414 MHD_websocket_free (ws, payload);
4415 }
4416
4417 MHD_websocket_stream_free (ws);
4418 }
4419 else
4420 {
4421 fprintf (stderr,
4422 "Parameter decode tests failed in line %u\n",
4423 (unsigned int) __LINE__);
4424 ++failed;
4425 }
4426 }
4427
4428 /*
4429 ------------------------------------------------------------------------------
4430 validity after temporary out-of-memory
4431 ------------------------------------------------------------------------------
4432 */
4433 {
4434 struct MHD_WebSocketStream*ws;
4435 if (MHD_WEBSOCKET_STATUS_OK == MHD_websocket_stream_init2 (&ws,
4436 MHD_WEBSOCKET_FLAG_SERVER
4437 |
4438 MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
4439 0,
4440 test_malloc,
4441 test_realloc,
4442 test_free))
4443 {
4444 size_t streambuf_read_len = 0;
4445 char*payload = NULL;
4446 size_t payload_len = 0;
4447 int ret = 0;
4448
4449 /* Failure test: No memory allocation at the start */
4450 disable_alloc = 1;
4451 payload = (char *) (uintptr_t) 0xBAADF00D;
4452 payload_len = 0x87654321;
4453 streambuf_read_len = 1000;
4454 ret = MHD_websocket_decode (ws,
4455 "\x81\x85\x00\x00\x00\x00Hello",
4456 11,
4457 &streambuf_read_len,
4458 &payload,
4459 &payload_len);
4460 if ((MHD_WEBSOCKET_STATUS_MEMORY_ERROR != ret) ||
4461 (NULL != payload) ||
4462 (0 != payload_len) ||
4463 (1000 == streambuf_read_len) ||
4464 (MHD_WEBSOCKET_VALIDITY_VALID != MHD_websocket_stream_is_valid (ws)))
4465 {
4466 fprintf (stderr,
4467 "Decode test failed in line %u\n",
4468 (unsigned int) __LINE__);
4469 ++failed;
4470 }
4471 if (((char *) (uintptr_t) 0xBAADF00D) == payload)
4472 {
4473 payload = NULL;
4474 }
4475 if (NULL != payload)
4476 {
4477 MHD_websocket_free (ws, payload);
4478 }
4479 MHD_websocket_stream_free (ws);
4480 if (MHD_WEBSOCKET_STATUS_OK == MHD_websocket_stream_init2 (&ws,
4481 MHD_WEBSOCKET_FLAG_SERVER
4482 |
4483 MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
4484 0,
4485 test_malloc,
4486 test_realloc,
4487 test_free))
4488 {
4489 /* Failure test: No memory allocation after fragmented frame */
4490 disable_alloc = 0;
4491 payload = (char *) (uintptr_t) 0xBAADF00D;
4492 payload_len = 0x87654321;
4493 streambuf_read_len = 1000;
4494 ret = MHD_websocket_decode (ws,
4495 "\x01\x83\x00\x00\x00\x00" "Hel",
4496 9,
4497 &streambuf_read_len,
4498 &payload,
4499 &payload_len);
4500 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
4501 (NULL != payload) ||
4502 (0 != payload_len) ||
4503 (9 != streambuf_read_len) ||
4504 (MHD_WEBSOCKET_VALIDITY_VALID != MHD_websocket_stream_is_valid (
4505 ws)))
4506 {
4507 fprintf (stderr,
4508 "Decode test failed in line %u\n",
4509 (unsigned int) __LINE__);
4510 ++failed;
4511 }
4512 if (((char *) (uintptr_t) 0xBAADF00D) == payload)
4513 {
4514 payload = NULL;
4515 }
4516 if (NULL != payload)
4517 {
4518 MHD_websocket_free (ws, payload);
4519 }
4520 disable_alloc = 1;
4521 payload = (char *) (uintptr_t) 0xBAADF00D;
4522 payload_len = 0x87654321;
4523 streambuf_read_len = 1000;
4524 ret = MHD_websocket_decode (ws,
4525 "\x80\x82\x00\x00\x00\x00" "lo",
4526 8,
4527 &streambuf_read_len,
4528 &payload,
4529 &payload_len);
4530 if ((MHD_WEBSOCKET_STATUS_MEMORY_ERROR != ret) ||
4531 (NULL != payload) ||
4532 (0 != payload_len) ||
4533 (1000 == streambuf_read_len) ||
4534 (MHD_WEBSOCKET_VALIDITY_VALID != MHD_websocket_stream_is_valid (
4535 ws)))
4536 {
4537 fprintf (stderr,
4538 "Decode test failed in line %u\n",
4539 (unsigned int) __LINE__);
4540 ++failed;
4541 }
4542 if (((char *) (uintptr_t) 0xBAADF00D) == payload)
4543 {
4544 payload = NULL;
4545 }
4546 if (NULL != payload)
4547 {
4548 MHD_websocket_free (ws, payload);
4549 }
4550 /* Regular test: Success after memory allocation ok again */
4551 /* (streambuf_read_len may not be overwritten for this test) */
4552 disable_alloc = 0;
4553 payload = (char *) (uintptr_t) 0xBAADF00D;
4554 payload_len = 0x87654321;
4555 size_t old_streambuf_read_len = streambuf_read_len;
4556 ret = MHD_websocket_decode (ws,
4557 "\x80\x82\x00\x00\x00\x00lo"
4558 + old_streambuf_read_len,
4559 8 - old_streambuf_read_len,
4560 &streambuf_read_len,
4561 &payload,
4562 &payload_len);
4563 if ((MHD_WEBSOCKET_STATUS_TEXT_FRAME != ret) ||
4564 (NULL == payload) ||
4565 (5 != payload_len) ||
4566 (8 != streambuf_read_len + old_streambuf_read_len) ||
4567 (MHD_WEBSOCKET_VALIDITY_VALID != MHD_websocket_stream_is_valid (
4568 ws)) ||
4569 (0 != memcmp ("Hello", payload, 5)))
4570 {
4571 fprintf (stderr,
4572 "Decode test failed in line %u\n",
4573 (unsigned int) __LINE__);
4574 ++failed;
4575 }
4576 if (((char *) (uintptr_t) 0xBAADF00D) == payload)
4577 {
4578 payload = NULL;
4579 }
4580 if (NULL != payload)
4581 {
4582 MHD_websocket_free (ws, payload);
4583 }
4584
4585 MHD_websocket_stream_free (ws);
4586 }
4587 else
4588 {
4589 fprintf (stderr,
4590 "Memory decode test failed in line %u\n",
4591 (unsigned int) __LINE__);
4592 ++failed;
4593 }
4594 }
4595 else
4596 {
4597 fprintf (stderr,
4598 "Memory decode tests failed in line %u\n",
4599 (unsigned int) __LINE__);
4600 ++failed;
4601 }
4602 }
4603
4604 /*
4605 ------------------------------------------------------------------------------
4606 memory leak test, when freeing while decoding
4607 ------------------------------------------------------------------------------
4608 */
4609 {
4610 disable_alloc = 0;
4611 struct MHD_WebSocketStream*ws;
4612 size_t streambuf_read_len = 0;
4613 char*payload = NULL;
4614 size_t payload_len = 0;
4615 int ret = 0;
4616
4617 /* Regular test: Free while decoding of data frame */
4618 open_allocs = 0;
4619 if (MHD_WEBSOCKET_STATUS_OK == MHD_websocket_stream_init2 (&ws,
4620 MHD_WEBSOCKET_FLAG_SERVER
4621 |
4622 MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
4623 0,
4624 test_malloc,
4625 test_realloc,
4626 test_free))
4627 {
4628 ret = MHD_websocket_decode (ws,
4629 "\x81\x85\x00\x00\x00\x00Hel",
4630 9,
4631 &streambuf_read_len,
4632 &payload,
4633 &payload_len);
4634 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
4635 (0 != payload_len) ||
4636 (NULL != payload) ||
4637 (9 != streambuf_read_len) )
4638 {
4639 fprintf (stderr,
4640 "Memory decode test failed in line %u\n",
4641 (unsigned int) __LINE__);
4642 ++failed;
4643 }
4644 ret = MHD_websocket_stream_free (ws);
4645 if (MHD_WEBSOCKET_STATUS_OK != ret)
4646 {
4647 fprintf (stderr,
4648 "Memory decode test failed in line %u\n",
4649 (unsigned int) __LINE__);
4650 ++failed;
4651 }
4652 if (0 != open_allocs)
4653 {
4654 fprintf (stderr,
4655 "Memory decode test failed in line %u (memory leak detected)\n",
4656 (unsigned int) __LINE__);
4657 ++failed;
4658 }
4659 }
4660 else
4661 {
4662 fprintf (stderr,
4663 "Memory test failed in line %u\n",
4664 (unsigned int) __LINE__);
4665 ++failed;
4666 }
4667
4668 /* Regular test: Free while decoding of control frame */
4669 open_allocs = 0;
4670 if (MHD_WEBSOCKET_STATUS_OK == MHD_websocket_stream_init2 (&ws,
4671 MHD_WEBSOCKET_FLAG_SERVER
4672 |
4673 MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
4674 0,
4675 test_malloc,
4676 test_realloc,
4677 test_free))
4678 {
4679 ret = MHD_websocket_decode (ws,
4680 "\x88\x85\x00\x00\x00\x00Hel",
4681 9,
4682 &streambuf_read_len,
4683 &payload,
4684 &payload_len);
4685 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
4686 (0 != payload_len) ||
4687 (NULL != payload) ||
4688 (9 != streambuf_read_len) )
4689 {
4690 fprintf (stderr,
4691 "Memory decode test failed in line %u\n",
4692 (unsigned int) __LINE__);
4693 ++failed;
4694 }
4695 ret = MHD_websocket_stream_free (ws);
4696 if (MHD_WEBSOCKET_STATUS_OK != ret)
4697 {
4698 fprintf (stderr,
4699 "Memory decode test failed in line %u\n",
4700 (unsigned int) __LINE__);
4701 ++failed;
4702 }
4703 if (0 != open_allocs)
4704 {
4705 fprintf (stderr,
4706 "Memory decode test failed in line %u (memory leak detected)\n",
4707 (unsigned int) __LINE__);
4708 ++failed;
4709 }
4710 }
4711 else
4712 {
4713 fprintf (stderr,
4714 "Memory test failed in line %u\n",
4715 (unsigned int) __LINE__);
4716 ++failed;
4717 }
4718
4719 /* Regular test: Free while decoding of fragmented data frame */
4720 open_allocs = 0;
4721 if (MHD_WEBSOCKET_STATUS_OK == MHD_websocket_stream_init2 (&ws,
4722 MHD_WEBSOCKET_FLAG_SERVER
4723 |
4724 MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
4725 0,
4726 test_malloc,
4727 test_realloc,
4728 test_free))
4729 {
4730 ret = MHD_websocket_decode (ws,
4731 "\x01\x85\x00\x00\x00\x00Hello",
4732 11,
4733 &streambuf_read_len,
4734 &payload,
4735 &payload_len);
4736 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
4737 (0 != payload_len) ||
4738 (NULL != payload) ||
4739 (11 != streambuf_read_len) )
4740 {
4741 fprintf (stderr,
4742 "Memory decode test failed in line %u\n",
4743 (unsigned int) __LINE__);
4744 ++failed;
4745 }
4746 ret = MHD_websocket_stream_free (ws);
4747 if (MHD_WEBSOCKET_STATUS_OK != ret)
4748 {
4749 fprintf (stderr,
4750 "Memory decode test failed in line %u\n",
4751 (unsigned int) __LINE__);
4752 ++failed;
4753 }
4754 if (0 != open_allocs)
4755 {
4756 fprintf (stderr,
4757 "Memory decode test failed in line %u (memory leak detected)\n",
4758 (unsigned int) __LINE__);
4759 ++failed;
4760 }
4761 }
4762 else
4763 {
4764 fprintf (stderr,
4765 "Memory test failed in line %u\n",
4766 (unsigned int) __LINE__);
4767 ++failed;
4768 }
4769 /* Regular test: Free while decoding of continued fragmented data frame */
4770 open_allocs = 0;
4771 if (MHD_WEBSOCKET_STATUS_OK == MHD_websocket_stream_init2 (&ws,
4772 MHD_WEBSOCKET_FLAG_SERVER
4773 |
4774 MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
4775 0,
4776 test_malloc,
4777 test_realloc,
4778 test_free))
4779 {
4780 ret = MHD_websocket_decode (ws,
4781 "\x01\x85\x00\x00\x00\x00Hello",
4782 11,
4783 &streambuf_read_len,
4784 &payload,
4785 &payload_len);
4786 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
4787 (0 != payload_len) ||
4788 (NULL != payload) ||
4789 (11 != streambuf_read_len) )
4790 {
4791 fprintf (stderr,
4792 "Memory decode test failed in line %u\n",
4793 (unsigned int) __LINE__);
4794 ++failed;
4795 }
4796 ret = MHD_websocket_decode (ws,
4797 "\x80\x85\x00\x00\x00\x00Hel",
4798 9,
4799 &streambuf_read_len,
4800 &payload,
4801 &payload_len);
4802 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
4803 (0 != payload_len) ||
4804 (NULL != payload) ||
4805 (9 != streambuf_read_len) )
4806 {
4807 fprintf (stderr,
4808 "Memory decode test failed in line %u\n",
4809 (unsigned int) __LINE__);
4810 ++failed;
4811 }
4812 ret = MHD_websocket_stream_free (ws);
4813 if (MHD_WEBSOCKET_STATUS_OK != ret)
4814 {
4815 fprintf (stderr,
4816 "Memory decode test failed in line %u\n",
4817 (unsigned int) __LINE__);
4818 ++failed;
4819 }
4820 if (0 != open_allocs)
4821 {
4822 fprintf (stderr,
4823 "Memory decode test failed in line %u (memory leak detected)\n",
4824 (unsigned int) __LINE__);
4825 ++failed;
4826 }
4827 }
4828 else
4829 {
4830 fprintf (stderr,
4831 "Memory test failed in line %u\n",
4832 (unsigned int) __LINE__);
4833 ++failed;
4834 }
4835 /* Regular test: Free while decoding of control frame during fragmented data frame */
4836 open_allocs = 0;
4837 if (MHD_WEBSOCKET_STATUS_OK == MHD_websocket_stream_init2 (&ws,
4838 MHD_WEBSOCKET_FLAG_SERVER
4839 |
4840 MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
4841 0,
4842 test_malloc,
4843 test_realloc,
4844 test_free))
4845 {
4846 ret = MHD_websocket_decode (ws,
4847 "\x01\x85\x00\x00\x00\x00Hello",
4848 11,
4849 &streambuf_read_len,
4850 &payload,
4851 &payload_len);
4852 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
4853 (0 != payload_len) ||
4854 (NULL != payload) ||
4855 (11 != streambuf_read_len) )
4856 {
4857 fprintf (stderr,
4858 "Memory decode test failed in line %u\n",
4859 (unsigned int) __LINE__);
4860 ++failed;
4861 }
4862 ret = MHD_websocket_decode (ws,
4863 "\x88\x85\x00\x00\x00\x00Hel",
4864 9,
4865 &streambuf_read_len,
4866 &payload,
4867 &payload_len);
4868 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
4869 (0 != payload_len) ||
4870 (NULL != payload) ||
4871 (9 != streambuf_read_len) )
4872 {
4873 fprintf (stderr,
4874 "Memory decode test failed in line %u\n",
4875 (unsigned int) __LINE__);
4876 ++failed;
4877 }
4878 ret = MHD_websocket_stream_free (ws);
4879 if (MHD_WEBSOCKET_STATUS_OK != ret)
4880 {
4881 fprintf (stderr,
4882 "Memory decode test failed in line %u\n",
4883 (unsigned int) __LINE__);
4884 ++failed;
4885 }
4886 if (0 != open_allocs)
4887 {
4888 fprintf (stderr,
4889 "Memory decode test failed in line %u (memory leak detected)\n",
4890 (unsigned int) __LINE__);
4891 ++failed;
4892 }
4893 }
4894 else
4895 {
4896 fprintf (stderr,
4897 "Memory test failed in line %u\n",
4898 (unsigned int) __LINE__);
4899 ++failed;
4900 }
4901 }
4902
4903 if (NULL != buf1)
4904 {
4905 free (buf1);
4906 buf1 = NULL;
4907 }
4908 if (NULL != buf2)
4909 {
4910 free (buf2);
4911 buf2 = NULL;
4912 }
4913 return failed != 0 ? 0x04 : 0x00;
4914}
4915
4916
4917/**
4918 * Test procedure for `MHD_websocket_encode_text()`
4919 */
4920int
4921test_encodes_text ()
4922{
4923 int failed = 0;
4924 struct MHD_WebSocketStream*wss;
4925 struct MHD_WebSocketStream*wsc;
4926 int ret;
4927 char *buf1 = NULL, *buf2 = NULL;
4928 char*frame = NULL;
4929 size_t frame_len = 0;
4930 int utf8_step = 0;
4931
4932 if (MHD_WEBSOCKET_STATUS_OK != MHD_websocket_stream_init (&wsc,
4933 MHD_WEBSOCKET_FLAG_CLIENT,
4934 0))
4935 {
4936 fprintf (stderr,
4937 "No encode text tests possible due to failed stream init in line %u\n",
4938 (unsigned int) __LINE__);
4939 return 0x08;
4940 }
4941 if (MHD_WEBSOCKET_STATUS_OK != MHD_websocket_stream_init (&wss,
4942 MHD_WEBSOCKET_FLAG_SERVER,
4943 0))
4944 {
4945 fprintf (stderr,
4946 "No encode text tests possible due to failed stream init in line %u\n",
4947 (unsigned int) __LINE__);
4948 if (NULL != wsc)
4949 MHD_websocket_stream_free (wsc);
4950 return 0x08;
4951 }
4952
4953 /*
4954 ------------------------------------------------------------------------------
4955 Encoding
4956 ------------------------------------------------------------------------------
4957 */
4958 /* Regular test: Some data without UTF-8, we are server */
4959 ret = MHD_websocket_encode_text (wss,
4960 "blablabla",
4961 9,
4962 MHD_WEBSOCKET_FRAGMENTATION_NONE,
4963 &frame,
4964 &frame_len,
4965 NULL);
4966 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
4967 (11 != frame_len) ||
4968 (NULL == frame) ||
4969 (0 != memcmp (frame, "\x81\x09" "blablabla", 11)))
4970 {
4971 fprintf (stderr,
4972 "Encode text test failed in line %u\n",
4973 (unsigned int) __LINE__);
4974 ++failed;
4975 }
4976 if (NULL != frame)
4977 {
4978 MHD_websocket_free (wss, frame);
4979 frame = NULL;
4980 }
4981 /* Regular test: Some data without UTF-8, we are client */
4982 ret = MHD_websocket_encode_text (wsc,
4983 "blablabla",
4984 9,
4985 MHD_WEBSOCKET_FRAGMENTATION_NONE,
4986 &frame,
4987 &frame_len,
4988 NULL);
4989 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
4990 (15 != frame_len) ||
4991 (NULL == frame) )
4992 {
4993 fprintf (stderr,
4994 "Encode text test failed in line %u\n",
4995 (unsigned int) __LINE__);
4996 ++failed;
4997 }
4998 else
4999 {
5000 failed += test_decode_single (__LINE__,
5001 MHD_WEBSOCKET_FLAG_SERVER
5002 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
5003 0,
5004 1,
5005 0,
5006 frame,
5007 frame_len,
5008 "blablabla",
5009 9,
5010 MHD_WEBSOCKET_STATUS_TEXT_FRAME,
5011 MHD_WEBSOCKET_VALIDITY_VALID,
5012 frame_len);
5013 }
5014 if (NULL != frame)
5015 {
5016 MHD_websocket_free (wsc, frame);
5017 frame = NULL;
5018 }
5019 /* Regular test: Some data with UTF-8, we are server */
5020 ret = MHD_websocket_encode_text (wss,
5021 "bla" "\xC3\xA4" "blabla",
5022 11,
5023 MHD_WEBSOCKET_FRAGMENTATION_NONE,
5024 &frame,
5025 &frame_len,
5026 NULL);
5027 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
5028 (13 != frame_len) ||
5029 (NULL == frame) ||
5030 (0 != memcmp (frame, "\x81\x0B" "bla" "\xC3\xA4" "blabla", 13)))
5031 {
5032 fprintf (stderr,
5033 "Encode text test failed in line %u\n",
5034 (unsigned int) __LINE__);
5035 ++failed;
5036 }
5037 if (NULL != frame)
5038 {
5039 MHD_websocket_free (wss, frame);
5040 frame = NULL;
5041 }
5042 /* Regular test: Some data with UTF-8, we are client */
5043 ret = MHD_websocket_encode_text (wsc,
5044 "bla" "\xC3\xA4" "blabla",
5045 11,
5046 MHD_WEBSOCKET_FRAGMENTATION_NONE,
5047 &frame,
5048 &frame_len,
5049 NULL);
5050 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
5051 (17 != frame_len) ||
5052 (NULL == frame) )
5053 {
5054 fprintf (stderr,
5055 "Encode text test failed in line %u\n",
5056 (unsigned int) __LINE__);
5057 ++failed;
5058 }
5059 else
5060 {
5061 failed += test_decode_single (__LINE__,
5062 MHD_WEBSOCKET_FLAG_SERVER
5063 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
5064 0,
5065 1,
5066 0,
5067 frame,
5068 frame_len,
5069 "bla" "\xC3\xA4" "blabla",
5070 11,
5071 MHD_WEBSOCKET_STATUS_TEXT_FRAME,
5072 MHD_WEBSOCKET_VALIDITY_VALID,
5073 frame_len);
5074 }
5075 if (NULL != frame)
5076 {
5077 MHD_websocket_free (wsc, frame);
5078 frame = NULL;
5079 }
5080 /* Edge test (success): Some data with NUL characters, we are server */
5081 ret = MHD_websocket_encode_text (wss,
5082 "bla" "\0\0\0" "bla",
5083 9,
5084 MHD_WEBSOCKET_FRAGMENTATION_NONE,
5085 &frame,
5086 &frame_len,
5087 NULL);
5088 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
5089 (11 != frame_len) ||
5090 (NULL == frame) ||
5091 (0 != memcmp (frame, "\x81\x09" "bla" "\0\0\0" "bla", 11)))
5092 {
5093 fprintf (stderr,
5094 "Encode text test failed in line %u\n",
5095 (unsigned int) __LINE__);
5096 ++failed;
5097 }
5098 if (NULL != frame)
5099 {
5100 MHD_websocket_free (wss, frame);
5101 frame = NULL;
5102 }
5103 /* Fail test: Some data with broken UTF-8, we are server */
5104 ret = MHD_websocket_encode_text (wss,
5105 "bla" "\xC3" "blabla",
5106 10,
5107 MHD_WEBSOCKET_FRAGMENTATION_NONE,
5108 &frame,
5109 &frame_len,
5110 NULL);
5111 if ((MHD_WEBSOCKET_STATUS_UTF8_ENCODING_ERROR != ret) ||
5112 (0 != frame_len) ||
5113 (NULL != frame) )
5114 {
5115 fprintf (stderr,
5116 "Encode text test failed in line %u\n",
5117 (unsigned int) __LINE__);
5118 ++failed;
5119 }
5120 if (NULL != frame)
5121 {
5122 MHD_websocket_free (wss, frame);
5123 frame = NULL;
5124 }
5125
5126 /*
5127 ------------------------------------------------------------------------------
5128 Fragmentation
5129 ------------------------------------------------------------------------------
5130 */
5131 /* Regular test: Some data without UTF-8 */
5132 ret = MHD_websocket_encode_text (wss,
5133 "blablabla",
5134 9,
5135 MHD_WEBSOCKET_FRAGMENTATION_NONE,
5136 &frame,
5137 &frame_len,
5138 &utf8_step);
5139 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
5140 (11 != frame_len) ||
5141 (NULL == frame) ||
5142 (MHD_WEBSOCKET_UTF8STEP_NORMAL != utf8_step) ||
5143 (0 != memcmp (frame, "\x81\x09" "blablabla", 11)))
5144 {
5145 fprintf (stderr,
5146 "Encode text test failed in line %u\n",
5147 (unsigned int) __LINE__);
5148 ++failed;
5149 }
5150 if (NULL != frame)
5151 {
5152 MHD_websocket_free (wss, frame);
5153 frame = NULL;
5154 }
5155 /* Regular test: First fragment without UTF-8 */
5156 ret = MHD_websocket_encode_text (wss,
5157 "blablabla",
5158 9,
5159 MHD_WEBSOCKET_FRAGMENTATION_FIRST,
5160 &frame,
5161 &frame_len,
5162 &utf8_step);
5163 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
5164 (11 != frame_len) ||
5165 (NULL == frame) ||
5166 (MHD_WEBSOCKET_UTF8STEP_NORMAL != utf8_step) ||
5167 (0 != memcmp (frame, "\x01\x09" "blablabla", 11)))
5168 {
5169 fprintf (stderr,
5170 "Encode text test failed in line %u\n",
5171 (unsigned int) __LINE__);
5172 ++failed;
5173 }
5174 if (NULL != frame)
5175 {
5176 MHD_websocket_free (wss, frame);
5177 frame = NULL;
5178 }
5179 /* Regular test: Middle fragment without UTF-8 */
5180 ret = MHD_websocket_encode_text (wss,
5181 "blablabla",
5182 9,
5183 MHD_WEBSOCKET_FRAGMENTATION_FOLLOWING,
5184 &frame,
5185 &frame_len,
5186 &utf8_step);
5187 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
5188 (11 != frame_len) ||
5189 (NULL == frame) ||
5190 (MHD_WEBSOCKET_UTF8STEP_NORMAL != utf8_step) ||
5191 (0 != memcmp (frame, "\x00\x09" "blablabla", 11)))
5192 {
5193 fprintf (stderr,
5194 "Encode text test failed in line %u\n",
5195 (unsigned int) __LINE__);
5196 ++failed;
5197 }
5198 if (NULL != frame)
5199 {
5200 MHD_websocket_free (wss, frame);
5201 frame = NULL;
5202 }
5203 /* Regular test: Last fragment without UTF-8 */
5204 ret = MHD_websocket_encode_text (wss,
5205 "blablabla",
5206 9,
5207 MHD_WEBSOCKET_FRAGMENTATION_LAST,
5208 &frame,
5209 &frame_len,
5210 &utf8_step);
5211 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
5212 (11 != frame_len) ||
5213 (NULL == frame) ||
5214 (MHD_WEBSOCKET_UTF8STEP_NORMAL != utf8_step) ||
5215 (0 != memcmp (frame, "\x80\x09" "blablabla", 11)))
5216 {
5217 fprintf (stderr,
5218 "Encode text test failed in line %u\n",
5219 (unsigned int) __LINE__);
5220 ++failed;
5221 }
5222 if (NULL != frame)
5223 {
5224 MHD_websocket_free (wss, frame);
5225 frame = NULL;
5226 }
5227 /* Edge test (success): First fragment with UTF-8 on the edge */
5228 ret = MHD_websocket_encode_text (wss,
5229 "blablabl\xC3",
5230 9,
5231 MHD_WEBSOCKET_FRAGMENTATION_FIRST,
5232 &frame,
5233 &frame_len,
5234 &utf8_step);
5235 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
5236 (11 != frame_len) ||
5237 (NULL == frame) ||
5238 (MHD_WEBSOCKET_UTF8STEP_UTF2TAIL_1OF1 != utf8_step) ||
5239 (0 != memcmp (frame, "\x01\x09" "blablabl\xC3", 11)))
5240 {
5241 fprintf (stderr,
5242 "Encode text test failed in line %u\n",
5243 (unsigned int) __LINE__);
5244 ++failed;
5245 }
5246 if (NULL != frame)
5247 {
5248 MHD_websocket_free (wss, frame);
5249 frame = NULL;
5250 }
5251 /* Edge test (success): Last fragment with UTF-8 on the edge */
5252 ret = MHD_websocket_encode_text (wss,
5253 "\xA4" "blablabla",
5254 10,
5255 MHD_WEBSOCKET_FRAGMENTATION_LAST,
5256 &frame,
5257 &frame_len,
5258 &utf8_step);
5259 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
5260 (12 != frame_len) ||
5261 (NULL == frame) ||
5262 (MHD_WEBSOCKET_UTF8STEP_NORMAL != utf8_step) ||
5263 (0 != memcmp (frame, "\x80\x0A" "\xA4" "blablabla", 12)))
5264 {
5265 fprintf (stderr,
5266 "Encode text test failed in line %u\n",
5267 (unsigned int) __LINE__);
5268 ++failed;
5269 }
5270 if (NULL != frame)
5271 {
5272 MHD_websocket_free (wss, frame);
5273 frame = NULL;
5274 }
5275 /* Fail test: Last fragment with UTF-8 on the edge (here with wrong old utf8_step) */
5276 utf8_step = MHD_WEBSOCKET_UTF8STEP_NORMAL;
5277 ret = MHD_websocket_encode_text (wss,
5278 "\xA4" "blablabla",
5279 10,
5280 MHD_WEBSOCKET_FRAGMENTATION_LAST,
5281 &frame,
5282 &frame_len,
5283 &utf8_step);
5284 if ((MHD_WEBSOCKET_STATUS_UTF8_ENCODING_ERROR != ret) ||
5285 (0 != frame_len) ||
5286 (NULL != frame) ||
5287 (MHD_WEBSOCKET_UTF8STEP_NORMAL != utf8_step) )
5288 {
5289 fprintf (stderr,
5290 "Encode text test failed in line %u\n",
5291 (unsigned int) __LINE__);
5292 ++failed;
5293 }
5294 if (NULL != frame)
5295 {
5296 MHD_websocket_free (wss, frame);
5297 frame = NULL;
5298 }
5299 /* Regular test: Last fragment with UTF-8 on the edge for UTF2TAIL_1OF1 */
5300 utf8_step = MHD_WEBSOCKET_UTF8STEP_UTF2TAIL_1OF1;
5301 ret = MHD_websocket_encode_text (wss,
5302 "\xA4" "blablabla",
5303 10,
5304 MHD_WEBSOCKET_FRAGMENTATION_LAST,
5305 &frame,
5306 &frame_len,
5307 &utf8_step);
5308 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
5309 (12 != frame_len) ||
5310 (NULL == frame) ||
5311 (MHD_WEBSOCKET_UTF8STEP_NORMAL != utf8_step) ||
5312 (0 != memcmp (frame, "\x80\x0A" "\xA4" "blablabla", 12)))
5313 {
5314 fprintf (stderr,
5315 "Encode text test failed in line %u\n",
5316 (unsigned int) __LINE__);
5317 ++failed;
5318 }
5319 if (NULL != frame)
5320 {
5321 MHD_websocket_free (wss, frame);
5322 frame = NULL;
5323 }
5324 /* Regular test: Last fragment with UTF-8 on the edge for UTF3TAIL1_1OF2 */
5325 utf8_step = MHD_WEBSOCKET_UTF8STEP_UTF3TAIL1_1OF2;
5326 ret = MHD_websocket_encode_text (wss,
5327 "\xA0\x80" "blablabla",
5328 11,
5329 MHD_WEBSOCKET_FRAGMENTATION_LAST,
5330 &frame,
5331 &frame_len,
5332 &utf8_step);
5333 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
5334 (13 != frame_len) ||
5335 (NULL == frame) ||
5336 (MHD_WEBSOCKET_UTF8STEP_NORMAL != utf8_step) ||
5337 (0 != memcmp (frame, "\x80\x0B" "\xA0\x80" "blablabla", 13)))
5338 {
5339 fprintf (stderr,
5340 "Encode text test failed in line %u\n",
5341 (unsigned int) __LINE__);
5342 ++failed;
5343 }
5344 if (NULL != frame)
5345 {
5346 MHD_websocket_free (wss, frame);
5347 frame = NULL;
5348 }
5349 /* Regular test: Last fragment with UTF-8 on the edge for UTF3TAIL2_1OF2 */
5350 utf8_step = MHD_WEBSOCKET_UTF8STEP_UTF3TAIL2_1OF2;
5351 ret = MHD_websocket_encode_text (wss,
5352 "\x80\x80" "blablabla",
5353 11,
5354 MHD_WEBSOCKET_FRAGMENTATION_LAST,
5355 &frame,
5356 &frame_len,
5357 &utf8_step);
5358 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
5359 (13 != frame_len) ||
5360 (NULL == frame) ||
5361 (MHD_WEBSOCKET_UTF8STEP_NORMAL != utf8_step) ||
5362 (0 != memcmp (frame, "\x80\x0B" "\x80\x80" "blablabla", 13)))
5363 {
5364 fprintf (stderr,
5365 "Encode text test failed in line %u\n",
5366 (unsigned int) __LINE__);
5367 ++failed;
5368 }
5369 if (NULL != frame)
5370 {
5371 MHD_websocket_free (wss, frame);
5372 frame = NULL;
5373 }
5374 /* Regular test: Last fragment with UTF-8 on the edge for UTF3TAIL_1OF2 */
5375 utf8_step = MHD_WEBSOCKET_UTF8STEP_UTF3TAIL_1OF2;
5376 ret = MHD_websocket_encode_text (wss,
5377 "\x80\x80" "blablabla",
5378 11,
5379 MHD_WEBSOCKET_FRAGMENTATION_LAST,
5380 &frame,
5381 &frame_len,
5382 &utf8_step);
5383 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
5384 (13 != frame_len) ||
5385 (NULL == frame) ||
5386 (MHD_WEBSOCKET_UTF8STEP_NORMAL != utf8_step) ||
5387 (0 != memcmp (frame, "\x80\x0B" "\x80\x80" "blablabla", 13)))
5388 {
5389 fprintf (stderr,
5390 "Encode text test failed in line %u\n",
5391 (unsigned int) __LINE__);
5392 ++failed;
5393 }
5394 if (NULL != frame)
5395 {
5396 MHD_websocket_free (wss, frame);
5397 frame = NULL;
5398 }
5399 /* Regular test: Last fragment with UTF-8 on the edge for UTF3TAIL_2OF2 */
5400 utf8_step = MHD_WEBSOCKET_UTF8STEP_UTF3TAIL_2OF2;
5401 ret = MHD_websocket_encode_text (wss,
5402 "\x80" " blablabla",
5403 11,
5404 MHD_WEBSOCKET_FRAGMENTATION_LAST,
5405 &frame,
5406 &frame_len,
5407 &utf8_step);
5408 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
5409 (13 != frame_len) ||
5410 (NULL == frame) ||
5411 (MHD_WEBSOCKET_UTF8STEP_NORMAL != utf8_step) ||
5412 (0 != memcmp (frame, "\x80\x0B" "\x80" " blablabla", 13)))
5413 {
5414 fprintf (stderr,
5415 "Encode text test failed in line %u\n",
5416 (unsigned int) __LINE__);
5417 ++failed;
5418 }
5419 if (NULL != frame)
5420 {
5421 MHD_websocket_free (wss, frame);
5422 frame = NULL;
5423 }
5424 /* Regular test: Last fragment with UTF-8 on the edge for UTF4TAIL1_1OF3 */
5425 utf8_step = MHD_WEBSOCKET_UTF8STEP_UTF4TAIL1_1OF3;
5426 ret = MHD_websocket_encode_text (wss,
5427 "\x90\x80\x80" "blablabla",
5428 12,
5429 MHD_WEBSOCKET_FRAGMENTATION_LAST,
5430 &frame,
5431 &frame_len,
5432 &utf8_step);
5433 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
5434 (14 != frame_len) ||
5435 (NULL == frame) ||
5436 (MHD_WEBSOCKET_UTF8STEP_NORMAL != utf8_step) ||
5437 (0 != memcmp (frame, "\x80\x0C" "\x90\x80\x80" "blablabla", 14)))
5438 {
5439 fprintf (stderr,
5440 "Encode text test failed in line %u\n",
5441 (unsigned int) __LINE__);
5442 ++failed;
5443 }
5444 if (NULL != frame)
5445 {
5446 MHD_websocket_free (wss, frame);
5447 frame = NULL;
5448 }
5449 /* Regular test: Last fragment with UTF-8 on the edge for UTF4TAIL2_1OF3 */
5450 utf8_step = MHD_WEBSOCKET_UTF8STEP_UTF4TAIL2_1OF3;
5451 ret = MHD_websocket_encode_text (wss,
5452 "\x80\x80\x80" "blablabla",
5453 12,
5454 MHD_WEBSOCKET_FRAGMENTATION_LAST,
5455 &frame,
5456 &frame_len,
5457 &utf8_step);
5458 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
5459 (14 != frame_len) ||
5460 (NULL == frame) ||
5461 (MHD_WEBSOCKET_UTF8STEP_NORMAL != utf8_step) ||
5462 (0 != memcmp (frame, "\x80\x0C" "\x80\x80\x80" "blablabla", 14)))
5463 {
5464 fprintf (stderr,
5465 "Encode text test failed in line %u\n",
5466 (unsigned int) __LINE__);
5467 ++failed;
5468 }
5469 if (NULL != frame)
5470 {
5471 MHD_websocket_free (wss, frame);
5472 frame = NULL;
5473 }
5474 /* Regular test: Last fragment with UTF-8 on the edge for UTF4TAIL_1OF3 */
5475 utf8_step = MHD_WEBSOCKET_UTF8STEP_UTF4TAIL_1OF3;
5476 ret = MHD_websocket_encode_text (wss,
5477 "\x80\x80\x80" "blablabla",
5478 12,
5479 MHD_WEBSOCKET_FRAGMENTATION_LAST,
5480 &frame,
5481 &frame_len,
5482 &utf8_step);
5483 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
5484 (14 != frame_len) ||
5485 (NULL == frame) ||
5486 (MHD_WEBSOCKET_UTF8STEP_NORMAL != utf8_step) ||
5487 (0 != memcmp (frame, "\x80\x0C" "\x80\x80\x80" "blablabla", 14)))
5488 {
5489 fprintf (stderr,
5490 "Encode text test failed in line %u\n",
5491 (unsigned int) __LINE__);
5492 ++failed;
5493 }
5494 if (NULL != frame)
5495 {
5496 MHD_websocket_free (wss, frame);
5497 frame = NULL;
5498 }
5499 /* Regular test: Last fragment with UTF-8 on the edge for UTF4TAIL_2OF3 */
5500 utf8_step = MHD_WEBSOCKET_UTF8STEP_UTF4TAIL_2OF3;
5501 ret = MHD_websocket_encode_text (wss,
5502 "\x80\x80" " blablabla",
5503 12,
5504 MHD_WEBSOCKET_FRAGMENTATION_LAST,
5505 &frame,
5506 &frame_len,
5507 &utf8_step);
5508 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
5509 (14 != frame_len) ||
5510 (NULL == frame) ||
5511 (MHD_WEBSOCKET_UTF8STEP_NORMAL != utf8_step) ||
5512 (0 != memcmp (frame, "\x80\x0C" "\x80\x80" " blablabla", 14)))
5513 {
5514 fprintf (stderr,
5515 "Encode text test failed in line %u\n",
5516 (unsigned int) __LINE__);
5517 ++failed;
5518 }
5519 if (NULL != frame)
5520 {
5521 MHD_websocket_free (wss, frame);
5522 frame = NULL;
5523 }
5524 /* Regular test: Last fragment with UTF-8 on the edge for UTF4TAIL_3OF3 */
5525 utf8_step = MHD_WEBSOCKET_UTF8STEP_UTF4TAIL_3OF3;
5526 ret = MHD_websocket_encode_text (wss,
5527 "\x80" " blablabla",
5528 12,
5529 MHD_WEBSOCKET_FRAGMENTATION_LAST,
5530 &frame,
5531 &frame_len,
5532 &utf8_step);
5533 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
5534 (14 != frame_len) ||
5535 (NULL == frame) ||
5536 (MHD_WEBSOCKET_UTF8STEP_NORMAL != utf8_step) ||
5537 (0 != memcmp (frame, "\x80\x0C" "\x80" " blablabla", 14)))
5538 {
5539 fprintf (stderr,
5540 "Encode text test failed in line %u\n",
5541 (unsigned int) __LINE__);
5542 ++failed;
5543 }
5544 if (NULL != frame)
5545 {
5546 MHD_websocket_free (wss, frame);
5547 frame = NULL;
5548 }
5549
5550 /*
5551 ------------------------------------------------------------------------------
5552 Length checks
5553 ------------------------------------------------------------------------------
5554 */
5555 /* Edge test (success): Text frame without data */
5556 ret = MHD_websocket_encode_text (wss,
5557 NULL,
5558 0,
5559 MHD_WEBSOCKET_FRAGMENTATION_NONE,
5560 &frame,
5561 &frame_len,
5562 NULL);
5563 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
5564 (2 != frame_len) ||
5565 (NULL == frame) ||
5566 (0 != memcmp (frame, "\x81\x00", 2)))
5567 {
5568 fprintf (stderr,
5569 "Encode text test failed in line %u\n",
5570 (unsigned int) __LINE__);
5571 ++failed;
5572 }
5573 if (NULL != frame)
5574 {
5575 MHD_websocket_free (wss, frame);
5576 frame = NULL;
5577 }
5578 /* Edge test (success): Text frame with 1 byte of data */
5579 ret = MHD_websocket_encode_text (wss,
5580 "a",
5581 1,
5582 MHD_WEBSOCKET_FRAGMENTATION_NONE,
5583 &frame,
5584 &frame_len,
5585 NULL);
5586 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
5587 (3 != frame_len) ||
5588 (NULL == frame) ||
5589 (0 != memcmp (frame, "\x81\x01" "a", 3)))
5590 {
5591 fprintf (stderr,
5592 "Encode text test failed in line %u\n",
5593 (unsigned int) __LINE__);
5594 ++failed;
5595 }
5596 if (NULL != frame)
5597 {
5598 MHD_websocket_free (wss, frame);
5599 frame = NULL;
5600 }
5601 /* Edge test (success): Text frame with 125 bytes of data */
5602 ret = MHD_websocket_encode_text (wss,
5603 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ012345678",
5604 125,
5605 MHD_WEBSOCKET_FRAGMENTATION_NONE,
5606 &frame,
5607 &frame_len,
5608 NULL);
5609 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
5610 (127 != frame_len) ||
5611 (NULL == frame) ||
5612 (0 != memcmp (frame, "\x81\x7D"
5613 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ012345678",
5614 127)))
5615 {
5616 fprintf (stderr,
5617 "Encode text test failed in line %u\n",
5618 (unsigned int) __LINE__);
5619 ++failed;
5620 }
5621 if (NULL != frame)
5622 {
5623 MHD_websocket_free (wss, frame);
5624 frame = NULL;
5625 }
5626 /* Edge test (success): Text frame with 126 bytes of data */
5627 ret = MHD_websocket_encode_text (wss,
5628 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789",
5629 126,
5630 MHD_WEBSOCKET_FRAGMENTATION_NONE,
5631 &frame,
5632 &frame_len,
5633 NULL);
5634 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
5635 (130 != frame_len) ||
5636 (NULL == frame) ||
5637 (0 != memcmp (frame, "\x81\x7E\x00\x7E"
5638 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789",
5639 130)))
5640 {
5641 fprintf (stderr,
5642 "Encode text test failed in line %u\n",
5643 (unsigned int) __LINE__);
5644 ++failed;
5645 }
5646 if (NULL != frame)
5647 {
5648 MHD_websocket_free (wss, frame);
5649 frame = NULL;
5650 }
5651 /* Edge test (success): Text frame with 65535 bytes of data */
5652 allocate_length_test_data (&buf1,
5653 &buf2,
5654 65535,
5655 "\x81\x7E\xFF\xFF",
5656 4);
5657 ret = MHD_websocket_encode_text (wss,
5658 buf2,
5659 65535,
5660 MHD_WEBSOCKET_FRAGMENTATION_NONE,
5661 &frame,
5662 &frame_len,
5663 NULL);
5664 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
5665 (65535 + 4 != frame_len) ||
5666 (NULL == frame) ||
5667 (0 != memcmp (frame, buf1, 65535 + 4)))
5668 {
5669 fprintf (stderr,
5670 "Encode text test failed in line %u\n",
5671 (unsigned int) __LINE__);
5672 ++failed;
5673 }
5674 if (NULL != frame)
5675 {
5676 MHD_websocket_free (wss, frame);
5677 frame = NULL;
5678 }
5679 /* Edge test (success): Text frame with 65536 bytes of data */
5680 allocate_length_test_data (&buf1,
5681 &buf2,
5682 65536,
5683 "\x81\x7F\x00\x00\x00\x00\x00\x01\x00\x00",
5684 10);
5685 ret = MHD_websocket_encode_text (wss,
5686 buf2,
5687 65536,
5688 MHD_WEBSOCKET_FRAGMENTATION_NONE,
5689 &frame,
5690 &frame_len,
5691 NULL);
5692 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
5693 (65536 + 10 != frame_len) ||
5694 (NULL == frame) ||
5695 (0 != memcmp (frame, buf1, 65536 + 10)))
5696 {
5697 fprintf (stderr,
5698 "Encode text test failed in line %u\n",
5699 (unsigned int) __LINE__);
5700 ++failed;
5701 }
5702 if (NULL != frame)
5703 {
5704 MHD_websocket_free (wss, frame);
5705 frame = NULL;
5706 }
5707 /* Regular test: Text frame with 100 MB of data */
5708 allocate_length_test_data (&buf1,
5709 &buf2,
5710 104857600,
5711 "\x81\x7F\x00\x00\x00\x00\x06\x40\x00\x00",
5712 10);
5713 ret = MHD_websocket_encode_text (wss,
5714 buf2,
5715 104857600,
5716 MHD_WEBSOCKET_FRAGMENTATION_NONE,
5717 &frame,
5718 &frame_len,
5719 NULL);
5720 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
5721 (104857600 + 10 != frame_len) ||
5722 (NULL == frame) ||
5723 (0 != memcmp (frame, buf1, 104857600 + 10)))
5724 {
5725 fprintf (stderr,
5726 "Encode text test failed in line %u\n",
5727 (unsigned int) __LINE__);
5728 ++failed;
5729 }
5730 if (NULL != frame)
5731 {
5732 MHD_websocket_free (wss, frame);
5733 frame = NULL;
5734 }
5735 if (NULL != buf1)
5736 {
5737 free (buf1);
5738 buf1 = NULL;
5739 }
5740 if (NULL != buf2)
5741 {
5742 free (buf2);
5743 buf2 = NULL;
5744 }
5745 /* Fail test: frame_len is greater than 0x7FFFFFFFFFFFFFFF
5746 (this is the maximum allowed payload size) */
5747 frame_len = 0;
5748 ret = MHD_websocket_encode_text (wss,
5749 "abc",
5750 (uint64_t) 0x8000000000000000,
5751 MHD_WEBSOCKET_FRAGMENTATION_NONE,
5752 &frame,
5753 &frame_len,
5754 NULL);
5755 if ((MHD_WEBSOCKET_STATUS_MAXIMUM_SIZE_EXCEEDED != ret) ||
5756 (0 != frame_len) ||
5757 (NULL != frame) )
5758 {
5759 fprintf (stderr,
5760 "Encode text test failed in line %u\n",
5761 (unsigned int) __LINE__);
5762 ++failed;
5763 }
5764 if (NULL != frame)
5765 {
5766 MHD_websocket_free (wss, frame);
5767 frame = NULL;
5768 }
5769
5770 /*
5771 ------------------------------------------------------------------------------
5772 Wrong parameters
5773 ------------------------------------------------------------------------------
5774 */
5775 /* Fail test: `ws` not passed */
5776 frame = (char*) (uintptr_t) 0xBAADF00D;
5777 frame_len = 0x87654321;
5778 ret = MHD_websocket_encode_text (NULL,
5779 "abc",
5780 3,
5781 MHD_WEBSOCKET_FRAGMENTATION_NONE,
5782 &frame,
5783 &frame_len,
5784 NULL);
5785 if ((MHD_WEBSOCKET_STATUS_PARAMETER_ERROR != ret) ||
5786 (0 != frame_len) ||
5787 (NULL != frame) )
5788 {
5789 fprintf (stderr,
5790 "Encode text test failed in line %u\n",
5791 (unsigned int) __LINE__);
5792 ++failed;
5793 }
5794 if (((char*) (uintptr_t) 0xBAADF00D) == frame)
5795 {
5796 frame = NULL;
5797 }
5798 if (NULL != frame)
5799 {
5800 MHD_websocket_free (wss, frame);
5801 frame = NULL;
5802 }
5803 /* Fail test: `payload_utf8` not passed, but `payload_utf8_len` != 0 */
5804 frame = (char*) (uintptr_t) 0xBAADF00D;
5805 frame_len = 0x87654321;
5806 ret = MHD_websocket_encode_text (wss,
5807 NULL,
5808 3,
5809 MHD_WEBSOCKET_FRAGMENTATION_NONE,
5810 &frame,
5811 &frame_len,
5812 NULL);
5813 if ((MHD_WEBSOCKET_STATUS_PARAMETER_ERROR != ret) ||
5814 (0 != frame_len) ||
5815 (NULL != frame) )
5816 {
5817 fprintf (stderr,
5818 "Encode text test failed in line %u\n",
5819 (unsigned int) __LINE__);
5820 ++failed;
5821 }
5822 if (((char*) (uintptr_t) 0xBAADF00D) == frame)
5823 {
5824 frame = NULL;
5825 }
5826 if (NULL != frame)
5827 {
5828 MHD_websocket_free (wss, frame);
5829 frame = NULL;
5830 }
5831 /* Regular test: `payload_utf8` passed, but `payload_utf8_len` == 0 */
5832 frame = (char*) (uintptr_t) 0xBAADF00D;
5833 frame_len = 0x87654321;
5834 ret = MHD_websocket_encode_text (wss,
5835 "abc",
5836 0,
5837 MHD_WEBSOCKET_FRAGMENTATION_NONE,
5838 &frame,
5839 &frame_len,
5840 NULL);
5841 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
5842 (2 != frame_len) ||
5843 (NULL == frame) ||
5844 (((char*) (uintptr_t) 0xBAADF00D) == frame) ||
5845 (0 != memcmp (frame, "\x81\x00", 2)))
5846 {
5847 fprintf (stderr,
5848 "Encode text test failed in line %u\n",
5849 (unsigned int) __LINE__);
5850 ++failed;
5851 }
5852 if (((char*) (uintptr_t) 0xBAADF00D) == frame)
5853 {
5854 frame = NULL;
5855 }
5856 if (NULL != frame)
5857 {
5858 MHD_websocket_free (wss, frame);
5859 frame = NULL;
5860 }
5861 /* Fail test: `frame` not passed */
5862 frame_len = 0x87654321;
5863 ret = MHD_websocket_encode_text (wss,
5864 "abc",
5865 3,
5866 MHD_WEBSOCKET_FRAGMENTATION_NONE,
5867 NULL,
5868 &frame_len,
5869 NULL);
5870 if ((MHD_WEBSOCKET_STATUS_PARAMETER_ERROR != ret) ||
5871 (0 != frame_len) )
5872 {
5873 fprintf (stderr,
5874 "Encode text test failed in line %u\n",
5875 (unsigned int) __LINE__);
5876 ++failed;
5877 }
5878 /* Fail test: `frame_len` not passed */
5879 frame = (char*) (uintptr_t) 0xBAADF00D;
5880 ret = MHD_websocket_encode_text (wss,
5881 "abc",
5882 3,
5883 MHD_WEBSOCKET_FRAGMENTATION_NONE,
5884 &frame,
5885 NULL,
5886 NULL);
5887 if ((MHD_WEBSOCKET_STATUS_PARAMETER_ERROR != ret) ||
5888 (NULL != frame) )
5889 {
5890 fprintf (stderr,
5891 "Encode text test failed in line %u\n",
5892 (unsigned int) __LINE__);
5893 ++failed;
5894 }
5895 if (((char*) (uintptr_t) 0xBAADF00D) == frame)
5896 {
5897 frame = NULL;
5898 }
5899 if (NULL != frame)
5900 {
5901 MHD_websocket_free (wss, frame);
5902 frame = NULL;
5903 }
5904 /* Regular test: `utf8_step` passed for non-fragmentation
5905 (is allowed and `utf8_step` will be filled then) */
5906 frame = (char*) (uintptr_t) 0xBAADF00D;
5907 frame_len = 0x87654321;
5908 utf8_step = -99;
5909 ret = MHD_websocket_encode_text (wss,
5910 "abc",
5911 3,
5912 MHD_WEBSOCKET_FRAGMENTATION_NONE,
5913 &frame,
5914 &frame_len,
5915 &utf8_step);
5916 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
5917 (5 != frame_len) ||
5918 (NULL == frame) ||
5919 (((char*) (uintptr_t) 0xBAADF00D) == frame) ||
5920 (MHD_WEBSOCKET_UTF8STEP_NORMAL != utf8_step) ||
5921 (0 != memcmp (frame, "\x81\x03" "abc", 5)))
5922 {
5923 fprintf (stderr,
5924 "Encode text test failed in line %u\n",
5925 (unsigned int) __LINE__);
5926 ++failed;
5927 }
5928 if (((char*) (uintptr_t) 0xBAADF00D) == frame)
5929 {
5930 frame = NULL;
5931 }
5932 if (NULL != frame)
5933 {
5934 MHD_websocket_free (wss, frame);
5935 frame = NULL;
5936 }
5937 /* Fail test: `utf8_step` passed for non-fragmentation with invalid UTF-8
5938 (is allowed and `utf8_step` will be filled then) */
5939 frame = (char*) (uintptr_t) 0xBAADF00D;
5940 frame_len = 0x87654321;
5941 utf8_step = -99;
5942 ret = MHD_websocket_encode_text (wss,
5943 "ab\xC3",
5944 3,
5945 MHD_WEBSOCKET_FRAGMENTATION_NONE,
5946 &frame,
5947 &frame_len,
5948 &utf8_step);
5949 if ((MHD_WEBSOCKET_STATUS_UTF8_ENCODING_ERROR != ret) ||
5950 (0 != frame_len) ||
5951 (NULL != frame) ||
5952 (MHD_WEBSOCKET_UTF8STEP_UTF2TAIL_1OF1 != utf8_step) )
5953 {
5954 fprintf (stderr,
5955 "Encode text test failed in line %u\n",
5956 (unsigned int) __LINE__);
5957 ++failed;
5958 }
5959 if (((char*) (uintptr_t) 0xBAADF00D) == frame)
5960 {
5961 frame = NULL;
5962 }
5963 if (NULL != frame)
5964 {
5965 MHD_websocket_free (wss, frame);
5966 frame = NULL;
5967 }
5968 /* Fail test: `utf8_step` not passed for fragmentation #1 */
5969 frame = (char*) (uintptr_t) 0xBAADF00D;
5970 frame_len = 0x87654321;
5971 ret = MHD_websocket_encode_text (wss,
5972 "abc",
5973 3,
5974 MHD_WEBSOCKET_FRAGMENTATION_FIRST,
5975 &frame,
5976 &frame_len,
5977 NULL);
5978 if ((MHD_WEBSOCKET_STATUS_PARAMETER_ERROR != ret) ||
5979 (0 != frame_len) ||
5980 (NULL != frame) )
5981 {
5982 fprintf (stderr,
5983 "Encode text test failed in line %u\n",
5984 (unsigned int) __LINE__);
5985 ++failed;
5986 }
5987 if (((char*) (uintptr_t) 0xBAADF00D) == frame)
5988 {
5989 frame = NULL;
5990 }
5991 if (NULL != frame)
5992 {
5993 MHD_websocket_free (wss, frame);
5994 frame = NULL;
5995 }
5996 /* Fail test: `utf8_step` not passed for fragmentation #2 */
5997 frame = (char*) (uintptr_t) 0xBAADF00D;
5998 frame_len = 0x87654321;
5999 ret = MHD_websocket_encode_text (wss,
6000 "abc",
6001 3,
6002 MHD_WEBSOCKET_FRAGMENTATION_FOLLOWING,
6003 &frame,
6004 &frame_len,
6005 NULL);
6006 if ((MHD_WEBSOCKET_STATUS_PARAMETER_ERROR != ret) ||
6007 (0 != frame_len) ||
6008 (NULL != frame) )
6009 {
6010 fprintf (stderr,
6011 "Encode text test failed in line %u\n",
6012 (unsigned int) __LINE__);
6013 ++failed;
6014 }
6015 if (((char*) (uintptr_t) 0xBAADF00D) == frame)
6016 {
6017 frame = NULL;
6018 }
6019 if (NULL != frame)
6020 {
6021 MHD_websocket_free (wss, frame);
6022 frame = NULL;
6023 }
6024 /* Fail test: `utf8_step` not passed for fragmentation #3 */
6025 frame = (char*) (uintptr_t) 0xBAADF00D;
6026 frame_len = 0x87654321;
6027 ret = MHD_websocket_encode_text (wss,
6028 "abc",
6029 3,
6030 MHD_WEBSOCKET_FRAGMENTATION_LAST,
6031 &frame,
6032 &frame_len,
6033 NULL);
6034 if ((MHD_WEBSOCKET_STATUS_PARAMETER_ERROR != ret) ||
6035 (0 != frame_len) ||
6036 (NULL != frame) )
6037 {
6038 fprintf (stderr,
6039 "Encode text test failed in line %u\n",
6040 (unsigned int) __LINE__);
6041 ++failed;
6042 }
6043 if (((char*) (uintptr_t) 0xBAADF00D) == frame)
6044 {
6045 frame = NULL;
6046 }
6047 if (NULL != frame)
6048 {
6049 MHD_websocket_free (wss, frame);
6050 frame = NULL;
6051 }
6052 /* Regular test: `utf8_step` passed for fragmentation #1 */
6053 frame = (char*) (uintptr_t) 0xBAADF00D;
6054 frame_len = 0x87654321;
6055 utf8_step = -99;
6056 ret = MHD_websocket_encode_text (wss,
6057 "abc",
6058 3,
6059 MHD_WEBSOCKET_FRAGMENTATION_FIRST,
6060 &frame,
6061 &frame_len,
6062 &utf8_step);
6063 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
6064 (5 != frame_len) ||
6065 (NULL == frame) ||
6066 (((char*) (uintptr_t) 0xBAADF00D) == frame) ||
6067 (MHD_WEBSOCKET_UTF8STEP_NORMAL != utf8_step) ||
6068 (0 != memcmp (frame, "\x01\x03" "abc", 5)))
6069 {
6070 fprintf (stderr,
6071 "Encode text test failed in line %u\n",
6072 (unsigned int) __LINE__);
6073 ++failed;
6074 }
6075 if (((char*) (uintptr_t) 0xBAADF00D) == frame)
6076 {
6077 frame = NULL;
6078 }
6079 if (NULL != frame)
6080 {
6081 MHD_websocket_free (wss, frame);
6082 frame = NULL;
6083 }
6084 /* Regular test: `utf8_step` passed for fragmentation #2 */
6085 frame = (char*) (uintptr_t) 0xBAADF00D;
6086 frame_len = 0x87654321;
6087 utf8_step = MHD_WEBSOCKET_UTF8STEP_NORMAL;
6088 ret = MHD_websocket_encode_text (wss,
6089 "abc",
6090 3,
6091 MHD_WEBSOCKET_FRAGMENTATION_FOLLOWING,
6092 &frame,
6093 &frame_len,
6094 &utf8_step);
6095 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
6096 (5 != frame_len) ||
6097 (NULL == frame) ||
6098 (((char*) (uintptr_t) 0xBAADF00D) == frame) ||
6099 (MHD_WEBSOCKET_UTF8STEP_NORMAL != utf8_step) ||
6100 (0 != memcmp (frame, "\x00\x03" "abc", 5)))
6101 {
6102 fprintf (stderr,
6103 "Encode text test failed in line %u\n",
6104 (unsigned int) __LINE__);
6105 ++failed;
6106 }
6107 if (((char*) (uintptr_t) 0xBAADF00D) == frame)
6108 {
6109 frame = NULL;
6110 }
6111 if (NULL != frame)
6112 {
6113 MHD_websocket_free (wss, frame);
6114 frame = NULL;
6115 }
6116 /* Regular test: `utf8_step` passed for fragmentation #3 */
6117 frame = (char*) (uintptr_t) 0xBAADF00D;
6118 frame_len = 0x87654321;
6119 utf8_step = MHD_WEBSOCKET_UTF8STEP_NORMAL;
6120 ret = MHD_websocket_encode_text (wss,
6121 "abc",
6122 3,
6123 MHD_WEBSOCKET_FRAGMENTATION_LAST,
6124 &frame,
6125 &frame_len,
6126 &utf8_step);
6127 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
6128 (5 != frame_len) ||
6129 (NULL == frame) ||
6130 (((char*) (uintptr_t) 0xBAADF00D) == frame) ||
6131 (MHD_WEBSOCKET_UTF8STEP_NORMAL != utf8_step) ||
6132 (0 != memcmp (frame, "\x80\x03" "abc", 5)))
6133 {
6134 fprintf (stderr,
6135 "Encode text test failed in line %u\n",
6136 (unsigned int) __LINE__);
6137 ++failed;
6138 }
6139 if (((char*) (uintptr_t) 0xBAADF00D) == frame)
6140 {
6141 frame = NULL;
6142 }
6143 if (NULL != frame)
6144 {
6145 MHD_websocket_free (wss, frame);
6146 frame = NULL;
6147 }
6148 /* Fail test: `fragmentation` has an invalid value */
6149 frame = (char*) (uintptr_t) 0xBAADF00D;
6150 frame_len = 0x87654321;
6151 utf8_step = -99;
6152 ret = MHD_websocket_encode_text (wss,
6153 "abc",
6154 3,
6155 MHD_WEBSOCKET_FRAGMENTATION_LAST + 1,
6156 &frame,
6157 &frame_len,
6158 &utf8_step);
6159 if ((MHD_WEBSOCKET_STATUS_PARAMETER_ERROR != ret) ||
6160 (0 != frame_len) ||
6161 (NULL != frame) ||
6162 (-99 != utf8_step) )
6163 {
6164 fprintf (stderr,
6165 "Encode text test failed in line %u\n",
6166 (unsigned int) __LINE__);
6167 ++failed;
6168 }
6169 if (((char*) (uintptr_t) 0xBAADF00D) == frame)
6170 {
6171 frame = NULL;
6172 }
6173 if (NULL != frame)
6174 {
6175 MHD_websocket_free (wss, frame);
6176 frame = NULL;
6177 }
6178
6179 /*
6180 ------------------------------------------------------------------------------
6181 validity after temporary out-of-memory
6182 ------------------------------------------------------------------------------
6183 */
6184 {
6185 struct MHD_WebSocketStream*wsx;
6186 if (MHD_WEBSOCKET_STATUS_OK == MHD_websocket_stream_init2 (&wsx,
6187 MHD_WEBSOCKET_FLAG_SERVER,
6188 0,
6189 test_malloc,
6190 test_realloc,
6191 test_free))
6192 {
6193 /* Fail test: allocation while no memory available */
6194 disable_alloc = 1;
6195 ret = MHD_websocket_encode_text (wsx,
6196 "abc",
6197 3,
6198 MHD_WEBSOCKET_FRAGMENTATION_NONE,
6199 &frame,
6200 &frame_len,
6201 NULL);
6202 if ((MHD_WEBSOCKET_STATUS_MEMORY_ERROR != ret) ||
6203 (0 != frame_len) ||
6204 (NULL != frame) )
6205 {
6206 fprintf (stderr,
6207 "Encode text test failed in line %u\n",
6208 (unsigned int) __LINE__);
6209 ++failed;
6210 }
6211 if (NULL != frame)
6212 {
6213 MHD_websocket_free (wsx, frame);
6214 frame = NULL;
6215 }
6216 /* Regular test: allocation while memory is available again */
6217 disable_alloc = 0;
6218 ret = MHD_websocket_encode_text (wsx,
6219 "abc",
6220 3,
6221 MHD_WEBSOCKET_FRAGMENTATION_NONE,
6222 &frame,
6223 &frame_len,
6224 NULL);
6225 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
6226 (5 != frame_len) ||
6227 (NULL == frame) ||
6228 (0 != memcmp (frame, "\x81\x03" "abc", 5)))
6229 {
6230 fprintf (stderr,
6231 "Encode text test failed in line %u\n",
6232 (unsigned int) __LINE__);
6233 ++failed;
6234 }
6235 if (NULL != frame)
6236 {
6237 MHD_websocket_free (wsx, frame);
6238 frame = NULL;
6239 }
6240
6241 MHD_websocket_stream_free (wsx);
6242 }
6243 else
6244 {
6245 fprintf (stderr,
6246 "Couldn't perform memory test for text encoding in line %u\n",
6247 (unsigned int) __LINE__);
6248 ++failed;
6249 }
6250 }
6251
6252 if (NULL != buf1)
6253 free (buf1);
6254 if (NULL != buf2)
6255 free (buf2);
6256 if (NULL != wsc)
6257 MHD_websocket_stream_free (wsc);
6258 if (NULL != wss)
6259 MHD_websocket_stream_free (wss);
6260
6261 return failed != 0 ? 0x08 : 0x00;
6262}
6263
6264
6265/**
6266 * Test procedure for `MHD_websocket_encode_binary()`
6267 */
6268int
6269test_encodes_binary ()
6270{
6271 int failed = 0;
6272 struct MHD_WebSocketStream*wss;
6273 struct MHD_WebSocketStream*wsc;
6274 int ret;
6275 char *buf1 = NULL, *buf2 = NULL;
6276 char*frame = NULL;
6277 size_t frame_len = 0;
6278
6279 if (MHD_WEBSOCKET_STATUS_OK != MHD_websocket_stream_init (&wsc,
6280 MHD_WEBSOCKET_FLAG_CLIENT,
6281 0))
6282 {
6283 fprintf (stderr,
6284 "No encode binary tests possible due to failed stream init in line %u\n",
6285 (unsigned int) __LINE__);
6286 return 0x10;
6287 }
6288 if (MHD_WEBSOCKET_STATUS_OK != MHD_websocket_stream_init (&wss,
6289 MHD_WEBSOCKET_FLAG_SERVER,
6290 0))
6291 {
6292 fprintf (stderr,
6293 "No encode binary tests possible due to failed stream init in line %u\n",
6294 (unsigned int) __LINE__);
6295 if (NULL != wsc)
6296 MHD_websocket_stream_free (wsc);
6297 return 0x10;
6298 }
6299
6300 /*
6301 ------------------------------------------------------------------------------
6302 Encoding
6303 ------------------------------------------------------------------------------
6304 */
6305 /* Regular test: Some data, we are server */
6306 ret = MHD_websocket_encode_binary (wss,
6307 "blablabla",
6308 9,
6309 MHD_WEBSOCKET_FRAGMENTATION_NONE,
6310 &frame,
6311 &frame_len);
6312 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
6313 (11 != frame_len) ||
6314 (NULL == frame) ||
6315 (0 != memcmp (frame, "\x82\x09" "blablabla", 11)))
6316 {
6317 fprintf (stderr,
6318 "Encode binary test failed in line %u\n",
6319 (unsigned int) __LINE__);
6320 ++failed;
6321 }
6322 if (NULL != frame)
6323 {
6324 MHD_websocket_free (wss, frame);
6325 frame = NULL;
6326 }
6327 /* Regular test: Some data, we are client */
6328 ret = MHD_websocket_encode_binary (wsc,
6329 "blablabla",
6330 9,
6331 MHD_WEBSOCKET_FRAGMENTATION_NONE,
6332 &frame,
6333 &frame_len);
6334 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
6335 (15 != frame_len) ||
6336 (NULL == frame) )
6337 {
6338 fprintf (stderr,
6339 "Encode binary test failed in line %u\n",
6340 (unsigned int) __LINE__);
6341 ++failed;
6342 }
6343 else
6344 {
6345 failed += test_decode_single (__LINE__,
6346 MHD_WEBSOCKET_FLAG_SERVER
6347 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
6348 0,
6349 1,
6350 0,
6351 frame,
6352 frame_len,
6353 "blablabla",
6354 9,
6355 MHD_WEBSOCKET_STATUS_BINARY_FRAME,
6356 MHD_WEBSOCKET_VALIDITY_VALID,
6357 frame_len);
6358 }
6359 if (NULL != frame)
6360 {
6361 MHD_websocket_free (wsc, frame);
6362 frame = NULL;
6363 }
6364 /* Edge test (success): Some data with NUL characters, we are server */
6365 ret = MHD_websocket_encode_binary (wss,
6366 "bla" "\0\0\0" "bla",
6367 9,
6368 MHD_WEBSOCKET_FRAGMENTATION_NONE,
6369 &frame,
6370 &frame_len);
6371 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
6372 (11 != frame_len) ||
6373 (NULL == frame) ||
6374 (0 != memcmp (frame, "\x82\x09" "bla" "\0\0\0" "bla", 11)))
6375 {
6376 fprintf (stderr,
6377 "Encode binary test failed in line %u\n",
6378 (unsigned int) __LINE__);
6379 ++failed;
6380 }
6381 if (NULL != frame)
6382 {
6383 MHD_websocket_free (wss, frame);
6384 frame = NULL;
6385 }
6386 /* Regular test: Some data which looks like broken UTF-8, we are server */
6387 ret = MHD_websocket_encode_binary (wss,
6388 "bla" "\xC3" "blabla",
6389 10,
6390 MHD_WEBSOCKET_FRAGMENTATION_NONE,
6391 &frame,
6392 &frame_len);
6393 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
6394 (12 != frame_len) ||
6395 (NULL == frame) ||
6396 (0 != memcmp (frame, "\x82\x0A" "bla" "\xC3" "blabla", 12)))
6397 {
6398 fprintf (stderr,
6399 "Encode binary test failed in line %u\n",
6400 (unsigned int) __LINE__);
6401 ++failed;
6402 }
6403 if (NULL != frame)
6404 {
6405 MHD_websocket_free (wss, frame);
6406 frame = NULL;
6407 }
6408
6409 /*
6410 ------------------------------------------------------------------------------
6411 Fragmentation
6412 ------------------------------------------------------------------------------
6413 */
6414 /* Regular test: Some data */
6415 ret = MHD_websocket_encode_binary (wss,
6416 "blablabla",
6417 9,
6418 MHD_WEBSOCKET_FRAGMENTATION_NONE,
6419 &frame,
6420 &frame_len);
6421 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
6422 (11 != frame_len) ||
6423 (NULL == frame) ||
6424 (0 != memcmp (frame, "\x82\x09" "blablabla", 11)))
6425 {
6426 fprintf (stderr,
6427 "Encode binary test failed in line %u\n",
6428 (unsigned int) __LINE__);
6429 ++failed;
6430 }
6431 if (NULL != frame)
6432 {
6433 MHD_websocket_free (wss, frame);
6434 frame = NULL;
6435 }
6436 /* Regular test: First fragment */
6437 ret = MHD_websocket_encode_binary (wss,
6438 "blablabla",
6439 9,
6440 MHD_WEBSOCKET_FRAGMENTATION_FIRST,
6441 &frame,
6442 &frame_len);
6443 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
6444 (11 != frame_len) ||
6445 (NULL == frame) ||
6446 (0 != memcmp (frame, "\x02\x09" "blablabla", 11)))
6447 {
6448 fprintf (stderr,
6449 "Encode binary test failed in line %u\n",
6450 (unsigned int) __LINE__);
6451 ++failed;
6452 }
6453 if (NULL != frame)
6454 {
6455 MHD_websocket_free (wss, frame);
6456 frame = NULL;
6457 }
6458 /* Regular test: Middle fragment */
6459 ret = MHD_websocket_encode_binary (wss,
6460 "blablabla",
6461 9,
6462 MHD_WEBSOCKET_FRAGMENTATION_FOLLOWING,
6463 &frame,
6464 &frame_len);
6465 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
6466 (11 != frame_len) ||
6467 (NULL == frame) ||
6468 (0 != memcmp (frame, "\x00\x09" "blablabla", 11)))
6469 {
6470 fprintf (stderr,
6471 "Encode binary test failed in line %u\n",
6472 (unsigned int) __LINE__);
6473 ++failed;
6474 }
6475 if (NULL != frame)
6476 {
6477 MHD_websocket_free (wss, frame);
6478 frame = NULL;
6479 }
6480 /* Regular test: Last fragment */
6481 ret = MHD_websocket_encode_binary (wss,
6482 "blablabla",
6483 9,
6484 MHD_WEBSOCKET_FRAGMENTATION_LAST,
6485 &frame,
6486 &frame_len);
6487 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
6488 (11 != frame_len) ||
6489 (NULL == frame) ||
6490 (0 != memcmp (frame, "\x80\x09" "blablabla", 11)))
6491 {
6492 fprintf (stderr,
6493 "Encode binary test failed in line %u\n",
6494 (unsigned int) __LINE__);
6495 ++failed;
6496 }
6497 if (NULL != frame)
6498 {
6499 MHD_websocket_free (wss, frame);
6500 frame = NULL;
6501 }
6502
6503 /*
6504 ------------------------------------------------------------------------------
6505 Length checks
6506 ------------------------------------------------------------------------------
6507 */
6508 /* Edge test (success): Binary frame without data */
6509 ret = MHD_websocket_encode_binary (wss,
6510 NULL,
6511 0,
6512 MHD_WEBSOCKET_FRAGMENTATION_NONE,
6513 &frame,
6514 &frame_len);
6515 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
6516 (2 != frame_len) ||
6517 (NULL == frame) ||
6518 (0 != memcmp (frame, "\x82\x00", 2)))
6519 {
6520 fprintf (stderr,
6521 "Encode binary test failed in line %u\n",
6522 (unsigned int) __LINE__);
6523 ++failed;
6524 }
6525 if (NULL != frame)
6526 {
6527 MHD_websocket_free (wss, frame);
6528 frame = NULL;
6529 }
6530 /* Edge test (success): Binary frame with 1 byte of data */
6531 ret = MHD_websocket_encode_binary (wss,
6532 "a",
6533 1,
6534 MHD_WEBSOCKET_FRAGMENTATION_NONE,
6535 &frame,
6536 &frame_len);
6537 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
6538 (3 != frame_len) ||
6539 (NULL == frame) ||
6540 (0 != memcmp (frame, "\x82\x01" "a", 3)))
6541 {
6542 fprintf (stderr,
6543 "Encode binary test failed in line %u\n",
6544 (unsigned int) __LINE__);
6545 ++failed;
6546 }
6547 if (NULL != frame)
6548 {
6549 MHD_websocket_free (wss, frame);
6550 frame = NULL;
6551 }
6552 /* Edge test (success): Binary frame with 125 bytes of data */
6553 ret = MHD_websocket_encode_binary (wss,
6554 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ012345678",
6555 125,
6556 MHD_WEBSOCKET_FRAGMENTATION_NONE,
6557 &frame,
6558 &frame_len);
6559 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
6560 (127 != frame_len) ||
6561 (NULL == frame) ||
6562 (0 != memcmp (frame, "\x82\x7D"
6563 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ012345678",
6564 127)))
6565 {
6566 fprintf (stderr,
6567 "Encode binary test failed in line %u\n",
6568 (unsigned int) __LINE__);
6569 ++failed;
6570 }
6571 if (NULL != frame)
6572 {
6573 MHD_websocket_free (wss, frame);
6574 frame = NULL;
6575 }
6576 /* Edge test (success): Binary frame with 126 bytes of data */
6577 ret = MHD_websocket_encode_binary (wss,
6578 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789",
6579 126,
6580 MHD_WEBSOCKET_FRAGMENTATION_NONE,
6581 &frame,
6582 &frame_len);
6583 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
6584 (130 != frame_len) ||
6585 (NULL == frame) ||
6586 (0 != memcmp (frame, "\x82\x7E\x00\x7E"
6587 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789",
6588 130)))
6589 {
6590 fprintf (stderr,
6591 "Encode binary test failed in line %u\n",
6592 (unsigned int) __LINE__);
6593 ++failed;
6594 }
6595 if (NULL != frame)
6596 {
6597 MHD_websocket_free (wss, frame);
6598 frame = NULL;
6599 }
6600 /* Edge test (success): Binary frame with 65535 bytes of data */
6601 allocate_length_test_data (&buf1,
6602 &buf2,
6603 65535,
6604 "\x82\x7E\xFF\xFF",
6605 4);
6606 ret = MHD_websocket_encode_binary (wss,
6607 buf2,
6608 65535,
6609 MHD_WEBSOCKET_FRAGMENTATION_NONE,
6610 &frame,
6611 &frame_len);
6612 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
6613 (65535 + 4 != frame_len) ||
6614 (NULL == frame) ||
6615 (0 != memcmp (frame, buf1, 65535 + 4)))
6616 {
6617 fprintf (stderr,
6618 "Encode binary test failed in line %u\n",
6619 (unsigned int) __LINE__);
6620 ++failed;
6621 }
6622 if (NULL != frame)
6623 {
6624 MHD_websocket_free (wss, frame);
6625 frame = NULL;
6626 }
6627 /* Edge test (success): Binary frame with 65536 bytes of data */
6628 allocate_length_test_data (&buf1,
6629 &buf2,
6630 65536,
6631 "\x82\x7F\x00\x00\x00\x00\x00\x01\x00\x00",
6632 10);
6633 ret = MHD_websocket_encode_binary (wss,
6634 buf2,
6635 65536,
6636 MHD_WEBSOCKET_FRAGMENTATION_NONE,
6637 &frame,
6638 &frame_len);
6639 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
6640 (65536 + 10 != frame_len) ||
6641 (NULL == frame) ||
6642 (0 != memcmp (frame, buf1, 65536 + 10)))
6643 {
6644 fprintf (stderr,
6645 "Encode binary test failed in line %u\n",
6646 (unsigned int) __LINE__);
6647 ++failed;
6648 }
6649 if (NULL != frame)
6650 {
6651 MHD_websocket_free (wss, frame);
6652 frame = NULL;
6653 }
6654 /* Regular test: Binary frame with 100 MB of data */
6655 allocate_length_test_data (&buf1,
6656 &buf2,
6657 104857600,
6658 "\x82\x7F\x00\x00\x00\x00\x06\x40\x00\x00",
6659 10);
6660 ret = MHD_websocket_encode_binary (wss,
6661 buf2,
6662 104857600,
6663 MHD_WEBSOCKET_FRAGMENTATION_NONE,
6664 &frame,
6665 &frame_len);
6666 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
6667 (104857600 + 10 != frame_len) ||
6668 (NULL == frame) ||
6669 (0 != memcmp (frame, buf1, 104857600 + 10)))
6670 {
6671 fprintf (stderr,
6672 "Encode binary test failed in line %u\n",
6673 (unsigned int) __LINE__);
6674 ++failed;
6675 }
6676 if (NULL != frame)
6677 {
6678 MHD_websocket_free (wss, frame);
6679 frame = NULL;
6680 }
6681 if (NULL != buf1)
6682 {
6683 free (buf1);
6684 buf1 = NULL;
6685 }
6686 if (NULL != buf2)
6687 {
6688 free (buf2);
6689 buf2 = NULL;
6690 }
6691 /* Fail test: `frame_len` is greater than 0x7FFFFFFFFFFFFFFF
6692 (this is the maximum allowed payload size) */
6693 frame_len = 0;
6694 ret = MHD_websocket_encode_binary (wss,
6695 "abc",
6696 (uint64_t) 0x8000000000000000,
6697 MHD_WEBSOCKET_FRAGMENTATION_NONE,
6698 &frame,
6699 &frame_len);
6700 if ((MHD_WEBSOCKET_STATUS_MAXIMUM_SIZE_EXCEEDED != ret) ||
6701 (0 != frame_len) ||
6702 (NULL != frame) )
6703 {
6704 fprintf (stderr,
6705 "Encode binary test failed in line %u\n",
6706 (unsigned int) __LINE__);
6707 ++failed;
6708 }
6709 if (NULL != frame)
6710 {
6711 MHD_websocket_free (wss, frame);
6712 frame = NULL;
6713 }
6714
6715 /*
6716 ------------------------------------------------------------------------------
6717 Wrong parameters
6718 ------------------------------------------------------------------------------
6719 */
6720 /* Fail test: `ws` not passed */
6721 frame = (char*) (uintptr_t) 0xBAADF00D;
6722 frame_len = 0x87654321;
6723 ret = MHD_websocket_encode_binary (NULL,
6724 "abc",
6725 3,
6726 MHD_WEBSOCKET_FRAGMENTATION_NONE,
6727 &frame,
6728 &frame_len);
6729 if ((MHD_WEBSOCKET_STATUS_PARAMETER_ERROR != ret) ||
6730 (0 != frame_len) ||
6731 (NULL != frame) )
6732 {
6733 fprintf (stderr,
6734 "Encode binary test failed in line %u\n",
6735 (unsigned int) __LINE__);
6736 ++failed;
6737 }
6738 if (((char*) (uintptr_t) 0xBAADF00D) == frame)
6739 {
6740 frame = NULL;
6741 }
6742 if (NULL != frame)
6743 {
6744 MHD_websocket_free (wss, frame);
6745 frame = NULL;
6746 }
6747 /* Fail test: `payload` not passed, but `payload_len` != 0 */
6748 frame = (char*) (uintptr_t) 0xBAADF00D;
6749 frame_len = 0x87654321;
6750 ret = MHD_websocket_encode_binary (wss,
6751 NULL,
6752 3,
6753 MHD_WEBSOCKET_FRAGMENTATION_NONE,
6754 &frame,
6755 &frame_len);
6756 if ((MHD_WEBSOCKET_STATUS_PARAMETER_ERROR != ret) ||
6757 (0 != frame_len) ||
6758 (NULL != frame) )
6759 {
6760 fprintf (stderr,
6761 "Encode binary test failed in line %u\n",
6762 (unsigned int) __LINE__);
6763 ++failed;
6764 }
6765 if (((char*) (uintptr_t) 0xBAADF00D) == frame)
6766 {
6767 frame = NULL;
6768 }
6769 if (NULL != frame)
6770 {
6771 MHD_websocket_free (wss, frame);
6772 frame = NULL;
6773 }
6774 /* Regular test: `payload` passed, but `payload_len` == 0 */
6775 frame = (char*) (uintptr_t) 0xBAADF00D;
6776 frame_len = 0x87654321;
6777 ret = MHD_websocket_encode_binary (wss,
6778 "abc",
6779 0,
6780 MHD_WEBSOCKET_FRAGMENTATION_NONE,
6781 &frame,
6782 &frame_len);
6783 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
6784 (2 != frame_len) ||
6785 (NULL == frame) ||
6786 (((char*) (uintptr_t) 0xBAADF00D) == frame) ||
6787 (0 != memcmp (frame, "\x82\x00", 2)))
6788 {
6789 fprintf (stderr,
6790 "Encode binary test failed in line %u\n",
6791 (unsigned int) __LINE__);
6792 ++failed;
6793 }
6794 if (((char*) (uintptr_t) 0xBAADF00D) == frame)
6795 {
6796 frame = NULL;
6797 }
6798 if (NULL != frame)
6799 {
6800 MHD_websocket_free (wss, frame);
6801 frame = NULL;
6802 }
6803 /* Fail test: `frame` not passed */
6804 frame_len = 0x87654321;
6805 ret = MHD_websocket_encode_binary (wss,
6806 "abc",
6807 3,
6808 MHD_WEBSOCKET_FRAGMENTATION_NONE,
6809 NULL,
6810 &frame_len);
6811 if ((MHD_WEBSOCKET_STATUS_PARAMETER_ERROR != ret) ||
6812 (0 != frame_len) ||
6813 (NULL != frame) )
6814 {
6815 fprintf (stderr,
6816 "Encode binary test failed in line %u\n",
6817 (unsigned int) __LINE__);
6818 ++failed;
6819 }
6820 /* Fail test: `frame_len` not passed */
6821 frame = (char*) (uintptr_t) 0xBAADF00D;
6822 ret = MHD_websocket_encode_binary (wss,
6823 "abc",
6824 3,
6825 MHD_WEBSOCKET_FRAGMENTATION_NONE,
6826 &frame,
6827 NULL);
6828 if ((MHD_WEBSOCKET_STATUS_PARAMETER_ERROR != ret) ||
6829 (NULL != frame) )
6830 {
6831 fprintf (stderr,
6832 "Encode binary test failed in line %u\n",
6833 (unsigned int) __LINE__);
6834 ++failed;
6835 }
6836 if (((char*) (uintptr_t) 0xBAADF00D) == frame)
6837 {
6838 frame = NULL;
6839 }
6840 if (NULL != frame)
6841 {
6842 MHD_websocket_free (wss, frame);
6843 frame = NULL;
6844 }
6845 /* Fail test: `fragmentation` has an invalid value */
6846 frame = (char*) (uintptr_t) 0xBAADF00D;
6847 frame_len = 0x87654321;
6848 ret = MHD_websocket_encode_binary (wss,
6849 "abc",
6850 3,
6851 MHD_WEBSOCKET_FRAGMENTATION_LAST + 1,
6852 &frame,
6853 &frame_len);
6854 if ((MHD_WEBSOCKET_STATUS_PARAMETER_ERROR != ret) ||
6855 (0 != frame_len) ||
6856 (NULL != frame) )
6857 {
6858 fprintf (stderr,
6859 "Encode binary test failed in line %u\n",
6860 (unsigned int) __LINE__);
6861 ++failed;
6862 }
6863 if (((char*) (uintptr_t) 0xBAADF00D) == frame)
6864 {
6865 frame = NULL;
6866 }
6867 if (NULL != frame)
6868 {
6869 MHD_websocket_free (wss, frame);
6870 frame = NULL;
6871 }
6872
6873 /*
6874 ------------------------------------------------------------------------------
6875 validity after temporary out-of-memory
6876 ------------------------------------------------------------------------------
6877 */
6878 {
6879 struct MHD_WebSocketStream*wsx;
6880 if (MHD_WEBSOCKET_STATUS_OK == MHD_websocket_stream_init2 (&wsx,
6881 MHD_WEBSOCKET_FLAG_SERVER,
6882 0,
6883 test_malloc,
6884 test_realloc,
6885 test_free))
6886 {
6887 /* Fail test: allocation while no memory available */
6888 disable_alloc = 1;
6889 ret = MHD_websocket_encode_binary (wsx,
6890 "abc",
6891 3,
6892 MHD_WEBSOCKET_FRAGMENTATION_NONE,
6893 &frame,
6894 &frame_len);
6895 if ((MHD_WEBSOCKET_STATUS_MEMORY_ERROR != ret) ||
6896 (0 != frame_len) ||
6897 (NULL != frame) )
6898 {
6899 fprintf (stderr,
6900 "Encode binary test failed in line %u\n",
6901 (unsigned int) __LINE__);
6902 ++failed;
6903 }
6904 if (NULL != frame)
6905 {
6906 MHD_websocket_free (wsx, frame);
6907 frame = NULL;
6908 }
6909 /* Regular test: allocation while memory is available again */
6910 disable_alloc = 0;
6911 ret = MHD_websocket_encode_binary (wsx,
6912 "abc",
6913 3,
6914 MHD_WEBSOCKET_FRAGMENTATION_NONE,
6915 &frame,
6916 &frame_len);
6917 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
6918 (5 != frame_len) ||
6919 (NULL == frame) ||
6920 (0 != memcmp (frame, "\x82\x03" "abc", 5)))
6921 {
6922 fprintf (stderr,
6923 "Encode binary test failed in line %u\n",
6924 (unsigned int) __LINE__);
6925 ++failed;
6926 }
6927 if (NULL != frame)
6928 {
6929 MHD_websocket_free (wsx, frame);
6930 frame = NULL;
6931 }
6932
6933 MHD_websocket_stream_free (wsx);
6934 }
6935 else
6936 {
6937 fprintf (stderr,
6938 "Couldn't perform memory test for binary encoding in line %u\n",
6939 (unsigned int) __LINE__);
6940 ++failed;
6941 }
6942 }
6943
6944 if (NULL != buf1)
6945 free (buf1);
6946 if (NULL != buf2)
6947 free (buf2);
6948 if (NULL != wsc)
6949 MHD_websocket_stream_free (wsc);
6950 if (NULL != wss)
6951 MHD_websocket_stream_free (wss);
6952
6953 return failed != 0 ? 0x10 : 0x00;
6954}
6955
6956
6957/**
6958 * Test procedure for `MHD_websocket_encode_close()`
6959 */
6960int
6961test_encodes_close ()
6962{
6963 int failed = 0;
6964 struct MHD_WebSocketStream*wss;
6965 struct MHD_WebSocketStream*wsc;
6966 int ret;
6967 char *buf1 = NULL, *buf2 = NULL;
6968 char*frame = NULL;
6969 size_t frame_len = 0;
6970
6971 if (MHD_WEBSOCKET_STATUS_OK != MHD_websocket_stream_init (&wsc,
6972 MHD_WEBSOCKET_FLAG_CLIENT,
6973 0))
6974 {
6975 fprintf (stderr,
6976 "No encode close tests possible due to failed stream init in line %u\n",
6977 (unsigned int) __LINE__);
6978 return 0x10;
6979 }
6980 if (MHD_WEBSOCKET_STATUS_OK != MHD_websocket_stream_init (&wss,
6981 MHD_WEBSOCKET_FLAG_SERVER,
6982 0))
6983 {
6984 fprintf (stderr,
6985 "No encode close tests possible due to failed stream init in line %u\n",
6986 (unsigned int) __LINE__);
6987 if (NULL != wsc)
6988 MHD_websocket_stream_free (wsc);
6989 return 0x10;
6990 }
6991
6992 /*
6993 ------------------------------------------------------------------------------
6994 Encoding
6995 ------------------------------------------------------------------------------
6996 */
6997 /* Regular test: Some data, we are server */
6998 ret = MHD_websocket_encode_close (wss,
6999 MHD_WEBSOCKET_CLOSEREASON_REGULAR,
7000 "blablabla",
7001 9,
7002 &frame,
7003 &frame_len);
7004 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
7005 (13 != frame_len) ||
7006 (NULL == frame) ||
7007 (0 != memcmp (frame, "\x88\x0B\x03\xE8" "blablabla", 13)))
7008 {
7009 fprintf (stderr,
7010 "Encode close test failed in line %u\n",
7011 (unsigned int) __LINE__);
7012 ++failed;
7013 }
7014 if (NULL != frame)
7015 {
7016 MHD_websocket_free (wss, frame);
7017 frame = NULL;
7018 }
7019 /* Regular test: Some data, we are client */
7020 ret = MHD_websocket_encode_close (wsc,
7021 MHD_WEBSOCKET_CLOSEREASON_REGULAR,
7022 "blablabla",
7023 9,
7024 &frame,
7025 &frame_len);
7026 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
7027 (17 != frame_len) ||
7028 (NULL == frame) )
7029 {
7030 fprintf (stderr,
7031 "Encode close test failed in line %u\n",
7032 (unsigned int) __LINE__);
7033 ++failed;
7034 }
7035 else
7036 {
7037 failed += test_decode_single (__LINE__,
7038 MHD_WEBSOCKET_FLAG_SERVER
7039 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
7040 0,
7041 1,
7042 0,
7043 frame,
7044 frame_len,
7045 "\x03\xE8" "blablabla",
7046 11,
7047 MHD_WEBSOCKET_STATUS_CLOSE_FRAME,
7048 MHD_WEBSOCKET_VALIDITY_ONLY_VALID_FOR_CONTROL_FRAMES,
7049 frame_len);
7050 }
7051 if (NULL != frame)
7052 {
7053 MHD_websocket_free (wsc, frame);
7054 frame = NULL;
7055 }
7056 /* Regular test: Close reason without text, we are server */
7057 ret = MHD_websocket_encode_close (wss,
7058 MHD_WEBSOCKET_CLOSEREASON_REGULAR,
7059 NULL,
7060 0,
7061 &frame,
7062 &frame_len);
7063 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
7064 (4 != frame_len) ||
7065 (NULL == frame) ||
7066 (0 != memcmp (frame, "\x88\x02\x03\xE8", 4)))
7067 {
7068 fprintf (stderr,
7069 "Encode close test failed in line %u\n",
7070 (unsigned int) __LINE__);
7071 ++failed;
7072 }
7073 if (NULL != frame)
7074 {
7075 MHD_websocket_free (wss, frame);
7076 frame = NULL;
7077 }
7078 /* Regular test: Close reason without text, we are client */
7079 ret = MHD_websocket_encode_close (wsc,
7080 MHD_WEBSOCKET_CLOSEREASON_REGULAR,
7081 NULL,
7082 0,
7083 &frame,
7084 &frame_len);
7085 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
7086 (8 != frame_len) ||
7087 (NULL == frame) )
7088 {
7089 fprintf (stderr,
7090 "Encode close test failed in line %u\n",
7091 (unsigned int) __LINE__);
7092 ++failed;
7093 }
7094 else
7095 {
7096 failed += test_decode_single (__LINE__,
7097 MHD_WEBSOCKET_FLAG_SERVER
7098 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
7099 0,
7100 1,
7101 0,
7102 frame,
7103 frame_len,
7104 "\x03\xE8",
7105 2,
7106 MHD_WEBSOCKET_STATUS_CLOSE_FRAME,
7107 MHD_WEBSOCKET_VALIDITY_ONLY_VALID_FOR_CONTROL_FRAMES,
7108 frame_len);
7109 }
7110 if (NULL != frame)
7111 {
7112 MHD_websocket_free (wsc, frame);
7113 frame = NULL;
7114 }
7115 /* Regular test: Close without reason, we are server */
7116 ret = MHD_websocket_encode_close (wss,
7117 MHD_WEBSOCKET_CLOSEREASON_NO_REASON,
7118 NULL,
7119 0,
7120 &frame,
7121 &frame_len);
7122 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
7123 (2 != frame_len) ||
7124 (NULL == frame) ||
7125 (0 != memcmp (frame, "\x88\x00", 2)))
7126 {
7127 fprintf (stderr,
7128 "Encode close test failed in line %u\n",
7129 (unsigned int) __LINE__);
7130 ++failed;
7131 }
7132 if (NULL != frame)
7133 {
7134 MHD_websocket_free (wss, frame);
7135 frame = NULL;
7136 }
7137 /* Regular test: Close without reason, we are client */
7138 ret = MHD_websocket_encode_close (wsc,
7139 MHD_WEBSOCKET_CLOSEREASON_NO_REASON,
7140 NULL,
7141 0,
7142 &frame,
7143 &frame_len);
7144 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
7145 (6 != frame_len) ||
7146 (NULL == frame) )
7147 {
7148 fprintf (stderr,
7149 "Encode close test failed in line %u\n",
7150 (unsigned int) __LINE__);
7151 ++failed;
7152 }
7153 else
7154 {
7155 failed += test_decode_single (__LINE__,
7156 MHD_WEBSOCKET_FLAG_SERVER
7157 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
7158 0,
7159 1,
7160 0,
7161 frame,
7162 frame_len,
7163 NULL,
7164 0,
7165 MHD_WEBSOCKET_STATUS_CLOSE_FRAME,
7166 MHD_WEBSOCKET_VALIDITY_ONLY_VALID_FOR_CONTROL_FRAMES,
7167 frame_len);
7168 }
7169 if (NULL != frame)
7170 {
7171 MHD_websocket_free (wsc, frame);
7172 frame = NULL;
7173 }
7174 /* Regular test: Close with UTF-8 sequence in reason, we are client */
7175 ret = MHD_websocket_encode_close (wsc,
7176 MHD_WEBSOCKET_CLOSEREASON_REGULAR,
7177 "bla" "\xC3\xA4" "blabla",
7178 11,
7179 &frame,
7180 &frame_len);
7181 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
7182 (19 != frame_len) ||
7183 (NULL == frame) )
7184 {
7185 fprintf (stderr,
7186 "Encode close test failed in line %u\n",
7187 (unsigned int) __LINE__);
7188 ++failed;
7189 }
7190 else
7191 {
7192 failed += test_decode_single (__LINE__,
7193 MHD_WEBSOCKET_FLAG_SERVER
7194 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
7195 0,
7196 1,
7197 0,
7198 frame,
7199 frame_len,
7200 "\x03\xE8" "bla" "\xC3\xA4" "blabla",
7201 13,
7202 MHD_WEBSOCKET_STATUS_CLOSE_FRAME,
7203 MHD_WEBSOCKET_VALIDITY_ONLY_VALID_FOR_CONTROL_FRAMES,
7204 frame_len);
7205 }
7206 if (NULL != frame)
7207 {
7208 MHD_websocket_free (wsc, frame);
7209 frame = NULL;
7210 }
7211 /* Edge test (success): Close reason with NUL characters, we are server */
7212 ret = MHD_websocket_encode_close (wss,
7213 MHD_WEBSOCKET_CLOSEREASON_GOING_AWAY,
7214 "bla" "\0\0\0" "bla",
7215 9,
7216 &frame,
7217 &frame_len);
7218 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
7219 (13 != frame_len) ||
7220 (NULL == frame) ||
7221 (0 != memcmp (frame, "\x88\x0B\x03\xE9" "bla" "\0\0\0" "bla", 13)))
7222 {
7223 fprintf (stderr,
7224 "Encode close test failed in line %u\n",
7225 (unsigned int) __LINE__);
7226 ++failed;
7227 }
7228 if (NULL != frame)
7229 {
7230 MHD_websocket_free (wss, frame);
7231 frame = NULL;
7232 }
7233 /* Fail test: Some data with broken UTF-8, we are server */
7234 ret = MHD_websocket_encode_close (wss,
7235 MHD_WEBSOCKET_CLOSEREASON_REGULAR,
7236 "bla" "\xC3" "blabla",
7237 10,
7238 &frame,
7239 &frame_len);
7240 if ((MHD_WEBSOCKET_STATUS_UTF8_ENCODING_ERROR != ret) ||
7241 (0 != frame_len) ||
7242 (NULL != frame) )
7243 {
7244 fprintf (stderr,
7245 "Encode close test failed in line %u\n",
7246 (unsigned int) __LINE__);
7247 ++failed;
7248 }
7249 if (NULL != frame)
7250 {
7251 MHD_websocket_free (wss, frame);
7252 frame = NULL;
7253 }
7254
7255 /*
7256 ------------------------------------------------------------------------------
7257 Length checks
7258 ------------------------------------------------------------------------------
7259 */
7260 /* Edge test (success): Close frame without payload */
7261 ret = MHD_websocket_encode_close (wss,
7262 MHD_WEBSOCKET_CLOSEREASON_NO_REASON,
7263 NULL,
7264 0,
7265 &frame,
7266 &frame_len);
7267 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
7268 (2 != frame_len) ||
7269 (NULL == frame) ||
7270 (0 != memcmp (frame, "\x88\x00", 2)))
7271 {
7272 fprintf (stderr,
7273 "Encode close test failed in line %u\n",
7274 (unsigned int) __LINE__);
7275 ++failed;
7276 }
7277 if (NULL != frame)
7278 {
7279 MHD_websocket_free (wss, frame);
7280 frame = NULL;
7281 }
7282 /* Edge test (success): Close frame only reason code */
7283 ret = MHD_websocket_encode_close (wss,
7284 MHD_WEBSOCKET_CLOSEREASON_REGULAR,
7285 NULL,
7286 0,
7287 &frame,
7288 &frame_len);
7289 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
7290 (4 != frame_len) ||
7291 (NULL == frame) ||
7292 (0 != memcmp (frame, "\x88\x02\x03\xE8", 4)))
7293 {
7294 fprintf (stderr,
7295 "Encode close test failed in line %u\n",
7296 (unsigned int) __LINE__);
7297 ++failed;
7298 }
7299 if (NULL != frame)
7300 {
7301 MHD_websocket_free (wss, frame);
7302 frame = NULL;
7303 }
7304 /* Edge test (success): Close frame with 1 bytes of reason text */
7305 ret = MHD_websocket_encode_close (wss,
7306 MHD_WEBSOCKET_CLOSEREASON_REGULAR,
7307 "a",
7308 1,
7309 &frame,
7310 &frame_len);
7311 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
7312 (5 != frame_len) ||
7313 (NULL == frame) ||
7314 (0 != memcmp (frame, "\x88\x03\x03\xE8" "a", 5)))
7315 {
7316 fprintf (stderr,
7317 "Encode close test failed in line %u\n",
7318 (unsigned int) __LINE__);
7319 ++failed;
7320 }
7321 if (NULL != frame)
7322 {
7323 MHD_websocket_free (wss, frame);
7324 frame = NULL;
7325 }
7326 /* Edge test (success): Close frame with 123 bytes of reason text */
7327 ret = MHD_websocket_encode_close (wss,
7328 MHD_WEBSOCKET_CLOSEREASON_REGULAR,
7329 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456",
7330 123,
7331 &frame,
7332 &frame_len);
7333 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
7334 (127 != frame_len) ||
7335 (NULL == frame) ||
7336 (0 != memcmp (frame, "\x88\x7D\x03\xE8"
7337 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456",
7338 127)))
7339 {
7340 fprintf (stderr,
7341 "Encode close test failed in line %u\n",
7342 (unsigned int) __LINE__);
7343 ++failed;
7344 }
7345 if (NULL != frame)
7346 {
7347 MHD_websocket_free (wss, frame);
7348 frame = NULL;
7349 }
7350 /* Edge test (fail): Close frame with 124 bytes of reason text*/
7351 ret = MHD_websocket_encode_close (wss,
7352 MHD_WEBSOCKET_CLOSEREASON_REGULAR,
7353 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567",
7354 124,
7355 &frame,
7356 &frame_len);
7357 if ((MHD_WEBSOCKET_STATUS_MAXIMUM_SIZE_EXCEEDED != ret) ||
7358 (0 != frame_len) ||
7359 (NULL != frame) )
7360 {
7361 fprintf (stderr,
7362 "Encode close test failed in line %u\n",
7363 (unsigned int) __LINE__);
7364 ++failed;
7365 }
7366 if (NULL != frame)
7367 {
7368 MHD_websocket_free (wss, frame);
7369 frame = NULL;
7370 }
7371
7372 /*
7373 ------------------------------------------------------------------------------
7374 Wrong parameters
7375 ------------------------------------------------------------------------------
7376 */
7377 /* Fail test: `ws` not passed */
7378 frame = (char*) (uintptr_t) 0xBAADF00D;
7379 frame_len = 0x87654321;
7380 ret = MHD_websocket_encode_close (NULL,
7381 MHD_WEBSOCKET_CLOSEREASON_REGULAR,
7382 "abc",
7383 3,
7384 &frame,
7385 &frame_len);
7386 if ((MHD_WEBSOCKET_STATUS_PARAMETER_ERROR != ret) ||
7387 (0 != frame_len) ||
7388 (NULL != frame) )
7389 {
7390 fprintf (stderr,
7391 "Encode close test failed in line %u\n",
7392 (unsigned int) __LINE__);
7393 ++failed;
7394 }
7395 if (((char*) (uintptr_t) 0xBAADF00D) == frame)
7396 {
7397 frame = NULL;
7398 }
7399 if (NULL != frame)
7400 {
7401 MHD_websocket_free (wss, frame);
7402 frame = NULL;
7403 }
7404 /* Fail test: `payload` not passed, but `payload_len` != 0 */
7405 frame = (char*) (uintptr_t) 0xBAADF00D;
7406 frame_len = 0x87654321;
7407 ret = MHD_websocket_encode_close (wss,
7408 MHD_WEBSOCKET_CLOSEREASON_REGULAR,
7409 NULL,
7410 3,
7411 &frame,
7412 &frame_len);
7413 if ((MHD_WEBSOCKET_STATUS_PARAMETER_ERROR != ret) ||
7414 (0 != frame_len) ||
7415 (NULL != frame) )
7416 {
7417 fprintf (stderr,
7418 "Encode close test failed in line %u\n",
7419 (unsigned int) __LINE__);
7420 ++failed;
7421 }
7422 if (((char*) (uintptr_t) 0xBAADF00D) == frame)
7423 {
7424 frame = NULL;
7425 }
7426 if (NULL != frame)
7427 {
7428 MHD_websocket_free (wss, frame);
7429 frame = NULL;
7430 }
7431 /* Regular test: `payload` passed, but `payload_len` == 0 */
7432 frame = (char*) (uintptr_t) 0xBAADF00D;
7433 frame_len = 0x87654321;
7434 ret = MHD_websocket_encode_close (wss,
7435 MHD_WEBSOCKET_CLOSEREASON_REGULAR,
7436 "abc",
7437 0,
7438 &frame,
7439 &frame_len);
7440 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
7441 (4 != frame_len) ||
7442 (NULL == frame) ||
7443 (((char*) (uintptr_t) 0xBAADF00D) == frame) ||
7444 (0 != memcmp (frame, "\x88\x02\x03\xE8", 4)))
7445 {
7446 fprintf (stderr,
7447 "Encode close test failed in line %u\n",
7448 (unsigned int) __LINE__);
7449 ++failed;
7450 }
7451 if (((char*) (uintptr_t) 0xBAADF00D) == frame)
7452 {
7453 frame = NULL;
7454 }
7455 if (NULL != frame)
7456 {
7457 MHD_websocket_free (wss, frame);
7458 frame = NULL;
7459 }
7460 /* Fail test: `frame` not passed */
7461 frame_len = 0x87654321;
7462 ret = MHD_websocket_encode_close (wss,
7463 MHD_WEBSOCKET_CLOSEREASON_REGULAR,
7464 "abc",
7465 3,
7466 NULL,
7467 &frame_len);
7468 if ((MHD_WEBSOCKET_STATUS_PARAMETER_ERROR != ret) ||
7469 (0 != frame_len) ||
7470 (NULL != frame) )
7471 {
7472 fprintf (stderr,
7473 "Encode close test failed in line %u\n",
7474 (unsigned int) __LINE__);
7475 ++failed;
7476 }
7477 /* Fail test: `frame_len` not passed */
7478 frame = (char*) (uintptr_t) 0xBAADF00D;
7479 ret = MHD_websocket_encode_close (wss,
7480 MHD_WEBSOCKET_CLOSEREASON_REGULAR,
7481 "abc",
7482 3,
7483 &frame,
7484 NULL);
7485 if ((MHD_WEBSOCKET_STATUS_PARAMETER_ERROR != ret) ||
7486 (0 != frame_len) ||
7487 (NULL != frame) )
7488 {
7489 fprintf (stderr,
7490 "Encode close test failed in line %u\n",
7491 (unsigned int) __LINE__);
7492 ++failed;
7493 }
7494 if (((char*) (uintptr_t) 0xBAADF00D) == frame)
7495 {
7496 frame = NULL;
7497 }
7498 if (NULL != frame)
7499 {
7500 MHD_websocket_free (wss, frame);
7501 frame = NULL;
7502 }
7503 /* Fail test: no reason code passed, but reason text */
7504 frame = (char*) (uintptr_t) 0xBAADF00D;
7505 frame_len = 0x87654321;
7506 ret = MHD_websocket_encode_close (wss,
7507 MHD_WEBSOCKET_CLOSEREASON_NO_REASON,
7508 "abc",
7509 3,
7510 &frame,
7511 &frame_len);
7512 if ((MHD_WEBSOCKET_STATUS_PARAMETER_ERROR != ret) ||
7513 (0 != frame_len) ||
7514 (NULL != frame) )
7515 {
7516 fprintf (stderr,
7517 "Encode close test failed in line %u\n",
7518 (unsigned int) __LINE__);
7519 ++failed;
7520 }
7521 if (((char*) (uintptr_t) 0xBAADF00D) == frame)
7522 {
7523 frame = NULL;
7524 }
7525 if (NULL != frame)
7526 {
7527 MHD_websocket_free (wss, frame);
7528 frame = NULL;
7529 }
7530 /* Edge test (fail): Invalid reason code */
7531 frame = (char*) (uintptr_t) 0xBAADF00D;
7532 frame_len = 0x87654321;
7533 ret = MHD_websocket_encode_close (wss,
7534 1,
7535 "abc",
7536 3,
7537 &frame,
7538 &frame_len);
7539 if ((MHD_WEBSOCKET_STATUS_PARAMETER_ERROR != ret) ||
7540 (0 != frame_len) ||
7541 (NULL != frame) )
7542 {
7543 fprintf (stderr,
7544 "Encode close test failed in line %u\n",
7545 (unsigned int) __LINE__);
7546 ++failed;
7547 }
7548 if (((char*) (uintptr_t) 0xBAADF00D) == frame)
7549 {
7550 frame = NULL;
7551 }
7552 if (NULL != frame)
7553 {
7554 MHD_websocket_free (wss, frame);
7555 frame = NULL;
7556 }
7557 /* Edge test (fail): Invalid reason code */
7558 frame = (char*) (uintptr_t) 0xBAADF00D;
7559 frame_len = 0x87654321;
7560 ret = MHD_websocket_encode_close (wss,
7561 999,
7562 "abc",
7563 3,
7564 &frame,
7565 &frame_len);
7566 if ((MHD_WEBSOCKET_STATUS_PARAMETER_ERROR != ret) ||
7567 (0 != frame_len) ||
7568 (NULL != frame) )
7569 {
7570 fprintf (stderr,
7571 "Encode close test failed in line %u\n",
7572 (unsigned int) __LINE__);
7573 ++failed;
7574 }
7575 if (((char*) (uintptr_t) 0xBAADF00D) == frame)
7576 {
7577 frame = NULL;
7578 }
7579 if (NULL != frame)
7580 {
7581 MHD_websocket_free (wss, frame);
7582 frame = NULL;
7583 }
7584 /* Regular test: Custom reason code */
7585 frame = (char*) (uintptr_t) 0xBAADF00D;
7586 frame_len = 0x87654321;
7587 ret = MHD_websocket_encode_close (wss,
7588 2000,
7589 "abc",
7590 3,
7591 &frame,
7592 &frame_len);
7593 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
7594 (7 != frame_len) ||
7595 (NULL == frame) ||
7596 (((char*) (uintptr_t) 0xBAADF00D) == frame) ||
7597 (0 != memcmp (frame, "\x88\x05\x07\xD0" "abc", 7)))
7598 {
7599 fprintf (stderr,
7600 "Encode close test failed in line %u\n",
7601 (unsigned int) __LINE__);
7602 ++failed;
7603 }
7604 if (((char*) (uintptr_t) 0xBAADF00D) == frame)
7605 {
7606 frame = NULL;
7607 }
7608 if (NULL != frame)
7609 {
7610 MHD_websocket_free (wss, frame);
7611 frame = NULL;
7612 }
7613
7614 /*
7615 ------------------------------------------------------------------------------
7616 validity after temporary out-of-memory
7617 ------------------------------------------------------------------------------
7618 */
7619 {
7620 struct MHD_WebSocketStream*wsx;
7621 if (MHD_WEBSOCKET_STATUS_OK == MHD_websocket_stream_init2 (&wsx,
7622 MHD_WEBSOCKET_FLAG_SERVER,
7623 0,
7624 test_malloc,
7625 test_realloc,
7626 test_free))
7627 {
7628 /* Fail test: allocation while no memory available */
7629 disable_alloc = 1;
7630 ret = MHD_websocket_encode_close (wsx,
7631 MHD_WEBSOCKET_CLOSEREASON_REGULAR,
7632 "abc",
7633 3,
7634 &frame,
7635 &frame_len);
7636 if ((MHD_WEBSOCKET_STATUS_MEMORY_ERROR != ret) ||
7637 (0 != frame_len) ||
7638 (NULL != frame) )
7639 {
7640 fprintf (stderr,
7641 "Encode close test failed in line %u\n",
7642 (unsigned int) __LINE__);
7643 ++failed;
7644 }
7645 if (NULL != frame)
7646 {
7647 MHD_websocket_free (wsx, frame);
7648 frame = NULL;
7649 }
7650 /* Regular test: allocation while memory is available again */
7651 disable_alloc = 0;
7652 ret = MHD_websocket_encode_close (wsx,
7653 MHD_WEBSOCKET_CLOSEREASON_REGULAR,
7654 "abc",
7655 3,
7656 &frame,
7657 &frame_len);
7658 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
7659 (7 != frame_len) ||
7660 (NULL == frame) ||
7661 (0 != memcmp (frame, "\x88\x05\x03\xE8" "abc", 7)))
7662 {
7663 fprintf (stderr,
7664 "Encode close test failed in line %u\n",
7665 (unsigned int) __LINE__);
7666 ++failed;
7667 }
7668 if (NULL != frame)
7669 {
7670 MHD_websocket_free (wsx, frame);
7671 frame = NULL;
7672 }
7673
7674 MHD_websocket_stream_free (wsx);
7675 }
7676 else
7677 {
7678 fprintf (stderr,
7679 "Couldn't perform memory test for close encoding in line %u\n",
7680 (unsigned int) __LINE__);
7681 ++failed;
7682 }
7683 }
7684
7685 if (NULL != buf1)
7686 free (buf1);
7687 if (NULL != buf2)
7688 free (buf2);
7689 if (NULL != wsc)
7690 MHD_websocket_stream_free (wsc);
7691 if (NULL != wss)
7692 MHD_websocket_stream_free (wss);
7693
7694 return failed != 0 ? 0x20 : 0x00;
7695}
7696
7697
7698/**
7699 * Test procedure for `MHD_websocket_encode_ping()`
7700 */
7701int
7702test_encodes_ping ()
7703{
7704 int failed = 0;
7705 struct MHD_WebSocketStream*wss;
7706 struct MHD_WebSocketStream*wsc;
7707 int ret;
7708 char *buf1 = NULL, *buf2 = NULL;
7709 char*frame = NULL;
7710 size_t frame_len = 0;
7711
7712 if (MHD_WEBSOCKET_STATUS_OK != MHD_websocket_stream_init (&wsc,
7713 MHD_WEBSOCKET_FLAG_CLIENT,
7714 0))
7715 {
7716 fprintf (stderr,
7717 "No encode ping tests possible due to failed stream init in line %u\n",
7718 (unsigned int) __LINE__);
7719 return 0x10;
7720 }
7721 if (MHD_WEBSOCKET_STATUS_OK != MHD_websocket_stream_init (&wss,
7722 MHD_WEBSOCKET_FLAG_SERVER,
7723 0))
7724 {
7725 fprintf (stderr,
7726 "No encode ping tests possible due to failed stream init in line %u\n",
7727 (unsigned int) __LINE__);
7728 if (NULL != wsc)
7729 MHD_websocket_stream_free (wsc);
7730 return 0x10;
7731 }
7732
7733 /*
7734 ------------------------------------------------------------------------------
7735 Encoding
7736 ------------------------------------------------------------------------------
7737 */
7738 /* Regular test: Some data, we are server */
7739 ret = MHD_websocket_encode_ping (wss,
7740 "blablabla",
7741 9,
7742 &frame,
7743 &frame_len);
7744 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
7745 (11 != frame_len) ||
7746 (NULL == frame) ||
7747 (0 != memcmp (frame, "\x89\x09" "blablabla", 11)))
7748 {
7749 fprintf (stderr,
7750 "Encode ping test failed in line %u\n",
7751 (unsigned int) __LINE__);
7752 ++failed;
7753 }
7754 if (NULL != frame)
7755 {
7756 MHD_websocket_free (wss, frame);
7757 frame = NULL;
7758 }
7759 /* Regular test: Some data, we are client */
7760 ret = MHD_websocket_encode_ping (wsc,
7761 "blablabla",
7762 9,
7763 &frame,
7764 &frame_len);
7765 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
7766 (15 != frame_len) ||
7767 (NULL == frame) )
7768 {
7769 fprintf (stderr,
7770 "Encode ping test failed in line %u\n",
7771 (unsigned int) __LINE__);
7772 ++failed;
7773 }
7774 else
7775 {
7776 failed += test_decode_single (__LINE__,
7777 MHD_WEBSOCKET_FLAG_SERVER
7778 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
7779 0,
7780 1,
7781 0,
7782 frame,
7783 frame_len,
7784 "blablabla",
7785 9,
7786 MHD_WEBSOCKET_STATUS_PING_FRAME,
7787 MHD_WEBSOCKET_VALIDITY_VALID,
7788 frame_len);
7789 }
7790 if (NULL != frame)
7791 {
7792 MHD_websocket_free (wsc, frame);
7793 frame = NULL;
7794 }
7795 /* Regular test: Ping without payload, we are server */
7796 ret = MHD_websocket_encode_ping (wss,
7797 NULL,
7798 0,
7799 &frame,
7800 &frame_len);
7801 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
7802 (2 != frame_len) ||
7803 (NULL == frame) ||
7804 (0 != memcmp (frame, "\x89\x00", 2)))
7805 {
7806 fprintf (stderr,
7807 "Encode ping test failed in line %u\n",
7808 (unsigned int) __LINE__);
7809 ++failed;
7810 }
7811 if (NULL != frame)
7812 {
7813 MHD_websocket_free (wss, frame);
7814 frame = NULL;
7815 }
7816 /* Regular test: Ping without payload, we are client */
7817 ret = MHD_websocket_encode_ping (wsc,
7818 NULL,
7819 0,
7820 &frame,
7821 &frame_len);
7822 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
7823 (6 != frame_len) ||
7824 (NULL == frame) )
7825 {
7826 fprintf (stderr,
7827 "Encode ping test failed in line %u\n",
7828 (unsigned int) __LINE__);
7829 ++failed;
7830 }
7831 else
7832 {
7833 failed += test_decode_single (__LINE__,
7834 MHD_WEBSOCKET_FLAG_SERVER
7835 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
7836 0,
7837 1,
7838 0,
7839 frame,
7840 frame_len,
7841 NULL,
7842 0,
7843 MHD_WEBSOCKET_STATUS_PING_FRAME,
7844 MHD_WEBSOCKET_VALIDITY_VALID,
7845 frame_len);
7846 }
7847 if (NULL != frame)
7848 {
7849 MHD_websocket_free (wsc, frame);
7850 frame = NULL;
7851 }
7852 /* Regular test: Ping with something like UTF-8 sequence in payload, we are client */
7853 ret = MHD_websocket_encode_ping (wsc,
7854 "bla" "\xC3\xA4" "blabla",
7855 11,
7856 &frame,
7857 &frame_len);
7858 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
7859 (17 != frame_len) ||
7860 (NULL == frame) )
7861 {
7862 fprintf (stderr,
7863 "Encode ping test failed in line %u\n",
7864 (unsigned int) __LINE__);
7865 ++failed;
7866 }
7867 else
7868 {
7869 failed += test_decode_single (__LINE__,
7870 MHD_WEBSOCKET_FLAG_SERVER
7871 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
7872 0,
7873 1,
7874 0,
7875 frame,
7876 frame_len,
7877 "bla" "\xC3\xA4" "blabla",
7878 11,
7879 MHD_WEBSOCKET_STATUS_PING_FRAME,
7880 MHD_WEBSOCKET_VALIDITY_VALID,
7881 frame_len);
7882 }
7883 if (NULL != frame)
7884 {
7885 MHD_websocket_free (wsc, frame);
7886 frame = NULL;
7887 }
7888 /* Edge test (success): Ping payload with NUL characters, we are server */
7889 ret = MHD_websocket_encode_ping (wss,
7890 "bla" "\0\0\0" "bla",
7891 9,
7892 &frame,
7893 &frame_len);
7894 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
7895 (11 != frame_len) ||
7896 (NULL == frame) ||
7897 (0 != memcmp (frame, "\x89\x09" "bla" "\0\0\0" "bla", 11)))
7898 {
7899 fprintf (stderr,
7900 "Encode ping test failed in line %u\n",
7901 (unsigned int) __LINE__);
7902 ++failed;
7903 }
7904 if (NULL != frame)
7905 {
7906 MHD_websocket_free (wss, frame);
7907 frame = NULL;
7908 }
7909 /* Regular test: Ping payload with with something which looks like broken UTF-8, we are server */
7910 ret = MHD_websocket_encode_ping (wss,
7911 "bla" "\xC3" "blabla",
7912 10,
7913 &frame,
7914 &frame_len);
7915 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
7916 (12 != frame_len) ||
7917 (NULL == frame) ||
7918 (0 != memcmp (frame, "\x89\x0A" "bla" "\xC3" "blabla", 12)))
7919 {
7920 fprintf (stderr,
7921 "Encode ping test failed in line %u\n",
7922 (unsigned int) __LINE__);
7923 ++failed;
7924 }
7925 if (NULL != frame)
7926 {
7927 MHD_websocket_free (wss, frame);
7928 frame = NULL;
7929 }
7930
7931 /*
7932 ------------------------------------------------------------------------------
7933 Length checks
7934 ------------------------------------------------------------------------------
7935 */
7936 /* Edge test (success): Ping frame without payload */
7937 ret = MHD_websocket_encode_ping (wss,
7938 NULL,
7939 0,
7940 &frame,
7941 &frame_len);
7942 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
7943 (2 != frame_len) ||
7944 (NULL == frame) ||
7945 (0 != memcmp (frame, "\x89\x00", 2)))
7946 {
7947 fprintf (stderr,
7948 "Encode ping test failed in line %u\n",
7949 (unsigned int) __LINE__);
7950 ++failed;
7951 }
7952 if (NULL != frame)
7953 {
7954 MHD_websocket_free (wss, frame);
7955 frame = NULL;
7956 }
7957 /* Edge test (success): Ping frame with one byte of payload */
7958 ret = MHD_websocket_encode_ping (wss,
7959 NULL,
7960 0,
7961 &frame,
7962 &frame_len);
7963 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
7964 (2 != frame_len) ||
7965 (NULL == frame) ||
7966 (0 != memcmp (frame, "\x89\x00", 2)))
7967 {
7968 fprintf (stderr,
7969 "Encode ping test failed in line %u\n",
7970 (unsigned int) __LINE__);
7971 ++failed;
7972 }
7973 if (NULL != frame)
7974 {
7975 MHD_websocket_free (wss, frame);
7976 frame = NULL;
7977 }
7978 /* Edge test (success): Ping frame with 125 bytes of payload */
7979 ret = MHD_websocket_encode_ping (wss,
7980 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ012345678",
7981 125,
7982 &frame,
7983 &frame_len);
7984 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
7985 (127 != frame_len) ||
7986 (NULL == frame) ||
7987 (0 != memcmp (frame, "\x89\x7D"
7988 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ012345678",
7989 127)))
7990 {
7991 fprintf (stderr,
7992 "Encode ping test failed in line %u\n",
7993 (unsigned int) __LINE__);
7994 ++failed;
7995 }
7996 if (NULL != frame)
7997 {
7998 MHD_websocket_free (wss, frame);
7999 frame = NULL;
8000 }
8001 /* Edge test (fail): Ping frame with 126 bytes of payload */
8002 ret = MHD_websocket_encode_ping (wss,
8003 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789",
8004 126,
8005 &frame,
8006 &frame_len);
8007 if ((MHD_WEBSOCKET_STATUS_MAXIMUM_SIZE_EXCEEDED != ret) ||
8008 (0 != frame_len) ||
8009 (NULL != frame) )
8010 {
8011 fprintf (stderr,
8012 "Encode ping test failed in line %u\n",
8013 (unsigned int) __LINE__);
8014 ++failed;
8015 }
8016 if (NULL != frame)
8017 {
8018 MHD_websocket_free (wss, frame);
8019 frame = NULL;
8020 }
8021
8022 /*
8023 ------------------------------------------------------------------------------
8024 Wrong parameters
8025 ------------------------------------------------------------------------------
8026 */
8027 /* Fail test: `ws` not passed */
8028 frame = (char*) (uintptr_t) 0xBAADF00D;
8029 frame_len = 0x87654321;
8030 ret = MHD_websocket_encode_ping (NULL,
8031 "abc",
8032 3,
8033 &frame,
8034 &frame_len);
8035 if ((MHD_WEBSOCKET_STATUS_PARAMETER_ERROR != ret) ||
8036 (0 != frame_len) ||
8037 (NULL != frame) )
8038 {
8039 fprintf (stderr,
8040 "Encode ping test failed in line %u\n",
8041 (unsigned int) __LINE__);
8042 ++failed;
8043 }
8044 if (((char*) (uintptr_t) 0xBAADF00D) == frame)
8045 {
8046 frame = NULL;
8047 }
8048 if (NULL != frame)
8049 {
8050 MHD_websocket_free (wss, frame);
8051 frame = NULL;
8052 }
8053 /* Fail test: `payload` not passed, but `payload_len` != 0 */
8054 frame = (char*) (uintptr_t) 0xBAADF00D;
8055 frame_len = 0x87654321;
8056 ret = MHD_websocket_encode_ping (wss,
8057 NULL,
8058 3,
8059 &frame,
8060 &frame_len);
8061 if ((MHD_WEBSOCKET_STATUS_PARAMETER_ERROR != ret) ||
8062 (0 != frame_len) ||
8063 (NULL != frame) )
8064 {
8065 fprintf (stderr,
8066 "Encode ping test failed in line %u\n",
8067 (unsigned int) __LINE__);
8068 ++failed;
8069 }
8070 if (((char*) (uintptr_t) 0xBAADF00D) == frame)
8071 {
8072 frame = NULL;
8073 }
8074 if (NULL != frame)
8075 {
8076 MHD_websocket_free (wss, frame);
8077 frame = NULL;
8078 }
8079 /* Regular test: `payload` passed, but `payload_len` == 0 */
8080 frame = (char*) (uintptr_t) 0xBAADF00D;
8081 frame_len = 0x87654321;
8082 ret = MHD_websocket_encode_ping (wss,
8083 "abc",
8084 0,
8085 &frame,
8086 &frame_len);
8087 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
8088 (2 != frame_len) ||
8089 (NULL == frame) ||
8090 (((char*) (uintptr_t) 0xBAADF00D) == frame) ||
8091 (0 != memcmp (frame, "\x89\x00", 2)))
8092 {
8093 fprintf (stderr,
8094 "Encode ping test failed in line %u\n",
8095 (unsigned int) __LINE__);
8096 ++failed;
8097 }
8098 if (((char*) (uintptr_t) 0xBAADF00D) == frame)
8099 {
8100 frame = NULL;
8101 }
8102 if (NULL != frame)
8103 {
8104 MHD_websocket_free (wss, frame);
8105 frame = NULL;
8106 }
8107 /* Fail test: `frame` not passed */
8108 frame_len = 0x87654321;
8109 ret = MHD_websocket_encode_ping (wss,
8110 "abc",
8111 3,
8112 NULL,
8113 &frame_len);
8114 if ((MHD_WEBSOCKET_STATUS_PARAMETER_ERROR != ret) ||
8115 (0 != frame_len) )
8116 {
8117 fprintf (stderr,
8118 "Encode ping test failed in line %u\n",
8119 (unsigned int) __LINE__);
8120 ++failed;
8121 }
8122 /* Fail test: `frame_len` not passed */
8123 frame = (char*) (uintptr_t) 0xBAADF00D;
8124 ret = MHD_websocket_encode_ping (wss,
8125 "abc",
8126 3,
8127 &frame,
8128 NULL);
8129 if ((MHD_WEBSOCKET_STATUS_PARAMETER_ERROR != ret) ||
8130 (NULL != frame) )
8131 {
8132 fprintf (stderr,
8133 "Encode ping test failed in line %u\n",
8134 (unsigned int) __LINE__);
8135 ++failed;
8136 }
8137 if (((char*) (uintptr_t) 0xBAADF00D) == frame)
8138 {
8139 frame = NULL;
8140 }
8141 if (NULL != frame)
8142 {
8143 MHD_websocket_free (wss, frame);
8144 frame = NULL;
8145 }
8146
8147 /*
8148 ------------------------------------------------------------------------------
8149 validity after temporary out-of-memory
8150 ------------------------------------------------------------------------------
8151 */
8152 {
8153 struct MHD_WebSocketStream*wsx;
8154 if (MHD_WEBSOCKET_STATUS_OK == MHD_websocket_stream_init2 (&wsx,
8155 MHD_WEBSOCKET_FLAG_SERVER,
8156 0,
8157 test_malloc,
8158 test_realloc,
8159 test_free))
8160 {
8161 /* Fail test: allocation while no memory available */
8162 disable_alloc = 1;
8163 ret = MHD_websocket_encode_ping (wsx,
8164 "abc",
8165 3,
8166 &frame,
8167 &frame_len);
8168 if ((MHD_WEBSOCKET_STATUS_MEMORY_ERROR != ret) ||
8169 (0 != frame_len) ||
8170 (NULL != frame) )
8171 {
8172 fprintf (stderr,
8173 "Encode ping test failed in line %u\n",
8174 (unsigned int) __LINE__);
8175 ++failed;
8176 }
8177 if (NULL != frame)
8178 {
8179 MHD_websocket_free (wsx, frame);
8180 frame = NULL;
8181 }
8182 /* Regular test: allocation while memory is available again */
8183 disable_alloc = 0;
8184 ret = MHD_websocket_encode_ping (wsx,
8185 "abc",
8186 3,
8187 &frame,
8188 &frame_len);
8189 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
8190 (5 != frame_len) ||
8191 (NULL == frame) ||
8192 (0 != memcmp (frame, "\x89\x03" "abc", 5)))
8193 {
8194 fprintf (stderr,
8195 "Encode ping test failed in line %u\n",
8196 (unsigned int) __LINE__);
8197 ++failed;
8198 }
8199 if (NULL != frame)
8200 {
8201 MHD_websocket_free (wsx, frame);
8202 frame = NULL;
8203 }
8204
8205 MHD_websocket_stream_free (wsx);
8206 }
8207 else
8208 {
8209 fprintf (stderr,
8210 "Couldn't perform memory test for ping encoding in line %u\n",
8211 (unsigned int) __LINE__);
8212 ++failed;
8213 }
8214 }
8215
8216 if (NULL != buf1)
8217 free (buf1);
8218 if (NULL != buf2)
8219 free (buf2);
8220 if (NULL != wsc)
8221 MHD_websocket_stream_free (wsc);
8222 if (NULL != wss)
8223 MHD_websocket_stream_free (wss);
8224
8225 return failed != 0 ? 0x40 : 0x00;
8226}
8227
8228
8229/**
8230 * Test procedure for `MHD_websocket_encode_pong()`
8231 */
8232int
8233test_encodes_pong ()
8234{
8235 int failed = 0;
8236 struct MHD_WebSocketStream*wss;
8237 struct MHD_WebSocketStream*wsc;
8238 int ret;
8239 char *buf1 = NULL, *buf2 = NULL;
8240 char*frame = NULL;
8241 size_t frame_len = 0;
8242
8243 if (MHD_WEBSOCKET_STATUS_OK != MHD_websocket_stream_init (&wsc,
8244 MHD_WEBSOCKET_FLAG_CLIENT,
8245 0))
8246 {
8247 fprintf (stderr,
8248 "No encode pong tests possible due to failed stream init in line %u\n",
8249 (unsigned int) __LINE__);
8250 return 0x10;
8251 }
8252 if (MHD_WEBSOCKET_STATUS_OK != MHD_websocket_stream_init (&wss,
8253 MHD_WEBSOCKET_FLAG_SERVER,
8254 0))
8255 {
8256 fprintf (stderr,
8257 "No encode pong tests possible due to failed stream init in line %u\n",
8258 (unsigned int) __LINE__);
8259 if (NULL != wsc)
8260 MHD_websocket_stream_free (wsc);
8261 return 0x10;
8262 }
8263
8264 /*
8265 ------------------------------------------------------------------------------
8266 Encoding
8267 ------------------------------------------------------------------------------
8268 */
8269 /* Regular test: Some data, we are server */
8270 ret = MHD_websocket_encode_pong (wss,
8271 "blablabla",
8272 9,
8273 &frame,
8274 &frame_len);
8275 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
8276 (11 != frame_len) ||
8277 (NULL == frame) ||
8278 (0 != memcmp (frame, "\x8A\x09" "blablabla", 11)))
8279 {
8280 fprintf (stderr,
8281 "Encode pong test failed in line %u\n",
8282 (unsigned int) __LINE__);
8283 ++failed;
8284 }
8285 if (NULL != frame)
8286 {
8287 MHD_websocket_free (wss, frame);
8288 frame = NULL;
8289 }
8290 /* Regular test: Some data, we are client */
8291 ret = MHD_websocket_encode_pong (wsc,
8292 "blablabla",
8293 9,
8294 &frame,
8295 &frame_len);
8296 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
8297 (15 != frame_len) ||
8298 (NULL == frame) )
8299 {
8300 fprintf (stderr,
8301 "Encode pong test failed in line %u\n",
8302 (unsigned int) __LINE__);
8303 ++failed;
8304 }
8305 else
8306 {
8307 failed += test_decode_single (__LINE__,
8308 MHD_WEBSOCKET_FLAG_SERVER
8309 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
8310 0,
8311 1,
8312 0,
8313 frame,
8314 frame_len,
8315 "blablabla",
8316 9,
8317 MHD_WEBSOCKET_STATUS_PONG_FRAME,
8318 MHD_WEBSOCKET_VALIDITY_VALID,
8319 frame_len);
8320 }
8321 if (NULL != frame)
8322 {
8323 MHD_websocket_free (wsc, frame);
8324 frame = NULL;
8325 }
8326 /* Regular test: Pong without payload, we are server */
8327 ret = MHD_websocket_encode_pong (wss,
8328 NULL,
8329 0,
8330 &frame,
8331 &frame_len);
8332 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
8333 (2 != frame_len) ||
8334 (NULL == frame) ||
8335 (0 != memcmp (frame, "\x8A\x00", 2)))
8336 {
8337 fprintf (stderr,
8338 "Encode pong test failed in line %u\n",
8339 (unsigned int) __LINE__);
8340 ++failed;
8341 }
8342 if (NULL != frame)
8343 {
8344 MHD_websocket_free (wss, frame);
8345 frame = NULL;
8346 }
8347 /* Regular test: Pong without payload, we are client */
8348 ret = MHD_websocket_encode_pong (wsc,
8349 NULL,
8350 0,
8351 &frame,
8352 &frame_len);
8353 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
8354 (6 != frame_len) ||
8355 (NULL == frame) )
8356 {
8357 fprintf (stderr,
8358 "Encode pong test failed in line %u\n",
8359 (unsigned int) __LINE__);
8360 ++failed;
8361 }
8362 else
8363 {
8364 failed += test_decode_single (__LINE__,
8365 MHD_WEBSOCKET_FLAG_SERVER
8366 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
8367 0,
8368 1,
8369 0,
8370 frame,
8371 frame_len,
8372 NULL,
8373 0,
8374 MHD_WEBSOCKET_STATUS_PONG_FRAME,
8375 MHD_WEBSOCKET_VALIDITY_VALID,
8376 frame_len);
8377 }
8378 if (NULL != frame)
8379 {
8380 MHD_websocket_free (wsc, frame);
8381 frame = NULL;
8382 }
8383 /* Regular test: Pong with something like UTF-8 sequence in payload, we are client */
8384 ret = MHD_websocket_encode_pong (wsc,
8385 "bla" "\xC3\xA4" "blabla",
8386 11,
8387 &frame,
8388 &frame_len);
8389 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
8390 (17 != frame_len) ||
8391 (NULL == frame) )
8392 {
8393 fprintf (stderr,
8394 "Encode pong test failed in line %u\n",
8395 (unsigned int) __LINE__);
8396 ++failed;
8397 }
8398 else
8399 {
8400 failed += test_decode_single (__LINE__,
8401 MHD_WEBSOCKET_FLAG_SERVER
8402 | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS,
8403 0,
8404 1,
8405 0,
8406 frame,
8407 frame_len,
8408 "bla" "\xC3\xA4" "blabla",
8409 11,
8410 MHD_WEBSOCKET_STATUS_PONG_FRAME,
8411 MHD_WEBSOCKET_VALIDITY_VALID,
8412 frame_len);
8413 }
8414 if (NULL != frame)
8415 {
8416 MHD_websocket_free (wsc, frame);
8417 frame = NULL;
8418 }
8419 /* Edge test (success): Pong payload with NUL characters, we are server */
8420 ret = MHD_websocket_encode_pong (wss,
8421 "bla" "\0\0\0" "bla",
8422 9,
8423 &frame,
8424 &frame_len);
8425 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
8426 (11 != frame_len) ||
8427 (NULL == frame) ||
8428 (0 != memcmp (frame, "\x8A\x09" "bla" "\0\0\0" "bla", 11)))
8429 {
8430 fprintf (stderr,
8431 "Encode pong test failed in line %u\n",
8432 (unsigned int) __LINE__);
8433 ++failed;
8434 }
8435 if (NULL != frame)
8436 {
8437 MHD_websocket_free (wss, frame);
8438 frame = NULL;
8439 }
8440 /* Regular test: Pong payload with with something which looks like broken UTF-8, we are server */
8441 ret = MHD_websocket_encode_pong (wss,
8442 "bla" "\xC3" "blabla",
8443 10,
8444 &frame,
8445 &frame_len);
8446 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
8447 (12 != frame_len) ||
8448 (NULL == frame) ||
8449 (0 != memcmp (frame, "\x8A\x0A" "bla" "\xC3" "blabla", 12)))
8450 {
8451 fprintf (stderr,
8452 "Encode pong test failed in line %u\n",
8453 (unsigned int) __LINE__);
8454 ++failed;
8455 }
8456 if (NULL != frame)
8457 {
8458 MHD_websocket_free (wss, frame);
8459 frame = NULL;
8460 }
8461
8462 /*
8463 ------------------------------------------------------------------------------
8464 Length checks
8465 ------------------------------------------------------------------------------
8466 */
8467 /* Edge test (success): Pong frame without payload */
8468 ret = MHD_websocket_encode_pong (wss,
8469 NULL,
8470 0,
8471 &frame,
8472 &frame_len);
8473 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
8474 (2 != frame_len) ||
8475 (NULL == frame) ||
8476 (0 != memcmp (frame, "\x8A\x00", 2)))
8477 {
8478 fprintf (stderr,
8479 "Encode pong test failed in line %u\n",
8480 (unsigned int) __LINE__);
8481 ++failed;
8482 }
8483 if (NULL != frame)
8484 {
8485 MHD_websocket_free (wss, frame);
8486 frame = NULL;
8487 }
8488 /* Edge test (success): Pong frame with one byte of payload */
8489 ret = MHD_websocket_encode_pong (wss,
8490 NULL,
8491 0,
8492 &frame,
8493 &frame_len);
8494 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
8495 (2 != frame_len) ||
8496 (NULL == frame) ||
8497 (0 != memcmp (frame, "\x8A\x00", 2)))
8498 {
8499 fprintf (stderr,
8500 "Encode pong test failed in line %u\n",
8501 (unsigned int) __LINE__);
8502 ++failed;
8503 }
8504 if (NULL != frame)
8505 {
8506 MHD_websocket_free (wss, frame);
8507 frame = NULL;
8508 }
8509 /* Edge test (success): Pong frame with 125 bytes of payload */
8510 ret = MHD_websocket_encode_pong (wss,
8511 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ012345678",
8512 125,
8513 &frame,
8514 &frame_len);
8515 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
8516 (127 != frame_len) ||
8517 (NULL == frame) ||
8518 (0 != memcmp (frame, "\x8A\x7D"
8519 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ012345678",
8520 127)))
8521 {
8522 fprintf (stderr,
8523 "Encode pong test failed in line %u\n",
8524 (unsigned int) __LINE__);
8525 ++failed;
8526 }
8527 if (NULL != frame)
8528 {
8529 MHD_websocket_free (wss, frame);
8530 frame = NULL;
8531 }
8532 /* Edge test (fail): Pong frame with 126 bytes of payload */
8533 ret = MHD_websocket_encode_pong (wss,
8534 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789",
8535 126,
8536 &frame,
8537 &frame_len);
8538 if ((MHD_WEBSOCKET_STATUS_MAXIMUM_SIZE_EXCEEDED != ret) ||
8539 (0 != frame_len) ||
8540 (NULL != frame) )
8541 {
8542 fprintf (stderr,
8543 "Encode pong test failed in line %u\n",
8544 (unsigned int) __LINE__);
8545 ++failed;
8546 }
8547 if (NULL != frame)
8548 {
8549 MHD_websocket_free (wss, frame);
8550 frame = NULL;
8551 }
8552
8553 /*
8554 ------------------------------------------------------------------------------
8555 Wrong parameters
8556 ------------------------------------------------------------------------------
8557 */
8558 /* Fail test: `ws` not passed */
8559 frame = (char*) (uintptr_t) 0xBAADF00D;
8560 frame_len = 0x87654321;
8561 ret = MHD_websocket_encode_pong (NULL,
8562 "abc",
8563 3,
8564 &frame,
8565 &frame_len);
8566 if ((MHD_WEBSOCKET_STATUS_PARAMETER_ERROR != ret) ||
8567 (0 != frame_len) ||
8568 (NULL != frame) )
8569 {
8570 fprintf (stderr,
8571 "Encode pong test failed in line %u\n",
8572 (unsigned int) __LINE__);
8573 ++failed;
8574 }
8575 if (((char*) (uintptr_t) 0xBAADF00D) == frame)
8576 {
8577 frame = NULL;
8578 }
8579 if (NULL != frame)
8580 {
8581 MHD_websocket_free (wss, frame);
8582 frame = NULL;
8583 }
8584 /* Fail test: `payload` not passed, but `payload_len` != 0 */
8585 frame = (char*) (uintptr_t) 0xBAADF00D;
8586 frame_len = 0x87654321;
8587 ret = MHD_websocket_encode_pong (wss,
8588 NULL,
8589 3,
8590 &frame,
8591 &frame_len);
8592 if ((MHD_WEBSOCKET_STATUS_PARAMETER_ERROR != ret) ||
8593 (0 != frame_len) ||
8594 (NULL != frame) )
8595 {
8596 fprintf (stderr,
8597 "Encode pong test failed in line %u\n",
8598 (unsigned int) __LINE__);
8599 ++failed;
8600 }
8601 if (((char*) (uintptr_t) 0xBAADF00D) == frame)
8602 {
8603 frame = NULL;
8604 }
8605 if (NULL != frame)
8606 {
8607 MHD_websocket_free (wss, frame);
8608 frame = NULL;
8609 }
8610 /* Regular test: `payload` passed, but `payload_len` == 0 */
8611 frame = (char*) (uintptr_t) 0xBAADF00D;
8612 frame_len = 0x87654321;
8613 ret = MHD_websocket_encode_pong (wss,
8614 "abc",
8615 0,
8616 &frame,
8617 &frame_len);
8618 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
8619 (2 != frame_len) ||
8620 (NULL == frame) ||
8621 (((char*) (uintptr_t) 0xBAADF00D) == frame) ||
8622 (0 != memcmp (frame, "\x8A\x00", 2)))
8623 {
8624 fprintf (stderr,
8625 "Encode pong test failed in line %u\n",
8626 (unsigned int) __LINE__);
8627 ++failed;
8628 }
8629 if (((char*) (uintptr_t) 0xBAADF00D) == frame)
8630 {
8631 frame = NULL;
8632 }
8633 if (NULL != frame)
8634 {
8635 MHD_websocket_free (wss, frame);
8636 frame = NULL;
8637 }
8638 /* Fail test: `frame` not passed */
8639 frame_len = 0x87654321;
8640 ret = MHD_websocket_encode_pong (wss,
8641 "abc",
8642 3,
8643 NULL,
8644 &frame_len);
8645 if ((MHD_WEBSOCKET_STATUS_PARAMETER_ERROR != ret) ||
8646 (0 != frame_len) )
8647 {
8648 fprintf (stderr,
8649 "Encode pong test failed in line %u\n",
8650 (unsigned int) __LINE__);
8651 ++failed;
8652 }
8653 /* Fail test: `frame_len` not passed */
8654 frame = (char*) (uintptr_t) 0xBAADF00D;
8655 ret = MHD_websocket_encode_pong (wss,
8656 "abc",
8657 3,
8658 &frame,
8659 NULL);
8660 if ((MHD_WEBSOCKET_STATUS_PARAMETER_ERROR != ret) ||
8661 (NULL != frame) )
8662 {
8663 fprintf (stderr,
8664 "Encode pong test failed in line %u\n",
8665 (unsigned int) __LINE__);
8666 ++failed;
8667 }
8668 if (((char*) (uintptr_t) 0xBAADF00D) == frame)
8669 {
8670 frame = NULL;
8671 }
8672 if (NULL != frame)
8673 {
8674 MHD_websocket_free (wss, frame);
8675 frame = NULL;
8676 }
8677
8678 /*
8679 ------------------------------------------------------------------------------
8680 validity after temporary out-of-memory
8681 ------------------------------------------------------------------------------
8682 */
8683 {
8684 struct MHD_WebSocketStream*wsx;
8685 if (MHD_WEBSOCKET_STATUS_OK == MHD_websocket_stream_init2 (&wsx,
8686 MHD_WEBSOCKET_FLAG_SERVER,
8687 0,
8688 test_malloc,
8689 test_realloc,
8690 test_free))
8691 {
8692 /* Fail test: allocation while no memory available */
8693 disable_alloc = 1;
8694 ret = MHD_websocket_encode_pong (wsx,
8695 "abc",
8696 3,
8697 &frame,
8698 &frame_len);
8699 if ((MHD_WEBSOCKET_STATUS_MEMORY_ERROR != ret) ||
8700 (0 != frame_len) ||
8701 (NULL != frame) )
8702 {
8703 fprintf (stderr,
8704 "Encode pong test failed in line %u\n",
8705 (unsigned int) __LINE__);
8706 ++failed;
8707 }
8708 if (NULL != frame)
8709 {
8710 MHD_websocket_free (wsx, frame);
8711 frame = NULL;
8712 }
8713 /* Regular test: allocation while memory is available again */
8714 disable_alloc = 0;
8715 ret = MHD_websocket_encode_pong (wsx,
8716 "abc",
8717 3,
8718 &frame,
8719 &frame_len);
8720 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
8721 (5 != frame_len) ||
8722 (NULL == frame) ||
8723 (0 != memcmp (frame, "\x8A\x03" "abc", 5)))
8724 {
8725 fprintf (stderr,
8726 "Encode pong test failed in line %u\n",
8727 (unsigned int) __LINE__);
8728 ++failed;
8729 }
8730 if (NULL != frame)
8731 {
8732 MHD_websocket_free (wsx, frame);
8733 frame = NULL;
8734 }
8735
8736 MHD_websocket_stream_free (wsx);
8737 }
8738 else
8739 {
8740 fprintf (stderr,
8741 "Couldn't perform memory test for pong encoding in line %u\n",
8742 (unsigned int) __LINE__);
8743 ++failed;
8744 }
8745 }
8746
8747 if (NULL != buf1)
8748 free (buf1);
8749 if (NULL != buf2)
8750 free (buf2);
8751 if (NULL != wsc)
8752 MHD_websocket_stream_free (wsc);
8753 if (NULL != wss)
8754 MHD_websocket_stream_free (wss);
8755
8756 return failed != 0 ? 0x80 : 0x00;
8757}
8758
8759
8760/**
8761 * Test procedure for `MHD_websocket_split_close_reason()`
8762 */
8763int
8764test_split_close_reason ()
8765{
8766 int failed = 0;
8767 const char*payload;
8768 unsigned short reason_code;
8769 const char*reason_utf8;
8770 size_t reason_utf8_len;
8771 int ret;
8772
8773 /*
8774 ------------------------------------------------------------------------------
8775 Normal splits
8776 ------------------------------------------------------------------------------
8777 */
8778 /* Regular test: Reason code + Reason text */
8779 reason_code = 9999;
8780 reason_utf8 = (const char*) (intptr_t) 0xBAADF00D;
8781 reason_utf8_len = 12345;
8782 payload = "\x03\xE8" "abc";
8783 ret = MHD_websocket_split_close_reason (payload,
8784 5,
8785 &reason_code,
8786 &reason_utf8,
8787 &reason_utf8_len);
8788 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
8789 (MHD_WEBSOCKET_CLOSEREASON_REGULAR != reason_code) ||
8790 (3 != reason_utf8_len) ||
8791 (payload + 2 != reason_utf8) )
8792 {
8793 fprintf (stderr,
8794 "split close reason test failed in line %u\n",
8795 (unsigned int) __LINE__);
8796 ++failed;
8797 }
8798 /* Regular test: Reason code */
8799 reason_code = 9999;
8800 reason_utf8 = (const char*) (intptr_t) 0xBAADF00D;
8801 reason_utf8_len = 12345;
8802 payload = "\x03\xE8";
8803 ret = MHD_websocket_split_close_reason (payload,
8804 2,
8805 &reason_code,
8806 &reason_utf8,
8807 &reason_utf8_len);
8808 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
8809 (MHD_WEBSOCKET_CLOSEREASON_REGULAR != reason_code) ||
8810 (0 != reason_utf8_len) ||
8811 (NULL != reason_utf8) )
8812 {
8813 fprintf (stderr,
8814 "split close reason test failed in line %u\n",
8815 (unsigned int) __LINE__);
8816 ++failed;
8817 }
8818 /* Regular test: No payload */
8819 reason_code = 9999;
8820 reason_utf8 = (const char*) (intptr_t) 0xBAADF00D;
8821 reason_utf8_len = 12345;
8822 payload = NULL;
8823 ret = MHD_websocket_split_close_reason (payload,
8824 0,
8825 &reason_code,
8826 &reason_utf8,
8827 &reason_utf8_len);
8828 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
8829 (MHD_WEBSOCKET_CLOSEREASON_NO_REASON != reason_code) ||
8830 (0 != reason_utf8_len) ||
8831 (NULL != reason_utf8) )
8832 {
8833 fprintf (stderr,
8834 "split close reason test failed in line %u\n",
8835 (unsigned int) __LINE__);
8836 ++failed;
8837 }
8838 /* Regular test: `payload` is not NULL given, but `payload_len` == 0 */
8839 reason_code = 9999;
8840 reason_utf8 = (const char*) (intptr_t) 0xBAADF00D;
8841 reason_utf8_len = 12345;
8842 payload = "abc";
8843 ret = MHD_websocket_split_close_reason (payload,
8844 0,
8845 &reason_code,
8846 &reason_utf8,
8847 &reason_utf8_len);
8848 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
8849 (MHD_WEBSOCKET_CLOSEREASON_NO_REASON != reason_code) ||
8850 (0 != reason_utf8_len) ||
8851 (NULL != reason_utf8) )
8852 {
8853 fprintf (stderr,
8854 "split close reason test failed in line %u\n",
8855 (unsigned int) __LINE__);
8856 ++failed;
8857 }
8858
8859 /*
8860 ------------------------------------------------------------------------------
8861 Wrong parameters
8862 ------------------------------------------------------------------------------
8863 */
8864 /* Fail test: `payload` not passed, but `payload_len` != 0 */
8865 reason_code = 9999;
8866 reason_utf8 = (const char*) (intptr_t) 0xBAADF00D;
8867 reason_utf8_len = 12345;
8868 payload = NULL;
8869 ret = MHD_websocket_split_close_reason (payload,
8870 3,
8871 &reason_code,
8872 &reason_utf8,
8873 &reason_utf8_len);
8874 if ((MHD_WEBSOCKET_STATUS_PARAMETER_ERROR != ret) ||
8875 (MHD_WEBSOCKET_CLOSEREASON_NO_REASON != reason_code) ||
8876 (0 != reason_utf8_len) ||
8877 (NULL != reason_utf8) )
8878 {
8879 fprintf (stderr,
8880 "split close reason test failed in line %u\n",
8881 (unsigned int) __LINE__);
8882 ++failed;
8883 }
8884 /* Regular test: `reason_code` not passed */
8885 reason_utf8 = (const char*) (intptr_t) 0xBAADF00D;
8886 reason_utf8_len = 12345;
8887 payload = "\x03\xE8" "abc";
8888 ret = MHD_websocket_split_close_reason (payload,
8889 5,
8890 NULL,
8891 &reason_utf8,
8892 &reason_utf8_len);
8893 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
8894 (3 != reason_utf8_len) ||
8895 (payload + 2 != reason_utf8) )
8896 {
8897 fprintf (stderr,
8898 "split close reason test failed in line %u\n",
8899 (unsigned int) __LINE__);
8900 ++failed;
8901 }
8902 /* Regular test: `reason_utf8` not passed */
8903 reason_code = 9999;
8904 reason_utf8_len = 12345;
8905 payload = "\x03\xE8" "abc";
8906 ret = MHD_websocket_split_close_reason (payload,
8907 5,
8908 &reason_code,
8909 NULL,
8910 &reason_utf8_len);
8911 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
8912 (MHD_WEBSOCKET_CLOSEREASON_REGULAR != reason_code) ||
8913 (3 != reason_utf8_len) )
8914 {
8915 fprintf (stderr,
8916 "split close reason test failed in line %u\n",
8917 (unsigned int) __LINE__);
8918 ++failed;
8919 }
8920 /* Regular test: `reason_utf8_len` not passed */
8921 reason_code = 9999;
8922 reason_utf8 = (const char*) (intptr_t) 0xBAADF00D;
8923 payload = "\x03\xE8" "abc";
8924 ret = MHD_websocket_split_close_reason (payload,
8925 5,
8926 &reason_code,
8927 &reason_utf8,
8928 NULL);
8929 if ((MHD_WEBSOCKET_STATUS_OK != ret) ||
8930 (MHD_WEBSOCKET_CLOSEREASON_REGULAR != reason_code) ||
8931 (payload + 2 != reason_utf8) )
8932 {
8933 fprintf (stderr,
8934 "split close reason test failed in line %u\n",
8935 (unsigned int) __LINE__);
8936 ++failed;
8937 }
8938 /* Regular test: `reason_code`, `reason_utf8` and `reason_utf8_len` not passed */
8939 /* (this is not prohibited, although it doesn't really make sense) */
8940 payload = "\x03\xE8" "abc";
8941 ret = MHD_websocket_split_close_reason (payload,
8942 5,
8943 NULL,
8944 NULL,
8945 NULL);
8946 if (MHD_WEBSOCKET_STATUS_OK != ret)
8947 {
8948 fprintf (stderr,
8949 "split close reason test failed in line %u\n",
8950 (unsigned int) __LINE__);
8951 ++failed;
8952 }
8953
8954 return failed != 0 ? 0x100 : 0x00;
8955}
8956
8957
8958int
8959main (int argc, char *const *argv)
8960{
8961 unsigned int errorCount = 0;
8962 (void) argc; (void) argv; /* Unused. Silent compiler warning. */
8963
8964 /* seed random number generator */
8965 MHD_websocket_srand ((unsigned long) time (NULL));
8966
8967 /* perform tests */
8968 errorCount += test_inits ();
8969 errorCount += test_accept ();
8970 errorCount += test_decodes ();
8971 errorCount += test_encodes_text ();
8972 errorCount += test_encodes_binary ();
8973 errorCount += test_encodes_close ();
8974 errorCount += test_encodes_ping ();
8975 errorCount += test_encodes_pong ();
8976 errorCount += test_split_close_reason ();
8977
8978 /* output result */
8979 if (errorCount != 0)
8980 fprintf (stderr, "Error (code: %u)\n", errorCount);
8981
8982 return errorCount != 0; /* 0 == pass */
8983}