isomorfeus-iodine 0.7.49 → 0.7.50

Sign up to get free protection for your applications and to get access to all the features.
Files changed (83) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby.yml +1 -1
  3. data/CHANGELOG.md +17 -3
  4. data/Rakefile +1 -9
  5. data/examples/etag.ru +16 -0
  6. data/ext/{iodine → iodine_ext}/extconf.rb +1 -1
  7. data/ext/{iodine → iodine_ext}/fio.c +0 -0
  8. data/ext/{iodine → iodine_ext}/fio.h +0 -0
  9. data/ext/{iodine → iodine_ext}/fio_cli.c +0 -0
  10. data/ext/{iodine → iodine_ext}/fio_cli.h +189 -189
  11. data/ext/{iodine → iodine_ext}/fio_json_parser.h +687 -687
  12. data/ext/{iodine → iodine_ext}/fio_siphash.c +157 -157
  13. data/ext/{iodine → iodine_ext}/fio_siphash.h +37 -37
  14. data/ext/{iodine → iodine_ext}/fio_tls.h +129 -129
  15. data/ext/{iodine → iodine_ext}/fio_tls_missing.c +0 -0
  16. data/ext/{iodine → iodine_ext}/fio_tls_openssl.c +0 -0
  17. data/ext/{iodine → iodine_ext}/fio_tmpfile.h +0 -0
  18. data/ext/{iodine → iodine_ext}/fiobj.h +44 -44
  19. data/ext/{iodine → iodine_ext}/fiobj4fio.h +21 -21
  20. data/ext/{iodine → iodine_ext}/fiobj_ary.c +333 -333
  21. data/ext/{iodine → iodine_ext}/fiobj_ary.h +139 -139
  22. data/ext/{iodine → iodine_ext}/fiobj_data.c +0 -0
  23. data/ext/{iodine → iodine_ext}/fiobj_data.h +0 -0
  24. data/ext/{iodine → iodine_ext}/fiobj_hash.c +0 -0
  25. data/ext/{iodine → iodine_ext}/fiobj_hash.h +176 -176
  26. data/ext/{iodine → iodine_ext}/fiobj_json.c +622 -622
  27. data/ext/{iodine → iodine_ext}/fiobj_json.h +68 -68
  28. data/ext/{iodine → iodine_ext}/fiobj_mem.h +71 -71
  29. data/ext/{iodine → iodine_ext}/fiobj_mustache.c +0 -0
  30. data/ext/{iodine → iodine_ext}/fiobj_mustache.h +62 -62
  31. data/ext/{iodine → iodine_ext}/fiobj_numbers.c +0 -0
  32. data/ext/{iodine → iodine_ext}/fiobj_numbers.h +127 -127
  33. data/ext/{iodine → iodine_ext}/fiobj_str.c +0 -0
  34. data/ext/{iodine → iodine_ext}/fiobj_str.h +172 -172
  35. data/ext/{iodine → iodine_ext}/fiobject.c +0 -0
  36. data/ext/{iodine → iodine_ext}/fiobject.h +0 -0
  37. data/ext/{iodine → iodine_ext}/hpack.h +1923 -1923
  38. data/ext/{iodine → iodine_ext}/http.c +14 -27
  39. data/ext/{iodine → iodine_ext}/http.h +1002 -1002
  40. data/ext/{iodine → iodine_ext}/http1.c +0 -0
  41. data/ext/{iodine → iodine_ext}/http1.h +29 -29
  42. data/ext/{iodine → iodine_ext}/http1_parser.h +0 -0
  43. data/ext/{iodine → iodine_ext}/http_internal.c +0 -0
  44. data/ext/{iodine → iodine_ext}/http_internal.h +0 -0
  45. data/ext/{iodine → iodine_ext}/http_mime_parser.h +350 -350
  46. data/ext/{iodine → iodine_ext}/iodine.c +1 -1
  47. data/ext/{iodine → iodine_ext}/iodine.h +0 -0
  48. data/ext/{iodine → iodine_ext}/iodine_caller.c +0 -0
  49. data/ext/{iodine → iodine_ext}/iodine_caller.h +0 -0
  50. data/ext/{iodine → iodine_ext}/iodine_connection.c +0 -0
  51. data/ext/{iodine → iodine_ext}/iodine_connection.h +55 -55
  52. data/ext/{iodine → iodine_ext}/iodine_defer.c +0 -0
  53. data/ext/{iodine → iodine_ext}/iodine_defer.h +6 -6
  54. data/ext/{iodine → iodine_ext}/iodine_fiobj2rb.h +120 -120
  55. data/ext/{iodine → iodine_ext}/iodine_helpers.c +0 -0
  56. data/ext/{iodine → iodine_ext}/iodine_helpers.h +12 -12
  57. data/ext/{iodine → iodine_ext}/iodine_http.c +0 -2
  58. data/ext/{iodine → iodine_ext}/iodine_http.h +23 -23
  59. data/ext/{iodine → iodine_ext}/iodine_json.c +302 -302
  60. data/ext/{iodine → iodine_ext}/iodine_json.h +6 -6
  61. data/ext/{iodine → iodine_ext}/iodine_mustache.c +0 -0
  62. data/ext/{iodine → iodine_ext}/iodine_mustache.h +6 -6
  63. data/ext/{iodine → iodine_ext}/iodine_pubsub.c +0 -0
  64. data/ext/{iodine → iodine_ext}/iodine_pubsub.h +26 -26
  65. data/ext/{iodine → iodine_ext}/iodine_rack_io.c +0 -0
  66. data/ext/{iodine → iodine_ext}/iodine_rack_io.h +20 -20
  67. data/ext/{iodine → iodine_ext}/iodine_store.c +0 -0
  68. data/ext/{iodine → iodine_ext}/iodine_store.h +20 -20
  69. data/ext/{iodine → iodine_ext}/iodine_tcp.c +0 -0
  70. data/ext/{iodine → iodine_ext}/iodine_tcp.h +0 -0
  71. data/ext/{iodine → iodine_ext}/iodine_tls.c +0 -0
  72. data/ext/{iodine → iodine_ext}/iodine_tls.h +13 -13
  73. data/ext/{iodine → iodine_ext}/mustache_parser.h +0 -0
  74. data/ext/{iodine → iodine_ext}/redis_engine.c +0 -0
  75. data/ext/{iodine → iodine_ext}/redis_engine.h +0 -0
  76. data/ext/{iodine → iodine_ext}/resp_parser.h +0 -0
  77. data/ext/{iodine → iodine_ext}/websocket_parser.h +505 -505
  78. data/ext/{iodine → iodine_ext}/websockets.c +0 -0
  79. data/ext/{iodine → iodine_ext}/websockets.h +185 -185
  80. data/isomorfeus-iodine.gemspec +1 -2
  81. data/lib/iodine/version.rb +1 -1
  82. data/lib/iodine.rb +1 -1
  83. metadata +79 -78
@@ -1,505 +1,505 @@
1
- /*
2
- copyright: Boaz Segev, 2017-2019
3
- license: MIT
4
-
5
- Feel free to copy, use and enjoy according to the license specified.
6
- */
7
- #ifndef H_WEBSOCKET_PARSER_H
8
- /**\file
9
-
10
- A single file WebSocket message parser and WebSocket message wrapper, decoupled
11
- from any IO layer.
12
-
13
- Notice that this header file library includes static funnction declerations that
14
- must be implemented by the including file (the callbacks).
15
-
16
- */
17
- #define H_WEBSOCKET_PARSER_H
18
- #include <stdint.h>
19
- #include <stdlib.h>
20
- #include <string.h>
21
- #if DEBUG
22
- #include <stdio.h>
23
- #endif
24
- /* *****************************************************************************
25
- API - Message Wrapping
26
- ***************************************************************************** */
27
-
28
- /** returns the length of the buffer required to wrap a message `len` long */
29
- static inline __attribute__((unused)) uint64_t
30
- websocket_wrapped_len(uint64_t len);
31
-
32
- /**
33
- * Wraps a WebSocket server message and writes it to the target buffer.
34
- *
35
- * The `first` and `last` flags can be used to support message fragmentation.
36
- *
37
- * * target: the target buffer to write to.
38
- * * msg: the message to be wrapped.
39
- * * len: the message length.
40
- * * opcode: set to 1 for UTF-8 message, 2 for binary, etc'.
41
- * * first: set to 1 if `msg` points the beginning of the message.
42
- * * last: set to 1 if `msg + len` ends the message.
43
- * * client: set to 1 to use client mode (data masking).
44
- *
45
- * Further opcode values:
46
- * * %x0 denotes a continuation frame
47
- * * %x1 denotes a text frame
48
- * * %x2 denotes a binary frame
49
- * * %x3-7 are reserved for further non-control frames
50
- * * %x8 denotes a connection close
51
- * * %x9 denotes a ping
52
- * * %xA denotes a pong
53
- * * %xB-F are reserved for further control frames
54
- *
55
- * Returns the number of bytes written. Always `websocket_wrapped_len(len)`
56
- */
57
- inline static uint64_t __attribute__((unused))
58
- websocket_server_wrap(void *target, void *msg, uint64_t len,
59
- unsigned char opcode, unsigned char first,
60
- unsigned char last, unsigned char rsv);
61
-
62
- /**
63
- * Wraps a WebSocket client message and writes it to the target buffer.
64
- *
65
- * The `first` and `last` flags can be used to support message fragmentation.
66
- *
67
- * * target: the target buffer to write to.
68
- * * msg: the message to be wrapped.
69
- * * len: the message length.
70
- * * opcode: set to 1 for UTF-8 message, 2 for binary, etc'.
71
- * * first: set to 1 if `msg` points the beginning of the message.
72
- * * last: set to 1 if `msg + len` ends the message.
73
- * * client: set to 1 to use client mode (data masking).
74
- *
75
- * Returns the number of bytes written. Always `websocket_wrapped_len(len) + 4`
76
- */
77
- inline static __attribute__((unused)) uint64_t
78
- websocket_client_wrap(void *target, void *msg, uint64_t len,
79
- unsigned char opcode, unsigned char first,
80
- unsigned char last, unsigned char rsv);
81
-
82
- /* *****************************************************************************
83
- Callbacks - Required functions that must be inplemented to use this header
84
- ***************************************************************************** */
85
-
86
- static void websocket_on_unwrapped(void *udata, void *msg, uint64_t len,
87
- char first, char last, char text,
88
- unsigned char rsv);
89
- static void websocket_on_protocol_ping(void *udata, void *msg, uint64_t len);
90
- static void websocket_on_protocol_pong(void *udata, void *msg, uint64_t len);
91
- static void websocket_on_protocol_close(void *udata);
92
- static void websocket_on_protocol_error(void *udata);
93
-
94
- /* *****************************************************************************
95
- API - Parsing (unwrapping)
96
- ***************************************************************************** */
97
-
98
- /** the returned value for `websocket_buffer_required` */
99
- struct websocket_packet_info_s {
100
- /** the expected packet length */
101
- uint64_t packet_length;
102
- /** the packet's "head" size (before the data) */
103
- uint8_t head_length;
104
- /** a flag indicating if the packet is masked */
105
- uint8_t masked;
106
- };
107
-
108
- /**
109
- * Returns all known information regarding the upcoming message.
110
- *
111
- * @returns a struct websocket_packet_info_s.
112
- *
113
- * On protocol error, the `head_length` value is 0 (no valid head detected).
114
- */
115
- inline static struct websocket_packet_info_s
116
- websocket_buffer_peek(void *buffer, uint64_t len);
117
-
118
- /**
119
- * Consumes the data in the buffer, calling any callbacks required.
120
- *
121
- * Returns the remaining data in the existing buffer (can be 0).
122
- *
123
- * Notice: if there's any data in the buffer that can't be parsed
124
- * just yet, `memmove` is used to place the data at the beginning of the buffer.
125
- */
126
- inline static __attribute__((unused)) uint64_t
127
- websocket_consume(void *buffer, uint64_t len, void *udata,
128
- uint8_t require_masking);
129
-
130
- /* *****************************************************************************
131
- API - Internal Helpers
132
- ***************************************************************************** */
133
-
134
- /** used internally to mask and unmask client messages. */
135
- inline static void websocket_xmask(void *msg, uint64_t len, uint32_t mask);
136
-
137
- /* *****************************************************************************
138
-
139
- Implementation
140
-
141
- ***************************************************************************** */
142
-
143
- /* *****************************************************************************
144
- Message masking
145
- ***************************************************************************** */
146
- /** used internally to mask and unmask client messages. */
147
- void websocket_xmask(void *msg, uint64_t len, uint32_t mask) {
148
- if (len > 7) {
149
- { /* XOR any unaligned memory (4 byte alignment) */
150
- const uintptr_t offset = 4 - ((uintptr_t)msg & 3);
151
- switch (offset) {
152
- case 3:
153
- ((uint8_t *)msg)[2] ^= ((uint8_t *)(&mask))[2];
154
- /* fallthrough */
155
- case 2:
156
- ((uint8_t *)msg)[1] ^= ((uint8_t *)(&mask))[1];
157
- /* fallthrough */
158
- case 1:
159
- ((uint8_t *)msg)[0] ^= ((uint8_t *)(&mask))[0];
160
- /* rotate mask and move pointer to first 4 byte alignment */
161
- uint64_t comb = mask | ((uint64_t)mask << 32);
162
- ((uint8_t *)(&mask))[0] = ((uint8_t *)(&comb))[0 + offset];
163
- ((uint8_t *)(&mask))[1] = ((uint8_t *)(&comb))[1 + offset];
164
- ((uint8_t *)(&mask))[2] = ((uint8_t *)(&comb))[2 + offset];
165
- ((uint8_t *)(&mask))[3] = ((uint8_t *)(&comb))[3 + offset];
166
- msg = (void *)((uintptr_t)msg + offset);
167
- len -= offset;
168
- }
169
- }
170
- #if UINTPTR_MAX <= 0xFFFFFFFF
171
- /* handle 4 byte XOR alignment in 32 bit mnachine*/
172
- while (len >= 4) {
173
- *((uint32_t *)msg) ^= mask;
174
- len -= 4;
175
- msg = (void *)((uintptr_t)msg + 4);
176
- }
177
- #else
178
- /* handle first 4 byte XOR alignment and move on to 64 bits */
179
- if ((uintptr_t)msg & 7) {
180
- *((uint32_t *)msg) ^= mask;
181
- len -= 4;
182
- msg = (void *)((uintptr_t)msg + 4);
183
- }
184
- /* intrinsic / XOR by 8 byte block, memory aligned */
185
- const uint64_t xmask = (((uint64_t)mask) << 32) | mask;
186
- while (len >= 8) {
187
- *((uint64_t *)msg) ^= xmask;
188
- len -= 8;
189
- msg = (void *)((uintptr_t)msg + 8);
190
- }
191
- #endif
192
- }
193
-
194
- /* XOR any leftover bytes (might be non aligned) */
195
- switch (len) {
196
- case 7:
197
- ((uint8_t *)msg)[6] ^= ((uint8_t *)(&mask))[2];
198
- /* fallthrough */
199
- case 6:
200
- ((uint8_t *)msg)[5] ^= ((uint8_t *)(&mask))[1];
201
- /* fallthrough */
202
- case 5:
203
- ((uint8_t *)msg)[4] ^= ((uint8_t *)(&mask))[0];
204
- /* fallthrough */
205
- case 4:
206
- ((uint8_t *)msg)[3] ^= ((uint8_t *)(&mask))[3];
207
- /* fallthrough */
208
- case 3:
209
- ((uint8_t *)msg)[2] ^= ((uint8_t *)(&mask))[2];
210
- /* fallthrough */
211
- case 2:
212
- ((uint8_t *)msg)[1] ^= ((uint8_t *)(&mask))[1];
213
- /* fallthrough */
214
- case 1:
215
- ((uint8_t *)msg)[0] ^= ((uint8_t *)(&mask))[0];
216
- /* fallthrough */
217
- }
218
- }
219
-
220
- /* *****************************************************************************
221
- Message wrapping
222
- ***************************************************************************** */
223
-
224
- /** Converts an unaligned network ordered byte stream to a 16 bit number. */
225
- #define websocket_str2u16(c) \
226
- ((uint16_t)(((uint16_t)(((uint8_t *)(c))[0]) << 8) | \
227
- (uint16_t)(((uint8_t *)(c))[1])))
228
-
229
- /** Converts an unaligned network ordered byte stream to a 64 bit number. */
230
- #define websocket_str2u64(c) \
231
- ((uint64_t)((((uint64_t)((uint8_t *)(c))[0]) << 56) | \
232
- (((uint64_t)((uint8_t *)(c))[1]) << 48) | \
233
- (((uint64_t)((uint8_t *)(c))[2]) << 40) | \
234
- (((uint64_t)((uint8_t *)(c))[3]) << 32) | \
235
- (((uint64_t)((uint8_t *)(c))[4]) << 24) | \
236
- (((uint64_t)((uint8_t *)(c))[5]) << 16) | \
237
- (((uint64_t)((uint8_t *)(c))[6]) << 8) | (((uint8_t *)(c))[7])))
238
-
239
- /** Writes a local 16 bit number to an unaligned buffer in network order. */
240
- #define websocket_u2str16(buffer, i) \
241
- do { \
242
- ((uint8_t *)(buffer))[0] = ((uint16_t)(i) >> 8) & 0xFF; \
243
- ((uint8_t *)(buffer))[1] = ((uint16_t)(i)) & 0xFF; \
244
- } while (0);
245
-
246
- /** Writes a local 64 bit number to an unaligned buffer in network order. */
247
- #define websocket_u2str64(buffer, i) \
248
- do { \
249
- ((uint8_t *)(buffer))[0] = ((uint64_t)(i) >> 56) & 0xFF; \
250
- ((uint8_t *)(buffer))[1] = ((uint64_t)(i) >> 48) & 0xFF; \
251
- ((uint8_t *)(buffer))[2] = ((uint64_t)(i) >> 40) & 0xFF; \
252
- ((uint8_t *)(buffer))[3] = ((uint64_t)(i) >> 32) & 0xFF; \
253
- ((uint8_t *)(buffer))[4] = ((uint64_t)(i) >> 24) & 0xFF; \
254
- ((uint8_t *)(buffer))[5] = ((uint64_t)(i) >> 16) & 0xFF; \
255
- ((uint8_t *)(buffer))[6] = ((uint64_t)(i) >> 8) & 0xFF; \
256
- ((uint8_t *)(buffer))[7] = ((uint64_t)(i)) & 0xFF; \
257
- } while (0);
258
-
259
- /** returns the length of the buffer required to wrap a message `len` long */
260
- static inline uint64_t websocket_wrapped_len(uint64_t len) {
261
- if (len < 126)
262
- return len + 2;
263
- if (len < (1UL << 16))
264
- return len + 4;
265
- return len + 10;
266
- }
267
-
268
- /**
269
- * Wraps a WebSocket server message and writes it to the target buffer.
270
- *
271
- * The `first` and `last` flags can be used to support message fragmentation.
272
- *
273
- * * target: the target buffer to write to.
274
- * * msg: the message to be wrapped.
275
- * * len: the message length.
276
- * * opcode: set to 1 for UTF-8 message, 2 for binary, etc'.
277
- * * first: set to 1 if `msg` points the beginning of the message.
278
- * * last: set to 1 if `msg + len` ends the message.
279
- * * client: set to 1 to use client mode (data masking).
280
- *
281
- * Further opcode values:
282
- * * %x0 denotes a continuation frame
283
- * * %x1 denotes a text frame
284
- * * %x2 denotes a binary frame
285
- * * %x3-7 are reserved for further non-control frames
286
- * * %x8 denotes a connection close
287
- * * %x9 denotes a ping
288
- * * %xA denotes a pong
289
- * * %xB-F are reserved for further control frames
290
- *
291
- * Returns the number of bytes written. Always `websocket_wrapped_len(len)`
292
- */
293
- static uint64_t websocket_server_wrap(void *target, void *msg, uint64_t len,
294
- unsigned char opcode, unsigned char first,
295
- unsigned char last, unsigned char rsv) {
296
- ((uint8_t *)target)[0] = 0 |
297
- /* opcode */ (((first ? opcode : 0) & 15)) |
298
- /* rsv */ ((rsv & 7) << 4) |
299
- /*fin*/ ((last & 1) << 7);
300
- if (len < 126) {
301
- ((uint8_t *)target)[1] = len;
302
- memcpy(((uint8_t *)target) + 2, msg, len);
303
- return len + 2;
304
- } else if (len < (1UL << 16)) {
305
- /* head is 4 bytes */
306
- ((uint8_t *)target)[1] = 126;
307
- websocket_u2str16(((uint8_t *)target + 2), len);
308
- memcpy((uint8_t *)target + 4, msg, len);
309
- return len + 4;
310
- }
311
- /* Really Long Message */
312
- ((uint8_t *)target)[1] = 127;
313
- websocket_u2str64(((uint8_t *)target + 2), len);
314
- memcpy((uint8_t *)target + 10, msg, len);
315
- return len + 10;
316
- }
317
-
318
- /**
319
- * Wraps a WebSocket client message and writes it to the target buffer.
320
- *
321
- * The `first` and `last` flags can be used to support message fragmentation.
322
- *
323
- * * target: the target buffer to write to.
324
- * * msg: the message to be wrapped.
325
- * * len: the message length.
326
- * * opcode: set to 1 for UTF-8 message, 2 for binary, etc'.
327
- * * first: set to 1 if `msg` points the beginning of the message.
328
- * * last: set to 1 if `msg + len` ends the message.
329
- *
330
- * Returns the number of bytes written. Always `websocket_wrapped_len(len) +
331
- * 4`
332
- */
333
- static uint64_t websocket_client_wrap(void *target, void *msg, uint64_t len,
334
- unsigned char opcode, unsigned char first,
335
- unsigned char last, unsigned char rsv) {
336
- uint32_t mask = rand() | 0x01020408;
337
- ((uint8_t *)target)[0] = 0 |
338
- /* opcode */ (((first ? opcode : 0) & 15)) |
339
- /* rsv */ ((rsv & 7) << 4) |
340
- /*fin*/ ((last & 1) << 7);
341
- if (len < 126) {
342
- ((uint8_t *)target)[1] = len | 128;
343
- ((uint8_t *)target)[2] = ((uint8_t *)(&mask))[0];
344
- ((uint8_t *)target)[3] = ((uint8_t *)(&mask))[1];
345
- ((uint8_t *)target)[4] = ((uint8_t *)(&mask))[2];
346
- ((uint8_t *)target)[5] = ((uint8_t *)(&mask))[3];
347
- memcpy(((uint8_t *)target) + 6, msg, len);
348
- websocket_xmask((uint8_t *)target + 6, len, mask);
349
- return len + 6;
350
- } else if (len < (1UL << 16)) {
351
- /* head is 4 bytes */
352
- ((uint8_t *)target)[1] = 126 | 128;
353
- websocket_u2str16(((uint8_t *)target + 2), len);
354
- ((uint8_t *)target)[4] = ((uint8_t *)(&mask))[0];
355
- ((uint8_t *)target)[5] = ((uint8_t *)(&mask))[1];
356
- ((uint8_t *)target)[6] = ((uint8_t *)(&mask))[2];
357
- ((uint8_t *)target)[7] = ((uint8_t *)(&mask))[3];
358
- memcpy((uint8_t *)target + 8, msg, len);
359
- websocket_xmask((uint8_t *)target + 8, len, mask);
360
- return len + 8;
361
- }
362
- /* Really Long Message */
363
- ((uint8_t *)target)[1] = 255;
364
- websocket_u2str64(((uint8_t *)target + 2), len);
365
- ((uint8_t *)target)[10] = ((uint8_t *)(&mask))[0];
366
- ((uint8_t *)target)[11] = ((uint8_t *)(&mask))[1];
367
- ((uint8_t *)target)[12] = ((uint8_t *)(&mask))[2];
368
- ((uint8_t *)target)[13] = ((uint8_t *)(&mask))[3];
369
- memcpy((uint8_t *)target + 14, msg, len);
370
- websocket_xmask((uint8_t *)target + 14, len, mask);
371
- return len + 14;
372
- }
373
-
374
- /* *****************************************************************************
375
- Message unwrapping
376
- ***************************************************************************** */
377
-
378
- /**
379
- * Returns all known information regarding the upcoming message.
380
- *
381
- * @returns a struct websocket_packet_info_s.
382
- *
383
- * On protocol error, the `head_length` value is 0 (no valid head detected).
384
- */
385
- inline static struct websocket_packet_info_s
386
- websocket_buffer_peek(void *buffer, uint64_t len) {
387
- if (len < 2) {
388
- const struct websocket_packet_info_s info = {0 /* packet */, 2 /* head */,
389
- 0 /* masked? */};
390
- return info;
391
- }
392
- const uint8_t mask_f = (((uint8_t *)buffer)[1] >> 7) & 1;
393
- const uint8_t mask_l = (mask_f << 2);
394
- uint8_t len_indicator = ((((uint8_t *)buffer)[1]) & 127);
395
- switch (len_indicator) {
396
- case 126:
397
- if (len < 4)
398
- return (struct websocket_packet_info_s){0, (uint8_t)(4 + mask_l), mask_f};
399
- return (struct websocket_packet_info_s){
400
- (uint64_t)websocket_str2u16(((uint8_t *)buffer + 2)),
401
- (uint8_t)(4 + mask_l), mask_f};
402
- case 127:
403
- if (len < 10)
404
- return (struct websocket_packet_info_s){0, (uint8_t)(10 + mask_l),
405
- mask_f};
406
- {
407
- uint64_t msg_len = websocket_str2u64(((uint8_t *)buffer + 2));
408
- if (msg_len >> 62)
409
- return (struct websocket_packet_info_s){0, 0, 0};
410
- return (struct websocket_packet_info_s){msg_len, (uint8_t)(10 + mask_l),
411
- mask_f};
412
- }
413
- default:
414
- return (struct websocket_packet_info_s){len_indicator,
415
- (uint8_t)(2 + mask_l), mask_f};
416
- }
417
- }
418
-
419
- /**
420
- * Consumes the data in the buffer, calling any callbacks required.
421
- *
422
- * Returns the remaining data in the existing buffer (can be 0).
423
- */
424
- static uint64_t websocket_consume(void *buffer, uint64_t len, void *udata,
425
- uint8_t require_masking) {
426
- volatile struct websocket_packet_info_s info =
427
- websocket_buffer_peek(buffer, len);
428
- if (!info.head_length) {
429
- #if DEBUG
430
- fprintf(stderr, "ERROR: WebSocket protocol error - malicious header.\n");
431
- #endif
432
- websocket_on_protocol_error(udata);
433
- return 0;
434
- }
435
- if (info.head_length + info.packet_length > len)
436
- return len;
437
- uint64_t reminder = len;
438
- uint8_t *pos = (uint8_t *)buffer;
439
- while (info.head_length + info.packet_length <= reminder) {
440
- /* parse head */
441
- void *payload = (void *)(pos + info.head_length);
442
- /* unmask? */
443
- if (info.masked) {
444
- /* masked */
445
- uint32_t mask; // = ((uint32_t *)payload)[-1];
446
- ((uint8_t *)(&mask))[0] = ((uint8_t *)(payload))[-4];
447
- ((uint8_t *)(&mask))[1] = ((uint8_t *)(payload))[-3];
448
- ((uint8_t *)(&mask))[2] = ((uint8_t *)(payload))[-2];
449
- ((uint8_t *)(&mask))[3] = ((uint8_t *)(payload))[-1];
450
- websocket_xmask(payload, info.packet_length, mask);
451
- } else if (require_masking && info.packet_length) {
452
- #if DEBUG
453
- fprintf(stderr, "ERROR: WebSocket protocol error - unmasked data.\n");
454
- #endif
455
- websocket_on_protocol_error(udata);
456
- }
457
- /* call callback */
458
- switch (pos[0] & 15) {
459
- case 0:
460
- /* continuation frame */
461
- websocket_on_unwrapped(udata, payload, info.packet_length, 0,
462
- ((pos[0] >> 7) & 1), 0, ((pos[0] >> 4) & 7));
463
- break;
464
- case 1:
465
- /* text frame */
466
- websocket_on_unwrapped(udata, payload, info.packet_length, 1,
467
- ((pos[0] >> 7) & 1), 1, ((pos[0] >> 4) & 7));
468
- break;
469
- case 2:
470
- /* data frame */
471
- websocket_on_unwrapped(udata, payload, info.packet_length, 1,
472
- ((pos[0] >> 7) & 1), 0, ((pos[0] >> 4) & 7));
473
- break;
474
- case 8:
475
- /* close frame */
476
- websocket_on_protocol_close(udata);
477
- break;
478
- case 9:
479
- /* ping frame */
480
- websocket_on_protocol_ping(udata, payload, info.packet_length);
481
- break;
482
- case 10:
483
- /* pong frame */
484
- websocket_on_protocol_pong(udata, payload, info.packet_length);
485
- break;
486
- default:
487
- #if DEBUG
488
- fprintf(stderr, "ERROR: WebSocket protocol error - unknown opcode %u\n",
489
- (unsigned int)(pos[0] & 15));
490
- #endif
491
- websocket_on_protocol_error(udata);
492
- }
493
- /* step forward */
494
- reminder = reminder - (info.head_length + info.packet_length);
495
- if (!reminder)
496
- return 0;
497
- pos += info.head_length + info.packet_length;
498
- info = websocket_buffer_peek(pos, reminder);
499
- }
500
- /* reset buffer state - support pipelining */
501
- memmove(buffer, (uint8_t *)buffer + len - reminder, reminder);
502
- return reminder;
503
- }
504
-
505
- #endif
1
+ /*
2
+ copyright: Boaz Segev, 2017-2019
3
+ license: MIT
4
+
5
+ Feel free to copy, use and enjoy according to the license specified.
6
+ */
7
+ #ifndef H_WEBSOCKET_PARSER_H
8
+ /**\file
9
+
10
+ A single file WebSocket message parser and WebSocket message wrapper, decoupled
11
+ from any IO layer.
12
+
13
+ Notice that this header file library includes static funnction declerations that
14
+ must be implemented by the including file (the callbacks).
15
+
16
+ */
17
+ #define H_WEBSOCKET_PARSER_H
18
+ #include <stdint.h>
19
+ #include <stdlib.h>
20
+ #include <string.h>
21
+ #if DEBUG
22
+ #include <stdio.h>
23
+ #endif
24
+ /* *****************************************************************************
25
+ API - Message Wrapping
26
+ ***************************************************************************** */
27
+
28
+ /** returns the length of the buffer required to wrap a message `len` long */
29
+ static inline __attribute__((unused)) uint64_t
30
+ websocket_wrapped_len(uint64_t len);
31
+
32
+ /**
33
+ * Wraps a WebSocket server message and writes it to the target buffer.
34
+ *
35
+ * The `first` and `last` flags can be used to support message fragmentation.
36
+ *
37
+ * * target: the target buffer to write to.
38
+ * * msg: the message to be wrapped.
39
+ * * len: the message length.
40
+ * * opcode: set to 1 for UTF-8 message, 2 for binary, etc'.
41
+ * * first: set to 1 if `msg` points the beginning of the message.
42
+ * * last: set to 1 if `msg + len` ends the message.
43
+ * * client: set to 1 to use client mode (data masking).
44
+ *
45
+ * Further opcode values:
46
+ * * %x0 denotes a continuation frame
47
+ * * %x1 denotes a text frame
48
+ * * %x2 denotes a binary frame
49
+ * * %x3-7 are reserved for further non-control frames
50
+ * * %x8 denotes a connection close
51
+ * * %x9 denotes a ping
52
+ * * %xA denotes a pong
53
+ * * %xB-F are reserved for further control frames
54
+ *
55
+ * Returns the number of bytes written. Always `websocket_wrapped_len(len)`
56
+ */
57
+ inline static uint64_t __attribute__((unused))
58
+ websocket_server_wrap(void *target, void *msg, uint64_t len,
59
+ unsigned char opcode, unsigned char first,
60
+ unsigned char last, unsigned char rsv);
61
+
62
+ /**
63
+ * Wraps a WebSocket client message and writes it to the target buffer.
64
+ *
65
+ * The `first` and `last` flags can be used to support message fragmentation.
66
+ *
67
+ * * target: the target buffer to write to.
68
+ * * msg: the message to be wrapped.
69
+ * * len: the message length.
70
+ * * opcode: set to 1 for UTF-8 message, 2 for binary, etc'.
71
+ * * first: set to 1 if `msg` points the beginning of the message.
72
+ * * last: set to 1 if `msg + len` ends the message.
73
+ * * client: set to 1 to use client mode (data masking).
74
+ *
75
+ * Returns the number of bytes written. Always `websocket_wrapped_len(len) + 4`
76
+ */
77
+ inline static __attribute__((unused)) uint64_t
78
+ websocket_client_wrap(void *target, void *msg, uint64_t len,
79
+ unsigned char opcode, unsigned char first,
80
+ unsigned char last, unsigned char rsv);
81
+
82
+ /* *****************************************************************************
83
+ Callbacks - Required functions that must be inplemented to use this header
84
+ ***************************************************************************** */
85
+
86
+ static void websocket_on_unwrapped(void *udata, void *msg, uint64_t len,
87
+ char first, char last, char text,
88
+ unsigned char rsv);
89
+ static void websocket_on_protocol_ping(void *udata, void *msg, uint64_t len);
90
+ static void websocket_on_protocol_pong(void *udata, void *msg, uint64_t len);
91
+ static void websocket_on_protocol_close(void *udata);
92
+ static void websocket_on_protocol_error(void *udata);
93
+
94
+ /* *****************************************************************************
95
+ API - Parsing (unwrapping)
96
+ ***************************************************************************** */
97
+
98
+ /** the returned value for `websocket_buffer_required` */
99
+ struct websocket_packet_info_s {
100
+ /** the expected packet length */
101
+ uint64_t packet_length;
102
+ /** the packet's "head" size (before the data) */
103
+ uint8_t head_length;
104
+ /** a flag indicating if the packet is masked */
105
+ uint8_t masked;
106
+ };
107
+
108
+ /**
109
+ * Returns all known information regarding the upcoming message.
110
+ *
111
+ * @returns a struct websocket_packet_info_s.
112
+ *
113
+ * On protocol error, the `head_length` value is 0 (no valid head detected).
114
+ */
115
+ inline static struct websocket_packet_info_s
116
+ websocket_buffer_peek(void *buffer, uint64_t len);
117
+
118
+ /**
119
+ * Consumes the data in the buffer, calling any callbacks required.
120
+ *
121
+ * Returns the remaining data in the existing buffer (can be 0).
122
+ *
123
+ * Notice: if there's any data in the buffer that can't be parsed
124
+ * just yet, `memmove` is used to place the data at the beginning of the buffer.
125
+ */
126
+ inline static __attribute__((unused)) uint64_t
127
+ websocket_consume(void *buffer, uint64_t len, void *udata,
128
+ uint8_t require_masking);
129
+
130
+ /* *****************************************************************************
131
+ API - Internal Helpers
132
+ ***************************************************************************** */
133
+
134
+ /** used internally to mask and unmask client messages. */
135
+ inline static void websocket_xmask(void *msg, uint64_t len, uint32_t mask);
136
+
137
+ /* *****************************************************************************
138
+
139
+ Implementation
140
+
141
+ ***************************************************************************** */
142
+
143
+ /* *****************************************************************************
144
+ Message masking
145
+ ***************************************************************************** */
146
+ /** used internally to mask and unmask client messages. */
147
+ void websocket_xmask(void *msg, uint64_t len, uint32_t mask) {
148
+ if (len > 7) {
149
+ { /* XOR any unaligned memory (4 byte alignment) */
150
+ const uintptr_t offset = 4 - ((uintptr_t)msg & 3);
151
+ switch (offset) {
152
+ case 3:
153
+ ((uint8_t *)msg)[2] ^= ((uint8_t *)(&mask))[2];
154
+ /* fallthrough */
155
+ case 2:
156
+ ((uint8_t *)msg)[1] ^= ((uint8_t *)(&mask))[1];
157
+ /* fallthrough */
158
+ case 1:
159
+ ((uint8_t *)msg)[0] ^= ((uint8_t *)(&mask))[0];
160
+ /* rotate mask and move pointer to first 4 byte alignment */
161
+ uint64_t comb = mask | ((uint64_t)mask << 32);
162
+ ((uint8_t *)(&mask))[0] = ((uint8_t *)(&comb))[0 + offset];
163
+ ((uint8_t *)(&mask))[1] = ((uint8_t *)(&comb))[1 + offset];
164
+ ((uint8_t *)(&mask))[2] = ((uint8_t *)(&comb))[2 + offset];
165
+ ((uint8_t *)(&mask))[3] = ((uint8_t *)(&comb))[3 + offset];
166
+ msg = (void *)((uintptr_t)msg + offset);
167
+ len -= offset;
168
+ }
169
+ }
170
+ #if UINTPTR_MAX <= 0xFFFFFFFF
171
+ /* handle 4 byte XOR alignment in 32 bit mnachine*/
172
+ while (len >= 4) {
173
+ *((uint32_t *)msg) ^= mask;
174
+ len -= 4;
175
+ msg = (void *)((uintptr_t)msg + 4);
176
+ }
177
+ #else
178
+ /* handle first 4 byte XOR alignment and move on to 64 bits */
179
+ if ((uintptr_t)msg & 7) {
180
+ *((uint32_t *)msg) ^= mask;
181
+ len -= 4;
182
+ msg = (void *)((uintptr_t)msg + 4);
183
+ }
184
+ /* intrinsic / XOR by 8 byte block, memory aligned */
185
+ const uint64_t xmask = (((uint64_t)mask) << 32) | mask;
186
+ while (len >= 8) {
187
+ *((uint64_t *)msg) ^= xmask;
188
+ len -= 8;
189
+ msg = (void *)((uintptr_t)msg + 8);
190
+ }
191
+ #endif
192
+ }
193
+
194
+ /* XOR any leftover bytes (might be non aligned) */
195
+ switch (len) {
196
+ case 7:
197
+ ((uint8_t *)msg)[6] ^= ((uint8_t *)(&mask))[2];
198
+ /* fallthrough */
199
+ case 6:
200
+ ((uint8_t *)msg)[5] ^= ((uint8_t *)(&mask))[1];
201
+ /* fallthrough */
202
+ case 5:
203
+ ((uint8_t *)msg)[4] ^= ((uint8_t *)(&mask))[0];
204
+ /* fallthrough */
205
+ case 4:
206
+ ((uint8_t *)msg)[3] ^= ((uint8_t *)(&mask))[3];
207
+ /* fallthrough */
208
+ case 3:
209
+ ((uint8_t *)msg)[2] ^= ((uint8_t *)(&mask))[2];
210
+ /* fallthrough */
211
+ case 2:
212
+ ((uint8_t *)msg)[1] ^= ((uint8_t *)(&mask))[1];
213
+ /* fallthrough */
214
+ case 1:
215
+ ((uint8_t *)msg)[0] ^= ((uint8_t *)(&mask))[0];
216
+ /* fallthrough */
217
+ }
218
+ }
219
+
220
+ /* *****************************************************************************
221
+ Message wrapping
222
+ ***************************************************************************** */
223
+
224
+ /** Converts an unaligned network ordered byte stream to a 16 bit number. */
225
+ #define websocket_str2u16(c) \
226
+ ((uint16_t)(((uint16_t)(((uint8_t *)(c))[0]) << 8) | \
227
+ (uint16_t)(((uint8_t *)(c))[1])))
228
+
229
+ /** Converts an unaligned network ordered byte stream to a 64 bit number. */
230
+ #define websocket_str2u64(c) \
231
+ ((uint64_t)((((uint64_t)((uint8_t *)(c))[0]) << 56) | \
232
+ (((uint64_t)((uint8_t *)(c))[1]) << 48) | \
233
+ (((uint64_t)((uint8_t *)(c))[2]) << 40) | \
234
+ (((uint64_t)((uint8_t *)(c))[3]) << 32) | \
235
+ (((uint64_t)((uint8_t *)(c))[4]) << 24) | \
236
+ (((uint64_t)((uint8_t *)(c))[5]) << 16) | \
237
+ (((uint64_t)((uint8_t *)(c))[6]) << 8) | (((uint8_t *)(c))[7])))
238
+
239
+ /** Writes a local 16 bit number to an unaligned buffer in network order. */
240
+ #define websocket_u2str16(buffer, i) \
241
+ do { \
242
+ ((uint8_t *)(buffer))[0] = ((uint16_t)(i) >> 8) & 0xFF; \
243
+ ((uint8_t *)(buffer))[1] = ((uint16_t)(i)) & 0xFF; \
244
+ } while (0);
245
+
246
+ /** Writes a local 64 bit number to an unaligned buffer in network order. */
247
+ #define websocket_u2str64(buffer, i) \
248
+ do { \
249
+ ((uint8_t *)(buffer))[0] = ((uint64_t)(i) >> 56) & 0xFF; \
250
+ ((uint8_t *)(buffer))[1] = ((uint64_t)(i) >> 48) & 0xFF; \
251
+ ((uint8_t *)(buffer))[2] = ((uint64_t)(i) >> 40) & 0xFF; \
252
+ ((uint8_t *)(buffer))[3] = ((uint64_t)(i) >> 32) & 0xFF; \
253
+ ((uint8_t *)(buffer))[4] = ((uint64_t)(i) >> 24) & 0xFF; \
254
+ ((uint8_t *)(buffer))[5] = ((uint64_t)(i) >> 16) & 0xFF; \
255
+ ((uint8_t *)(buffer))[6] = ((uint64_t)(i) >> 8) & 0xFF; \
256
+ ((uint8_t *)(buffer))[7] = ((uint64_t)(i)) & 0xFF; \
257
+ } while (0);
258
+
259
+ /** returns the length of the buffer required to wrap a message `len` long */
260
+ static inline uint64_t websocket_wrapped_len(uint64_t len) {
261
+ if (len < 126)
262
+ return len + 2;
263
+ if (len < (1UL << 16))
264
+ return len + 4;
265
+ return len + 10;
266
+ }
267
+
268
+ /**
269
+ * Wraps a WebSocket server message and writes it to the target buffer.
270
+ *
271
+ * The `first` and `last` flags can be used to support message fragmentation.
272
+ *
273
+ * * target: the target buffer to write to.
274
+ * * msg: the message to be wrapped.
275
+ * * len: the message length.
276
+ * * opcode: set to 1 for UTF-8 message, 2 for binary, etc'.
277
+ * * first: set to 1 if `msg` points the beginning of the message.
278
+ * * last: set to 1 if `msg + len` ends the message.
279
+ * * client: set to 1 to use client mode (data masking).
280
+ *
281
+ * Further opcode values:
282
+ * * %x0 denotes a continuation frame
283
+ * * %x1 denotes a text frame
284
+ * * %x2 denotes a binary frame
285
+ * * %x3-7 are reserved for further non-control frames
286
+ * * %x8 denotes a connection close
287
+ * * %x9 denotes a ping
288
+ * * %xA denotes a pong
289
+ * * %xB-F are reserved for further control frames
290
+ *
291
+ * Returns the number of bytes written. Always `websocket_wrapped_len(len)`
292
+ */
293
+ static uint64_t websocket_server_wrap(void *target, void *msg, uint64_t len,
294
+ unsigned char opcode, unsigned char first,
295
+ unsigned char last, unsigned char rsv) {
296
+ ((uint8_t *)target)[0] = 0 |
297
+ /* opcode */ (((first ? opcode : 0) & 15)) |
298
+ /* rsv */ ((rsv & 7) << 4) |
299
+ /*fin*/ ((last & 1) << 7);
300
+ if (len < 126) {
301
+ ((uint8_t *)target)[1] = len;
302
+ memcpy(((uint8_t *)target) + 2, msg, len);
303
+ return len + 2;
304
+ } else if (len < (1UL << 16)) {
305
+ /* head is 4 bytes */
306
+ ((uint8_t *)target)[1] = 126;
307
+ websocket_u2str16(((uint8_t *)target + 2), len);
308
+ memcpy((uint8_t *)target + 4, msg, len);
309
+ return len + 4;
310
+ }
311
+ /* Really Long Message */
312
+ ((uint8_t *)target)[1] = 127;
313
+ websocket_u2str64(((uint8_t *)target + 2), len);
314
+ memcpy((uint8_t *)target + 10, msg, len);
315
+ return len + 10;
316
+ }
317
+
318
+ /**
319
+ * Wraps a WebSocket client message and writes it to the target buffer.
320
+ *
321
+ * The `first` and `last` flags can be used to support message fragmentation.
322
+ *
323
+ * * target: the target buffer to write to.
324
+ * * msg: the message to be wrapped.
325
+ * * len: the message length.
326
+ * * opcode: set to 1 for UTF-8 message, 2 for binary, etc'.
327
+ * * first: set to 1 if `msg` points the beginning of the message.
328
+ * * last: set to 1 if `msg + len` ends the message.
329
+ *
330
+ * Returns the number of bytes written. Always `websocket_wrapped_len(len) +
331
+ * 4`
332
+ */
333
+ static uint64_t websocket_client_wrap(void *target, void *msg, uint64_t len,
334
+ unsigned char opcode, unsigned char first,
335
+ unsigned char last, unsigned char rsv) {
336
+ uint32_t mask = rand() | 0x01020408;
337
+ ((uint8_t *)target)[0] = 0 |
338
+ /* opcode */ (((first ? opcode : 0) & 15)) |
339
+ /* rsv */ ((rsv & 7) << 4) |
340
+ /*fin*/ ((last & 1) << 7);
341
+ if (len < 126) {
342
+ ((uint8_t *)target)[1] = len | 128;
343
+ ((uint8_t *)target)[2] = ((uint8_t *)(&mask))[0];
344
+ ((uint8_t *)target)[3] = ((uint8_t *)(&mask))[1];
345
+ ((uint8_t *)target)[4] = ((uint8_t *)(&mask))[2];
346
+ ((uint8_t *)target)[5] = ((uint8_t *)(&mask))[3];
347
+ memcpy(((uint8_t *)target) + 6, msg, len);
348
+ websocket_xmask((uint8_t *)target + 6, len, mask);
349
+ return len + 6;
350
+ } else if (len < (1UL << 16)) {
351
+ /* head is 4 bytes */
352
+ ((uint8_t *)target)[1] = 126 | 128;
353
+ websocket_u2str16(((uint8_t *)target + 2), len);
354
+ ((uint8_t *)target)[4] = ((uint8_t *)(&mask))[0];
355
+ ((uint8_t *)target)[5] = ((uint8_t *)(&mask))[1];
356
+ ((uint8_t *)target)[6] = ((uint8_t *)(&mask))[2];
357
+ ((uint8_t *)target)[7] = ((uint8_t *)(&mask))[3];
358
+ memcpy((uint8_t *)target + 8, msg, len);
359
+ websocket_xmask((uint8_t *)target + 8, len, mask);
360
+ return len + 8;
361
+ }
362
+ /* Really Long Message */
363
+ ((uint8_t *)target)[1] = 255;
364
+ websocket_u2str64(((uint8_t *)target + 2), len);
365
+ ((uint8_t *)target)[10] = ((uint8_t *)(&mask))[0];
366
+ ((uint8_t *)target)[11] = ((uint8_t *)(&mask))[1];
367
+ ((uint8_t *)target)[12] = ((uint8_t *)(&mask))[2];
368
+ ((uint8_t *)target)[13] = ((uint8_t *)(&mask))[3];
369
+ memcpy((uint8_t *)target + 14, msg, len);
370
+ websocket_xmask((uint8_t *)target + 14, len, mask);
371
+ return len + 14;
372
+ }
373
+
374
+ /* *****************************************************************************
375
+ Message unwrapping
376
+ ***************************************************************************** */
377
+
378
+ /**
379
+ * Returns all known information regarding the upcoming message.
380
+ *
381
+ * @returns a struct websocket_packet_info_s.
382
+ *
383
+ * On protocol error, the `head_length` value is 0 (no valid head detected).
384
+ */
385
+ inline static struct websocket_packet_info_s
386
+ websocket_buffer_peek(void *buffer, uint64_t len) {
387
+ if (len < 2) {
388
+ const struct websocket_packet_info_s info = {0 /* packet */, 2 /* head */,
389
+ 0 /* masked? */};
390
+ return info;
391
+ }
392
+ const uint8_t mask_f = (((uint8_t *)buffer)[1] >> 7) & 1;
393
+ const uint8_t mask_l = (mask_f << 2);
394
+ uint8_t len_indicator = ((((uint8_t *)buffer)[1]) & 127);
395
+ switch (len_indicator) {
396
+ case 126:
397
+ if (len < 4)
398
+ return (struct websocket_packet_info_s){0, (uint8_t)(4 + mask_l), mask_f};
399
+ return (struct websocket_packet_info_s){
400
+ (uint64_t)websocket_str2u16(((uint8_t *)buffer + 2)),
401
+ (uint8_t)(4 + mask_l), mask_f};
402
+ case 127:
403
+ if (len < 10)
404
+ return (struct websocket_packet_info_s){0, (uint8_t)(10 + mask_l),
405
+ mask_f};
406
+ {
407
+ uint64_t msg_len = websocket_str2u64(((uint8_t *)buffer + 2));
408
+ if (msg_len >> 62)
409
+ return (struct websocket_packet_info_s){0, 0, 0};
410
+ return (struct websocket_packet_info_s){msg_len, (uint8_t)(10 + mask_l),
411
+ mask_f};
412
+ }
413
+ default:
414
+ return (struct websocket_packet_info_s){len_indicator,
415
+ (uint8_t)(2 + mask_l), mask_f};
416
+ }
417
+ }
418
+
419
+ /**
420
+ * Consumes the data in the buffer, calling any callbacks required.
421
+ *
422
+ * Returns the remaining data in the existing buffer (can be 0).
423
+ */
424
+ static uint64_t websocket_consume(void *buffer, uint64_t len, void *udata,
425
+ uint8_t require_masking) {
426
+ volatile struct websocket_packet_info_s info =
427
+ websocket_buffer_peek(buffer, len);
428
+ if (!info.head_length) {
429
+ #if DEBUG
430
+ fprintf(stderr, "ERROR: WebSocket protocol error - malicious header.\n");
431
+ #endif
432
+ websocket_on_protocol_error(udata);
433
+ return 0;
434
+ }
435
+ if (info.head_length + info.packet_length > len)
436
+ return len;
437
+ uint64_t reminder = len;
438
+ uint8_t *pos = (uint8_t *)buffer;
439
+ while (info.head_length + info.packet_length <= reminder) {
440
+ /* parse head */
441
+ void *payload = (void *)(pos + info.head_length);
442
+ /* unmask? */
443
+ if (info.masked) {
444
+ /* masked */
445
+ uint32_t mask; // = ((uint32_t *)payload)[-1];
446
+ ((uint8_t *)(&mask))[0] = ((uint8_t *)(payload))[-4];
447
+ ((uint8_t *)(&mask))[1] = ((uint8_t *)(payload))[-3];
448
+ ((uint8_t *)(&mask))[2] = ((uint8_t *)(payload))[-2];
449
+ ((uint8_t *)(&mask))[3] = ((uint8_t *)(payload))[-1];
450
+ websocket_xmask(payload, info.packet_length, mask);
451
+ } else if (require_masking && info.packet_length) {
452
+ #if DEBUG
453
+ fprintf(stderr, "ERROR: WebSocket protocol error - unmasked data.\n");
454
+ #endif
455
+ websocket_on_protocol_error(udata);
456
+ }
457
+ /* call callback */
458
+ switch (pos[0] & 15) {
459
+ case 0:
460
+ /* continuation frame */
461
+ websocket_on_unwrapped(udata, payload, info.packet_length, 0,
462
+ ((pos[0] >> 7) & 1), 0, ((pos[0] >> 4) & 7));
463
+ break;
464
+ case 1:
465
+ /* text frame */
466
+ websocket_on_unwrapped(udata, payload, info.packet_length, 1,
467
+ ((pos[0] >> 7) & 1), 1, ((pos[0] >> 4) & 7));
468
+ break;
469
+ case 2:
470
+ /* data frame */
471
+ websocket_on_unwrapped(udata, payload, info.packet_length, 1,
472
+ ((pos[0] >> 7) & 1), 0, ((pos[0] >> 4) & 7));
473
+ break;
474
+ case 8:
475
+ /* close frame */
476
+ websocket_on_protocol_close(udata);
477
+ break;
478
+ case 9:
479
+ /* ping frame */
480
+ websocket_on_protocol_ping(udata, payload, info.packet_length);
481
+ break;
482
+ case 10:
483
+ /* pong frame */
484
+ websocket_on_protocol_pong(udata, payload, info.packet_length);
485
+ break;
486
+ default:
487
+ #if DEBUG
488
+ fprintf(stderr, "ERROR: WebSocket protocol error - unknown opcode %u\n",
489
+ (unsigned int)(pos[0] & 15));
490
+ #endif
491
+ websocket_on_protocol_error(udata);
492
+ }
493
+ /* step forward */
494
+ reminder = reminder - (info.head_length + info.packet_length);
495
+ if (!reminder)
496
+ return 0;
497
+ pos += info.head_length + info.packet_length;
498
+ info = websocket_buffer_peek(pos, reminder);
499
+ }
500
+ /* reset buffer state - support pipelining */
501
+ memmove(buffer, (uint8_t *)buffer + len - reminder, reminder);
502
+ return reminder;
503
+ }
504
+
505
+ #endif