gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[libmicrohttpd] branch master updated (f5d59eb3 -> 55f715e1)


From: gnunet
Subject: [libmicrohttpd] branch master updated (f5d59eb3 -> 55f715e1)
Date: Wed, 25 Dec 2019 23:01:32 +0100

This is an automated email from the git hooks/post-receive script.

grothoff pushed a change to branch master
in repository libmicrohttpd.

    from f5d59eb3 Given post body "a&b=1", how should MHD interpret the data?
     new 0f4460e5 more logging in testcase
     new 55f715e1 first experimental rewrite of URL postprocessor, still fails, 
not production ready

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 src/microhttpd/postprocessor.c      | 394 +++++++++++++++++++++++-------------
 src/microhttpd/test_postprocessor.c |  70 ++++++-
 2 files changed, 320 insertions(+), 144 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
 
   /* url encoding-states */
   PP_ProcessValue,
+  PP_Callback,
   PP_ExpectNewLine,
 
   /* post encoding-states  */
@@ -172,11 +173,10 @@ struct MHD_PostProcessor
   char *content_transfer_encoding;
 
   /**
-   * Unprocessed value bytes due to escape
-   * sequences (URL-encoding only).
+   * Value data left over from previous iteration.
    */
-  char xbuf[8];
-
+  char xbuf[2];
+  
   /**
    * Size of our buffer for the key.
    */
@@ -347,6 +347,103 @@ MHD_create_post_processor (struct MHD_Connection 
*connection,
 }
 
 
+/**
+ * Give a (possibly partial) value to the
+ * application callback.  We have some
+ * part of the value in the 'pp->xbuf', the
+ * rest is between @a value_start and @a value_end.
+ * If @a last_escape is non-NULL, there may be
+ * an incomplete escape sequence at at @a value_escape
+ * between @a value_start and @a value_end which
+ * we should preserve in 'pp->xbuf' for the future.
+ *
+ * Unescapes the value and calls the iterator
+ * together with the key.  The key must already
+ * be in the key buffer allocated and 0-terminated
+ * at the end of @a pp at the time of the call.
+ *
+ * @param pp post processor to act upon
+ * @param value_start where in memory is the value
+ * @param value_end where does the value end
+ * @param last_escape last '%'-sign in value range,
+ *        if relevant, or NULL
+ */
+static void
+process_value (struct MHD_PostProcessor *pp,
+               const char *value_start,
+               const char *value_end,
+               const char *last_escape)
+{
+  char xbuf[XBUF_SIZE + 1];
+  size_t xoff;
+
+  mhd_assert (pp->xbuf_pos < sizeof (xbuf));
+  memcpy (xbuf,
+          pp->xbuf,
+          pp->xbuf_pos);
+  xoff = pp->xbuf_pos;
+  pp->xbuf_pos = 0;
+  if (NULL != last_escape)
+  {
+    if (value_end - last_escape < sizeof (pp->xbuf))
+    {
+      pp->xbuf_pos = value_end - last_escape;
+      memcpy (pp->xbuf,
+              last_escape,
+              value_end - last_escape);
+      value_end = last_escape;
+    }
+  }
+  while ( (value_start != value_end) ||
+          (xoff > 0) )
+  {
+    size_t delta = value_end - value_start;
+
+    if (delta > XBUF_SIZE - xoff)
+      delta = XBUF_SIZE - xoff;
+    /* move input into processing buffer */
+    memcpy (&xbuf[xoff],
+            value_start,
+            delta);
+    /* find if escape sequence is at the end of the processing buffer;
+       if so, exclude those from processing (reduce delta to point at
+       end of processed region) */
+    if (delta >= XBUF_SIZE - 2)
+    {
+      if ((xoff + delta > 0) &&
+          ('%' == xbuf[xoff + delta - 1]))
+        delta--;
+      else if ((xoff + delta > 1) &&
+               ('%' == xbuf[xoff + delta - 2]))
+        delta -= 2;
+    }
+    xoff += delta;
+    value_start += delta;
+    mhd_assert (xoff < sizeof (xbuf));
+    /* unescape */
+    xbuf[xoff] = '\0';        /* 0-terminate in preparation */
+    MHD_unescape_plus (xbuf);
+    xoff = MHD_http_unescape (xbuf);
+    /* finally: call application! */
+    if (MHD_NO == pp->ikvi (pp->cls,
+                            MHD_POSTDATA_KIND,
+                            (const char *) &pp[1],        /* key */
+                            NULL,
+                            NULL,
+                            NULL,
+                            xbuf,
+                            pp->value_offset,
+                            xoff))
+    {
+      pp->state = PP_Error;
+      return;
+    }
+    pp->value_offset += xoff;
+    xoff = 0;
+  }
+}
+
+
 /**
  * Process url-encoded POST data.
  *
@@ -360,154 +457,142 @@ post_process_urlencoded (struct MHD_PostProcessor *pp,
                          const char *post_data,
                          size_t post_data_len)
 {
-  size_t equals;
-  size_t amper;
+  char *kbuf = (char *) &pp[1];
   size_t poff;
-  size_t xoff;
-  size_t delta;
-  int end_of_value_found;
-  char *buf;
-  char xbuf[XBUF_SIZE + 1];
+  const char *start_key = NULL;
+  const char *end_key = NULL;
+  const char *start_value = NULL;
+  const char *end_value = NULL;
+  const char *last_escape = NULL;
 
-  buf = (char *) &pp[1];
   poff = 0;
-  while (poff < post_data_len)
+  while ( (poff < post_data_len) &&
+          (pp->state != PP_Error) )
   {
-    switch (pp->state)
-    {
+    switch (pp->state) {
     case PP_Error:
-      return MHD_NO;
-    case PP_Done:
-      /* did not expect to receive more data */
-      pp->state = PP_Error;
-      return MHD_NO;
+      /* clearly impossible as per while loop invariant */
+      abort ();
+      break;
     case PP_Init:
-      equals = 0;
-      while ((equals + poff < post_data_len) &&
-             (post_data[equals + poff] != '='))
-        equals++;
-      if (equals + pp->buffer_pos > pp->buffer_size)
+      /* key phase */
+      if (NULL == start_key)
+        start_key = &post_data[poff];
+      switch (post_data[poff])
       {
-        pp->state = PP_Error;           /* out of memory */
-        return MHD_NO;
+      case '=':
+        /* Case: 'key=' */
+        end_key = &post_data[poff];
+        poff++;
+        pp->state = PP_ProcessValue;
+        break;
+      case '&':
+        /* Case: 'key&' */
+        end_key = &post_data[poff];
+        mhd_assert (NULL == start_value);
+        mhd_assert (NULL == end_value);
+        poff++;
+        pp->state = PP_Callback;
+        break;
+      case '\n':
+      case '\r':
+        /* Case: 'key\n' or 'key\r' */
+        end_key = &post_data[poff];
+        poff++;
+        pp->state = PP_Done;
+        break;
+      default:
+        /* normal character, advance! */
+        poff++;
+        continue;
       }
-      memcpy (&buf[pp->buffer_pos], &post_data[poff], equals);
-      pp->buffer_pos += equals;
-      if (equals + poff == post_data_len)
-        return MHD_YES;         /* no '=' yet */
-      buf[pp->buffer_pos] = '\0';       /* 0-terminate key */
-      pp->buffer_pos = 0;       /* reset for next key */
-      MHD_unescape_plus (buf);
-      MHD_http_unescape (buf);
-      poff += equals + 1;
-      pp->state = PP_ProcessValue;
-      pp->value_offset = 0;
-      break;
+      break; /* end PP_Init */
     case PP_ProcessValue:
-      /* obtain rest of value from previous iteration */
-      memcpy (xbuf, pp->xbuf, pp->xbuf_pos);
-      xoff = pp->xbuf_pos;
-      pp->xbuf_pos = 0;
-
-      /* find last position in input buffer that is part of the value */
-      amper = 0;
-      while ((amper + poff < post_data_len) &&
-             (amper < XBUF_SIZE) &&
-             (post_data[amper + poff] != '&') &&
-             (post_data[amper + poff] != '\n') &&
-             (post_data[amper + poff] != '\r'))
-        amper++;
-      end_of_value_found = ((amper + poff < post_data_len) &&
-                            ((post_data[amper + poff] == '&') ||
-                             (post_data[amper + poff] == '\n') ||
-                             (post_data[amper + poff] == '\r')));
-      /* compute delta, the maximum number of bytes that we will be able to
-         process right now (either amper-limited of xbuf-size limited) */
-      delta = amper;
-      if (delta > XBUF_SIZE - xoff)
-        delta = XBUF_SIZE - xoff;
-
-      /* move input into processing buffer */
-      memcpy (&xbuf[xoff], &post_data[poff], delta);
-      xoff += delta;
-      poff += delta;
-
-      /* find if escape sequence is at the end of the processing buffer;
-         if so, exclude those from processing (reduce delta to point at
-         end of processed region) */
-      delta = xoff;
-      if ((delta > 0) &&
-          ('%' == xbuf[delta - 1]))
-        delta--;
-      else if ((delta > 1) &&
-               ('%' == xbuf[delta - 2]))
-        delta -= 2;
-
-      /* if we have an incomplete escape sequence, save it to
-         pp->xbuf for later */
-      if (delta < xoff)
-      {
-        memcpy (pp->xbuf,
-                &xbuf[delta],
-                xoff - delta);
-        pp->xbuf_pos = xoff - delta;
-        xoff = delta;
+      if (NULL == start_value)
+        start_value = &post_data[poff];
+      switch (post_data[poff]) {
+      case '=':
+        /* case 'key==' */
+        pp->state = PP_Error;
+        continue;
+      case '&':
+        /* case 'value&' */
+        end_value = &post_data[poff];
+        poff++;
+        pp->state = PP_Callback;
+      case '\n':
+      case '\r':
+        /* Case: 'value\n' or 'value\r' */
+        end_value = &post_data[poff];
+        poff++;
+        pp->state = PP_Done;
+        break;
+      case '%':
+        last_escape = &post_data[poff];
+        poff++;
+        break;
+      case '0':
+      case '1':
+      case '2':
+      case '3':
+      case '4':
+      case '5':
+      case '6':
+      case '7':
+      case '8':
+      case '9':
+        /* character, may be part of escaping */
+        poff++;
+        continue;
+      default:
+        /* normal character, no more escaping! */
+        last_escape = NULL;
+        poff++;
+        continue;
       }
-
-      /* If we have nothing to do (delta == 0) and
-         not just because the value is empty (are
-         waiting for more data), go for next iteration */
-      if ( (0 == xoff) &&
-           (poff == post_data_len))
+      break; /* end PP_ProcessValue */
+    case PP_Done:
+      switch (post_data[poff]) {
+      case '\n':
+      case '\r':
+        poff++;
         continue;
-
-      /* unescape */
-      xbuf[xoff] = '\0';        /* 0-terminate in preparation */
-      MHD_unescape_plus (xbuf);
-      xoff = MHD_http_unescape (xbuf);
-      /* finally: call application! */
-      pp->must_ikvi = MHD_NO;
-      if (MHD_NO == pp->ikvi (pp->cls,
-                              MHD_POSTDATA_KIND,
-                              (const char *) &pp[1],        /* key */
-                              NULL,
-                              NULL,
-                              NULL,
-                              xbuf,
-                              pp->value_offset,
-                              xoff))
+      }
+      /* unexpected data at the end, fail! */
+      pp->state = PP_Error;
+      break;
+    case PP_Callback:
+      if ( (pp->buffer_pos + (end_key - start_key) >
+            pp->buffer_size) ||
+           (pp->buffer_pos + (end_key - start_key) >
+            pp->buffer_pos) )
       {
+        /* key too long, cannot parse! */
         pp->state = PP_Error;
-        return MHD_NO;
+        continue;
       }
-      pp->value_offset += xoff;
-
-      /* are we done with the value? */
-      if (end_of_value_found)
+      /* compute key, if we have not already */
+      if (NULL != start_key)
       {
-        /* we found the end of the value! */
-        if ( ('\n' == post_data[poff]) ||
-             ('\r' == post_data[poff]) )
-        {
-          pp->state = PP_ExpectNewLine;
-        }
-        else if ('&' == post_data[poff])
-        {
-          poff++;               /* skip '&' */
-          pp->state = PP_Init;
-        }
+        memcpy (&kbuf[pp->buffer_pos],
+                start_key,
+                end_key - start_key);
+        pp->buffer_pos += end_key - start_key;
+        start_key = NULL;
+        end_key = NULL;
+        kbuf[pp->buffer_pos] = '\0'; /* 0-terminate key */
+        MHD_unescape_plus (kbuf);
+        MHD_http_unescape (kbuf);
       }
+      process_value (pp,
+                     start_value,
+                     end_value,
+                     NULL);
+      pp->value_offset = 0;
+      start_value = NULL;
+      end_value = NULL;
+      pp->state = PP_Init;
       break;
-    case PP_ExpectNewLine:
-      if ( ('\n' == post_data[poff]) ||
-           ('\r' == post_data[poff]) )
-      {
-        poff++;
-        /* we are done, report error if we receive any more... */
-        pp->state = PP_Done;
-        return MHD_YES;
-      }
-      return MHD_NO;
     default:
       mhd_panic (mhd_panic_cls,
                  __FILE__,
@@ -515,6 +600,42 @@ post_process_urlencoded (struct MHD_PostProcessor *pp,
                  NULL);              /* should never happen! */
     }
   }
+
+  /* save remaining data for next iteration */
+  if ( (NULL != start_key) &&
+       (PP_Init == pp->state) )
+  {
+    if (NULL == end_key) 
+      end_key = &post_data[poff];
+    memcpy (&kbuf[pp->buffer_pos],
+            start_key,
+            end_key - start_key);
+    pp->buffer_pos += end_key - start_key;
+  }
+  if ( (NULL != start_value) &&
+       (PP_ProcessValue == pp->state) )
+  {
+    /* compute key, if we have not already */
+    if (NULL != start_key)
+    {
+      memcpy (&kbuf[pp->buffer_pos],
+              start_key,
+              end_key - start_key);
+      pp->buffer_pos += end_key - start_key;
+      start_key = NULL;
+      end_key = NULL;
+      kbuf[pp->buffer_pos] = '\0'; /* 0-terminate key */
+      MHD_unescape_plus (kbuf);
+      MHD_http_unescape (kbuf);
+    }
+    if (NULL == end_value)
+      end_value = &post_data[poff];
+    process_value (pp,
+                   start_value,
+                   end_value,
+                   last_escape);
+  }
+  
   return MHD_YES;
 }
 
@@ -1276,8 +1397,7 @@ MHD_destroy_post_processor (struct MHD_PostProcessor *pp)
      the post-processing may have been interrupted
      at any stage */
   if ( (pp->xbuf_pos > 0) ||
-       ( (pp->state != PP_Done) &&
-         (pp->state != PP_ExpectNewLine) ) )
+       (pp->state != PP_Done) )
     ret = MHD_NO;
   else
     ret = MHD_YES;
diff --git a/src/microhttpd/test_postprocessor.c 
b/src/microhttpd/test_postprocessor.c
index 6f8ce6f5..4b0c9e07 100644
--- a/src/microhttpd/test_postprocessor.c
+++ b/src/microhttpd/test_postprocessor.c
@@ -1,6 +1,6 @@
 /*
      This file is part of libmicrohttpd
-     Copyright (C) 2007,2013 Christian Grothoff
+     Copyright (C) 2007,2013,2019 Christian Grothoff
 
      libmicrohttpd is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published
@@ -104,7 +104,6 @@ value_checker (void *cls,
   int idx = *want_off;
   (void) kind;  /* Unused. Silent compiler warning. */
 
-
 #if 0
   fprintf (stderr,
            "VC: `%s' `%s' `%s' `%s' `%.*s'\n",
@@ -123,12 +122,26 @@ value_checker (void *cls,
       (0 != memcmp (data, &want[idx + 4][off], size)))
   {
     *want_off = -1;
+    fprintf (stderr,
+             "Failed with: `%s' `%s' `%s' `%s' `%.*s'\n",
+             key, filename, content_type, transfer_encoding,
+             (int) size,
+             data);
+    fprintf (stderr,
+             "Unexpected result: %d/%d/%d/%d/%d/%d/%d\n",
+             (idx < 0),
+             (want[idx] == NULL),
+             (0 != strcmp (key, want[idx])),
+             (mismatch (filename, want[idx + 1])),
+             (mismatch (content_type, want[idx + 2])),
+             (mismatch (transfer_encoding, want[idx + 3])),
+             (0 != memcmp (data, &want[idx + 4][off], size)));
+             
     return MHD_NO;
   }
   if (off + size == strlen (want[idx + 4]))
     *want_off = idx + 5;
   return MHD_YES;
-
 }
 
 
@@ -155,18 +168,27 @@ test_urlencoding_case (unsigned int want_start,
     MHD_HTTP_POST_ENCODING_FORM_URLENCODED);
   header.kind = MHD_HEADER_KIND;
   pp = MHD_create_post_processor (&connection,
-                                  1024, &value_checker, &want_off);
+                                  1024,
+                                  &value_checker,
+                                  &want_off);
   i = 0;
   size = strlen (url_data);
   while (i < size)
   {
     delta = 1 + MHD_random_ () % (size - i);
-    MHD_post_process (pp, &url_data[i], delta);
+    MHD_post_process (pp,
+                      &url_data[i],
+                      delta);
     i += delta;
   }
   MHD_destroy_post_processor (pp);
   if (want_off != want_end)
+  {
+    fprintf (stderr,
+             "Test failed in line %u\n",
+             (unsigned int) __LINE__);
     return 1;
+  }
   return 0;
 }
 
@@ -175,11 +197,18 @@ static int
 test_urlencoding (void)
 {
   unsigned int errorCount = 0;
+
   errorCount += test_urlencoding_case (URL_START, URL_END, URL_DATA);
-  errorCount += test_urlencoding_case (URL_NOVALUE1_START, URL_NOVALUE1_END,
+  errorCount += test_urlencoding_case (URL_NOVALUE1_START,
+                                       URL_NOVALUE1_END,
                                        URL_NOVALUE1_DATA);
-  errorCount += test_urlencoding_case (URL_NOVALUE2_START, URL_NOVALUE2_END,
+  errorCount += test_urlencoding_case (URL_NOVALUE2_START,
+                                       URL_NOVALUE2_END,
                                        URL_NOVALUE2_DATA);
+  fprintf (stderr,
+           "Test failed in line %u with %u errors\n",
+           (unsigned int) __LINE__,
+           errorCount);
   return errorCount;
 }
 
@@ -220,7 +249,13 @@ test_multipart_garbage (void)
     MHD_post_process (pp, &xdata[splitpoint], size - splitpoint);
     MHD_destroy_post_processor (pp);
     if (want_off != FORM_END)
+    {
+      fprintf (stderr,
+               "Test failed in line %u at point %d\n",
+               (unsigned int) __LINE__,
+               (int) splitpoint);
       return (int) splitpoint;
+    }
   }
   return 0;
 }
@@ -255,7 +290,13 @@ test_multipart_splits (void)
     MHD_post_process (pp, &FORM_DATA[splitpoint], size - splitpoint);
     MHD_destroy_post_processor (pp);
     if (want_off != FORM_END)
+    {
+      fprintf (stderr,
+               "Test failed in line %u at point %d\n",
+               (unsigned int) __LINE__,
+               (int) splitpoint);
       return (int) splitpoint;
+    }
   }
   return 0;
 }
@@ -293,7 +334,12 @@ test_multipart (void)
   }
   MHD_destroy_post_processor (pp);
   if (want_off != FORM_END)
+  {
+    fprintf (stderr,
+             "Test failed in line %u\n",
+             (unsigned int) __LINE__);
     return 2;
+  }
   return 0;
 }
 
@@ -330,7 +376,12 @@ test_nested_multipart (void)
   }
   MHD_destroy_post_processor (pp);
   if (want_off != FORM_NESTED_END)
+  {
+    fprintf (stderr,
+             "Test failed in line %u\n",
+             (unsigned int) __LINE__);
     return 4;
+  }
   return 0;
 }
 
@@ -366,7 +417,12 @@ test_empty_value (void)
   }
   MHD_destroy_post_processor (pp);
   if (want_off != URL_EMPTY_VALUE_END)
+  {
+    fprintf (stderr,
+             "Test failed in line %u\n",
+             (unsigned int) __LINE__);
     return 8;
+  }
   return 0;
 }
 

-- 
To stop receiving notification emails like this one, please contact
address@hidden.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]