aboutsummaryrefslogtreecommitdiff
path: root/src/testzzuf
diff options
context:
space:
mode:
Diffstat (limited to 'src/testzzuf')
-rw-r--r--src/testzzuf/Makefile.am121
-rw-r--r--src/testzzuf/mhd_debug_funcs.c45
-rw-r--r--src/testzzuf/mhd_debug_funcs.h10
-rw-r--r--src/testzzuf/socat.c117
-rw-r--r--src/testzzuf/test_get.c1726
-rw-r--r--src/testzzuf/test_get_chunked.c364
-rw-r--r--src/testzzuf/test_long_header.c265
-rw-r--r--src/testzzuf/test_post.c416
-rw-r--r--src/testzzuf/test_post_form.c432
-rw-r--r--src/testzzuf/test_put.c380
-rw-r--r--src/testzzuf/test_put_chunked.c395
-rw-r--r--src/testzzuf/test_put_large.c403
-rwxr-xr-xsrc/testzzuf/zzuf_test_runner.sh55
13 files changed, 1701 insertions, 3028 deletions
diff --git a/src/testzzuf/Makefile.am b/src/testzzuf/Makefile.am
index 5c5c00ea..23b96d66 100644
--- a/src/testzzuf/Makefile.am
+++ b/src/testzzuf/Makefile.am
@@ -1,17 +1,29 @@
1# This Makefile.am is in the public domain 1# This Makefile.am is in the public domain
2
2SUBDIRS = . 3SUBDIRS = .
3 4
5# ZZUF_SEED can be redefined to use other initial seeds
6# for extended testing. E.g.,
7# make ZZUF_SEED=1234 check
8ZZUF_SEED = 0
9
10# Additional flags for zzuf
11ZZUF_FLAGS =
12
4AM_CPPFLAGS = \ 13AM_CPPFLAGS = \
5 -I$(top_srcdir)/src/include \ 14 -I$(top_srcdir)/src/include \
6 -I$(top_srcdir)/src/microhttpd \ 15 -I$(top_srcdir)/src/microhttpd \
7 -DMHD_CPU_COUNT=$(CPU_COUNT) \ 16 -DMHD_CPU_COUNT=$(CPU_COUNT) \
8 $(CPPFLAGS_ac) $(LIBCURL_CPPFLAGS) 17 $(CPPFLAGS_ac) $(LIBCURL_CPPFLAGS)
9 18
10AM_CFLAGS = $(CFLAGS_ac) @LIBGCRYPT_CFLAGS@ 19AM_CFLAGS = $(CFLAGS_ac)
11 20
12AM_LDFLAGS = $(LDFLAGS_ac) 21AM_LDFLAGS = $(LDFLAGS_ac)
13 22
14AM_TESTS_ENVIRONMENT = $(TESTS_ENVIRONMENT_ac) 23AM_TESTS_ENVIRONMENT = $(TESTS_ENVIRONMENT_ac) \
24 ZZUF="$(ZZUF)" ; export ZZUF ; \
25 ZZUF_SEED="$(ZZUF_SEED)" ; export ZZUF_SEED ; \
26 ZZUF_FLAGS="$(ZZUF_FLAGS)" ; export ZZUF_FLAGS ;
15 27
16if USE_COVERAGE 28if USE_COVERAGE
17 AM_CFLAGS += -fprofile-arcs -ftest-coverage 29 AM_CFLAGS += -fprofile-arcs -ftest-coverage
@@ -25,11 +37,6 @@ $(top_builddir)/src/microhttpd/libmicrohttpd.la: $(top_builddir)/src/microhttpd/
25 @echo ' cd $(top_builddir)/src/microhttpd && $(MAKE) $(AM_MAKEFLAGS) libmicrohttpd.la'; \ 37 @echo ' cd $(top_builddir)/src/microhttpd && $(MAKE) $(AM_MAKEFLAGS) libmicrohttpd.la'; \
26 $(am__cd) $(top_builddir)/src/microhttpd && $(MAKE) $(AM_MAKEFLAGS) libmicrohttpd.la 38 $(am__cd) $(top_builddir)/src/microhttpd && $(MAKE) $(AM_MAKEFLAGS) libmicrohttpd.la
27 39
28EXTRA_DIST = README socat.c
29
30THREAD_ONLY_TESTS = \
31 test_long_header
32
33check_PROGRAMS = \ 40check_PROGRAMS = \
34 test_get \ 41 test_get \
35 test_get_chunked \ 42 test_get_chunked \
@@ -38,64 +45,86 @@ check_PROGRAMS = \
38 test_put \ 45 test_put \
39 test_put_chunked \ 46 test_put_chunked \
40 test_put_large \ 47 test_put_large \
41 test_get11 \ 48 test_get_long_uri \
42 test_post11 \ 49 test_get_long_header \
43 test_post_form11 \ 50 test_get_close \
44 test_put11 \ 51 test_get_chunked_close \
45 test_put_large11 52 test_post_close \
53 test_post_form_close \
54 test_put_close \
55 test_put_chunked_close \
56 test_put_large_close \
57 test_get_long_uri_close \
58 test_get_long_header_close \
59 test_get10 \
60 test_get_chunked10 \
61 test_post10 \
62 test_post_form10 \
63 test_put10 \
64 test_put_large10 \
65 test_get_long_uri10 \
66 test_get_long_header10
46 67
47.NOTPARALLEL: 68.NOTPARALLEL:
48 69
49 70
50if USE_POSIX_THREADS 71TESTS = $(check_PROGRAMS)
51check_PROGRAMS += \
52 $(THREAD_ONLY_TESTS)
53endif
54if USE_W32_THREADS
55check_PROGRAMS += \
56 $(THREAD_ONLY_TESTS)
57endif
58 72
73dist_check_SCRIPTS = zzuf_test_runner.sh
59 74
60TESTS = $(check_PROGRAMS) 75LOG_COMPILER = @SHELL@ $(srcdir)/zzuf_test_runner.sh
76
77tests_common_sources = mhd_debug_funcs.h mhd_debug_funcs.c
61 78
62test_get_SOURCES = \ 79test_get_SOURCES = \
63 test_get.c 80 test_get.c $(tests_common_sources)
81
82test_get_chunked_SOURCES = $(test_get_SOURCES)
83
84test_post_SOURCES = $(test_get_SOURCES)
85
86test_post_form_SOURCES = $(test_get_SOURCES)
87
88test_put_SOURCES = $(test_get_SOURCES)
89
90test_put_chunked_SOURCES = $(test_get_SOURCES)
91
92test_put_large_SOURCES = $(test_get_SOURCES)
93
94test_get_long_uri_SOURCES = $(test_get_SOURCES)
95
96test_get_long_header_SOURCES = $(test_get_SOURCES)
97
98test_get_close_SOURCES = $(test_get_SOURCES)
99
100test_get_chunked_close_SOURCES = $(test_get_chunked_SOURCES)
101
102test_post_close_SOURCES = $(test_post_SOURCES)
64 103
65test_get_chunked_SOURCES = \ 104test_post_form_close_SOURCES = $(test_post_form_SOURCES)
66 test_get_chunked.c
67 105
68test_post_SOURCES = \ 106test_put_close_SOURCES = $(test_put_SOURCES)
69 test_post.c
70 107
71test_post_form_SOURCES = \ 108test_put_chunked_close_SOURCES = $(test_put_chunked_SOURCES)
72 test_post_form.c
73 109
74test_put_SOURCES = \ 110test_put_large_close_SOURCES = $(test_put_large_SOURCES)
75 test_put.c
76 111
77test_put_chunked_SOURCES = \ 112test_get_long_uri_close_SOURCES = $(test_get_long_uri_SOURCES)
78 test_put_chunked.c
79 113
80test_put_large_SOURCES = \ 114test_get_long_header_close_SOURCES = $(test_get_long_header_SOURCES)
81 test_put_large.c
82 115
116test_get10_SOURCES = $(test_get_SOURCES)
83 117
118test_get_chunked10_SOURCES = $(test_get_chunked_SOURCES)
84 119
85test_get11_SOURCES = \ 120test_post10_SOURCES = $(test_post_SOURCES)
86 test_get.c
87 121
88test_post11_SOURCES = \ 122test_post_form10_SOURCES = $(test_post_form_SOURCES)
89 test_post.c
90 123
91test_post_form11_SOURCES = \ 124test_put10_SOURCES = $(test_put_SOURCES)
92 test_post_form.c
93 125
94test_put11_SOURCES = \ 126test_put_large10_SOURCES = $(test_put_large_SOURCES)
95 test_put.c
96 127
97test_put_large11_SOURCES = \ 128test_get_long_uri10_SOURCES = $(test_get_long_uri_SOURCES)
98 test_put_large.c
99 129
100test_long_header_SOURCES = \ 130test_get_long_header10_SOURCES = $(test_get_long_header_SOURCES)
101 test_long_header.c
diff --git a/src/testzzuf/mhd_debug_funcs.c b/src/testzzuf/mhd_debug_funcs.c
index 9bfd3001..5db50b41 100644
--- a/src/testzzuf/mhd_debug_funcs.c
+++ b/src/testzzuf/mhd_debug_funcs.c
@@ -61,3 +61,48 @@ MHD_avoid_accept4_ (struct MHD_Daemon *daemon)
61#endif /* ! _DEBUG */ 61#endif /* ! _DEBUG */
62#endif /* USE_ACCEPT4 */ 62#endif /* USE_ACCEPT4 */
63} 63}
64
65#ifdef MHD_ASAN_ACTIVE
66#define MHD_ASAN_ENABLED_ 1
67#else /* ! MHD_ASAN_ACTIVE */
68#ifdef __SANITIZE_ADDRESS__
69#define MHD_ASAN_ENABLED_ 1
70#else /* ! __SANITIZE_ADDRESS__ */
71#if defined(__has_feature)
72#if __has_feature(address_sanitizer)
73#define MHD_ASAN_ENABLED_ 1
74#endif /* __has_feature(address_sanitizer) */
75#endif /* __has_feature */
76#endif /* ! __SANITIZE_ADDRESS__ */
77#endif /* ! MHD_ASAN_ACTIVE */
78/**
79 * Checks whether any know sanitizer is enabled for this build.
80 * zzuf does not work together with sanitizers as both are intercepting
81 * standard library calls.
82 * @return non-zero if any sanitizer is enabled,
83 * zero otherwise
84 */
85int
86MHD_are_sanitizers_enabled_ (void)
87{
88 int ret = 0;
89#ifdef MHD_ASAN_ENABLED_
90 ++ret;
91#endif /* ! MHD_ASAN_ENABLED_ */
92#if defined(__has_feature)
93#if __has_feature(thread_sanitizer)
94 ++ret;
95#endif
96#if __has_feature(memory_sanitizer)
97 ++ret;
98#endif
99#if __has_feature(dataflow_sanitizer)
100 ++ret;
101#endif
102#else /* ! defined(__has_feature) */
103#ifdef __SANITIZE_THREAD__
104 ++ret;
105#endif
106#endif /* ! defined(__has_feature) */
107 return ret;
108}
diff --git a/src/testzzuf/mhd_debug_funcs.h b/src/testzzuf/mhd_debug_funcs.h
index 02423edb..04de0970 100644
--- a/src/testzzuf/mhd_debug_funcs.h
+++ b/src/testzzuf/mhd_debug_funcs.h
@@ -44,4 +44,14 @@ MHD_is_avoid_accept4_possible_ (void);
44void 44void
45MHD_avoid_accept4_ (struct MHD_Daemon *daemon); 45MHD_avoid_accept4_ (struct MHD_Daemon *daemon);
46 46
47/**
48 * Checks whether any know sanitizer is enabled for this build.
49 * zzuf does not work together with sanitizers as both are intercepting
50 * standard library calls.
51 * @return non-zero if any sanitizer is enabled,
52 * zero otherwise
53 */
54int
55MHD_are_sanitizers_enabled_ (void);
56
47#endif /* MHD_DEBUG_FUNCS_H */ 57#endif /* MHD_DEBUG_FUNCS_H */
diff --git a/src/testzzuf/socat.c b/src/testzzuf/socat.c
deleted file mode 100644
index 0ee14749..00000000
--- a/src/testzzuf/socat.c
+++ /dev/null
@@ -1,117 +0,0 @@
1/*
2 This file is part of libmicrohttpd
3 Copyright (C) 2008,2016 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 2, 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., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19*/
20
21/**
22 * @file socat.c
23 * @brief Code to fork-exec zzuf and start the socat process
24 * @author Christian Grothoff
25 */
26
27#include <errno.h>
28#include <sys/types.h>
29#include <sys/wait.h>
30#include <signal.h>
31
32#ifdef _WIN32
33#ifndef WIN32_LEAN_AND_MEAN
34#define WIN32_LEAN_AND_MEAN 1
35#endif /* !WIN32_LEAN_AND_MEAN */
36#include <windows.h>
37#endif
38
39
40/**
41 * A larger loop count will run more random tests --
42 * which would be good, except that it may take too
43 * long for most user's patience. So this small
44 * value is the default.
45 */
46#ifndef _MHD_VHEAVY_TESTS
47#define LOOP_COUNT 10
48#else /* ! _MHD_VHEAVY_TESTS */
49#define LOOP_COUNT 200
50#endif /* ! _MHD_VHEAVY_TESTS */
51
52#define CURL_TIMEOUT 50L
53
54static pid_t zzuf_pid;
55
56static void
57zzuf_socat_start ()
58{
59 int status;
60 char *const args[] = {
61 "zzuf",
62 "--ratio=0.0:0.75",
63 "-n",
64 "-A",
65 "socat",
66 "-lf",
67 "/dev/null",
68 "TCP4-LISTEN:11081,reuseaddr,fork",
69 "TCP4:127.0.0.1:11080",
70 NULL,
71 };
72 zzuf_pid = fork ();
73 if (zzuf_pid == -1)
74 {
75 fprintf (stderr, "fork failed: %s\n", strerror (errno));
76 exit (1);
77 }
78 if (zzuf_pid != 0)
79 {
80 (void) sleep (1); /* allow zzuf and socat to start */
81 status = 0;
82 if (0 < waitpid (zzuf_pid, &status, WNOHANG))
83 {
84 if (WIFEXITED (status))
85 fprintf (stderr,
86 "zzuf died with status code %d!\n",
87 WEXITSTATUS (status));
88 if (WIFSIGNALED (status))
89 fprintf (stderr,
90 "zzuf died from signal %d!\n", WTERMSIG (status));
91 exit (1);
92 }
93 return;
94 }
95 setpgid (0, 0);
96 execvp ("zzuf", args);
97 fprintf (stderr, "execution of `zzuf' failed: %s\n", strerror (errno));
98 exit (1);
99}
100
101
102static void
103zzuf_socat_stop ()
104{
105 int status;
106 if (zzuf_pid != 0)
107 {
108 if (0 != killpg (zzuf_pid, SIGINT))
109 fprintf (stderr, "Failed to killpg: %s\n", strerror (errno));
110 kill (zzuf_pid, SIGINT);
111 waitpid (zzuf_pid, &status, 0);
112 (void) sleep (1); /* allow socat to also die in peace */
113 }
114}
115
116
117/* end of socat.c */
diff --git a/src/testzzuf/test_get.c b/src/testzzuf/test_get.c
index e2b86ffe..904808bc 100644
--- a/src/testzzuf/test_get.c
+++ b/src/testzzuf/test_get.c
@@ -1,6 +1,7 @@
1/* 1/*
2 This file is part of libmicrohttpd 2 This file is part of libmicrohttpd
3 Copyright (C) 2007, 2008 Christian Grothoff 3 Copyright (C) 2007, 2008 Christian Grothoff
4 Copyright (C) 2016-2022 Evgeny Grin (Karlson2k)
4 5
5 libmicrohttpd is free software; you can redistribute it and/or modify 6 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 it under the terms of the GNU General Public License as published
@@ -19,12 +20,12 @@
19*/ 20*/
20 21
21/** 22/**
22 * @file test_get.c 23 * @file testzzuf/test_get.c
23 * @brief Testcase for libmicrohttpd GET operations 24 * @brief Several testcases for libmicrohttpd with input fuzzing
24 * @author Christian Grothoff 25 * @author Christian Grothoff
26 * @author Karlson2k (Evgeny Grin)
25 */ 27 */
26 28
27#include "MHD_config.h"
28#include "platform.h" 29#include "platform.h"
29#include <curl/curl.h> 30#include <curl/curl.h>
30#include <microhttpd.h> 31#include <microhttpd.h>
@@ -36,298 +37,1603 @@
36#include <unistd.h> 37#include <unistd.h>
37#endif 38#endif
38 39
39#include "socat.c" 40#include "mhd_debug_funcs.h"
41#include "test_helpers.h"
40 42
43#ifndef MHD_STATICSTR_LEN_
44/**
45 * Determine length of static string / macro strings at compile time.
46 */
47#define MHD_STATICSTR_LEN_(macro) (sizeof(macro) / sizeof(char) - 1)
48#endif /* ! MHD_STATICSTR_LEN_ */
49
50#ifndef CURL_VERSION_BITS
51#define CURL_VERSION_BITS(x,y,z) ((x) << 16 | (y) << 8 | (z))
52#endif /* ! CURL_VERSION_BITS */
53#ifndef CURL_AT_LEAST_VERSION
54#define CURL_AT_LEAST_VERSION(x,y,z) \
55 (LIBCURL_VERSION_NUM >= CURL_VERSION_BITS (x, y, z))
56#endif /* ! CURL_AT_LEAST_VERSION */
57
58/**
59 * A larger loop count will run more random tests --
60 * which would be good, except that it may take too
61 * long for most user's patience. So this small
62 * value is the default.
63 * Can be redefined by CPPFLAGS=-DLOOP_COUNT=123
64 */
65#ifndef LOOP_COUNT
66#ifndef _MHD_VHEAVY_TESTS
67#define LOOP_COUNT 10
68#else /* ! _MHD_HEAVY_TESTS */
69#define LOOP_COUNT 200
70#endif /* ! _MHD_HEAVY_TESTS */
71#endif /* LOOP_COUNT */
72
73#ifdef _DEBUG
74/* Uncomment the next line (or use CPPFLAGS) to see all request and response bodies in log */
75/* #define TEST_PRINT_BODY */
76/* Uncomment the next line (or use CPPFLAGS) to see all request bodies as they are sent by libcurl */
77/* #define TEST_PRINT_BODY_RQ 1 */
78/* Uncomment the next line (or use CPPFLAGS) to see all request bodies as they are received by libcurl */
79/* #define TEST_PRINT_BODY_RP 1 */
80#endif /* _DEBUG */
81
82#define MHD_TIMEOUT 2
83
84#define CURL_TIMEOUT 5
85
86/* Global test parameters */
41static int oneone; 87static int oneone;
88static int dry_run;
89static int use_get;
90static int use_get_chunked;
91static int use_put;
92static int use_put_large;
93static int use_put_chunked;
94static int use_post;
95static int use_post_form;
96static int use_long_header;
97static int use_long_uri;
98static int use_close;
42 99
43struct CBC 100#define TEST_BASE_URI "http:/" "/127.0.0.1/test_uri"
101
102#define EMPTY_PAGE "Empty page."
103#define EMPTY_PAGE_ALT "Alternative empty page."
104#define METHOD_NOT_SUPPORTED "HTTP method is not supported."
105#define POST_DATA_BROKEN "The POST request is ill-formed."
106
107#define POST_KEY1 "test"
108#define POST_VALUE1 "test_post"
109#define POST_KEY2 "library"
110#define POST_VALUE2 "GNU libmicrohttpd"
111#define POST_URLENC_DATA \
112 POST_KEY1 "=" POST_VALUE1 "&" POST_KEY2 "=" "GNU%20libmicrohttpd"
113
114#define PUT_NORMAL_SIZE 11
115/* Does not need to be very large as MHD buffer will be made smaller anyway */
116#define PUT_LARGE_SIZE (4 * 1024)
117/* The length of "very long" URI and header strings. MHD uses smaller buffer. */
118#define TEST_STRING_VLONG_LEN 8 * 1024
119
120
121#if ! CURL_AT_LEAST_VERSION (7,56,0)
122#define TEST_USE_STATIC_POST_DATA 1
123static struct curl_httppost *post_first;
124static struct curl_httppost *post_last;
125#endif /* ! CURL_AT_LEAST_VERSION(7,56,0) */
126
127static struct curl_slist *libcurl_long_header;
128
129/**
130 * Initialise long header for libcurl
131 *
132 * @return non-zero if succeed,
133 * zero if failed
134 */
135static int
136long_header_init (void)
44{ 137{
45 char *buf; 138 char *buf;
46 size_t pos; 139
47 size_t size; 140 buf = malloc (TEST_STRING_VLONG_LEN + 1);
141 if (NULL == buf)
142 {
143 fprintf (stderr, "malloc() failed "
144 "at line %d.\n", (int) __LINE__);
145 return 0;
146 }
147 buf[TEST_STRING_VLONG_LEN] = 0;
148 buf[0] = 'A';
149 memset (buf + 1, 'a', TEST_STRING_VLONG_LEN / 2 - 2);
150 buf[TEST_STRING_VLONG_LEN / 2 - 1] = ':';
151 buf[TEST_STRING_VLONG_LEN / 2] = ' ';
152 memset (buf + TEST_STRING_VLONG_LEN / 2 + 1, 'c',
153 TEST_STRING_VLONG_LEN / 2 - 1);
154 libcurl_long_header = curl_slist_append (NULL, buf);
155 free (buf);
156 if (NULL != libcurl_long_header)
157 return ! 0; /* Success exit point */
158
159 fprintf (stderr, "curl_slist_append() failed "
160 "at line %d.\n", (int) __LINE__);
161 return 0; /* Failure exit point */
162}
163
164
165/**
166 * Globally initialise test environment
167 * @return non-zero if succeed,
168 * zero if failed
169 */
170static int
171test_global_init (void)
172{
173 libcurl_long_header = NULL;
174 if (CURLE_OK != curl_global_init (CURL_GLOBAL_WIN32))
175 {
176 fprintf (stderr, "curl_global_init() failed "
177 "at line %d.\n", (int) __LINE__);
178 return 0;
179 }
180
181 if (long_header_init ())
182 {
183#ifndef TEST_USE_STATIC_POST_DATA
184 return 1; /* Success exit point */
185#else /* ! TEST_USE_STATIC_POST_DATA */
186 post_first = NULL;
187 post_last = NULL;
188 if ((CURL_FORMADD_OK !=
189 curl_formadd (&post_first, &post_last,
190 CURLFORM_PTRNAME, POST_KEY1,
191 CURLFORM_NAMELENGTH,
192 (long) MHD_STATICSTR_LEN_ (POST_KEY1),
193 CURLFORM_PTRCONTENTS, POST_VALUE1,
194#if CURL_AT_LEAST_VERSION (7,46,0)
195 CURLFORM_CONTENTLEN,
196 (curl_off_t) MHD_STATICSTR_LEN_ (POST_VALUE1),
197#else /* ! CURL_AT_LEAST_VERSION(7,46,0) */
198 CURLFORM_CONTENTSLENGTH,
199 (long) MHD_STATICSTR_LEN_ (POST_VALUE1),
200#endif /* ! CURL_AT_LEAST_VERSION(7,46,0) */
201 CURLFORM_END)) ||
202 (CURL_FORMADD_OK !=
203 curl_formadd (&post_first, &post_last,
204 CURLFORM_PTRNAME, POST_KEY2,
205 CURLFORM_NAMELENGTH,
206 (long) MHD_STATICSTR_LEN_ (POST_KEY2),
207 CURLFORM_PTRCONTENTS, POST_VALUE2,
208#if CURL_AT_LEAST_VERSION (7,46,0)
209 CURLFORM_CONTENTLEN,
210 (curl_off_t) MHD_STATICSTR_LEN_ (POST_VALUE2),
211#else /* ! CURL_AT_LEAST_VERSION(7,46,0) */
212 CURLFORM_CONTENTSLENGTH,
213 (long) MHD_STATICSTR_LEN_ (POST_VALUE2),
214#endif /* ! CURL_AT_LEAST_VERSION(7,46,0) */
215 CURLFORM_END)))
216 fprintf (stderr, "curl_formadd() failed "
217 "at line %d.\n", (int) __LINE__);
218 else
219 return 1; /* Success exit point */
220
221 if (NULL != post_first)
222 curl_formfree (post_first);
223 curl_slist_free_all (libcurl_long_header);
224#endif /* ! CURL_AT_LEAST_VERSION(7,56,0) */
225 }
226 curl_global_cleanup ();
227 return 0; /* Failure exit point */
228}
229
230
231/**
232 * Globally de-initialise test environment
233 */
234static void
235test_global_deinit (void)
236{
237#ifdef TEST_USE_STATIC_POST_DATA
238 curl_formfree (post_first);
239#endif /* TEST_USE_STATIC_POST_DATA */
240 curl_global_cleanup ();
241 if (NULL != libcurl_long_header)
242 curl_slist_free_all (libcurl_long_header);
243}
244
245
246/**
247 * libcurl callback parameters for uploads, downloads and debug callbacks
248 */
249struct CBC
250{
251 /* Upload members */
252 size_t up_pos;
253 size_t up_size;
254 /* Download members */
255 char *dn_buf;
256 size_t dn_pos;
257 size_t dn_buf_size;
258 /* Debug callback members */
259 unsigned int excess_found;
48}; 260};
49 261
262static void
263initCBC (struct CBC *libcurlcbc, char *dn_buf, size_t dn_buf_size)
264{
265 libcurlcbc->up_pos = 0;
266 if (use_put_large)
267 libcurlcbc->up_size = PUT_LARGE_SIZE;
268 else if (use_put)
269 libcurlcbc->up_size = PUT_NORMAL_SIZE;
270 else
271 libcurlcbc->up_size = 0;
272 libcurlcbc->dn_buf = dn_buf;
273 libcurlcbc->dn_pos = 0;
274 libcurlcbc->dn_buf_size = dn_buf_size;
275 libcurlcbc->excess_found = 0;
276}
277
278
279static void
280resetCBC (struct CBC *libcurlcbc)
281{
282 libcurlcbc->up_pos = 0;
283 libcurlcbc->dn_pos = 0;
284}
285
286
287static size_t
288putBuffer (void *stream, size_t item_size, size_t nitems, void *ctx)
289{
290 size_t to_fill;
291 size_t i;
292 struct CBC *cbc = ctx;
293
294 to_fill = cbc->up_size - cbc->up_pos;
295 /* Skip overflow check as the return value is valid anyway */
296 if (use_put_chunked)
297 {
298 /* Send data as several chunks */
299 if (to_fill > cbc->up_size / 3)
300 to_fill = cbc->up_size / 3;
301 }
302 if (to_fill > item_size * nitems)
303 to_fill = item_size * nitems;
304
305 /* Avoid libcurl magic numbers */
306#ifdef CURL_READFUNC_PAUSE
307 if (CURL_READFUNC_ABORT == to_fill)
308 to_fill -= 2;
309#endif /* CURL_READFUNC_PAUSE */
310#ifdef CURL_READFUNC_ABORT
311 if (CURL_READFUNC_ABORT == to_fill)
312 --to_fill;
313#endif /* CURL_READFUNC_ABORT */
314 for (i = 0; i < to_fill; ++i)
315 ((char *) stream)[i] = 'a' + (char) ((cbc->up_pos + i)
316 % (unsigned char) ('z' - 'a' + 1));
317
318 cbc->up_pos += to_fill;
319 return to_fill;
320}
321
322
50static size_t 323static size_t
51copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx) 324copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx)
52{ 325{
53 struct CBC *cbc = ctx; 326 struct CBC *cbc = ctx;
54 327
55 if (cbc->pos + size * nmemb > cbc->size) 328 if (cbc->dn_pos + size * nmemb > cbc->dn_buf_size)
56 return 0; /* overflow */ 329 return 0; /* overflow */
57 memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb); 330 memcpy (&cbc->dn_buf[cbc->dn_pos], ptr, size * nmemb);
58 cbc->pos += size * nmemb; 331 cbc->dn_pos += size * nmemb;
59 return size * nmemb; 332 return size * nmemb;
60} 333}
61 334
62 335
336#define TEST_MAGIC_MARKER0 0xFEE1C0DE
337#define TEST_MAGIC_MARKER1 (TEST_MAGIC_MARKER0 + 1)
338#define TEST_MAGIC_MARKER2 (TEST_MAGIC_MARKER0 + 2)
339
340struct content_cb_param_strct
341{
342 unsigned int magic0; /**< Must have TEST_MAGIC_MARKER0 value */
343 struct MHD_Response *response; /**< The pointer to the response structure */
344};
345
346/**
347 * MHD content reader callback that returns
348 * data in chunks.
349 */
350static ssize_t
351content_cb (void *cls, uint64_t pos, char *buf, size_t max)
352{
353 struct content_cb_param_strct *param = (struct content_cb_param_strct *) cls;
354 size_t fill_size;
355
356 if ((unsigned int) TEST_MAGIC_MARKER0 != param->magic0)
357 {
358 fprintf (stderr, "Wrong cls pointer "
359 "at line %d.\n", (int) __LINE__);
360 fflush (stderr);
361 abort ();
362 }
363
364 if (pos >= 128 * 10)
365 {
366 if (MHD_YES !=
367 MHD_add_response_footer (param->response, "Footer", "working"))
368 {
369 fprintf (stderr, "MHD_add_response_footer() failed "
370 "at line %d.\n", (int) __LINE__);
371 fflush (stderr);
372 abort ();
373 }
374 return MHD_CONTENT_READER_END_OF_STREAM;
375 }
376
377 if (128 > max)
378 fill_size = 128;
379 else
380 fill_size = max;
381 memset (buf, 'A' + (char) (unsigned int) (pos / 128), fill_size);
382
383 return (ssize_t) fill_size;
384}
385
386
387/**
388 * Deallocate memory for callback cls.
389 */
390static void
391crcf (void *ptr)
392{
393 free (ptr);
394}
395
396
397struct req_process_strct
398{
399 unsigned int magic2; /**< Must have TEST_MAGIC_MARKER2 value */
400 int is_static; /**< Non-zero if statically allocated, zero if malloc()'ed */
401 struct MHD_PostProcessor *postprocsr;
402 unsigned int post_data_sum;
403};
404
63static enum MHD_Result 405static enum MHD_Result
64ahc_echo (void *cls, 406post_iterator (void *cls,
65 struct MHD_Connection *connection, 407 enum MHD_ValueKind kind,
66 const char *url, 408 const char *key,
67 const char *method, 409 const char *filename,
68 const char *version, 410 const char *content_type,
69 const char *upload_data, size_t *upload_data_size, 411 const char *transfer_encoding,
70 void **req_cls) 412 const char *value, uint64_t off, size_t size)
413{
414 struct req_process_strct *param = (struct req_process_strct *) cls;
415 size_t i;
416
417 (void) filename; (void) content_type; (void) transfer_encoding;
418 (void) off; /* Unused. Mute compiler warnings. */
419
420 if (TEST_MAGIC_MARKER2 != param->magic2)
421 {
422 fprintf (stderr, "The 'param->magic2' has wrong value "
423 "at line %d.\n", (int) __LINE__);
424 abort ();
425 }
426
427 if (MHD_POSTDATA_KIND != kind)
428 {
429 fprintf (stderr, "The 'kind' parameter has wrong value "
430 "at line %d.\n", (int) __LINE__);
431 abort ();
432 }
433
434 if (NULL != key)
435 param->post_data_sum += (unsigned int) strlen (key);
436
437 for (i = 0; size > i; ++i)
438 param->post_data_sum += (unsigned int) (unsigned char) value[i];
439
440 return MHD_YES;
441}
442
443
444static void
445free_req_pr_data (struct req_process_strct *pr_data)
446{
447 if (NULL == pr_data)
448 return;
449 if (TEST_MAGIC_MARKER2 != pr_data->magic2)
450 {
451 fprintf (stderr, "The 'pr_data->magic2' has wrong value "
452 "at line %d.\n", (int) __LINE__);
453 abort ();
454 }
455 if (pr_data->is_static)
456 {
457 if (NULL != pr_data->postprocsr)
458 {
459 fprintf (stderr, "The 'pr_data->postprocsr' has wrong value "
460 "at line %d.\n", (int) __LINE__);
461 abort ();
462 }
463 return;
464 }
465 if (NULL != pr_data->postprocsr)
466 MHD_destroy_post_processor (pr_data->postprocsr);
467 pr_data->postprocsr = NULL;
468 free (pr_data);
469}
470
471
472struct ahc_param_strct
473{
474 unsigned int magic1; /**< Must have TEST_MAGIC_MARKER1 value */
475 unsigned int err_flag; /**< Non-zero if any error is encountered */
476 unsigned int num_replies; /**< The number of replies sent for the current request */
477};
478
479static enum MHD_Result
480send_error_response (struct MHD_Connection *connection,
481 struct ahc_param_strct *param,
482 unsigned int status_code,
483 const char *static_text,
484 const size_t static_text_len)
71{ 485{
72 static int ptr; 486 struct MHD_Response *response;
73 const char *me = cls; 487 response =
488 MHD_create_response_from_buffer_static (static_text_len,
489 static_text);
490 if (NULL != response)
491 {
492 if (MHD_YES == MHD_add_response_header (response,
493 MHD_HTTP_HEADER_CONNECTION,
494 "close"))
495 {
496 if (MHD_YES == MHD_queue_response (connection, status_code, response))
497 {
498 MHD_destroy_response (response);
499 return MHD_YES; /* Success exit point */
500 }
501 else
502 fprintf (stderr, "MHD_queue_response() failed "
503 "at line %d.\n", (int) __LINE__);
504 }
505 else
506 fprintf (stderr, "MHD_add_response_header() failed "
507 "at line %d.\n", (int) __LINE__);
508 MHD_destroy_response (response);
509 }
510 else
511 fprintf (stderr, "MHD_create_response_from_callback() failed "
512 "at line %d.\n", (int) __LINE__);
513
514 param->err_flag = 1;
515 return MHD_NO; /* Failure exit point */
516}
517
518
519static enum MHD_Result
520ahc_check (void *cls,
521 struct MHD_Connection *connection,
522 const char *url,
523 const char *method,
524 const char *version,
525 const char *upload_data, size_t *upload_data_size,
526 void **req_cls)
527{
528 static struct req_process_strct static_req_pr_data = {
529 TEST_MAGIC_MARKER2, ! 0, NULL, 0
530 };
531 struct req_process_strct *req_pr_data;
532 struct ahc_param_strct *param = (struct ahc_param_strct *) cls;
74 struct MHD_Response *response; 533 struct MHD_Response *response;
75 enum MHD_Result ret; 534 enum MHD_Result ret;
76 (void) version; (void) upload_data; (void) upload_data_size; /* Unused. Silent compiler warning. */ 535 unsigned char data_sum;
536 int is_post_req;
77 537
538 if (NULL == cls)
539 {
540 fprintf (stderr, "The 'cls' parameter is NULL "
541 "at line %d.\n", (int) __LINE__);
542 fflush (stderr);
543 abort ();
544 }
545 if ((unsigned int) TEST_MAGIC_MARKER1 != param->magic1)
546 {
547 fprintf (stderr, "The 'param->magic1' has wrong value "
548 "at line %d.\n", (int) __LINE__);
549 fflush (stderr);
550 abort ();
551 }
552 if (NULL == connection)
553 {
554 fprintf (stderr, "The 'connection' parameter is NULL "
555 "at line %d.\n", (int) __LINE__);
556 param->err_flag = 1;
557 return MHD_NO; /* Should not reply */
558 }
559 if (1)
560 { /* Simple check for 'connection' parameter validity */
561 const union MHD_ConnectionInfo *conn_info;
562 conn_info =
563 MHD_get_connection_info (connection,
564 MHD_CONNECTION_INFO_CONNECTION_TIMEOUT);
565 if (NULL == conn_info)
566 {
567 fprintf (stderr, "The 'MHD_get_connection_info' has returned NULL "
568 "at line %d.\n", (int) __LINE__);
569 param->err_flag = 1;
570 }
571 else if (MHD_TIMEOUT != conn_info->connection_timeout)
572 {
573 fprintf (stderr, "The 'MHD_get_connection_info' has returned "
574 "unexpected timeout value "
575 "at line %d.\n", (int) __LINE__);
576 param->err_flag = 1;
577 }
578 }
78 if (NULL == url) 579 if (NULL == url)
79 fprintf (stderr, "The \"url\" parameter is NULL.\n"); 580 {
581 fprintf (stderr, "The 'url' parameter is NULL "
582 "at line %d.\n", (int) __LINE__);
583 param->err_flag = 1;
584 }
80 if (NULL == method) 585 if (NULL == method)
81 fprintf (stderr, "The \"method\" parameter is NULL.\n"); 586 {
587 fprintf (stderr, "The 'method' parameter is NULL "
588 "at line %d.\n", (int) __LINE__);
589 param->err_flag = 1;
590 return MHD_NO; /* Should not reply */
591 }
82 if (NULL == version) 592 if (NULL == version)
83 fprintf (stderr, "The \"version\" parameter is NULL.\n"); 593 {
594 fprintf (stderr, "The 'version' parameter is NULL "
595 "at line %d.\n", (int) __LINE__);
596 param->err_flag = 1;
597 return MHD_NO; /* Should not reply */
598 }
84 if (NULL == upload_data_size) 599 if (NULL == upload_data_size)
85 fprintf (stderr, "The \"upload_data_size\" parameter is NULL.\n"); 600 {
601 fprintf (stderr, "The 'upload_data_size' parameter is NULL "
602 "at line %d.\n", (int) __LINE__);
603 param->err_flag = 1;
604 return MHD_NO; /* Should not reply */
605 }
86 if ((0 != *upload_data_size) && (NULL == upload_data)) 606 if ((0 != *upload_data_size) && (NULL == upload_data))
87 fprintf (stderr, "Upload data is NULL with non-zero size.\n");
88 if (0 != strcmp (me, method))
89 return MHD_NO; /* unexpected method */
90 if (&ptr != *req_cls)
91 { 607 {
92 *req_cls = &ptr; 608 fprintf (stderr, "The 'upload_data' parameter is NULL "
609 "while '*upload_data_size' is not zero "
610 "at line %d.\n", (int) __LINE__);
611 param->err_flag = 1;
612 return MHD_NO; /* Should not reply */
613 }
614 if ((NULL != upload_data) && (0 == *upload_data_size))
615 {
616 fprintf (stderr, "The 'upload_data' parameter is NOT NULL "
617 "while '*upload_data_size' is zero "
618 "at line %d.\n", (int) __LINE__);
619 param->err_flag = 1;
620 return MHD_NO; /* Should not reply */
621 }
622
623 if (0 != param->num_replies)
624 {
625 /* Phantom "second" request due to the fuzzing of the input. Refuse. */
626 return MHD_NO;
627 }
628
629 is_post_req = (0 == strcmp (method, MHD_HTTP_METHOD_POST));
630 if ((0 != strcmp (method, MHD_HTTP_METHOD_GET))
631 && (0 != strcmp (method, MHD_HTTP_METHOD_HEAD))
632 && (0 != strcmp (method, MHD_HTTP_METHOD_PUT))
633 && (! is_post_req))
634 {
635 /* Unsupported method for this callback */
636 return send_error_response (connection, param, MHD_HTTP_NOT_IMPLEMENTED,
637 METHOD_NOT_SUPPORTED,
638 MHD_STATICSTR_LEN_ (METHOD_NOT_SUPPORTED));
639 }
640
641 if (NULL == *req_cls)
642 {
643 if (! is_post_req)
644 { /* Use static memory */
645 *req_cls = &static_req_pr_data;
646 }
647 else
648 { /* POST request, use PostProcessor */
649 req_pr_data =
650 (struct req_process_strct *) malloc (sizeof (struct req_process_strct));
651 if (NULL == req_pr_data)
652 {
653 fprintf (stderr, "malloc() failed "
654 "at line %d.\n", (int) __LINE__);
655 return MHD_NO;
656 }
657 req_pr_data->magic2 = TEST_MAGIC_MARKER2;
658 req_pr_data->is_static = 0;
659 req_pr_data->post_data_sum = 0;
660 req_pr_data->postprocsr = MHD_create_post_processor (connection, 1024,
661 &post_iterator,
662 req_pr_data);
663 if (NULL == req_pr_data->postprocsr)
664 {
665 free (req_pr_data);
666 if (NULL == upload_data)
667 return send_error_response (connection, param, MHD_HTTP_BAD_REQUEST,
668 POST_DATA_BROKEN,
669 MHD_STATICSTR_LEN_ (POST_DATA_BROKEN));
670 else
671 return MHD_NO; /* Cannot handle request, broken POST */
672 }
673 *req_cls = req_pr_data;
674 }
675 if (NULL == upload_data)
676 return MHD_YES;
677 }
678 req_pr_data = (struct req_process_strct *) *req_cls;
679
680 data_sum = 0;
681 if (NULL != upload_data)
682 {
683 if (is_post_req)
684 {
685 if (MHD_YES != MHD_post_process (req_pr_data->postprocsr,
686 upload_data, *upload_data_size))
687 {
688 free_req_pr_data (req_pr_data);
689 *req_cls = NULL;
690 /* Processing upload body (context), error reply cannot be queued here */
691 return MHD_NO;
692 }
693 *upload_data_size = 0; /* All data have been processed */
694 }
695 else
696 {
697 /* Check that all 'upload_data' is addressable */
698 size_t pos;
699 for (pos = 0; pos < *upload_data_size; ++pos)
700 data_sum += (unsigned char) upload_data[pos];
701 if (0 != *upload_data_size)
702 {
703 if (3 >= *upload_data_size)
704 *upload_data_size = 0; /* Consume all incoming data */
705 else
706 *upload_data_size = data_sum % *upload_data_size; /* Pseudo-random */
707 }
708 }
93 return MHD_YES; 709 return MHD_YES;
94 } 710 }
711 if (is_post_req)
712 {
713 if (MHD_YES != MHD_destroy_post_processor (req_pr_data->postprocsr))
714 {
715 free (req_pr_data);
716 *req_cls = NULL;
717 return send_error_response (connection, param, MHD_HTTP_BAD_REQUEST,
718 POST_DATA_BROKEN,
719 MHD_STATICSTR_LEN_ (POST_DATA_BROKEN));
720 }
721 req_pr_data->postprocsr = NULL;
722 }
723 data_sum += (unsigned char) req_pr_data->post_data_sum;
724 free_req_pr_data (req_pr_data);
95 *req_cls = NULL; 725 *req_cls = NULL;
96 response = MHD_create_response_from_buffer (strlen (url), 726
97 (void *) url, 727 ret = MHD_YES;
98 MHD_RESPMEM_MUST_COPY); 728 if (use_get_chunked)
99 ret = MHD_queue_response (connection, MHD_HTTP_OK, response); 729 {
100 MHD_destroy_response (response); 730 struct content_cb_param_strct *cnt_cb_param;
101 if (ret == MHD_NO) 731 cnt_cb_param = malloc (sizeof (struct content_cb_param_strct));
732 if (NULL == cnt_cb_param)
733 {
734 fprintf (stderr, "malloc() failed "
735 "at line %d.\n", (int) __LINE__);
736 /* External error, do not rise the error flag */
737 return MHD_NO;
738 }
739 cnt_cb_param->magic0 = (unsigned int) TEST_MAGIC_MARKER0;
740 response = MHD_create_response_from_callback (MHD_SIZE_UNKNOWN,
741 1024,
742 &content_cb, cnt_cb_param,
743 &crcf);
744 if (NULL == response)
745 {
746 fprintf (stderr, "MHD_create_response_from_callback() failed "
747 "at line %d.\n", (int) __LINE__);
748 free (cnt_cb_param);
749 param->err_flag = 1;
750 ret = MHD_NO;
751 }
752 else
753 cnt_cb_param->response = response;
754 }
755 else if (use_get || use_put || use_post)
756 {
757 /* Randomly choose the response page for the POST requests */
758 if (0 == data_sum % 2)
759 response =
760 MHD_create_response_from_buffer_static (MHD_STATICSTR_LEN_ (EMPTY_PAGE),
761 EMPTY_PAGE);
762 else
763 response =
764 MHD_create_response_from_buffer_static (MHD_STATICSTR_LEN_ ( \
765 EMPTY_PAGE_ALT),
766 EMPTY_PAGE_ALT);
767
768 if (NULL == response)
769 {
770 fprintf (stderr, "MHD_create_response_from_buffer_static() failed "
771 "at line %d.\n", (int) __LINE__);
772 param->err_flag = 1;
773 ret = MHD_NO;
774 }
775 }
776 else
777 {
778 fprintf (stderr, "Response is not implemented for this test. "
779 "Internal logic is broken. "
780 "At line %d.\n", (int) __LINE__);
102 abort (); 781 abort ();
782 }
783
784 if (NULL != response)
785 {
786 if ((MHD_YES == ret) &&
787 (use_close || (! oneone && (0 != strcmp (version,
788 MHD_HTTP_VERSION_1_0)))))
789 {
790 ret = MHD_add_response_header (response,
791 MHD_HTTP_HEADER_CONNECTION,
792 "close");
793 if (MHD_YES != ret)
794 {
795 fprintf (stderr, "MHD_add_response_header() failed "
796 "at line %d.\n", (int) __LINE__);
797 param->err_flag = 1;
798 }
799 }
800 if (MHD_YES == ret)
801 {
802 ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
803 if (MHD_YES != ret)
804 {
805 fprintf (stderr, "MHD_queue_response() failed "
806 "at line %d.\n", (int) __LINE__);
807 param->err_flag = 1;
808 }
809 }
810 else
811 param->num_replies++;
812
813 MHD_destroy_response (response);
814 }
815 else
816 {
817 fprintf (stderr, "MHD_create_response_from_buffer_static() failed "
818 "at line %d.\n", (int) __LINE__);
819 ret = MHD_NO;
820 }
103 return ret; 821 return ret;
104} 822}
105 823
106 824
107static unsigned int 825static void
108testInternalGet () 826req_completed_cleanup (void *cls,
827 struct MHD_Connection *connection,
828 void **req_cls,
829 enum MHD_RequestTerminationCode toe)
830{
831 struct ahc_param_strct *param = (struct ahc_param_strct *) cls;
832 struct req_process_strct *req_pr_data = (struct req_process_strct *) *req_cls;
833 (void) connection; /* Unused. Mute compiler warning. */
834
835 if (NULL == param)
836 {
837 fprintf (stderr, "The 'cls' parameter is NULL at line %d.\n",
838 (int) __LINE__);
839 fflush (stderr);
840 abort ();
841 }
842 if ((unsigned int) TEST_MAGIC_MARKER1 != param->magic1)
843 {
844 fprintf (stderr, "The 'param->magic1' has wrong value at line %d.\n",
845 (int) __LINE__);
846 fflush (stderr);
847 abort ();
848 }
849 if (NULL == req_pr_data)
850 return; /* The data have been freed */
851 if ((unsigned int) TEST_MAGIC_MARKER2 != req_pr_data->magic2)
852 {
853 fprintf (stderr, "The 'req_pr_data->magic2' has wrong value at line %d.\n",
854 (int) __LINE__);
855 fflush (stderr);
856 abort ();
857 }
858 if (MHD_REQUEST_TERMINATED_COMPLETED_OK == toe)
859 {
860 fprintf (stderr, "The request completed successful, but request cls has"
861 "not been cleared. "
862 "At line %d.\n", (int) __LINE__);
863 param->err_flag = 1;
864 }
865 if (req_pr_data->is_static)
866 return;
867 if (NULL != req_pr_data->postprocsr)
868 MHD_destroy_post_processor (req_pr_data->postprocsr);
869 req_pr_data->postprocsr = NULL;
870 free (req_pr_data);
871 *req_cls = NULL;
872}
873
874
875/* Un-comment the next line (or use CPPFLAGS) to avoid
876 logging of the traffic with debug builds */
877/* #define TEST_NO_PRINT_TRAFFIC 1 */
878
879#ifdef _DEBUG
880#ifdef TEST_PRINT_BODY
881#ifndef TEST_PRINT_BODY_RQ
882#define TEST_PRINT_BODY_RQ 1
883#endif /* TEST_PRINT_BODY_RQ */
884#ifndef TEST_PRINT_BODY_RP
885#define TEST_PRINT_BODY_RP 1
886#endif /* TEST_PRINT_BODY_RP */
887#endif /* TEST_PRINT_BODY */
888#endif /* _DEBUG */
889
890static int
891libcurl_debug_cb (CURL *handle,
892 curl_infotype type,
893 char *data,
894 size_t size,
895 void *ctx)
896{
897 static const char excess_mark[] = "Excess found";
898 static const size_t excess_mark_len = MHD_STATICSTR_LEN_ (excess_mark);
899 struct CBC *cbc = ctx;
900 (void) handle;
901
902#if defined(_DEBUG) && ! defined(TEST_NO_PRINT_TRAFFIC)
903 switch (type)
904 {
905 case CURLINFO_TEXT:
906 fprintf (stderr, "* %.*s", (int) size, data);
907 break;
908 case CURLINFO_HEADER_IN:
909 fprintf (stderr, "< %.*s", (int) size, data);
910 break;
911 case CURLINFO_HEADER_OUT:
912 fprintf (stderr, "> %.*s", (int) size, data);
913 break;
914 case CURLINFO_DATA_IN:
915#ifdef TEST_PRINT_BODY_RP
916 fprintf (stderr, "<| %.*s\n", (int) size, data);
917#endif /* TEST_PRINT_BODY_RP */
918 break;
919 case CURLINFO_DATA_OUT:
920#ifdef TEST_PRINT_BODY_RQ
921 fprintf (stderr, ">| %.*s\n", (int) size, data);
922#endif /* TEST_PRINT_BODY_RQ */
923 break;
924 case CURLINFO_SSL_DATA_IN:
925 case CURLINFO_SSL_DATA_OUT:
926 case CURLINFO_END:
927 default:
928 break;
929 }
930#endif /* _DEBUG && ! TEST_NO_PRINT_TRAFFIC */
931 if (use_close || ! oneone)
932 {
933 /* Check for extra data only if every connection is terminated by MHD
934 after one request, otherwise MHD may react on garbage after request
935 data. */
936 if (CURLINFO_TEXT == type)
937 {
938 if ((size >= excess_mark_len) &&
939 (0 == memcmp (data, excess_mark, excess_mark_len)))
940 {
941 fprintf (stderr, "Extra data has been detected in MHD reply "
942 "at line %d.\n", (int) __LINE__);
943 cbc->excess_found++;
944 }
945 }
946 }
947 return 0;
948}
949
950
951static CURL *
952setupCURL (struct CBC *cbc, uint16_t port
953#ifndef TEST_USE_STATIC_POST_DATA
954 , curl_mime **mime
955#endif /* ! TEST_USE_STATIC_POST_DATA */
956 )
109{ 957{
110 struct MHD_Daemon *d;
111 CURL *c; 958 CURL *c;
112 char buf[2048]; 959 CURLcode e;
113 struct CBC cbc; 960 char *buf;
114 int i; 961 const char *uri_to_use;
115 962
116 cbc.buf = buf; 963#ifndef TEST_USE_STATIC_POST_DATA
117 cbc.size = 2048; 964 *mime = NULL;
118 cbc.pos = 0; 965#endif /* ! TEST_USE_STATIC_POST_DATA */
119 d = 966
120 MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD /* | MHD_USE_ERROR_LOG */, 967 if (! use_long_uri)
121 11080, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END); 968 {
122 if (d == NULL) 969 uri_to_use = TEST_BASE_URI;
123 return 1; 970 buf = NULL;
124 zzuf_socat_start (); 971 }
125 for (i = 0; i < LOOP_COUNT; i++) 972 else
126 { 973 {
127 fprintf (stderr, "."); 974 size_t pos;
128 c = curl_easy_init (); 975 buf = malloc (TEST_STRING_VLONG_LEN + 1);
129 curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:11081/hello_world"); 976 if (NULL == buf)
130 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer); 977 {
131 curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); 978 fprintf (stderr, "malloc() failed "
132 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L); 979 "at line %d.\n", (int) __LINE__);
133 curl_easy_setopt (c, CURLOPT_TIMEOUT_MS, CURL_TIMEOUT); 980 return NULL;
134 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT_MS, CURL_TIMEOUT); 981 }
135 if (oneone) 982 memcpy (buf, TEST_BASE_URI, MHD_STATICSTR_LEN_ (TEST_BASE_URI));
136 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); 983 for (pos = MHD_STATICSTR_LEN_ (TEST_BASE_URI);
984 pos < TEST_STRING_VLONG_LEN;
985 ++pos)
986 {
987 if (0 == pos % 9)
988 buf[pos] = '/';
989 else
990 buf[pos] = 'a' + (char) (unsigned char) (pos % ((unsigned char)
991 ('z' - 'a' + 1)));
992 }
993 buf[TEST_STRING_VLONG_LEN] = 0;
994 uri_to_use = buf;
995 }
996
997 c = curl_easy_init ();
998 if (NULL == c)
999 {
1000 fprintf (stderr, "curl_easy_init() failed "
1001 "at line %d.\n", (int) __LINE__);
1002 return NULL;
1003 }
1004
1005 if ((CURLE_OK == (e = curl_easy_setopt (c, CURLOPT_URL,
1006 uri_to_use))) &&
1007 (CURLE_OK == (e = curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L))) &&
1008 (CURLE_OK == (e = curl_easy_setopt (c, CURLOPT_WRITEFUNCTION,
1009 &copyBuffer))) &&
1010 (CURLE_OK == (e = curl_easy_setopt (c, CURLOPT_WRITEDATA, cbc))) &&
1011 (CURLE_OK == (e = curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT,
1012 ((long) CURL_TIMEOUT)))) &&
1013 (CURLE_OK == (e = curl_easy_setopt (c, CURLOPT_HTTP_VERSION,
1014 oneone ?
1015 CURL_HTTP_VERSION_1_1 :
1016 CURL_HTTP_VERSION_1_0))) &&
1017 (CURLE_OK == (e = curl_easy_setopt (c, CURLOPT_TIMEOUT,
1018 ((long) CURL_TIMEOUT)))) &&
1019 (CURLE_OK == (e = curl_easy_setopt (c, CURLOPT_FAILONERROR, 0L))) &&
1020#ifdef _DEBUG
1021 (CURLE_OK == (e = curl_easy_setopt (c, CURLOPT_VERBOSE, 1L))) &&
1022#endif /* _DEBUG */
1023 (CURLE_OK == (e = curl_easy_setopt (c, CURLOPT_DEBUGFUNCTION,
1024 &libcurl_debug_cb))) &&
1025 (CURLE_OK == (e = curl_easy_setopt (c, CURLOPT_DEBUGDATA,
1026 cbc))) &&
1027#if CURL_AT_LEAST_VERSION (7, 19, 4)
1028 (CURLE_OK == (e = curl_easy_setopt (c, CURLOPT_PROTOCOLS,
1029 CURLPROTO_HTTP))) &&
1030#endif /* CURL_AT_LEAST_VERSION (7, 19, 4) */
1031#if CURL_AT_LEAST_VERSION (7, 45, 0)
1032 (CURLE_OK == (e = curl_easy_setopt (c,
1033 CURLOPT_DEFAULT_PROTOCOL, "http"))) &&
1034#endif /* CURL_AT_LEAST_VERSION (7, 45, 0) */
1035#if CURL_AT_LEAST_VERSION (7, 24, 0)
1036 (CURLE_OK == (e = curl_easy_setopt (c, CURLOPT_INTERFACE,
1037 "host!127.0.0.101"))) &&
1038#else /* ! CURL_AT_LEAST_VERSION (7, 24, 0) */
1039 (CURLE_OK == (e = curl_easy_setopt (c, CURLOPT_INTERFACE,
1040 "127.0.0.101"))) &&
1041#endif /* ! CURL_AT_LEAST_VERSION (7, 24, 0) */
1042 (CURLE_OK == (e = curl_easy_setopt (c, CURLOPT_PORT, ((long) port)))) &&
1043 (CURLE_OK == (e = curl_easy_setopt (c, CURLOPT_HTTPHEADER,
1044 use_long_header ?
1045 libcurl_long_header : NULL)))
1046 )
1047 {
1048 if (NULL != buf)
1049 {
1050 free (buf);
1051 buf = NULL;
1052 }
1053 if (use_put)
1054 {
1055 if ((CURLE_OK == (e = curl_easy_setopt (c, CURLOPT_READFUNCTION,
1056 &putBuffer))) &&
1057 (CURLE_OK == (e = curl_easy_setopt (c, CURLOPT_READDATA, cbc))) &&
1058 (CURLE_OK == (e = curl_easy_setopt (c, CURLOPT_UPLOAD, (long) 1))) &&
1059 (CURLE_OK == (e = curl_easy_setopt (c, CURLOPT_INFILESIZE_LARGE,
1060 use_put_chunked ?
1061 ((curl_off_t) -1) :
1062 ((curl_off_t) cbc->up_size)))))
1063 {
1064 return c; /* Success exit point for 'use_put' */
1065 }
1066 else
1067 fprintf (stderr, "PUT-related curl_easy_setopt() failed at line %d, "
1068 "error: %s\n", (int) __LINE__,
1069 curl_easy_strerror (e));
1070 }
1071 else if (use_post)
1072 {
1073 if (! use_post_form)
1074 {
1075 if ((CURLE_OK == (e = curl_easy_setopt (c, CURLOPT_POST, (long) 1))) &&
1076 (CURLE_OK == (e = curl_easy_setopt (c, CURLOPT_POSTFIELDS,
1077 POST_URLENC_DATA))) &&
1078 (CURLE_OK ==
1079 (e = curl_easy_setopt (c, CURLOPT_POSTFIELDSIZE,
1080 MHD_STATICSTR_LEN_ (POST_URLENC_DATA)))))
1081 {
1082 return c; /* Success exit point for 'use_post' */
1083 }
1084 else
1085 fprintf (stderr,
1086 "POST-related curl_easy_setopt() failed at line %d, "
1087 "error: %s\n", (int) __LINE__,
1088 curl_easy_strerror (e));
1089 }
1090 else
1091 {
1092#ifndef TEST_USE_STATIC_POST_DATA
1093 *mime = curl_mime_init (c);
1094 if (NULL != *mime)
1095 {
1096 curl_mimepart *part;
1097 if ((NULL != (part = curl_mime_addpart (*mime))) &&
1098 (CURLE_OK == curl_mime_name (part, POST_KEY1)) &&
1099 (CURLE_OK == curl_mime_data (part, POST_VALUE1,
1100 MHD_STATICSTR_LEN_ (POST_VALUE1))) &&
1101 (NULL != (part = curl_mime_addpart (*mime))) &&
1102 (CURLE_OK == curl_mime_name (part, POST_KEY2)) &&
1103 (CURLE_OK == curl_mime_data (part, POST_VALUE2,
1104 MHD_STATICSTR_LEN_ (POST_VALUE2))))
1105 {
1106 if (CURLE_OK ==
1107 (e = curl_easy_setopt (c, CURLOPT_MIMEPOST, *mime)))
1108 return c; /* Success exit point for 'use_post' */
1109 else
1110 fprintf (stderr, "curl_easy_setopt(c, CURLOPT_MIMEPOST, mime) "
1111 "failed at line %d, error: %s\n",
1112 (int) __LINE__, curl_easy_strerror (e));
1113 }
1114 else
1115 fprintf (stderr, "curl_mime_addpart(), curl_mime_name() or "
1116 "curl_mime_data() failed.\n");
1117 }
1118 else
1119 fprintf (stderr, "curl_mime_init() failed.\n");
1120
1121#else /* TEST_USE_STATIC_POST_DATA */
1122 if (CURLE_OK == (e = curl_easy_setopt (c,
1123 CURLOPT_HTTPPOST, post_first)))
1124 {
1125 return c; /* Success exit point for 'use_post' */
1126 }
1127 else
1128 fprintf (stderr, "POST form-related curl_easy_setopt() failed, "
1129 "error: %s\n", curl_easy_strerror (e));
1130#endif /* TEST_USE_STATIC_POST_DATA */
1131 }
1132 }
137 else 1133 else
138 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); 1134 return c; /* Success exit point */
139 /* NOTE: use of CONNECTTIMEOUT without also
140 * setting NOSIGNAL results in really weird
141 * crashes on my system! */
142 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
143 curl_easy_perform (c);
144 curl_easy_cleanup (c);
145 } 1135 }
146 fprintf (stderr, "\n"); 1136 else
147 zzuf_socat_stop (); 1137 fprintf (stderr, "curl_easy_setopt() failed at line %d, "
148 MHD_stop_daemon (d); 1138 "error: %s\n", (int) __LINE__,
149 return 0; 1139 curl_easy_strerror (e));
1140
1141 curl_easy_cleanup (c);
1142#ifndef TEST_USE_STATIC_POST_DATA
1143 if (NULL != *mime)
1144 curl_mime_free (*mime);
1145#endif /* ! TEST_USE_STATIC_POST_DATA */
1146
1147 if (NULL != buf)
1148 free (buf);
1149
1150 return NULL; /* Failure exit point */
1151}
1152
1153
1154static struct MHD_Daemon *
1155start_daemon_for_test (unsigned int daemon_flags, uint16_t *pport,
1156 struct ahc_param_strct *callback_param)
1157{
1158 struct MHD_Daemon *d;
1159 struct MHD_OptionItem ops[] = {
1160 { MHD_OPTION_END, 0, NULL },
1161 { MHD_OPTION_END, 0, NULL }
1162 };
1163 callback_param->magic1 = (unsigned int) TEST_MAGIC_MARKER1;
1164 callback_param->err_flag = 0;
1165 callback_param->num_replies = 0;
1166
1167 if (use_put_large)
1168 {
1169 ops[0].option = MHD_OPTION_CONNECTION_MEMORY_LIMIT;
1170 ops[0].value = (intptr_t) (PUT_LARGE_SIZE / 4);
1171 }
1172 else if (use_long_header || use_long_uri)
1173 {
1174 ops[0].option = MHD_OPTION_CONNECTION_MEMORY_LIMIT;
1175 ops[0].value = (intptr_t) (TEST_STRING_VLONG_LEN / 2);
1176 }
1177 d = MHD_start_daemon (daemon_flags /* | MHD_USE_ERROR_LOG */,
1178 *pport, NULL, NULL,
1179 &ahc_check, callback_param,
1180 MHD_OPTION_CONNECTION_TIMEOUT,
1181 (unsigned int) MHD_TIMEOUT,
1182 MHD_OPTION_NOTIFY_COMPLETED,
1183 &req_completed_cleanup, callback_param,
1184 MHD_OPTION_ARRAY, ops,
1185 MHD_OPTION_END);
1186 if (NULL == d)
1187 {
1188 fprintf (stderr, "MHD_start_daemon() failed "
1189 "at line %d.\n", (int) __LINE__);
1190 return NULL;
1191 }
1192 /* Do not use accept4() as only accept() is intercepted by zzuf */
1193 MHD_avoid_accept4_ (d);
1194
1195 if (0 == *pport)
1196 {
1197 const union MHD_DaemonInfo *dinfo;
1198
1199 dinfo = MHD_get_daemon_info (d,
1200 MHD_DAEMON_INFO_BIND_PORT);
1201 if ( (NULL == dinfo) ||
1202 (0 == dinfo->port) )
1203 {
1204 fprintf (stderr, "MHD_get_daemon_info() failed "
1205 "at line %d.\n", (int) __LINE__);
1206 MHD_stop_daemon (d);
1207 return NULL;
1208 }
1209 *pport = dinfo->port;
1210 }
1211 return d;
1212}
1213
1214
1215static void
1216print_test_starting (unsigned int daemon_flags)
1217{
1218 fflush (stderr);
1219 if (0 != (MHD_USE_INTERNAL_POLLING_THREAD & daemon_flags))
1220 {
1221 if (0 != (MHD_USE_THREAD_PER_CONNECTION & daemon_flags))
1222 {
1223 if (0 != (MHD_USE_POLL & daemon_flags))
1224 printf ("\nStarting test with internal polling by poll() and "
1225 "thread-per-connection.\n");
1226 else
1227 printf ("\nStarting test with internal polling by select() and "
1228 "thread-per-connection.\n");
1229 }
1230 else
1231 {
1232 if (0 != (MHD_USE_POLL & daemon_flags))
1233 printf ("\nStarting test with internal polling by poll().\n");
1234 else if (0 != (MHD_USE_EPOLL & daemon_flags))
1235 printf ("\nStarting test with internal polling by 'epoll'.\n");
1236 else
1237 printf ("\nStarting test with internal polling by select().\n");
1238 }
1239 }
1240 else
1241 {
1242 if (0 != (MHD_USE_EPOLL & daemon_flags))
1243 printf ("\nStarting test with external polling and internal 'epoll'.\n");
1244 else
1245 printf ("\nStarting test with external polling.\n");
1246 }
1247 fflush (stdout);
150} 1248}
151 1249
152 1250
153static unsigned int 1251static unsigned int
154testMultithreadedGet () 1252testInternalPolling (uint16_t *pport, unsigned int daemon_flags)
155{ 1253{
156 struct MHD_Daemon *d; 1254 struct MHD_Daemon *d;
157 CURL *c; 1255 CURL *c;
158 char buf[2048]; 1256 char buf[2048];
159 struct CBC cbc; 1257 struct CBC cbc;
160 int i; 1258 struct ahc_param_strct callback_param;
161 1259 unsigned int ret;
162 cbc.buf = buf; 1260#ifndef TEST_USE_STATIC_POST_DATA
163 cbc.size = 2048; 1261 curl_mime *mime;
164 cbc.pos = 0; 1262#endif /* ! TEST_USE_STATIC_POST_DATA */
165 d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION 1263
166 | MHD_USE_INTERNAL_POLLING_THREAD /* | MHD_USE_ERROR_LOG */, 1264 if (0 == (MHD_USE_INTERNAL_POLLING_THREAD & daemon_flags))
167 11080, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END); 1265 {
1266 fprintf (stderr, "Wrong internal flags, the test is broken. "
1267 "At line %d.\n", (int) __LINE__);
1268 abort (); /* Wrong flags, error in code */
1269 }
1270
1271 print_test_starting (daemon_flags);
1272 initCBC (&cbc, buf, sizeof(buf));
1273 d = start_daemon_for_test (daemon_flags, pport, &callback_param);
168 if (d == NULL) 1274 if (d == NULL)
169 return 16; 1275 return 1;
170 zzuf_socat_start (); 1276
171 for (i = 0; i < LOOP_COUNT; i++) 1277 ret = 0;
172 { 1278 c = setupCURL (&cbc, *pport
173 fprintf (stderr, "."); 1279#ifndef TEST_USE_STATIC_POST_DATA
174 c = curl_easy_init (); 1280 , &mime
175 curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:11081/hello_world"); 1281#endif /* ! TEST_USE_STATIC_POST_DATA */
176 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer); 1282 );
177 curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); 1283 if (NULL != c)
178 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L); 1284 {
179 curl_easy_setopt (c, CURLOPT_TIMEOUT_MS, CURL_TIMEOUT); 1285 int i;
180 if (oneone) 1286
181 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); 1287 for (i = dry_run ? LOOP_COUNT : 0; i < LOOP_COUNT; i++)
182 else 1288 {
183 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); 1289 fprintf (stderr, ".");
184 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT_MS, CURL_TIMEOUT); 1290 callback_param.num_replies = 0;
185 /* NOTE: use of CONNECTTIMEOUT without also 1291 resetCBC (&cbc);
186 * setting NOSIGNAL results in really weird 1292 /* Run libcurl without checking the result */
187 * crashes on my system! */ 1293 curl_easy_perform (c);
188 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L); 1294 fflush (stderr);
189 curl_easy_perform (c); 1295 }
190 curl_easy_cleanup (c); 1296 curl_easy_cleanup (c);
1297#ifndef TEST_USE_STATIC_POST_DATA
1298 if (NULL != mime)
1299 curl_mime_free (mime);
1300#endif /* ! TEST_USE_STATIC_POST_DATA */
1301 }
1302 else
1303 ret = 99; /* Not an MHD error */
1304
1305 if ((0 == ret) && callback_param.err_flag)
1306 {
1307 fprintf (stderr, "One or more errors have been detected by "
1308 "access handler callback function. "
1309 "At line %d.\n", (int) __LINE__);
1310 ret = 1;
1311 }
1312 else if ((0 == ret) && cbc.excess_found)
1313 {
1314 fprintf (stderr, "The extra reply data have been detected one "
1315 "or more times. "
1316 "At line %d.\n", (int) __LINE__);
1317 ret = 1;
191 } 1318 }
1319
192 fprintf (stderr, "\n"); 1320 fprintf (stderr, "\n");
193 zzuf_socat_stop ();
194 MHD_stop_daemon (d); 1321 MHD_stop_daemon (d);
195 return 0; 1322 fflush (stderr);
1323 return ret;
196} 1324}
197 1325
198 1326
199static unsigned int 1327static unsigned int
200testExternalGet () 1328testExternalPolling (uint16_t *pport, unsigned int daemon_flags)
201{ 1329{
202 struct MHD_Daemon *d; 1330 struct MHD_Daemon *d;
203 CURL *c; 1331 CURLM *multi;
204 char buf[2048]; 1332 char buf[2048];
205 struct CBC cbc; 1333 struct CBC cbc;
206 CURLM *multi; 1334 struct ahc_param_strct callback_param;
207 CURLMcode mret; 1335 unsigned int ret;
208 fd_set rs; 1336#ifndef TEST_USE_STATIC_POST_DATA
209 fd_set ws; 1337 curl_mime *mime;
210 fd_set es; 1338#endif /* ! TEST_USE_STATIC_POST_DATA */
211 int max; 1339
212 int running; 1340 if (0 != (MHD_USE_INTERNAL_POLLING_THREAD & daemon_flags))
213 time_t start; 1341 {
214 struct timeval tv; 1342 fprintf (stderr, "Wrong internal flags, the test is broken. "
215 int i; 1343 "At line %d.\n", (int) __LINE__);
216 1344 abort (); /* Wrong flags, error in code */
217 multi = NULL; 1345 }
218 cbc.buf = buf; 1346
219 cbc.size = 2048; 1347 print_test_starting (daemon_flags);
220 cbc.pos = 0; 1348 initCBC (&cbc, buf, sizeof(buf));
221 d = MHD_start_daemon (MHD_NO_FLAG /* | MHD_USE_ERROR_LOG */, 1349 d = start_daemon_for_test (daemon_flags, pport, &callback_param);
222 11080, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END);
223 if (d == NULL) 1350 if (d == NULL)
224 return 256; 1351 return 1;
1352
1353 ret = 0;
225 multi = curl_multi_init (); 1354 multi = curl_multi_init ();
226 if (multi == NULL) 1355 if (multi == NULL)
227 { 1356 {
228 MHD_stop_daemon (d); 1357 fprintf (stderr, "curl_multi_init() failed "
229 return 512; 1358 "at line %d.\n", (int) __LINE__);
1359 ret = 99; /* Not an MHD error */
230 } 1360 }
231 zzuf_socat_start (); 1361 else
232 for (i = 0; i < LOOP_COUNT; i++)
233 { 1362 {
234 fprintf (stderr, "."); 1363 CURL *c;
235 c = curl_easy_init (); 1364 c = setupCURL (&cbc, *pport
236 curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:11081/hello_world"); 1365#ifndef TEST_USE_STATIC_POST_DATA
237 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer); 1366 , &mime
238 curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); 1367#endif /* ! TEST_USE_STATIC_POST_DATA */
239 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L); 1368 );
240 if (oneone) 1369
241 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); 1370 if (NULL == c)
1371 ret = 99; /* Not an MHD error */
242 else 1372 else
243 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
244 curl_easy_setopt (c, CURLOPT_TIMEOUT_MS, CURL_TIMEOUT);
245 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT_MS, CURL_TIMEOUT);
246 /* NOTE: use of CONNECTTIMEOUT without also
247 * setting NOSIGNAL results in really weird
248 * crashes on my system! */
249 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
250 mret = curl_multi_add_handle (multi, c);
251 if (mret != CURLM_OK)
252 { 1373 {
253 curl_multi_cleanup (multi); 1374 int i;
254 curl_easy_cleanup (c); 1375
255 zzuf_socat_stop (); 1376 for (i = dry_run ? LOOP_COUNT : 0;
256 MHD_stop_daemon (d); 1377 (i < LOOP_COUNT) && (0 == ret); i++)
257 return 1024;
258 }
259 start = time (NULL);
260 while ((time (NULL) - start < 5) && (c != NULL))
261 {
262 max = 0;
263 FD_ZERO (&rs);
264 FD_ZERO (&ws);
265 FD_ZERO (&es);
266 curl_multi_perform (multi, &running);
267 mret = curl_multi_fdset (multi, &rs, &ws, &es, &max);
268 if (mret != CURLM_OK)
269 {
270 curl_multi_remove_handle (multi, c);
271 curl_multi_cleanup (multi);
272 curl_easy_cleanup (c);
273 zzuf_socat_stop ();
274 MHD_stop_daemon (d);
275 return 2048;
276 }
277 if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &max))
278 {
279 curl_multi_remove_handle (multi, c);
280 curl_multi_cleanup (multi);
281 curl_easy_cleanup (c);
282 zzuf_socat_stop ();
283 MHD_stop_daemon (d);
284 return 4096;
285 }
286 tv.tv_sec = 0;
287 tv.tv_usec = 1000;
288 select (max + 1, &rs, &ws, &es, &tv);
289 curl_multi_perform (multi, &running);
290 if (running == 0)
291 { 1378 {
292 curl_multi_info_read (multi, &running); 1379 CURLMcode mret;
293 curl_multi_remove_handle (multi, c); 1380
294 curl_easy_cleanup (c); 1381 /* The same 'multi' handle will be used in transfers so
295 c = NULL; 1382 connection will be reused.
1383 The same 'easy' handle is added (and removed later) to (re-)start
1384 the same transfer. */
1385 mret = curl_multi_add_handle (multi, c);
1386 if (CURLM_OK != mret)
1387 {
1388 fprintf (stderr, "curl_multi_add_handle() failed at %d, "
1389 "error: %s\n", (int) __LINE__,
1390 curl_multi_strerror (mret));
1391 ret = 99; /* Not an MHD error */
1392 }
1393 else
1394 {
1395 time_t start;
1396
1397 fprintf (stderr, ".");
1398 callback_param.num_replies = 0;
1399 resetCBC (&cbc);
1400 start = time (NULL);
1401 do
1402 {
1403 fd_set rs;
1404 fd_set ws;
1405 fd_set es;
1406 int maxfd_curl;
1407 MHD_socket maxfd_mhd;
1408 int maxfd;
1409 int running;
1410 struct timeval tv;
1411
1412 maxfd_curl = 0;
1413 maxfd_mhd = MHD_INVALID_SOCKET;
1414 FD_ZERO (&rs);
1415 FD_ZERO (&ws);
1416 FD_ZERO (&es);
1417 curl_multi_perform (multi, &running);
1418 if (0 == running)
1419 {
1420 int msgs_left;
1421 do
1422 {
1423 (void) curl_multi_info_read (multi, &msgs_left);
1424 } while (0 != msgs_left);
1425 break; /* The transfer has been finished */
1426 }
1427 mret = curl_multi_fdset (multi, &rs, &ws, &es, &maxfd_curl);
1428 if (CURLM_OK != mret)
1429 {
1430 fprintf (stderr, "curl_multi_fdset() failed at line %d, "
1431 "error: %s\n", (int) __LINE__,
1432 curl_multi_strerror (mret));
1433 ret = 99; /* Not an MHD error */
1434 break;
1435 }
1436 if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &maxfd_mhd))
1437 {
1438 fprintf (stderr, "MHD_get_fdset() failed "
1439 "at line %d.\n", (int) __LINE__);
1440 ret = 1;
1441 break;
1442 }
1443#ifndef MHD_WINSOCK_SOCKETS
1444 if ((int) maxfd_mhd > maxfd_curl)
1445 maxfd = (int) maxfd_mhd;
1446 else
1447#endif /* ! MHD_WINSOCK_SOCKETS */
1448 maxfd = maxfd_curl;
1449 tv.tv_sec = 0;
1450 tv.tv_usec = 100 * 1000;
1451 if (0 == MHD_get_timeout64s (d))
1452 tv.tv_usec = 0;
1453 else
1454 {
1455 long curl_to = -1;
1456 curl_multi_timeout (multi, &curl_to);
1457 if (0 == curl_to)
1458 tv.tv_usec = 0;
1459 }
1460 if (-1 == select (maxfd + 1, &rs, &ws, &es, &tv))
1461 {
1462#ifdef MHD_POSIX_SOCKETS
1463 if (EINTR != errno)
1464 fprintf (stderr, "Unexpected select() error "
1465 "at line %d.\n", (int) __LINE__);
1466#else /* ! MHD_POSIX_SOCKETS */
1467 if ((WSAEINVAL != WSAGetLastError ()) ||
1468 (0 != rs.fd_count) || (0 != ws.fd_count) ||
1469 (0 != es.fd_count))
1470 fprintf (stderr, "Unexpected select() error "
1471 "at line %d.\n", (int) __LINE__);
1472 Sleep ((unsigned long) tv.tv_usec / 1000);
1473#endif /* ! MHD_POSIX_SOCKETS */
1474 }
1475 MHD_run (d);
1476 } while (time (NULL) - start <= MHD_TIMEOUT);
1477 /* Remove 'easy' handle from 'multi' handle to
1478 * restart the transfer or to finish. */
1479 curl_multi_remove_handle (multi, c);
1480 }
296 } 1481 }
297 MHD_run (d);
298 }
299 if (c != NULL)
300 {
301 curl_multi_remove_handle (multi, c);
302 curl_easy_cleanup (c); 1482 curl_easy_cleanup (c);
303 } 1483 }
1484 curl_multi_cleanup (multi);
1485#ifndef TEST_USE_STATIC_POST_DATA
1486 if (NULL != mime)
1487 curl_mime_free (mime);
1488#endif /* ! TEST_USE_STATIC_POST_DATA */
304 } 1489 }
1490
1491 if ((0 == ret) && callback_param.err_flag)
1492 {
1493 fprintf (stderr, "One or more errors have been detected by "
1494 "access handler callback function. "
1495 "At line %d.\n", (int) __LINE__);
1496 ret = 1;
1497 }
1498 else if ((0 == ret) && cbc.excess_found)
1499 {
1500 fprintf (stderr, "The extra reply data have been detected one "
1501 "or more times. "
1502 "At line %d.\n", (int) __LINE__);
1503 ret = 1;
1504 }
1505
305 fprintf (stderr, "\n"); 1506 fprintf (stderr, "\n");
306 curl_multi_cleanup (multi);
307 zzuf_socat_stop ();
308 MHD_stop_daemon (d); 1507 MHD_stop_daemon (d);
309 return 0; 1508 return 0;
310} 1509}
311 1510
312 1511
1512static unsigned int
1513run_all_checks (void)
1514{
1515 uint16_t port;
1516 unsigned int testRes;
1517 unsigned int ret = 0;
1518
1519 if (MHD_are_sanitizers_enabled_ ())
1520 {
1521 fprintf (stderr, "The test does not work with sanitizers. "
1522 "At line %d.\n", (int) __LINE__);
1523 return 77;
1524 }
1525 if (! MHD_is_avoid_accept4_possible_ ())
1526 {
1527 fprintf (stderr,
1528 "Non-debug build of MHD on this platform use accept4() function. "
1529 "Test with zzuf is not possible. "
1530 "At line %d.\n", (int) __LINE__);
1531 return 77;
1532 }
1533 if (MHD_NO != MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT))
1534 port = 0; /* Use system automatic assignment */
1535 else
1536 {
1537 port = 4010; /* Use predefined port, may break parallel testing of another MHD build */
1538 if (oneone)
1539 port += 100;
1540 if (use_long_uri)
1541 port += 30;
1542 else if (use_long_header)
1543 port += 35;
1544 else if (use_get_chunked)
1545 port += 0;
1546 else if (use_get)
1547 port += 5;
1548 else if (use_post_form)
1549 port += 10;
1550 else if (use_post)
1551 port += 15;
1552 else if (use_put_large)
1553 port += 20;
1554 else if (use_put_chunked)
1555 port += 25;
1556 }
1557
1558 if (! dry_run && (MHD_YES == MHD_is_feature_supported (MHD_FEATURE_THREADS)))
1559 {
1560 testRes = testInternalPolling (&port, MHD_USE_SELECT_INTERNALLY);
1561 if ((77 == testRes) || (99 == testRes))
1562 return testRes;
1563 ret += testRes;
1564 testRes = testInternalPolling (&port, MHD_USE_SELECT_INTERNALLY
1565 | MHD_USE_THREAD_PER_CONNECTION);
1566 if ((77 == testRes) || (99 == testRes))
1567 return testRes;
1568 ret += testRes;
1569
1570 if (MHD_YES == MHD_is_feature_supported (MHD_FEATURE_POLL))
1571 {
1572 testRes = testInternalPolling (&port, MHD_USE_POLL_INTERNALLY);
1573 if ((77 == testRes) || (99 == testRes))
1574 return testRes;
1575 ret += testRes;
1576 testRes = testInternalPolling (&port, MHD_USE_POLL_INTERNALLY
1577 | MHD_USE_THREAD_PER_CONNECTION);
1578 if ((77 == testRes) || (99 == testRes))
1579 return testRes;
1580 ret += testRes;
1581 }
1582
1583 if (MHD_YES == MHD_is_feature_supported (MHD_FEATURE_EPOLL))
1584 {
1585 testRes = testInternalPolling (&port, MHD_USE_EPOLL_INTERNALLY);
1586 if ((77 == testRes) || (99 == testRes))
1587 return testRes;
1588 }
1589 }
1590 testRes = testExternalPolling (&port, MHD_NO_FLAG);
1591 if ((77 == testRes) || (99 == testRes))
1592 return testRes;
1593 ret += testRes;
1594
1595 return ret;
1596}
1597
1598
313int 1599int
314main (int argc, char *const *argv) 1600main (int argc, char *const *argv)
315{ 1601{
316 unsigned int errorCount = 0; 1602 unsigned int res;
317 (void) argc; /* Unused. Silent compiler warning. */ 1603
1604 oneone = ! has_in_name (argv[0], "10");
1605 use_get = has_in_name (argv[0], "_get");
1606 use_get_chunked = has_in_name (argv[0], "_get_chunked");
1607 use_put = has_in_name (argv[0], "_put");
1608 use_put_large = has_in_name (argv[0], "_put_large");
1609 use_put_chunked = has_in_name (argv[0], "_put_chunked");
1610 use_post = has_in_name (argv[0], "_post");
1611 use_post_form = has_in_name (argv[0], "_post_form");
1612 use_long_header = has_in_name (argv[0], "_long_header");
1613 use_long_uri = has_in_name (argv[0], "_long_uri");
1614 use_close = has_in_name (argv[0], "_close");
318 1615
319 oneone = (NULL != strrchr (argv[0], (int) '/')) ? 1616 dry_run = has_param (argc, argv, "--dry-run") ||
320 (NULL != strstr (strrchr (argv[0], (int) '/'), "11")) : 0; 1617 has_param (argc, argv, "-n");
321 if (0 != curl_global_init (CURL_GLOBAL_WIN32)) 1618
322 return 2; 1619 if (1 !=
323 if (MHD_YES == MHD_is_feature_supported (MHD_FEATURE_THREADS)) 1620 ((use_get ? 1 : 0) + (use_put ? 1 : 0) + (use_post ? 1 : 0)))
324 { 1621 {
325 errorCount += testInternalGet (); 1622 fprintf (stderr, "Wrong test name '%s': no or multiple indications "
326 errorCount += testMultithreadedGet (); 1623 "for the test type.\n", argv[0] ? argv[0] : "(NULL)");
1624 return 99;
327 } 1625 }
328 errorCount += testExternalGet (); 1626
329 if (errorCount != 0) 1627 /* zzuf cannot bypass exit values.
330 fprintf (stderr, "Error (code: %u)\n", errorCount); 1628 Unless 'dry run' is used, do not return errors for external error
331 curl_global_cleanup (); 1629 conditions (like out-of-memory) as they will be reported as test failures. */
332 return (0 == errorCount) ? 0 : 1; /* 0 == pass */ 1630 if (! test_global_init ())
1631 return dry_run ? 99 : 0;
1632 res = run_all_checks ();
1633 test_global_deinit ();
1634 if (99 == res)
1635 return dry_run ? 99 : 0;
1636 if (77 == res)
1637 return dry_run ? 77 : 0;
1638 return (0 == res) ? 0 : 1; /* 0 == pass */
333} 1639}
diff --git a/src/testzzuf/test_get_chunked.c b/src/testzzuf/test_get_chunked.c
deleted file mode 100644
index 8013494f..00000000
--- a/src/testzzuf/test_get_chunked.c
+++ /dev/null
@@ -1,364 +0,0 @@
1/*
2 This file is part of libmicrohttpd
3 Copyright (C) 2007, 2008 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 2, 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., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19*/
20
21/**
22 * @file daemontest_get_chunked.c
23 * @brief Testcase for libmicrohttpd GET operations with chunked content encoding
24 * @author Christian Grothoff
25 */
26
27#include "MHD_config.h"
28#include "platform.h"
29#include <curl/curl.h>
30#include <microhttpd.h>
31#include <stdlib.h>
32#include <string.h>
33#include <time.h>
34
35#ifndef WINDOWS
36#include <unistd.h>
37#endif
38
39#include "socat.c"
40
41struct CBC
42{
43 char *buf;
44 size_t pos;
45 size_t size;
46};
47
48static size_t
49copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx)
50{
51 struct CBC *cbc = ctx;
52
53 if (cbc->pos + size * nmemb > cbc->size)
54 return 0; /* overflow */
55 memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb);
56 cbc->pos += size * nmemb;
57 return size * nmemb;
58}
59
60
61/**
62 * MHD content reader callback that returns
63 * data in chunks.
64 */
65static ssize_t
66crc (void *cls, uint64_t pos, char *buf, size_t max)
67{
68 struct MHD_Response **responseptr = cls;
69
70 if (pos == 128 * 10)
71 {
72 MHD_add_response_header (*responseptr, "Footer", "working");
73 return MHD_CONTENT_READER_END_OF_STREAM;
74 }
75 if (max < 128)
76 abort (); /* should not happen in this testcase... */
77 memset (buf, 'A' + (pos / 128), 128);
78 return 128;
79}
80
81
82/**
83 * Dummy function that does nothing.
84 */
85static void
86crcf (void *ptr)
87{
88 free (ptr);
89}
90
91
92static enum MHD_Result
93ahc_echo (void *cls,
94 struct MHD_Connection *connection,
95 const char *url,
96 const char *method,
97 const char *version,
98 const char *upload_data, size_t *upload_data_size, void **req_cls)
99{
100 static int aptr;
101 const char *me = cls;
102 struct MHD_Response *response;
103 struct MHD_Response **responseptr;
104 enum MHD_Result ret;
105
106 (void) url;
107 (void) version; /* Unused. Silent compiler warning. */
108 (void) upload_data;
109 (void) upload_data_size; /* Unused. Silent compiler warning. */
110
111 if (NULL == url)
112 fprintf (stderr, "The \"url\" parameter is NULL.\n");
113 if (NULL == method)
114 fprintf (stderr, "The \"method\" parameter is NULL.\n");
115 if (NULL == version)
116 fprintf (stderr, "The \"version\" parameter is NULL.\n");
117 if (NULL == upload_data_size)
118 fprintf (stderr, "The \"upload_data_size\" parameter is NULL.\n");
119 if ((0 != *upload_data_size) && (NULL == upload_data))
120 fprintf (stderr, "Upload data is NULL with non-zero size.\n");
121 if (0 != strcmp (me, method))
122 return MHD_NO; /* unexpected method */
123 if (&aptr != *req_cls)
124 {
125 /* do never respond on first call */
126 *req_cls = &aptr;
127 return MHD_YES;
128 }
129 responseptr = malloc (sizeof (struct MHD_Response *));
130 if (NULL == responseptr)
131 return MHD_NO;
132 response = MHD_create_response_from_callback (MHD_SIZE_UNKNOWN,
133 1024,
134 &crc, responseptr, &crcf);
135 if (NULL == response)
136 {
137 free (responseptr);
138 return MHD_NO;
139 }
140 *responseptr = response;
141 ret = MHD_queue_response (connection,
142 MHD_HTTP_OK,
143 response);
144 MHD_destroy_response (response);
145 return ret;
146}
147
148
149static unsigned int
150testInternalGet ()
151{
152 struct MHD_Daemon *d;
153 CURL *c;
154 char buf[2048];
155 struct CBC cbc;
156 int i;
157
158 cbc.buf = buf;
159 cbc.size = 2048;
160 cbc.pos = 0;
161 d =
162 MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD /* | MHD_USE_ERROR_LOG */,
163 11080, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END);
164 if (d == NULL)
165 return 1;
166 zzuf_socat_start ();
167 for (i = 0; i < LOOP_COUNT; i++)
168 {
169 fprintf (stderr, ".");
170 c = curl_easy_init ();
171 curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:11081/hello_world");
172 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
173 curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
174 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L);
175 curl_easy_setopt (c, CURLOPT_TIMEOUT_MS, CURL_TIMEOUT);
176 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT_MS, CURL_TIMEOUT);
177 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
178 /* NOTE: use of CONNECTTIMEOUT without also
179 * setting NOSIGNAL results in really weird
180 * crashes on my system! */
181 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
182 curl_easy_perform (c);
183 curl_easy_cleanup (c);
184 }
185 fprintf (stderr, "\n");
186 zzuf_socat_stop ();
187 MHD_stop_daemon (d);
188 return 0;
189}
190
191
192static unsigned int
193testMultithreadedGet ()
194{
195 struct MHD_Daemon *d;
196 CURL *c;
197 char buf[2048];
198 struct CBC cbc;
199 int i;
200
201 cbc.buf = buf;
202 cbc.size = 2048;
203 cbc.pos = 0;
204 d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION
205 | MHD_USE_INTERNAL_POLLING_THREAD /* | MHD_USE_ERROR_LOG */,
206 11080, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END);
207 if (d == NULL)
208 return 16;
209 zzuf_socat_start ();
210 for (i = 0; i < LOOP_COUNT; i++)
211 {
212 fprintf (stderr, ".");
213 c = curl_easy_init ();
214 curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:11081/hello_world");
215 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
216 curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
217 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L);
218 curl_easy_setopt (c, CURLOPT_TIMEOUT_MS, CURL_TIMEOUT);
219 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
220 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT_MS, CURL_TIMEOUT);
221 /* NOTE: use of CONNECTTIMEOUT without also
222 * setting NOSIGNAL results in really weird
223 * crashes on my system! */
224 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
225 curl_easy_perform (c);
226 curl_easy_cleanup (c);
227 }
228 fprintf (stderr, "\n");
229 zzuf_socat_stop ();
230 MHD_stop_daemon (d);
231 return 0;
232}
233
234
235static unsigned int
236testExternalGet ()
237{
238 struct MHD_Daemon *d;
239 CURL *c;
240 char buf[2048];
241 struct CBC cbc;
242 CURLM *multi;
243 CURLMcode mret;
244 fd_set rs;
245 fd_set ws;
246 fd_set es;
247 int max;
248 int running;
249 time_t start;
250 struct timeval tv;
251 int i;
252
253 multi = NULL;
254 cbc.buf = buf;
255 cbc.size = 2048;
256 cbc.pos = 0;
257 d = MHD_start_daemon (MHD_NO_FLAG /* | MHD_USE_ERROR_LOG */,
258 11080, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END);
259 if (d == NULL)
260 return 256;
261 multi = curl_multi_init ();
262 if (multi == NULL)
263 {
264 MHD_stop_daemon (d);
265 return 512;
266 }
267 zzuf_socat_start ();
268 for (i = 0; i < LOOP_COUNT; i++)
269 {
270 fprintf (stderr, ".");
271 c = curl_easy_init ();
272 curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:11081/hello_world");
273 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
274 curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
275 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L);
276 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
277 curl_easy_setopt (c, CURLOPT_TIMEOUT_MS, CURL_TIMEOUT);
278 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT_MS, CURL_TIMEOUT);
279 /* NOTE: use of CONNECTTIMEOUT without also
280 * setting NOSIGNAL results in really weird
281 * crashes on my system! */
282 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
283 mret = curl_multi_add_handle (multi, c);
284 if (mret != CURLM_OK)
285 {
286 curl_multi_cleanup (multi);
287 curl_easy_cleanup (c);
288 zzuf_socat_stop ();
289 MHD_stop_daemon (d);
290 return 1024;
291 }
292 start = time (NULL);
293 while ((time (NULL) - start < 5) && (c != NULL))
294 {
295 max = 0;
296 FD_ZERO (&rs);
297 FD_ZERO (&ws);
298 FD_ZERO (&es);
299 curl_multi_perform (multi, &running);
300 mret = curl_multi_fdset (multi, &rs, &ws, &es, &max);
301 if (mret != CURLM_OK)
302 {
303 curl_multi_remove_handle (multi, c);
304 curl_multi_cleanup (multi);
305 curl_easy_cleanup (c);
306 zzuf_socat_stop ();
307 MHD_stop_daemon (d);
308 return 2048;
309 }
310 if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &max))
311 {
312 curl_multi_remove_handle (multi, c);
313 curl_multi_cleanup (multi);
314 curl_easy_cleanup (c);
315 zzuf_socat_stop ();
316 MHD_stop_daemon (d);
317 return 4096;
318 }
319 tv.tv_sec = 0;
320 tv.tv_usec = 1000;
321 select (max + 1, &rs, &ws, &es, &tv);
322 curl_multi_perform (multi, &running);
323 if (running == 0)
324 {
325 curl_multi_info_read (multi, &running);
326 curl_multi_remove_handle (multi, c);
327 curl_easy_cleanup (c);
328 c = NULL;
329 }
330 MHD_run (d);
331 }
332 if (c != NULL)
333 {
334 curl_multi_remove_handle (multi, c);
335 curl_easy_cleanup (c);
336 }
337 }
338 fprintf (stderr, "\n");
339 curl_multi_cleanup (multi);
340 zzuf_socat_stop ();
341 MHD_stop_daemon (d);
342 return 0;
343}
344
345
346int
347main (int argc, char *const *argv)
348{
349 unsigned int errorCount = 0;
350 (void) argc; (void) argv; /* Unused. Silent compiler warning. */
351
352 if (0 != curl_global_init (CURL_GLOBAL_WIN32))
353 return 2;
354 if (MHD_YES == MHD_is_feature_supported (MHD_FEATURE_THREADS))
355 {
356 errorCount += testInternalGet ();
357 errorCount += testMultithreadedGet ();
358 }
359 errorCount += testExternalGet ();
360 if (errorCount != 0)
361 fprintf (stderr, "Error (code: %u)\n", errorCount);
362 curl_global_cleanup ();
363 return (0 == errorCount) ? 0 : 1; /* 0 == pass */
364}
diff --git a/src/testzzuf/test_long_header.c b/src/testzzuf/test_long_header.c
deleted file mode 100644
index c0259398..00000000
--- a/src/testzzuf/test_long_header.c
+++ /dev/null
@@ -1,265 +0,0 @@
1/*
2 This file is part of libmicrohttpd
3 Copyright (C) 2007, 2008 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 2, 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., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19*/
20
21/**
22 * @file test_long_header.c
23 * @brief Testcase for libmicrohttpd handling of very long headers
24 * @author Christian Grothoff
25 */
26
27#include "MHD_config.h"
28#include "platform.h"
29#include <curl/curl.h>
30#include <microhttpd.h>
31#include <stdlib.h>
32#include <string.h>
33#include <time.h>
34
35#ifndef WINDOWS
36#include <unistd.h>
37#endif
38
39#include "socat.c"
40
41/**
42 * We will set the memory available per connection to
43 * half of this value, so the actual value does not have
44 * to be big at all...
45 */
46#define VERY_LONG (1024 * 10)
47
48static int oneone;
49
50static enum MHD_Result
51apc_all (void *cls, const struct sockaddr *addr, socklen_t addrlen)
52{
53 (void) cls; (void) addr; (void) addrlen; /* Unused. Silent compiler warning. */
54 return MHD_YES;
55}
56
57
58struct CBC
59{
60 char *buf;
61 size_t pos;
62 size_t size;
63};
64
65static size_t
66copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx)
67{
68 (void) ptr; (void) ctx; /* Unused. Silent compiler warning. */
69 return size * nmemb;
70}
71
72
73static enum MHD_Result
74ahc_echo (void *cls,
75 struct MHD_Connection *connection,
76 const char *url,
77 const char *method,
78 const char *version,
79 const char *upload_data, size_t *upload_data_size,
80 void **req_cls)
81{
82 const char *me = cls;
83 struct MHD_Response *response;
84 enum MHD_Result ret;
85 (void) version; (void) upload_data; /* Unused. Silent compiler warning. */
86 (void) upload_data_size; (void) req_cls; /* Unused. Silent compiler warning. */
87
88 if (NULL == url)
89 fprintf (stderr, "The \"url\" parameter is NULL.\n");
90 if (NULL == method)
91 fprintf (stderr, "The \"method\" parameter is NULL.\n");
92 if (NULL == version)
93 fprintf (stderr, "The \"version\" parameter is NULL.\n");
94 if (NULL == upload_data_size)
95 fprintf (stderr, "The \"upload_data_size\" parameter is NULL.\n");
96 if ((0 != *upload_data_size) && (NULL == upload_data))
97 fprintf (stderr, "Upload data is NULL with non-zero size.\n");
98 if (0 != strcmp (me, method))
99 return MHD_NO; /* unexpected method */
100 response = MHD_create_response_from_buffer (strlen (url),
101 (void *) url,
102 MHD_RESPMEM_MUST_COPY);
103 ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
104 MHD_destroy_response (response);
105 return ret;
106}
107
108
109static unsigned int
110testLongUrlGet ()
111{
112 struct MHD_Daemon *d;
113 CURL *c;
114 char buf[2048];
115 struct CBC cbc;
116 char *url;
117 int i;
118
119 cbc.buf = buf;
120 cbc.size = 2048;
121 cbc.pos = 0;
122 d =
123 MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD /* | MHD_USE_ERROR_LOG */,
124 11080,
125 &apc_all,
126 NULL,
127 &ahc_echo,
128 "GET",
129 MHD_OPTION_CONNECTION_MEMORY_LIMIT,
130 (size_t) (VERY_LONG / 2), MHD_OPTION_END);
131
132 if (d == NULL)
133 return 1;
134 zzuf_socat_start ();
135 for (i = 0; i < LOOP_COUNT; i++)
136 {
137 fprintf (stderr, ".");
138
139 c = curl_easy_init ();
140 url = malloc (VERY_LONG);
141 if (NULL == url)
142 {
143 zzuf_socat_stop ();
144 return 1;
145 }
146 memset (url, 'a', VERY_LONG);
147 url[VERY_LONG - 1] = '\0';
148 memcpy (url, "http://127.0.0.1:11081/",
149 strlen ("http://127.0.0.1:11081/"));
150 curl_easy_setopt (c, CURLOPT_URL, url);
151 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
152 curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
153 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L);
154 curl_easy_setopt (c, CURLOPT_TIMEOUT_MS, CURL_TIMEOUT);
155 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT_MS, CURL_TIMEOUT);
156 if (oneone)
157 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
158 else
159 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
160 /* NOTE: use of CONNECTTIMEOUT without also
161 * setting NOSIGNAL results in really weird
162 * crashes on my system! */
163 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
164 curl_easy_perform (c);
165 curl_easy_cleanup (c);
166 free (url);
167 }
168 fprintf (stderr, "\n");
169 zzuf_socat_stop ();
170
171 MHD_stop_daemon (d);
172 return 0;
173}
174
175
176static unsigned int
177testLongHeaderGet ()
178{
179 struct MHD_Daemon *d;
180 CURL *c;
181 char buf[2048];
182 struct CBC cbc;
183 char *url;
184 struct curl_slist *header = NULL;
185 int i;
186
187 cbc.buf = buf;
188 cbc.size = 2048;
189 cbc.pos = 0;
190 d =
191 MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD /* | MHD_USE_ERROR_LOG */,
192 11080,
193 &apc_all,
194 NULL,
195 &ahc_echo,
196 "GET",
197 MHD_OPTION_CONNECTION_MEMORY_LIMIT,
198 (size_t) (VERY_LONG / 2), MHD_OPTION_END);
199 if (d == NULL)
200 return 16;
201 zzuf_socat_start ();
202 for (i = 0; i < LOOP_COUNT; i++)
203 {
204 fprintf (stderr, ".");
205 c = curl_easy_init ();
206 url = malloc (VERY_LONG);
207 if (NULL == url)
208 {
209 zzuf_socat_stop ();
210 curl_easy_cleanup (c);
211 return 16;
212 }
213 memset (url, 'a', VERY_LONG);
214 url[VERY_LONG - 1] = '\0';
215 url[VERY_LONG / 2] = ':';
216 url[VERY_LONG / 2 + 1] = ' ';
217 header = curl_slist_append (header, url);
218
219 curl_easy_setopt (c, CURLOPT_HTTPHEADER, header);
220 curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:11081/hello_world");
221 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
222 curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
223 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L);
224 curl_easy_setopt (c, CURLOPT_TIMEOUT_MS, CURL_TIMEOUT);
225 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT_MS, CURL_TIMEOUT);
226 if (oneone)
227 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
228 else
229 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
230 /* NOTE: use of CONNECTTIMEOUT without also
231 * setting NOSIGNAL results in really weird
232 * crashes on my system! */
233 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
234 curl_easy_perform (c);
235 curl_slist_free_all (header);
236 header = NULL;
237 curl_easy_cleanup (c);
238 free (url);
239 }
240 fprintf (stderr, "\n");
241 zzuf_socat_stop ();
242
243 MHD_stop_daemon (d);
244 return 0;
245}
246
247
248int
249main (int argc, char *const *argv)
250{
251 unsigned int errorCount = 0;
252 const char *sl;
253 (void) argc; /* Unused. Silent compiler warning. */
254
255 sl = strrchr (argv[0], (int) '/');
256 oneone = (NULL != sl) ? (NULL != strstr (sl, "11")) : 0;
257 if (0 != curl_global_init (CURL_GLOBAL_WIN32))
258 return 2;
259 errorCount += testLongUrlGet ();
260 errorCount += testLongHeaderGet ();
261 if (errorCount != 0)
262 fprintf (stderr, "Error (code: %u)\n", errorCount);
263 curl_global_cleanup ();
264 return (0 == errorCount) ? 0 : 1; /* 0 == pass */
265}
diff --git a/src/testzzuf/test_post.c b/src/testzzuf/test_post.c
deleted file mode 100644
index 895c5fce..00000000
--- a/src/testzzuf/test_post.c
+++ /dev/null
@@ -1,416 +0,0 @@
1/*
2 This file is part of libmicrohttpd
3 Copyright (C) 2007, 2008 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 2, 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., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19*/
20
21/**
22 * @file test_post.c
23 * @brief Testcase for libmicrohttpd POST operations using URL-encoding
24 * @author Christian Grothoff
25 */
26
27#include "MHD_config.h"
28#include "platform.h"
29#include <curl/curl.h>
30#include <microhttpd.h>
31#include <stdlib.h>
32#include <string.h>
33#include <time.h>
34
35#ifndef WINDOWS
36#include <unistd.h>
37#endif
38
39
40#include "socat.c"
41
42#define POST_DATA "name=daniel&project=curl"
43
44static int oneone;
45
46struct CBC
47{
48 char *buf;
49 size_t pos;
50 size_t size;
51};
52
53
54static void
55completed_cb (void *cls,
56 struct MHD_Connection *connection,
57 void **req_cls,
58 enum MHD_RequestTerminationCode toe)
59{
60 struct MHD_PostProcessor *pp = *req_cls;
61 (void) cls; (void) connection; (void) toe; /* Unused. Silent compiler warning. */
62
63 if (NULL != pp)
64 MHD_destroy_post_processor (pp);
65 *req_cls = NULL;
66}
67
68
69static size_t
70copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx)
71{
72 struct CBC *cbc = ctx;
73
74 if (cbc->pos + size * nmemb > cbc->size)
75 return 0; /* overflow */
76 memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb);
77 cbc->pos += size * nmemb;
78 return size * nmemb;
79}
80
81
82/**
83 * Note that this post_iterator is not perfect
84 * in that it fails to support incremental processing.
85 * (to be fixed in the future)
86 */
87static enum MHD_Result
88post_iterator (void *cls,
89 enum MHD_ValueKind kind,
90 const char *key,
91 const char *filename,
92 const char *content_type,
93 const char *transfer_encoding,
94 const char *value, uint64_t off, size_t size)
95{
96 int *eok = cls;
97 (void) kind; (void) filename; (void) content_type; /* Unused. Silent compiler warning. */
98 (void) transfer_encoding; (void) off; /* Unused. Silent compiler warning. */
99
100 if ((0 == strcmp (key, "name")) &&
101 (size == strlen ("daniel")) && (0 == strncmp (value, "daniel", size)))
102 (*eok) |= 1;
103 if ((0 == strcmp (key, "project")) &&
104 (size == strlen ("curl")) && (0 == strncmp (value, "curl", size)))
105 (*eok) |= 2;
106 return MHD_YES;
107}
108
109
110static enum MHD_Result
111ahc_echo (void *cls,
112 struct MHD_Connection *connection,
113 const char *url,
114 const char *method,
115 const char *version,
116 const char *upload_data, size_t *upload_data_size,
117 void **req_cls)
118{
119 static int eok;
120 struct MHD_Response *response;
121 struct MHD_PostProcessor *pp;
122 enum MHD_Result ret;
123 (void) cls; (void) version; /* Unused. Silent compiler warning. */
124
125 if (NULL == url)
126 fprintf (stderr, "The \"url\" parameter is NULL.\n");
127 if (NULL == method)
128 fprintf (stderr, "The \"method\" parameter is NULL.\n");
129 if (NULL == version)
130 fprintf (stderr, "The \"version\" parameter is NULL.\n");
131 if (NULL == upload_data_size)
132 fprintf (stderr, "The \"upload_data_size\" parameter is NULL.\n");
133 if ((0 != *upload_data_size) && (NULL == upload_data))
134 fprintf (stderr, "Upload data is NULL with non-zero size.\n");
135 if (0 != strcmp ("POST", method))
136 {
137 return MHD_NO; /* unexpected method */
138 }
139 pp = *req_cls;
140 if (pp == NULL)
141 {
142 eok = 0;
143 pp = MHD_create_post_processor (connection, 1024, &post_iterator, &eok);
144 *req_cls = pp;
145 }
146 MHD_post_process (pp, upload_data, *upload_data_size);
147 if ((eok == 3) && (0 == *upload_data_size))
148 {
149 response = MHD_create_response_from_buffer (strlen (url),
150 (void *) url,
151 MHD_RESPMEM_MUST_COPY);
152 ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
153 MHD_destroy_response (response);
154 MHD_destroy_post_processor (pp);
155 *req_cls = NULL;
156 return ret;
157 }
158 *upload_data_size = 0;
159 return MHD_YES;
160}
161
162
163static unsigned int
164testInternalPost ()
165{
166 struct MHD_Daemon *d;
167 CURL *c;
168 char buf[2048];
169 struct CBC cbc;
170 int i;
171
172 cbc.buf = buf;
173 cbc.size = 2048;
174 cbc.pos = 0;
175 d =
176 MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD /* | MHD_USE_ERROR_LOG */,
177 11080, NULL, NULL, &ahc_echo, NULL,
178 MHD_OPTION_NOTIFY_COMPLETED, &completed_cb, NULL,
179 MHD_OPTION_END);
180 if (d == NULL)
181 return 1;
182 zzuf_socat_start ();
183 for (i = 0; i < LOOP_COUNT; i++)
184 {
185 fprintf (stderr, ".");
186
187 c = curl_easy_init ();
188 curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:11081/hello_world");
189 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
190 curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
191 curl_easy_setopt (c, CURLOPT_POSTFIELDS, POST_DATA);
192 curl_easy_setopt (c, CURLOPT_POSTFIELDSIZE, strlen (POST_DATA));
193 curl_easy_setopt (c, CURLOPT_POST, 1L);
194 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L);
195 curl_easy_setopt (c, CURLOPT_TIMEOUT_MS, CURL_TIMEOUT);
196 if (oneone)
197 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
198 else
199 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
200 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT_MS, CURL_TIMEOUT);
201 /* NOTE: use of CONNECTTIMEOUT without also
202 * setting NOSIGNAL results in really weird
203 * crashes on my system! */
204 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
205 curl_easy_perform (c);
206 curl_easy_cleanup (c);
207 }
208 fprintf (stderr, "\n");
209 zzuf_socat_stop ();
210 MHD_stop_daemon (d);
211
212 return 0;
213}
214
215
216static unsigned int
217testMultithreadedPost ()
218{
219 struct MHD_Daemon *d;
220 CURL *c;
221 char buf[2048];
222 struct CBC cbc;
223 int i;
224
225 cbc.buf = buf;
226 cbc.size = 2048;
227 cbc.pos = 0;
228 d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION
229 | MHD_USE_INTERNAL_POLLING_THREAD /* | MHD_USE_ERROR_LOG */,
230 11080, NULL, NULL, &ahc_echo, NULL,
231 MHD_OPTION_NOTIFY_COMPLETED, &completed_cb, NULL,
232 MHD_OPTION_END);
233 if (d == NULL)
234 return 16;
235
236 zzuf_socat_start ();
237 for (i = 0; i < LOOP_COUNT; i++)
238 {
239 fprintf (stderr, ".");
240
241 c = curl_easy_init ();
242 curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:11081/hello_world");
243 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
244 curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
245 curl_easy_setopt (c, CURLOPT_POSTFIELDS, POST_DATA);
246 curl_easy_setopt (c, CURLOPT_POSTFIELDSIZE, strlen (POST_DATA));
247 curl_easy_setopt (c, CURLOPT_POST, 1L);
248 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L);
249 curl_easy_setopt (c, CURLOPT_TIMEOUT_MS, CURL_TIMEOUT);
250 if (oneone)
251 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
252 else
253 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
254 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT_MS, CURL_TIMEOUT);
255 /* NOTE: use of CONNECTTIMEOUT without also
256 * setting NOSIGNAL results in really weird
257 * crashes on my system! */
258 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
259 curl_easy_perform (c);
260 curl_easy_cleanup (c);
261 }
262 fprintf (stderr, "\n");
263 zzuf_socat_stop ();
264
265 MHD_stop_daemon (d);
266 return 0;
267}
268
269
270static unsigned int
271testExternalPost ()
272{
273 struct MHD_Daemon *d;
274 CURL *c;
275 char buf[2048];
276 struct CBC cbc;
277 CURLM *multi;
278 CURLMcode mret;
279 fd_set rs;
280 fd_set ws;
281 fd_set es;
282 int max;
283 int running;
284 time_t start;
285 struct timeval tv;
286 int i;
287
288 multi = NULL;
289 cbc.buf = buf;
290 cbc.size = 2048;
291 cbc.pos = 0;
292 d = MHD_start_daemon (MHD_NO_FLAG /* | MHD_USE_ERROR_LOG */,
293 1082, NULL, NULL, &ahc_echo, NULL,
294 MHD_OPTION_NOTIFY_COMPLETED, &completed_cb, NULL,
295 MHD_OPTION_END);
296 if (d == NULL)
297 return 256;
298 multi = curl_multi_init ();
299 if (multi == NULL)
300 {
301 MHD_stop_daemon (d);
302 return 512;
303 }
304
305 zzuf_socat_start ();
306 for (i = 0; i < LOOP_COUNT; i++)
307 {
308 fprintf (stderr, ".");
309
310
311 c = curl_easy_init ();
312 curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:1082/hello_world");
313 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
314 curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
315 curl_easy_setopt (c, CURLOPT_POSTFIELDS, POST_DATA);
316 curl_easy_setopt (c, CURLOPT_POSTFIELDSIZE, strlen (POST_DATA));
317 curl_easy_setopt (c, CURLOPT_POST, 1L);
318 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L);
319 curl_easy_setopt (c, CURLOPT_TIMEOUT_MS, CURL_TIMEOUT);
320 if (oneone)
321 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
322 else
323 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
324 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT_MS, CURL_TIMEOUT);
325 /* NOTE: use of CONNECTTIMEOUT without also
326 * setting NOSIGNAL results in really weird
327 * crashes on my system! */
328 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
329
330
331 mret = curl_multi_add_handle (multi, c);
332 if (mret != CURLM_OK)
333 {
334 curl_multi_cleanup (multi);
335 curl_easy_cleanup (c);
336 zzuf_socat_stop ();
337 MHD_stop_daemon (d);
338 return 1024;
339 }
340 start = time (NULL);
341 while ((time (NULL) - start < 5) && (c != NULL))
342 {
343 max = 0;
344 FD_ZERO (&rs);
345 FD_ZERO (&ws);
346 FD_ZERO (&es);
347 curl_multi_perform (multi, &running);
348 mret = curl_multi_fdset (multi, &rs, &ws, &es, &max);
349 if (mret != CURLM_OK)
350 {
351 curl_multi_remove_handle (multi, c);
352 curl_multi_cleanup (multi);
353 curl_easy_cleanup (c);
354 zzuf_socat_stop ();
355 MHD_stop_daemon (d);
356 return 2048;
357 }
358 if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &max))
359 {
360 curl_multi_remove_handle (multi, c);
361 curl_multi_cleanup (multi);
362 curl_easy_cleanup (c);
363 zzuf_socat_stop ();
364 MHD_stop_daemon (d);
365 return 4096;
366 }
367 tv.tv_sec = 0;
368 tv.tv_usec = 1000;
369 select (max + 1, &rs, &ws, &es, &tv);
370 curl_multi_perform (multi, &running);
371 if (running == 0)
372 {
373 curl_multi_info_read (multi, &running);
374 curl_multi_remove_handle (multi, c);
375 curl_easy_cleanup (c);
376 c = NULL;
377 }
378 MHD_run (d);
379 }
380 if (c != NULL)
381 {
382 curl_multi_remove_handle (multi, c);
383 curl_easy_cleanup (c);
384 }
385
386 }
387 fprintf (stderr, "\n");
388 curl_multi_cleanup (multi);
389 zzuf_socat_stop ();
390
391 MHD_stop_daemon (d);
392 return 0;
393}
394
395
396int
397main (int argc, char *const *argv)
398{
399 unsigned int errorCount = 0;
400 (void) argc; /* Unused. Silent compiler warning. */
401
402 oneone = (NULL != strrchr (argv[0], (int) '/')) ?
403 (NULL != strstr (strrchr (argv[0], (int) '/'), "11")) : 0;
404 if (0 != curl_global_init (CURL_GLOBAL_WIN32))
405 return 2;
406 if (MHD_YES == MHD_is_feature_supported (MHD_FEATURE_THREADS))
407 {
408 errorCount += testInternalPost ();
409 errorCount += testMultithreadedPost ();
410 }
411 errorCount += testExternalPost ();
412 if (errorCount != 0)
413 fprintf (stderr, "Error (code: %u)\n", errorCount);
414 curl_global_cleanup ();
415 return (0 == errorCount) ? 0 : 1; /* 0 == pass */
416}
diff --git a/src/testzzuf/test_post_form.c b/src/testzzuf/test_post_form.c
deleted file mode 100644
index b16b0cdd..00000000
--- a/src/testzzuf/test_post_form.c
+++ /dev/null
@@ -1,432 +0,0 @@
1/*
2 This file is part of libmicrohttpd
3 Copyright (C) 2007, 2008 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 2, 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., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19*/
20
21/**
22 * @file test_post_form.c
23 * @brief Testcase for libmicrohttpd POST operations using multipart/postform data
24 * @author Christian Grothoff
25 */
26
27#include "MHD_config.h"
28#include "platform.h"
29#include <curl/curl.h>
30#include <microhttpd.h>
31#include <stdlib.h>
32#include <string.h>
33#include <time.h>
34
35#ifndef WINDOWS
36#include <unistd.h>
37#endif
38
39
40#include "socat.c"
41
42static int oneone;
43
44struct CBC
45{
46 char *buf;
47 size_t pos;
48 size_t size;
49};
50
51
52static void
53completed_cb (void *cls,
54 struct MHD_Connection *connection,
55 void **req_cls,
56 enum MHD_RequestTerminationCode toe)
57{
58 struct MHD_PostProcessor *pp = *req_cls;
59 (void) cls; (void) connection; (void) toe; /* Unused. Silent compiler warning. */
60
61 if (NULL != pp)
62 MHD_destroy_post_processor (pp);
63 *req_cls = NULL;
64}
65
66
67static size_t
68copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx)
69{
70 struct CBC *cbc = ctx;
71
72 if (cbc->pos + size * nmemb > cbc->size)
73 return 0; /* overflow */
74 memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb);
75 cbc->pos += size * nmemb;
76 return size * nmemb;
77}
78
79
80/**
81 * Note that this post_iterator is not perfect
82 * in that it fails to support incremental processing.
83 * (to be fixed in the future)
84 */
85static enum MHD_Result
86post_iterator (void *cls,
87 enum MHD_ValueKind kind,
88 const char *key,
89 const char *filename,
90 const char *content_type,
91 const char *transfer_encoding,
92 const char *value, uint64_t off, size_t size)
93{
94 int *eok = cls;
95 (void) kind; (void) filename; (void) content_type; /* Unused. Silent compiler warning. */
96 (void) transfer_encoding; (void) off; /* Unused. Silent compiler warning. */
97
98 if (key == NULL)
99 return MHD_YES;
100#if 0
101 fprintf (stderr, "PI sees %s-%.*s\n", key, size, value);
102#endif
103 if ((0 == strcmp (key, "name")) &&
104 (size == strlen ("daniel")) && (0 == strncmp (value, "daniel", size)))
105 (*eok) |= 1;
106 if ((0 == strcmp (key, "project")) &&
107 (size == strlen ("curl")) && (0 == strncmp (value, "curl", size)))
108 (*eok) |= 2;
109 return MHD_YES;
110}
111
112
113static enum MHD_Result
114ahc_echo (void *cls,
115 struct MHD_Connection *connection,
116 const char *url,
117 const char *method,
118 const char *version,
119 const char *upload_data, size_t *upload_data_size,
120 void **req_cls)
121{
122 static int eok;
123 struct MHD_Response *response;
124 struct MHD_PostProcessor *pp;
125 enum MHD_Result ret;
126 (void) cls; (void) version; /* Unused. Silent compiler warning. */
127
128 if (NULL == url)
129 fprintf (stderr, "The \"url\" parameter is NULL.\n");
130 if (NULL == method)
131 fprintf (stderr, "The \"method\" parameter is NULL.\n");
132 if (NULL == version)
133 fprintf (stderr, "The \"version\" parameter is NULL.\n");
134 if (NULL == upload_data_size)
135 fprintf (stderr, "The \"upload_data_size\" parameter is NULL.\n");
136 if ((0 != *upload_data_size) && (NULL == upload_data))
137 fprintf (stderr, "Upload data is NULL with non-zero size.\n");
138 if (0 != strcmp ("POST", method))
139 {
140 return MHD_NO; /* unexpected method */
141 }
142 pp = *req_cls;
143 if (pp == NULL)
144 {
145 eok = 0;
146 pp = MHD_create_post_processor (connection, 1024, &post_iterator, &eok);
147 if (pp == NULL)
148 return MHD_NO;
149 *req_cls = pp;
150 }
151 MHD_post_process (pp, upload_data, *upload_data_size);
152 if ((eok == 3) && (0 == *upload_data_size))
153 {
154 response = MHD_create_response_from_buffer (strlen (url),
155 (void *) url,
156 MHD_RESPMEM_MUST_COPY);
157 ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
158 MHD_destroy_response (response);
159 MHD_destroy_post_processor (pp);
160 *req_cls = NULL;
161 return ret;
162 }
163 *upload_data_size = 0;
164 return MHD_YES;
165}
166
167
168static struct curl_httppost *
169make_form ()
170{
171 struct curl_httppost *post = NULL;
172 struct curl_httppost *last = NULL;
173
174 curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
175 CURLFORM_COPYCONTENTS, "daniel", CURLFORM_END);
176 curl_formadd (&post, &last, CURLFORM_COPYNAME, "project",
177 CURLFORM_COPYCONTENTS, "curl", CURLFORM_END);
178 return post;
179}
180
181
182static unsigned int
183testInternalPost ()
184{
185 struct MHD_Daemon *d;
186 CURL *c;
187 char buf[2048];
188 struct CBC cbc;
189 int i;
190 struct curl_httppost *pd;
191
192 cbc.buf = buf;
193 cbc.size = 2048;
194 cbc.pos = 0;
195 d =
196 MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD /* | MHD_USE_ERROR_LOG */,
197 11080, NULL, NULL, &ahc_echo, NULL,
198 MHD_OPTION_NOTIFY_COMPLETED, &completed_cb, NULL,
199 MHD_OPTION_END);
200 if (d == NULL)
201 return 1;
202 zzuf_socat_start ();
203 for (i = 0; i < LOOP_COUNT; i++)
204 {
205 fprintf (stderr, ".");
206 c = curl_easy_init ();
207 curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:11081/hello_world");
208 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
209 curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
210 pd = make_form ();
211 curl_easy_setopt (c, CURLOPT_HTTPPOST, pd);
212 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L);
213 curl_easy_setopt (c, CURLOPT_TIMEOUT_MS, CURL_TIMEOUT);
214 if (oneone)
215 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
216 else
217 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
218 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT_MS, CURL_TIMEOUT);
219 /* NOTE: use of CONNECTTIMEOUT without also
220 * setting NOSIGNAL results in really weird
221 * crashes on my system! */
222 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
223 curl_easy_perform (c);
224 curl_easy_cleanup (c);
225 curl_formfree (pd);
226 }
227 fprintf (stderr, "\n");
228 zzuf_socat_stop ();
229 MHD_stop_daemon (d);
230 return 0;
231}
232
233
234static unsigned int
235testMultithreadedPost ()
236{
237 struct MHD_Daemon *d;
238 CURL *c;
239 char buf[2048];
240 struct CBC cbc;
241 int i;
242 struct curl_httppost *pd;
243
244 cbc.buf = buf;
245 cbc.size = 2048;
246 cbc.pos = 0;
247 d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION
248 | MHD_USE_INTERNAL_POLLING_THREAD /* | MHD_USE_ERROR_LOG */,
249 11080, NULL, NULL, &ahc_echo, NULL,
250 MHD_OPTION_NOTIFY_COMPLETED, &completed_cb, NULL,
251 MHD_OPTION_END);
252 if (d == NULL)
253 return 16;
254 zzuf_socat_start ();
255 for (i = 0; i < LOOP_COUNT; i++)
256 {
257 fprintf (stderr, ".");
258 c = curl_easy_init ();
259 curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:11081/hello_world");
260 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
261 curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
262 pd = make_form ();
263 curl_easy_setopt (c, CURLOPT_HTTPPOST, pd);
264 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L);
265 curl_easy_setopt (c, CURLOPT_TIMEOUT_MS, CURL_TIMEOUT);
266 if (oneone)
267 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
268 else
269 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
270 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT_MS, CURL_TIMEOUT);
271 /* NOTE: use of CONNECTTIMEOUT without also
272 * setting NOSIGNAL results in really weird
273 * crashes on my system! */
274 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
275 curl_easy_perform (c);
276 curl_easy_cleanup (c);
277 curl_formfree (pd);
278 }
279 fprintf (stderr, "\n");
280 zzuf_socat_stop ();
281 MHD_stop_daemon (d);
282 return 0;
283}
284
285
286static unsigned int
287testExternalPost ()
288{
289 struct MHD_Daemon *d;
290 CURL *c;
291 char buf[2048];
292 struct CBC cbc;
293 CURLM *multi;
294 CURLMcode mret;
295 fd_set rs;
296 fd_set ws;
297 fd_set es;
298 int max;
299 int running;
300 time_t start;
301 struct timeval tv;
302 struct curl_httppost *pd;
303 int i;
304
305 multi = NULL;
306 cbc.buf = buf;
307 cbc.size = 2048;
308 cbc.pos = 0;
309 d = MHD_start_daemon (MHD_NO_FLAG /* | MHD_USE_ERROR_LOG */,
310 1082, NULL, NULL, &ahc_echo, NULL,
311 MHD_OPTION_NOTIFY_COMPLETED, &completed_cb, NULL,
312 MHD_OPTION_END);
313 if (d == NULL)
314 return 256;
315 multi = curl_multi_init ();
316 if (multi == NULL)
317 {
318 MHD_stop_daemon (d);
319 return 512;
320 }
321 zzuf_socat_start ();
322 for (i = 0; i < LOOP_COUNT; i++)
323 {
324 fprintf (stderr, ".");
325
326 c = curl_easy_init ();
327 curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:1082/hello_world");
328 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
329 curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
330 pd = make_form ();
331 curl_easy_setopt (c, CURLOPT_HTTPPOST, pd);
332 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L);
333 curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
334 if (oneone)
335 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
336 else
337 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
338 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L);
339 /* NOTE: use of CONNECTTIMEOUT without also
340 * setting NOSIGNAL results in really weird
341 * crashes on my system! */
342 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
343
344 mret = curl_multi_add_handle (multi, c);
345 if (mret != CURLM_OK)
346 {
347 curl_multi_cleanup (multi);
348 curl_formfree (pd);
349 curl_easy_cleanup (c);
350 zzuf_socat_stop ();
351 MHD_stop_daemon (d);
352 return 1024;
353 }
354 start = time (NULL);
355 while ((time (NULL) - start < 5) && (c != NULL))
356 {
357 max = 0;
358 FD_ZERO (&rs);
359 FD_ZERO (&ws);
360 FD_ZERO (&es);
361 curl_multi_perform (multi, &running);
362 mret = curl_multi_fdset (multi, &rs, &ws, &es, &max);
363 if (mret != CURLM_OK)
364 {
365 curl_multi_remove_handle (multi, c);
366 curl_multi_cleanup (multi);
367 curl_easy_cleanup (c);
368 zzuf_socat_stop ();
369 MHD_stop_daemon (d);
370 curl_formfree (pd);
371 return 2048;
372 }
373 if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &max))
374 {
375 curl_multi_remove_handle (multi, c);
376 curl_multi_cleanup (multi);
377 curl_easy_cleanup (c);
378 curl_formfree (pd);
379 zzuf_socat_stop ();
380 MHD_stop_daemon (d);
381 return 4096;
382 }
383 tv.tv_sec = 0;
384 tv.tv_usec = 1000;
385 select (max + 1, &rs, &ws, &es, &tv);
386 curl_multi_perform (multi, &running);
387 if (running == 0)
388 {
389 curl_multi_info_read (multi, &running);
390 curl_multi_remove_handle (multi, c);
391 curl_easy_cleanup (c);
392 c = NULL;
393 }
394 MHD_run (d);
395 }
396 if (c != NULL)
397 {
398 curl_multi_remove_handle (multi, c);
399 curl_easy_cleanup (c);
400 }
401 curl_formfree (pd);
402 }
403 fprintf (stderr, "\n");
404 zzuf_socat_stop ();
405 curl_multi_cleanup (multi);
406
407 MHD_stop_daemon (d);
408 return 0;
409}
410
411
412int
413main (int argc, char *const *argv)
414{
415 unsigned int errorCount = 0;
416 (void) argc; /* Unused. Silent compiler warning. */
417
418 oneone = (NULL != strrchr (argv[0], (int) '/')) ?
419 (NULL != strstr (strrchr (argv[0], (int) '/'), "11")) : 0;
420 if (0 != curl_global_init (CURL_GLOBAL_WIN32))
421 return 2;
422 if (MHD_YES == MHD_is_feature_supported (MHD_FEATURE_THREADS))
423 {
424 errorCount += testInternalPost ();
425 errorCount += testMultithreadedPost ();
426 }
427 errorCount += testExternalPost ();
428 if (errorCount != 0)
429 fprintf (stderr, "Error (code: %u)\n", errorCount);
430 curl_global_cleanup ();
431 return (0 == errorCount) ? 0 : 1; /* 0 == pass */
432}
diff --git a/src/testzzuf/test_put.c b/src/testzzuf/test_put.c
deleted file mode 100644
index 9e3749d1..00000000
--- a/src/testzzuf/test_put.c
+++ /dev/null
@@ -1,380 +0,0 @@
1/*
2 This file is part of libmicrohttpd
3 Copyright (C) 2007, 2008 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 2, 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., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19*/
20
21/**
22 * @file test_put.c
23 * @brief Testcase for libmicrohttpd PUT operations
24 * @author Christian Grothoff
25 */
26
27#include "MHD_config.h"
28#include "platform.h"
29#include <curl/curl.h>
30#include <microhttpd.h>
31#include <stdlib.h>
32#include <string.h>
33#include <time.h>
34
35#ifndef WINDOWS
36#include <unistd.h>
37#endif
38
39
40#include "socat.c"
41
42static int oneone;
43
44struct CBC
45{
46 char *buf;
47 size_t pos;
48 size_t size;
49};
50
51static size_t
52putBuffer (void *stream, size_t size, size_t nmemb, void *ptr)
53{
54 unsigned int *pos = ptr;
55 unsigned int wrt;
56
57 wrt = size * nmemb;
58 if (wrt > 8 - (*pos))
59 wrt = 8 - (*pos);
60 memcpy (stream, &("Hello123"[*pos]), wrt);
61 (*pos) += wrt;
62 return wrt;
63}
64
65
66static size_t
67copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx)
68{
69 struct CBC *cbc = ctx;
70
71 if (cbc->pos + size * nmemb > cbc->size)
72 return 0; /* overflow */
73 memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb);
74 cbc->pos += size * nmemb;
75 return size * nmemb;
76}
77
78
79static enum MHD_Result
80ahc_echo (void *cls,
81 struct MHD_Connection *connection,
82 const char *url,
83 const char *method,
84 const char *version,
85 const char *upload_data, size_t *upload_data_size,
86 void **req_cls)
87{
88 int *done = cls;
89 struct MHD_Response *response;
90 enum MHD_Result ret;
91 (void) version; (void) req_cls; /* Unused. Silent compiler warning. */
92
93 if (NULL == url)
94 fprintf (stderr, "The \"url\" parameter is NULL.\n");
95 if (NULL == method)
96 fprintf (stderr, "The \"method\" parameter is NULL.\n");
97 if (NULL == version)
98 fprintf (stderr, "The \"version\" parameter is NULL.\n");
99 if (NULL == upload_data_size)
100 fprintf (stderr, "The \"upload_data_size\" parameter is NULL.\n");
101 if ((0 != *upload_data_size) && (NULL == upload_data))
102 fprintf (stderr, "Upload data is NULL with non-zero size.\n");
103 if (0 != strcmp ("PUT", method))
104 return MHD_NO; /* unexpected method */
105 if ((*done) == 0)
106 {
107 if (*upload_data_size != 8)
108 return MHD_YES; /* not yet ready */
109 if (0 == memcmp (upload_data, "Hello123", 8))
110 {
111 *upload_data_size = 0;
112 }
113 else
114 {
115 printf ("Invalid upload data `%8s'!\n", upload_data);
116 return MHD_NO;
117 }
118 *done = 1;
119 return MHD_YES;
120 }
121 response = MHD_create_response_from_buffer (strlen (url),
122 (void *) url,
123 MHD_RESPMEM_MUST_COPY);
124 ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
125 MHD_destroy_response (response);
126 return ret;
127}
128
129
130static unsigned int
131testInternalPut ()
132{
133 struct MHD_Daemon *d;
134 CURL *c;
135 char buf[2048];
136 struct CBC cbc;
137 unsigned int pos = 0;
138 int done_flag = 0;
139 int i;
140
141 cbc.buf = buf;
142 cbc.size = 2048;
143 cbc.pos = 0;
144 d =
145 MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD /* | MHD_USE_ERROR_LOG */,
146 11080,
147 NULL, NULL, &ahc_echo, &done_flag, MHD_OPTION_END);
148 if (d == NULL)
149 return 1;
150 zzuf_socat_start ();
151 for (i = 0; i < LOOP_COUNT; i++)
152 {
153 fprintf (stderr, ".");
154 c = curl_easy_init ();
155 curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:11081/hello_world");
156 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
157 curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
158 curl_easy_setopt (c, CURLOPT_READFUNCTION, &putBuffer);
159 curl_easy_setopt (c, CURLOPT_READDATA, &pos);
160 curl_easy_setopt (c, CURLOPT_UPLOAD, 1L);
161 curl_easy_setopt (c, CURLOPT_INFILESIZE_LARGE, (curl_off_t) 8L);
162 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L);
163 curl_easy_setopt (c, CURLOPT_TIMEOUT_MS, CURL_TIMEOUT);
164 if (oneone)
165 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
166 else
167 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
168 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT_MS, CURL_TIMEOUT);
169 /* NOTE: use of CONNECTTIMEOUT without also
170 * setting NOSIGNAL results in really weird
171 * crashes on my system! */
172 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
173 curl_easy_perform (c);
174 curl_easy_cleanup (c);
175 }
176 fprintf (stderr, "\n");
177 zzuf_socat_stop ();
178 MHD_stop_daemon (d);
179 return 0;
180}
181
182
183static unsigned int
184testMultithreadedPut ()
185{
186 struct MHD_Daemon *d;
187 CURL *c;
188 char buf[2048];
189 struct CBC cbc;
190 unsigned int pos = 0;
191 int done_flag = 0;
192 int i;
193
194 cbc.buf = buf;
195 cbc.size = 2048;
196 cbc.pos = 0;
197 d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION
198 | MHD_USE_INTERNAL_POLLING_THREAD /* | MHD_USE_ERROR_LOG */,
199 11080,
200 NULL, NULL, &ahc_echo, &done_flag, MHD_OPTION_END);
201 if (d == NULL)
202 return 16;
203 zzuf_socat_start ();
204 for (i = 0; i < LOOP_COUNT; i++)
205 {
206 fprintf (stderr, ".");
207 c = curl_easy_init ();
208 curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:11081/hello_world");
209 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
210 curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
211 curl_easy_setopt (c, CURLOPT_READFUNCTION, &putBuffer);
212 curl_easy_setopt (c, CURLOPT_READDATA, &pos);
213 curl_easy_setopt (c, CURLOPT_UPLOAD, 1L);
214 curl_easy_setopt (c, CURLOPT_INFILESIZE_LARGE, (curl_off_t) 8L);
215 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L);
216 curl_easy_setopt (c, CURLOPT_TIMEOUT_MS, CURL_TIMEOUT);
217 if (oneone)
218 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
219 else
220 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
221 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT_MS, CURL_TIMEOUT);
222 /* NOTE: use of CONNECTTIMEOUT without also
223 * setting NOSIGNAL results in really weird
224 * crashes on my system! */
225 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
226 curl_easy_perform (c);
227 curl_easy_cleanup (c);
228 }
229 fprintf (stderr, "\n");
230 zzuf_socat_stop ();
231 MHD_stop_daemon (d);
232 return 0;
233}
234
235
236static unsigned int
237testExternalPut ()
238{
239 struct MHD_Daemon *d;
240 CURL *c;
241 char buf[2048];
242 struct CBC cbc;
243 CURLM *multi;
244 CURLMcode mret;
245 fd_set rs;
246 fd_set ws;
247 fd_set es;
248 int max;
249 int running;
250 time_t start;
251 struct timeval tv;
252 unsigned int pos = 0;
253 int done_flag = 0;
254 int i;
255
256 multi = NULL;
257 cbc.buf = buf;
258 cbc.size = 2048;
259 cbc.pos = 0;
260 d = MHD_start_daemon (MHD_NO_FLAG /* | MHD_USE_ERROR_LOG */,
261 11080,
262 NULL, NULL, &ahc_echo, &done_flag, MHD_OPTION_END);
263 if (d == NULL)
264 return 256;
265 multi = curl_multi_init ();
266 if (multi == NULL)
267 {
268 MHD_stop_daemon (d);
269 return 512;
270 }
271 zzuf_socat_start ();
272 for (i = 0; i < LOOP_COUNT; i++)
273 {
274 fprintf (stderr, ".");
275
276 c = curl_easy_init ();
277 curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:11081/hello_world");
278 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
279 curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
280 curl_easy_setopt (c, CURLOPT_READFUNCTION, &putBuffer);
281 curl_easy_setopt (c, CURLOPT_READDATA, &pos);
282 curl_easy_setopt (c, CURLOPT_UPLOAD, 1L);
283 curl_easy_setopt (c, CURLOPT_INFILESIZE_LARGE, (curl_off_t) 8L);
284 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L);
285 curl_easy_setopt (c, CURLOPT_TIMEOUT_MS, CURL_TIMEOUT);
286 if (oneone)
287 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
288 else
289 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
290 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT_MS, CURL_TIMEOUT);
291 /* NOTE: use of CONNECTTIMEOUT without also
292 * setting NOSIGNAL results in really weird
293 * crashes on my system! */
294 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
295
296
297 mret = curl_multi_add_handle (multi, c);
298 if (mret != CURLM_OK)
299 {
300 curl_multi_cleanup (multi);
301 curl_easy_cleanup (c);
302 zzuf_socat_stop ();
303 MHD_stop_daemon (d);
304 return 1024;
305 }
306 start = time (NULL);
307 while ((time (NULL) - start < 5) && (c != NULL))
308 {
309 max = 0;
310 FD_ZERO (&rs);
311 FD_ZERO (&ws);
312 FD_ZERO (&es);
313 curl_multi_perform (multi, &running);
314 mret = curl_multi_fdset (multi, &rs, &ws, &es, &max);
315 if (mret != CURLM_OK)
316 {
317 curl_multi_remove_handle (multi, c);
318 curl_multi_cleanup (multi);
319 curl_easy_cleanup (c);
320 zzuf_socat_stop ();
321 MHD_stop_daemon (d);
322 return 2048;
323 }
324 if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &max))
325 {
326 curl_multi_remove_handle (multi, c);
327 curl_multi_cleanup (multi);
328 curl_easy_cleanup (c);
329 zzuf_socat_stop ();
330 MHD_stop_daemon (d);
331 return 4096;
332 }
333 tv.tv_sec = 0;
334 tv.tv_usec = 1000;
335 select (max + 1, &rs, &ws, &es, &tv);
336 curl_multi_perform (multi, &running);
337 if (running == 0)
338 {
339 curl_multi_info_read (multi, &running);
340 curl_multi_remove_handle (multi, c);
341 curl_easy_cleanup (c);
342 c = NULL;
343 }
344 MHD_run (d);
345 }
346 if (c != NULL)
347 {
348 curl_multi_remove_handle (multi, c);
349 curl_easy_cleanup (c);
350 }
351 }
352 fprintf (stderr, "\n");
353 curl_multi_cleanup (multi);
354 zzuf_socat_stop ();
355 MHD_stop_daemon (d);
356 return 0;
357}
358
359
360int
361main (int argc, char *const *argv)
362{
363 unsigned int errorCount = 0;
364 (void) argc; /* Unused. Silent compiler warning. */
365
366 oneone = (NULL != strrchr (argv[0], (int) '/')) ?
367 (NULL != strstr (strrchr (argv[0], (int) '/'), "11")) : 0;
368 if (0 != curl_global_init (CURL_GLOBAL_WIN32))
369 return 2;
370 if (MHD_YES == MHD_is_feature_supported (MHD_FEATURE_THREADS))
371 {
372 errorCount += testInternalPut ();
373 errorCount += testMultithreadedPut ();
374 }
375 errorCount += testExternalPut ();
376 if (errorCount != 0)
377 fprintf (stderr, "Error (code: %u)\n", errorCount);
378 curl_global_cleanup ();
379 return (0 == errorCount) ? 0 : 1; /* 0 == pass */
380}
diff --git a/src/testzzuf/test_put_chunked.c b/src/testzzuf/test_put_chunked.c
deleted file mode 100644
index 3dd67e43..00000000
--- a/src/testzzuf/test_put_chunked.c
+++ /dev/null
@@ -1,395 +0,0 @@
1/*
2 This file is part of libmicrohttpd
3 Copyright (C) 2007, 2008 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 2, 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., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19*/
20
21/**
22 * @file daemontest_put_chunked.c
23 * @brief Testcase for libmicrohttpd PUT operations with chunked encoding
24 * for the upload data
25 * @author Christian Grothoff
26 */
27
28#include "MHD_config.h"
29#include "platform.h"
30#include <curl/curl.h>
31#include <microhttpd.h>
32#include <stdlib.h>
33#include <string.h>
34#include <time.h>
35
36#ifndef WINDOWS
37#include <unistd.h>
38#endif
39
40#include "socat.c"
41
42struct CBC
43{
44 char *buf;
45 size_t pos;
46 size_t size;
47};
48
49static size_t
50putBuffer (void *stream, size_t size, size_t nmemb, void *ptr)
51{
52 unsigned int *pos = ptr;
53 unsigned int wrt;
54
55 wrt = size * nmemb;
56 if (wrt > 8 - (*pos))
57 wrt = 8 - (*pos);
58 if (wrt > 4)
59 wrt = 4; /* only send half at first => force multiple chunks! */
60 memcpy (stream, &("Hello123"[*pos]), wrt);
61 (*pos) += wrt;
62 return wrt;
63}
64
65
66static size_t
67copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx)
68{
69 struct CBC *cbc = ctx;
70
71 if (cbc->pos + size * nmemb > cbc->size)
72 return 0; /* overflow */
73 memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb);
74 cbc->pos += size * nmemb;
75 return size * nmemb;
76}
77
78
79static enum MHD_Result
80ahc_echo (void *cls,
81 struct MHD_Connection *connection,
82 const char *url,
83 const char *method,
84 const char *version,
85 const char *upload_data, size_t *upload_data_size,
86 void **req_cls)
87{
88 int *done = cls;
89 struct MHD_Response *response;
90 enum MHD_Result ret;
91 int have;
92 (void) version; (void) req_cls; /* Unused. Silent compiler warning. */
93
94 if (NULL == url)
95 fprintf (stderr, "The \"url\" parameter is NULL.\n");
96 if (NULL == method)
97 fprintf (stderr, "The \"method\" parameter is NULL.\n");
98 if (NULL == version)
99 fprintf (stderr, "The \"version\" parameter is NULL.\n");
100 if (NULL == upload_data_size)
101 fprintf (stderr, "The \"upload_data_size\" parameter is NULL.\n");
102 if ((0 != *upload_data_size) && (NULL == upload_data))
103 fprintf (stderr, "Upload data is NULL with non-zero size.\n");
104 if (0 != strcmp ("PUT", method))
105 return MHD_NO; /* unexpected method */
106 if ((*done) < 8)
107 {
108 have = *upload_data_size;
109 if (have + *done > 8)
110 {
111 return MHD_NO;
112 }
113 if (0 == have)
114 {
115 (void) 0; /* Do nothing - no data yet */
116 }
117 else if (0 == memcmp (upload_data, &"Hello123"[*done], have))
118 {
119 *done += have;
120 *upload_data_size = 0;
121 }
122 else
123 {
124 return MHD_NO;
125 }
126#if 0
127 fprintf (stderr, "Not ready for response: %u/%u\n", *done, 8);
128#endif
129 return MHD_YES;
130 }
131 response = MHD_create_response_from_buffer (strlen (url),
132 (void *) url,
133 MHD_RESPMEM_MUST_COPY);
134 ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
135 MHD_destroy_response (response);
136 return ret;
137}
138
139
140static unsigned int
141testInternalPut ()
142{
143 struct MHD_Daemon *d;
144 CURL *c;
145 char buf[2048];
146 struct CBC cbc;
147 unsigned int pos = 0;
148 int done_flag = 0;
149 int i;
150
151 cbc.buf = buf;
152 cbc.size = 2048;
153 cbc.pos = 0;
154 d = MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG,
155 11080,
156 NULL, NULL, &ahc_echo, &done_flag, MHD_OPTION_END);
157 if (d == NULL)
158 return 1;
159 zzuf_socat_start ();
160 for (i = 0; i < LOOP_COUNT; i++)
161 {
162 fprintf (stderr, ".");
163 done_flag = 0;
164 c = curl_easy_init ();
165 curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:11080/hello_world");
166 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
167 curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
168 curl_easy_setopt (c, CURLOPT_READFUNCTION, &putBuffer);
169 curl_easy_setopt (c, CURLOPT_READDATA, &pos);
170 curl_easy_setopt (c, CURLOPT_UPLOAD, 1L);
171 /* by not giving the file size, we force chunking! */
172 /*
173 curl_easy_setopt (c, CURLOPT_INFILESIZE_LARGE, (curl_off_t) 8L);
174 */
175 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L);
176 curl_easy_setopt (c, CURLOPT_TIMEOUT_MS, CURL_TIMEOUT);
177 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
178 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT_MS, CURL_TIMEOUT);
179 /* NOTE: use of CONNECTTIMEOUT without also
180 * setting NOSIGNAL results in really weird
181 * crashes on my system! */
182 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
183 curl_easy_perform (c);
184 curl_easy_cleanup (c);
185 }
186 fprintf (stderr, "\n");
187 zzuf_socat_stop ();
188 MHD_stop_daemon (d);
189 return 0;
190}
191
192
193static unsigned int
194testMultithreadedPut ()
195{
196 struct MHD_Daemon *d;
197 CURL *c;
198 char buf[2048];
199 struct CBC cbc;
200 unsigned int pos = 0;
201 int done_flag = 0;
202 CURLcode errornum;
203
204 cbc.buf = buf;
205 cbc.size = 2048;
206 cbc.pos = 0;
207 d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION
208 | MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG,
209 11081,
210 NULL, NULL, &ahc_echo, &done_flag, MHD_OPTION_END);
211 if (d == NULL)
212 return 16;
213 c = curl_easy_init ();
214 curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:11081/hello_world");
215 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
216 curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
217 curl_easy_setopt (c, CURLOPT_READFUNCTION, &putBuffer);
218 curl_easy_setopt (c, CURLOPT_READDATA, &pos);
219 curl_easy_setopt (c, CURLOPT_UPLOAD, 1L);
220 /* by not giving the file size, we force chunking! */
221 /*
222 curl_easy_setopt (c, CURLOPT_INFILESIZE_LARGE, (curl_off_t) 8L);
223 */
224 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L);
225 curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
226 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
227 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L);
228 /* NOTE: use of CONNECTTIMEOUT without also
229 * setting NOSIGNAL results in really weird
230 * crashes on my system! */
231 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
232 if (CURLE_OK != (errornum = curl_easy_perform (c)))
233 {
234 fprintf (stderr,
235 "curl_easy_perform failed: `%s'\n",
236 curl_easy_strerror (errornum));
237 curl_easy_cleanup (c);
238 MHD_stop_daemon (d);
239 return 32;
240 }
241 curl_easy_cleanup (c);
242 MHD_stop_daemon (d);
243 if (cbc.pos != strlen ("/hello_world"))
244 return 64;
245 if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
246 return 128;
247
248 return 0;
249}
250
251
252static unsigned int
253testExternalPut ()
254{
255 struct MHD_Daemon *d;
256 CURL *c;
257 char buf[2048];
258 struct CBC cbc;
259 CURLM *multi;
260 CURLMcode mret;
261 fd_set rs;
262 fd_set ws;
263 fd_set es;
264 int max;
265 int running;
266 time_t start;
267 struct timeval tv;
268 unsigned int pos = 0;
269 int done_flag = 0;
270 int i;
271
272 multi = NULL;
273 cbc.buf = buf;
274 cbc.size = 2048;
275 cbc.pos = 0;
276 d = MHD_start_daemon (MHD_USE_ERROR_LOG,
277 11082,
278 NULL, NULL, &ahc_echo, &done_flag, MHD_OPTION_END);
279 if (d == NULL)
280 return 256;
281
282 multi = curl_multi_init ();
283 if (multi == NULL)
284 {
285 MHD_stop_daemon (d);
286 return 512;
287 }
288 zzuf_socat_start ();
289 for (i = 0; i < LOOP_COUNT; i++)
290 {
291 fprintf (stderr, ".");
292 done_flag = 0;
293 c = curl_easy_init ();
294 curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:11082/hello_world");
295 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
296 curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
297 curl_easy_setopt (c, CURLOPT_READFUNCTION, &putBuffer);
298 curl_easy_setopt (c, CURLOPT_READDATA, &pos);
299 curl_easy_setopt (c, CURLOPT_UPLOAD, 1L);
300 /* by not giving the file size, we force chunking! */
301 /*
302 curl_easy_setopt (c, CURLOPT_INFILESIZE_LARGE, (curl_off_t) 8L);
303 */
304 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L);
305 curl_easy_setopt (c, CURLOPT_TIMEOUT_MS, CURL_TIMEOUT);
306 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
307 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT_MS, CURL_TIMEOUT);
308 /* NOTE: use of CONNECTTIMEOUT without also
309 * setting NOSIGNAL results in really weird
310 * crashes on my system! */
311 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
312
313
314 mret = curl_multi_add_handle (multi, c);
315 if (mret != CURLM_OK)
316 {
317 curl_multi_cleanup (multi);
318 curl_easy_cleanup (c);
319 zzuf_socat_stop ();
320 MHD_stop_daemon (d);
321 return 1024;
322 }
323 start = time (NULL);
324 while ((time (NULL) - start < 5) && (c != NULL))
325 {
326 max = 0;
327 FD_ZERO (&rs);
328 FD_ZERO (&ws);
329 FD_ZERO (&es);
330 curl_multi_perform (multi, &running);
331 mret = curl_multi_fdset (multi, &rs, &ws, &es, &max);
332 if (mret != CURLM_OK)
333 {
334 curl_multi_remove_handle (multi, c);
335 curl_multi_cleanup (multi);
336 curl_easy_cleanup (c);
337 zzuf_socat_stop ();
338 MHD_stop_daemon (d);
339 return 2048;
340 }
341 if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &max))
342 {
343 curl_multi_remove_handle (multi, c);
344 curl_multi_cleanup (multi);
345 curl_easy_cleanup (c);
346 zzuf_socat_stop ();
347 MHD_stop_daemon (d);
348 return 4096;
349 }
350 tv.tv_sec = 0;
351 tv.tv_usec = 1000;
352 select (max + 1, &rs, &ws, &es, &tv);
353 curl_multi_perform (multi, &running);
354 if (running == 0)
355 {
356 curl_multi_info_read (multi, &running);
357 curl_multi_remove_handle (multi, c);
358 curl_easy_cleanup (c);
359 c = NULL;
360 }
361 MHD_run (d);
362 }
363 if (c != NULL)
364 {
365 curl_multi_remove_handle (multi, c);
366 curl_easy_cleanup (c);
367 }
368 }
369 fprintf (stderr, "\n");
370 curl_multi_cleanup (multi);
371 zzuf_socat_stop ();
372 MHD_stop_daemon (d);
373 return 0;
374}
375
376
377int
378main (int argc, char *const *argv)
379{
380 unsigned int errorCount = 0;
381 (void) argc; (void) argv; /* Unused. Silent compiler warning. */
382
383 if (0 != curl_global_init (CURL_GLOBAL_WIN32))
384 return 2;
385 if (MHD_YES == MHD_is_feature_supported (MHD_FEATURE_THREADS))
386 {
387 errorCount += testInternalPut ();
388 errorCount += testMultithreadedPut ();
389 }
390 errorCount += testExternalPut ();
391 if (errorCount != 0)
392 fprintf (stderr, "Error (code: %u)\n", errorCount);
393 curl_global_cleanup ();
394 return (0 == errorCount) ? 0 : 1; /* 0 == pass */
395}
diff --git a/src/testzzuf/test_put_large.c b/src/testzzuf/test_put_large.c
deleted file mode 100644
index 900284ef..00000000
--- a/src/testzzuf/test_put_large.c
+++ /dev/null
@@ -1,403 +0,0 @@
1/*
2 This file is part of libmicrohttpd
3 Copyright (C) 2007, 2008 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 2, 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., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19*/
20
21/**
22 * @file test_put_large.c
23 * @brief Testcase for libmicrohttpd PUT operations
24 * @author Christian Grothoff
25 */
26
27#include "MHD_config.h"
28#include "platform.h"
29#include <curl/curl.h>
30#include <microhttpd.h>
31#include <stdlib.h>
32#include <string.h>
33#include <time.h>
34
35#ifndef WINDOWS
36#include <unistd.h>
37#endif
38
39#include "socat.c"
40
41static int oneone;
42
43/**
44 * Do not make this much larger since we will hit the
45 * MHD default buffer limit and the test code is not
46 * written for incremental upload processing...
47 */
48#define PUT_SIZE (256 * 1024)
49
50static char *put_buffer;
51
52struct CBC
53{
54 char *buf;
55 size_t pos;
56 size_t size;
57};
58
59static size_t
60putBuffer (void *stream, size_t size, size_t nmemb, void *ptr)
61{
62 unsigned int *pos = ptr;
63 unsigned int wrt;
64
65 wrt = size * nmemb;
66 if (wrt > PUT_SIZE - (*pos))
67 wrt = PUT_SIZE - (*pos);
68 memcpy (stream, &put_buffer[*pos], wrt);
69 (*pos) += wrt;
70 return wrt;
71}
72
73
74static size_t
75copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx)
76{
77 struct CBC *cbc = ctx;
78
79 if (cbc->pos + size * nmemb > cbc->size)
80 return 0; /* overflow */
81 memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb);
82 cbc->pos += size * nmemb;
83 return size * nmemb;
84}
85
86
87static enum MHD_Result
88ahc_echo (void *cls,
89 struct MHD_Connection *connection,
90 const char *url,
91 const char *method,
92 const char *version,
93 const char *upload_data, size_t *upload_data_size,
94 void **req_cls)
95{
96 int *done = cls;
97 struct MHD_Response *response;
98 enum MHD_Result ret;
99 (void) version; (void) req_cls; /* Unused. Silent compiler warning. */
100
101 if (NULL == url)
102 fprintf (stderr, "The \"url\" parameter is NULL.\n");
103 if (NULL == method)
104 fprintf (stderr, "The \"method\" parameter is NULL.\n");
105 if (NULL == version)
106 fprintf (stderr, "The \"version\" parameter is NULL.\n");
107 if (NULL == upload_data_size)
108 fprintf (stderr, "The \"upload_data_size\" parameter is NULL.\n");
109 if ((0 != *upload_data_size) && (NULL == upload_data))
110 fprintf (stderr, "Upload data is NULL with non-zero size.\n");
111 if (0 != strcmp ("PUT", method))
112 return MHD_NO; /* unexpected method */
113 if ((*done) == 0)
114 {
115 if (*upload_data_size != PUT_SIZE)
116 {
117#if 0
118 fprintf (stderr,
119 "Waiting for more data (%u/%u)...\n",
120 *upload_data_size, PUT_SIZE);
121#endif
122 return MHD_YES; /* not yet ready */
123 }
124 if (0 == memcmp (upload_data, put_buffer, PUT_SIZE))
125 {
126 *upload_data_size = 0;
127 }
128 else
129 {
130 return MHD_NO;
131 }
132 *done = 1;
133 return MHD_YES;
134 }
135 response = MHD_create_response_from_buffer (strlen (url),
136 (void *) url,
137 MHD_RESPMEM_MUST_COPY);
138 ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
139 MHD_destroy_response (response);
140 return ret;
141}
142
143
144static unsigned int
145testInternalPut ()
146{
147 struct MHD_Daemon *d;
148 CURL *c;
149 struct CBC cbc;
150 unsigned int pos = 0;
151 int done_flag = 0;
152 char buf[2048];
153 int i;
154
155 cbc.buf = buf;
156 cbc.size = 2048;
157 cbc.pos = 0;
158 d =
159 MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD /* | MHD_USE_ERROR_LOG */,
160 11080,
161 NULL, NULL, &ahc_echo, &done_flag, MHD_OPTION_END);
162 if (d == NULL)
163 return 1;
164 zzuf_socat_start ();
165 for (i = 0; i < LOOP_COUNT; i++)
166 {
167 fprintf (stderr, ".");
168
169 c = curl_easy_init ();
170 curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:11081/hello_world");
171 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
172 curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
173 curl_easy_setopt (c, CURLOPT_READFUNCTION, &putBuffer);
174 curl_easy_setopt (c, CURLOPT_READDATA, &pos);
175 curl_easy_setopt (c, CURLOPT_UPLOAD, 1L);
176 curl_easy_setopt (c, CURLOPT_INFILESIZE, (long) PUT_SIZE);
177 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L);
178 curl_easy_setopt (c, CURLOPT_TIMEOUT_MS, CURL_TIMEOUT);
179 if (oneone)
180 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
181 else
182 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
183 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT_MS, CURL_TIMEOUT);
184 /* NOTE: use of CONNECTTIMEOUT without also
185 * setting NOSIGNAL results in really weird
186 * crashes on my system! */
187 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
188 curl_easy_perform (c);
189 curl_easy_cleanup (c);
190 }
191 fprintf (stderr, "\n");
192 zzuf_socat_stop ();
193 MHD_stop_daemon (d);
194 return 0;
195}
196
197
198static unsigned int
199testMultithreadedPut ()
200{
201 struct MHD_Daemon *d;
202 CURL *c;
203 struct CBC cbc;
204 unsigned int pos = 0;
205 int done_flag = 0;
206 char buf[2048];
207 int i;
208
209 cbc.buf = buf;
210 cbc.size = 2048;
211 cbc.pos = 0;
212 d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION
213 | MHD_USE_INTERNAL_POLLING_THREAD /* | MHD_USE_ERROR_LOG */,
214 11080,
215 NULL, NULL, &ahc_echo, &done_flag, MHD_OPTION_END);
216 if (d == NULL)
217 return 16;
218 zzuf_socat_start ();
219 for (i = 0; i < LOOP_COUNT; i++)
220 {
221 fprintf (stderr, ".");
222
223 c = curl_easy_init ();
224 curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:11081/hello_world");
225 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
226 curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
227 curl_easy_setopt (c, CURLOPT_READFUNCTION, &putBuffer);
228 curl_easy_setopt (c, CURLOPT_READDATA, &pos);
229 curl_easy_setopt (c, CURLOPT_UPLOAD, 1L);
230 curl_easy_setopt (c, CURLOPT_INFILESIZE, (long) PUT_SIZE);
231 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L);
232 curl_easy_setopt (c, CURLOPT_TIMEOUT_MS, CURL_TIMEOUT);
233 if (oneone)
234 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
235 else
236 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
237 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT_MS, CURL_TIMEOUT);
238 /* NOTE: use of CONNECTTIMEOUT without also
239 * setting NOSIGNAL results in really weird
240 * crashes on my system! */
241 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
242 curl_easy_perform (c);
243 curl_easy_cleanup (c);
244 }
245 fprintf (stderr, "\n");
246 zzuf_socat_stop ();
247 MHD_stop_daemon (d);
248 return 0;
249}
250
251
252static unsigned int
253testExternalPut ()
254{
255 struct MHD_Daemon *d;
256 CURL *c;
257 struct CBC cbc;
258 CURLM *multi;
259 CURLMcode mret;
260 fd_set rs;
261 fd_set ws;
262 fd_set es;
263 int max;
264 int running;
265 time_t start;
266 struct timeval tv;
267 unsigned int pos = 0;
268 int done_flag = 0;
269 char buf[2048];
270 int i;
271
272 cbc.buf = buf;
273 cbc.size = 2048;
274 cbc.pos = 0;
275 multi = NULL;
276 d = MHD_start_daemon (MHD_NO_FLAG /* | MHD_USE_ERROR_LOG */,
277 11080,
278 NULL, NULL, &ahc_echo, &done_flag,
279 MHD_OPTION_CONNECTION_MEMORY_LIMIT,
280 (size_t) (PUT_SIZE * 4), MHD_OPTION_END);
281 if (d == NULL)
282 return 256;
283 multi = curl_multi_init ();
284 if (multi == NULL)
285 {
286 MHD_stop_daemon (d);
287 return 512;
288 }
289 zzuf_socat_start ();
290 for (i = 0; i < LOOP_COUNT; i++)
291 {
292 fprintf (stderr, ".");
293
294 c = curl_easy_init ();
295 curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:11081/hello_world");
296 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
297 curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
298 curl_easy_setopt (c, CURLOPT_READFUNCTION, &putBuffer);
299 curl_easy_setopt (c, CURLOPT_READDATA, &pos);
300 curl_easy_setopt (c, CURLOPT_UPLOAD, 1L);
301 curl_easy_setopt (c, CURLOPT_INFILESIZE, (long) PUT_SIZE);
302 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L);
303 curl_easy_setopt (c, CURLOPT_TIMEOUT_MS, CURL_TIMEOUT);
304 if (oneone)
305 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
306 else
307 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
308 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT_MS, CURL_TIMEOUT);
309 /* NOTE: use of CONNECTTIMEOUT without also
310 * setting NOSIGNAL results in really weird
311 * crashes on my system! */
312 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
313
314
315 mret = curl_multi_add_handle (multi, c);
316 if (mret != CURLM_OK)
317 {
318 curl_multi_cleanup (multi);
319 curl_easy_cleanup (c);
320 zzuf_socat_stop ();
321 MHD_stop_daemon (d);
322 return 1024;
323 }
324 start = time (NULL);
325 while ((time (NULL) - start < 5) && (c != NULL))
326 {
327 max = 0;
328 FD_ZERO (&rs);
329 FD_ZERO (&ws);
330 FD_ZERO (&es);
331 curl_multi_perform (multi, &running);
332 mret = curl_multi_fdset (multi, &rs, &ws, &es, &max);
333 if (mret != CURLM_OK)
334 {
335 curl_multi_remove_handle (multi, c);
336 curl_multi_cleanup (multi);
337 curl_easy_cleanup (c);
338 zzuf_socat_stop ();
339 MHD_stop_daemon (d);
340 return 2048;
341 }
342 if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &max))
343 {
344 curl_multi_remove_handle (multi, c);
345 curl_multi_cleanup (multi);
346 curl_easy_cleanup (c);
347 zzuf_socat_stop ();
348 MHD_stop_daemon (d);
349 return 4096;
350 }
351 tv.tv_sec = 0;
352 tv.tv_usec = 1000;
353 select (max + 1, &rs, &ws, &es, &tv);
354 curl_multi_perform (multi, &running);
355 if (running == 0)
356 {
357 curl_multi_info_read (multi, &running);
358 curl_multi_remove_handle (multi, c);
359 curl_easy_cleanup (c);
360 c = NULL;
361 }
362 MHD_run (d);
363 }
364 if (c != NULL)
365 {
366 curl_multi_remove_handle (multi, c);
367 curl_easy_cleanup (c);
368 }
369 }
370 fprintf (stderr, "\n");
371 zzuf_socat_stop ();
372 curl_multi_cleanup (multi);
373 MHD_stop_daemon (d);
374 return 0;
375}
376
377
378int
379main (int argc, char *const *argv)
380{
381 unsigned int errorCount = 0;
382 (void) argc; /* Unused. Silent compiler warning. */
383
384 oneone = (NULL != strrchr (argv[0], (int) '/')) ?
385 (NULL != strstr (strrchr (argv[0], (int) '/'), "11")) : 0;
386 if (0 != curl_global_init (CURL_GLOBAL_WIN32))
387 return 2;
388 put_buffer = malloc (PUT_SIZE);
389 if (0 == put_buffer)
390 return 77;
391 memset (put_buffer, 1, PUT_SIZE);
392 if (MHD_YES == MHD_is_feature_supported (MHD_FEATURE_THREADS))
393 {
394 errorCount += testInternalPut ();
395 errorCount += testMultithreadedPut ();
396 }
397 errorCount += testExternalPut ();
398 free (put_buffer);
399 if (errorCount != 0)
400 fprintf (stderr, "Error (code: %u)\n", errorCount);
401 curl_global_cleanup ();
402 return (0 == errorCount) ? 0 : 1; /* 0 == pass */
403}
diff --git a/src/testzzuf/zzuf_test_runner.sh b/src/testzzuf/zzuf_test_runner.sh
new file mode 100755
index 00000000..aa1dfdde
--- /dev/null
+++ b/src/testzzuf/zzuf_test_runner.sh
@@ -0,0 +1,55 @@
1#!/bin/sh
2
3mhd_listen_ip='127.0.0.1'
4max_runtime_sec='300'
5
6if test "x${ZZUF}" = "xno" ; then
7 echo "zzuf command missing" 1>&2
8 exit 77
9fi
10
11if command -v "${ZZUF}" > /dev/null 2>&1 ; then : ; else
12 echo "zzuf command missing" 1>&2
13 exit 77
14fi
15
16# zzuf cannot pass-through the return value of checked program
17# so try the direct dry-run first to get possibe 77 or 99 codes
18echo "## Dry-run of the $@..."
19if "$@" --dry-run ; then
20 echo "# Dry-run succeded."
21else
22 res_code=$?
23 echo "Dry-run failed with exit code $res_code. $@ will not be run with zzuf." 1>&2
24 exit $res_code
25fi
26
27# fuzz the input only for IP ${mhd_listen_ip}. libcurl uses another IP
28# in this test therefore libcurl input is not fuzzed.
29zzuf_all_params="--ratio=0.001:0.4 --autoinc --verbose --signal \
30 --max-usertime=${max_runtime_sec} --check-exit --network \
31 --allow=${mhd_listen_ip} --exclude=."
32
33if test -n "${ZZUF_SEED}" ; then
34 zzuf_all_params="${zzuf_all_params} --seed=${ZZUF_SEED}"
35fi
36
37if test -n "${ZZUF_FLAGS}" ; then
38 zzuf_all_params="${zzuf_all_params} ${ZZUF_FLAGS}"
39fi
40
41# Uncomment the next line to see more data in logs
42#zzuf_all_params="${zzuf_all_params} -dd"
43
44echo "## Dry-run of the $@ with zzuf..."
45if "$ZZUF" ${zzuf_all_params} "$@" --dry-run ; then
46 echo "# Dry-run with zzuf succeded."
47else
48 res_code=$?
49 echo "$@ cannot be run with zzuf. The test is skipped." 1>&2
50 exit 77
51fi
52
53echo "## Real test of $@ with zzuf..."
54"$ZZUF" ${zzuf_all_params} "$@"
55exit $?