aboutsummaryrefslogtreecommitdiff
path: root/src/include/microhttpd_ws.h
blob: 915ca33900f40ee8289e1dcd6d204b798e839fa6 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
/*
     This file is part of libmicrohttpd
     Copyright (C) 2021 Christian Grothoff (and other contributing authors)

     This library is free software; you can redistribute it and/or
     modify it under the terms of the GNU Lesser General Public
     License as published by the Free Software Foundation; either
     version 2.1 of the License, or (at your option) any later version.

     This library is distributed in the hope that it will be useful,
     but WITHOUT ANY WARRANTY; without even the implied warranty of
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     Lesser General Public License for more details.

     You should have received a copy of the GNU Lesser General Public
     License along with this library; if not, write to the Free Software
     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
*/
/**
 * @file microhttpd_ws.h
 * @brief interface for experimental web socket extension to libmicrohttpd
 * @author David Gausmann
 */
#ifndef MHD_MICROHTTPD_WS_H
#define MHD_MICROHTTPD_WS_H


#ifdef __cplusplus
extern "C"
{
#if 0                           /* keep Emacsens' auto-indent happy */
}
#endif
#endif


/**
 * @brief Handle for the encoding/decoding of websocket data
 *        (one stream is used per websocket)
 * @ingroup websocket
 */
struct MHD_WebSocketStream;

/**
 * @brief Flags for the initialization of a websocket stream
 *        `struct MHD_WebSocketStream` used by
 *        #MHD_websocket_stream_init() or
 *        #MHD_websocket_stream_init2().
 * @ingroup websocket
 */
enum MHD_WEBSOCKET_FLAG
{
  /**
   * The websocket is used by the server (default).
   * Thus all outgoing payload will not be "masked".
   * All incoming payload must be masked.
   * This cannot be used together with #MHD_WEBSOCKET_FLAG_CLIENT
   */
  MHD_WEBSOCKET_FLAG_SERVER = 0,
  /**
   * The websocket is used by the client
   * (not used if you provide the server).
   * Thus all outgoing payload will be "masked" (XOR-ed with random values).
   * All incoming payload must be unmasked.
   * Please note that this implementation doesn't use a strong random
   * number generator for the mask as suggested in RFC6455 10.3, because
   * the main intention of this implemention is the use as server
   * with MHD, which doesn't need masking.
   * Instead a weak random number generator is used (`rand()`).
   * You can set the seed for the random number generator
   * by calling #MHD_websocket_srand().
   * This cannot be used together with #MHD_WEBSOCKET_FLAG_SERVER
   */
  MHD_WEBSOCKET_FLAG_CLIENT = 1,
  /**
   * You don't want to get fragmented data while decoding.
   * Fragmented frames will be internally put together until
   * they are complete.
   * Whether or not data is fragmented is decided
   * by the sender of the data during encoding.
   * This cannot be used together with #MHD_WEBSOCKET_FLAG_WANT_FRAGMENTS
   */
  MHD_WEBSOCKET_FLAG_NO_FRAGMENTS = 0,
  /**
   * You want fragmented data, if it appears while decoding.
   * You will receive the content of the fragmented frame,
   * but if you are decoding text, you will never get an unfinished
   * UTF-8 sequences (if the sequence appears between two fragments).
   * Instead the text will end before the unfinished UTF-8 sequence.
   * With the next fragment, which finishes the UTF-8 sequence,
   * you will get the complete UTF-8 sequence.
   * This cannot be used together with #MHD_WEBSOCKET_FLAG_WANT_FRAGMENTS
   */
  MHD_WEBSOCKET_FLAG_WANT_FRAGMENTS = 2,
  /**
   * If the websocket stream becomes invalid during decoding due to
   * protocol errors, a matching close frame will automatically
   * be generated.
   * The close frame will be returned via the parameters
   * result and result_len of #MHD_websocket_decode() and
   * the return value is negative
   * (a value of `enum MHD_WEBSOCKET_STATUS`).
   * The generated close frame must be freed by the caller
   * with #MHD_websocket_free().
   */
  MHD_WEBSOCKET_FLAG_GENERATE_CLOSE_FRAMES_ON_ERROR = 4
};

/**
 * @brief Enum to specify the fragmenting behavior
 *        while encoding with #MHD_websocket_encode_text() or
 *        #MHD_websocket_encode_binary().
 * @ingroup websocket
 */
enum MHD_WEBSOCKET_FRAGMENTATION
{
  /**
   * You don't want to use fragmentation.
   * The encoded frame consists of only one frame.
   */
  MHD_WEBSOCKET_FRAGMENTATION_NONE = 0,
  /**
   * You want to use fragmentation.
   * The encoded frame is the first frame of
   * a series of data frames of the same type
   * (text or binary).
   * You may send control frames (ping, pong or close)
   * between these data frames.
   */
  MHD_WEBSOCKET_FRAGMENTATION_FIRST = 1,
  /**
   * You want to use fragmentation.
   * The encoded frame is not the first frame of
   * the series of data frames, but also not the last one.
   * You may send control frames (ping, pong or close)
   * between these data frames.
   */
  MHD_WEBSOCKET_FRAGMENTATION_FOLLOWING = 2,
  /**
   * You want to use fragmentation.
   * The encoded frame is the last frame of
   * the series of data frames, but also not the first one.
   * After this frame, you may send all type of frames again.
   */
  MHD_WEBSOCKET_FRAGMENTATION_LAST = 3
};

/**
 * @brief Enum of the return value for almost every MHD_websocket function.
 *        Errors are negative and values equal to or above zero mean a success.
 *        Positive values are only used by #MHD_websocket_decode().
 * @ingroup websocket
 */
enum MHD_WEBSOCKET_STATUS
{
  /**
   * The call succeeded.
   * For #MHD_websocket_decode() this means that no error occurred,
   * but also no frame has been completed yet.
   */
  MHD_WEBSOCKET_STATUS_OK = 0,
  /**
   * #MHD_websocket_decode() has decoded a text frame.
   * The parameters result and result_len are filled with the decoded text
   * (if any).
   */
  MHD_WEBSOCKET_STATUS_TEXT_FRAME = 0x1,
  /**
   * #MHD_websocket_decode() has decoded a binary frame.
   * The parameters result and result_len are filled with the decoded
   * binary data (if any).
   */
  MHD_WEBSOCKET_STATUS_BINARY_FRAME = 0x2,
  /**
   * #MHD_websocket_decode() has decoded a close frame.
   * This means you must close the socket using #MHD_upgrade_action()
   * with #MHD_UPGRADE_ACTION_CLOSE.
   * You may respond with a close frame before closing.
   * The parameters result and result_len are filled with
   * the close reason (if any).
   * The close reason starts with a two byte sequence of close code
   * in network byte order (see `enum MHD_WEBSOCKET_CLOSEREASON`).
   * After these two bytes a UTF-8 encoded close reason may follow.
   * Compare with result_len to decide whether there is any close reason.
   */
  MHD_WEBSOCKET_STATUS_CLOSE_FRAME = 0x8,
  /**
   * #MHD_websocket_decode() has decoded a ping frame.
   * You should respond to this with a pong frame.
   * The pong frame must contain the same binary data as
   * the corresponding ping frame (if it had any).
   * The parameters result and result_len are filled with
   * the binary ping data (if any).
   */
  MHD_WEBSOCKET_STATUS_PING_FRAME = 0x9,
  /**
   * #MHD_websocket_decode() has decoded a pong frame.
   * You should usually only receive pong frames if you sent
   * a ping frame before.
   * The binary data should be equal to your ping frame and can be
   * used to distinguish the response if you sent multiple ping frames.
   * The parameters result and result_len are filled with
   * the binary pong data (if any).
   */
  MHD_WEBSOCKET_STATUS_PONG_FRAME = 0xA,
  /**
   * #MHD_websocket_decode() has decoded a text frame fragment.
   * The parameters result and result_len are filled with the decoded text
   * (if any).
   * This is like #MHD_WEBSOCKET_STATUS_TEXT_FRAME, but it can only
   * appear if you specified #MHD_WEBSOCKET_FLAG_WANT_FRAGMENTS during
   * the call of #MHD_websocket_stream_init() or
   * #MHD_websocket_stream_init2().
   */
  MHD_WEBSOCKET_STATUS_TEXT_FRAGMENT = 0x11,
  /**
   * #MHD_websocket_decode() has decoded a binary frame fragment.
   * The parameters result and result_len are filled with the decoded
   * binary data (if any).
   * This is like #MHD_WEBSOCKET_STATUS_BINARY_FRAME, but it can only
   * appear if you specified #MHD_WEBSOCKET_FLAG_WANT_FRAGMENTS during
   * the call of #MHD_websocket_stream_init() or
   * #MHD_websocket_stream_init2().
   */
  MHD_WEBSOCKET_STATUS_BINARY_FRAGMENT = 0x12,
  /**
  * #MHD_websocket_decode() has decoded the last text frame fragment.
  * The parameters result and result_len are filled with the decoded text
  * (if any).
  * This is like #MHD_WEBSOCKET_STATUS_TEXT_FRAGMENT, but it appears
  * only for the last fragment of a series of fragments.
  * It can only appear if you specified #MHD_WEBSOCKET_FLAG_WANT_FRAGMENTS
  * during the call of #MHD_websocket_stream_init() or
  * #MHD_websocket_stream_init2().
  */
  MHD_WEBSOCKET_STATUS_TEXT_LAST_FRAGMENT = 0x21,
  /**
  * #MHD_websocket_decode() has decoded the last binary frame fragment.
  * The parameters result and result_len are filled with the decoded
  * binary data (if any).
  * This is like #MHD_WEBSOCKET_STATUS_BINARY_FRAGMENT, but it appears
  * only for the last fragment of a series of fragments.
  * It can only appear if you specified #MHD_WEBSOCKET_FLAG_WANT_FRAGMENTS
  * during the call of #MHD_websocket_stream_init() or
  * #MHD_websocket_stream_init2().
  */
  MHD_WEBSOCKET_STATUS_BINARY_LAST_FRAGMENT = 0x22,
  /**
   * The call failed and the stream is invalid now for decoding.
   * You must close the websocket now using #MHD_upgrade_action()
   * with #MHD_UPGRADE_ACTION_CLOSE.
   * You can send a close frame before closing.
   * This is only used by #MHD_websocket_decode() and happens
   * if the stream contains errors (i. e. invalid byte data).
   */
  MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR = -1,
  /**
   * You tried to decode something, but the stream has already
   * been marked invalid.
   * You must close the websocket now using #MHD_upgrade_action()
   * with #MHD_UPGRADE_ACTION_CLOSE.
   * You can send a close frame before closing.
   * This is only used by #MHD_websocket_decode() and happens
   * if you call #MDM_websocket_decode() again after is
   * has been invalidated.
   */
  MHD_WEBSOCKET_STATUS_STREAM_BROKEN = -2,
  /**
   * A memory allocation failed. The stream remains valid.
   * If this occurred while decoding, the decoding could be
   * possible later if enough memory is available.
   * This could happen while decoding if you received a too big data frame.
   * You could try to specify max_payload_size during the call of
   * #MHD_websocket_stream_init() or #MHD_websocket_stream_init2() then to
   * avoid this and close the frame instead.
   */
  MHD_WEBSOCKET_STATUS_MEMORY_ERROR = -3,
  /**
   * You passed invalid parameters during the function call
   * (i. e. a NULL pointer for a required parameter).
   * The stream remains valid.
   */
  MHD_WEBSOCKET_STATUS_PARAMETER_ERROR = -4,
  /**
   * The maximum payload size has been exceeded.
   * If you got this return code from #MHD_websocket_decode() then
   * the stream becomes invalid and the websocket must be closed
   * using #MHD_upgrade_action() with #MHD_UPGRADE_ACTION_CLOSE.
   * You can send a close frame before closing.
   * The maximum payload size is specified during the call of
   * #MHD_websocket_stream_init() or #MHD_websocket_stream_init2().
   * This can also appear if you specified 0 as maximum payload size
   * when the message is greater than the maximum allocatable memory size
   * (i. e. more than 4 GB on 32 bit systems).
   * If you got this return code from #MHD_websocket_encode_close(),
   * #MHD_websocket_encode_ping() or #MHD_websocket_encode_pong() then
   * you passed to much payload data. The stream remains valid then.
   */
  MHD_WEBSOCKET_STATUS_MAXIMUM_SIZE_EXCEEDED = -5,
  /**
   * An UTF-8 text is invalid.
   * If you got this return code from #MHD_websocket_decode() then
   * the stream becomes invalid and you must close the websocket
   * using #MHD_upgrade_action() with #MHD_UPGRADE_ACTION_CLOSE.
   * You can send a close frame before closing.
   * If you got this from #MHD_websocket_encode_text() or
   * #MHD_websocket_encode_close() then you passed invalid UTF-8 text.
   * The stream remains valid then.
   */
  MHD_WEBSOCKET_STATUS_UTF8_ENCODING_ERROR = -6
};

/**
 * @brief Enumeration of possible close reasons for close frames.
 *
 * The possible values are specified in RFC 6455 7.4.1
 * These close reasons here are the default set specified by RFC 6455,
 * but also other close reasons could be used.
 *
 * The definition is for short:
 * 0-999 are never used (if you pass 0 in
 *   #MHD_websocket_encode_close() then no close reason is used).
 * 1000-2999 are specified by RFC 6455.
 * 3000-3999 are specified by libraries, etc. but must be registered by IANA.
 * 4000-4999 are reserved for private use.
 *
 * @ingroup websocket
 */
enum MHD_WEBSOCKET_CLOSEREASON
{
  /**
   * This value is used as placeholder for #MHD_websocket_encode_close()
   * to tell that you don't want to specify any reason.
   * If you use this value then no reason text may be used.
   * This value cannot a result of decoding, because this value
   * is not a valid close reason for the WebSocket protocol.
   */
  MHD_WEBSOCKET_CLOSEREASON_NO_REASON = 0,
  /**
   * You close the websocket fulfilled its purpose and shall
   * now be closed in a normal, planned way.
   */
  MHD_WEBSOCKET_CLOSEREASON_REGULAR = 1000,
  /**
   * You close the websocket because are shutting down the server or
   * something similar.
   */
  MHD_WEBSOCKET_CLOSEREASON_GOING_AWAY = 1001,
  /**
   * You close the websocket because you a protocol error occurred
   * during decoding (i. e. invalid byte data).
   */
  MHD_WEBSOCKET_CLOSEREASON_PROTOCOL_ERROR = 1002,
  /**
   * You close the websocket because you received data which you don't accept.
   * For example if you received a binary frame,
   * but your application only expects text frames.
   */
  MHD_WEBSOCKET_CLOSEREASON_UNSUPPORTED_DATATYPE = 1003,
  /**
   * You close the websocket because it contains malformed UTF-8.
   * The UTF-8 validity is automatically checked by #MHD_websocket_decode(),
   * so you don't need to check it on your own.
   * UTF-8 is specified in RFC 3629.
   */
  MHD_WEBSOCKET_CLOSEREASON_MALFORMED_UTF8 = 1007,
  /**
   * You close the websocket because of any reason.
   * Usually this close reason is used if no other close reason
   * is more specific or if you don't want to use any other close reason.
   */
  MHD_WEBSOCKET_CLOSEREASON_POLICY_VIOLATED = 1008,
  /**
   * You close the websocket because you received a frame which is too big to process.
   * You can specify the maximum allowed payload size during the call of
   * #MHD_websocket_stream_init() or #MHD_websocket_stream_init2().
   */
  MHD_WEBSOCKET_CLOSEREASON_MAXIMUM_ALLOWED_PAYLOAD_SIZE_EXCEEDED = 1009,
  /**
   * This status code can be sent by the client if it
   * expected a specific extension, but this extension hasn't been negotiated.
   */
  MHD_WEBSOCKET_CLOSEREASON_MISSING_EXTENSION = 1010,
  /**
   * The server closes the websocket because it encountered
   * an unexpected condition that prevented it from fulfilling the request.
   */
  MHD_WEBSOCKET_CLOSEREASON_UNEXPECTED_CONDITION = 1011
};

/**
 * @brief Enumeration of possible UTF-8 check steps
 *
 * These values are used during the encoding of fragmented text frames
 * or for error analysis while encoding text frames.
 * Its values specify the next step of the UTF-8 check.
 * UTF-8 sequences consist of one to four bytes.
 * This enumeration just says how long the current UTF-8 sequence is
 * and what is the next expected byte.
 *
 * @ingroup websocket
 */
enum MHD_WEBSOCKET_UTF8STEP
{
  /**
   * There is no open UTF-8 sequence.
   * The next byte must be 0x00-0x7F or 0xC2-0xF4.
   */
  MHD_WEBSOCKET_UTF8STEP_NORMAL   = 0,
  /**
   * The second byte of a two byte UTF-8 sequence.
   * The first byte was 0xC2-0xDF.
   * The next byte must be 0x80-0xBF.
   */
  MHD_WEBSOCKET_UTF8STEP_UTF2TAIL_1OF1 = 1,
  /**
   * The second byte of a three byte UTF-8 sequence.
   * The first byte was 0xE0.
   * The next byte must be 0xA0-0xBF.
   */
  MHD_WEBSOCKET_UTF8STEP_UTF3TAIL1_1OF2 = 2,
  /**
  * The second byte of a three byte UTF-8 sequence.
  * The first byte was 0xED.
  * The next byte must by 0x80-0x9F.
  */
  MHD_WEBSOCKET_UTF8STEP_UTF3TAIL2_1OF2 = 3,
  /**
  * The second byte of a three byte UTF-8 sequence.
  * The first byte was 0xE1-0xEC or 0xEE-0xEF.
  * The next byte must be 0x80-0xBF.
  */
  MHD_WEBSOCKET_UTF8STEP_UTF3TAIL_1OF2 = 4,
  /**
  * The third byte of a three byte UTF-8 sequence.
  * The next byte must be 0x80-0xBF.
  */
  MHD_WEBSOCKET_UTF8STEP_UTF3TAIL_2OF2 = 5,
  /**
   * The second byte of a four byte UTF-8 sequence.
   * The first byte was 0xF0.
   * The next byte must be 0x90-0xBF.
   */
  MHD_WEBSOCKET_UTF8STEP_UTF4TAIL1_1OF3 = 6,
  /**
   * The second byte of a four byte UTF-8 sequence.
   * The first byte was 0xF4.
   * The next byte must be 0x80-0x8F.
   */
  MHD_WEBSOCKET_UTF8STEP_UTF4TAIL2_1OF3 = 7,
  /**
   * The second byte of a four byte UTF-8 sequence.
   * The first byte was 0xF1-0xF3.
   * The next byte must be 0x80-0xBF.
   */
  MHD_WEBSOCKET_UTF8STEP_UTF4TAIL_1OF3 = 8,
  /**
   * The third byte of a four byte UTF-8 sequence.
   * The next byte must be 0x80-0xBF.
   */
  MHD_WEBSOCKET_UTF8STEP_UTF4TAIL_2OF3 = 9,
  /**
  * The fourth byte of a four byte UTF-8 sequence.
  * The next byte must be 0x80-0xBF.
  */
  MHD_WEBSOCKET_UTF8STEP_UTF4TAIL_3OF3 = 10
};

/**
* @brief Enumeration of validity values
*
* These values are used for #MHD_websocket_stream_is_valid()
* and specifiy the validity status.
*
* @ingroup websocket
*/
enum MHD_WEBSOCKET_VALIDITY
{
  /**
  * The stream is invalid.
  * It cannot be used for decoding anymore.
  */
  MHD_WEBSOCKET_VALIDITY_INVALID = 0,
  /**
   * The stream is valid.
   * Decoding works as expected.
   */
  MHD_WEBSOCKET_VALIDITY_VALID   = 1,
  /**
   * The stream has received a close frame and
   * is partly invalid.
   * You can still use the stream for decoding,
   * but if a data frame is received an error will be reported.
   * After a close frame has been sent, no data frames
   * may follow from the sender of the close frame.
   */
  MHD_WEBSOCKET_VALIDITY_ONLY_VALID_FOR_CONTROL_FRAMES = 2
};
/**
 * This method is called by many websocket
 * functions for allocating data.
 * By default 'malloc' is used.
 * This can be used for operating systems like Windows
 * where malloc, realloc and free are compiler dependent.
 *
 * @param len new size
 * @return allocated memory
 * @ingroup websocket
 */
typedef void*
(*MHD_WebSocketMallocCallback) (size_t len);
/**
 * This method is called by many websocket
 * functions for reallocating data.
 * By default 'realloc' is used.
 * This can be used for operating systems like Windows
 * where malloc, realloc and free are compiler dependent.
 *
 * @param cls closure
 * @param len new size
 * @return reallocated memory
 * @ingroup websocket
 */
typedef void*
(*MHD_WebSocketReallocCallback) (void *cls, size_t len);
/**
 * This method is called by many websocket
 * functions for freeing data.
 * By default 'free' is used.
 * This can be used for operating systems like Windows
 * where malloc, realloc and free are compiler dependent.
 *
 * @param cls closure
 * @ingroup websocket
 */
typedef void
(*MHD_WebSocketFreeCallback) (void *cls);

/**
 * Creates the response value for the incoming 'Sec-WebSocket-Key' header.
 * The generated value must be sent to the client as 'Sec-WebSocket-Accept' response header.
 *
 * @param sec_websocket_key The value of the 'Sec-WebSocket-Key' request header
 * @param[out] sec_websocket_accept The response buffer, which will receive
 *                                  the generated 'Sec-WebSocket-Accept' header.
 *                                  This buffer must be at least 29 bytes long and
 *                                  will contain a terminating NUL character.
 * @return A value of `enum MHD_WEBSOCKET_STATUS`.
 *         Typically 0 on success or less than 0 on errors.
 * @ingroup websocket
 */
_MHD_EXTERN int
MHD_websocket_create_accept (const char*sec_websocket_key,
                             char*sec_websocket_accept);

/**
 * Creates a new websocket stream, used for decoding/encoding.
 *
 * @param[out] ws The websocket stream
 * @param flags Combination of `enum MHD_WEBSOCKET_FLAG` values
 *              to modify the behavior of the websocket stream.
 * @param max_message_size The maximum size for incoming payload
 *                         data in bytes. Use 0 to allow each size.
 * @return A value of `enum MHD_WEBSOCKET_STATUS`.
 *         Typically 0 on success or less than 0 on errors.
 * @ingroup websocket
 */
_MHD_EXTERN int
MHD_websocket_stream_init (struct MHD_WebSocketStream**ws,
                           int flags,
                           size_t max_payload_size);

/**
 * Creates a new websocket stream, used for decoding/encoding,
 * but with custom memory functions for malloc, realloc and free.
 *
 * @param[out] ws The websocket stream
 * @param flags Combination of `enum MHD_WEBSOCKET_FLAG` values
 *              to modify the behavior of the websocket stream.
 * @param max_message_size The maximum size for incoming payload
 *                         data in bytes. Use 0 to allow each size.
 * @param callback_malloc  The callback function for 'malloc'.
 * @param callback_realloc The callback function for 'realloc'.
 * @param callback_free    The callback function for 'free'.
 * @return A value of `enum MHD_WEBSOCKET_STATUS`.
 *         Typically 0 on success or less than 0 on errors.
 * @ingroup websocket
 */
_MHD_EXTERN int
MHD_websocket_stream_init2 (struct MHD_WebSocketStream**ws,
                            int flags,
                            size_t max_payload_size,
                            MHD_WebSocketMallocCallback callback_malloc,
                            MHD_WebSocketReallocCallback callback_realloc,
                            MHD_WebSocketFreeCallback callback_free);

/**
 * Frees a websocket stream
 *
 * @param ws The websocket stream. This value may be NULL.
 * @return A value of `enum MHD_WEBSOCKET_STATUS`.
 *         Typically 0 on success or less than 0 on errors.
 * @ingroup websocket
 */
_MHD_EXTERN int
MHD_websocket_stream_free (struct MHD_WebSocketStream*ws);

/**
 * Invalidates a websocket stream.
 * After invalidation a websocket stream cannot be used for decoding anymore.
 * Encoding is still possible.
 *
 * @param ws The websocket stream.
 * @return A value of `enum MHD_WEBSOCKET_STATUS`.
 *         Typically 0 on success or less than 0 on errors.
 * @ingroup websocket
 */
_MHD_EXTERN int
MHD_websocket_stream_invalidate (struct MHD_WebSocketStream*ws);

/**
 * Queries whether a websocket stream is valid.
 * Invalidated websocket streams cannot be used for decoding anymore.
 * Encoding is still possible.
 *
 * @param ws The websocket stream.
 * @return A value of `enum MHD_WEBSOCKET_VALIDITY`.
 * @ingroup websocket
 */
_MHD_EXTERN int
MHD_websocket_stream_is_valid (struct MHD_WebSocketStream*ws);

/**
 * Decodes a byte sequence via this websocket stream.
 * Decoding is done until either a frame is complete or
 * the end of the byte sequence is reached.
 *
 * @param ws The websocket stream.
 * @param streambuf The byte sequence for decoding.
 *                  Typically that what you received via `recv()`.
 * @param streambuf_len The length of the byte sequence @a streambuf
 * @param[out] streambuf_read_len The number of bytes which has been processed
 *                                by this call. This value may be less
 *                                than @a streambuf_len when a frame is decoded
 *                                before the end of the buffer is reached.
 *                                The remaining bytes of @a buf must be passed
 *                                in the following decoding.
 * @param[out] payload This variable receives a buffer with the decoded
 *                     payload data.
 *                     If no decoded data is available this is NULL.
 *                     When this variable is not NULL then
 *                     the buffer contains always @a payload_len bytes plus
 *                     one terminating NUL character.
 *                     The caller must free this buffer
 *                     using #MHD_websocket_free().
 *                     If you passed the flag
 *                     #MHD_WEBSOCKET_FLAG_GENERATE_CLOSE_FRAMES_ON_ERROR
 *                     upon creation of this websocket stream and
 *                     a decoding error occurred
 *                     (return value less than 0), then this
 *                     buffer contains a generated close frame
 *                     which must be sent via the socket to the recipient.
 *                     If you passed the flag #MHD_WEBSOCKET_FLAG_WANT_FRAGMENTS
 *                     upon creation of this websocket stream then
 *                     this payload may only be a part of the complete message.
 *                     Only complete UTF-8 sequences are returned
 *                     for fragmented text frames.
 *                     If necessary the UTF-8 sequence will be completed
 *                     with the next text fragment.
 * @param[out] payload_len The length of the result payload buffer in bytes.
 *
 * @return A value of `enum MHD_WEBSOCKET_STATUS`.
 *         This is greater than 0 if a frame has is complete, equal to 0 if more data
 *         is needed an less than 0 on errors.
 * @ingroup websocket
 */
_MHD_EXTERN int
MHD_websocket_decode (struct MHD_WebSocketStream*ws,
                      const char*streambuf,
                      size_t streambuf_len,
                      size_t*streambuf_read_len,
                      char**payload,
                      size_t*payload_len);

/**
 * Splits the payload of of a decoded close frame.
 *
 * @param payload The payload of the close frame.
 *                This parameter may be NULL if @a payload_len is 0.
 * @param payload_len The length of @a payload.
 * @param[out] reason_code The numeric close reason.
 *                         If there was no close reason, this is
 *                         #MHD_WEBSOCKET_CLOSEREASON_NO_REASON.
 *                         Compare with `enum MHD_WEBSOCKET_CLOSEREASON`.
 *                         This parameter is optional and can be NULL.
 * @param[out] reason_utf8 The literal close reason.
 *                         If there was no literal close reason, this is NULL.
 *                         This parameter is optional and can be NULL.
 *                         Please note that no memory is allocated
 *                         in this function.
 *                         If not NULL the returned value of this parameter
 *                         points to a position in the specified @a payload.
 * @param[out] reason_utf8_len The length of the literal close reason.
 *                             If there was no literal close reason, this is 0.
 *                             This parameter is optional and can be NULL.
 *
 * @return A value of `enum MHD_WEBSOCKET_STATUS`.
 *         This is #MHD_WEBSOCKET_STATUS_OK (= 0) on success
 *         or a value less than 0 on errors.
 * @ingroup websocket
 */
_MHD_EXTERN int
MHD_websocket_split_close_reason (const char*payload,
                                  size_t payload_len,
                                  unsigned short*reason_code,
                                  const char**reason_utf8,
                                  size_t*reason_utf8_len);

/**
 * Encodes an UTF-8 encoded text into websocket text frame.
 *
 * @param ws The websocket stream.
 * @param payload_utf8 The UTF-8 encoded text to send.
 *                     This can be NULL if payload_utf8_len is 0.
 * @param payload_utf8_len The length of the UTF-8 encoded text in bytes.
 * @param fragmentation A value of `enum MHD_WEBSOCKET_FRAGMENTATION`
 *                      to specifiy the fragmentation behavior.
 *                      Specify MHD_WEBSOCKET_FRAGMENTATION_NONE
 *                      if you don't want to use fragmentation.
 * @param[out] frame This variable receives a buffer with the encoded frame.
 *                   This is what you typically send via `send()` to the recipient.
 *                   If no encoded data is available this is NULL.
 *                   When this variable is not NULL then the buffer contains always
 *                   @a frame_len bytes plus one terminating NUL character.
 *                   The caller must free this buffer using #MHD_websocket_free().
 * @param[out] frame_len The length of the encoded frame in bytes.
 * @param[out] utf8_step This parameter is required for fragmentation and
 *                       can be NULL if no fragmentation is used.
 *                       It contains information about the last encoded
 *                       UTF-8 sequence and is required to continue a previous
 *                       UTF-8 sequence when fragmentation is used.
 *                       The `enum MHD_WEBSOCKET_UTF8STEP` is for this.
 *                       If you start a new fragment using
 *                       MHD_WEBSOCKET_FRAGMENTATION_NONE or
 *                       MHD_WEBSOCKET_FRAGMENTATION_FIRST the value
 *                       of this variable will be initialized
 *                       to MHD_WEBSOCKET_UTF8STEP_NORMAL.
 *
 * @return A value of `enum MHD_WEBSOCKET_STATUS`.
 *         This is #MHD_WEBSOCKET_STATUS_OK (= 0) on success
 *         or a value less than 0 on errors.
 * @ingroup websocket
 */
_MHD_EXTERN int
MHD_websocket_encode_text (struct MHD_WebSocketStream*ws,
                           const char*payload_utf8,
                           size_t payload_utf8_len,
                           int fragmentation,
                           char**frame,
                           size_t*frame_len,
                           int*utf8_step);

/**
 * Encodes a binary data into websocket binary frame.
 *
 * @param ws The websocket stream.
 * @param payload The binary data to send.
 * @param payload_len The length of the binary data in bytes.
 * @param fragmentation A value of `enum MHD_WEBSOCKET_FRAGMENTATION`
 *                      to specifiy the fragmentation behavior.
 *                      Specify MHD_WEBSOCKET_FRAGMENTATION_NONE
 *                      if you don't want to use fragmentation.
 * @param[out] frame This variable receives a buffer with
 *                   the encoded binary frame.
 *                   This is what you typically send via `send()`
 *                   to the recipient.
 *                   If no encoded frame is available this is NULL.
 *                   When this variable is not NULL then the allocated buffer
 *                   contains always @a frame_len bytes plus one terminating
 *                   NUL character.
 *                   The caller must free this buffer using #MHD_websocket_free().
 * @param[out] frame_len The length of the result frame buffer in bytes.
 *
 * @return A value of `enum MHD_WEBSOCKET_STATUS`.
 *         This is #MHD_WEBSOCKET_STATUS_OK (= 0) on success
 *         or a value less than 0 on errors.
 * @ingroup websocket
 */
_MHD_EXTERN int
MHD_websocket_encode_binary (struct MHD_WebSocketStream*ws,
                             const char*payload,
                             size_t payload_len,
                             int fragmentation,
                             char**frame,
                             size_t*frame_len);

/**
 * Encodes a websocket ping frame
 *
 * @param ws The websocket stream.
 * @param payload The binary ping payload data to send.
 *                This may be NULL if @a payload_len is 0.
 * @param payload_len The length of the payload data in bytes.
 *                    This may not exceed 125 bytes.
 * @param[out] frame This variable receives a buffer with the encoded ping frame data.
 *                   This is what you typically send via `send()` to the recipient.
 *                   If no encoded frame is available this is NULL.
 *                   When this variable is not NULL then the buffer contains always
 *                   @a frame_len bytes plus one terminating NUL character.
 *                   The caller must free this buffer using #MHD_websocket_free().
 * @param[out] frame_len The length of the result frame buffer in bytes.
 *
 * @return A value of `enum MHD_WEBSOCKET_STATUS`.
 *         This is #MHD_WEBSOCKET_STATUS_OK (= 0) on success
 *         or a value less than 0 on errors.
 * @ingroup websocket
 */
_MHD_EXTERN int
MHD_websocket_encode_ping (struct MHD_WebSocketStream*ws,
                           const char*payload,
                           size_t payload_len,
                           char**frame,
                           size_t*frame_len);

/**
 * Encodes a websocket pong frame
 *
 * @param ws The websocket stream.
 * @param payload The binary pong payload data, which is typically
 *                the decoded payload from the received ping frame.
 *                This may be NULL if @a payload_len is 0.
 * @param payload_len The length of the payload data in bytes.
 *                    This may not exceed 125 bytes.
 * @param[out] frame This variable receives a buffer with
 *                   the encoded pong frame data.
 *                   This is what you typically send via `send()`
 *                   to the recipient.
 *                   If no encoded frame is available this is NULL.
 *                   When this variable is not NULL then the buffer
 *                   contains always @a frame_len bytes plus one
 *                   terminating NUL character.
 *                   The caller must free this buffer
 *                   using #MHD_websocket_free().
 * @param[out] frame_len The length of the result frame buffer in bytes.
 *
 * @return A value of `enum MHD_WEBSOCKET_STATUS`.
 *         This is #MHD_WEBSOCKET_STATUS_OK (= 0) on success
 *         or a value less than 0 on errors.
 * @ingroup websocket
 */
_MHD_EXTERN int
MHD_websocket_encode_pong (struct MHD_WebSocketStream*ws,
                           const char*payload,
                           size_t payload_len,
                           char**frame,
                           size_t*frame_len);

/**
 * Encodes a websocket close frame
 *
 * @param ws The websocket stream.
 * @param reason_code The reason for close.
 *                    You can use `enum MHD_WEBSOCKET_CLOSEREASON`
 *                    for typical reasons,
 *                    but you are not limited to these values.
 *                    The allowed values are specified in RFC 6455 7.4.
 *                    If you don't want to enter a reason, you can specify
 *                    #MHD_WEBSOCKET_CLOSEREASON_NO_REASON then
 *                    no reason is encoded.
 * @param reason_utf8 An UTF-8 encoded text reason why the connection is closed.
 *                    This may be NULL if @a reason_utf8_len is 0.
 *                    This must be NULL if @a reason_code is
 *                    #MHD_WEBSOCKET_CLOSEREASON_NO_REASON (= 0).
 * @param reason_utf8_len The length of the UTF-8 encoded text reason in bytes.
 *                        This may not exceed 123 bytes.
 * @param[out] frame This variable receives a buffer with
 *                   the encoded close frame.
 *                   This is what you typically send via `send()`
 *                   to the recipient.
 *                   If no encoded frame is available this is NULL.
 *                   When this variable is not NULL then the buffer
 *                   contains always @a frame_len bytes plus
 *                   one terminating NUL character.
 *                   The caller must free this buffer
 *                   using #MHD_websocket_free().
 * @param[out] frame_len The length of the result frame buffer in bytes.
 *
 * @return A value of `enum MHD_WEBSOCKET_STATUS`.
 *         This is #MHD_WEBSOCKET_STATUS_OK (= 0) on success
 *         or a value less than 0 on errors.
 * @ingroup websocket
 */
_MHD_EXTERN int
MHD_websocket_encode_close (struct MHD_WebSocketStream*ws,
                            unsigned short reason_code,
                            const char*reason_utf8,
                            size_t reason_utf8_len,
                            char**frame,
                            size_t*frame_len);

/**
 * Sets the seed for the random number generated used for
 * the generation of masked frames (this is only used for client websockets).
 * This seed is used for all websocket streams.
 * Internally `srand()` is called.
 * Please note that on some situations
 * (where `rand()` and `srand()` are shared between your program
 * and this library) this could cause unwanted results in your program if
 * your program relies on a specific seed.
 *
 * @param seed The seed used for the initialization of
 *             the pseudo random number generator.
 *             Typically `time(NULL)` is used here to
 *             generate a seed.
 *
 * @return A value of `enum MHD_WEBSOCKET_STATUS`.
 *         This is #MHD_WEBSOCKET_STATUS_OK (= 0) on success
 *         or a value less than 0 on errors.
 * @ingroup websocket
 */
_MHD_EXTERN int
MHD_websocket_srand (unsigned long seed);

/**
 * Allocates memory with the associated 'malloc' function
 * of the websocket stream
 *
 * @param ws The websocket stream.
 * @param len The length of the memory to allocate in bytes
 *
 * @return The allocated memory on success or NULL on failure.
 * @ingroup websocket
 */
_MHD_EXTERN void*
MHD_websocket_malloc (struct MHD_WebSocketStream*ws,
                      size_t len);

/**
 * Reallocates memory with the associated 'realloc' function
 * of the websocket stream
 *
 * @param ws The websocket stream.
 * @param cls The previously allocated memory or NULL
 * @param len The new length of the memory in bytes
 *
 * @return The allocated memory on success or NULL on failure.
 *         If NULL is returned the previously allocated buffer
 *         remains valid.
 * @ingroup websocket
 */
_MHD_EXTERN void*
MHD_websocket_realloc (struct MHD_WebSocketStream*ws,
                       void*cls,
                       size_t len);

/**
 * Frees memory with the associated 'free' function
 * of the websocket stream
 *
 * @param ws The websocket stream.
 * @param cls The previously allocated memory or NULL
 *
 * @return A value of `enum MHD_WEBSOCKET_STATUS`.
 *         This is #MHD_WEBSOCKET_STATUS_OK (= 0) on success
 *         or a value less than 0 on errors.
 * @ingroup websocket
 */
_MHD_EXTERN int
MHD_websocket_free (struct MHD_WebSocketStream*ws,
                    void*cls);

#if 0                           /* keep Emacsens' auto-indent happy */
{
#endif
#ifdef __cplusplus
}
#endif

#endif