aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2019-12-25 22:58:20 +0100
committerChristian Grothoff <christian@grothoff.org>2019-12-25 22:58:20 +0100
commit55f715e15e3ce66babc939b5a670bee02d4d9571 (patch)
tree7e89f42f747fc96dd30876ea91be844d87b299f9
parent0f4460e545f19ec74bf53438b246d64f0127884e (diff)
downloadlibmicrohttpd-55f715e15e3ce66babc939b5a670bee02d4d9571.tar.gz
libmicrohttpd-55f715e15e3ce66babc939b5a670bee02d4d9571.zip
first experimental rewrite of URL postprocessor, still fails, not production ready
-rw-r--r--src/microhttpd/postprocessor.c394
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 */
371static void
372process_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;