diff options
Diffstat (limited to 'src/microhttpd_ws')
-rw-r--r-- | src/microhttpd_ws/mhd_websocket.c | 587 | ||||
-rw-r--r-- | src/microhttpd_ws/sha1.c | 720 | ||||
-rw-r--r-- | src/microhttpd_ws/sha1.h | 245 | ||||
-rw-r--r-- | src/microhttpd_ws/test_websocket.c | 1247 | ||||
-rw-r--r-- | src/microhttpd_ws/test_websocket_browser.c | 563 |
5 files changed, 2667 insertions, 695 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 | } | ||
diff --git a/src/microhttpd_ws/sha1.c b/src/microhttpd_ws/sha1.c index 910c1bdb..9888cbfe 100644 --- a/src/microhttpd_ws/sha1.c +++ b/src/microhttpd_ws/sha1.c | |||
@@ -1,420 +1,378 @@ | |||
1 | /* sha1.c - Functions to compute SHA1 message digest of files or | 1 | /* |
2 | memory blocks according to the NIST specification FIPS-180-1. | 2 | This file is part of libmicrohttpd |
3 | 3 | Copyright (C) 2019-2021 Karlson2k (Evgeny Grin) | |
4 | Copyright (C) 2000-2021 Free Software Foundation, Inc. | 4 | |
5 | 5 | libmicrohttpd is free software; you can redistribute it and/or | |
6 | This program is free software; you can redistribute it and/or modify it | 6 | modify it under the terms of the GNU Lesser General Public |
7 | under the terms of the GNU General Public License as published by the | 7 | License as published by the Free Software Foundation; either |
8 | Free Software Foundation; either version 2, or (at your option) any | 8 | version 2.1 of the License, or (at your option) any later version. |
9 | later version. | 9 | |
10 | 10 | This library is distributed in the hope that it will be useful, | |
11 | This program is distributed in the hope that it will be useful, | 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 13 | Lesser General Public License for more details. |
14 | GNU General Public License for more details. | 14 | |
15 | 15 | You should have received a copy of the GNU Lesser General Public | |
16 | You should have received a copy of the GNU General Public License | 16 | License along with this library. |
17 | along with this program; if not, write to the Free Software Foundation, | 17 | If not, see <http://www.gnu.org/licenses/>. |
18 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ | ||
19 | |||
20 | /* Written by Scott G. Miller | ||
21 | Credits: | ||
22 | Robert Klep <robert@ilse.nl> -- Expansion function fix | ||
23 | */ | 18 | */ |
24 | 19 | ||
25 | /*#include <config.h>*/ | 20 | /** |
21 | * @file microhttpd/sha1.c | ||
22 | * @brief Calculation of SHA-1 digest as defined in FIPS PUB 180-4 (2015) | ||
23 | * @author Karlson2k (Evgeny Grin) | ||
24 | */ | ||
26 | 25 | ||
27 | #include "sha1.h" | 26 | #include "sha1.h" |
28 | 27 | ||
29 | #include <stddef.h> | ||
30 | #include <string.h> | 28 | #include <string.h> |
31 | 29 | #ifdef HAVE_MEMORY_H | |
32 | #if USE_UNLOCKED_IO | 30 | #include <memory.h> |
33 | # include "unlocked-io.h" | 31 | #endif /* HAVE_MEMORY_H */ |
34 | #endif | 32 | #include "mhd_bithelpers.h" |
35 | 33 | #include "mhd_assert.h" | |
36 | #ifdef WORDS_BIGENDIAN | 34 | |
37 | # define SWAP(n) (n) | 35 | /** |
38 | #else | 36 | * Initialise structure for SHA-1 calculation. |
39 | # define SWAP(n) \ | 37 | * |
40 | (((n) << 24) | (((n) & 0xff00) << 8) | (((n) >> 8) & 0xff00) | ((n) >> 24)) | 38 | * @param ctx_ must be a `struct sha1_ctx *` |
41 | #endif | 39 | */ |
42 | |||
43 | #define BLOCKSIZE 4096 | ||
44 | #if BLOCKSIZE % 64 != 0 | ||
45 | # error "invalid BLOCKSIZE" | ||
46 | #endif | ||
47 | |||
48 | /* This array contains the bytes used to pad the buffer to the next | ||
49 | 64-byte boundary. (RFC 1321, 3.1: Step 1) */ | ||
50 | static const unsigned char fillbuf[64] = { 0x80, 0 /* , 0, 0, ... */ }; | ||
51 | |||
52 | |||
53 | /* Take a pointer to a 160 bit block of data (five 32 bit ints) and | ||
54 | initialize it to the start constants of the SHA1 algorithm. This | ||
55 | must be called before using hash in the call to sha1_hash. */ | ||
56 | void | 40 | void |
57 | sha1_init_ctx (struct sha1_ctx *ctx) | 41 | MHD_SHA1_init (void *ctx_) |
58 | { | 42 | { |
59 | ctx->A = 0x67452301; | 43 | struct sha1_ctx *const ctx = ctx_; |
60 | ctx->B = 0xefcdab89; | 44 | /* Initial hash values, see FIPS PUB 180-4 paragraph 5.3.1 */ |
61 | ctx->C = 0x98badcfe; | 45 | /* Just some "magic" numbers defined by standard */ |
62 | ctx->D = 0x10325476; | 46 | ctx->H[0] = UINT32_C (0x67452301); |
63 | ctx->E = 0xc3d2e1f0; | 47 | ctx->H[1] = UINT32_C (0xefcdab89); |
64 | 48 | ctx->H[2] = UINT32_C (0x98badcfe); | |
65 | ctx->total[0] = ctx->total[1] = 0; | 49 | ctx->H[3] = UINT32_C (0x10325476); |
66 | ctx->buflen = 0; | 50 | ctx->H[4] = UINT32_C (0xc3d2e1f0); |
51 | |||
52 | /* Initialise number of bytes. */ | ||
53 | ctx->count = 0; | ||
67 | } | 54 | } |
68 | 55 | ||
69 | 56 | ||
70 | /* Put result from CTX in first 20 bytes following RESBUF. The result | 57 | /** |
71 | must be in little endian byte order. | 58 | * Base of SHA-1 transformation. |
72 | 59 | * Gets full 512 bits / 64 bytes block of data and updates hash values; | |
73 | IMPORTANT: On some systems it is required that RESBUF is correctly | 60 | * @param H hash values |
74 | aligned for a 32-bit value. */ | 61 | * @param data data, must be exactly 64 bytes long |
75 | void * | 62 | */ |
76 | sha1_read_ctx (const struct sha1_ctx *ctx, void *resbuf) | 63 | static void |
64 | sha1_transform (uint32_t H[_SHA1_DIGEST_LENGTH], | ||
65 | const uint8_t data[SHA1_BLOCK_SIZE]) | ||
77 | { | 66 | { |
78 | ((sha1_uint32 *) resbuf)[0] = SWAP (ctx->A); | 67 | /* Working variables, |
79 | ((sha1_uint32 *) resbuf)[1] = SWAP (ctx->B); | 68 | see FIPS PUB 180-4 paragraph 6.1.3 */ |
80 | ((sha1_uint32 *) resbuf)[2] = SWAP (ctx->C); | 69 | uint32_t a = H[0]; |
81 | ((sha1_uint32 *) resbuf)[3] = SWAP (ctx->D); | 70 | uint32_t b = H[1]; |
82 | ((sha1_uint32 *) resbuf)[4] = SWAP (ctx->E); | 71 | uint32_t c = H[2]; |
83 | 72 | uint32_t d = H[3]; | |
84 | return resbuf; | 73 | uint32_t e = H[4]; |
74 | |||
75 | /* Data buffer, used as cyclic buffer. | ||
76 | See FIPS PUB 180-4 paragraphs 5.2.1, 6.1.3 */ | ||
77 | uint32_t W[16]; | ||
78 | |||
79 | /* 'Ch' and 'Maj' macro functions are defined with | ||
80 | widely-used optimization. | ||
81 | See FIPS PUB 180-4 formulae 4.1. */ | ||
82 | #define Ch(x,y,z) ( (z) ^ ((x) & ((y) ^ (z))) ) | ||
83 | #define Maj(x,y,z) ( ((x) & (y)) ^ ((z) & ((x) ^ (y))) ) | ||
84 | /* Unoptimized (original) versions: */ | ||
85 | /* #define Ch(x,y,z) ( ( (x) & (y) ) ^ ( ~(x) & (z) ) ) */ | ||
86 | /* #define Maj(x,y,z) ( ((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)) ) */ | ||
87 | #define Par(x,y,z) ( (x) ^ (y) ^ (z) ) | ||
88 | |||
89 | /* Single step of SHA-1 computation, | ||
90 | see FIPS PUB 180-4 paragraph 6.1.3 step 3. | ||
91 | * Note: instead of reassigning all working variables on each step, | ||
92 | variables are rotated for each step: | ||
93 | SHA1STEP32 (a, b, c, d, e, func, K00, W[0]); | ||
94 | SHA1STEP32 (e, a, b, c, d, func, K00, W[1]); | ||
95 | so current 'vC' will be used as 'vD' on the next step, | ||
96 | current 'vE' will be used as 'vA' on the next step. | ||
97 | * Note: 'wt' must be used exactly one time in this macro as it change other data as well | ||
98 | every time when used. */ | ||
99 | |||
100 | #define SHA1STEP32(vA,vB,vC,vD,vE,ft,kt,wt) do { \ | ||
101 | (vE) += _MHD_ROTL32 ((vA), 5) + ft ((vB), (vC), (vD)) + (kt) + (wt); \ | ||
102 | (vB) = _MHD_ROTL32 ((vB), 30); } while (0) | ||
103 | |||
104 | /* Get value of W(t) from input data buffer, | ||
105 | See FIPS PUB 180-4 paragraph 6.1.3. | ||
106 | Input data must be read in big-endian bytes order, | ||
107 | see FIPS PUB 180-4 paragraph 3.1.2. */ | ||
108 | #define GET_W_FROM_DATA(buf,t) \ | ||
109 | _MHD_GET_32BIT_BE (((const uint8_t*) (buf)) + (t) * SHA1_BYTES_IN_WORD) | ||
110 | |||
111 | #ifndef _MHD_GET_32BIT_BE_UNALIGNED | ||
112 | if (0 != (((uintptr_t) data) % _MHD_UINT32_ALIGN)) | ||
113 | { | ||
114 | /* Copy the unaligned input data to the aligned buffer */ | ||
115 | memcpy (W, data, SHA1_BLOCK_SIZE); | ||
116 | /* The W[] buffer itself will be used as the source of the data, | ||
117 | * but data will be reloaded in correct bytes order during | ||
118 | * the next steps */ | ||
119 | data = (uint8_t*) W; | ||
120 | } | ||
121 | #endif /* _MHD_GET_32BIT_BE_UNALIGNED */ | ||
122 | |||
123 | /* SHA-1 values of Kt for t=0..19, see FIPS PUB 180-4 paragraph 4.2.1. */ | ||
124 | #define K00 UINT32_C(0x5a827999) | ||
125 | /* SHA-1 values of Kt for t=20..39, see FIPS PUB 180-4 paragraph 4.2.1.*/ | ||
126 | #define K20 UINT32_C(0x6ed9eba1) | ||
127 | /* SHA-1 values of Kt for t=40..59, see FIPS PUB 180-4 paragraph 4.2.1.*/ | ||
128 | #define K40 UINT32_C(0x8f1bbcdc) | ||
129 | /* SHA-1 values of Kt for t=60..79, see FIPS PUB 180-4 paragraph 4.2.1.*/ | ||
130 | #define K60 UINT32_C(0xca62c1d6) | ||
131 | |||
132 | /* During first 16 steps, before making any calculations on each step, | ||
133 | the W element is read from input data buffer as big-endian value and | ||
134 | stored in array of W elements. */ | ||
135 | /* Note: instead of using K constants as array, all K values are specified | ||
136 | individually for each step. */ | ||
137 | SHA1STEP32 (a, b, c, d, e, Ch, K00, W[0] = GET_W_FROM_DATA (data, 0)); | ||
138 | SHA1STEP32 (e, a, b, c, d, Ch, K00, W[1] = GET_W_FROM_DATA (data, 1)); | ||
139 | SHA1STEP32 (d, e, a, b, c, Ch, K00, W[2] = GET_W_FROM_DATA (data, 2)); | ||
140 | SHA1STEP32 (c, d, e, a, b, Ch, K00, W[3] = GET_W_FROM_DATA (data, 3)); | ||
141 | SHA1STEP32 (b, c, d, e, a, Ch, K00, W[4] = GET_W_FROM_DATA (data, 4)); | ||
142 | SHA1STEP32 (a, b, c, d, e, Ch, K00, W[5] = GET_W_FROM_DATA (data, 5)); | ||
143 | SHA1STEP32 (e, a, b, c, d, Ch, K00, W[6] = GET_W_FROM_DATA (data, 6)); | ||
144 | SHA1STEP32 (d, e, a, b, c, Ch, K00, W[7] = GET_W_FROM_DATA (data, 7)); | ||
145 | SHA1STEP32 (c, d, e, a, b, Ch, K00, W[8] = GET_W_FROM_DATA (data, 8)); | ||
146 | SHA1STEP32 (b, c, d, e, a, Ch, K00, W[9] = GET_W_FROM_DATA (data, 9)); | ||
147 | SHA1STEP32 (a, b, c, d, e, Ch, K00, W[10] = GET_W_FROM_DATA (data, 10)); | ||
148 | SHA1STEP32 (e, a, b, c, d, Ch, K00, W[11] = GET_W_FROM_DATA (data, 11)); | ||
149 | SHA1STEP32 (d, e, a, b, c, Ch, K00, W[12] = GET_W_FROM_DATA (data, 12)); | ||
150 | SHA1STEP32 (c, d, e, a, b, Ch, K00, W[13] = GET_W_FROM_DATA (data, 13)); | ||
151 | SHA1STEP32 (b, c, d, e, a, Ch, K00, W[14] = GET_W_FROM_DATA (data, 14)); | ||
152 | SHA1STEP32 (a, b, c, d, e, Ch, K00, W[15] = GET_W_FROM_DATA (data, 15)); | ||
153 | |||
154 | /* 'W' generation and assignment for 16 <= t <= 79. | ||
155 | See FIPS PUB 180-4 paragraph 6.1.3. | ||
156 | As only last 16 'W' are used in calculations, it is possible to | ||
157 | use 16 elements array of W as cyclic buffer. */ | ||
158 | #define Wgen(w,t) _MHD_ROTL32((w)[(t + 13) & 0xf] ^ (w)[(t + 8) & 0xf] \ | ||
159 | ^ (w)[(t + 2) & 0xf] ^ (w)[t & 0xf], 1) | ||
160 | |||
161 | /* During last 60 steps, before making any calculations on each step, | ||
162 | W element is generated from W elements of cyclic buffer and generated value | ||
163 | stored back in cyclic buffer. */ | ||
164 | /* Note: instead of using K constants as array, all K values are specified | ||
165 | individually for each step, see FIPS PUB 180-4 paragraph 4.2.1. */ | ||
166 | SHA1STEP32 (e, a, b, c, d, Ch, K00, W[16 & 0xf] = Wgen (W, 16)); | ||
167 | SHA1STEP32 (d, e, a, b, c, Ch, K00, W[17 & 0xf] = Wgen (W, 17)); | ||
168 | SHA1STEP32 (c, d, e, a, b, Ch, K00, W[18 & 0xf] = Wgen (W, 18)); | ||
169 | SHA1STEP32 (b, c, d, e, a, Ch, K00, W[19 & 0xf] = Wgen (W, 19)); | ||
170 | SHA1STEP32 (a, b, c, d, e, Par, K20, W[20 & 0xf] = Wgen (W, 20)); | ||
171 | SHA1STEP32 (e, a, b, c, d, Par, K20, W[21 & 0xf] = Wgen (W, 21)); | ||
172 | SHA1STEP32 (d, e, a, b, c, Par, K20, W[22 & 0xf] = Wgen (W, 22)); | ||
173 | SHA1STEP32 (c, d, e, a, b, Par, K20, W[23 & 0xf] = Wgen (W, 23)); | ||
174 | SHA1STEP32 (b, c, d, e, a, Par, K20, W[24 & 0xf] = Wgen (W, 24)); | ||
175 | SHA1STEP32 (a, b, c, d, e, Par, K20, W[25 & 0xf] = Wgen (W, 25)); | ||
176 | SHA1STEP32 (e, a, b, c, d, Par, K20, W[26 & 0xf] = Wgen (W, 26)); | ||
177 | SHA1STEP32 (d, e, a, b, c, Par, K20, W[27 & 0xf] = Wgen (W, 27)); | ||
178 | SHA1STEP32 (c, d, e, a, b, Par, K20, W[28 & 0xf] = Wgen (W, 28)); | ||
179 | SHA1STEP32 (b, c, d, e, a, Par, K20, W[29 & 0xf] = Wgen (W, 29)); | ||
180 | SHA1STEP32 (a, b, c, d, e, Par, K20, W[30 & 0xf] = Wgen (W, 30)); | ||
181 | SHA1STEP32 (e, a, b, c, d, Par, K20, W[31 & 0xf] = Wgen (W, 31)); | ||
182 | SHA1STEP32 (d, e, a, b, c, Par, K20, W[32 & 0xf] = Wgen (W, 32)); | ||
183 | SHA1STEP32 (c, d, e, a, b, Par, K20, W[33 & 0xf] = Wgen (W, 33)); | ||
184 | SHA1STEP32 (b, c, d, e, a, Par, K20, W[34 & 0xf] = Wgen (W, 34)); | ||
185 | SHA1STEP32 (a, b, c, d, e, Par, K20, W[35 & 0xf] = Wgen (W, 35)); | ||
186 | SHA1STEP32 (e, a, b, c, d, Par, K20, W[36 & 0xf] = Wgen (W, 36)); | ||
187 | SHA1STEP32 (d, e, a, b, c, Par, K20, W[37 & 0xf] = Wgen (W, 37)); | ||
188 | SHA1STEP32 (c, d, e, a, b, Par, K20, W[38 & 0xf] = Wgen (W, 38)); | ||
189 | SHA1STEP32 (b, c, d, e, a, Par, K20, W[39 & 0xf] = Wgen (W, 39)); | ||
190 | SHA1STEP32 (a, b, c, d, e, Maj, K40, W[40 & 0xf] = Wgen (W, 40)); | ||
191 | SHA1STEP32 (e, a, b, c, d, Maj, K40, W[41 & 0xf] = Wgen (W, 41)); | ||
192 | SHA1STEP32 (d, e, a, b, c, Maj, K40, W[42 & 0xf] = Wgen (W, 42)); | ||
193 | SHA1STEP32 (c, d, e, a, b, Maj, K40, W[43 & 0xf] = Wgen (W, 43)); | ||
194 | SHA1STEP32 (b, c, d, e, a, Maj, K40, W[44 & 0xf] = Wgen (W, 44)); | ||
195 | SHA1STEP32 (a, b, c, d, e, Maj, K40, W[45 & 0xf] = Wgen (W, 45)); | ||
196 | SHA1STEP32 (e, a, b, c, d, Maj, K40, W[46 & 0xf] = Wgen (W, 46)); | ||
197 | SHA1STEP32 (d, e, a, b, c, Maj, K40, W[47 & 0xf] = Wgen (W, 47)); | ||
198 | SHA1STEP32 (c, d, e, a, b, Maj, K40, W[48 & 0xf] = Wgen (W, 48)); | ||
199 | SHA1STEP32 (b, c, d, e, a, Maj, K40, W[49 & 0xf] = Wgen (W, 49)); | ||
200 | SHA1STEP32 (a, b, c, d, e, Maj, K40, W[50 & 0xf] = Wgen (W, 50)); | ||
201 | SHA1STEP32 (e, a, b, c, d, Maj, K40, W[51 & 0xf] = Wgen (W, 51)); | ||
202 | SHA1STEP32 (d, e, a, b, c, Maj, K40, W[52 & 0xf] = Wgen (W, 52)); | ||
203 | SHA1STEP32 (c, d, e, a, b, Maj, K40, W[53 & 0xf] = Wgen (W, 53)); | ||
204 | SHA1STEP32 (b, c, d, e, a, Maj, K40, W[54 & 0xf] = Wgen (W, 54)); | ||
205 | SHA1STEP32 (a, b, c, d, e, Maj, K40, W[55 & 0xf] = Wgen (W, 55)); | ||
206 | SHA1STEP32 (e, a, b, c, d, Maj, K40, W[56 & 0xf] = Wgen (W, 56)); | ||
207 | SHA1STEP32 (d, e, a, b, c, Maj, K40, W[57 & 0xf] = Wgen (W, 57)); | ||
208 | SHA1STEP32 (c, d, e, a, b, Maj, K40, W[58 & 0xf] = Wgen (W, 58)); | ||
209 | SHA1STEP32 (b, c, d, e, a, Maj, K40, W[59 & 0xf] = Wgen (W, 59)); | ||
210 | SHA1STEP32 (a, b, c, d, e, Par, K60, W[60 & 0xf] = Wgen (W, 60)); | ||
211 | SHA1STEP32 (e, a, b, c, d, Par, K60, W[61 & 0xf] = Wgen (W, 61)); | ||
212 | SHA1STEP32 (d, e, a, b, c, Par, K60, W[62 & 0xf] = Wgen (W, 62)); | ||
213 | SHA1STEP32 (c, d, e, a, b, Par, K60, W[63 & 0xf] = Wgen (W, 63)); | ||
214 | SHA1STEP32 (b, c, d, e, a, Par, K60, W[64 & 0xf] = Wgen (W, 64)); | ||
215 | SHA1STEP32 (a, b, c, d, e, Par, K60, W[65 & 0xf] = Wgen (W, 65)); | ||
216 | SHA1STEP32 (e, a, b, c, d, Par, K60, W[66 & 0xf] = Wgen (W, 66)); | ||
217 | SHA1STEP32 (d, e, a, b, c, Par, K60, W[67 & 0xf] = Wgen (W, 67)); | ||
218 | SHA1STEP32 (c, d, e, a, b, Par, K60, W[68 & 0xf] = Wgen (W, 68)); | ||
219 | SHA1STEP32 (b, c, d, e, a, Par, K60, W[69 & 0xf] = Wgen (W, 69)); | ||
220 | SHA1STEP32 (a, b, c, d, e, Par, K60, W[70 & 0xf] = Wgen (W, 70)); | ||
221 | SHA1STEP32 (e, a, b, c, d, Par, K60, W[71 & 0xf] = Wgen (W, 71)); | ||
222 | SHA1STEP32 (d, e, a, b, c, Par, K60, W[72 & 0xf] = Wgen (W, 72)); | ||
223 | SHA1STEP32 (c, d, e, a, b, Par, K60, W[73 & 0xf] = Wgen (W, 73)); | ||
224 | SHA1STEP32 (b, c, d, e, a, Par, K60, W[74 & 0xf] = Wgen (W, 74)); | ||
225 | SHA1STEP32 (a, b, c, d, e, Par, K60, W[75 & 0xf] = Wgen (W, 75)); | ||
226 | SHA1STEP32 (e, a, b, c, d, Par, K60, W[76 & 0xf] = Wgen (W, 76)); | ||
227 | SHA1STEP32 (d, e, a, b, c, Par, K60, W[77 & 0xf] = Wgen (W, 77)); | ||
228 | SHA1STEP32 (c, d, e, a, b, Par, K60, W[78 & 0xf] = Wgen (W, 78)); | ||
229 | SHA1STEP32 (b, c, d, e, a, Par, K60, W[79 & 0xf] = Wgen (W, 79)); | ||
230 | |||
231 | /* Compute intermediate hash. | ||
232 | See FIPS PUB 180-4 paragraph 6.1.3 step 4. */ | ||
233 | H[0] += a; | ||
234 | H[1] += b; | ||
235 | H[2] += c; | ||
236 | H[3] += d; | ||
237 | H[4] += e; | ||
85 | } | 238 | } |
86 | 239 | ||
87 | 240 | ||
88 | /* Process the remaining bytes in the internal buffer and the usual | 241 | /** |
89 | prolog according to the standard and write the result to RESBUF. | 242 | * Process portion of bytes. |
90 | 243 | * | |
91 | IMPORTANT: On some systems it is required that RESBUF is correctly | 244 | * @param ctx_ must be a `struct sha1_ctx *` |
92 | aligned for a 32-bit value. */ | 245 | * @param data bytes to add to hash |
93 | void * | 246 | * @param length number of bytes in @a data |
94 | sha1_finish_ctx (struct sha1_ctx *ctx, void *resbuf) | 247 | */ |
248 | void | ||
249 | MHD_SHA1_update (void *ctx_, | ||
250 | const uint8_t *data, | ||
251 | size_t length) | ||
95 | { | 252 | { |
96 | /* Take yet unprocessed bytes into account. */ | 253 | struct sha1_ctx *const ctx = ctx_; |
97 | sha1_uint32 bytes = ctx->buflen; | 254 | unsigned bytes_have; /**< Number of bytes in buffer */ |
98 | size_t size = (bytes < 56) ? 64 / 4 : 64 * 2 / 4; | ||
99 | |||
100 | /* Now count remaining bytes. */ | ||
101 | ctx->total[0] += bytes; | ||
102 | if (ctx->total[0] < bytes) | ||
103 | ++ctx->total[1]; | ||
104 | |||
105 | /* Put the 64-bit file length in *bits* at the end of the buffer. */ | ||
106 | ctx->buffer[size - 2] = SWAP ((ctx->total[1] << 3) | (ctx->total[0] >> 29)); | ||
107 | ctx->buffer[size - 1] = SWAP (ctx->total[0] << 3); | ||
108 | |||
109 | memcpy (&((char *) ctx->buffer)[bytes], fillbuf, (size - 2) * 4 - bytes); | ||
110 | |||
111 | /* Process last bytes. */ | ||
112 | sha1_process_block (ctx->buffer, size * 4, ctx); | ||
113 | |||
114 | return sha1_read_ctx (ctx, resbuf); | ||
115 | } | ||
116 | 255 | ||
256 | mhd_assert ((data != NULL) || (length == 0)); | ||
117 | 257 | ||
118 | /* Compute SHA1 message digest for bytes read from STREAM. The | 258 | if (0 == length) |
119 | resulting message digest number will be written into the 16 bytes | 259 | return; /* Do nothing */ |
120 | beginning at RESBLOCK. */ | ||
121 | int | ||
122 | sha1_stream (FILE *stream, void *resblock) | ||
123 | { | ||
124 | struct sha1_ctx ctx; | ||
125 | char buffer[BLOCKSIZE + 72]; | ||
126 | size_t sum; | ||
127 | 260 | ||
128 | /* Initialize the computation context. */ | 261 | /* Note: (count & (SHA1_BLOCK_SIZE-1)) |
129 | sha1_init_ctx (&ctx); | 262 | equal (count % SHA1_BLOCK_SIZE) for this block size. */ |
263 | bytes_have = (unsigned) (ctx->count & (SHA1_BLOCK_SIZE - 1)); | ||
264 | ctx->count += length; | ||
130 | 265 | ||
131 | /* Iterate over full file contents. */ | 266 | if (0 != bytes_have) |
132 | while (1) | ||
133 | { | 267 | { |
134 | /* We read the file in blocks of BLOCKSIZE bytes. One call of the | 268 | unsigned bytes_left = SHA1_BLOCK_SIZE - bytes_have; |
135 | computation function processes the whole buffer so that with the | 269 | if (length >= bytes_left) |
136 | next round of the loop another block can be read. */ | 270 | { /* Combine new data with the data in the buffer and |
137 | size_t n; | 271 | process the full block. */ |
138 | sum = 0; | 272 | memcpy (ctx->buffer + bytes_have, |
139 | 273 | data, | |
140 | /* Read block. Take care for partial reads. */ | 274 | bytes_left); |
141 | while (1) | 275 | data += bytes_left; |
142 | { | 276 | length -= bytes_left; |
143 | n = fread (buffer + sum, 1, BLOCKSIZE - sum, stream); | 277 | sha1_transform (ctx->H, ctx->buffer); |
144 | 278 | bytes_have = 0; | |
145 | sum += n; | ||
146 | |||
147 | if (sum == BLOCKSIZE) | ||
148 | break; | ||
149 | |||
150 | if (n == 0) | ||
151 | { | ||
152 | /* Check for the error flag IFF N == 0, so that we don't | ||
153 | exit the loop after a partial read due to e.g., EAGAIN | ||
154 | or EWOULDBLOCK. */ | ||
155 | if (ferror (stream)) | ||
156 | return 1; | ||
157 | goto process_partial_block; | ||
158 | } | ||
159 | |||
160 | /* We've read at least one byte, so ignore errors. But always | ||
161 | check for EOF, since feof may be true even though N > 0. | ||
162 | Otherwise, we could end up calling fread after EOF. */ | ||
163 | if (feof (stream)) | ||
164 | goto process_partial_block; | ||
165 | } | 279 | } |
166 | |||
167 | /* Process buffer with BLOCKSIZE bytes. Note that | ||
168 | BLOCKSIZE % 64 == 0 | ||
169 | */ | ||
170 | sha1_process_block (buffer, BLOCKSIZE, &ctx); | ||
171 | } | 280 | } |
172 | 281 | ||
173 | process_partial_block:; | 282 | while (SHA1_BLOCK_SIZE <= length) |
174 | 283 | { /* Process any full blocks of new data directly, | |
175 | /* Process any remaining bytes. */ | 284 | without copying to the buffer. */ |
176 | if (sum > 0) | 285 | sha1_transform (ctx->H, data); |
177 | sha1_process_bytes (buffer, sum, &ctx); | 286 | data += SHA1_BLOCK_SIZE; |
287 | length -= SHA1_BLOCK_SIZE; | ||
288 | } | ||
178 | 289 | ||
179 | /* Construct result in desired memory. */ | 290 | if (0 != length) |
180 | sha1_finish_ctx (&ctx, resblock); | 291 | { /* Copy incomplete block of new data (if any) |
181 | return 0; | 292 | to the buffer. */ |
293 | memcpy (ctx->buffer + bytes_have, data, length); | ||
294 | } | ||
182 | } | 295 | } |
183 | 296 | ||
184 | 297 | ||
185 | /* Compute SHA1 message digest for LEN bytes beginning at BUFFER. The | 298 | /** |
186 | result is always in little endian byte order, so that a byte-wise | 299 | * Size of "length" padding addition in bytes. |
187 | output yields to the wanted ASCII representation of the message | 300 | * See FIPS PUB 180-4 paragraph 5.1.1. |
188 | digest. */ | 301 | */ |
189 | void * | 302 | #define SHA1_SIZE_OF_LEN_ADD (64 / 8) |
190 | sha1_buffer (const char *buffer, size_t len, void *resblock) | ||
191 | { | ||
192 | struct sha1_ctx ctx; | ||
193 | |||
194 | /* Initialize the computation context. */ | ||
195 | sha1_init_ctx (&ctx); | ||
196 | |||
197 | /* Process whole buffer but last len % 64 bytes. */ | ||
198 | sha1_process_bytes (buffer, len, &ctx); | ||
199 | |||
200 | /* Put result in desired memory area. */ | ||
201 | return sha1_finish_ctx (&ctx, resblock); | ||
202 | } | ||
203 | |||
204 | 303 | ||
304 | /** | ||
305 | * Finalise SHA-1 calculation, return digest. | ||
306 | * | ||
307 | * @param ctx_ must be a `struct sha1_ctx *` | ||
308 | * @param[out] digest set to the hash, must be #SHA1_DIGEST_SIZE bytes | ||
309 | */ | ||
205 | void | 310 | void |
206 | sha1_process_bytes (const void *buffer, size_t len, struct sha1_ctx *ctx) | 311 | MHD_SHA1_finish (void *ctx_, |
312 | uint8_t digest[SHA1_DIGEST_SIZE]) | ||
207 | { | 313 | { |
208 | /* When we already have some bits in our internal buffer concatenate | 314 | struct sha1_ctx *const ctx = ctx_; |
209 | both inputs first. */ | 315 | uint64_t num_bits; /**< Number of processed bits */ |
210 | if (ctx->buflen != 0) | 316 | unsigned bytes_have; /**< Number of bytes in buffer */ |
211 | { | 317 | |
212 | size_t left_over = ctx->buflen; | 318 | num_bits = ctx->count << 3; |
213 | size_t add = 128 - left_over > len ? len : 128 - left_over; | 319 | /* Note: (count & (SHA1_BLOCK_SIZE-1)) |
214 | 320 | equals (count % SHA1_BLOCK_SIZE) for this block size. */ | |
215 | memcpy (&((char *) ctx->buffer)[left_over], buffer, add); | 321 | bytes_have = (unsigned) (ctx->count & (SHA1_BLOCK_SIZE - 1)); |
216 | ctx->buflen += add; | 322 | |
217 | 323 | /* Input data must be padded with bit "1" and with length of data in bits. | |
218 | if (ctx->buflen > 64) | 324 | See FIPS PUB 180-4 paragraph 5.1.1. */ |
219 | { | 325 | /* Data is always processed in form of bytes (not by individual bits), |
220 | sha1_process_block (ctx->buffer, ctx->buflen & ~63, ctx); | 326 | therefore position of first padding bit in byte is always predefined (0x80). */ |
221 | 327 | /* Buffer always have space at least for one byte (as full buffers are | |
222 | ctx->buflen &= 63; | 328 | processed immediately). */ |
223 | /* The regions in the following copy operation cannot overlap. */ | 329 | ctx->buffer[bytes_have++] = 0x80; |
224 | memcpy (ctx->buffer, | 330 | |
225 | &((char *) ctx->buffer)[(left_over + add) & ~63], | 331 | if (SHA1_BLOCK_SIZE - bytes_have < SHA1_SIZE_OF_LEN_ADD) |
226 | ctx->buflen); | 332 | { /* No space in current block to put total length of message. |
227 | } | 333 | Pad current block with zeros and process it. */ |
228 | 334 | if (SHA1_BLOCK_SIZE > bytes_have) | |
229 | buffer = (const char *) buffer + add; | 335 | memset (ctx->buffer + bytes_have, 0, SHA1_BLOCK_SIZE - bytes_have); |
230 | len -= add; | 336 | /* Process full block. */ |
337 | sha1_transform (ctx->H, ctx->buffer); | ||
338 | /* Start new block. */ | ||
339 | bytes_have = 0; | ||
231 | } | 340 | } |
232 | 341 | ||
233 | /* Process available complete blocks. */ | 342 | /* Pad the rest of the buffer with zeros. */ |
234 | if (len >= 64) | 343 | memset (ctx->buffer + bytes_have, 0, |
344 | SHA1_BLOCK_SIZE - SHA1_SIZE_OF_LEN_ADD - bytes_have); | ||
345 | /* Put the number of bits in the processed message as a big-endian value. */ | ||
346 | _MHD_PUT_64BIT_BE_SAFE (ctx->buffer + SHA1_BLOCK_SIZE - SHA1_SIZE_OF_LEN_ADD, | ||
347 | num_bits); | ||
348 | /* Process the full final block. */ | ||
349 | sha1_transform (ctx->H, ctx->buffer); | ||
350 | |||
351 | /* Put final hash/digest in BE mode */ | ||
352 | #ifndef _MHD_PUT_32BIT_BE_UNALIGNED | ||
353 | if (0 != ((uintptr_t) digest) % _MHD_UINT32_ALIGN) | ||
235 | { | 354 | { |
236 | #if ! _STRING_ARCH_unaligned | 355 | uint32_t alig_dgst[_SHA1_DIGEST_LENGTH]; |
237 | # define alignof(type) offsetof (struct { char c; type x; }, x) | 356 | _MHD_PUT_32BIT_BE (alig_dgst + 0, ctx->H[0]); |
238 | # define UNALIGNED_P(p) (((size_t) p) % alignof (sha1_uint32) != 0) | 357 | _MHD_PUT_32BIT_BE (alig_dgst + 1, ctx->H[1]); |
239 | if (UNALIGNED_P (buffer)) | 358 | _MHD_PUT_32BIT_BE (alig_dgst + 2, ctx->H[2]); |
240 | while (len > 64) | 359 | _MHD_PUT_32BIT_BE (alig_dgst + 3, ctx->H[3]); |
241 | { | 360 | _MHD_PUT_32BIT_BE (alig_dgst + 4, ctx->H[4]); |
242 | sha1_process_block (memcpy (ctx->buffer, buffer, 64), 64, ctx); | 361 | /* Copy result to unaligned destination address */ |
243 | buffer = (const char *) buffer + 64; | 362 | memcpy (digest, alig_dgst, SHA1_DIGEST_SIZE); |
244 | len -= 64; | ||
245 | } | ||
246 | else | ||
247 | #endif | ||
248 | { | ||
249 | sha1_process_block (buffer, len & ~63, ctx); | ||
250 | buffer = (const char *) buffer + (len & ~63); | ||
251 | len &= 63; | ||
252 | } | ||
253 | } | 363 | } |
254 | 364 | else | |
255 | /* Move remaining bytes in internal buffer. */ | 365 | #else /* _MHD_PUT_32BIT_BE_UNALIGNED */ |
256 | if (len > 0) | 366 | if (1) |
367 | #endif /* _MHD_PUT_32BIT_BE_UNALIGNED */ | ||
257 | { | 368 | { |
258 | size_t left_over = ctx->buflen; | 369 | _MHD_PUT_32BIT_BE (digest + 0 * SHA1_BYTES_IN_WORD, ctx->H[0]); |
259 | 370 | _MHD_PUT_32BIT_BE (digest + 1 * SHA1_BYTES_IN_WORD, ctx->H[1]); | |
260 | memcpy (&((char *) ctx->buffer)[left_over], buffer, len); | 371 | _MHD_PUT_32BIT_BE (digest + 2 * SHA1_BYTES_IN_WORD, ctx->H[2]); |
261 | left_over += len; | 372 | _MHD_PUT_32BIT_BE (digest + 3 * SHA1_BYTES_IN_WORD, ctx->H[3]); |
262 | if (left_over >= 64) | 373 | _MHD_PUT_32BIT_BE (digest + 4 * SHA1_BYTES_IN_WORD, ctx->H[4]); |
263 | { | ||
264 | sha1_process_block (ctx->buffer, 64, ctx); | ||
265 | left_over -= 64; | ||
266 | memmove (ctx->buffer, &ctx->buffer[16], left_over); | ||
267 | } | ||
268 | ctx->buflen = left_over; | ||
269 | } | 374 | } |
270 | } | ||
271 | |||
272 | |||
273 | /* --- Code below is the primary difference between md5.c and sha1.c --- */ | ||
274 | |||
275 | /* SHA1 round constants */ | ||
276 | #define K1 0x5a827999 | ||
277 | #define K2 0x6ed9eba1 | ||
278 | #define K3 0x8f1bbcdc | ||
279 | #define K4 0xca62c1d6 | ||
280 | |||
281 | /* Round functions. Note that F2 is the same as F4. */ | ||
282 | #define F1(B,C,D) ( D ^ ( B & ( C ^ D ) ) ) | ||
283 | #define F2(B,C,D) (B ^ C ^ D) | ||
284 | #define F3(B,C,D) ( ( B & C ) | ( D & ( B | C ) ) ) | ||
285 | #define F4(B,C,D) (B ^ C ^ D) | ||
286 | |||
287 | /* Process LEN bytes of BUFFER, accumulating context into CTX. | ||
288 | It is assumed that LEN % 64 == 0. | ||
289 | Most of this code comes from GnuPG's cipher/sha1.c. */ | ||
290 | 375 | ||
291 | void | 376 | /* Erase potentially sensitive data. */ |
292 | sha1_process_block (const void *buffer, size_t len, struct sha1_ctx *ctx) | 377 | memset (ctx, 0, sizeof(struct sha1_ctx)); |
293 | { | ||
294 | const sha1_uint32 *words = (const sha1_uint32*) buffer; | ||
295 | size_t nwords = len / sizeof (sha1_uint32); | ||
296 | const sha1_uint32 *endp = words + nwords; | ||
297 | sha1_uint32 x[16]; | ||
298 | sha1_uint32 a = ctx->A; | ||
299 | sha1_uint32 b = ctx->B; | ||
300 | sha1_uint32 c = ctx->C; | ||
301 | sha1_uint32 d = ctx->D; | ||
302 | sha1_uint32 e = ctx->E; | ||
303 | |||
304 | /* First increment the byte count. RFC 1321 specifies the possible | ||
305 | length of the file up to 2^64 bits. Here we only compute the | ||
306 | number of bytes. Do a double word increment. */ | ||
307 | ctx->total[0] += len; | ||
308 | ctx->total[1] += ((len >> 31) >> 1) + (ctx->total[0] < len); | ||
309 | |||
310 | #define rol(x, n) (((x) << (n)) | ((sha1_uint32) (x) >> (32 - (n)))) | ||
311 | |||
312 | #define M(I) ( tm = x[I&0x0f] ^ x[(I-14)&0x0f] \ | ||
313 | ^ x[(I-8)&0x0f] ^ x[(I-3)&0x0f] \ | ||
314 | , (x[I&0x0f] = rol(tm, 1)) ) | ||
315 | |||
316 | #define R(A,B,C,D,E,F,K,M) do { E += rol( A, 5 ) \ | ||
317 | + F( B, C, D ) \ | ||
318 | + K \ | ||
319 | + M; \ | ||
320 | B = rol( B, 30 ); \ | ||
321 | } while(0) | ||
322 | |||
323 | while (words < endp) | ||
324 | { | ||
325 | sha1_uint32 tm; | ||
326 | int t; | ||
327 | for (t = 0; t < 16; t++) | ||
328 | { | ||
329 | x[t] = SWAP (*words); | ||
330 | words++; | ||
331 | } | ||
332 | |||
333 | R (a, b, c, d, e, F1, K1, x[ 0]); | ||
334 | R (e, a, b, c, d, F1, K1, x[ 1]); | ||
335 | R (d, e, a, b, c, F1, K1, x[ 2]); | ||
336 | R (c, d, e, a, b, F1, K1, x[ 3]); | ||
337 | R (b, c, d, e, a, F1, K1, x[ 4]); | ||
338 | R (a, b, c, d, e, F1, K1, x[ 5]); | ||
339 | R (e, a, b, c, d, F1, K1, x[ 6]); | ||
340 | R (d, e, a, b, c, F1, K1, x[ 7]); | ||
341 | R (c, d, e, a, b, F1, K1, x[ 8]); | ||
342 | R (b, c, d, e, a, F1, K1, x[ 9]); | ||
343 | R (a, b, c, d, e, F1, K1, x[10]); | ||
344 | R (e, a, b, c, d, F1, K1, x[11]); | ||
345 | R (d, e, a, b, c, F1, K1, x[12]); | ||
346 | R (c, d, e, a, b, F1, K1, x[13]); | ||
347 | R (b, c, d, e, a, F1, K1, x[14]); | ||
348 | R (a, b, c, d, e, F1, K1, x[15]); | ||
349 | R (e, a, b, c, d, F1, K1, M (16) ); | ||
350 | R (d, e, a, b, c, F1, K1, M (17) ); | ||
351 | R (c, d, e, a, b, F1, K1, M (18) ); | ||
352 | R (b, c, d, e, a, F1, K1, M (19) ); | ||
353 | R (a, b, c, d, e, F2, K2, M (20) ); | ||
354 | R (e, a, b, c, d, F2, K2, M (21) ); | ||
355 | R (d, e, a, b, c, F2, K2, M (22) ); | ||
356 | R (c, d, e, a, b, F2, K2, M (23) ); | ||
357 | R (b, c, d, e, a, F2, K2, M (24) ); | ||
358 | R (a, b, c, d, e, F2, K2, M (25) ); | ||
359 | R (e, a, b, c, d, F2, K2, M (26) ); | ||
360 | R (d, e, a, b, c, F2, K2, M (27) ); | ||
361 | R (c, d, e, a, b, F2, K2, M (28) ); | ||
362 | R (b, c, d, e, a, F2, K2, M (29) ); | ||
363 | R (a, b, c, d, e, F2, K2, M (30) ); | ||
364 | R (e, a, b, c, d, F2, K2, M (31) ); | ||
365 | R (d, e, a, b, c, F2, K2, M (32) ); | ||
366 | R (c, d, e, a, b, F2, K2, M (33) ); | ||
367 | R (b, c, d, e, a, F2, K2, M (34) ); | ||
368 | R (a, b, c, d, e, F2, K2, M (35) ); | ||
369 | R (e, a, b, c, d, F2, K2, M (36) ); | ||
370 | R (d, e, a, b, c, F2, K2, M (37) ); | ||
371 | R (c, d, e, a, b, F2, K2, M (38) ); | ||
372 | R (b, c, d, e, a, F2, K2, M (39) ); | ||
373 | R (a, b, c, d, e, F3, K3, M (40) ); | ||
374 | R (e, a, b, c, d, F3, K3, M (41) ); | ||
375 | R (d, e, a, b, c, F3, K3, M (42) ); | ||
376 | R (c, d, e, a, b, F3, K3, M (43) ); | ||
377 | R (b, c, d, e, a, F3, K3, M (44) ); | ||
378 | R (a, b, c, d, e, F3, K3, M (45) ); | ||
379 | R (e, a, b, c, d, F3, K3, M (46) ); | ||
380 | R (d, e, a, b, c, F3, K3, M (47) ); | ||
381 | R (c, d, e, a, b, F3, K3, M (48) ); | ||
382 | R (b, c, d, e, a, F3, K3, M (49) ); | ||
383 | R (a, b, c, d, e, F3, K3, M (50) ); | ||
384 | R (e, a, b, c, d, F3, K3, M (51) ); | ||
385 | R (d, e, a, b, c, F3, K3, M (52) ); | ||
386 | R (c, d, e, a, b, F3, K3, M (53) ); | ||
387 | R (b, c, d, e, a, F3, K3, M (54) ); | ||
388 | R (a, b, c, d, e, F3, K3, M (55) ); | ||
389 | R (e, a, b, c, d, F3, K3, M (56) ); | ||
390 | R (d, e, a, b, c, F3, K3, M (57) ); | ||
391 | R (c, d, e, a, b, F3, K3, M (58) ); | ||
392 | R (b, c, d, e, a, F3, K3, M (59) ); | ||
393 | R (a, b, c, d, e, F4, K4, M (60) ); | ||
394 | R (e, a, b, c, d, F4, K4, M (61) ); | ||
395 | R (d, e, a, b, c, F4, K4, M (62) ); | ||
396 | R (c, d, e, a, b, F4, K4, M (63) ); | ||
397 | R (b, c, d, e, a, F4, K4, M (64) ); | ||
398 | R (a, b, c, d, e, F4, K4, M (65) ); | ||
399 | R (e, a, b, c, d, F4, K4, M (66) ); | ||
400 | R (d, e, a, b, c, F4, K4, M (67) ); | ||
401 | R (c, d, e, a, b, F4, K4, M (68) ); | ||
402 | R (b, c, d, e, a, F4, K4, M (69) ); | ||
403 | R (a, b, c, d, e, F4, K4, M (70) ); | ||
404 | R (e, a, b, c, d, F4, K4, M (71) ); | ||
405 | R (d, e, a, b, c, F4, K4, M (72) ); | ||
406 | R (c, d, e, a, b, F4, K4, M (73) ); | ||
407 | R (b, c, d, e, a, F4, K4, M (74) ); | ||
408 | R (a, b, c, d, e, F4, K4, M (75) ); | ||
409 | R (e, a, b, c, d, F4, K4, M (76) ); | ||
410 | R (d, e, a, b, c, F4, K4, M (77) ); | ||
411 | R (c, d, e, a, b, F4, K4, M (78) ); | ||
412 | R (b, c, d, e, a, F4, K4, M (79) ); | ||
413 | |||
414 | a = ctx->A += a; | ||
415 | b = ctx->B += b; | ||
416 | c = ctx->C += c; | ||
417 | d = ctx->D += d; | ||
418 | e = ctx->E += e; | ||
419 | } | ||
420 | } | 378 | } |
diff --git a/src/microhttpd_ws/sha1.h b/src/microhttpd_ws/sha1.h index be0d190b..851a4429 100644 --- a/src/microhttpd_ws/sha1.h +++ b/src/microhttpd_ws/sha1.h | |||
@@ -1,145 +1,110 @@ | |||
1 | /* Declarations of functions and data types used for SHA1 sum | 1 | /* |
2 | library functions. | 2 | This file is part of libmicrohttpd |
3 | Copyright (C) 2000-2021 Free Software Foundation, Inc. | 3 | Copyright (C) 2019-2021 Karlson2k (Evgeny Grin) |
4 | 4 | ||
5 | This program is free software; you can redistribute it and/or modify it | 5 | This library is free software; you can redistribute it and/or |
6 | under the terms of the GNU General Public License as published by the | 6 | modify it under the terms of the GNU Lesser General Public |
7 | Free Software Foundation; either version 3, or (at your option) any | 7 | License as published by the Free Software Foundation; either |
8 | later version. | 8 | version 2.1 of the License, or (at your option) any later version. |
9 | 9 | ||
10 | This program is distributed in the hope that it will be useful, | 10 | This library is distributed in the hope that it will be useful, |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
13 | GNU General Public License for more details. | 13 | Lesser General Public License for more details. |
14 | 14 | ||
15 | You should have received a copy of the GNU General Public License | 15 | You should have received a copy of the GNU Lesser General Public |
16 | along with this program; if not, write to the Free Software Foundation, | 16 | License along with this library. |
17 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ | 17 | If not, see <http://www.gnu.org/licenses/>. |
18 | 18 | */ | |
19 | #ifndef SHA1_H | 19 | |
20 | # define SHA1_H 1 | 20 | /** |
21 | 21 | * @file microhttpd/sha1.h | |
22 | #include <stdio.h> | 22 | * @brief Calculation of SHA-1 digest |
23 | 23 | * @author Karlson2k (Evgeny Grin) | |
24 | #if defined HAVE_LIMITS_H || _LIBC | 24 | */ |
25 | # include <limits.h> | 25 | |
26 | #endif | 26 | #ifndef MHD_SHA1_H |
27 | 27 | #define MHD_SHA1_H 1 | |
28 | /*#include "ansidecl.h"*/ | 28 | |
29 | 29 | #include "mhd_options.h" | |
30 | /* The following contortions are an attempt to use the C preprocessor | ||
31 | to determine an unsigned integral type that is 32 bits wide. An | ||
32 | alternative approach is to use autoconf's AC_CHECK_SIZEOF macro, but | ||
33 | doing that would require that the configure script compile and *run* | ||
34 | the resulting executable. Locally running cross-compiled executables | ||
35 | is usually not possible. */ | ||
36 | |||
37 | #ifdef _LIBC | ||
38 | # include <sys/types.h> | ||
39 | typedef u_int32_t sha1_uint32; | ||
40 | typedef uintptr_t sha1_uintptr; | ||
41 | #elif defined (HAVE_SYS_TYPES_H) && defined (HAVE_STDINT_H) | ||
42 | #include <stdint.h> | 30 | #include <stdint.h> |
43 | #include <sys/types.h> | 31 | #ifdef HAVE_STDDEF_H |
44 | typedef uint32_t sha1_uint32; | 32 | #include <stddef.h> /* for size_t */ |
45 | typedef uintptr_t sha1_uintptr; | 33 | #endif /* HAVE_STDDEF_H */ |
46 | #else | 34 | |
47 | # define INT_MAX_32_BITS 2147483647 | 35 | /** |
48 | 36 | * SHA-1 digest is kept internally as 5 32-bit words. | |
49 | /* If UINT_MAX isn't defined, assume it's a 32-bit type. | 37 | */ |
50 | This should be valid for all systems GNU cares about because | 38 | #define _SHA1_DIGEST_LENGTH 5 |
51 | that doesn't include 16-bit systems, and only modern systems | 39 | |
52 | (that certainly have <limits.h>) have 64+-bit integral types. */ | 40 | /** |
53 | 41 | * Number of bits in single SHA-1 word | |
54 | # ifndef INT_MAX | 42 | */ |
55 | # define INT_MAX INT_MAX_32_BITS | 43 | #define SHA1_WORD_SIZE_BITS 32 |
56 | # endif | 44 | |
57 | 45 | /** | |
58 | # if INT_MAX == INT_MAX_32_BITS | 46 | * Number of bytes in single SHA-1 word |
59 | typedef unsigned int sha1_uint32; | 47 | */ |
60 | # else | 48 | #define SHA1_BYTES_IN_WORD (SHA1_WORD_SIZE_BITS / 8) |
61 | # if SHRT_MAX == INT_MAX_32_BITS | 49 | |
62 | typedef unsigned short sha1_uint32; | 50 | /** |
63 | # else | 51 | * Size of SHA-1 digest in bytes |
64 | # if LONG_MAX == INT_MAX_32_BITS | 52 | */ |
65 | typedef unsigned long sha1_uint32; | 53 | #define SHA1_DIGEST_SIZE (_SHA1_DIGEST_LENGTH * SHA1_BYTES_IN_WORD) |
66 | # else | 54 | |
67 | /* The following line is intended to evoke an error. | 55 | /** |
68 | Using #error is not portable enough. */ | 56 | * Size of SHA-1 digest string in chars including termination NUL |
69 | "Cannot determine unsigned 32-bit data type." | 57 | */ |
70 | # endif | 58 | #define SHA1_DIGEST_STRING_SIZE ((SHA1_DIGEST_SIZE) * 2 + 1) |
71 | # endif | 59 | |
72 | # endif | 60 | /** |
73 | #endif | 61 | * Size of single processing block in bits |
74 | 62 | */ | |
75 | #ifdef __cplusplus | 63 | #define SHA1_BLOCK_SIZE_BITS 512 |
76 | extern "C" { | 64 | |
77 | #endif | 65 | /** |
78 | 66 | * Size of single processing block in bytes | |
79 | /* Structure to save state of computation between the single steps. */ | 67 | */ |
68 | #define SHA1_BLOCK_SIZE (SHA1_BLOCK_SIZE_BITS / 8) | ||
69 | |||
70 | |||
80 | struct sha1_ctx | 71 | struct sha1_ctx |
81 | { | 72 | { |
82 | sha1_uint32 A; | 73 | uint32_t H[_SHA1_DIGEST_LENGTH]; /**< Intermediate hash value / digest at end of calculation */ |
83 | sha1_uint32 B; | 74 | uint8_t buffer[SHA1_BLOCK_SIZE]; /**< SHA256 input data buffer */ |
84 | sha1_uint32 C; | 75 | uint64_t count; /**< number of bytes, mod 2^64 */ |
85 | sha1_uint32 D; | ||
86 | sha1_uint32 E; | ||
87 | |||
88 | sha1_uint32 total[2]; | ||
89 | sha1_uint32 buflen; | ||
90 | sha1_uint32 buffer[32]; | ||
91 | }; | 76 | }; |
92 | 77 | ||
93 | 78 | /** | |
94 | /* Initialize structure containing state of computation. */ | 79 | * Initialise structure for SHA-1 calculation. |
95 | extern void sha1_init_ctx (struct sha1_ctx *ctx); | 80 | * |
96 | 81 | * @param ctx must be a `struct sha1_ctx *` | |
97 | /* Starting with the result of former calls of this function (or the | 82 | */ |
98 | initialization function update the context for the next LEN bytes | 83 | void |
99 | starting at BUFFER. | 84 | MHD_SHA1_init (void *ctx_); |
100 | It is necessary that LEN is a multiple of 64!!! */ | 85 | |
101 | extern void sha1_process_block (const void *buffer, size_t len, | 86 | |
102 | struct sha1_ctx *ctx); | 87 | /** |
103 | 88 | * Process portion of bytes. | |
104 | /* Starting with the result of former calls of this function (or the | 89 | * |
105 | initialization function update the context for the next LEN bytes | 90 | * @param ctx_ must be a `struct sha1_ctx *` |
106 | starting at BUFFER. | 91 | * @param data bytes to add to hash |
107 | It is NOT required that LEN is a multiple of 64. */ | 92 | * @param length number of bytes in @a data |
108 | extern void sha1_process_bytes (const void *buffer, size_t len, | 93 | */ |
109 | struct sha1_ctx *ctx); | 94 | void |
110 | 95 | MHD_SHA1_update (void *ctx_, | |
111 | /* Process the remaining bytes in the buffer and put result from CTX | 96 | const uint8_t *data, |
112 | in first 20 bytes following RESBUF. The result is always in little | 97 | size_t length); |
113 | endian byte order, so that a byte-wise output yields to the wanted | 98 | |
114 | ASCII representation of the message digest. | 99 | |
115 | 100 | /** | |
116 | IMPORTANT: On some systems it is required that RESBUF be correctly | 101 | * Finalise SHA-1 calculation, return digest. |
117 | aligned for a 32 bits value. */ | 102 | * |
118 | extern void *sha1_finish_ctx (struct sha1_ctx *ctx, void *resbuf); | 103 | * @param ctx_ must be a `struct sha1_ctx *` |
119 | 104 | * @param[out] digest set to the hash, must be #SHA1_DIGEST_SIZE bytes | |
120 | 105 | */ | |
121 | /* Put result from CTX in first 20 bytes following RESBUF. The result is | 106 | void |
122 | always in little endian byte order, so that a byte-wise output yields | 107 | MHD_SHA1_finish (void *ctx_, |
123 | to the wanted ASCII representation of the message digest. | 108 | uint8_t digest[SHA1_DIGEST_SIZE]); |
124 | 109 | ||
125 | IMPORTANT: On some systems it is required that RESBUF is correctly | 110 | #endif /* MHD_SHA1_H */ |
126 | aligned for a 32 bits value. */ | ||
127 | extern void *sha1_read_ctx (const struct sha1_ctx *ctx, void *resbuf); | ||
128 | |||
129 | |||
130 | /* Compute SHA1 message digest for bytes read from STREAM. The | ||
131 | resulting message digest number will be written into the 20 bytes | ||
132 | beginning at RESBLOCK. */ | ||
133 | extern int sha1_stream (FILE *stream, void *resblock); | ||
134 | |||
135 | /* Compute SHA1 message digest for LEN bytes beginning at BUFFER. The | ||
136 | result is always in little endian byte order, so that a byte-wise | ||
137 | output yields to the wanted ASCII representation of the message | ||
138 | digest. */ | ||
139 | extern void *sha1_buffer (const char *buffer, size_t len, void *resblock); | ||
140 | |||
141 | #ifdef __cplusplus | ||
142 | } | ||
143 | #endif | ||
144 | |||
145 | #endif | ||
diff --git a/src/microhttpd_ws/test_websocket.c b/src/microhttpd_ws/test_websocket.c index 0034eb4c..29a4661a 100644 --- a/src/microhttpd_ws/test_websocket.c +++ b/src/microhttpd_ws/test_websocket.c | |||
@@ -27,8 +27,13 @@ | |||
27 | #include <stdlib.h> | 27 | #include <stdlib.h> |
28 | #include <string.h> | 28 | #include <string.h> |
29 | #include <stdio.h> | 29 | #include <stdio.h> |
30 | #include <stdint.h> | ||
30 | #include <time.h> | 31 | #include <time.h> |
31 | 32 | ||
33 | #if SIZE_MAX >= 0x100000000 | ||
34 | #define ENABLE_64BIT_TESTS 1 | ||
35 | #endif | ||
36 | |||
32 | int disable_alloc = 0; | 37 | int disable_alloc = 0; |
33 | size_t open_allocs = 0; | 38 | size_t open_allocs = 0; |
34 | 39 | ||
@@ -73,6 +78,20 @@ test_free (void*buf) | |||
73 | free (buf); | 78 | free (buf); |
74 | } | 79 | } |
75 | 80 | ||
81 | /** | ||
82 | * Custom `rng()` function used for client mode tests | ||
83 | */ | ||
84 | static size_t | ||
85 | test_rng (void*cls, void*buf, size_t buf_len) | ||
86 | { | ||
87 | for (size_t i = 0; i < buf_len; ++i) | ||
88 | { | ||
89 | ((char*) buf) [i] = (char) (rand () % 0xFF); | ||
90 | } | ||
91 | |||
92 | return buf_len; | ||
93 | } | ||
94 | |||
76 | 95 | ||
77 | /** | 96 | /** |
78 | * Helper function which allocates a big amount of data | 97 | * Helper function which allocates a big amount of data |
@@ -126,7 +145,14 @@ test_decode_single (unsigned int test_line, | |||
126 | int ret = MHD_WEBSOCKET_STATUS_OK; | 145 | int ret = MHD_WEBSOCKET_STATUS_OK; |
127 | 146 | ||
128 | /* initialize stream */ | 147 | /* initialize stream */ |
129 | ret = MHD_websocket_stream_init (&ws, flags, max_payload_size); | 148 | ret = MHD_websocket_stream_init2 (&ws, |
149 | flags, | ||
150 | max_payload_size, | ||
151 | malloc, | ||
152 | realloc, | ||
153 | free, | ||
154 | NULL, | ||
155 | test_rng); | ||
130 | if (MHD_WEBSOCKET_STATUS_OK != ret) | 156 | if (MHD_WEBSOCKET_STATUS_OK != ret) |
131 | { | 157 | { |
132 | fprintf (stderr, | 158 | fprintf (stderr, |
@@ -267,7 +293,7 @@ test_decode_single (unsigned int test_line, | |||
267 | 293 | ||
268 | /** | 294 | /** |
269 | * Test procedure for `MHD_websocket_stream_init()` and | 295 | * Test procedure for `MHD_websocket_stream_init()` and |
270 | * `MHD_websocket_stream_init()2` | 296 | * `MHD_websocket_stream_init2()` |
271 | */ | 297 | */ |
272 | int | 298 | int |
273 | test_inits () | 299 | test_inits () |
@@ -281,15 +307,19 @@ test_inits () | |||
281 | All valid flags | 307 | All valid flags |
282 | ------------------------------------------------------------------------------ | 308 | ------------------------------------------------------------------------------ |
283 | */ | 309 | */ |
284 | /* Regular test: all valid flags for init */ | 310 | /* Regular test: all valid flags for init (only the even ones work) */ |
285 | for (int i = 0; i < 7; ++i) | 311 | for (int i = 0; i < 7; ++i) |
286 | { | 312 | { |
287 | ws = NULL; | 313 | ws = NULL; |
288 | ret = MHD_websocket_stream_init (&ws, | 314 | ret = MHD_websocket_stream_init (&ws, |
289 | i, | 315 | i, |
290 | 0); | 316 | 0); |
291 | if ((MHD_WEBSOCKET_STATUS_OK != ret) || | 317 | if (((0 == (i & MHD_WEBSOCKET_FLAG_CLIENT)) && |
292 | (NULL == ws) ) | 318 | ((MHD_WEBSOCKET_STATUS_OK != ret) || |
319 | (NULL == ws))) || | ||
320 | ((0 != (i & MHD_WEBSOCKET_FLAG_CLIENT)) && | ||
321 | ((MHD_WEBSOCKET_STATUS_OK == ret) || | ||
322 | (NULL != ws)))) | ||
293 | { | 323 | { |
294 | fprintf (stderr, | 324 | fprintf (stderr, |
295 | "Init test failed in line %u for flags %d.\n", | 325 | "Init test failed in line %u for flags %d.\n", |
@@ -312,7 +342,9 @@ test_inits () | |||
312 | 0, | 342 | 0, |
313 | test_malloc, | 343 | test_malloc, |
314 | test_realloc, | 344 | test_realloc, |
315 | test_free); | 345 | test_free, |
346 | NULL, | ||
347 | test_rng); | ||
316 | if ((MHD_WEBSOCKET_STATUS_OK != ret) || | 348 | if ((MHD_WEBSOCKET_STATUS_OK != ret) || |
317 | (NULL == ws) ) | 349 | (NULL == ws) ) |
318 | { | 350 | { |
@@ -361,7 +393,9 @@ test_inits () | |||
361 | 0, | 393 | 0, |
362 | test_malloc, | 394 | test_malloc, |
363 | test_realloc, | 395 | test_realloc, |
364 | test_free); | 396 | test_free, |
397 | NULL, | ||
398 | NULL); | ||
365 | if ((MHD_WEBSOCKET_STATUS_PARAMETER_ERROR != ret) || | 399 | if ((MHD_WEBSOCKET_STATUS_PARAMETER_ERROR != ret) || |
366 | (NULL != ws) ) | 400 | (NULL != ws) ) |
367 | { | 401 | { |
@@ -410,7 +444,9 @@ test_inits () | |||
410 | 0, | 444 | 0, |
411 | test_malloc, | 445 | test_malloc, |
412 | test_realloc, | 446 | test_realloc, |
413 | test_free); | 447 | test_free, |
448 | NULL, | ||
449 | NULL); | ||
414 | if ((MHD_WEBSOCKET_STATUS_OK != ret) || | 450 | if ((MHD_WEBSOCKET_STATUS_OK != ret) || |
415 | (NULL == ws) ) | 451 | (NULL == ws) ) |
416 | { | 452 | { |
@@ -451,7 +487,9 @@ test_inits () | |||
451 | 1, | 487 | 1, |
452 | test_malloc, | 488 | test_malloc, |
453 | test_realloc, | 489 | test_realloc, |
454 | test_free); | 490 | test_free, |
491 | NULL, | ||
492 | NULL); | ||
455 | if ((MHD_WEBSOCKET_STATUS_OK != ret) || | 493 | if ((MHD_WEBSOCKET_STATUS_OK != ret) || |
456 | (NULL == ws) ) | 494 | (NULL == ws) ) |
457 | { | 495 | { |
@@ -492,7 +530,9 @@ test_inits () | |||
492 | 1000, | 530 | 1000, |
493 | test_malloc, | 531 | test_malloc, |
494 | test_realloc, | 532 | test_realloc, |
495 | test_free); | 533 | test_free, |
534 | NULL, | ||
535 | NULL); | ||
496 | if ((MHD_WEBSOCKET_STATUS_OK != ret) || | 536 | if ((MHD_WEBSOCKET_STATUS_OK != ret) || |
497 | (NULL == ws) ) | 537 | (NULL == ws) ) |
498 | { | 538 | { |
@@ -506,6 +546,7 @@ test_inits () | |||
506 | MHD_websocket_stream_free (ws); | 546 | MHD_websocket_stream_free (ws); |
507 | ws = NULL; | 547 | ws = NULL; |
508 | } | 548 | } |
549 | #ifdef ENABLE_64BIT_TESTS | ||
509 | /* Edge test (success): max_payload_size = 0x7FFFFFFFFFFFFFFF for init */ | 550 | /* Edge test (success): max_payload_size = 0x7FFFFFFFFFFFFFFF for init */ |
510 | ws = NULL; | 551 | ws = NULL; |
511 | ret = MHD_websocket_stream_init (&ws, | 552 | ret = MHD_websocket_stream_init (&ws, |
@@ -533,7 +574,9 @@ test_inits () | |||
533 | (uint64_t) 0x7FFFFFFFFFFFFFFF, | 574 | (uint64_t) 0x7FFFFFFFFFFFFFFF, |
534 | test_malloc, | 575 | test_malloc, |
535 | test_realloc, | 576 | test_realloc, |
536 | test_free); | 577 | test_free, |
578 | NULL, | ||
579 | NULL); | ||
537 | if ((MHD_WEBSOCKET_STATUS_OK != ret) || | 580 | if ((MHD_WEBSOCKET_STATUS_OK != ret) || |
538 | (NULL == ws) ) | 581 | (NULL == ws) ) |
539 | { | 582 | { |
@@ -574,7 +617,9 @@ test_inits () | |||
574 | (uint64_t) 0x8000000000000000, | 617 | (uint64_t) 0x8000000000000000, |
575 | test_malloc, | 618 | test_malloc, |
576 | test_realloc, | 619 | test_realloc, |
577 | test_free); | 620 | test_free, |
621 | NULL, | ||
622 | NULL); | ||
578 | if ((MHD_WEBSOCKET_STATUS_PARAMETER_ERROR != ret) || | 623 | if ((MHD_WEBSOCKET_STATUS_PARAMETER_ERROR != ret) || |
579 | (NULL != ws) ) | 624 | (NULL != ws) ) |
580 | { | 625 | { |
@@ -588,6 +633,7 @@ test_inits () | |||
588 | MHD_websocket_stream_free (ws); | 633 | MHD_websocket_stream_free (ws); |
589 | ws = NULL; | 634 | ws = NULL; |
590 | } | 635 | } |
636 | #endif | ||
591 | 637 | ||
592 | /* | 638 | /* |
593 | ------------------------------------------------------------------------------ | 639 | ------------------------------------------------------------------------------ |
@@ -621,7 +667,9 @@ test_inits () | |||
621 | 0, | 667 | 0, |
622 | test_malloc, | 668 | test_malloc, |
623 | test_realloc, | 669 | test_realloc, |
624 | test_free); | 670 | test_free, |
671 | NULL, | ||
672 | NULL); | ||
625 | if ((MHD_WEBSOCKET_STATUS_PARAMETER_ERROR != ret) || | 673 | if ((MHD_WEBSOCKET_STATUS_PARAMETER_ERROR != ret) || |
626 | (NULL != ws) ) | 674 | (NULL != ws) ) |
627 | { | 675 | { |
@@ -643,7 +691,9 @@ test_inits () | |||
643 | 0, | 691 | 0, |
644 | NULL, | 692 | NULL, |
645 | test_realloc, | 693 | test_realloc, |
646 | test_free); | 694 | test_free, |
695 | NULL, | ||
696 | NULL); | ||
647 | if ((MHD_WEBSOCKET_STATUS_PARAMETER_ERROR != ret) || | 697 | if ((MHD_WEBSOCKET_STATUS_PARAMETER_ERROR != ret) || |
648 | (NULL != ws) ) | 698 | (NULL != ws) ) |
649 | { | 699 | { |
@@ -665,7 +715,9 @@ test_inits () | |||
665 | 0, | 715 | 0, |
666 | test_malloc, | 716 | test_malloc, |
667 | NULL, | 717 | NULL, |
668 | test_free); | 718 | test_free, |
719 | NULL, | ||
720 | NULL); | ||
669 | if ((MHD_WEBSOCKET_STATUS_PARAMETER_ERROR != ret) || | 721 | if ((MHD_WEBSOCKET_STATUS_PARAMETER_ERROR != ret) || |
670 | (NULL != ws) ) | 722 | (NULL != ws) ) |
671 | { | 723 | { |
@@ -687,6 +739,8 @@ test_inits () | |||
687 | 0, | 739 | 0, |
688 | test_malloc, | 740 | test_malloc, |
689 | test_realloc, | 741 | test_realloc, |
742 | NULL, | ||
743 | NULL, | ||
690 | NULL); | 744 | NULL); |
691 | if ((MHD_WEBSOCKET_STATUS_PARAMETER_ERROR != ret) || | 745 | if ((MHD_WEBSOCKET_STATUS_PARAMETER_ERROR != ret) || |
692 | (NULL != ws) ) | 746 | (NULL != ws) ) |
@@ -701,13 +755,109 @@ test_inits () | |||
701 | MHD_websocket_stream_free (ws); | 755 | MHD_websocket_stream_free (ws); |
702 | ws = NULL; | 756 | ws = NULL; |
703 | } | 757 | } |
758 | /* Regular test: rng given for server mode (will be ignored) */ | ||
759 | ws = NULL; | ||
760 | ret = MHD_websocket_stream_init2 (&ws, | ||
761 | MHD_WEBSOCKET_FLAG_SERVER | ||
762 | | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS, | ||
763 | 0, | ||
764 | test_malloc, | ||
765 | test_realloc, | ||
766 | test_free, | ||
767 | NULL, | ||
768 | test_rng); | ||
769 | if ((MHD_WEBSOCKET_STATUS_OK != ret) || | ||
770 | (NULL == ws) ) | ||
771 | { | ||
772 | fprintf (stderr, | ||
773 | "Init test failed in line %u.\n", | ||
774 | (unsigned int) __LINE__); | ||
775 | ++failed; | ||
776 | } | ||
777 | if (NULL != ws) | ||
778 | { | ||
779 | MHD_websocket_stream_free (ws); | ||
780 | ws = NULL; | ||
781 | } | ||
782 | /* Regular test: cls_rng given for server mode (will be ignored) */ | ||
783 | ws = NULL; | ||
784 | ret = MHD_websocket_stream_init2 (&ws, | ||
785 | MHD_WEBSOCKET_FLAG_SERVER | ||
786 | | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS, | ||
787 | 0, | ||
788 | test_malloc, | ||
789 | test_realloc, | ||
790 | test_free, | ||
791 | (void*) 12345, | ||
792 | test_rng); | ||
793 | if ((MHD_WEBSOCKET_STATUS_OK != ret) || | ||
794 | (NULL == ws) ) | ||
795 | { | ||
796 | fprintf (stderr, | ||
797 | "Init test failed in line %u.\n", | ||
798 | (unsigned int) __LINE__); | ||
799 | ++failed; | ||
800 | } | ||
801 | if (NULL != ws) | ||
802 | { | ||
803 | MHD_websocket_stream_free (ws); | ||
804 | ws = NULL; | ||
805 | } | ||
806 | /* Regular test: rng given for client mode */ | ||
807 | ws = NULL; | ||
808 | ret = MHD_websocket_stream_init2 (&ws, | ||
809 | MHD_WEBSOCKET_FLAG_CLIENT | ||
810 | | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS, | ||
811 | 0, | ||
812 | test_malloc, | ||
813 | test_realloc, | ||
814 | test_free, | ||
815 | NULL, | ||
816 | test_rng); | ||
817 | if ((MHD_WEBSOCKET_STATUS_OK != ret) || | ||
818 | (NULL == ws) ) | ||
819 | { | ||
820 | fprintf (stderr, | ||
821 | "Init test failed in line %u.\n", | ||
822 | (unsigned int) __LINE__); | ||
823 | ++failed; | ||
824 | } | ||
825 | if (NULL != ws) | ||
826 | { | ||
827 | MHD_websocket_stream_free (ws); | ||
828 | ws = NULL; | ||
829 | } | ||
830 | /* Fail test: rng not given for client mode */ | ||
831 | ws = NULL; | ||
832 | ret = MHD_websocket_stream_init2 (&ws, | ||
833 | MHD_WEBSOCKET_FLAG_CLIENT | ||
834 | | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS, | ||
835 | 0, | ||
836 | test_malloc, | ||
837 | test_realloc, | ||
838 | test_free, | ||
839 | NULL, | ||
840 | NULL); | ||
841 | if ((MHD_WEBSOCKET_STATUS_PARAMETER_ERROR != ret) || | ||
842 | (NULL != ws) ) | ||
843 | { | ||
844 | fprintf (stderr, | ||
845 | "Init test failed in line %u %u.\n", | ||
846 | (unsigned int) __LINE__, ret); | ||
847 | ++failed; | ||
848 | } | ||
849 | if (NULL != ws) | ||
850 | { | ||
851 | MHD_websocket_stream_free (ws); | ||
852 | ws = NULL; | ||
853 | } | ||
704 | 854 | ||
705 | return failed != 0 ? 0x01 : 0x00; | 855 | return failed != 0 ? 0x01 : 0x00; |
706 | } | 856 | } |
707 | 857 | ||
708 | 858 | ||
709 | /** | 859 | /** |
710 | * Test procedure for `MHD_websocket_create_accept()` | 860 | * Test procedure for `MHD_websocket_create_accept_header()` |
711 | */ | 861 | */ |
712 | int | 862 | int |
713 | test_accept () | 863 | test_accept () |
@@ -723,8 +873,8 @@ test_accept () | |||
723 | */ | 873 | */ |
724 | /* Regular test: Test case from RFC6455 4.2.2 */ | 874 | /* Regular test: Test case from RFC6455 4.2.2 */ |
725 | memset (accept_key, 0, 29); | 875 | memset (accept_key, 0, 29); |
726 | ret = MHD_websocket_create_accept ("dGhlIHNhbXBsZSBub25jZQ==", | 876 | ret = MHD_websocket_create_accept_header ("dGhlIHNhbXBsZSBub25jZQ==", |
727 | accept_key); | 877 | accept_key); |
728 | if ((MHD_WEBSOCKET_STATUS_OK != ret) || | 878 | if ((MHD_WEBSOCKET_STATUS_OK != ret) || |
729 | (0 != memcmp (accept_key, "s3pPLMBiTxaQ9kYGzzhZRbK+xOo=", 29))) | 879 | (0 != memcmp (accept_key, "s3pPLMBiTxaQ9kYGzzhZRbK+xOo=", 29))) |
730 | { | 880 | { |
@@ -741,9 +891,9 @@ test_accept () | |||
741 | */ | 891 | */ |
742 | /* Fail test: missing sec-key value */ | 892 | /* Fail test: missing sec-key value */ |
743 | memset (accept_key, 0, 29); | 893 | memset (accept_key, 0, 29); |
744 | ret = MHD_websocket_create_accept (NULL, | 894 | ret = MHD_websocket_create_accept_header (NULL, |
745 | accept_key); | 895 | accept_key); |
746 | if (MHD_WEBSOCKET_STATUS_PARAMETER_ERROR != ret) | 896 | if (MHD_WEBSOCKET_STATUS_NO_WEBSOCKET_HANDSHAKE_HEADER != ret) |
747 | { | 897 | { |
748 | fprintf (stderr, | 898 | fprintf (stderr, |
749 | "Accept test failed in line %u.\n", | 899 | "Accept test failed in line %u.\n", |
@@ -752,8 +902,8 @@ test_accept () | |||
752 | } | 902 | } |
753 | /* Fail test: missing accept variable */ | 903 | /* Fail test: missing accept variable */ |
754 | memset (accept_key, 0, 29); | 904 | memset (accept_key, 0, 29); |
755 | ret = MHD_websocket_create_accept ("dGhlIHNhbXBsZSBub25jZQ==", | 905 | ret = MHD_websocket_create_accept_header ("dGhlIHNhbXBsZSBub25jZQ==", |
756 | NULL); | 906 | NULL); |
757 | if (MHD_WEBSOCKET_STATUS_PARAMETER_ERROR != ret) | 907 | if (MHD_WEBSOCKET_STATUS_PARAMETER_ERROR != ret) |
758 | { | 908 | { |
759 | fprintf (stderr, | 909 | fprintf (stderr, |
@@ -1038,7 +1188,7 @@ test_decodes () | |||
1038 | 12, | 1188 | 12, |
1039 | NULL, | 1189 | NULL, |
1040 | 0, | 1190 | 0, |
1041 | MHD_WEBSOCKET_STATUS_BINARY_FRAGMENT, | 1191 | MHD_WEBSOCKET_STATUS_BINARY_FIRST_FRAGMENT, |
1042 | MHD_WEBSOCKET_VALIDITY_VALID, | 1192 | MHD_WEBSOCKET_VALIDITY_VALID, |
1043 | 6); | 1193 | 6); |
1044 | /* Regular test: Fragmented binary frame without payload, fragments to the caller, 2nd call */ | 1194 | /* Regular test: Fragmented binary frame without payload, fragments to the caller, 2nd call */ |
@@ -1080,7 +1230,7 @@ test_decodes () | |||
1080 | 18, | 1230 | 18, |
1081 | "\x01\x02\x03", | 1231 | "\x01\x02\x03", |
1082 | 3, | 1232 | 3, |
1083 | MHD_WEBSOCKET_STATUS_BINARY_FRAGMENT, | 1233 | MHD_WEBSOCKET_STATUS_BINARY_FIRST_FRAGMENT, |
1084 | MHD_WEBSOCKET_VALIDITY_VALID, | 1234 | MHD_WEBSOCKET_VALIDITY_VALID, |
1085 | 9); | 1235 | 9); |
1086 | /* Regular test: Fragmented binary frame without payload, fragments to the caller, 2nd call */ | 1236 | /* Regular test: Fragmented binary frame without payload, fragments to the caller, 2nd call */ |
@@ -1097,6 +1247,62 @@ test_decodes () | |||
1097 | MHD_WEBSOCKET_STATUS_BINARY_LAST_FRAGMENT, | 1247 | MHD_WEBSOCKET_STATUS_BINARY_LAST_FRAGMENT, |
1098 | MHD_WEBSOCKET_VALIDITY_VALID, | 1248 | MHD_WEBSOCKET_VALIDITY_VALID, |
1099 | 18); | 1249 | 18); |
1250 | /* Regular test: Fragmented binary frame with payload, fragments to the caller, 1st call */ | ||
1251 | failed += test_decode_single (__LINE__, | ||
1252 | MHD_WEBSOCKET_FLAG_SERVER | ||
1253 | | MHD_WEBSOCKET_FLAG_WANT_FRAGMENTS, | ||
1254 | 0, | ||
1255 | 1, | ||
1256 | 0, | ||
1257 | "\x02\x83\x00\x00\x00\x00\x01\x02\x03\x00\x83\x00\x00\x00\x00\x04\x05\x06\x00\x83\x00\x00\x00\x00\x07\x08\x09\x80\x83\x00\x00\x00\x00\x0A\x0B\x0C", | ||
1258 | 36, | ||
1259 | "\x01\x02\x03", | ||
1260 | 3, | ||
1261 | MHD_WEBSOCKET_STATUS_BINARY_FIRST_FRAGMENT, | ||
1262 | MHD_WEBSOCKET_VALIDITY_VALID, | ||
1263 | 9); | ||
1264 | /* Regular test: Fragmented binary frame without payload, fragments to the caller, 2nd call */ | ||
1265 | failed += test_decode_single (__LINE__, | ||
1266 | MHD_WEBSOCKET_FLAG_SERVER | ||
1267 | | MHD_WEBSOCKET_FLAG_WANT_FRAGMENTS, | ||
1268 | 0, | ||
1269 | 2, | ||
1270 | 0, | ||
1271 | "\x02\x83\x00\x00\x00\x00\x01\x02\x03\x00\x83\x00\x00\x00\x00\x04\x05\x06\x00\x83\x00\x00\x00\x00\x07\x08\x09\x80\x83\x00\x00\x00\x00\x0A\x0B\x0C", | ||
1272 | 36, | ||
1273 | "\x04\x05\x06", | ||
1274 | 3, | ||
1275 | MHD_WEBSOCKET_STATUS_BINARY_NEXT_FRAGMENT, | ||
1276 | MHD_WEBSOCKET_VALIDITY_VALID, | ||
1277 | 18); | ||
1278 | /* Regular test: Fragmented binary frame without payload, fragments to the caller, 3rd call */ | ||
1279 | failed += test_decode_single (__LINE__, | ||
1280 | MHD_WEBSOCKET_FLAG_SERVER | ||
1281 | | MHD_WEBSOCKET_FLAG_WANT_FRAGMENTS, | ||
1282 | 0, | ||
1283 | 3, | ||
1284 | 0, | ||
1285 | "\x02\x83\x00\x00\x00\x00\x01\x02\x03\x00\x83\x00\x00\x00\x00\x04\x05\x06\x00\x83\x00\x00\x00\x00\x07\x08\x09\x80\x83\x00\x00\x00\x00\x0A\x0B\x0C", | ||
1286 | 36, | ||
1287 | "\x07\x08\x09", | ||
1288 | 3, | ||
1289 | MHD_WEBSOCKET_STATUS_BINARY_NEXT_FRAGMENT, | ||
1290 | MHD_WEBSOCKET_VALIDITY_VALID, | ||
1291 | 27); | ||
1292 | /* Regular test: Fragmented binary frame without payload, fragments to the caller, 4th call */ | ||
1293 | failed += test_decode_single (__LINE__, | ||
1294 | MHD_WEBSOCKET_FLAG_SERVER | ||
1295 | | MHD_WEBSOCKET_FLAG_WANT_FRAGMENTS, | ||
1296 | 0, | ||
1297 | 4, | ||
1298 | 0, | ||
1299 | "\x02\x83\x00\x00\x00\x00\x01\x02\x03\x00\x83\x00\x00\x00\x00\x04\x05\x06\x00\x83\x00\x00\x00\x00\x07\x08\x09\x80\x83\x00\x00\x00\x00\x0A\x0B\x0C", | ||
1300 | 36, | ||
1301 | "\x0A\x0B\x0C", | ||
1302 | 3, | ||
1303 | MHD_WEBSOCKET_STATUS_BINARY_LAST_FRAGMENT, | ||
1304 | MHD_WEBSOCKET_VALIDITY_VALID, | ||
1305 | 36); | ||
1100 | /* Regular test: Binary frame with bytes which look like invalid UTF-8 character */ | 1306 | /* Regular test: Binary frame with bytes which look like invalid UTF-8 character */ |
1101 | failed += test_decode_single (__LINE__, | 1307 | failed += test_decode_single (__LINE__, |
1102 | MHD_WEBSOCKET_FLAG_SERVER | 1308 | MHD_WEBSOCKET_FLAG_SERVER |
@@ -1167,7 +1373,7 @@ test_decodes () | |||
1167 | 17, | 1373 | 17, |
1168 | "H\xC3", | 1374 | "H\xC3", |
1169 | 2, | 1375 | 2, |
1170 | MHD_WEBSOCKET_STATUS_BINARY_FRAGMENT, | 1376 | MHD_WEBSOCKET_STATUS_BINARY_FIRST_FRAGMENT, |
1171 | MHD_WEBSOCKET_VALIDITY_VALID, | 1377 | MHD_WEBSOCKET_VALIDITY_VALID, |
1172 | 8); | 1378 | 8); |
1173 | /* Regular test: Fragmented binary frame with bytes which look like valid UTF-8 sequence, | 1379 | /* Regular test: Fragmented binary frame with bytes which look like valid UTF-8 sequence, |
@@ -1802,7 +2008,7 @@ test_decodes () | |||
1802 | 17, | 2008 | 17, |
1803 | "Hel", | 2009 | "Hel", |
1804 | 3, | 2010 | 3, |
1805 | MHD_WEBSOCKET_STATUS_TEXT_FRAGMENT, | 2011 | MHD_WEBSOCKET_STATUS_TEXT_FIRST_FRAGMENT, |
1806 | MHD_WEBSOCKET_VALIDITY_VALID, | 2012 | MHD_WEBSOCKET_VALIDITY_VALID, |
1807 | 9); | 2013 | 9); |
1808 | /* Regular test: Fragmented, masked text frame, we are the server and want fragments, second call */ | 2014 | /* Regular test: Fragmented, masked text frame, we are the server and want fragments, second call */ |
@@ -1833,6 +2039,48 @@ test_decodes () | |||
1833 | MHD_WEBSOCKET_STATUS_OK, | 2039 | MHD_WEBSOCKET_STATUS_OK, |
1834 | MHD_WEBSOCKET_VALIDITY_VALID, | 2040 | MHD_WEBSOCKET_VALIDITY_VALID, |
1835 | 17); | 2041 | 17); |
2042 | /* Regular test: Fragmented, masked text frame, we are the server and want fragments, 1st call */ | ||
2043 | failed += test_decode_single (__LINE__, | ||
2044 | MHD_WEBSOCKET_FLAG_SERVER | ||
2045 | | MHD_WEBSOCKET_FLAG_WANT_FRAGMENTS, | ||
2046 | 0, | ||
2047 | 1, | ||
2048 | 0, | ||
2049 | "\x01\x83\x37\xfa\x21\x3d\x7f\x9f\x4d\x00\x81\x3d\x37\xfa\x21\x51\x80\x81\x37\x37\xfa\x21\x58", | ||
2050 | 23, | ||
2051 | "Hel", | ||
2052 | 3, | ||
2053 | MHD_WEBSOCKET_STATUS_TEXT_FIRST_FRAGMENT, | ||
2054 | MHD_WEBSOCKET_VALIDITY_VALID, | ||
2055 | 9); | ||
2056 | /* Regular test: Fragmented, masked text frame, we are the server and want fragments, 2nd call */ | ||
2057 | failed += test_decode_single (__LINE__, | ||
2058 | MHD_WEBSOCKET_FLAG_SERVER | ||
2059 | | MHD_WEBSOCKET_FLAG_WANT_FRAGMENTS, | ||
2060 | 0, | ||
2061 | 2, | ||
2062 | 0, | ||
2063 | "\x01\x83\x37\xfa\x21\x3d\x7f\x9f\x4d\x00\x81\x3d\x37\xfa\x21\x51\x80\x81\x37\x37\xfa\x21\x58", | ||
2064 | 23, | ||
2065 | "l", | ||
2066 | 1, | ||
2067 | MHD_WEBSOCKET_STATUS_TEXT_NEXT_FRAGMENT, | ||
2068 | MHD_WEBSOCKET_VALIDITY_VALID, | ||
2069 | 16); | ||
2070 | /* Regular test: Fragmented, masked text frame, we are the server and want fragments, 3rd call */ | ||
2071 | failed += test_decode_single (__LINE__, | ||
2072 | MHD_WEBSOCKET_FLAG_SERVER | ||
2073 | | MHD_WEBSOCKET_FLAG_WANT_FRAGMENTS, | ||
2074 | 0, | ||
2075 | 3, | ||
2076 | 0, | ||
2077 | "\x01\x83\x37\xfa\x21\x3d\x7f\x9f\x4d\x00\x81\x3d\x37\xfa\x21\x51\x80\x81\x37\x37\xfa\x21\x58", | ||
2078 | 23, | ||
2079 | "o", | ||
2080 | 1, | ||
2081 | MHD_WEBSOCKET_STATUS_TEXT_LAST_FRAGMENT, | ||
2082 | MHD_WEBSOCKET_VALIDITY_VALID, | ||
2083 | 23); | ||
1836 | 2084 | ||
1837 | 2085 | ||
1838 | /* | 2086 | /* |
@@ -2255,6 +2503,7 @@ test_decodes () | |||
2255 | free (buf2); | 2503 | free (buf2); |
2256 | buf2 = NULL; | 2504 | buf2 = NULL; |
2257 | } | 2505 | } |
2506 | #ifdef ENABLE_64BIT_TESTS | ||
2258 | /* Edge test (success): Maximum allowed length (here is only the header checked) */ | 2507 | /* Edge test (success): Maximum allowed length (here is only the header checked) */ |
2259 | failed += test_decode_single (__LINE__, | 2508 | failed += test_decode_single (__LINE__, |
2260 | MHD_WEBSOCKET_FLAG_SERVER | 2509 | MHD_WEBSOCKET_FLAG_SERVER |
@@ -2269,6 +2518,23 @@ test_decodes () | |||
2269 | MHD_WEBSOCKET_STATUS_OK, | 2518 | MHD_WEBSOCKET_STATUS_OK, |
2270 | MHD_WEBSOCKET_VALIDITY_VALID, | 2519 | MHD_WEBSOCKET_VALIDITY_VALID, |
2271 | 10); | 2520 | 10); |
2521 | #else | ||
2522 | /* Edge test (fail): Maximum allowed length | ||
2523 | (the size is allowed, but the system cannot handle this amount of memory) */ | ||
2524 | failed += test_decode_single (__LINE__, | ||
2525 | MHD_WEBSOCKET_FLAG_SERVER | ||
2526 | | MHD_WEBSOCKET_FLAG_NO_FRAGMENTS, | ||
2527 | 0, | ||
2528 | 1, | ||
2529 | 0, | ||
2530 | "\x81\xff\x7f\xff\xff\xff\xff\xff\xff\xff", | ||
2531 | 10, | ||
2532 | NULL, | ||
2533 | 0, | ||
2534 | MHD_WEBSOCKET_STATUS_MAXIMUM_SIZE_EXCEEDED, | ||
2535 | MHD_WEBSOCKET_VALIDITY_INVALID, | ||
2536 | 10); | ||
2537 | #endif | ||
2272 | /* Edge test (fail): Too big payload length */ | 2538 | /* Edge test (fail): Too big payload length */ |
2273 | failed += test_decode_single (__LINE__, | 2539 | failed += test_decode_single (__LINE__, |
2274 | MHD_WEBSOCKET_FLAG_SERVER | 2540 | MHD_WEBSOCKET_FLAG_SERVER |
@@ -2447,7 +2713,7 @@ test_decodes () | |||
2447 | 17, | 2713 | 17, |
2448 | "Hel", | 2714 | "Hel", |
2449 | 3, | 2715 | 3, |
2450 | MHD_WEBSOCKET_STATUS_TEXT_FRAGMENT, | 2716 | MHD_WEBSOCKET_STATUS_TEXT_FIRST_FRAGMENT, |
2451 | MHD_WEBSOCKET_VALIDITY_VALID, | 2717 | MHD_WEBSOCKET_VALIDITY_VALID, |
2452 | 9); | 2718 | 9); |
2453 | /* Edge test (success): Fragmented frames with the sum of payload greater than | 2719 | /* Edge test (success): Fragmented frames with the sum of payload greater than |
@@ -3247,7 +3513,7 @@ test_decodes () | |||
3247 | 28, | 3513 | 28, |
3248 | "This is my n", | 3514 | "This is my n", |
3249 | 12, | 3515 | 12, |
3250 | MHD_WEBSOCKET_STATUS_TEXT_FRAGMENT, | 3516 | MHD_WEBSOCKET_STATUS_TEXT_FIRST_FRAGMENT, |
3251 | MHD_WEBSOCKET_VALIDITY_VALID, | 3517 | MHD_WEBSOCKET_VALIDITY_VALID, |
3252 | 19); | 3518 | 19); |
3253 | /* Regular test: UTF-8 sequence between fragments, fragmentation for the caller, 2nd call */ | 3519 | /* Regular test: UTF-8 sequence between fragments, fragmentation for the caller, 2nd call */ |
@@ -3276,7 +3542,7 @@ test_decodes () | |||
3276 | 14, | 3542 | 14, |
3277 | NULL, | 3543 | NULL, |
3278 | 0, | 3544 | 0, |
3279 | MHD_WEBSOCKET_STATUS_TEXT_FRAGMENT, | 3545 | MHD_WEBSOCKET_STATUS_TEXT_FIRST_FRAGMENT, |
3280 | MHD_WEBSOCKET_VALIDITY_VALID, | 3546 | MHD_WEBSOCKET_VALIDITY_VALID, |
3281 | 7); | 3547 | 7); |
3282 | /* Edge test (success): UTF-8 sequence between fragments, but nothing before, fragmentation for the caller, 2nd call */ | 3548 | /* Edge test (success): UTF-8 sequence between fragments, but nothing before, fragmentation for the caller, 2nd call */ |
@@ -3664,7 +3930,7 @@ test_decodes () | |||
3664 | 35, | 3930 | 35, |
3665 | "This ", | 3931 | "This ", |
3666 | 5, | 3932 | 5, |
3667 | MHD_WEBSOCKET_STATUS_TEXT_FRAGMENT, | 3933 | MHD_WEBSOCKET_STATUS_TEXT_FIRST_FRAGMENT, |
3668 | MHD_WEBSOCKET_VALIDITY_VALID, | 3934 | MHD_WEBSOCKET_VALIDITY_VALID, |
3669 | 11); | 3935 | 11); |
3670 | /* Regular test: Fragmented text frame mixed with one ping frame, the caller wants fragments (2nd call) */ | 3936 | /* Regular test: Fragmented text frame mixed with one ping frame, the caller wants fragments (2nd call) */ |
@@ -3734,7 +4000,7 @@ test_decodes () | |||
3734 | 36, | 4000 | 36, |
3735 | "This ", | 4001 | "This ", |
3736 | 5, | 4002 | 5, |
3737 | MHD_WEBSOCKET_STATUS_TEXT_FRAGMENT, | 4003 | MHD_WEBSOCKET_STATUS_TEXT_FIRST_FRAGMENT, |
3738 | MHD_WEBSOCKET_VALIDITY_VALID, | 4004 | MHD_WEBSOCKET_VALIDITY_VALID, |
3739 | 11); | 4005 | 11); |
3740 | /* Fail test: Fragmented text frame mixed with one non-fragmented binary frame; the caller wants fragments; 2nd call */ | 4006 | /* Fail test: Fragmented text frame mixed with one non-fragmented binary frame; the caller wants fragments; 2nd call */ |
@@ -4106,7 +4372,7 @@ test_decodes () | |||
4106 | &streambuf_read_len, | 4372 | &streambuf_read_len, |
4107 | &payload, | 4373 | &payload, |
4108 | &payload_len); | 4374 | &payload_len); |
4109 | if ((MHD_WEBSOCKET_STATUS_TEXT_FRAGMENT != ret) || | 4375 | if ((MHD_WEBSOCKET_STATUS_TEXT_FIRST_FRAGMENT != ret) || |
4110 | (3 != payload_len) || | 4376 | (3 != payload_len) || |
4111 | (NULL == payload) || | 4377 | (NULL == payload) || |
4112 | (0 != memcmp ("Hel", payload, 3 + 1))) | 4378 | (0 != memcmp ("Hel", payload, 3 + 1))) |
@@ -4155,7 +4421,7 @@ test_decodes () | |||
4155 | &streambuf_read_len, | 4421 | &streambuf_read_len, |
4156 | &payload, | 4422 | &payload, |
4157 | &payload_len); | 4423 | &payload_len); |
4158 | if ((MHD_WEBSOCKET_STATUS_TEXT_FRAGMENT != ret) || | 4424 | if ((MHD_WEBSOCKET_STATUS_TEXT_FIRST_FRAGMENT != ret) || |
4159 | (2 != payload_len) || | 4425 | (2 != payload_len) || |
4160 | (NULL == payload) || | 4426 | (NULL == payload) || |
4161 | (0 != memcmp ("He", payload, 2 + 1))) | 4427 | (0 != memcmp ("He", payload, 2 + 1))) |
@@ -4195,6 +4461,8 @@ test_decodes () | |||
4195 | MHD_websocket_free (ws, payload); | 4461 | MHD_websocket_free (ws, payload); |
4196 | payload = NULL; | 4462 | payload = NULL; |
4197 | } | 4463 | } |
4464 | |||
4465 | MHD_websocket_stream_free (ws); | ||
4198 | } | 4466 | } |
4199 | else | 4467 | else |
4200 | { | 4468 | { |
@@ -4439,7 +4707,9 @@ test_decodes () | |||
4439 | 0, | 4707 | 0, |
4440 | test_malloc, | 4708 | test_malloc, |
4441 | test_realloc, | 4709 | test_realloc, |
4442 | test_free)) | 4710 | test_free, |
4711 | NULL, | ||
4712 | NULL)) | ||
4443 | { | 4713 | { |
4444 | size_t streambuf_read_len = 0; | 4714 | size_t streambuf_read_len = 0; |
4445 | char*payload = NULL; | 4715 | char*payload = NULL; |
@@ -4484,7 +4754,9 @@ test_decodes () | |||
4484 | 0, | 4754 | 0, |
4485 | test_malloc, | 4755 | test_malloc, |
4486 | test_realloc, | 4756 | test_realloc, |
4487 | test_free)) | 4757 | test_free, |
4758 | NULL, | ||
4759 | NULL)) | ||
4488 | { | 4760 | { |
4489 | /* Failure test: No memory allocation after fragmented frame */ | 4761 | /* Failure test: No memory allocation after fragmented frame */ |
4490 | disable_alloc = 0; | 4762 | disable_alloc = 0; |
@@ -4623,7 +4895,9 @@ test_decodes () | |||
4623 | 0, | 4895 | 0, |
4624 | test_malloc, | 4896 | test_malloc, |
4625 | test_realloc, | 4897 | test_realloc, |
4626 | test_free)) | 4898 | test_free, |
4899 | NULL, | ||
4900 | NULL)) | ||
4627 | { | 4901 | { |
4628 | ret = MHD_websocket_decode (ws, | 4902 | ret = MHD_websocket_decode (ws, |
4629 | "\x81\x85\x00\x00\x00\x00Hel", | 4903 | "\x81\x85\x00\x00\x00\x00Hel", |
@@ -4674,7 +4948,9 @@ test_decodes () | |||
4674 | 0, | 4948 | 0, |
4675 | test_malloc, | 4949 | test_malloc, |
4676 | test_realloc, | 4950 | test_realloc, |
4677 | test_free)) | 4951 | test_free, |
4952 | NULL, | ||
4953 | NULL)) | ||
4678 | { | 4954 | { |
4679 | ret = MHD_websocket_decode (ws, | 4955 | ret = MHD_websocket_decode (ws, |
4680 | "\x88\x85\x00\x00\x00\x00Hel", | 4956 | "\x88\x85\x00\x00\x00\x00Hel", |
@@ -4725,7 +5001,9 @@ test_decodes () | |||
4725 | 0, | 5001 | 0, |
4726 | test_malloc, | 5002 | test_malloc, |
4727 | test_realloc, | 5003 | test_realloc, |
4728 | test_free)) | 5004 | test_free, |
5005 | NULL, | ||
5006 | NULL)) | ||
4729 | { | 5007 | { |
4730 | ret = MHD_websocket_decode (ws, | 5008 | ret = MHD_websocket_decode (ws, |
4731 | "\x01\x85\x00\x00\x00\x00Hello", | 5009 | "\x01\x85\x00\x00\x00\x00Hello", |
@@ -4775,7 +5053,9 @@ test_decodes () | |||
4775 | 0, | 5053 | 0, |
4776 | test_malloc, | 5054 | test_malloc, |
4777 | test_realloc, | 5055 | test_realloc, |
4778 | test_free)) | 5056 | test_free, |
5057 | NULL, | ||
5058 | NULL)) | ||
4779 | { | 5059 | { |
4780 | ret = MHD_websocket_decode (ws, | 5060 | ret = MHD_websocket_decode (ws, |
4781 | "\x01\x85\x00\x00\x00\x00Hello", | 5061 | "\x01\x85\x00\x00\x00\x00Hello", |
@@ -4841,7 +5121,9 @@ test_decodes () | |||
4841 | 0, | 5121 | 0, |
4842 | test_malloc, | 5122 | test_malloc, |
4843 | test_realloc, | 5123 | test_realloc, |
4844 | test_free)) | 5124 | test_free, |
5125 | NULL, | ||
5126 | NULL)) | ||
4845 | { | 5127 | { |
4846 | ret = MHD_websocket_decode (ws, | 5128 | ret = MHD_websocket_decode (ws, |
4847 | "\x01\x85\x00\x00\x00\x00Hello", | 5129 | "\x01\x85\x00\x00\x00\x00Hello", |
@@ -4929,9 +5211,14 @@ test_encodes_text () | |||
4929 | size_t frame_len = 0; | 5211 | size_t frame_len = 0; |
4930 | int utf8_step = 0; | 5212 | int utf8_step = 0; |
4931 | 5213 | ||
4932 | if (MHD_WEBSOCKET_STATUS_OK != MHD_websocket_stream_init (&wsc, | 5214 | if (MHD_WEBSOCKET_STATUS_OK != MHD_websocket_stream_init2 (&wsc, |
4933 | MHD_WEBSOCKET_FLAG_CLIENT, | 5215 | MHD_WEBSOCKET_FLAG_CLIENT, |
4934 | 0)) | 5216 | 0, |
5217 | malloc, | ||
5218 | realloc, | ||
5219 | free, | ||
5220 | NULL, | ||
5221 | test_rng)) | ||
4935 | { | 5222 | { |
4936 | fprintf (stderr, | 5223 | fprintf (stderr, |
4937 | "No encode text tests possible due to failed stream init in line %u\n", | 5224 | "No encode text tests possible due to failed stream init in line %u\n", |
@@ -5742,6 +6029,7 @@ test_encodes_text () | |||
5742 | free (buf2); | 6029 | free (buf2); |
5743 | buf2 = NULL; | 6030 | buf2 = NULL; |
5744 | } | 6031 | } |
6032 | #ifdef ENABLE_64BIT_TESTS | ||
5745 | /* Fail test: frame_len is greater than 0x7FFFFFFFFFFFFFFF | 6033 | /* Fail test: frame_len is greater than 0x7FFFFFFFFFFFFFFF |
5746 | (this is the maximum allowed payload size) */ | 6034 | (this is the maximum allowed payload size) */ |
5747 | frame_len = 0; | 6035 | frame_len = 0; |
@@ -5766,6 +6054,7 @@ test_encodes_text () | |||
5766 | MHD_websocket_free (wss, frame); | 6054 | MHD_websocket_free (wss, frame); |
5767 | frame = NULL; | 6055 | frame = NULL; |
5768 | } | 6056 | } |
6057 | #endif | ||
5769 | 6058 | ||
5770 | /* | 6059 | /* |
5771 | ------------------------------------------------------------------------------ | 6060 | ------------------------------------------------------------------------------ |
@@ -6188,7 +6477,9 @@ test_encodes_text () | |||
6188 | 0, | 6477 | 0, |
6189 | test_malloc, | 6478 | test_malloc, |
6190 | test_realloc, | 6479 | test_realloc, |
6191 | test_free)) | 6480 | test_free, |
6481 | NULL, | ||
6482 | NULL)) | ||
6192 | { | 6483 | { |
6193 | /* Fail test: allocation while no memory available */ | 6484 | /* Fail test: allocation while no memory available */ |
6194 | disable_alloc = 1; | 6485 | disable_alloc = 1; |
@@ -6276,9 +6567,14 @@ test_encodes_binary () | |||
6276 | char*frame = NULL; | 6567 | char*frame = NULL; |
6277 | size_t frame_len = 0; | 6568 | size_t frame_len = 0; |
6278 | 6569 | ||
6279 | if (MHD_WEBSOCKET_STATUS_OK != MHD_websocket_stream_init (&wsc, | 6570 | if (MHD_WEBSOCKET_STATUS_OK != MHD_websocket_stream_init2 (&wsc, |
6280 | MHD_WEBSOCKET_FLAG_CLIENT, | 6571 | MHD_WEBSOCKET_FLAG_CLIENT, |
6281 | 0)) | 6572 | 0, |
6573 | malloc, | ||
6574 | realloc, | ||
6575 | free, | ||
6576 | NULL, | ||
6577 | test_rng)) | ||
6282 | { | 6578 | { |
6283 | fprintf (stderr, | 6579 | fprintf (stderr, |
6284 | "No encode binary tests possible due to failed stream init in line %u\n", | 6580 | "No encode binary tests possible due to failed stream init in line %u\n", |
@@ -6688,6 +6984,7 @@ test_encodes_binary () | |||
6688 | free (buf2); | 6984 | free (buf2); |
6689 | buf2 = NULL; | 6985 | buf2 = NULL; |
6690 | } | 6986 | } |
6987 | #ifdef ENABLE_64BIT_TESTS | ||
6691 | /* Fail test: `frame_len` is greater than 0x7FFFFFFFFFFFFFFF | 6988 | /* Fail test: `frame_len` is greater than 0x7FFFFFFFFFFFFFFF |
6692 | (this is the maximum allowed payload size) */ | 6989 | (this is the maximum allowed payload size) */ |
6693 | frame_len = 0; | 6990 | frame_len = 0; |
@@ -6711,6 +7008,7 @@ test_encodes_binary () | |||
6711 | MHD_websocket_free (wss, frame); | 7008 | MHD_websocket_free (wss, frame); |
6712 | frame = NULL; | 7009 | frame = NULL; |
6713 | } | 7010 | } |
7011 | #endif | ||
6714 | 7012 | ||
6715 | /* | 7013 | /* |
6716 | ------------------------------------------------------------------------------ | 7014 | ------------------------------------------------------------------------------ |
@@ -6882,7 +7180,9 @@ test_encodes_binary () | |||
6882 | 0, | 7180 | 0, |
6883 | test_malloc, | 7181 | test_malloc, |
6884 | test_realloc, | 7182 | test_realloc, |
6885 | test_free)) | 7183 | test_free, |
7184 | NULL, | ||
7185 | NULL)) | ||
6886 | { | 7186 | { |
6887 | /* Fail test: allocation while no memory available */ | 7187 | /* Fail test: allocation while no memory available */ |
6888 | disable_alloc = 1; | 7188 | disable_alloc = 1; |
@@ -6968,18 +7268,28 @@ test_encodes_close () | |||
6968 | char*frame = NULL; | 7268 | char*frame = NULL; |
6969 | size_t frame_len = 0; | 7269 | size_t frame_len = 0; |
6970 | 7270 | ||
6971 | if (MHD_WEBSOCKET_STATUS_OK != MHD_websocket_stream_init (&wsc, | 7271 | if (MHD_WEBSOCKET_STATUS_OK != MHD_websocket_stream_init2 (&wsc, |
6972 | MHD_WEBSOCKET_FLAG_CLIENT, | 7272 | MHD_WEBSOCKET_FLAG_CLIENT, |
6973 | 0)) | 7273 | 0, |
7274 | malloc, | ||
7275 | realloc, | ||
7276 | free, | ||
7277 | NULL, | ||
7278 | test_rng)) | ||
6974 | { | 7279 | { |
6975 | fprintf (stderr, | 7280 | fprintf (stderr, |
6976 | "No encode close tests possible due to failed stream init in line %u\n", | 7281 | "No encode close tests possible due to failed stream init in line %u\n", |
6977 | (unsigned int) __LINE__); | 7282 | (unsigned int) __LINE__); |
6978 | return 0x10; | 7283 | return 0x10; |
6979 | } | 7284 | } |
6980 | if (MHD_WEBSOCKET_STATUS_OK != MHD_websocket_stream_init (&wss, | 7285 | if (MHD_WEBSOCKET_STATUS_OK != MHD_websocket_stream_init2 (&wss, |
6981 | MHD_WEBSOCKET_FLAG_SERVER, | 7286 | MHD_WEBSOCKET_FLAG_SERVER, |
6982 | 0)) | 7287 | 0, |
7288 | malloc, | ||
7289 | realloc, | ||
7290 | free, | ||
7291 | NULL, | ||
7292 | test_rng)) | ||
6983 | { | 7293 | { |
6984 | fprintf (stderr, | 7294 | fprintf (stderr, |
6985 | "No encode close tests possible due to failed stream init in line %u\n", | 7295 | "No encode close tests possible due to failed stream init in line %u\n", |
@@ -7623,7 +7933,9 @@ test_encodes_close () | |||
7623 | 0, | 7933 | 0, |
7624 | test_malloc, | 7934 | test_malloc, |
7625 | test_realloc, | 7935 | test_realloc, |
7626 | test_free)) | 7936 | test_free, |
7937 | NULL, | ||
7938 | NULL)) | ||
7627 | { | 7939 | { |
7628 | /* Fail test: allocation while no memory available */ | 7940 | /* Fail test: allocation while no memory available */ |
7629 | disable_alloc = 1; | 7941 | disable_alloc = 1; |
@@ -7709,9 +8021,14 @@ test_encodes_ping () | |||
7709 | char*frame = NULL; | 8021 | char*frame = NULL; |
7710 | size_t frame_len = 0; | 8022 | size_t frame_len = 0; |
7711 | 8023 | ||
7712 | if (MHD_WEBSOCKET_STATUS_OK != MHD_websocket_stream_init (&wsc, | 8024 | if (MHD_WEBSOCKET_STATUS_OK != MHD_websocket_stream_init2 (&wsc, |
7713 | MHD_WEBSOCKET_FLAG_CLIENT, | 8025 | MHD_WEBSOCKET_FLAG_CLIENT, |
7714 | 0)) | 8026 | 0, |
8027 | malloc, | ||
8028 | realloc, | ||
8029 | free, | ||
8030 | NULL, | ||
8031 | test_rng)) | ||
7715 | { | 8032 | { |
7716 | fprintf (stderr, | 8033 | fprintf (stderr, |
7717 | "No encode ping tests possible due to failed stream init in line %u\n", | 8034 | "No encode ping tests possible due to failed stream init in line %u\n", |
@@ -8156,7 +8473,9 @@ test_encodes_ping () | |||
8156 | 0, | 8473 | 0, |
8157 | test_malloc, | 8474 | test_malloc, |
8158 | test_realloc, | 8475 | test_realloc, |
8159 | test_free)) | 8476 | test_free, |
8477 | NULL, | ||
8478 | NULL)) | ||
8160 | { | 8479 | { |
8161 | /* Fail test: allocation while no memory available */ | 8480 | /* Fail test: allocation while no memory available */ |
8162 | disable_alloc = 1; | 8481 | disable_alloc = 1; |
@@ -8240,9 +8559,14 @@ test_encodes_pong () | |||
8240 | char*frame = NULL; | 8559 | char*frame = NULL; |
8241 | size_t frame_len = 0; | 8560 | size_t frame_len = 0; |
8242 | 8561 | ||
8243 | if (MHD_WEBSOCKET_STATUS_OK != MHD_websocket_stream_init (&wsc, | 8562 | if (MHD_WEBSOCKET_STATUS_OK != MHD_websocket_stream_init2 (&wsc, |
8244 | MHD_WEBSOCKET_FLAG_CLIENT, | 8563 | MHD_WEBSOCKET_FLAG_CLIENT, |
8245 | 0)) | 8564 | 0, |
8565 | malloc, | ||
8566 | realloc, | ||
8567 | free, | ||
8568 | NULL, | ||
8569 | test_rng)) | ||
8246 | { | 8570 | { |
8247 | fprintf (stderr, | 8571 | fprintf (stderr, |
8248 | "No encode pong tests possible due to failed stream init in line %u\n", | 8572 | "No encode pong tests possible due to failed stream init in line %u\n", |
@@ -8687,7 +9011,9 @@ test_encodes_pong () | |||
8687 | 0, | 9011 | 0, |
8688 | test_malloc, | 9012 | test_malloc, |
8689 | test_realloc, | 9013 | test_realloc, |
8690 | test_free)) | 9014 | test_free, |
9015 | NULL, | ||
9016 | NULL)) | ||
8691 | { | 9017 | { |
8692 | /* Fail test: allocation while no memory available */ | 9018 | /* Fail test: allocation while no memory available */ |
8693 | disable_alloc = 1; | 9019 | disable_alloc = 1; |
@@ -8955,6 +9281,793 @@ test_split_close_reason () | |||
8955 | } | 9281 | } |
8956 | 9282 | ||
8957 | 9283 | ||
9284 | /** | ||
9285 | * Test procedure for `MHD_websocket_check_http_version()` | ||
9286 | */ | ||
9287 | int | ||
9288 | test_check_http_version () | ||
9289 | { | ||
9290 | int failed = 0; | ||
9291 | int ret; | ||
9292 | |||
9293 | /* | ||
9294 | ------------------------------------------------------------------------------ | ||
9295 | Version check with valid HTTP version syntax | ||
9296 | ------------------------------------------------------------------------------ | ||
9297 | */ | ||
9298 | /* Regular test: HTTP/1.1 */ | ||
9299 | ret = MHD_websocket_check_http_version ("HTTP/1.1"); | ||
9300 | if (MHD_WEBSOCKET_STATUS_OK != ret) | ||
9301 | { | ||
9302 | fprintf (stderr, | ||
9303 | "check_http_version test failed in line %u.\n", | ||
9304 | (unsigned int) __LINE__); | ||
9305 | ++failed; | ||
9306 | } | ||
9307 | /* Regular test: HTTP/1.2 */ | ||
9308 | ret = MHD_websocket_check_http_version ("HTTP/1.2"); | ||
9309 | if (MHD_WEBSOCKET_STATUS_OK != ret) | ||
9310 | { | ||
9311 | fprintf (stderr, | ||
9312 | "check_http_version test failed in line %u.\n", | ||
9313 | (unsigned int) __LINE__); | ||
9314 | ++failed; | ||
9315 | } | ||
9316 | /* Regular test: HTTP/1.10 */ | ||
9317 | ret = MHD_websocket_check_http_version ("HTTP/1.10"); | ||
9318 | if (MHD_WEBSOCKET_STATUS_OK != ret) | ||
9319 | { | ||
9320 | fprintf (stderr, | ||
9321 | "check_http_version test failed in line %u.\n", | ||
9322 | (unsigned int) __LINE__); | ||
9323 | ++failed; | ||
9324 | } | ||
9325 | /* Regular test: HTTP/2.0 */ | ||
9326 | ret = MHD_websocket_check_http_version ("HTTP/2.0"); | ||
9327 | if (MHD_WEBSOCKET_STATUS_OK != ret) | ||
9328 | { | ||
9329 | fprintf (stderr, | ||
9330 | "check_http_version test failed in line %u.\n", | ||
9331 | (unsigned int) __LINE__); | ||
9332 | ++failed; | ||
9333 | } | ||
9334 | /* Regular test: HTTP/3.0 */ | ||
9335 | ret = MHD_websocket_check_http_version ("HTTP/3.0"); | ||
9336 | if (MHD_WEBSOCKET_STATUS_OK != ret) | ||
9337 | { | ||
9338 | fprintf (stderr, | ||
9339 | "check_http_version test failed in line %u.\n", | ||
9340 | (unsigned int) __LINE__); | ||
9341 | ++failed; | ||
9342 | } | ||
9343 | /* Fail test: HTTP/1.0 */ | ||
9344 | ret = MHD_websocket_check_http_version ("HTTP/1.0"); | ||
9345 | if (MHD_WEBSOCKET_STATUS_NO_WEBSOCKET_HANDSHAKE_HEADER != ret) | ||
9346 | { | ||
9347 | fprintf (stderr, | ||
9348 | "check_http_version test failed in line %u.\n", | ||
9349 | (unsigned int) __LINE__); | ||
9350 | ++failed; | ||
9351 | } | ||
9352 | /* Fail test: HTTP/0.9 */ | ||
9353 | ret = MHD_websocket_check_http_version ("HTTP/0.9"); | ||
9354 | if (MHD_WEBSOCKET_STATUS_NO_WEBSOCKET_HANDSHAKE_HEADER != ret) | ||
9355 | { | ||
9356 | fprintf (stderr, | ||
9357 | "check_http_version test failed in line %u.\n", | ||
9358 | (unsigned int) __LINE__); | ||
9359 | ++failed; | ||
9360 | } | ||
9361 | |||
9362 | /* | ||
9363 | ------------------------------------------------------------------------------ | ||
9364 | Version check edge cases | ||
9365 | ------------------------------------------------------------------------------ | ||
9366 | */ | ||
9367 | /* Edge test (success): HTTP/123.45 */ | ||
9368 | ret = MHD_websocket_check_http_version ("HTTP/123.45"); | ||
9369 | if (MHD_WEBSOCKET_STATUS_OK != ret) | ||
9370 | { | ||
9371 | fprintf (stderr, | ||
9372 | "check_http_version test failed in line %u.\n", | ||
9373 | (unsigned int) __LINE__); | ||
9374 | ++failed; | ||
9375 | } | ||
9376 | /* Edge test (success): HTTP/1.45 */ | ||
9377 | ret = MHD_websocket_check_http_version ("HTTP/1.45"); | ||
9378 | if (MHD_WEBSOCKET_STATUS_OK != ret) | ||
9379 | { | ||
9380 | fprintf (stderr, | ||
9381 | "check_http_version test failed in line %u.\n", | ||
9382 | (unsigned int) __LINE__); | ||
9383 | ++failed; | ||
9384 | } | ||
9385 | /* Edge test (success): HTTP/01.1 */ | ||
9386 | ret = MHD_websocket_check_http_version ("HTTP/01.1"); | ||
9387 | if (MHD_WEBSOCKET_STATUS_OK != ret) | ||
9388 | { | ||
9389 | fprintf (stderr, | ||
9390 | "check_http_version test failed in line %u.\n", | ||
9391 | (unsigned int) __LINE__); | ||
9392 | ++failed; | ||
9393 | } | ||
9394 | /* Edge test (success): HTTP/0001.1 */ | ||
9395 | ret = MHD_websocket_check_http_version ("HTTP/0001.1"); | ||
9396 | if (MHD_WEBSOCKET_STATUS_OK != ret) | ||
9397 | { | ||
9398 | fprintf (stderr, | ||
9399 | "check_http_version test failed in line %u.\n", | ||
9400 | (unsigned int) __LINE__); | ||
9401 | ++failed; | ||
9402 | } | ||
9403 | /* Edge test (success): HTTP/1.01 */ | ||
9404 | ret = MHD_websocket_check_http_version ("HTTP/1.01"); | ||
9405 | if (MHD_WEBSOCKET_STATUS_OK != ret) | ||
9406 | { | ||
9407 | fprintf (stderr, | ||
9408 | "check_http_version test failed in line %u.\n", | ||
9409 | (unsigned int) __LINE__); | ||
9410 | ++failed; | ||
9411 | } | ||
9412 | /* Edge test (success): HTTP/1.0001 */ | ||
9413 | ret = MHD_websocket_check_http_version ("HTTP/1.0001"); | ||
9414 | if (MHD_WEBSOCKET_STATUS_OK != ret) | ||
9415 | { | ||
9416 | fprintf (stderr, | ||
9417 | "check_http_version test failed in line %u.\n", | ||
9418 | (unsigned int) __LINE__); | ||
9419 | ++failed; | ||
9420 | } | ||
9421 | /* Edge test (success): HTTP/0001.0001 */ | ||
9422 | ret = MHD_websocket_check_http_version ("HTTP/0001.0001"); | ||
9423 | if (MHD_WEBSOCKET_STATUS_OK != ret) | ||
9424 | { | ||
9425 | fprintf (stderr, | ||
9426 | "check_http_version test failed in line %u.\n", | ||
9427 | (unsigned int) __LINE__); | ||
9428 | ++failed; | ||
9429 | } | ||
9430 | /* Edge test (success): HTTP/2.000 */ | ||
9431 | ret = MHD_websocket_check_http_version ("HTTP/2.000"); | ||
9432 | if (MHD_WEBSOCKET_STATUS_OK != ret) | ||
9433 | { | ||
9434 | fprintf (stderr, | ||
9435 | "check_http_version test failed in line %u.\n", | ||
9436 | (unsigned int) __LINE__); | ||
9437 | ++failed; | ||
9438 | } | ||
9439 | /* Edge test (fail): HTTP/0.0 */ | ||
9440 | ret = MHD_websocket_check_http_version ("HTTP/0.0"); | ||
9441 | if (MHD_WEBSOCKET_STATUS_NO_WEBSOCKET_HANDSHAKE_HEADER != ret) | ||
9442 | { | ||
9443 | fprintf (stderr, | ||
9444 | "check_http_version test failed in line %u.\n", | ||
9445 | (unsigned int) __LINE__); | ||
9446 | ++failed; | ||
9447 | } | ||
9448 | /* Edge test (fail): HTTP/00.0 */ | ||
9449 | ret = MHD_websocket_check_http_version ("HTTP/00.0"); | ||
9450 | if (MHD_WEBSOCKET_STATUS_NO_WEBSOCKET_HANDSHAKE_HEADER != ret) | ||
9451 | { | ||
9452 | fprintf (stderr, | ||
9453 | "check_http_version test failed in line %u.\n", | ||
9454 | (unsigned int) __LINE__); | ||
9455 | ++failed; | ||
9456 | } | ||
9457 | /* Edge test (fail): HTTP/00.0 */ | ||
9458 | ret = MHD_websocket_check_http_version ("HTTP/0.00"); | ||
9459 | if (MHD_WEBSOCKET_STATUS_NO_WEBSOCKET_HANDSHAKE_HEADER != ret) | ||
9460 | { | ||
9461 | fprintf (stderr, | ||
9462 | "check_http_version test failed in line %u.\n", | ||
9463 | (unsigned int) __LINE__); | ||
9464 | ++failed; | ||
9465 | } | ||
9466 | |||
9467 | /* | ||
9468 | ------------------------------------------------------------------------------ | ||
9469 | Invalid version syntax | ||
9470 | ------------------------------------------------------------------------------ | ||
9471 | */ | ||
9472 | /* Fail test: (empty string) */ | ||
9473 | ret = MHD_websocket_check_http_version (""); | ||
9474 | if (MHD_WEBSOCKET_STATUS_NO_WEBSOCKET_HANDSHAKE_HEADER != ret) | ||
9475 | { | ||
9476 | fprintf (stderr, | ||
9477 | "check_http_version test failed in line %u.\n", | ||
9478 | (unsigned int) __LINE__); | ||
9479 | ++failed; | ||
9480 | } | ||
9481 | /* Fail test: http/1.1 */ | ||
9482 | ret = MHD_websocket_check_http_version ("http/1.1"); | ||
9483 | if (MHD_WEBSOCKET_STATUS_NO_WEBSOCKET_HANDSHAKE_HEADER != ret) | ||
9484 | { | ||
9485 | fprintf (stderr, | ||
9486 | "check_http_version test failed in line %u.\n", | ||
9487 | (unsigned int) __LINE__); | ||
9488 | ++failed; | ||
9489 | } | ||
9490 | /* Fail test: "HTTP / 1.1" */ | ||
9491 | ret = MHD_websocket_check_http_version ("HTTP / 1.1"); | ||
9492 | if (MHD_WEBSOCKET_STATUS_NO_WEBSOCKET_HANDSHAKE_HEADER != ret) | ||
9493 | { | ||
9494 | fprintf (stderr, | ||
9495 | "check_http_version test failed in line %u.\n", | ||
9496 | (unsigned int) __LINE__); | ||
9497 | ++failed; | ||
9498 | } | ||
9499 | |||
9500 | /* | ||
9501 | ------------------------------------------------------------------------------ | ||
9502 | Missing parameters | ||
9503 | ------------------------------------------------------------------------------ | ||
9504 | */ | ||
9505 | /* Fail test: NULL as version */ | ||
9506 | ret = MHD_websocket_check_http_version (NULL); | ||
9507 | if (MHD_WEBSOCKET_STATUS_NO_WEBSOCKET_HANDSHAKE_HEADER != ret) | ||
9508 | { | ||
9509 | fprintf (stderr, | ||
9510 | "check_http_version test failed in line %u.\n", | ||
9511 | (unsigned int) __LINE__); | ||
9512 | ++failed; | ||
9513 | } | ||
9514 | |||
9515 | return failed != 0 ? 0x200 : 0x00; | ||
9516 | } | ||
9517 | |||
9518 | |||
9519 | /** | ||
9520 | * Test procedure for `MHD_websocket_check_connection_header()` | ||
9521 | */ | ||
9522 | int | ||
9523 | test_check_connection_header () | ||
9524 | { | ||
9525 | int failed = 0; | ||
9526 | int ret; | ||
9527 | |||
9528 | /* | ||
9529 | ------------------------------------------------------------------------------ | ||
9530 | Check with valid Connection header syntax | ||
9531 | ------------------------------------------------------------------------------ | ||
9532 | */ | ||
9533 | /* Regular test: Upgrade */ | ||
9534 | ret = MHD_websocket_check_connection_header ("Upgrade"); | ||
9535 | if (MHD_WEBSOCKET_STATUS_OK != ret) | ||
9536 | { | ||
9537 | fprintf (stderr, | ||
9538 | "check_connection_header test failed in line %u.\n", | ||
9539 | (unsigned int) __LINE__); | ||
9540 | ++failed; | ||
9541 | } | ||
9542 | /* Regular test: keep-alive, Upgrade */ | ||
9543 | ret = MHD_websocket_check_connection_header ("keep-alive, Upgrade"); | ||
9544 | if (MHD_WEBSOCKET_STATUS_OK != ret) | ||
9545 | { | ||
9546 | fprintf (stderr, | ||
9547 | "check_connection_header test failed in line %u.\n", | ||
9548 | (unsigned int) __LINE__); | ||
9549 | ++failed; | ||
9550 | } | ||
9551 | /* Fail test: keep-alive */ | ||
9552 | ret = MHD_websocket_check_connection_header ("keep-alive"); | ||
9553 | if (MHD_WEBSOCKET_STATUS_NO_WEBSOCKET_HANDSHAKE_HEADER != ret) | ||
9554 | { | ||
9555 | fprintf (stderr, | ||
9556 | "check_connection_header test failed in line %u.\n", | ||
9557 | (unsigned int) __LINE__); | ||
9558 | ++failed; | ||
9559 | } | ||
9560 | /* Fail test: close */ | ||
9561 | ret = MHD_websocket_check_connection_header ("close"); | ||
9562 | if (MHD_WEBSOCKET_STATUS_NO_WEBSOCKET_HANDSHAKE_HEADER != ret) | ||
9563 | { | ||
9564 | fprintf (stderr, | ||
9565 | "check_connection_header test failed in line %u.\n", | ||
9566 | (unsigned int) __LINE__); | ||
9567 | ++failed; | ||
9568 | } | ||
9569 | |||
9570 | /* | ||
9571 | ------------------------------------------------------------------------------ | ||
9572 | Connection check edge cases | ||
9573 | ------------------------------------------------------------------------------ | ||
9574 | */ | ||
9575 | /* Edge test (success): keep-alive,Upgrade */ | ||
9576 | ret = MHD_websocket_check_connection_header ("keep-alive,Upgrade"); | ||
9577 | if (MHD_WEBSOCKET_STATUS_OK != ret) | ||
9578 | { | ||
9579 | fprintf (stderr, | ||
9580 | "check_connection_header test failed in line %u.\n", | ||
9581 | (unsigned int) __LINE__); | ||
9582 | ++failed; | ||
9583 | } | ||
9584 | /* Edge test (success): Upgrade, keep-alive */ | ||
9585 | ret = MHD_websocket_check_connection_header ("Upgrade, keep-alive"); | ||
9586 | if (MHD_WEBSOCKET_STATUS_OK != ret) | ||
9587 | { | ||
9588 | fprintf (stderr, | ||
9589 | "check_connection_header test failed in line %u.\n", | ||
9590 | (unsigned int) __LINE__); | ||
9591 | ++failed; | ||
9592 | } | ||
9593 | /* Edge test (success): Upgrade,keep-alive */ | ||
9594 | ret = MHD_websocket_check_connection_header ("Upgrade,keep-alive"); | ||
9595 | if (MHD_WEBSOCKET_STATUS_OK != ret) | ||
9596 | { | ||
9597 | fprintf (stderr, | ||
9598 | "check_connection_header test failed in line %u.\n", | ||
9599 | (unsigned int) __LINE__); | ||
9600 | ++failed; | ||
9601 | } | ||
9602 | /* Edge test (success): Transfer-Encoding,Upgrade,keep-alive */ | ||
9603 | ret = MHD_websocket_check_connection_header ("Transfer-Encoding,Upgrade,keep-alive"); | ||
9604 | if (MHD_WEBSOCKET_STATUS_OK != ret) | ||
9605 | { | ||
9606 | fprintf (stderr, | ||
9607 | "check_connection_header test failed in line %u.\n", | ||
9608 | (unsigned int) __LINE__); | ||
9609 | ++failed; | ||
9610 | } | ||
9611 | /* Edge test (success): Transfer-Encoding , Upgrade , keep-alive */ | ||
9612 | ret = MHD_websocket_check_connection_header ("Transfer-Encoding , Upgrade , keep-alive"); | ||
9613 | if (MHD_WEBSOCKET_STATUS_OK != ret) | ||
9614 | { | ||
9615 | fprintf (stderr, | ||
9616 | "check_connection_header test failed in line %u.\n", | ||
9617 | (unsigned int) __LINE__); | ||
9618 | ++failed; | ||
9619 | } | ||
9620 | /* Edge test (success): upgrade */ | ||
9621 | ret = MHD_websocket_check_connection_header ("upgrade"); | ||
9622 | if (MHD_WEBSOCKET_STATUS_OK != ret) | ||
9623 | { | ||
9624 | fprintf (stderr, | ||
9625 | "check_connection_header test failed in line %u.\n", | ||
9626 | (unsigned int) __LINE__); | ||
9627 | ++failed; | ||
9628 | } | ||
9629 | /* Edge test (success): UPGRADE */ | ||
9630 | ret = MHD_websocket_check_connection_header ("UPGRADE"); | ||
9631 | if (MHD_WEBSOCKET_STATUS_OK != ret) | ||
9632 | { | ||
9633 | fprintf (stderr, | ||
9634 | "check_connection_header test failed in line %u.\n", | ||
9635 | (unsigned int) __LINE__); | ||
9636 | ++failed; | ||
9637 | } | ||
9638 | /* Edge test (success): All allowed token characters, then upgrade token */ | ||
9639 | ret = MHD_websocket_check_connection_header ("!#$%&'*+-.^_`|~0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz,Upgrade"); | ||
9640 | if (MHD_WEBSOCKET_STATUS_OK != ret) | ||
9641 | { | ||
9642 | fprintf (stderr, | ||
9643 | "check_connection_header test failed in line %u.\n", | ||
9644 | (unsigned int) __LINE__); | ||
9645 | ++failed; | ||
9646 | } | ||
9647 | /* Edge test (success): Different, allowed whitespaces */ | ||
9648 | ret = MHD_websocket_check_connection_header (" \tUpgrade \t"); | ||
9649 | if (MHD_WEBSOCKET_STATUS_OK != ret) | ||
9650 | { | ||
9651 | fprintf (stderr, | ||
9652 | "check_connection_header test failed in line %u.\n", | ||
9653 | (unsigned int) __LINE__); | ||
9654 | ++failed; | ||
9655 | } | ||
9656 | /* Edge test (fail): Different, disallowed whitespaces */ | ||
9657 | ret = MHD_websocket_check_connection_header ("\rUpgrade"); | ||
9658 | if (MHD_WEBSOCKET_STATUS_NO_WEBSOCKET_HANDSHAKE_HEADER != ret) | ||
9659 | { | ||
9660 | fprintf (stderr, | ||
9661 | "check_connection_header test failed in line %u.\n", | ||
9662 | (unsigned int) __LINE__); | ||
9663 | ++failed; | ||
9664 | } | ||
9665 | /* Edge test (fail): Different, disallowed whitespaces */ | ||
9666 | ret = MHD_websocket_check_connection_header ("\nUpgrade"); | ||
9667 | if (MHD_WEBSOCKET_STATUS_NO_WEBSOCKET_HANDSHAKE_HEADER != ret) | ||
9668 | { | ||
9669 | fprintf (stderr, | ||
9670 | "check_connection_header test failed in line %u.\n", | ||
9671 | (unsigned int) __LINE__); | ||
9672 | ++failed; | ||
9673 | } | ||
9674 | /* Edge test (fail): Different, disallowed whitespaces */ | ||
9675 | ret = MHD_websocket_check_connection_header ("\vUpgrade"); | ||
9676 | if (MHD_WEBSOCKET_STATUS_NO_WEBSOCKET_HANDSHAKE_HEADER != ret) | ||
9677 | { | ||
9678 | fprintf (stderr, | ||
9679 | "check_connection_header test failed in line %u.\n", | ||
9680 | (unsigned int) __LINE__); | ||
9681 | ++failed; | ||
9682 | } | ||
9683 | /* Edge test (fail): Different, disallowed whitespaces */ | ||
9684 | ret = MHD_websocket_check_connection_header ("\fUpgrade"); | ||
9685 | if (MHD_WEBSOCKET_STATUS_NO_WEBSOCKET_HANDSHAKE_HEADER != ret) | ||
9686 | { | ||
9687 | fprintf (stderr, | ||
9688 | "check_connection_header test failed in line %u.\n", | ||
9689 | (unsigned int) __LINE__); | ||
9690 | ++failed; | ||
9691 | } | ||
9692 | |||
9693 | /* | ||
9694 | ------------------------------------------------------------------------------ | ||
9695 | Invalid header syntax | ||
9696 | ------------------------------------------------------------------------------ | ||
9697 | */ | ||
9698 | /* Fail test: (empty string) */ | ||
9699 | ret = MHD_websocket_check_connection_header (""); | ||
9700 | if (MHD_WEBSOCKET_STATUS_NO_WEBSOCKET_HANDSHAKE_HEADER != ret) | ||
9701 | { | ||
9702 | fprintf (stderr, | ||
9703 | "check_connection_header test failed in line %u.\n", | ||
9704 | (unsigned int) __LINE__); | ||
9705 | ++failed; | ||
9706 | } | ||
9707 | /* Fail test: (Disallowed) multiple word token with the term "Upgrade" in it */ | ||
9708 | ret = MHD_websocket_check_connection_header ("Upgrade or Downgrade"); | ||
9709 | if (MHD_WEBSOCKET_STATUS_NO_WEBSOCKET_HANDSHAKE_HEADER != ret) | ||
9710 | { | ||
9711 | fprintf (stderr, | ||
9712 | "check_connection_header test failed in line %u.\n", | ||
9713 | (unsigned int) __LINE__); | ||
9714 | ++failed; | ||
9715 | } | ||
9716 | /* Fail test: Invalid characters */ | ||
9717 | ret = MHD_websocket_check_connection_header ("\"Upgrade\""); | ||
9718 | if (MHD_WEBSOCKET_STATUS_NO_WEBSOCKET_HANDSHAKE_HEADER != ret) | ||
9719 | { | ||
9720 | fprintf (stderr, | ||
9721 | "check_connection_header test failed in line %u.\n", | ||
9722 | (unsigned int) __LINE__); | ||
9723 | ++failed; | ||
9724 | } | ||
9725 | |||
9726 | /* | ||
9727 | ------------------------------------------------------------------------------ | ||
9728 | Missing parameters | ||
9729 | ------------------------------------------------------------------------------ | ||
9730 | */ | ||
9731 | /* Fail test: NULL as connection */ | ||
9732 | ret = MHD_websocket_check_connection_header (NULL); | ||
9733 | if (MHD_WEBSOCKET_STATUS_NO_WEBSOCKET_HANDSHAKE_HEADER != ret) | ||
9734 | { | ||
9735 | fprintf (stderr, | ||
9736 | "check_connection_header test failed in line %u.\n", | ||
9737 | (unsigned int) __LINE__); | ||
9738 | ++failed; | ||
9739 | } | ||
9740 | |||
9741 | return failed != 0 ? 0x400 : 0x00; | ||
9742 | } | ||
9743 | |||
9744 | |||
9745 | /** | ||
9746 | * Test procedure for `MHD_websocket_check_upgrade_header()` | ||
9747 | */ | ||
9748 | int | ||
9749 | test_check_upgrade_header () | ||
9750 | { | ||
9751 | int failed = 0; | ||
9752 | int ret; | ||
9753 | |||
9754 | /* | ||
9755 | ------------------------------------------------------------------------------ | ||
9756 | Check with valid Upgrade header syntax | ||
9757 | ------------------------------------------------------------------------------ | ||
9758 | */ | ||
9759 | /* Regular test: websocket */ | ||
9760 | ret = MHD_websocket_check_upgrade_header ("websocket"); | ||
9761 | if (MHD_WEBSOCKET_STATUS_OK != ret) | ||
9762 | { | ||
9763 | fprintf (stderr, | ||
9764 | "check_upgrade_header test failed in line %u.\n", | ||
9765 | (unsigned int) __LINE__); | ||
9766 | ++failed; | ||
9767 | } | ||
9768 | /* Fail test: HTTP/2.0 */ | ||
9769 | ret = MHD_websocket_check_upgrade_header ("HTTP/2.0"); | ||
9770 | if (MHD_WEBSOCKET_STATUS_NO_WEBSOCKET_HANDSHAKE_HEADER != ret) | ||
9771 | { | ||
9772 | fprintf (stderr, | ||
9773 | "check_upgrade_header test failed in line %u.\n", | ||
9774 | (unsigned int) __LINE__); | ||
9775 | ++failed; | ||
9776 | } | ||
9777 | |||
9778 | /* | ||
9779 | ------------------------------------------------------------------------------ | ||
9780 | Upgrade check edge cases | ||
9781 | ------------------------------------------------------------------------------ | ||
9782 | */ | ||
9783 | /* Edge test (success): websocket,HTTP/2.0 */ | ||
9784 | ret = MHD_websocket_check_upgrade_header ("websocket,HTTP/2.0"); | ||
9785 | if (MHD_WEBSOCKET_STATUS_OK != ret) | ||
9786 | { | ||
9787 | fprintf (stderr, | ||
9788 | "check_upgrade_header test failed in line %u.\n", | ||
9789 | (unsigned int) __LINE__); | ||
9790 | ++failed; | ||
9791 | } | ||
9792 | /* Edge test (success): websocket ,HTTP/2.0 */ | ||
9793 | ret = MHD_websocket_check_upgrade_header (" websocket ,HTTP/2.0"); | ||
9794 | if (MHD_WEBSOCKET_STATUS_OK != ret) | ||
9795 | { | ||
9796 | fprintf (stderr, | ||
9797 | "check_upgrade_header test failed in line %u.\n", | ||
9798 | (unsigned int) __LINE__); | ||
9799 | ++failed; | ||
9800 | } | ||
9801 | /* Edge test (success): HTTP/2.0, websocket */ | ||
9802 | ret = MHD_websocket_check_upgrade_header ("HTTP/2.0, websocket "); | ||
9803 | if (MHD_WEBSOCKET_STATUS_OK != ret) | ||
9804 | { | ||
9805 | fprintf (stderr, | ||
9806 | "check_upgrade_header test failed in line %u.\n", | ||
9807 | (unsigned int) __LINE__); | ||
9808 | ++failed; | ||
9809 | } | ||
9810 | /* Edge test (fail): websocket/13 */ | ||
9811 | ret = MHD_websocket_check_upgrade_header ("websocket/13"); | ||
9812 | if (MHD_WEBSOCKET_STATUS_NO_WEBSOCKET_HANDSHAKE_HEADER != ret) | ||
9813 | { | ||
9814 | fprintf (stderr, | ||
9815 | "check_upgrade_header test failed in line %u.\n", | ||
9816 | (unsigned int) __LINE__); | ||
9817 | ++failed; | ||
9818 | } | ||
9819 | /* Edge test (success): WeBsOcKeT */ | ||
9820 | ret = MHD_websocket_check_upgrade_header ("WeBsOcKeT"); | ||
9821 | if (MHD_WEBSOCKET_STATUS_OK != ret) | ||
9822 | { | ||
9823 | fprintf (stderr, | ||
9824 | "check_upgrade_header test failed in line %u.\n", | ||
9825 | (unsigned int) __LINE__); | ||
9826 | ++failed; | ||
9827 | } | ||
9828 | /* Edge test (success): WEBSOCKET */ | ||
9829 | ret = MHD_websocket_check_upgrade_header ("WEBSOCKET"); | ||
9830 | if (MHD_WEBSOCKET_STATUS_OK != ret) | ||
9831 | { | ||
9832 | fprintf (stderr, | ||
9833 | "check_upgrade_header test failed in line %u.\n", | ||
9834 | (unsigned int) __LINE__); | ||
9835 | ++failed; | ||
9836 | } | ||
9837 | /* Edge test (success): All allowed token characters plus /, then websocket keyowrd */ | ||
9838 | ret = MHD_websocket_check_upgrade_header ("!#$%&'*+-.^_`|~0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz/,websocket"); | ||
9839 | if (MHD_WEBSOCKET_STATUS_OK != ret) | ||
9840 | { | ||
9841 | fprintf (stderr, | ||
9842 | "check_upgrade_header test failed in line %u.\n", | ||
9843 | (unsigned int) __LINE__); | ||
9844 | ++failed; | ||
9845 | } | ||
9846 | /* Edge test (success): Different, allowed whitespaces */ | ||
9847 | ret = MHD_websocket_check_upgrade_header (" \twebsocket \t"); | ||
9848 | if (MHD_WEBSOCKET_STATUS_OK != ret) | ||
9849 | { | ||
9850 | fprintf (stderr, | ||
9851 | "check_upgrade_header test failed in line %u.\n", | ||
9852 | (unsigned int) __LINE__); | ||
9853 | ++failed; | ||
9854 | } | ||
9855 | /* Edge test (fail): Different, disallowed whitespaces */ | ||
9856 | ret = MHD_websocket_check_upgrade_header ("\rwebsocket"); | ||
9857 | if (MHD_WEBSOCKET_STATUS_NO_WEBSOCKET_HANDSHAKE_HEADER != ret) | ||
9858 | { | ||
9859 | fprintf (stderr, | ||
9860 | "check_upgrade_header test failed in line %u.\n", | ||
9861 | (unsigned int) __LINE__); | ||
9862 | ++failed; | ||
9863 | } | ||
9864 | /* Edge test (fail): Different, disallowed whitespaces */ | ||
9865 | ret = MHD_websocket_check_upgrade_header ("\nwebsocket"); | ||
9866 | if (MHD_WEBSOCKET_STATUS_NO_WEBSOCKET_HANDSHAKE_HEADER != ret) | ||
9867 | { | ||
9868 | fprintf (stderr, | ||
9869 | "check_upgrade_header test failed in line %u.\n", | ||
9870 | (unsigned int) __LINE__); | ||
9871 | ++failed; | ||
9872 | } | ||
9873 | /* Edge test (fail): Different, disallowed whitespaces */ | ||
9874 | ret = MHD_websocket_check_upgrade_header ("\vwebsocket"); | ||
9875 | if (MHD_WEBSOCKET_STATUS_NO_WEBSOCKET_HANDSHAKE_HEADER != ret) | ||
9876 | { | ||
9877 | fprintf (stderr, | ||
9878 | "check_upgrade_header test failed in line %u.\n", | ||
9879 | (unsigned int) __LINE__); | ||
9880 | ++failed; | ||
9881 | } | ||
9882 | /* Edge test (fail): Different, disallowed whitespaces */ | ||
9883 | ret = MHD_websocket_check_upgrade_header ("\fwebsocket"); | ||
9884 | if (MHD_WEBSOCKET_STATUS_NO_WEBSOCKET_HANDSHAKE_HEADER != ret) | ||
9885 | { | ||
9886 | fprintf (stderr, | ||
9887 | "check_upgrade_header test failed in line %u.\n", | ||
9888 | (unsigned int) __LINE__); | ||
9889 | ++failed; | ||
9890 | } | ||
9891 | |||
9892 | /* | ||
9893 | ------------------------------------------------------------------------------ | ||
9894 | Invalid header syntax | ||
9895 | ------------------------------------------------------------------------------ | ||
9896 | */ | ||
9897 | /* Fail test: (empty string) */ | ||
9898 | ret = MHD_websocket_check_upgrade_header (""); | ||
9899 | if (MHD_WEBSOCKET_STATUS_NO_WEBSOCKET_HANDSHAKE_HEADER != ret) | ||
9900 | { | ||
9901 | fprintf (stderr, | ||
9902 | "check_upgrade_header test failed in line %u.\n", | ||
9903 | (unsigned int) __LINE__); | ||
9904 | ++failed; | ||
9905 | } | ||
9906 | /* Fail test: (Disallowed) multiple word token with the term "websocket" in it */ | ||
9907 | ret = MHD_websocket_check_upgrade_header ("websocket or something"); | ||
9908 | if (MHD_WEBSOCKET_STATUS_NO_WEBSOCKET_HANDSHAKE_HEADER != ret) | ||
9909 | { | ||
9910 | fprintf (stderr, | ||
9911 | "check_upgrade_header test failed in line %u.\n", | ||
9912 | (unsigned int) __LINE__); | ||
9913 | ++failed; | ||
9914 | } | ||
9915 | /* Fail test: Invalid characters */ | ||
9916 | ret = MHD_websocket_check_upgrade_header ("\"websocket\""); | ||
9917 | if (MHD_WEBSOCKET_STATUS_NO_WEBSOCKET_HANDSHAKE_HEADER != ret) | ||
9918 | { | ||
9919 | fprintf (stderr, | ||
9920 | "check_upgrade_header test failed in line %u.\n", | ||
9921 | (unsigned int) __LINE__); | ||
9922 | ++failed; | ||
9923 | } | ||
9924 | |||
9925 | /* | ||
9926 | ------------------------------------------------------------------------------ | ||
9927 | Missing parameters | ||
9928 | ------------------------------------------------------------------------------ | ||
9929 | */ | ||
9930 | /* Fail test: NULL as upgrade */ | ||
9931 | ret = MHD_websocket_check_upgrade_header (NULL); | ||
9932 | if (MHD_WEBSOCKET_STATUS_NO_WEBSOCKET_HANDSHAKE_HEADER != ret) | ||
9933 | { | ||
9934 | fprintf (stderr, | ||
9935 | "check_upgrade_header test failed in line %u.\n", | ||
9936 | (unsigned int) __LINE__); | ||
9937 | ++failed; | ||
9938 | } | ||
9939 | |||
9940 | return failed != 0 ? 0x800 : 0x00; | ||
9941 | } | ||
9942 | |||
9943 | |||
9944 | /** | ||
9945 | * Test procedure for `MHD_websocket_check_version_header()` | ||
9946 | */ | ||
9947 | int | ||
9948 | test_check_version_header () | ||
9949 | { | ||
9950 | int failed = 0; | ||
9951 | int ret; | ||
9952 | |||
9953 | /* | ||
9954 | ------------------------------------------------------------------------------ | ||
9955 | Check with valid Upgrade header syntax | ||
9956 | ------------------------------------------------------------------------------ | ||
9957 | */ | ||
9958 | /* Regular test: 13 */ | ||
9959 | ret = MHD_websocket_check_version_header ("13"); | ||
9960 | if (MHD_WEBSOCKET_STATUS_OK != ret) | ||
9961 | { | ||
9962 | fprintf (stderr, | ||
9963 | "check_version_header test failed in line %u.\n", | ||
9964 | (unsigned int) __LINE__); | ||
9965 | ++failed; | ||
9966 | } | ||
9967 | |||
9968 | /* | ||
9969 | ------------------------------------------------------------------------------ | ||
9970 | Version check edge cases | ||
9971 | ------------------------------------------------------------------------------ | ||
9972 | */ | ||
9973 | /* Edge test (fail): 14 */ | ||
9974 | ret = MHD_websocket_check_version_header ("14"); | ||
9975 | if (MHD_WEBSOCKET_STATUS_NO_WEBSOCKET_HANDSHAKE_HEADER != ret) | ||
9976 | { | ||
9977 | fprintf (stderr, | ||
9978 | "check_version_header test failed in line %u.\n", | ||
9979 | (unsigned int) __LINE__); | ||
9980 | ++failed; | ||
9981 | } | ||
9982 | /* Edge test (fail): 12 */ | ||
9983 | ret = MHD_websocket_check_version_header ("12"); | ||
9984 | if (MHD_WEBSOCKET_STATUS_NO_WEBSOCKET_HANDSHAKE_HEADER != ret) | ||
9985 | { | ||
9986 | fprintf (stderr, | ||
9987 | "check_version_header test failed in line %u.\n", | ||
9988 | (unsigned int) __LINE__); | ||
9989 | ++failed; | ||
9990 | } | ||
9991 | /* Edge test (fail): 0 */ | ||
9992 | ret = MHD_websocket_check_version_header ("1"); | ||
9993 | if (MHD_WEBSOCKET_STATUS_NO_WEBSOCKET_HANDSHAKE_HEADER != ret) | ||
9994 | { | ||
9995 | fprintf (stderr, | ||
9996 | "check_version_header test failed in line %u.\n", | ||
9997 | (unsigned int) __LINE__); | ||
9998 | ++failed; | ||
9999 | } | ||
10000 | /* Edge test (fail): 1 */ | ||
10001 | ret = MHD_websocket_check_version_header ("1"); | ||
10002 | if (MHD_WEBSOCKET_STATUS_NO_WEBSOCKET_HANDSHAKE_HEADER != ret) | ||
10003 | { | ||
10004 | fprintf (stderr, | ||
10005 | "check_version_header test failed in line %u.\n", | ||
10006 | (unsigned int) __LINE__); | ||
10007 | ++failed; | ||
10008 | } | ||
10009 | /* Edge test (fail): 130 */ | ||
10010 | ret = MHD_websocket_check_version_header ("130"); | ||
10011 | if (MHD_WEBSOCKET_STATUS_NO_WEBSOCKET_HANDSHAKE_HEADER != ret) | ||
10012 | { | ||
10013 | fprintf (stderr, | ||
10014 | "check_version_header test failed in line %u.\n", | ||
10015 | (unsigned int) __LINE__); | ||
10016 | ++failed; | ||
10017 | } | ||
10018 | /* Edge test (fail): " 13" */ | ||
10019 | ret = MHD_websocket_check_version_header (" 13"); | ||
10020 | if (MHD_WEBSOCKET_STATUS_NO_WEBSOCKET_HANDSHAKE_HEADER != ret) | ||
10021 | { | ||
10022 | fprintf (stderr, | ||
10023 | "check_version_header test failed in line %u.\n", | ||
10024 | (unsigned int) __LINE__); | ||
10025 | ++failed; | ||
10026 | } | ||
10027 | |||
10028 | /* | ||
10029 | ------------------------------------------------------------------------------ | ||
10030 | Invalid header syntax | ||
10031 | ------------------------------------------------------------------------------ | ||
10032 | */ | ||
10033 | /* Fail test: (empty string) */ | ||
10034 | ret = MHD_websocket_check_version_header (""); | ||
10035 | if (MHD_WEBSOCKET_STATUS_NO_WEBSOCKET_HANDSHAKE_HEADER != ret) | ||
10036 | { | ||
10037 | fprintf (stderr, | ||
10038 | "check_version_header test failed in line %u.\n", | ||
10039 | (unsigned int) __LINE__); | ||
10040 | ++failed; | ||
10041 | } | ||
10042 | /* Fail test: Invalid characters */ | ||
10043 | ret = MHD_websocket_check_version_header ("abc"); | ||
10044 | if (MHD_WEBSOCKET_STATUS_NO_WEBSOCKET_HANDSHAKE_HEADER != ret) | ||
10045 | { | ||
10046 | fprintf (stderr, | ||
10047 | "check_version_header test failed in line %u.\n", | ||
10048 | (unsigned int) __LINE__); | ||
10049 | ++failed; | ||
10050 | } | ||
10051 | |||
10052 | /* | ||
10053 | ------------------------------------------------------------------------------ | ||
10054 | Missing parameters | ||
10055 | ------------------------------------------------------------------------------ | ||
10056 | */ | ||
10057 | /* Fail test: NULL as version */ | ||
10058 | ret = MHD_websocket_check_version_header (NULL); | ||
10059 | if (MHD_WEBSOCKET_STATUS_NO_WEBSOCKET_HANDSHAKE_HEADER != ret) | ||
10060 | { | ||
10061 | fprintf (stderr, | ||
10062 | "check_version_header test failed in line %u.\n", | ||
10063 | (unsigned int) __LINE__); | ||
10064 | ++failed; | ||
10065 | } | ||
10066 | |||
10067 | return failed != 0 ? 0x1000 : 0x00; | ||
10068 | } | ||
10069 | |||
10070 | |||
8958 | int | 10071 | int |
8959 | main (int argc, char *const *argv) | 10072 | main (int argc, char *const *argv) |
8960 | { | 10073 | { |
@@ -8962,7 +10075,7 @@ main (int argc, char *const *argv) | |||
8962 | (void) argc; (void) argv; /* Unused. Silent compiler warning. */ | 10075 | (void) argc; (void) argv; /* Unused. Silent compiler warning. */ |
8963 | 10076 | ||
8964 | /* seed random number generator */ | 10077 | /* seed random number generator */ |
8965 | MHD_websocket_srand ((unsigned long) time (NULL)); | 10078 | srand ((unsigned long) time (NULL)); |
8966 | 10079 | ||
8967 | /* perform tests */ | 10080 | /* perform tests */ |
8968 | errorCount += test_inits (); | 10081 | errorCount += test_inits (); |
@@ -8974,6 +10087,10 @@ main (int argc, char *const *argv) | |||
8974 | errorCount += test_encodes_ping (); | 10087 | errorCount += test_encodes_ping (); |
8975 | errorCount += test_encodes_pong (); | 10088 | errorCount += test_encodes_pong (); |
8976 | errorCount += test_split_close_reason (); | 10089 | errorCount += test_split_close_reason (); |
10090 | errorCount += test_check_http_version (); | ||
10091 | errorCount += test_check_connection_header (); | ||
10092 | errorCount += test_check_upgrade_header (); | ||
10093 | errorCount += test_check_version_header (); | ||
8977 | 10094 | ||
8978 | /* output result */ | 10095 | /* output result */ |
8979 | if (errorCount != 0) | 10096 | if (errorCount != 0) |
diff --git a/src/microhttpd_ws/test_websocket_browser.c b/src/microhttpd_ws/test_websocket_browser.c new file mode 100644 index 00000000..dfbcd116 --- /dev/null +++ b/src/microhttpd_ws/test_websocket_browser.c | |||
@@ -0,0 +1,563 @@ | |||
1 | /* | ||
2 | This file is part of libmicrohttpd | ||
3 | Copyright (C) 2021 David Gausmann | ||
4 | |||
5 | libmicrohttpd is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published | ||
7 | by the Free Software Foundation; either version 3, or (at your | ||
8 | option) any later version. | ||
9 | |||
10 | libmicrohttpd is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with libmicrohttpd; see the file COPYING. If not, write to the | ||
17 | Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | ||
18 | Boston, MA 02110-1301, USA. | ||
19 | */ | ||
20 | /** | ||
21 | * @file test_websocket_browser.c | ||
22 | * @brief Testcase for WebSocket decoding/encoding with external browser | ||
23 | * @author David Gausmann | ||
24 | */ | ||
25 | #include <sys/types.h> | ||
26 | #ifndef _WIN32 | ||
27 | #include <sys/select.h> | ||
28 | #include <sys/socket.h> | ||
29 | #include <fcntl.h> | ||
30 | #else | ||
31 | #include <winsock2.h> | ||
32 | #endif | ||
33 | #include "microhttpd.h" | ||
34 | #include "microhttpd_ws.h" | ||
35 | #include <stdlib.h> | ||
36 | #include <string.h> | ||
37 | #include <stdio.h> | ||
38 | #include <stdint.h> | ||
39 | #include <time.h> | ||
40 | #include <errno.h> | ||
41 | |||
42 | #define PORT 80 | ||
43 | |||
44 | #define PAGE \ | ||
45 | "<!DOCTYPE html>\n" \ | ||
46 | "<html>\n" \ | ||
47 | "<head>\n" \ | ||
48 | "<meta charset=\"UTF-8\">\n" \ | ||
49 | "<title>Websocket External Test with Webbrowser</title>\n" \ | ||
50 | "<script>\n" \ | ||
51 | "\n" \ | ||
52 | "let current_mode = 0;\n" \ | ||
53 | "let current_step = 0;\n" \ | ||
54 | "let sent_payload = null;\n" \ | ||
55 | "let charset = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_!@%&/\\\\';\n" \ | ||
56 | "let step_to_bytes = [ 0, 1, 2, 3, 122, 123, 124, 125, 126, 127, 128, 32766, 32767, 32768, 65534, 65535, 65536, 65537, 1048576, 10485760 ];\n" \ | ||
57 | "let url = 'ws' + (window.location.protocol === 'https:' ? 's' : '')" \ | ||
58 | " + '://' +\n" \ | ||
59 | " window.location.host + '/websocket';\n" \ | ||
60 | "let socket = null;\n" \ | ||
61 | "\n" \ | ||
62 | "window.onload = function (event) {\n" \ | ||
63 | " if (!window.WebSocket) {\n" \ | ||
64 | " document.write ('ERROR: The WebSocket class is not supported by your browser.<br>');\n" \ | ||
65 | " }\n" \ | ||
66 | " if (!window.fetch) {\n" \ | ||
67 | " document.write ('ERROR: The fetch-API is not supported by your browser.<br>');\n" \ | ||
68 | " }\n" \ | ||
69 | " document.write ('Starting tests.<br>');\n" \ | ||
70 | " runTest ();\n" \ | ||
71 | "}\n" \ | ||
72 | "\n" \ | ||
73 | "function runTest () {\n" \ | ||
74 | " switch (current_mode) {\n" \ | ||
75 | " case 0:\n" \ | ||
76 | " document.write ('TEXT');\n" \ | ||
77 | " break;\n" \ | ||
78 | " case 1:\n" \ | ||
79 | " document.write ('BINARY');\n" \ | ||
80 | " break;\n" \ | ||
81 | " }\n" \ | ||
82 | " document.write (', ' + step_to_bytes[current_step] + ' Bytes: ');\n" \ | ||
83 | " socket = new WebSocket(url);\n" \ | ||
84 | " socket.binaryType = 'arraybuffer';\n" \ | ||
85 | " socket.onopen = function (event) {\n" \ | ||
86 | " switch (current_mode) {\n" \ | ||
87 | " case 0:\n" \ | ||
88 | " sent_payload = randomText (step_to_bytes[current_step]);\n" \ | ||
89 | " socket.send (sent_payload);\n" \ | ||
90 | " break;\n" \ | ||
91 | " case 1:\n" \ | ||
92 | " sent_payload = randomBinary (step_to_bytes[current_step]);\n" \ | ||
93 | " socket.send (sent_payload);\n" \ | ||
94 | " break;\n" \ | ||
95 | " }\n" \ | ||
96 | " }\n" \ | ||
97 | "\n" \ | ||
98 | " socket.onclose = function (event) {\n" \ | ||
99 | " socket.onmessage = null;\n" \ | ||
100 | " socket.onclose = null;\n" \ | ||
101 | " socket.onerror = null;\n" \ | ||
102 | " document.write ('CLOSED unexpectedly.<br>');\n" \ | ||
103 | " notifyError ();\n" \ | ||
104 | " }\n" \ | ||
105 | "\n" \ | ||
106 | " socket.onerror = function (event) {\n" \ | ||
107 | " socket.onmessage = null;\n" \ | ||
108 | " socket.onclose = null;\n" \ | ||
109 | " socket.onerror = null;\n" \ | ||
110 | " document.write ('ERROR.<br>');\n" \ | ||
111 | " notifyError ();\n" \ | ||
112 | " }\n" \ | ||
113 | "\n" \ | ||
114 | " socket.onmessage = async function (event) {\n" \ | ||
115 | " if (compareData (event.data, sent_payload)) {\n" \ | ||
116 | " document.write ('SUCCESS.<br>');\n" \ | ||
117 | " socket.onmessage = null;\n" \ | ||
118 | " socket.onclose = null;\n" \ | ||
119 | " socket.onerror = null;\n" \ | ||
120 | " socket.close();\n" \ | ||
121 | " socket = null;\n" \ | ||
122 | " if (step_to_bytes.length <= ++current_step) {\n" \ | ||
123 | " current_step = 0;\n" \ | ||
124 | " if (1 < ++current_mode) {\n" \ | ||
125 | " document.write ('FINISHED ALL TESTS.<br>');\n" \ | ||
126 | " return;\n" \ | ||
127 | " }\n" \ | ||
128 | " }\n" \ | ||
129 | " runTest ();\n" \ | ||
130 | " }" \ | ||
131 | " }\n" \ | ||
132 | "}\n" \ | ||
133 | "\n" \ | ||
134 | "function compareData (data, data2) {\n" \ | ||
135 | " if (typeof (data) === 'string' && typeof (data2) === 'string') {\n" \ | ||
136 | " return (data === data2); \n" \ | ||
137 | " } \n" \ | ||
138 | " else if ((data instanceof ArrayBuffer) && (data2 instanceof ArrayBuffer)) {\n" \ | ||
139 | " let view1 = new Uint8Array (data);\n" \ | ||
140 | " let view2 = new Uint8Array (data2);\n" \ | ||
141 | " if (view1.length != view2.length)\n" \ | ||
142 | " return false;\n" \ | ||
143 | " for (let i = 0; i < view1.length; ++i) {\n" \ | ||
144 | " if (view1[i] !== view2[i])\n" \ | ||
145 | " return false;\n" \ | ||
146 | " }\n" \ | ||
147 | " return true;\n" \ | ||
148 | " }\n" \ | ||
149 | " else\n" \ | ||
150 | " {\n" \ | ||
151 | " return false;\n" \ | ||
152 | " }\n" \ | ||
153 | "}\n" \ | ||
154 | "\n" \ | ||
155 | "function randomText (length) {\n" \ | ||
156 | " let result = new Array (length);\n" \ | ||
157 | " for (let i = 0; i < length; ++i)\n" \ | ||
158 | " result [i] = charset [~~(Math.random () * charset.length)];\n" \ | ||
159 | " return result.join ('');\n" \ | ||
160 | "}\n" \ | ||
161 | "\n" \ | ||
162 | "function randomBinary (length) {\n" \ | ||
163 | " let buffer = new ArrayBuffer (length);\n" \ | ||
164 | " let view = new Uint8Array (buffer);\n" \ | ||
165 | " for (let i = 0; i < length; ++i)\n" \ | ||
166 | " view [i] = ~~(Math.random () * 256);\n" \ | ||
167 | " return buffer;\n" \ | ||
168 | "}\n" \ | ||
169 | "\n" \ | ||
170 | "function notifyError () {\n" \ | ||
171 | " fetch('error/' + (0 == current_mode ? 'text' : 'binary') + '/' + step_to_bytes[current_step]);\n" \ | ||
172 | "}\n" \ | ||
173 | "\n" \ | ||
174 | "</script>\n" \ | ||
175 | "</head>\n" \ | ||
176 | "<body>\n" \ | ||
177 | "</body>\n" \ | ||
178 | "</html>" | ||
179 | |||
180 | #define PAGE_NOT_FOUND \ | ||
181 | "404 Not Found" | ||
182 | |||
183 | #define PAGE_INVALID_WEBSOCKET_REQUEST \ | ||
184 | "Invalid WebSocket request!" | ||
185 | |||
186 | static void | ||
187 | send_all (MHD_socket fd, | ||
188 | const char *buf, | ||
189 | size_t len); | ||
190 | static void | ||
191 | make_blocking (MHD_socket fd); | ||
192 | |||
193 | static void | ||
194 | upgrade_handler (void *cls, | ||
195 | struct MHD_Connection *connection, | ||
196 | void *con_cls, | ||
197 | const char *extra_in, | ||
198 | size_t extra_in_size, | ||
199 | MHD_socket fd, | ||
200 | struct MHD_UpgradeResponseHandle *urh) | ||
201 | { | ||
202 | /* make the socket blocking (operating-system-dependent code) */ | ||
203 | make_blocking (fd); | ||
204 | |||
205 | /* create a websocket stream for this connection */ | ||
206 | struct MHD_WebSocketStream* ws; | ||
207 | int result = MHD_websocket_stream_init (&ws, | ||
208 | 0, | ||
209 | 0); | ||
210 | if (0 != result) | ||
211 | { | ||
212 | /* Couldn't create the websocket stream. | ||
213 | * So we close the socket and leave | ||
214 | */ | ||
215 | MHD_upgrade_action (urh, | ||
216 | MHD_UPGRADE_ACTION_CLOSE); | ||
217 | return; | ||
218 | } | ||
219 | |||
220 | /* Let's wait for incoming data */ | ||
221 | const size_t buf_len = 256; | ||
222 | char buf[buf_len]; | ||
223 | ssize_t got; | ||
224 | while (MHD_WEBSOCKET_VALIDITY_VALID == MHD_websocket_stream_is_valid (ws)) | ||
225 | { | ||
226 | got = recv (fd, | ||
227 | buf, | ||
228 | sizeof (buf), | ||
229 | 0); | ||
230 | if (0 >= got) | ||
231 | { | ||
232 | /* the TCP/IP socket has been closed */ | ||
233 | fprintf (stderr, | ||
234 | "Error (The socket has been closed unexpectedly)\n"); | ||
235 | break; | ||
236 | } | ||
237 | |||
238 | /* parse the entire received data */ | ||
239 | size_t buf_offset = 0; | ||
240 | while (buf_offset < (size_t) got) | ||
241 | { | ||
242 | size_t new_offset = 0; | ||
243 | char *payload_data = NULL; | ||
244 | size_t payload_len = 0; | ||
245 | char *frame_data = NULL; | ||
246 | size_t frame_len = 0; | ||
247 | int status = MHD_websocket_decode (ws, | ||
248 | buf + buf_offset, | ||
249 | ((size_t) got) - buf_offset, | ||
250 | &new_offset, | ||
251 | &payload_data, | ||
252 | &payload_len); | ||
253 | if (0 > status) | ||
254 | { | ||
255 | /* an error occurred and the connection must be closed */ | ||
256 | printf ("Decoding failed: status=%d, passed=%u\n", status, ((size_t) got) - buf_offset); | ||
257 | if (NULL != payload_data) | ||
258 | { | ||
259 | MHD_websocket_free (ws, payload_data); | ||
260 | } | ||
261 | break; | ||
262 | } | ||
263 | else | ||
264 | { | ||
265 | buf_offset += new_offset; | ||
266 | if (0 < status) | ||
267 | { | ||
268 | /* the frame is complete */ | ||
269 | printf ("Decoding succeeded: type=%d, passed=%u, parsed=%u, payload_len=%d\n", status, ((size_t) got) - buf_offset, new_offset, payload_len); | ||
270 | switch (status) | ||
271 | { | ||
272 | case MHD_WEBSOCKET_STATUS_TEXT_FRAME: | ||
273 | case MHD_WEBSOCKET_STATUS_BINARY_FRAME: | ||
274 | /* The client has sent some data. */ | ||
275 | if (NULL != payload_data || 0 == payload_len) | ||
276 | { | ||
277 | /* Send the received data back to the client */ | ||
278 | if (MHD_WEBSOCKET_STATUS_TEXT_FRAME == status) | ||
279 | { | ||
280 | result = MHD_websocket_encode_text (ws, | ||
281 | payload_data, | ||
282 | payload_len, | ||
283 | 0, | ||
284 | &frame_data, | ||
285 | &frame_len, | ||
286 | NULL); | ||
287 | } | ||
288 | else | ||
289 | { | ||
290 | result = MHD_websocket_encode_binary (ws, | ||
291 | payload_data, | ||
292 | payload_len, | ||
293 | 0, | ||
294 | &frame_data, | ||
295 | &frame_len); | ||
296 | } | ||
297 | if (0 == result) | ||
298 | { | ||
299 | send_all (fd, | ||
300 | frame_data, | ||
301 | frame_len); | ||
302 | } | ||
303 | } | ||
304 | else | ||
305 | { | ||
306 | /* should never happen */ | ||
307 | fprintf (stderr, | ||
308 | "Error (Empty buffer with payload_len != 0)\n"); | ||
309 | } | ||
310 | break; | ||
311 | |||
312 | default: | ||
313 | /* Other frame types are ignored | ||
314 | * in this test script. | ||
315 | */ | ||
316 | break; | ||
317 | } | ||
318 | } | ||
319 | if (NULL != payload_data) | ||
320 | { | ||
321 | MHD_websocket_free (ws, payload_data); | ||
322 | } | ||
323 | if (NULL != frame_data) | ||
324 | { | ||
325 | MHD_websocket_free (ws, frame_data); | ||
326 | } | ||
327 | } | ||
328 | } | ||
329 | } | ||
330 | |||
331 | /* free the websocket stream */ | ||
332 | MHD_websocket_stream_free (ws); | ||
333 | |||
334 | /* close the socket when it is not needed anymore */ | ||
335 | MHD_upgrade_action (urh, | ||
336 | MHD_UPGRADE_ACTION_CLOSE); | ||
337 | } | ||
338 | |||
339 | /* This helper function is used for the case that | ||
340 | * we need to resend some data | ||
341 | */ | ||
342 | static void | ||
343 | send_all (MHD_socket fd, | ||
344 | const char *buf, | ||
345 | size_t len) | ||
346 | { | ||
347 | ssize_t ret; | ||
348 | size_t off; | ||
349 | |||
350 | for (off = 0; off < len; off += ret) | ||
351 | { | ||
352 | ret = send (fd, | ||
353 | &buf[off], | ||
354 | (int) (len - off), | ||
355 | 0); | ||
356 | if (0 > ret) | ||
357 | { | ||
358 | if (EAGAIN == errno) | ||
359 | { | ||
360 | ret = 0; | ||
361 | continue; | ||
362 | } | ||
363 | break; | ||
364 | } | ||
365 | if (0 == ret) | ||
366 | break; | ||
367 | } | ||
368 | } | ||
369 | |||
370 | /* This helper function contains operating-system-dependent code and | ||
371 | * is used to make a socket blocking. | ||
372 | */ | ||
373 | static void | ||
374 | make_blocking (MHD_socket fd) | ||
375 | { | ||
376 | #ifndef _WIN32 | ||
377 | int flags; | ||
378 | |||
379 | flags = fcntl (fd, F_GETFL); | ||
380 | if (-1 == flags) | ||
381 | return; | ||
382 | if ((flags & ~O_NONBLOCK) != flags) | ||
383 | if (-1 == fcntl (fd, F_SETFL, flags & ~O_NONBLOCK)) | ||
384 | abort (); | ||
385 | #else | ||
386 | unsigned long flags = 0; | ||
387 | |||
388 | ioctlsocket (fd, FIONBIO, &flags); | ||
389 | #endif | ||
390 | } | ||
391 | |||
392 | static enum MHD_Result | ||
393 | access_handler (void *cls, | ||
394 | struct MHD_Connection *connection, | ||
395 | const char *url, | ||
396 | const char *method, | ||
397 | const char *version, | ||
398 | const char *upload_data, | ||
399 | size_t *upload_data_size, | ||
400 | void **ptr) | ||
401 | { | ||
402 | static int aptr; | ||
403 | struct MHD_Response *response; | ||
404 | int ret; | ||
405 | |||
406 | (void) cls; /* Unused. Silent compiler warning. */ | ||
407 | (void) upload_data; /* Unused. Silent compiler warning. */ | ||
408 | (void) upload_data_size; /* Unused. Silent compiler warning. */ | ||
409 | |||
410 | if (0 != strcmp (method, "GET")) | ||
411 | return MHD_NO; /* unexpected method */ | ||
412 | if (&aptr != *ptr) | ||
413 | { | ||
414 | /* do never respond on first call */ | ||
415 | *ptr = &aptr; | ||
416 | return MHD_YES; | ||
417 | } | ||
418 | *ptr = NULL; /* reset when done */ | ||
419 | |||
420 | if (0 == strcmp (url, "/")) | ||
421 | { | ||
422 | /* Default page for visiting the server */ | ||
423 | struct MHD_Response *response = MHD_create_response_from_buffer ( | ||
424 | strlen (PAGE), | ||
425 | PAGE, | ||
426 | MHD_RESPMEM_PERSISTENT); | ||
427 | ret = MHD_queue_response (connection, | ||
428 | MHD_HTTP_OK, | ||
429 | response); | ||
430 | MHD_destroy_response (response); | ||
431 | } | ||
432 | else if (0 == strncmp (url, "/error/", 7)) | ||
433 | { | ||
434 | /* Report error */ | ||
435 | fprintf (stderr, "Error in test (%s)\n", url + 7); | ||
436 | |||
437 | struct MHD_Response *response = MHD_create_response_from_buffer ( | ||
438 | 0, | ||
439 | "", | ||
440 | MHD_RESPMEM_PERSISTENT); | ||
441 | ret = MHD_queue_response (connection, | ||
442 | MHD_HTTP_OK, | ||
443 | response); | ||
444 | MHD_destroy_response (response); | ||
445 | } | ||
446 | else if (0 == strcmp (url, "/websocket")) | ||
447 | { | ||
448 | char is_valid = 1; | ||
449 | const char* value = NULL; | ||
450 | char sec_websocket_accept[29]; | ||
451 | |||
452 | if (0 != MHD_websocket_check_http_version (version)) | ||
453 | { | ||
454 | is_valid = 0; | ||
455 | } | ||
456 | value = MHD_lookup_connection_value (connection, | ||
457 | MHD_HEADER_KIND, | ||
458 | MHD_HTTP_HEADER_CONNECTION); | ||
459 | if (0 != MHD_websocket_check_connection_header (value)) | ||
460 | { | ||
461 | is_valid = 0; | ||
462 | } | ||
463 | value = MHD_lookup_connection_value (connection, | ||
464 | MHD_HEADER_KIND, | ||
465 | MHD_HTTP_HEADER_UPGRADE); | ||
466 | if (0 != MHD_websocket_check_upgrade_header (value)) | ||
467 | { | ||
468 | is_valid = 0; | ||
469 | } | ||
470 | value = MHD_lookup_connection_value (connection, | ||
471 | MHD_HEADER_KIND, | ||
472 | MHD_HTTP_HEADER_SEC_WEBSOCKET_VERSION); | ||
473 | if (0 != MHD_websocket_check_version_header (value)) | ||
474 | { | ||
475 | is_valid = 0; | ||
476 | } | ||
477 | value = MHD_lookup_connection_value (connection, | ||
478 | MHD_HEADER_KIND, | ||
479 | MHD_HTTP_HEADER_SEC_WEBSOCKET_KEY); | ||
480 | if (0 != MHD_websocket_create_accept_header (value, sec_websocket_accept)) | ||
481 | { | ||
482 | is_valid = 0; | ||
483 | } | ||
484 | |||
485 | if (1 == is_valid) | ||
486 | { | ||
487 | /* upgrade the connection */ | ||
488 | response = MHD_create_response_for_upgrade (&upgrade_handler, | ||
489 | NULL); | ||
490 | MHD_add_response_header (response, | ||
491 | MHD_HTTP_HEADER_CONNECTION, | ||
492 | "Upgrade"); | ||
493 | MHD_add_response_header (response, | ||
494 | MHD_HTTP_HEADER_UPGRADE, | ||
495 | "websocket"); | ||
496 | MHD_add_response_header (response, | ||
497 | MHD_HTTP_HEADER_SEC_WEBSOCKET_ACCEPT, | ||
498 | sec_websocket_accept); | ||
499 | ret = MHD_queue_response (connection, | ||
500 | MHD_HTTP_SWITCHING_PROTOCOLS, | ||
501 | response); | ||
502 | MHD_destroy_response (response); | ||
503 | } | ||
504 | else | ||
505 | { | ||
506 | /* return error page */ | ||
507 | struct MHD_Response*response = MHD_create_response_from_buffer ( | ||
508 | strlen (PAGE_INVALID_WEBSOCKET_REQUEST), | ||
509 | PAGE_INVALID_WEBSOCKET_REQUEST, | ||
510 | MHD_RESPMEM_PERSISTENT); | ||
511 | ret = MHD_queue_response (connection, | ||
512 | MHD_HTTP_BAD_REQUEST, | ||
513 | response); | ||
514 | MHD_destroy_response (response); | ||
515 | } | ||
516 | } | ||
517 | else | ||
518 | { | ||
519 | struct MHD_Response*response = MHD_create_response_from_buffer ( | ||
520 | strlen (PAGE_NOT_FOUND), | ||
521 | PAGE_NOT_FOUND, | ||
522 | MHD_RESPMEM_PERSISTENT); | ||
523 | ret = MHD_queue_response (connection, | ||
524 | MHD_HTTP_NOT_FOUND, | ||
525 | response); | ||
526 | MHD_destroy_response (response); | ||
527 | } | ||
528 | |||
529 | return ret; | ||
530 | } | ||
531 | |||
532 | int | ||
533 | main (int argc, | ||
534 | char *const *argv) | ||
535 | { | ||
536 | (void) argc; /* Unused. Silent compiler warning. */ | ||
537 | (void) argv; /* Unused. Silent compiler warning. */ | ||
538 | struct MHD_Daemon *daemon; | ||
539 | |||
540 | daemon = MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD | | ||
541 | MHD_USE_THREAD_PER_CONNECTION | | ||
542 | MHD_ALLOW_UPGRADE | | ||
543 | MHD_USE_ERROR_LOG, | ||
544 | PORT, NULL, NULL, | ||
545 | &access_handler, NULL, | ||
546 | MHD_OPTION_END); | ||
547 | |||
548 | if (NULL == daemon) | ||
549 | { | ||
550 | fprintf (stderr, "Error (Couldn't start daemon for testing)\n"); | ||
551 | return 1; | ||
552 | } | ||
553 | printf("The server is listening now.\n"); | ||
554 | printf("Access the server now with a websocket-capable webbrowser.\n\n"); | ||
555 | printf("Press return to close.\n"); | ||
556 | |||
557 | (void) getc (stdin); | ||
558 | |||
559 | MHD_stop_daemon (daemon); | ||
560 | |||
561 | return 0; | ||
562 | } | ||
563 | |||