• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
mismatch(const char * a,const char * b)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
value_checker(void * cls,enum MHD_ValueKind kind,const char * key,const char * filename,const char * content_type,const char * transfer_encoding,const char * data,uint64_t off,size_t size)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
test_urlencoding()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
test_multipart_garbage()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
test_multipart_splits()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
test_multipart()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
test_nested_multipart()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
test_empty_value()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
main(int argc,char * const * argv)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