diff options
Diffstat (limited to 'src/microhttpd_ws/mhd_websocket.c')
-rw-r--r-- | src/microhttpd_ws/mhd_websocket.c | 587 |
1 files changed, 478 insertions, 109 deletions
diff --git a/src/microhttpd_ws/mhd_websocket.c b/src/microhttpd_ws/mhd_websocket.c index ea1a5bda..da787f7d 100644 --- a/src/microhttpd_ws/mhd_websocket.c +++ b/src/microhttpd_ws/mhd_websocket.c | |||
@@ -36,6 +36,10 @@ struct MHD_WebSocketStream | |||
36 | MHD_WebSocketReallocCallback realloc; | 36 | MHD_WebSocketReallocCallback realloc; |
37 | /* The function pointer to free for payload (can be used to use different memory management) */ | 37 | /* The function pointer to free for payload (can be used to use different memory management) */ |
38 | MHD_WebSocketFreeCallback free; | 38 | MHD_WebSocketFreeCallback free; |
39 | /* A closure for the random number generator (only used for client mode; usually not required) */ | ||
40 | void* cls_rng; | ||
41 | /* The random number generator (only used for client mode; usually not required) */ | ||
42 | MHD_WebSocketRandomNumberGenerator rng; | ||
39 | /* The flags specified upon initialization. It may alter the behavior of decoding/encoding */ | 43 | /* The flags specified upon initialization. It may alter the behavior of decoding/encoding */ |
40 | int flags; | 44 | int flags; |
41 | /* The current step for the decoder. 0 means start of a frame. */ | 45 | /* The current step for the decoder. 0 means start of a frame. */ |
@@ -122,13 +126,6 @@ enum MHD_WebSocket_UTF8Result | |||
122 | MHD_WebSocket_UTF8Result_Incomplete = 2 | 126 | MHD_WebSocket_UTF8Result_Incomplete = 2 |
123 | }; | 127 | }; |
124 | 128 | ||
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 | |||
132 | static void | 129 | static void |
133 | MHD_websocket_copy_payload (char*dst, | 130 | MHD_websocket_copy_payload (char*dst, |
134 | const char*src, | 131 | const char*src, |
@@ -142,12 +139,12 @@ MHD_websocket_check_utf8 (const char*buf, | |||
142 | int*utf8_step, | 139 | int*utf8_step, |
143 | size_t*buf_offset); | 140 | size_t*buf_offset); |
144 | 141 | ||
145 | static int | 142 | static enum MHD_WEBSOCKET_STATUS |
146 | MHD_websocket_decode_header_complete (struct MHD_WebSocketStream*ws, | 143 | MHD_websocket_decode_header_complete (struct MHD_WebSocketStream*ws, |
147 | char**payload, | 144 | char**payload, |
148 | size_t*payload_len); | 145 | size_t*payload_len); |
149 | 146 | ||
150 | static int | 147 | static enum MHD_WEBSOCKET_STATUS |
151 | MHD_websocket_decode_payload_complete (struct MHD_WebSocketStream*ws, | 148 | MHD_websocket_decode_payload_complete (struct MHD_WebSocketStream*ws, |
152 | char**payload, | 149 | char**payload, |
153 | size_t*payload_len); | 150 | size_t*payload_len); |
@@ -158,7 +155,7 @@ static char | |||
158 | MHD_websocket_encode_overhead_size (struct MHD_WebSocketStream *ws, | 155 | MHD_websocket_encode_overhead_size (struct MHD_WebSocketStream *ws, |
159 | size_t payload_len); | 156 | size_t payload_len); |
160 | 157 | ||
161 | static int | 158 | static enum MHD_WEBSOCKET_STATUS |
162 | MHD_websocket_encode_data (struct MHD_WebSocketStream*ws, | 159 | MHD_websocket_encode_data (struct MHD_WebSocketStream*ws, |
163 | const char*payload, | 160 | const char*payload, |
164 | size_t payload_len, | 161 | size_t payload_len, |
@@ -167,7 +164,7 @@ MHD_websocket_encode_data (struct MHD_WebSocketStream*ws, | |||
167 | size_t*frame_len, | 164 | size_t*frame_len, |
168 | char opcode); | 165 | char opcode); |
169 | 166 | ||
170 | static int | 167 | static enum MHD_WEBSOCKET_STATUS |
171 | MHD_websocket_encode_ping_pong (struct MHD_WebSocketStream*ws, | 168 | MHD_websocket_encode_ping_pong (struct MHD_WebSocketStream*ws, |
172 | const char*payload, | 169 | const char*payload, |
173 | size_t payload_len, | 170 | size_t payload_len, |
@@ -176,35 +173,338 @@ MHD_websocket_encode_ping_pong (struct MHD_WebSocketStream*ws, | |||
176 | char opcode); | 173 | char opcode); |
177 | 174 | ||
178 | static uint32_t | 175 | static uint32_t |
179 | MHD_websocket_generate_mask (); | 176 | MHD_websocket_generate_mask (struct MHD_WebSocketStream*ws); |
177 | |||
178 | static uint16_t | ||
179 | MHD_htons (uint16_t value); | ||
180 | |||
181 | static uint64_t | ||
182 | MHD_htonll (uint64_t value); | ||
183 | |||
184 | |||
185 | /** | ||
186 | * Checks whether the HTTP version is 1.1 or above. | ||
187 | */ | ||
188 | _MHD_EXTERN enum MHD_WEBSOCKET_STATUS | ||
189 | MHD_websocket_check_http_version (const char* http_version) | ||
190 | { | ||
191 | /* validate parameters */ | ||
192 | if (NULL == http_version) | ||
193 | { | ||
194 | /* Like with the other check routines, */ | ||
195 | /* NULL is threated as "value not given" and not as parameter error */ | ||
196 | return MHD_WEBSOCKET_STATUS_NO_WEBSOCKET_HANDSHAKE_HEADER; | ||
197 | } | ||
198 | |||
199 | /* Check whether the version has a valid format */ | ||
200 | /* RFC 1945 3.1: The format must be "HTTP/x.x" where x is */ | ||
201 | /* any digit and must appear at least once */ | ||
202 | if ('H' != http_version[0] || | ||
203 | 'T' != http_version[1] || | ||
204 | 'T' != http_version[2] || | ||
205 | 'P' != http_version[3] || | ||
206 | '/' != http_version[4]) | ||
207 | { | ||
208 | return MHD_WEBSOCKET_STATUS_NO_WEBSOCKET_HANDSHAKE_HEADER; | ||
209 | } | ||
210 | |||
211 | /* Find the major and minor part of the version */ | ||
212 | /* RFC 1945 3.1: Both numbers must be threated as separate integers. */ | ||
213 | /* Leading zeros must be ignored and both integers may have multiple digits */ | ||
214 | const char* major = NULL; | ||
215 | const char* dot = NULL; | ||
216 | size_t i = 5; | ||
217 | for (;;) | ||
218 | { | ||
219 | char c = http_version[i]; | ||
220 | if ('0' <= c && '9' >= c) | ||
221 | { | ||
222 | if (NULL == major || | ||
223 | (http_version + i == major + 1 && '0' == *major) ) | ||
224 | { | ||
225 | major = http_version + i; | ||
226 | } | ||
227 | ++i; | ||
228 | } | ||
229 | else if ('.' == http_version[i]) | ||
230 | { | ||
231 | dot = http_version + i; | ||
232 | ++i; | ||
233 | break; | ||
234 | } | ||
235 | else | ||
236 | { | ||
237 | return MHD_WEBSOCKET_STATUS_NO_WEBSOCKET_HANDSHAKE_HEADER; | ||
238 | } | ||
239 | } | ||
240 | const char* minor = NULL; | ||
241 | const char* end = NULL; | ||
242 | for (;;) | ||
243 | { | ||
244 | char c = http_version[i]; | ||
245 | if ('0' <= c && '9' >= c) | ||
246 | { | ||
247 | if (NULL == minor || | ||
248 | (http_version + i == minor + 1 && '0' == *minor) ) | ||
249 | { | ||
250 | minor = http_version + i; | ||
251 | } | ||
252 | ++i; | ||
253 | } | ||
254 | else if (0 == c) | ||
255 | { | ||
256 | end = http_version + i; | ||
257 | break; | ||
258 | } | ||
259 | else | ||
260 | { | ||
261 | return MHD_WEBSOCKET_STATUS_NO_WEBSOCKET_HANDSHAKE_HEADER; | ||
262 | } | ||
263 | } | ||
264 | if (NULL == major || NULL == dot || NULL == minor || NULL == end) | ||
265 | { | ||
266 | return MHD_WEBSOCKET_STATUS_NO_WEBSOCKET_HANDSHAKE_HEADER; | ||
267 | } | ||
268 | if (2 <= dot - major || '2' <= *major || | ||
269 | ('1' == *major && (2 <= end - minor || '1' <= *minor)) ) | ||
270 | { | ||
271 | return MHD_WEBSOCKET_STATUS_OK; | ||
272 | } | ||
273 | |||
274 | return MHD_WEBSOCKET_STATUS_NO_WEBSOCKET_HANDSHAKE_HEADER; | ||
275 | } | ||
276 | |||
277 | |||
278 | /** | ||
279 | * Checks whether the "Connection" request header has the 'Upgrade' token. | ||
280 | */ | ||
281 | _MHD_EXTERN enum MHD_WEBSOCKET_STATUS | ||
282 | MHD_websocket_check_connection_header (const char* connection_header) | ||
283 | { | ||
284 | /* validate parameters */ | ||
285 | if (NULL == connection_header) | ||
286 | { | ||
287 | /* To be compatible with the return value */ | ||
288 | /* of MHD_lookup_connection_value, */ | ||
289 | /* NULL is threated as "value not given" and not as parameter error */ | ||
290 | return MHD_WEBSOCKET_STATUS_NO_WEBSOCKET_HANDSHAKE_HEADER; | ||
291 | } | ||
292 | |||
293 | /* Check whether the Connection includes an Upgrade token */ | ||
294 | /* RFC 7230 6.1: Multiple tokens may appear. */ | ||
295 | /* RFC 7230 3.2.6: Tokens are comma separated */ | ||
296 | const char* token_start = NULL; | ||
297 | const char* token_end = NULL; | ||
298 | for(size_t i = 0; ; ++i) | ||
299 | { | ||
300 | char c = connection_header[i]; | ||
301 | |||
302 | /* RFC 7230 3.2.6: The list of allowed characters is a token is: */ | ||
303 | /* "!" / "#" / "$" / "%" / "&" / "'" / "*" / */ | ||
304 | /* "+" / "-" / "." / "^" / "_" / "`" / "|" / "~" */ | ||
305 | /* DIGIT / ALPHA */ | ||
306 | if ('!' == c || '#' == c || '$' == c || '%' == c || | ||
307 | '&' == c || '\'' == c || '*' == c || | ||
308 | '+' == c || '-' == c || '.' == c || '^' == c || | ||
309 | '_' == c || '`' == c || '|' == c || '~' == c || | ||
310 | ('0' <= c && '9' >= c) || | ||
311 | ('A' <= c && 'Z' >= c) || ('a' <= c && 'z' >= c) ) | ||
312 | { | ||
313 | /* This is a valid token character */ | ||
314 | if (NULL == token_start) | ||
315 | { | ||
316 | token_start = connection_header + i; | ||
317 | } | ||
318 | token_end = connection_header + i + 1; | ||
319 | } | ||
320 | else if (' ' == c || '\t' == c) | ||
321 | { | ||
322 | /* White-spaces around tokens will be ignored */ | ||
323 | } | ||
324 | else if (',' == c || 0 == c) | ||
325 | { | ||
326 | /* Check the token (case-insensitive) */ | ||
327 | if (NULL != token_start) | ||
328 | { | ||
329 | if ( 7 == (token_end - token_start) ) | ||
330 | { | ||
331 | if ( ('U' == token_start[0] || 'u' == token_start[0]) && | ||
332 | ('P' == token_start[1] || 'p' == token_start[1]) && | ||
333 | ('G' == token_start[2] || 'g' == token_start[2]) && | ||
334 | ('R' == token_start[3] || 'r' == token_start[3]) && | ||
335 | ('A' == token_start[4] || 'a' == token_start[4]) && | ||
336 | ('D' == token_start[5] || 'd' == token_start[5]) && | ||
337 | ('E' == token_start[6] || 'e' == token_start[6]) ) | ||
338 | { | ||
339 | /* The token equals to "Upgrade" */ | ||
340 | return MHD_WEBSOCKET_STATUS_OK; | ||
341 | } | ||
342 | } | ||
343 | } | ||
344 | if (0 == c) | ||
345 | { | ||
346 | break; | ||
347 | } | ||
348 | token_start = NULL; | ||
349 | token_end = NULL; | ||
350 | } | ||
351 | else | ||
352 | { | ||
353 | /* RFC 7230 3.2.6: Other characters are not allowed */ | ||
354 | return MHD_WEBSOCKET_STATUS_NO_WEBSOCKET_HANDSHAKE_HEADER; | ||
355 | } | ||
356 | } | ||
357 | return MHD_WEBSOCKET_STATUS_NO_WEBSOCKET_HANDSHAKE_HEADER; | ||
358 | } | ||
359 | |||
360 | |||
361 | /** | ||
362 | * Checks whether the "Upgrade" request header has the "websocket" keyword. | ||
363 | */ | ||
364 | _MHD_EXTERN enum MHD_WEBSOCKET_STATUS | ||
365 | MHD_websocket_check_upgrade_header (const char* upgrade_header) | ||
366 | { | ||
367 | /* validate parameters */ | ||
368 | if (NULL == upgrade_header) | ||
369 | { | ||
370 | /* To be compatible with the return value */ | ||
371 | /* of MHD_lookup_connection_value, */ | ||
372 | /* NULL is threated as "value not given" and not as parameter error */ | ||
373 | return MHD_WEBSOCKET_STATUS_NO_WEBSOCKET_HANDSHAKE_HEADER; | ||
374 | } | ||
375 | |||
376 | /* Check whether the Connection includes an Upgrade token */ | ||
377 | /* RFC 7230 6.1: Multiple tokens may appear. */ | ||
378 | /* RFC 7230 3.2.6: Tokens are comma separated */ | ||
379 | const char* keyword_start = NULL; | ||
380 | const char* keyword_end = NULL; | ||
381 | for(size_t i = 0; ; ++i) | ||
382 | { | ||
383 | char c = upgrade_header[i]; | ||
384 | |||
385 | /* RFC 7230 3.2.6: The list of allowed characters is a token is: */ | ||
386 | /* "!" / "#" / "$" / "%" / "&" / "'" / "*" / */ | ||
387 | /* "+" / "-" / "." / "^" / "_" / "`" / "|" / "~" */ | ||
388 | /* DIGIT / ALPHA */ | ||
389 | /* We also allow "/" here as the sub-delimiter for the protocol version */ | ||
390 | if ('!' == c || '#' == c || '$' == c || '%' == c || | ||
391 | '&' == c || '\'' == c || '*' == c || | ||
392 | '+' == c || '-' == c || '.' == c || '^' == c || | ||
393 | '_' == c || '`' == c || '|' == c || '~' == c || | ||
394 | '/' == c || | ||
395 | ('0' <= c && '9' >= c) || | ||
396 | ('A' <= c && 'Z' >= c) || ('a' <= c && 'z' >= c) ) | ||
397 | { | ||
398 | /* This is a valid token character */ | ||
399 | if (NULL == keyword_start) | ||
400 | { | ||
401 | keyword_start = upgrade_header + i; | ||
402 | } | ||
403 | keyword_end = upgrade_header + i + 1; | ||
404 | } | ||
405 | else if (' ' == c || '\t' == c) | ||
406 | { | ||
407 | /* White-spaces around tokens will be ignored */ | ||
408 | } | ||
409 | else if (',' == c || 0 == c) | ||
410 | { | ||
411 | /* Check the token (case-insensitive) */ | ||
412 | if (NULL != keyword_start) | ||
413 | { | ||
414 | if ( 9 == (keyword_end - keyword_start) ) | ||
415 | { | ||
416 | if ( ('W' == keyword_start[0] || 'w' == keyword_start[0]) && | ||
417 | ('E' == keyword_start[1] || 'e' == keyword_start[1]) && | ||
418 | ('B' == keyword_start[2] || 'b' == keyword_start[2]) && | ||
419 | ('S' == keyword_start[3] || 's' == keyword_start[3]) && | ||
420 | ('O' == keyword_start[4] || 'o' == keyword_start[4]) && | ||
421 | ('C' == keyword_start[5] || 'c' == keyword_start[5]) && | ||
422 | ('K' == keyword_start[6] || 'k' == keyword_start[6]) && | ||
423 | ('E' == keyword_start[7] || 'e' == keyword_start[7]) && | ||
424 | ('T' == keyword_start[8] || 't' == keyword_start[8]) ) | ||
425 | { | ||
426 | /* The keyword equals to "websocket" */ | ||
427 | return MHD_WEBSOCKET_STATUS_OK; | ||
428 | } | ||
429 | } | ||
430 | } | ||
431 | if (0 == c) | ||
432 | { | ||
433 | break; | ||
434 | } | ||
435 | keyword_start = NULL; | ||
436 | keyword_end = NULL; | ||
437 | } | ||
438 | else | ||
439 | { | ||
440 | /* RFC 7230 3.2.6: Other characters are not allowed */ | ||
441 | return MHD_WEBSOCKET_STATUS_NO_WEBSOCKET_HANDSHAKE_HEADER; | ||
442 | } | ||
443 | } | ||
444 | return MHD_WEBSOCKET_STATUS_NO_WEBSOCKET_HANDSHAKE_HEADER; | ||
445 | } | ||
446 | |||
447 | |||
448 | /** | ||
449 | * Checks whether the "Sec-WebSocket-Version" request header | ||
450 | * equals to "13" | ||
451 | */ | ||
452 | _MHD_EXTERN enum MHD_WEBSOCKET_STATUS | ||
453 | MHD_websocket_check_version_header (const char* version_header) | ||
454 | { | ||
455 | /* validate parameters */ | ||
456 | if (NULL == version_header) | ||
457 | { | ||
458 | /* To be compatible with the return value */ | ||
459 | /* of MHD_lookup_connection_value, */ | ||
460 | /* NULL is threated as "value not given" and not as parameter error */ | ||
461 | return MHD_WEBSOCKET_STATUS_NO_WEBSOCKET_HANDSHAKE_HEADER; | ||
462 | } | ||
463 | |||
464 | if ('1' == version_header[0] && | ||
465 | '3' == version_header[1] && | ||
466 | 0 == version_header[2]) | ||
467 | { | ||
468 | /* The version equals to "13" */ | ||
469 | return MHD_WEBSOCKET_STATUS_OK; | ||
470 | } | ||
471 | return MHD_WEBSOCKET_STATUS_NO_WEBSOCKET_HANDSHAKE_HEADER; | ||
472 | } | ||
473 | |||
180 | 474 | ||
181 | /** | 475 | /** |
182 | * Creates the response for the Sec-WebSocket-Accept header | 476 | * Creates the response for the Sec-WebSocket-Accept header |
183 | */ | 477 | */ |
184 | _MHD_EXTERN int | 478 | _MHD_EXTERN enum MHD_WEBSOCKET_STATUS |
185 | MHD_websocket_create_accept (const char*sec_websocket_key, | 479 | MHD_websocket_create_accept_header (const char*sec_websocket_key, |
186 | char*sec_websocket_accept) | 480 | char*sec_websocket_accept) |
187 | { | 481 | { |
188 | /* initialize output variables for errors cases */ | 482 | /* initialize output variables for errors cases */ |
189 | if (NULL != sec_websocket_accept) | 483 | if (NULL != sec_websocket_accept) |
190 | *sec_websocket_accept = 0; | 484 | *sec_websocket_accept = 0; |
191 | 485 | ||
192 | /* validate parameters */ | 486 | /* validate parameters */ |
193 | if ((NULL == sec_websocket_key) || | 487 | if (NULL == sec_websocket_accept) |
194 | (NULL == sec_websocket_accept) ) | ||
195 | { | 488 | { |
196 | return MHD_WEBSOCKET_STATUS_PARAMETER_ERROR; | 489 | return MHD_WEBSOCKET_STATUS_PARAMETER_ERROR; |
197 | } | 490 | } |
491 | if (NULL == sec_websocket_key) | ||
492 | { | ||
493 | /* NULL is not a parameter error, */ | ||
494 | /* because MHD_lookup_connection_value returns NULL */ | ||
495 | /* if the header wasn't found */ | ||
496 | return MHD_WEBSOCKET_STATUS_NO_WEBSOCKET_HANDSHAKE_HEADER; | ||
497 | } | ||
198 | 498 | ||
199 | /* build SHA1 hash of the given key and the UUID appended */ | 499 | /* build SHA1 hash of the given key and the UUID appended */ |
200 | char sha1[20]; | 500 | char sha1[20]; |
201 | const char*suffix = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; | 501 | const char*suffix = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; |
202 | int length = (int) strlen (sec_websocket_key); | 502 | int length = (int) strlen (sec_websocket_key); |
203 | struct sha1_ctx ctx; | 503 | struct sha1_ctx ctx; |
204 | sha1_init_ctx (&ctx); | 504 | MHD_SHA1_init (&ctx); |
205 | sha1_process_bytes (sec_websocket_key, length, &ctx); | 505 | MHD_SHA1_update (&ctx, (const uint8_t*) sec_websocket_key, length); |
206 | sha1_process_bytes (suffix, 36, &ctx); | 506 | MHD_SHA1_update (&ctx, (const uint8_t*) suffix, 36); |
207 | sha1_finish_ctx (&ctx, sha1); | 507 | MHD_SHA1_finish (&ctx, (uint8_t*) sha1); |
208 | 508 | ||
209 | /* base64 encode that SHA1 hash */ | 509 | /* base64 encode that SHA1 hash */ |
210 | /* (simple algorithm here; SHA1 has always 20 bytes, */ | 510 | /* (simple algorithm here; SHA1 has always 20 bytes, */ |
@@ -234,7 +534,7 @@ MHD_websocket_create_accept (const char*sec_websocket_key, | |||
234 | /** | 534 | /** |
235 | * Initializes a new websocket stream | 535 | * Initializes a new websocket stream |
236 | */ | 536 | */ |
237 | _MHD_EXTERN int | 537 | _MHD_EXTERN enum MHD_WEBSOCKET_STATUS |
238 | MHD_websocket_stream_init (struct MHD_WebSocketStream**ws, | 538 | MHD_websocket_stream_init (struct MHD_WebSocketStream**ws, |
239 | int flags, | 539 | int flags, |
240 | size_t max_payload_size) | 540 | size_t max_payload_size) |
@@ -244,7 +544,9 @@ MHD_websocket_stream_init (struct MHD_WebSocketStream**ws, | |||
244 | max_payload_size, | 544 | max_payload_size, |
245 | malloc, | 545 | malloc, |
246 | realloc, | 546 | realloc, |
247 | free); | 547 | free, |
548 | NULL, | ||
549 | NULL); | ||
248 | } | 550 | } |
249 | 551 | ||
250 | 552 | ||
@@ -252,13 +554,15 @@ MHD_websocket_stream_init (struct MHD_WebSocketStream**ws, | |||
252 | * Initializes a new websocket stream with | 554 | * Initializes a new websocket stream with |
253 | * additional parameters for allocation functions | 555 | * additional parameters for allocation functions |
254 | */ | 556 | */ |
255 | _MHD_EXTERN int | 557 | _MHD_EXTERN enum MHD_WEBSOCKET_STATUS |
256 | MHD_websocket_stream_init2 (struct MHD_WebSocketStream**ws, | 558 | MHD_websocket_stream_init2 (struct MHD_WebSocketStream**ws, |
257 | int flags, | 559 | int flags, |
258 | size_t max_payload_size, | 560 | size_t max_payload_size, |
259 | MHD_WebSocketMallocCallback callback_malloc, | 561 | MHD_WebSocketMallocCallback callback_malloc, |
260 | MHD_WebSocketReallocCallback callback_realloc, | 562 | MHD_WebSocketReallocCallback callback_realloc, |
261 | MHD_WebSocketFreeCallback callback_free) | 563 | MHD_WebSocketFreeCallback callback_free, |
564 | void* cls_rng, | ||
565 | MHD_WebSocketRandomNumberGenerator callback_rng) | ||
262 | { | 566 | { |
263 | /* initialize output variables for errors cases */ | 567 | /* initialize output variables for errors cases */ |
264 | if (NULL != ws) | 568 | if (NULL != ws) |
@@ -270,7 +574,9 @@ MHD_websocket_stream_init2 (struct MHD_WebSocketStream**ws, | |||
270 | ((uint64_t) 0x7FFFFFFFFFFFFFFF < max_payload_size) || | 574 | ((uint64_t) 0x7FFFFFFFFFFFFFFF < max_payload_size) || |
271 | (NULL == callback_malloc) || | 575 | (NULL == callback_malloc) || |
272 | (NULL == callback_realloc) || | 576 | (NULL == callback_realloc) || |
273 | (NULL == callback_free) ) | 577 | (NULL == callback_free) || |
578 | ((0 != (flags & MHD_WEBSOCKET_FLAG_CLIENT)) && | ||
579 | (NULL == callback_rng))) | ||
274 | { | 580 | { |
275 | return MHD_WEBSOCKET_STATUS_PARAMETER_ERROR; | 581 | return MHD_WEBSOCKET_STATUS_PARAMETER_ERROR; |
276 | } | 582 | } |
@@ -288,6 +594,8 @@ MHD_websocket_stream_init2 (struct MHD_WebSocketStream**ws, | |||
288 | ws_->malloc = callback_malloc; | 594 | ws_->malloc = callback_malloc; |
289 | ws_->realloc = callback_realloc; | 595 | ws_->realloc = callback_realloc; |
290 | ws_->free = callback_free; | 596 | ws_->free = callback_free; |
597 | ws_->cls_rng = cls_rng; | ||
598 | ws_->rng = callback_rng; | ||
291 | ws_->validity = MHD_WEBSOCKET_VALIDITY_VALID; | 599 | ws_->validity = MHD_WEBSOCKET_VALIDITY_VALID; |
292 | 600 | ||
293 | /* return stream */ | 601 | /* return stream */ |
@@ -300,7 +608,7 @@ MHD_websocket_stream_init2 (struct MHD_WebSocketStream**ws, | |||
300 | /** | 608 | /** |
301 | * Frees a previously allocated websocket stream | 609 | * Frees a previously allocated websocket stream |
302 | */ | 610 | */ |
303 | _MHD_EXTERN int | 611 | _MHD_EXTERN enum MHD_WEBSOCKET_STATUS |
304 | MHD_websocket_stream_free (struct MHD_WebSocketStream*ws) | 612 | MHD_websocket_stream_free (struct MHD_WebSocketStream*ws) |
305 | { | 613 | { |
306 | /* validate parameters */ | 614 | /* validate parameters */ |
@@ -323,7 +631,7 @@ MHD_websocket_stream_free (struct MHD_WebSocketStream*ws) | |||
323 | /** | 631 | /** |
324 | * Invalidates a websocket stream (no more decoding possible) | 632 | * Invalidates a websocket stream (no more decoding possible) |
325 | */ | 633 | */ |
326 | _MHD_EXTERN int | 634 | _MHD_EXTERN enum MHD_WEBSOCKET_STATUS |
327 | MHD_websocket_stream_invalidate (struct MHD_WebSocketStream*ws) | 635 | MHD_websocket_stream_invalidate (struct MHD_WebSocketStream*ws) |
328 | { | 636 | { |
329 | /* validate parameters */ | 637 | /* validate parameters */ |
@@ -340,7 +648,7 @@ MHD_websocket_stream_invalidate (struct MHD_WebSocketStream*ws) | |||
340 | /** | 648 | /** |
341 | * Returns whether a websocket stream is valid | 649 | * Returns whether a websocket stream is valid |
342 | */ | 650 | */ |
343 | _MHD_EXTERN int | 651 | _MHD_EXTERN enum MHD_WEBSOCKET_VALIDITY |
344 | MHD_websocket_stream_is_valid (struct MHD_WebSocketStream*ws) | 652 | MHD_websocket_stream_is_valid (struct MHD_WebSocketStream*ws) |
345 | { | 653 | { |
346 | /* validate parameters */ | 654 | /* validate parameters */ |
@@ -354,7 +662,7 @@ MHD_websocket_stream_is_valid (struct MHD_WebSocketStream*ws) | |||
354 | /** | 662 | /** |
355 | * Decodes incoming data to a websocket frame | 663 | * Decodes incoming data to a websocket frame |
356 | */ | 664 | */ |
357 | _MHD_EXTERN int | 665 | _MHD_EXTERN enum MHD_WEBSOCKET_STATUS |
358 | MHD_websocket_decode (struct MHD_WebSocketStream*ws, | 666 | MHD_websocket_decode (struct MHD_WebSocketStream*ws, |
359 | const char*streambuf, | 667 | const char*streambuf, |
360 | size_t streambuf_len, | 668 | size_t streambuf_len, |
@@ -372,7 +680,7 @@ MHD_websocket_decode (struct MHD_WebSocketStream*ws, | |||
372 | 680 | ||
373 | /* validate parameters */ | 681 | /* validate parameters */ |
374 | if ((NULL == ws) || | 682 | if ((NULL == ws) || |
375 | (NULL == streambuf) && (0 != streambuf_len) || | 683 | ((NULL == streambuf) && (0 != streambuf_len)) || |
376 | (NULL == streambuf_read_len) || | 684 | (NULL == streambuf_read_len) || |
377 | (NULL == payload) || | 685 | (NULL == payload) || |
378 | (NULL == payload_len) ) | 686 | (NULL == payload_len) ) |
@@ -657,8 +965,8 @@ MHD_websocket_decode (struct MHD_WebSocketStream*ws, | |||
657 | else | 965 | else |
658 | { | 966 | { |
659 | size_t size = (size_t) frame_len; | 967 | size_t size = (size_t) frame_len; |
660 | if ((SIZE_MAX < size) || ws->max_payload_size && | 968 | if ((SIZE_MAX < size) || |
661 | (ws->max_payload_size < size) ) | 969 | (ws->max_payload_size && (ws->max_payload_size < size)) ) |
662 | { | 970 | { |
663 | /* RFC 6455 7.4.1 1009: If the message is too big to process, we may close the connection */ | 971 | /* 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; | 972 | ws->validity = MHD_WEBSOCKET_VALIDITY_INVALID; |
@@ -713,8 +1021,7 @@ MHD_websocket_decode (struct MHD_WebSocketStream*ws, | |||
713 | case MHD_WebSocket_DecodeStep_Length2of2: | 1021 | case MHD_WebSocket_DecodeStep_Length2of2: |
714 | { | 1022 | { |
715 | ws->frame_header [ws->frame_header_size++] = streambuf [current++]; | 1023 | ws->frame_header [ws->frame_header_size++] = streambuf [current++]; |
716 | size_t size = (size_t) htons (*((unsigned | 1024 | size_t size = (size_t) MHD_htons (*((uint16_t*) &ws->frame_header [2])); |
717 | short*) &ws->frame_header [2])); | ||
718 | if (125 >= size) | 1025 | if (125 >= size) |
719 | { | 1026 | { |
720 | /* RFC 6455 5.2 Payload length: The minimal number of bytes */ | 1027 | /* RFC 6455 5.2 Payload length: The minimal number of bytes */ |
@@ -733,8 +1040,8 @@ MHD_websocket_decode (struct MHD_WebSocketStream*ws, | |||
733 | *streambuf_read_len = current; | 1040 | *streambuf_read_len = current; |
734 | return MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR; | 1041 | return MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR; |
735 | } | 1042 | } |
736 | if ((SIZE_MAX < size) || ws->max_payload_size && (ws->max_payload_size < | 1043 | if ((SIZE_MAX < size) || |
737 | size) ) | 1044 | (ws->max_payload_size && (ws->max_payload_size < size)) ) |
738 | { | 1045 | { |
739 | /* RFC 6455 7.4.1 1009: If the message is too big to process, */ | 1046 | /* RFC 6455 7.4.1 1009: If the message is too big to process, */ |
740 | /* we may close the connection */ | 1047 | /* we may close the connection */ |
@@ -771,7 +1078,7 @@ MHD_websocket_decode (struct MHD_WebSocketStream*ws, | |||
771 | case MHD_WebSocket_DecodeStep_Length8of8: | 1078 | case MHD_WebSocket_DecodeStep_Length8of8: |
772 | { | 1079 | { |
773 | ws->frame_header [ws->frame_header_size++] = streambuf [current++]; | 1080 | ws->frame_header [ws->frame_header_size++] = streambuf [current++]; |
774 | uint64_t size = htonll (*((uint64_t*) &ws->frame_header [2])); | 1081 | uint64_t size = MHD_htonll (*((uint64_t*) &ws->frame_header [2])); |
775 | if (0x7fffffffffffffff < size) | 1082 | if (0x7fffffffffffffff < size) |
776 | { | 1083 | { |
777 | /* RFC 6455 5.2 frame-payload-length-63: The length may */ | 1084 | /* RFC 6455 5.2 frame-payload-length-63: The length may */ |
@@ -809,8 +1116,8 @@ MHD_websocket_decode (struct MHD_WebSocketStream*ws, | |||
809 | *streambuf_read_len = current; | 1116 | *streambuf_read_len = current; |
810 | return MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR; | 1117 | return MHD_WEBSOCKET_STATUS_PROTOCOL_ERROR; |
811 | } | 1118 | } |
812 | if ((SIZE_MAX < size) || ws->max_payload_size && (ws->max_payload_size < | 1119 | if ((SIZE_MAX < size) || |
813 | size) ) | 1120 | (ws->max_payload_size && (ws->max_payload_size < size)) ) |
814 | { | 1121 | { |
815 | /* RFC 6455 7.4.1 1009: If the message is too big to process, */ | 1122 | /* RFC 6455 7.4.1 1009: If the message is too big to process, */ |
816 | /* we may close the connection */ | 1123 | /* we may close the connection */ |
@@ -893,13 +1200,13 @@ MHD_websocket_decode (struct MHD_WebSocketStream*ws, | |||
893 | & 0x03)); | 1200 | & 0x03)); |
894 | current += bytes_to_take; | 1201 | current += bytes_to_take; |
895 | ws->payload_index += bytes_to_take; | 1202 | ws->payload_index += bytes_to_take; |
896 | if ((MHD_WebSocket_DecodeStep_PayloadOfDataFrame == | 1203 | if (((MHD_WebSocket_DecodeStep_PayloadOfDataFrame == |
897 | ws->decode_step) && | 1204 | ws->decode_step) && |
898 | (MHD_WebSocket_Opcode_Text == ws->data_type) || | 1205 | (MHD_WebSocket_Opcode_Text == ws->data_type)) || |
899 | (MHD_WebSocket_DecodeStep_PayloadOfControlFrame == | 1206 | ((MHD_WebSocket_DecodeStep_PayloadOfControlFrame == |
900 | ws->decode_step) && | 1207 | ws->decode_step) && |
901 | (MHD_WebSocket_Opcode_Close == (ws->frame_header [0] & 0x0f)) && | 1208 | (MHD_WebSocket_Opcode_Close == (ws->frame_header [0] & 0x0f)) && |
902 | (2 < ws->payload_index) ) | 1209 | (2 < ws->payload_index)) ) |
903 | { | 1210 | { |
904 | /* RFC 6455 8.1: We need to check the UTF-8 validity */ | 1211 | /* RFC 6455 8.1: We need to check the UTF-8 validity */ |
905 | int utf8_step; | 1212 | int utf8_step; |
@@ -1016,7 +1323,7 @@ MHD_websocket_decode (struct MHD_WebSocketStream*ws, | |||
1016 | } | 1323 | } |
1017 | 1324 | ||
1018 | 1325 | ||
1019 | static int | 1326 | static enum MHD_WEBSOCKET_STATUS |
1020 | MHD_websocket_decode_header_complete (struct MHD_WebSocketStream*ws, | 1327 | MHD_websocket_decode_header_complete (struct MHD_WebSocketStream*ws, |
1021 | char**payload, | 1328 | char**payload, |
1022 | size_t*payload_len) | 1329 | size_t*payload_len) |
@@ -1119,13 +1426,15 @@ MHD_websocket_decode_header_complete (struct MHD_WebSocketStream*ws, | |||
1119 | } | 1426 | } |
1120 | 1427 | ||
1121 | 1428 | ||
1122 | static int | 1429 | static enum MHD_WEBSOCKET_STATUS |
1123 | MHD_websocket_decode_payload_complete (struct MHD_WebSocketStream*ws, | 1430 | MHD_websocket_decode_payload_complete (struct MHD_WebSocketStream*ws, |
1124 | char**payload, | 1431 | char**payload, |
1125 | size_t*payload_len) | 1432 | size_t*payload_len) |
1126 | { | 1433 | { |
1127 | /* all payload data of the current frame has been received */ | 1434 | /* all payload data of the current frame has been received */ |
1128 | char is_fin = ws->frame_header [0] & 0x80; | 1435 | char is_continue = MHD_WebSocket_Opcode_Continuation == |
1436 | (ws->frame_header [0] & 0x0F); | ||
1437 | char is_fin = ws->frame_header [0] & 0x80; | ||
1129 | if (0 != is_fin) | 1438 | if (0 != is_fin) |
1130 | { | 1439 | { |
1131 | /* the frame is complete */ | 1440 | /* the frame is complete */ |
@@ -1134,9 +1443,9 @@ MHD_websocket_decode_payload_complete (struct MHD_WebSocketStream*ws, | |||
1134 | /* data frame */ | 1443 | /* data frame */ |
1135 | char data_type = ws->data_type; | 1444 | char data_type = ws->data_type; |
1136 | if ((0 != (ws->flags & MHD_WEBSOCKET_FLAG_WANT_FRAGMENTS)) && | 1445 | if ((0 != (ws->flags & MHD_WEBSOCKET_FLAG_WANT_FRAGMENTS)) && |
1137 | (MHD_WebSocket_Opcode_Continuation == (ws->frame_header [0] & 0x0F))) | 1446 | (0 != is_continue)) |
1138 | { | 1447 | { |
1139 | data_type |= 0x20; /* mark as last fragment */ | 1448 | data_type |= 0x40; /* mark as last fragment */ |
1140 | } | 1449 | } |
1141 | *payload = ws->data_payload; | 1450 | *payload = ws->data_payload; |
1142 | *payload_len = ws->data_payload_size; | 1451 | *payload_len = ws->data_payload_size; |
@@ -1170,7 +1479,7 @@ MHD_websocket_decode_payload_complete (struct MHD_WebSocketStream*ws, | |||
1170 | { | 1479 | { |
1171 | /* the last UTF-8 sequence is incomplete, so we keep the start of | 1480 | /* the last UTF-8 sequence is incomplete, so we keep the start of |
1172 | that and only return the part before */ | 1481 | that and only return the part before */ |
1173 | size_t given_utf8; | 1482 | size_t given_utf8 = 0; |
1174 | switch (ws->data_utf8_step) | 1483 | switch (ws->data_utf8_step) |
1175 | { | 1484 | { |
1176 | /* one byte given */ | 1485 | /* one byte given */ |
@@ -1220,7 +1529,10 @@ MHD_websocket_decode_payload_complete (struct MHD_WebSocketStream*ws, | |||
1220 | ws->decode_step = MHD_WebSocket_DecodeStep_Start; | 1529 | ws->decode_step = MHD_WebSocket_DecodeStep_Start; |
1221 | ws->payload_index = 0; | 1530 | ws->payload_index = 0; |
1222 | ws->frame_header_size = 0; | 1531 | ws->frame_header_size = 0; |
1223 | return ws->data_type | 0x10; /* mark as fragment */ | 1532 | if (0 != is_continue) |
1533 | return ws->data_type | 0x20; /* mark as middle fragment */ | ||
1534 | else | ||
1535 | return ws->data_type | 0x10; /* mark as first fragment */ | ||
1224 | } | 1536 | } |
1225 | else | 1537 | else |
1226 | { | 1538 | { |
@@ -1233,7 +1545,10 @@ MHD_websocket_decode_payload_complete (struct MHD_WebSocketStream*ws, | |||
1233 | ws->decode_step = MHD_WebSocket_DecodeStep_Start; | 1545 | ws->decode_step = MHD_WebSocket_DecodeStep_Start; |
1234 | ws->payload_index = 0; | 1546 | ws->payload_index = 0; |
1235 | ws->frame_header_size = 0; | 1547 | ws->frame_header_size = 0; |
1236 | return ws->data_type | 0x10; /* mark as fragment */ | 1548 | if (0 != is_continue) |
1549 | return ws->data_type | 0x20; /* mark as middle fragment */ | ||
1550 | else | ||
1551 | return ws->data_type | 0x10; /* mark as first fragment */ | ||
1237 | } | 1552 | } |
1238 | } | 1553 | } |
1239 | else | 1554 | else |
@@ -1251,7 +1566,7 @@ MHD_websocket_decode_payload_complete (struct MHD_WebSocketStream*ws, | |||
1251 | /** | 1566 | /** |
1252 | * Splits the received close reason | 1567 | * Splits the received close reason |
1253 | */ | 1568 | */ |
1254 | _MHD_EXTERN int | 1569 | _MHD_EXTERN enum MHD_WEBSOCKET_STATUS |
1255 | MHD_websocket_split_close_reason (const char*payload, | 1570 | MHD_websocket_split_close_reason (const char*payload, |
1256 | size_t payload_len, | 1571 | size_t payload_len, |
1257 | unsigned short*reason_code, | 1572 | unsigned short*reason_code, |
@@ -1283,7 +1598,7 @@ MHD_websocket_split_close_reason (const char*payload, | |||
1283 | else | 1598 | else |
1284 | { | 1599 | { |
1285 | if (NULL != reason_code) | 1600 | if (NULL != reason_code) |
1286 | *reason_code = htons (*((unsigned short*) payload)); | 1601 | *reason_code = MHD_htons (*((uint16_t*) payload)); |
1287 | } | 1602 | } |
1288 | 1603 | ||
1289 | /* decode reason text */ | 1604 | /* decode reason text */ |
@@ -1309,7 +1624,7 @@ MHD_websocket_split_close_reason (const char*payload, | |||
1309 | /** | 1624 | /** |
1310 | * Encodes a text into a websocket text frame | 1625 | * Encodes a text into a websocket text frame |
1311 | */ | 1626 | */ |
1312 | _MHD_EXTERN int | 1627 | _MHD_EXTERN enum MHD_WEBSOCKET_STATUS |
1313 | MHD_websocket_encode_text (struct MHD_WebSocketStream*ws, | 1628 | MHD_websocket_encode_text (struct MHD_WebSocketStream*ws, |
1314 | const char*payload_utf8, | 1629 | const char*payload_utf8, |
1315 | size_t payload_utf8_len, | 1630 | size_t payload_utf8_len, |
@@ -1333,13 +1648,13 @@ MHD_websocket_encode_text (struct MHD_WebSocketStream*ws, | |||
1333 | 1648 | ||
1334 | /* validate parameters */ | 1649 | /* validate parameters */ |
1335 | if ((NULL == ws) || | 1650 | if ((NULL == ws) || |
1336 | (0 != payload_utf8_len) && (NULL == payload_utf8) || | 1651 | ((0 != payload_utf8_len) && (NULL == payload_utf8)) || |
1337 | (NULL == frame) || | 1652 | (NULL == frame) || |
1338 | (NULL == frame_len) || | 1653 | (NULL == frame_len) || |
1339 | (MHD_WEBSOCKET_FRAGMENTATION_NONE > fragmentation) || | 1654 | (MHD_WEBSOCKET_FRAGMENTATION_NONE > fragmentation) || |
1340 | (MHD_WEBSOCKET_FRAGMENTATION_LAST < fragmentation) || | 1655 | (MHD_WEBSOCKET_FRAGMENTATION_LAST < fragmentation) || |
1341 | (MHD_WEBSOCKET_FRAGMENTATION_NONE != fragmentation) && (NULL == | 1656 | ((MHD_WEBSOCKET_FRAGMENTATION_NONE != fragmentation) && |
1342 | utf8_step) ) | 1657 | (NULL == utf8_step)) ) |
1343 | { | 1658 | { |
1344 | return MHD_WEBSOCKET_STATUS_PARAMETER_ERROR; | 1659 | return MHD_WEBSOCKET_STATUS_PARAMETER_ERROR; |
1345 | } | 1660 | } |
@@ -1356,8 +1671,8 @@ MHD_websocket_encode_text (struct MHD_WebSocketStream*ws, | |||
1356 | utf8_step, | 1671 | utf8_step, |
1357 | NULL); | 1672 | NULL); |
1358 | if ((MHD_WebSocket_UTF8Result_Invalid == utf8_result) || | 1673 | if ((MHD_WebSocket_UTF8Result_Invalid == utf8_result) || |
1359 | (MHD_WebSocket_UTF8Result_Incomplete == utf8_result) && | 1674 | ((MHD_WebSocket_UTF8Result_Incomplete == utf8_result) && |
1360 | (MHD_WEBSOCKET_FRAGMENTATION_NONE == fragmentation) ) | 1675 | (MHD_WEBSOCKET_FRAGMENTATION_NONE == fragmentation)) ) |
1361 | { | 1676 | { |
1362 | return MHD_WEBSOCKET_STATUS_UTF8_ENCODING_ERROR; | 1677 | return MHD_WEBSOCKET_STATUS_UTF8_ENCODING_ERROR; |
1363 | } | 1678 | } |
@@ -1376,7 +1691,7 @@ MHD_websocket_encode_text (struct MHD_WebSocketStream*ws, | |||
1376 | /** | 1691 | /** |
1377 | * Encodes binary data into a websocket binary frame | 1692 | * Encodes binary data into a websocket binary frame |
1378 | */ | 1693 | */ |
1379 | _MHD_EXTERN int | 1694 | _MHD_EXTERN enum MHD_WEBSOCKET_STATUS |
1380 | MHD_websocket_encode_binary (struct MHD_WebSocketStream*ws, | 1695 | MHD_websocket_encode_binary (struct MHD_WebSocketStream*ws, |
1381 | const char*payload, | 1696 | const char*payload, |
1382 | size_t payload_len, | 1697 | size_t payload_len, |
@@ -1392,7 +1707,7 @@ MHD_websocket_encode_binary (struct MHD_WebSocketStream*ws, | |||
1392 | 1707 | ||
1393 | /* validate parameters */ | 1708 | /* validate parameters */ |
1394 | if ((NULL == ws) || | 1709 | if ((NULL == ws) || |
1395 | (0 != payload_len) && (NULL == payload) || | 1710 | ((0 != payload_len) && (NULL == payload)) || |
1396 | (NULL == frame) || | 1711 | (NULL == frame) || |
1397 | (NULL == frame_len) || | 1712 | (NULL == frame_len) || |
1398 | (MHD_WEBSOCKET_FRAGMENTATION_NONE > fragmentation) || | 1713 | (MHD_WEBSOCKET_FRAGMENTATION_NONE > fragmentation) || |
@@ -1420,7 +1735,7 @@ MHD_websocket_encode_binary (struct MHD_WebSocketStream*ws, | |||
1420 | /** | 1735 | /** |
1421 | * Internal function for encoding text/binary data into a websocket frame | 1736 | * Internal function for encoding text/binary data into a websocket frame |
1422 | */ | 1737 | */ |
1423 | static int | 1738 | static enum MHD_WEBSOCKET_STATUS |
1424 | MHD_websocket_encode_data (struct MHD_WebSocketStream*ws, | 1739 | MHD_websocket_encode_data (struct MHD_WebSocketStream*ws, |
1425 | const char*payload, | 1740 | const char*payload, |
1426 | size_t payload_len, | 1741 | size_t payload_len, |
@@ -1433,7 +1748,7 @@ MHD_websocket_encode_data (struct MHD_WebSocketStream*ws, | |||
1433 | char is_masked = MHD_websocket_encode_is_masked (ws); | 1748 | char is_masked = MHD_websocket_encode_is_masked (ws); |
1434 | size_t overhead_len = MHD_websocket_encode_overhead_size (ws, payload_len); | 1749 | size_t overhead_len = MHD_websocket_encode_overhead_size (ws, payload_len); |
1435 | size_t total_len = overhead_len + payload_len; | 1750 | size_t total_len = overhead_len + payload_len; |
1436 | uint32_t mask = 0 != is_masked ? MHD_websocket_generate_mask () : 0; | 1751 | uint32_t mask = 0 != is_masked ? MHD_websocket_generate_mask (ws) : 0; |
1437 | 1752 | ||
1438 | /* allocate memory */ | 1753 | /* allocate memory */ |
1439 | char*result = ws->malloc (total_len + 1); | 1754 | char*result = ws->malloc (total_len + 1); |
@@ -1468,13 +1783,13 @@ MHD_websocket_encode_data (struct MHD_WebSocketStream*ws, | |||
1468 | else if (65536 > payload_len) | 1783 | else if (65536 > payload_len) |
1469 | { | 1784 | { |
1470 | *(result++) = is_masked | 126; | 1785 | *(result++) = is_masked | 126; |
1471 | *((unsigned short *) result) = htons ((unsigned short) payload_len); | 1786 | *((uint16_t *) result) = MHD_htons ((uint16_t) payload_len); |
1472 | result += 2; | 1787 | result += 2; |
1473 | } | 1788 | } |
1474 | else | 1789 | else |
1475 | { | 1790 | { |
1476 | *(result++) = is_masked | 127; | 1791 | *(result++) = is_masked | 127; |
1477 | *((uint64_t *) result) = htonll ((uint64_t) payload_len); | 1792 | *((uint64_t *) result) = MHD_htonll ((uint64_t) payload_len); |
1478 | result += 8; | 1793 | result += 8; |
1479 | 1794 | ||
1480 | } | 1795 | } |
@@ -1505,7 +1820,7 @@ MHD_websocket_encode_data (struct MHD_WebSocketStream*ws, | |||
1505 | /** | 1820 | /** |
1506 | * Encodes a websocket ping frame | 1821 | * Encodes a websocket ping frame |
1507 | */ | 1822 | */ |
1508 | _MHD_EXTERN int | 1823 | _MHD_EXTERN enum MHD_WEBSOCKET_STATUS |
1509 | MHD_websocket_encode_ping (struct MHD_WebSocketStream*ws, | 1824 | MHD_websocket_encode_ping (struct MHD_WebSocketStream*ws, |
1510 | const char*payload, | 1825 | const char*payload, |
1511 | size_t payload_len, | 1826 | size_t payload_len, |
@@ -1525,7 +1840,7 @@ MHD_websocket_encode_ping (struct MHD_WebSocketStream*ws, | |||
1525 | /** | 1840 | /** |
1526 | * Encodes a websocket pong frame | 1841 | * Encodes a websocket pong frame |
1527 | */ | 1842 | */ |
1528 | _MHD_EXTERN int | 1843 | _MHD_EXTERN enum MHD_WEBSOCKET_STATUS |
1529 | MHD_websocket_encode_pong (struct MHD_WebSocketStream*ws, | 1844 | MHD_websocket_encode_pong (struct MHD_WebSocketStream*ws, |
1530 | const char*payload, | 1845 | const char*payload, |
1531 | size_t payload_len, | 1846 | size_t payload_len, |
@@ -1545,7 +1860,7 @@ MHD_websocket_encode_pong (struct MHD_WebSocketStream*ws, | |||
1545 | /** | 1860 | /** |
1546 | * Internal function for encoding ping/pong frames | 1861 | * Internal function for encoding ping/pong frames |
1547 | */ | 1862 | */ |
1548 | static int | 1863 | static enum MHD_WEBSOCKET_STATUS |
1549 | MHD_websocket_encode_ping_pong (struct MHD_WebSocketStream*ws, | 1864 | MHD_websocket_encode_ping_pong (struct MHD_WebSocketStream*ws, |
1550 | const char*payload, | 1865 | const char*payload, |
1551 | size_t payload_len, | 1866 | size_t payload_len, |
@@ -1561,7 +1876,7 @@ MHD_websocket_encode_ping_pong (struct MHD_WebSocketStream*ws, | |||
1561 | 1876 | ||
1562 | /* validate the parameters */ | 1877 | /* validate the parameters */ |
1563 | if ((NULL == ws) || | 1878 | if ((NULL == ws) || |
1564 | (0 != payload_len) && (NULL == payload) || | 1879 | ((0 != payload_len) && (NULL == payload)) || |
1565 | (NULL == frame) || | 1880 | (NULL == frame) || |
1566 | (NULL == frame_len) ) | 1881 | (NULL == frame_len) ) |
1567 | { | 1882 | { |
@@ -1576,7 +1891,7 @@ MHD_websocket_encode_ping_pong (struct MHD_WebSocketStream*ws, | |||
1576 | char is_masked = MHD_websocket_encode_is_masked (ws); | 1891 | char is_masked = MHD_websocket_encode_is_masked (ws); |
1577 | size_t overhead_len = MHD_websocket_encode_overhead_size (ws, payload_len); | 1892 | size_t overhead_len = MHD_websocket_encode_overhead_size (ws, payload_len); |
1578 | size_t total_len = overhead_len + payload_len; | 1893 | size_t total_len = overhead_len + payload_len; |
1579 | uint32_t mask = is_masked != 0 ? MHD_websocket_generate_mask () : 0; | 1894 | uint32_t mask = is_masked != 0 ? MHD_websocket_generate_mask (ws) : 0; |
1580 | 1895 | ||
1581 | /* allocate memory */ | 1896 | /* allocate memory */ |
1582 | char*result = ws->malloc (total_len + 1); | 1897 | char*result = ws->malloc (total_len + 1); |
@@ -1618,7 +1933,7 @@ MHD_websocket_encode_ping_pong (struct MHD_WebSocketStream*ws, | |||
1618 | /** | 1933 | /** |
1619 | * Encodes a websocket close frame | 1934 | * Encodes a websocket close frame |
1620 | */ | 1935 | */ |
1621 | _MHD_EXTERN int | 1936 | _MHD_EXTERN enum MHD_WEBSOCKET_STATUS |
1622 | MHD_websocket_encode_close (struct MHD_WebSocketStream*ws, | 1937 | MHD_websocket_encode_close (struct MHD_WebSocketStream*ws, |
1623 | unsigned short reason_code, | 1938 | unsigned short reason_code, |
1624 | const char*reason_utf8, | 1939 | const char*reason_utf8, |
@@ -1634,13 +1949,13 @@ MHD_websocket_encode_close (struct MHD_WebSocketStream*ws, | |||
1634 | 1949 | ||
1635 | /* validate the parameters */ | 1950 | /* validate the parameters */ |
1636 | if ((NULL == ws) || | 1951 | if ((NULL == ws) || |
1637 | (0 != reason_utf8_len) && (NULL == reason_utf8) || | 1952 | ((0 != reason_utf8_len) && (NULL == reason_utf8)) || |
1638 | (NULL == frame) || | 1953 | (NULL == frame) || |
1639 | (NULL == frame_len) || | 1954 | (NULL == frame_len) || |
1640 | (MHD_WEBSOCKET_CLOSEREASON_NO_REASON != reason_code) && (1000 > | 1955 | ((MHD_WEBSOCKET_CLOSEREASON_NO_REASON != reason_code) && |
1641 | reason_code) || | 1956 | (1000 > reason_code)) || |
1642 | (0 != reason_utf8_len) && (MHD_WEBSOCKET_CLOSEREASON_NO_REASON == | 1957 | ((0 != reason_utf8_len) && |
1643 | reason_code) ) | 1958 | (MHD_WEBSOCKET_CLOSEREASON_NO_REASON == reason_code)) ) |
1644 | { | 1959 | { |
1645 | return MHD_WEBSOCKET_STATUS_PARAMETER_ERROR; | 1960 | return MHD_WEBSOCKET_STATUS_PARAMETER_ERROR; |
1646 | } | 1961 | } |
@@ -1668,7 +1983,7 @@ MHD_websocket_encode_close (struct MHD_WebSocketStream*ws, | |||
1668 | 2 + reason_utf8_len : 0); | 1983 | 2 + reason_utf8_len : 0); |
1669 | size_t overhead_len = MHD_websocket_encode_overhead_size (ws, payload_len); | 1984 | size_t overhead_len = MHD_websocket_encode_overhead_size (ws, payload_len); |
1670 | size_t total_len = overhead_len + payload_len; | 1985 | size_t total_len = overhead_len + payload_len; |
1671 | uint32_t mask = is_masked != 0 ? MHD_websocket_generate_mask () : 0; | 1986 | uint32_t mask = is_masked != 0 ? MHD_websocket_generate_mask (ws) : 0; |
1672 | 1987 | ||
1673 | /* allocate memory */ | 1988 | /* allocate memory */ |
1674 | char*result = ws->malloc (total_len + 1); | 1989 | char*result = ws->malloc (total_len + 1); |
@@ -1697,7 +2012,7 @@ MHD_websocket_encode_close (struct MHD_WebSocketStream*ws, | |||
1697 | if (0 != reason_code) | 2012 | if (0 != reason_code) |
1698 | { | 2013 | { |
1699 | /* close reason code */ | 2014 | /* close reason code */ |
1700 | unsigned short reason_code_nb = htons (reason_code); | 2015 | uint16_t reason_code_nb = MHD_htons (reason_code); |
1701 | MHD_websocket_copy_payload (result, | 2016 | MHD_websocket_copy_payload (result, |
1702 | (const char*) &reason_code_nb, | 2017 | (const char*) &reason_code_nb, |
1703 | 2, | 2018 | 2, |
@@ -1815,8 +2130,8 @@ MHD_websocket_check_utf8 (const char*buf, | |||
1815 | /* RFC 3629 4: three byte UTF-8 sequence, but the second byte must be 0x80-0x9F */ | 2130 | /* RFC 3629 4: three byte UTF-8 sequence, but the second byte must be 0x80-0x9F */ |
1816 | utf8_step_ = MHD_WEBSOCKET_UTF8STEP_UTF3TAIL2_1OF2; | 2131 | utf8_step_ = MHD_WEBSOCKET_UTF8STEP_UTF3TAIL2_1OF2; |
1817 | } | 2132 | } |
1818 | else if ((0xE1 <= character) && (0xEC >= character) || | 2133 | else if (((0xE1 <= character) && (0xEC >= character)) || |
1819 | (0xEE <= character) && (0xEF >= character) ) | 2134 | ((0xEE <= character) && (0xEF >= character)) ) |
1820 | { | 2135 | { |
1821 | /* RFC 3629 4: three byte UTF-8 sequence, both tail bytes must be 0x80-0xBF */ | 2136 | /* RFC 3629 4: three byte UTF-8 sequence, both tail bytes must be 0x80-0xBF */ |
1822 | utf8_step_ = MHD_WEBSOCKET_UTF8STEP_UTF3TAIL_1OF2; | 2137 | utf8_step_ = MHD_WEBSOCKET_UTF8STEP_UTF3TAIL_1OF2; |
@@ -1991,30 +2306,32 @@ MHD_websocket_check_utf8 (const char*buf, | |||
1991 | 2306 | ||
1992 | 2307 | ||
1993 | /** | 2308 | /** |
1994 | * Calls srand in the scope of MHD to set the seed | ||
1995 | * for the random number generator used for masking. | ||
1996 | */ | ||
1997 | _MHD_EXTERN int | ||
1998 | MHD_websocket_srand (unsigned long seed) | ||
1999 | { | ||
2000 | srand (seed); | ||
2001 | |||
2002 | return MHD_WEBSOCKET_STATUS_OK; | ||
2003 | } | ||
2004 | |||
2005 | |||
2006 | /** | ||
2007 | * Generates a mask for masking by calling | 2309 | * Generates a mask for masking by calling |
2008 | * a random number generator. | 2310 | * a random number generator. |
2009 | */ | 2311 | */ |
2010 | static uint32_t | 2312 | static uint32_t |
2011 | MHD_websocket_generate_mask () | 2313 | MHD_websocket_generate_mask (struct MHD_WebSocketStream*ws) |
2012 | { | 2314 | { |
2013 | unsigned char mask_[4]; | 2315 | unsigned char mask_[4]; |
2014 | mask_ [0] = (unsigned char) (rand () & 0xFF); | 2316 | if (NULL != ws->rng) |
2015 | mask_ [1] = (unsigned char) (rand () & 0xFF); | 2317 | { |
2016 | mask_ [2] = (unsigned char) (rand () & 0xFF); | 2318 | size_t offset = 0; |
2017 | mask_ [3] = (unsigned char) (rand () & 0xFF); | 2319 | while (offset < 4) |
2320 | { | ||
2321 | size_t encoded = ws->rng (ws->cls_rng, | ||
2322 | mask_ + offset, | ||
2323 | 4 - offset); | ||
2324 | offset += encoded; | ||
2325 | } | ||
2326 | } | ||
2327 | else | ||
2328 | { | ||
2329 | /* this case should never happen */ | ||
2330 | mask_ [0] = 0; | ||
2331 | mask_ [1] = 0; | ||
2332 | mask_ [2] = 0; | ||
2333 | mask_ [3] = 0; | ||
2334 | } | ||
2018 | 2335 | ||
2019 | return *((uint32_t *) mask_); | 2336 | return *((uint32_t *) mask_); |
2020 | } | 2337 | } |
@@ -2024,15 +2341,15 @@ MHD_websocket_generate_mask () | |||
2024 | * Calls the malloc function associated with the websocket steam | 2341 | * Calls the malloc function associated with the websocket steam |
2025 | */ | 2342 | */ |
2026 | _MHD_EXTERN void* | 2343 | _MHD_EXTERN void* |
2027 | MHD_websocket_malloc (struct MHD_WebSocketStream*ws, | 2344 | MHD_websocket_malloc (struct MHD_WebSocketStream* ws, |
2028 | size_t len) | 2345 | size_t buf_len) |
2029 | { | 2346 | { |
2030 | if (NULL == ws) | 2347 | if (NULL == ws) |
2031 | { | 2348 | { |
2032 | return NULL; | 2349 | return NULL; |
2033 | } | 2350 | } |
2034 | 2351 | ||
2035 | return ws->malloc (len); | 2352 | return ws->malloc (buf_len); |
2036 | } | 2353 | } |
2037 | 2354 | ||
2038 | 2355 | ||
@@ -2040,16 +2357,16 @@ MHD_websocket_malloc (struct MHD_WebSocketStream*ws, | |||
2040 | * Calls the realloc function associated with the websocket steam | 2357 | * Calls the realloc function associated with the websocket steam |
2041 | */ | 2358 | */ |
2042 | _MHD_EXTERN void* | 2359 | _MHD_EXTERN void* |
2043 | MHD_websocket_realloc (struct MHD_WebSocketStream*ws, | 2360 | MHD_websocket_realloc (struct MHD_WebSocketStream* ws, |
2044 | void*cls, | 2361 | void* buf, |
2045 | size_t len) | 2362 | size_t new_buf_len) |
2046 | { | 2363 | { |
2047 | if (NULL == ws) | 2364 | if (NULL == ws) |
2048 | { | 2365 | { |
2049 | return NULL; | 2366 | return NULL; |
2050 | } | 2367 | } |
2051 | 2368 | ||
2052 | return ws->realloc (cls, len); | 2369 | return ws->realloc (buf, new_buf_len); |
2053 | } | 2370 | } |
2054 | 2371 | ||
2055 | 2372 | ||
@@ -2057,15 +2374,67 @@ MHD_websocket_realloc (struct MHD_WebSocketStream*ws, | |||
2057 | * Calls the free function associated with the websocket steam | 2374 | * Calls the free function associated with the websocket steam |
2058 | */ | 2375 | */ |
2059 | _MHD_EXTERN int | 2376 | _MHD_EXTERN int |
2060 | MHD_websocket_free (struct MHD_WebSocketStream*ws, | 2377 | MHD_websocket_free (struct MHD_WebSocketStream* ws, |
2061 | void*cls) | 2378 | void* buf) |
2062 | { | 2379 | { |
2063 | if (NULL == ws) | 2380 | if (NULL == ws) |
2064 | { | 2381 | { |
2065 | return MHD_WEBSOCKET_STATUS_PARAMETER_ERROR; | 2382 | return MHD_WEBSOCKET_STATUS_PARAMETER_ERROR; |
2066 | } | 2383 | } |
2067 | 2384 | ||
2068 | ws->free (cls); | 2385 | ws->free (buf); |
2069 | 2386 | ||
2070 | return MHD_WEBSOCKET_STATUS_OK; | 2387 | return MHD_WEBSOCKET_STATUS_OK; |
2071 | } | 2388 | } |
2389 | |||
2390 | /** | ||
2391 | * Converts a 16 bit value into network byte order (MSB first) | ||
2392 | * in dependence of the host system | ||
2393 | */ | ||
2394 | static uint16_t | ||
2395 | MHD_htons (uint16_t value) | ||
2396 | { | ||
2397 | uint16_t endian = 0x0001; | ||
2398 | |||
2399 | if (((char *) &endian)[0] == 0x01) | ||
2400 | { | ||
2401 | /* least significant byte first */ | ||
2402 | ((char *) &endian)[0] = ((char *) &value)[1]; | ||
2403 | ((char *) &endian)[1] = ((char *) &value)[0]; | ||
2404 | return endian; | ||
2405 | } | ||
2406 | else | ||
2407 | { | ||
2408 | /* most significant byte first */ | ||
2409 | return value; | ||
2410 | } | ||
2411 | } | ||
2412 | |||
2413 | /** | ||
2414 | * Converts a 64 bit value into network byte order (MSB first) | ||
2415 | * in dependence of the host system | ||
2416 | */ | ||
2417 | static uint64_t | ||
2418 | MHD_htonll (uint64_t value) | ||
2419 | { | ||
2420 | uint64_t endian = 0x0000000000000001; | ||
2421 | |||
2422 | if (((char *) &endian)[0] == 0x01) | ||
2423 | { | ||
2424 | /* least significant byte first */ | ||
2425 | ((char *) &endian)[0] = ((char *) &value)[7]; | ||
2426 | ((char *) &endian)[1] = ((char *) &value)[6]; | ||
2427 | ((char *) &endian)[2] = ((char *) &value)[5]; | ||
2428 | ((char *) &endian)[3] = ((char *) &value)[4]; | ||
2429 | ((char *) &endian)[4] = ((char *) &value)[3]; | ||
2430 | ((char *) &endian)[5] = ((char *) &value)[2]; | ||
2431 | ((char *) &endian)[6] = ((char *) &value)[1]; | ||
2432 | ((char *) &endian)[7] = ((char *) &value)[0]; | ||
2433 | return endian; | ||
2434 | } | ||
2435 | else | ||
2436 | { | ||
2437 | /* most significant byte first */ | ||
2438 | return value; | ||
2439 | } | ||
2440 | } | ||