Home | History | Annotate | Download | only in microhttpd
      1 /*
      2      This file is part of libmicrohttpd
      3      Copyright (C) 2007,2013 Christian Grothoff
      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., 59 Temple Place - Suite 330,
     18      Boston, MA 02111-1307, USA.
     19 */
     20 
     21 /**
     22  * @file test_postprocessor.c
     23  * @brief  Testcase for postprocessor
     24  * @author Christian Grothoff
     25  */
     26 
     27 #include "platform.h"
     28 #include "microhttpd.h"
     29 #include "internal.h"
     30 #include <stdlib.h>
     31 #include <string.h>
     32 #include <stdio.h>
     33 
     34 #ifndef WINDOWS
     35 #include <unistd.h>
     36 #endif
     37 
     38 /**
     39  * Array of values that the value checker "wants".
     40  * Each series of checks should be terminated by
     41  * five NULL-entries.
     42  */
     43 const char *want[] = {
     44 #define URL_DATA "abc=def&x=5"
     45 #define URL_START 0
     46   "abc", NULL, NULL, NULL, "def",
     47   "x", NULL, NULL, NULL, "5",
     48 #define URL_END (URL_START + 10)
     49   NULL, NULL, NULL, NULL, NULL,
     50 #define FORM_DATA "--AaB03x\r\ncontent-disposition: form-data; name=\"field1\"\r\n\r\nJoe Blow\r\n--AaB03x\r\ncontent-disposition: form-data; name=\"pics\"; filename=\"file1.txt\"\r\nContent-Type: text/plain\r\nContent-Transfer-Encoding: binary\r\n\r\nfiledata\r\n--AaB03x--\r\n"
     51 #define FORM_START (URL_END + 5)
     52   "field1", NULL, NULL, NULL, "Joe Blow",
     53   "pics", "file1.txt", "text/plain", "binary", "filedata",
     54 #define FORM_END (FORM_START + 10)
     55   NULL, NULL, NULL, NULL, NULL,
     56 #define FORM_NESTED_DATA "--AaB03x\r\ncontent-disposition: form-data; name=\"field1\"\r\n\r\nJane Blow\r\n--AaB03x\r\ncontent-disposition: form-data; name=\"pics\"\r\nContent-type: multipart/mixed, boundary=BbC04y\r\n\r\n--BbC04y\r\nContent-disposition: attachment; filename=\"file1.txt\"\r\nContent-Type: text/plain\r\n\r\nfiledata1\r\n--BbC04y\r\nContent-disposition: attachment; filename=\"file2.gif\"\r\nContent-type: image/gif\r\nContent-Transfer-Encoding: binary\r\n\r\nfiledata2\r\n--BbC04y--\r\n--AaB03x--"
     57 #define FORM_NESTED_START (FORM_END + 5)
     58   "field1", NULL, NULL, NULL, "Jane Blow",
     59   "pics", "file1.txt", "text/plain", NULL, "filedata1",
     60   "pics", "file2.gif", "image/gif", "binary", "filedata2",
     61 #define FORM_NESTED_END (FORM_NESTED_START + 15)
     62   NULL, NULL, NULL, NULL, NULL,
     63 #define URL_EMPTY_VALUE_DATA "key1=value1&key2=&key3="
     64 #define URL_EMPTY_VALUE_START (FORM_NESTED_END + 5)
     65   "key1", NULL, NULL, NULL, "value1",
     66   "key2", NULL, NULL, NULL, "",
     67   "key3", NULL, NULL, NULL, "",
     68 #define URL_EMPTY_VALUE_END (URL_EMPTY_VALUE_START + 15)
     69   NULL, NULL, NULL, NULL, NULL
     70 };
     71 
     72 static int
     73 mismatch (const char *a, const char *b)
     74 {
     75   if (a == b)
     76     return 0;
     77   if ((a == NULL) || (b == NULL))
     78     return 1;
     79   return 0 != strcmp (a, b);
     80 }
     81 
     82 static int
     83 value_checker (void *cls,
     84                enum MHD_ValueKind kind,
     85                const char *key,
     86                const char *filename,
     87                const char *content_type,
     88                const char *transfer_encoding,
     89                const char *data, uint64_t off, size_t size)
     90 {
     91   int *want_off = cls;
     92   int idx = *want_off;
     93 
     94 #if 0
     95   fprintf (stderr,
     96            "VC: `%s' `%s' `%s' `%s' `%.*s'\n",
     97            key, filename, content_type, transfer_encoding,
     98            (int) size,
     99            data);
    100 #endif
    101   if ( (0 != off) && (0 == size) )
    102     return MHD_YES;
    103   if ((idx < 0) ||
    104       (want[idx] == NULL) ||
    105       (0 != strcmp (key, want[idx])) ||
    106       (mismatch (filename, want[idx + 1])) ||
    107       (mismatch (content_type, want[idx + 2])) ||
    108       (mismatch (transfer_encoding, want[idx + 3])) ||
    109       (0 != memcmp (data, &want[idx + 4][off], size)))
    110     {
    111       *want_off = -1;
    112       return MHD_NO;
    113     }
    114   if (off + size == strlen (want[idx + 4]))
    115     *want_off = idx + 5;
    116   return MHD_YES;
    117 
    118 }
    119 
    120 
    121 static int
    122 test_urlencoding ()
    123 {
    124   struct MHD_Connection connection;
    125   struct MHD_HTTP_Header header;
    126   struct MHD_PostProcessor *pp;
    127   unsigned int want_off = URL_START;
    128   int i;
    129   int delta;
    130   size_t size;
    131 
    132   memset (&connection, 0, sizeof (struct MHD_Connection));
    133   memset (&header, 0, sizeof (struct MHD_HTTP_Header));
    134   connection.headers_received = &header;
    135   header.header = MHD_HTTP_HEADER_CONTENT_TYPE;
    136   header.value = MHD_HTTP_POST_ENCODING_FORM_URLENCODED;
    137   header.kind = MHD_HEADER_KIND;
    138   pp = MHD_create_post_processor (&connection,
    139                                   1024, &value_checker, &want_off);
    140   i = 0;
    141   size = strlen (URL_DATA);
    142   while (i < size)
    143     {
    144       delta = 1 + MHD_random_ () % (size - i);
    145       MHD_post_process (pp, &URL_DATA[i], delta);
    146       i += delta;
    147     }
    148   MHD_destroy_post_processor (pp);
    149   if (want_off != URL_END)
    150     return 1;
    151   return 0;
    152 }
    153 
    154 
    155 static int
    156 test_multipart_garbage ()
    157 {
    158   struct MHD_Connection connection;
    159   struct MHD_HTTP_Header header;
    160   struct MHD_PostProcessor *pp;
    161   unsigned int want_off;
    162   size_t size = strlen (FORM_DATA);
    163   size_t splitpoint;
    164   char xdata[size + 3];
    165 
    166   /* fill in evil garbage at the beginning */
    167   xdata[0] = '-';
    168   xdata[1] = 'x';
    169   xdata[2] = '\r';
    170   memcpy (&xdata[3], FORM_DATA, size);
    171   size += 3;
    172 
    173   size = strlen (FORM_DATA);
    174   for (splitpoint = 1; splitpoint < size; splitpoint++)
    175   {
    176     want_off = FORM_START;
    177     memset (&connection, 0, sizeof (struct MHD_Connection));
    178     memset (&header, 0, sizeof (struct MHD_HTTP_Header));
    179     connection.headers_received = &header;
    180     header.header = MHD_HTTP_HEADER_CONTENT_TYPE;
    181     header.value =
    182       MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA ", boundary=AaB03x";
    183     header.kind = MHD_HEADER_KIND;
    184     pp = MHD_create_post_processor (&connection,
    185                                     1024, &value_checker, &want_off);
    186     MHD_post_process (pp, xdata, splitpoint);
    187     MHD_post_process (pp, &xdata[splitpoint], size - splitpoint);
    188     MHD_destroy_post_processor (pp);
    189     if (want_off != FORM_END)
    190       return (int) splitpoint;
    191   }
    192   return 0;
    193 }
    194 
    195 
    196 static int
    197 test_multipart_splits ()
    198 {
    199   struct MHD_Connection connection;
    200   struct MHD_HTTP_Header header;
    201   struct MHD_PostProcessor *pp;
    202   unsigned int want_off;
    203   size_t size;
    204   size_t splitpoint;
    205 
    206   size = strlen (FORM_DATA);
    207   for (splitpoint = 1; splitpoint < size; splitpoint++)
    208   {
    209     want_off = FORM_START;
    210     memset (&connection, 0, sizeof (struct MHD_Connection));
    211     memset (&header, 0, sizeof (struct MHD_HTTP_Header));
    212     connection.headers_received = &header;
    213     header.header = MHD_HTTP_HEADER_CONTENT_TYPE;
    214     header.value =
    215       MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA ", boundary=AaB03x";
    216     header.kind = MHD_HEADER_KIND;
    217     pp = MHD_create_post_processor (&connection,
    218                                     1024, &value_checker, &want_off);
    219     MHD_post_process (pp, FORM_DATA, splitpoint);
    220     MHD_post_process (pp, &FORM_DATA[splitpoint], size - splitpoint);
    221     MHD_destroy_post_processor (pp);
    222     if (want_off != FORM_END)
    223       return (int) splitpoint;
    224   }
    225   return 0;
    226 }
    227 
    228 
    229 static int
    230 test_multipart ()
    231 {
    232   struct MHD_Connection connection;
    233   struct MHD_HTTP_Header header;
    234   struct MHD_PostProcessor *pp;
    235   unsigned int want_off = FORM_START;
    236   int i;
    237   int delta;
    238   size_t size;
    239 
    240   memset (&connection, 0, sizeof (struct MHD_Connection));
    241   memset (&header, 0, sizeof (struct MHD_HTTP_Header));
    242   connection.headers_received = &header;
    243   header.header = MHD_HTTP_HEADER_CONTENT_TYPE;
    244   header.value =
    245     MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA ", boundary=AaB03x";
    246   header.kind = MHD_HEADER_KIND;
    247   pp = MHD_create_post_processor (&connection,
    248                                   1024, &value_checker, &want_off);
    249   i = 0;
    250   size = strlen (FORM_DATA);
    251   while (i < size)
    252     {
    253       delta = 1 + MHD_random_ () % (size - i);
    254       MHD_post_process (pp, &FORM_DATA[i], delta);
    255       i += delta;
    256     }
    257   MHD_destroy_post_processor (pp);
    258   if (want_off != FORM_END)
    259     return 2;
    260   return 0;
    261 }
    262 
    263 
    264 static int
    265 test_nested_multipart ()
    266 {
    267   struct MHD_Connection connection;
    268   struct MHD_HTTP_Header header;
    269   struct MHD_PostProcessor *pp;
    270   unsigned int want_off = FORM_NESTED_START;
    271   int i;
    272   int delta;
    273   size_t size;
    274 
    275   memset (&connection, 0, sizeof (struct MHD_Connection));
    276   memset (&header, 0, sizeof (struct MHD_HTTP_Header));
    277   connection.headers_received = &header;
    278   header.header = MHD_HTTP_HEADER_CONTENT_TYPE;
    279   header.value =
    280     MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA ", boundary=AaB03x";
    281   header.kind = MHD_HEADER_KIND;
    282   pp = MHD_create_post_processor (&connection,
    283                                   1024, &value_checker, &want_off);
    284   i = 0;
    285   size = strlen (FORM_NESTED_DATA);
    286   while (i < size)
    287     {
    288       delta = 1 + MHD_random_ () % (size - i);
    289       MHD_post_process (pp, &FORM_NESTED_DATA[i], delta);
    290       i += delta;
    291     }
    292   MHD_destroy_post_processor (pp);
    293   if (want_off != FORM_NESTED_END)
    294     return 4;
    295   return 0;
    296 }
    297 
    298 
    299 static int
    300 test_empty_value ()
    301 {
    302   struct MHD_Connection connection;
    303   struct MHD_HTTP_Header header;
    304   struct MHD_PostProcessor *pp;
    305   unsigned int want_off = URL_EMPTY_VALUE_START;
    306   int i;
    307   int delta;
    308   size_t size;
    309 
    310   memset (&connection, 0, sizeof (struct MHD_Connection));
    311   memset (&header, 0, sizeof (struct MHD_HTTP_Header));
    312   connection.headers_received = &header;
    313   header.header = MHD_HTTP_HEADER_CONTENT_TYPE;
    314   header.value = MHD_HTTP_POST_ENCODING_FORM_URLENCODED;
    315   header.kind = MHD_HEADER_KIND;
    316   pp = MHD_create_post_processor (&connection,
    317                                   1024, &value_checker, &want_off);
    318   i = 0;
    319   size = strlen (URL_EMPTY_VALUE_DATA);
    320   while (i < size)
    321     {
    322       delta = 1 + MHD_random_ () % (size - i);
    323       MHD_post_process (pp, &URL_EMPTY_VALUE_DATA[i], delta);
    324       i += delta;
    325     }
    326   MHD_destroy_post_processor (pp);
    327   if (want_off != URL_EMPTY_VALUE_END)
    328     return 8;
    329   return 0;
    330 }
    331 
    332 
    333 
    334 
    335 int
    336 main (int argc, char *const *argv)
    337 {
    338   unsigned int errorCount = 0;
    339 
    340   errorCount += test_multipart_splits ();
    341   errorCount += test_multipart_garbage ();
    342   errorCount += test_urlencoding ();
    343   errorCount += test_multipart ();
    344   errorCount += test_nested_multipart ();
    345   errorCount += test_empty_value ();
    346   if (errorCount != 0)
    347     fprintf (stderr, "Error (code: %u)\n", errorCount);
    348   return errorCount != 0;       /* 0 == pass */
    349 }
    350