Files
libmicrohttpd/src/microhttpd/test_postprocessor.c
T
LRN e524263be2 Add a variant of multipart preprocessor test that splits data in two parts
before feeding it to the preprocessor, trying all possible points where data
can be split. Prior to r30427 this test would have crashed only if data is
split at the very beginning (< 11). After r30427 this test crashes every time
the data is split somewhere around the boundary.
At least that is the case on W32.
2013-10-30 00:53:38 +00:00

313 lines
9.1 KiB
C

/*
This file is part of libmicrohttpd
(C) 2007 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
by the Free Software Foundation; either version 2, or (at your
option) any later version.
libmicrohttpd is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with libmicrohttpd; see the file COPYING. If not, write to the
Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.
*/
/**
* @file test_postprocessor.c
* @brief Testcase for postprocessor
* @author Christian Grothoff
*/
#include "platform.h"
#include "microhttpd.h"
#include "internal.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#ifndef WINDOWS
#include <unistd.h>
#endif
/**
* Array of values that the value checker "wants".
* Each series of checks should be terminated by
* five NULL-entries.
*/
const char *want[] = {
#define URL_DATA "abc=def&x=5"
#define URL_START 0
"abc", NULL, NULL, NULL, "def",
"x", NULL, NULL, NULL, "5",
#define URL_END (URL_START + 10)
NULL, NULL, NULL, NULL, NULL,
#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"
#define FORM_START (URL_END + 5)
"field1", NULL, NULL, NULL, "Joe Blow",
"pics", "file1.txt", "text/plain", "binary", "filedata",
#define FORM_END (FORM_START + 10)
NULL, NULL, NULL, NULL, NULL,
#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--"
#define FORM_NESTED_START (FORM_END + 5)
"field1", NULL, NULL, NULL, "Jane Blow",
"pics", "file1.txt", "text/plain", NULL, "filedata1",
"pics", "file2.gif", "image/gif", "binary", "filedata2",
#define FORM_NESTED_END (FORM_NESTED_START + 15)
NULL, NULL, NULL, NULL, NULL,
#define URL_EMPTY_VALUE_DATA "key1=value1&key2=&key3="
#define URL_EMPTY_VALUE_START (FORM_NESTED_END + 5)
"key1", NULL, NULL, NULL, "value1",
"key2", NULL, NULL, NULL, "",
"key3", NULL, NULL, NULL, "",
#define URL_EMPTY_VALUE_END (URL_EMPTY_VALUE_START + 15)
NULL, NULL, NULL, NULL, NULL
};
static int
mismatch (const char *a, const char *b)
{
if (a == b)
return 0;
if ((a == NULL) || (b == NULL))
return 1;
return 0 != strcmp (a, b);
}
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)
{
int *want_off = cls;
int idx = *want_off;
#if 0
fprintf (stderr,
"VC: `%s' `%s' `%s' `%s' `%.*s'\n",
key, filename, content_type, transfer_encoding, size, data);
#endif
if ( (0 != off) && (0 == size) )
return MHD_YES;
if ((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)))
{
*want_off = -1;
return MHD_NO;
}
if (off + size == strlen (want[idx + 4]))
*want_off = idx + 5;
return MHD_YES;
}
static int
test_urlencoding ()
{
struct MHD_Connection connection;
struct MHD_HTTP_Header header;
struct MHD_PostProcessor *pp;
unsigned int want_off = URL_START;
int i;
int delta;
size_t size;
memset (&connection, 0, sizeof (struct MHD_Connection));
memset (&header, 0, sizeof (struct MHD_HTTP_Header));
connection.headers_received = &header;
header.header = MHD_HTTP_HEADER_CONTENT_TYPE;
header.value = MHD_HTTP_POST_ENCODING_FORM_URLENCODED;
header.kind = MHD_HEADER_KIND;
pp = MHD_create_post_processor (&connection,
1024, &value_checker, &want_off);
i = 0;
size = strlen (URL_DATA);
while (i < size)
{
delta = 1 + RANDOM () % (size - i);
MHD_post_process (pp, &URL_DATA[i], delta);
i += delta;
}
MHD_destroy_post_processor (pp);
if (want_off != URL_END)
return 1;
return 0;
}
static int
test_multipart_splits ()
{
struct MHD_Connection connection;
struct MHD_HTTP_Header header;
struct MHD_PostProcessor *pp;
unsigned int want_off;
int i;
int delta;
size_t size;
size_t splitpoint;
size = strlen (FORM_DATA);
for (splitpoint = 1; splitpoint < size; splitpoint++)
{
want_off = FORM_START;
memset (&connection, 0, sizeof (struct MHD_Connection));
memset (&header, 0, sizeof (struct MHD_HTTP_Header));
connection.headers_received = &header;
header.header = MHD_HTTP_HEADER_CONTENT_TYPE;
header.value =
MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA ", boundary=AaB03x";
header.kind = MHD_HEADER_KIND;
pp = MHD_create_post_processor (&connection,
1024, &value_checker, &want_off);
i = 0;
delta = splitpoint;
MHD_post_process (pp, &FORM_DATA[i], delta);
i += delta;
delta = 1 + size - i;
MHD_post_process (pp, &FORM_DATA[i], delta);
i += delta;
MHD_destroy_post_processor (pp);
if (want_off != FORM_END)
return (int) splitpoint;
}
return 0;
}
static int
test_multipart ()
{
struct MHD_Connection connection;
struct MHD_HTTP_Header header;
struct MHD_PostProcessor *pp;
unsigned int want_off = FORM_START;
int i;
int delta;
size_t size;
memset (&connection, 0, sizeof (struct MHD_Connection));
memset (&header, 0, sizeof (struct MHD_HTTP_Header));
connection.headers_received = &header;
header.header = MHD_HTTP_HEADER_CONTENT_TYPE;
header.value =
MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA ", boundary=AaB03x";
header.kind = MHD_HEADER_KIND;
pp = MHD_create_post_processor (&connection,
1024, &value_checker, &want_off);
i = 0;
size = strlen (FORM_DATA);
while (i < size)
{
delta = 1 + RANDOM () % (size - i);
MHD_post_process (pp, &FORM_DATA[i], delta);
i += delta;
}
MHD_destroy_post_processor (pp);
if (want_off != FORM_END)
return 2;
return 0;
}
static int
test_nested_multipart ()
{
struct MHD_Connection connection;
struct MHD_HTTP_Header header;
struct MHD_PostProcessor *pp;
unsigned int want_off = FORM_NESTED_START;
int i;
int delta;
size_t size;
memset (&connection, 0, sizeof (struct MHD_Connection));
memset (&header, 0, sizeof (struct MHD_HTTP_Header));
connection.headers_received = &header;
header.header = MHD_HTTP_HEADER_CONTENT_TYPE;
header.value =
MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA ", boundary=AaB03x";
header.kind = MHD_HEADER_KIND;
pp = MHD_create_post_processor (&connection,
1024, &value_checker, &want_off);
i = 0;
size = strlen (FORM_NESTED_DATA);
while (i < size)
{
delta = 1 + RANDOM () % (size - i);
MHD_post_process (pp, &FORM_NESTED_DATA[i], delta);
i += delta;
}
MHD_destroy_post_processor (pp);
if (want_off != FORM_NESTED_END)
return 4;
return 0;
}
static int
test_empty_value ()
{
struct MHD_Connection connection;
struct MHD_HTTP_Header header;
struct MHD_PostProcessor *pp;
unsigned int want_off = URL_EMPTY_VALUE_START;
int i;
int delta;
size_t size;
memset (&connection, 0, sizeof (struct MHD_Connection));
memset (&header, 0, sizeof (struct MHD_HTTP_Header));
connection.headers_received = &header;
header.header = MHD_HTTP_HEADER_CONTENT_TYPE;
header.value = MHD_HTTP_POST_ENCODING_FORM_URLENCODED;
header.kind = MHD_HEADER_KIND;
pp = MHD_create_post_processor (&connection,
1024, &value_checker, &want_off);
i = 0;
size = strlen (URL_EMPTY_VALUE_DATA);
while (i < size)
{
delta = 1 + RANDOM () % (size - i);
MHD_post_process (pp, &URL_EMPTY_VALUE_DATA[i], delta);
i += delta;
}
MHD_destroy_post_processor (pp);
if (want_off != URL_EMPTY_VALUE_END)
return 8;
return 0;
}
int
main (int argc, char *const *argv)
{
unsigned int errorCount = 0;
errorCount += test_urlencoding ();
errorCount += test_multipart_splits ();
errorCount += test_multipart ();
errorCount += test_nested_multipart ();
errorCount += test_empty_value ();
if (errorCount != 0)
fprintf (stderr, "Error (code: %u)\n", errorCount);
return errorCount != 0; /* 0 == pass */
}