diff options
author | Christian Grothoff <christian@grothoff.org> | 2019-12-25 22:58:20 +0100 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2019-12-25 22:58:20 +0100 |
commit | 55f715e15e3ce66babc939b5a670bee02d4d9571 (patch) | |
tree | 7e89f42f747fc96dd30876ea91be844d87b299f9 | |
parent | 0f4460e545f19ec74bf53438b246d64f0127884e (diff) | |
download | libmicrohttpd-55f715e15e3ce66babc939b5a670bee02d4d9571.tar.gz libmicrohttpd-55f715e15e3ce66babc939b5a670bee02d4d9571.zip |
first experimental rewrite of URL postprocessor, still fails, not production ready
-rw-r--r-- | src/microhttpd/postprocessor.c | 394 |
1 files changed, 257 insertions, 137 deletions
diff --git a/src/microhttpd/postprocessor.c b/src/microhttpd/postprocessor.c index a7548ae3..e515b363 100644 --- a/src/microhttpd/postprocessor.c +++ b/src/microhttpd/postprocessor.c | |||
@@ -47,6 +47,7 @@ enum PP_State | |||
47 | 47 | ||
48 | /* url encoding-states */ | 48 | /* url encoding-states */ |
49 | PP_ProcessValue, | 49 | PP_ProcessValue, |
50 | PP_Callback, | ||
50 | PP_ExpectNewLine, | 51 | PP_ExpectNewLine, |
51 | 52 | ||
52 | /* post encoding-states */ | 53 | /* post encoding-states */ |
@@ -172,11 +173,10 @@ struct MHD_PostProcessor | |||
172 | char *content_transfer_encoding; | 173 | char *content_transfer_encoding; |
173 | 174 | ||
174 | /** | 175 | /** |
175 | * Unprocessed value bytes due to escape | 176 | * Value data left over from previous iteration. |
176 | * sequences (URL-encoding only). | ||
177 | */ | 177 | */ |
178 | char xbuf[8]; | 178 | char xbuf[2]; |
179 | 179 | ||
180 | /** | 180 | /** |
181 | * Size of our buffer for the key. | 181 | * Size of our buffer for the key. |
182 | */ | 182 | */ |
@@ -348,6 +348,103 @@ MHD_create_post_processor (struct MHD_Connection *connection, | |||
348 | 348 | ||
349 | 349 | ||
350 | /** | 350 | /** |
351 | * Give a (possibly partial) value to the | ||
352 | * application callback. We have some | ||
353 | * part of the value in the 'pp->xbuf', the | ||
354 | * rest is between @a value_start and @a value_end. | ||
355 | * If @a last_escape is non-NULL, there may be | ||
356 | * an incomplete escape sequence at at @a value_escape | ||
357 | * between @a value_start and @a value_end which | ||
358 | * we should preserve in 'pp->xbuf' for the future. | ||
359 | * | ||
360 | * Unescapes the value and calls the iterator | ||
361 | * together with the key. The key must already | ||
362 | * be in the key buffer allocated and 0-terminated | ||
363 | * at the end of @a pp at the time of the call. | ||
364 | * | ||
365 | * @param pp post processor to act upon | ||
366 | * @param value_start where in memory is the value | ||
367 | * @param value_end where does the value end | ||
368 | * @param last_escape last '%'-sign in value range, | ||
369 | * if relevant, or NULL | ||
370 | */ | ||
371 | static void | ||
372 | process_value (struct MHD_PostProcessor *pp, | ||
373 | const char *value_start, | ||
374 | const char *value_end, | ||
375 | const char *last_escape) | ||
376 | { | ||
377 | char xbuf[XBUF_SIZE + 1]; | ||
378 | size_t xoff; | ||
379 | |||
380 | mhd_assert (pp->xbuf_pos < sizeof (xbuf)); | ||
381 | memcpy (xbuf, | ||
382 | pp->xbuf, | ||
383 | pp->xbuf_pos); | ||
384 | xoff = pp->xbuf_pos; | ||
385 | pp->xbuf_pos = 0; | ||
386 | if (NULL != last_escape) | ||
387 | { | ||
388 | if (value_end - last_escape < sizeof (pp->xbuf)) | ||
389 | { | ||
390 | pp->xbuf_pos = value_end - last_escape; | ||
391 | memcpy (pp->xbuf, | ||
392 | last_escape, | ||
393 | value_end - last_escape); | ||
394 | value_end = last_escape; | ||
395 | } | ||
396 | } | ||
397 | while ( (value_start != value_end) || | ||
398 | (xoff > 0) ) | ||
399 | { | ||
400 | size_t delta = value_end - value_start; | ||
401 | |||
402 | if (delta > XBUF_SIZE - xoff) | ||
403 | delta = XBUF_SIZE - xoff; | ||
404 | /* move input into processing buffer */ | ||
405 | memcpy (&xbuf[xoff], | ||
406 | value_start, | ||
407 | delta); | ||
408 | /* find if escape sequence is at the end of the processing buffer; | ||
409 | if so, exclude those from processing (reduce delta to point at | ||
410 | end of processed region) */ | ||
411 | if (delta >= XBUF_SIZE - 2) | ||
412 | { | ||
413 | if ((xoff + delta > 0) && | ||
414 | ('%' == xbuf[xoff + delta - 1])) | ||
415 | delta--; | ||
416 | else if ((xoff + delta > 1) && | ||
417 | ('%' == xbuf[xoff + delta - 2])) | ||
418 | delta -= 2; | ||
419 | } | ||
420 | xoff += delta; | ||
421 | value_start += delta; | ||
422 | mhd_assert (xoff < sizeof (xbuf)); | ||
423 | /* unescape */ | ||
424 | xbuf[xoff] = '\0'; /* 0-terminate in preparation */ | ||
425 | MHD_unescape_plus (xbuf); | ||
426 | xoff = MHD_http_unescape (xbuf); | ||
427 | /* finally: call application! */ | ||
428 | if (MHD_NO == pp->ikvi (pp->cls, | ||
429 | MHD_POSTDATA_KIND, | ||
430 | (const char *) &pp[1], /* key */ | ||
431 | NULL, | ||
432 | NULL, | ||
433 | NULL, | ||
434 | xbuf, | ||
435 | pp->value_offset, | ||
436 | xoff)) | ||
437 | { | ||
438 | pp->state = PP_Error; | ||
439 | return; | ||
440 | } | ||
441 | pp->value_offset += xoff; | ||
442 | xoff = 0; | ||
443 | } | ||
444 | } | ||
445 | |||
446 | |||
447 | /** | ||
351 | * Process url-encoded POST data. | 448 | * Process url-encoded POST data. |
352 | * | 449 | * |
353 | * @param pp post processor context | 450 | * @param pp post processor context |
@@ -360,154 +457,142 @@ post_process_urlencoded (struct MHD_PostProcessor *pp, | |||
360 | const char *post_data, | 457 | const char *post_data, |
361 | size_t post_data_len) | 458 | size_t post_data_len) |
362 | { | 459 | { |
363 | size_t equals; | 460 | char *kbuf = (char *) &pp[1]; |
364 | size_t amper; | ||
365 | size_t poff; | 461 | size_t poff; |
366 | size_t xoff; | 462 | const char *start_key = NULL; |
367 | size_t delta; | 463 | const char *end_key = NULL; |
368 | int end_of_value_found; | 464 | const char *start_value = NULL; |
369 | char *buf; | 465 | const char *end_value = NULL; |
370 | char xbuf[XBUF_SIZE + 1]; | 466 | const char *last_escape = NULL; |
371 | 467 | ||
372 | buf = (char *) &pp[1]; | ||
373 | poff = 0; | 468 | poff = 0; |
374 | while (poff < post_data_len) | 469 | while ( (poff < post_data_len) && |
470 | (pp->state != PP_Error) ) | ||
375 | { | 471 | { |
376 | switch (pp->state) | 472 | switch (pp->state) { |
377 | { | ||
378 | case PP_Error: | 473 | case PP_Error: |
379 | return MHD_NO; | 474 | /* clearly impossible as per while loop invariant */ |
380 | case PP_Done: | 475 | abort (); |
381 | /* did not expect to receive more data */ | 476 | break; |
382 | pp->state = PP_Error; | ||
383 | return MHD_NO; | ||
384 | case PP_Init: | 477 | case PP_Init: |
385 | equals = 0; | 478 | /* key phase */ |
386 | while ((equals + poff < post_data_len) && | 479 | if (NULL == start_key) |
387 | (post_data[equals + poff] != '=')) | 480 | start_key = &post_data[poff]; |
388 | equals++; | 481 | switch (post_data[poff]) |
389 | if (equals + pp->buffer_pos > pp->buffer_size) | ||
390 | { | 482 | { |
391 | pp->state = PP_Error; /* out of memory */ | 483 | case '=': |
392 | return MHD_NO; | 484 | /* Case: 'key=' */ |
485 | end_key = &post_data[poff]; | ||
486 | poff++; | ||
487 | pp->state = PP_ProcessValue; | ||
488 | break; | ||
489 | case '&': | ||
490 | /* Case: 'key&' */ | ||
491 | end_key = &post_data[poff]; | ||
492 | mhd_assert (NULL == start_value); | ||
493 | mhd_assert (NULL == end_value); | ||
494 | poff++; | ||
495 | pp->state = PP_Callback; | ||
496 | break; | ||
497 | case '\n': | ||
498 | case '\r': | ||
499 | /* Case: 'key\n' or 'key\r' */ | ||
500 | end_key = &post_data[poff]; | ||
501 | poff++; | ||
502 | pp->state = PP_Done; | ||
503 | break; | ||
504 | default: | ||
505 | /* normal character, advance! */ | ||
506 | poff++; | ||
507 | continue; | ||
393 | } | 508 | } |
394 | memcpy (&buf[pp->buffer_pos], &post_data[poff], equals); | 509 | break; /* end PP_Init */ |
395 | pp->buffer_pos += equals; | ||
396 | if (equals + poff == post_data_len) | ||
397 | return MHD_YES; /* no '=' yet */ | ||
398 | buf[pp->buffer_pos] = '\0'; /* 0-terminate key */ | ||
399 | pp->buffer_pos = 0; /* reset for next key */ | ||
400 | MHD_unescape_plus (buf); | ||
401 | MHD_http_unescape (buf); | ||
402 | poff += equals + 1; | ||
403 | pp->state = PP_ProcessValue; | ||
404 | pp->value_offset = 0; | ||
405 | break; | ||
406 | case PP_ProcessValue: | 510 | case PP_ProcessValue: |
407 | /* obtain rest of value from previous iteration */ | 511 | if (NULL == start_value) |
408 | memcpy (xbuf, pp->xbuf, pp->xbuf_pos); | 512 | start_value = &post_data[poff]; |
409 | xoff = pp->xbuf_pos; | 513 | switch (post_data[poff]) { |
410 | pp->xbuf_pos = 0; | 514 | case '=': |
411 | 515 | /* case 'key==' */ | |
412 | /* find last position in input buffer that is part of the value */ | 516 | pp->state = PP_Error; |
413 | amper = 0; | 517 | continue; |
414 | while ((amper + poff < post_data_len) && | 518 | case '&': |
415 | (amper < XBUF_SIZE) && | 519 | /* case 'value&' */ |
416 | (post_data[amper + poff] != '&') && | 520 | end_value = &post_data[poff]; |
417 | (post_data[amper + poff] != '\n') && | 521 | poff++; |
418 | (post_data[amper + poff] != '\r')) | 522 | pp->state = PP_Callback; |
419 | amper++; | 523 | case '\n': |
420 | end_of_value_found = ((amper + poff < post_data_len) && | 524 | case '\r': |
421 | ((post_data[amper + poff] == '&') || | 525 | /* Case: 'value\n' or 'value\r' */ |
422 | (post_data[amper + poff] == '\n') || | 526 | end_value = &post_data[poff]; |
423 | (post_data[amper + poff] == '\r'))); | 527 | poff++; |
424 | /* compute delta, the maximum number of bytes that we will be able to | 528 | pp->state = PP_Done; |
425 | process right now (either amper-limited of xbuf-size limited) */ | 529 | break; |
426 | delta = amper; | 530 | case '%': |
427 | if (delta > XBUF_SIZE - xoff) | 531 | last_escape = &post_data[poff]; |
428 | delta = XBUF_SIZE - xoff; | 532 | poff++; |
429 | 533 | break; | |
430 | /* move input into processing buffer */ | 534 | case '0': |
431 | memcpy (&xbuf[xoff], &post_data[poff], delta); | 535 | case '1': |
432 | xoff += delta; | 536 | case '2': |
433 | poff += delta; | 537 | case '3': |
434 | 538 | case '4': | |
435 | /* find if escape sequence is at the end of the processing buffer; | 539 | case '5': |
436 | if so, exclude those from processing (reduce delta to point at | 540 | case '6': |
437 | end of processed region) */ | 541 | case '7': |
438 | delta = xoff; | 542 | case '8': |
439 | if ((delta > 0) && | 543 | case '9': |
440 | ('%' == xbuf[delta - 1])) | 544 | /* character, may be part of escaping */ |
441 | delta--; | 545 | poff++; |
442 | else if ((delta > 1) && | 546 | continue; |
443 | ('%' == xbuf[delta - 2])) | 547 | default: |
444 | delta -= 2; | 548 | /* normal character, no more escaping! */ |
445 | 549 | last_escape = NULL; | |
446 | /* if we have an incomplete escape sequence, save it to | 550 | poff++; |
447 | pp->xbuf for later */ | 551 | continue; |
448 | if (delta < xoff) | ||
449 | { | ||
450 | memcpy (pp->xbuf, | ||
451 | &xbuf[delta], | ||
452 | xoff - delta); | ||
453 | pp->xbuf_pos = xoff - delta; | ||
454 | xoff = delta; | ||
455 | } | 552 | } |
456 | 553 | break; /* end PP_ProcessValue */ | |
457 | /* If we have nothing to do (delta == 0) and | 554 | case PP_Done: |
458 | not just because the value is empty (are | 555 | switch (post_data[poff]) { |
459 | waiting for more data), go for next iteration */ | 556 | case '\n': |
460 | if ( (0 == xoff) && | 557 | case '\r': |
461 | (poff == post_data_len)) | 558 | poff++; |
462 | continue; | 559 | continue; |
463 | 560 | } | |
464 | /* unescape */ | 561 | /* unexpected data at the end, fail! */ |
465 | xbuf[xoff] = '\0'; /* 0-terminate in preparation */ | 562 | pp->state = PP_Error; |
466 | MHD_unescape_plus (xbuf); | 563 | break; |
467 | xoff = MHD_http_unescape (xbuf); | 564 | case PP_Callback: |
468 | /* finally: call application! */ | 565 | if ( (pp->buffer_pos + (end_key - start_key) > |
469 | pp->must_ikvi = MHD_NO; | 566 | pp->buffer_size) || |
470 | if (MHD_NO == pp->ikvi (pp->cls, | 567 | (pp->buffer_pos + (end_key - start_key) > |
471 | MHD_POSTDATA_KIND, | 568 | pp->buffer_pos) ) |
472 | (const char *) &pp[1], /* key */ | ||
473 | NULL, | ||
474 | NULL, | ||
475 | NULL, | ||
476 | xbuf, | ||
477 | pp->value_offset, | ||
478 | xoff)) | ||
479 | { | 569 | { |
570 | /* key too long, cannot parse! */ | ||
480 | pp->state = PP_Error; | 571 | pp->state = PP_Error; |
481 | return MHD_NO; | 572 | continue; |
482 | } | 573 | } |
483 | pp->value_offset += xoff; | 574 | /* compute key, if we have not already */ |
484 | 575 | if (NULL != start_key) | |
485 | /* are we done with the value? */ | ||
486 | if (end_of_value_found) | ||
487 | { | 576 | { |
488 | /* we found the end of the value! */ | 577 | memcpy (&kbuf[pp->buffer_pos], |
489 | if ( ('\n' == post_data[poff]) || | 578 | start_key, |
490 | ('\r' == post_data[poff]) ) | 579 | end_key - start_key); |
491 | { | 580 | pp->buffer_pos += end_key - start_key; |
492 | pp->state = PP_ExpectNewLine; | 581 | start_key = NULL; |
493 | } | 582 | end_key = NULL; |
494 | else if ('&' == post_data[poff]) | 583 | kbuf[pp->buffer_pos] = '\0'; /* 0-terminate key */ |
495 | { | 584 | MHD_unescape_plus (kbuf); |
496 | poff++; /* skip '&' */ | 585 | MHD_http_unescape (kbuf); |
497 | pp->state = PP_Init; | ||
498 | } | ||
499 | } | 586 | } |
587 | process_value (pp, | ||
588 | start_value, | ||
589 | end_value, | ||
590 | NULL); | ||
591 | pp->value_offset = 0; | ||
592 | start_value = NULL; | ||
593 | end_value = NULL; | ||
594 | pp->state = PP_Init; | ||
500 | break; | 595 | break; |
501 | case PP_ExpectNewLine: | ||
502 | if ( ('\n' == post_data[poff]) || | ||
503 | ('\r' == post_data[poff]) ) | ||
504 | { | ||
505 | poff++; | ||
506 | /* we are done, report error if we receive any more... */ | ||
507 | pp->state = PP_Done; | ||
508 | return MHD_YES; | ||
509 | } | ||
510 | return MHD_NO; | ||
511 | default: | 596 | default: |
512 | mhd_panic (mhd_panic_cls, | 597 | mhd_panic (mhd_panic_cls, |
513 | __FILE__, | 598 | __FILE__, |
@@ -515,6 +600,42 @@ post_process_urlencoded (struct MHD_PostProcessor *pp, | |||
515 | NULL); /* should never happen! */ | 600 | NULL); /* should never happen! */ |
516 | } | 601 | } |
517 | } | 602 | } |
603 | |||
604 | /* save remaining data for next iteration */ | ||
605 | if ( (NULL != start_key) && | ||
606 | (PP_Init == pp->state) ) | ||
607 | { | ||
608 | if (NULL == end_key) | ||
609 | end_key = &post_data[poff]; | ||
610 | memcpy (&kbuf[pp->buffer_pos], | ||
611 | start_key, | ||
612 | end_key - start_key); | ||
613 | pp->buffer_pos += end_key - start_key; | ||
614 | } | ||
615 | if ( (NULL != start_value) && | ||
616 | (PP_ProcessValue == pp->state) ) | ||
617 | { | ||
618 | /* compute key, if we have not already */ | ||
619 | if (NULL != start_key) | ||
620 | { | ||
621 | memcpy (&kbuf[pp->buffer_pos], | ||
622 | start_key, | ||
623 | end_key - start_key); | ||
624 | pp->buffer_pos += end_key - start_key; | ||
625 | start_key = NULL; | ||
626 | end_key = NULL; | ||
627 | kbuf[pp->buffer_pos] = '\0'; /* 0-terminate key */ | ||
628 | MHD_unescape_plus (kbuf); | ||
629 | MHD_http_unescape (kbuf); | ||
630 | } | ||
631 | if (NULL == end_value) | ||
632 | end_value = &post_data[poff]; | ||
633 | process_value (pp, | ||
634 | start_value, | ||
635 | end_value, | ||
636 | last_escape); | ||
637 | } | ||
638 | |||
518 | return MHD_YES; | 639 | return MHD_YES; |
519 | } | 640 | } |
520 | 641 | ||
@@ -1276,8 +1397,7 @@ MHD_destroy_post_processor (struct MHD_PostProcessor *pp) | |||
1276 | the post-processing may have been interrupted | 1397 | the post-processing may have been interrupted |
1277 | at any stage */ | 1398 | at any stage */ |
1278 | if ( (pp->xbuf_pos > 0) || | 1399 | if ( (pp->xbuf_pos > 0) || |
1279 | ( (pp->state != PP_Done) && | 1400 | (pp->state != PP_Done) ) |
1280 | (pp->state != PP_ExpectNewLine) ) ) | ||
1281 | ret = MHD_NO; | 1401 | ret = MHD_NO; |
1282 | else | 1402 | else |
1283 | ret = MHD_YES; | 1403 | ret = MHD_YES; |