aboutsummaryrefslogtreecommitdiff
path: root/src/testzzuf
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2008-04-12 20:45:58 +0000
committerChristian Grothoff <christian@grothoff.org>2008-04-12 20:45:58 +0000
commit5e9c5b7621d550d92f5565622ad0bf147d4d8a3f (patch)
tree39a50077b389cfea554cdc8c9ce94adaa8c05f96 /src/testzzuf
parenta7cd9f029a61823c9285318a1dfd283ffac1912b (diff)
downloadlibmicrohttpd-5e9c5b7621d550d92f5565622ad0bf147d4d8a3f.tar.gz
libmicrohttpd-5e9c5b7621d550d92f5565622ad0bf147d4d8a3f.zip
moving stuff around
Diffstat (limited to 'src/testzzuf')
-rw-r--r--src/testzzuf/Makefile.am125
-rw-r--r--src/testzzuf/daemontest.c163
-rw-r--r--src/testzzuf/daemontest_get.c330
-rw-r--r--src/testzzuf/daemontest_get_chunked.c364
-rw-r--r--src/testzzuf/daemontest_large_put.c404
-rw-r--r--src/testzzuf/daemontest_long_header.c240
-rw-r--r--src/testzzuf/daemontest_put.c375
-rw-r--r--src/testzzuf/daemontest_put_chunked.c383
8 files changed, 2384 insertions, 0 deletions
diff --git a/src/testzzuf/Makefile.am b/src/testzzuf/Makefile.am
new file mode 100644
index 00000000..b48b75be
--- /dev/null
+++ b/src/testzzuf/Makefile.am
@@ -0,0 +1,125 @@
1SUBDIRS = .
2
3INCLUDES = -I$(top_srcdir)/src/include
4
5check_PROGRAMS = \
6 postprocessor_test \
7 daemontest \
8 daemontest_get \
9 daemontest_post \
10 daemontest_postform \
11 daemontest_post_loop \
12 daemontest_put \
13 daemontest_large_put \
14 daemontest_get11 \
15 daemontest_post11 \
16 daemontest_postform11 \
17 daemontest_post_loop11 \
18 daemontest_put11 \
19 daemontest_large_put11 \
20 daemontest_long_header \
21 daemontest_get_chunked \
22 daemontest_put_chunked
23
24TESTS = $(check_PROGRAMS)
25
26daemontest_SOURCES = \
27 daemontest.c
28daemontest_LDADD = \
29 $(top_builddir)/src/daemon/libmicrohttpd.la
30
31postprocessor_test_SOURCES = \
32 postprocessor_test.c
33postprocessor_test_LDADD = \
34 $(top_builddir)/src/daemon/libmicrohttpd.la
35
36daemontest_get_SOURCES = \
37 daemontest_get.c
38daemontest_get_LDADD = \
39 $(top_builddir)/src/daemon/libmicrohttpd.la \
40 @LIBCURL@
41
42daemontest_get_chunked_SOURCES = \
43 daemontest_get_chunked.c
44daemontest_get_chunked_LDADD = \
45 $(top_builddir)/src/daemon/libmicrohttpd.la \
46 @LIBCURL@
47
48daemontest_post_SOURCES = \
49 daemontest_post.c
50daemontest_post_LDADD = \
51 $(top_builddir)/src/daemon/libmicrohttpd.la \
52 @LIBCURL@
53
54daemontest_postform_SOURCES = \
55 daemontest_postform.c
56daemontest_postform_LDADD = \
57 $(top_builddir)/src/daemon/libmicrohttpd.la \
58 @LIBCURL@
59
60daemontest_post_loop_SOURCES = \
61 daemontest_post_loop.c
62daemontest_post_loop_LDADD = \
63 $(top_builddir)/src/daemon/libmicrohttpd.la \
64 @LIBCURL@
65
66daemontest_put_SOURCES = \
67 daemontest_put.c
68daemontest_put_LDADD = \
69 $(top_builddir)/src/daemon/libmicrohttpd.la \
70 @LIBCURL@
71
72daemontest_put_chunked_SOURCES = \
73 daemontest_put_chunked.c
74daemontest_put_chunked_LDADD = \
75 $(top_builddir)/src/daemon/libmicrohttpd.la \
76 @LIBCURL@
77
78daemontest_get11_SOURCES = \
79 daemontest_get.c
80daemontest_get11_LDADD = \
81 $(top_builddir)/src/daemon/libmicrohttpd.la \
82 @LIBCURL@
83
84daemontest_post11_SOURCES = \
85 daemontest_post.c
86daemontest_post11_LDADD = \
87 $(top_builddir)/src/daemon/libmicrohttpd.la \
88 @LIBCURL@
89
90daemontest_postform11_SOURCES = \
91 daemontest_postform.c
92daemontest_postform11_LDADD = \
93 $(top_builddir)/src/daemon/libmicrohttpd.la \
94 @LIBCURL@
95
96daemontest_post_loop11_SOURCES = \
97 daemontest_post_loop.c
98daemontest_post_loop11_LDADD = \
99 $(top_builddir)/src/daemon/libmicrohttpd.la \
100 @LIBCURL@
101
102daemontest_put11_SOURCES = \
103 daemontest_put.c
104daemontest_put11_LDADD = \
105 $(top_builddir)/src/daemon/libmicrohttpd.la \
106 @LIBCURL@
107
108
109daemontest_large_put_SOURCES = \
110 daemontest_large_put.c
111daemontest_large_put_LDADD = \
112 $(top_builddir)/src/daemon/libmicrohttpd.la \
113 @LIBCURL@
114
115daemontest_large_put11_SOURCES = \
116 daemontest_large_put.c
117daemontest_large_put11_LDADD = \
118 $(top_builddir)/src/daemon/libmicrohttpd.la \
119 @LIBCURL@
120
121daemontest_long_header_SOURCES = \
122 daemontest_long_header.c
123daemontest_long_header_LDADD = \
124 $(top_builddir)/src/daemon/libmicrohttpd.la \
125 @LIBCURL@
diff --git a/src/testzzuf/daemontest.c b/src/testzzuf/daemontest.c
new file mode 100644
index 00000000..8048b438
--- /dev/null
+++ b/src/testzzuf/daemontest.c
@@ -0,0 +1,163 @@
1/*
2 This file is part of libmicrohttpd
3 (C) 2007 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., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20
21/**
22 * @file daemontest.c
23 * @brief Testcase for libmicrohttpd starts and stops
24 * @author Christian Grothoff
25 */
26
27#include "config.h"
28#include "microhttpd.h"
29#include <stdlib.h>
30#include <string.h>
31#include <stdio.h>
32
33#ifndef WINDOWS
34#include <unistd.h>
35#endif
36
37
38static int
39testStartError ()
40{
41 struct MHD_Daemon *d;
42
43 d = MHD_start_daemon (MHD_USE_DEBUG, 0, NULL, NULL, NULL, NULL);
44 if (d != NULL)
45 return 1;
46 return 0;
47}
48
49static int
50apc_nothing (void *cls, const struct sockaddr *addr, socklen_t addrlen)
51{
52 return MHD_NO;
53}
54
55static int
56apc_all (void *cls, const struct sockaddr *addr, socklen_t addrlen)
57{
58 return MHD_YES;
59}
60
61static int
62ahc_nothing (void *cls,
63 struct MHD_Connection *connection,
64 const char *url,
65 const char *method,
66 const char *version,
67 const char *upload_data, unsigned int *upload_data_size,
68 void **unused)
69{
70 return MHD_NO;
71}
72
73static int
74testStartStop ()
75{
76 struct MHD_Daemon *d;
77
78 d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG,
79 1080,
80 &apc_nothing,
81 NULL, &ahc_nothing, NULL, MHD_OPTION_END);
82 if (d == NULL)
83 return 2;
84 MHD_stop_daemon (d);
85 return 0;
86}
87
88static int
89testExternalRun ()
90{
91 struct MHD_Daemon *d;
92 fd_set rs;
93 int maxfd;
94 int i;
95
96 d = MHD_start_daemon (MHD_USE_DEBUG,
97 1081,
98 &apc_all, NULL, &ahc_nothing, NULL, MHD_OPTION_END);
99
100 if (d == NULL)
101 return 4;
102 i = 0;
103 while (i < 15)
104 {
105 maxfd = 0;
106 FD_ZERO (&rs);
107 MHD_get_fdset (d, &rs, &rs, &rs, &maxfd);
108 if (MHD_run (d) == MHD_NO)
109 {
110 MHD_stop_daemon (d);
111 return 8;
112 }
113 i++;
114 }
115 MHD_stop_daemon (d);
116 return 0;
117}
118
119static int
120testThread ()
121{
122 struct MHD_Daemon *d;
123 d = MHD_start_daemon (MHD_USE_DEBUG | MHD_USE_SELECT_INTERNALLY,
124 1082,
125 &apc_all, NULL, &ahc_nothing, NULL, MHD_OPTION_END);
126
127 if (d == NULL)
128 return 16;
129 if (MHD_run (d) != MHD_NO)
130 return 32;
131 MHD_stop_daemon (d);
132 return 0;
133}
134
135static int
136testMultithread ()
137{
138 struct MHD_Daemon *d;
139 d = MHD_start_daemon (MHD_USE_DEBUG | MHD_USE_THREAD_PER_CONNECTION,
140 1083,
141 &apc_all, NULL, &ahc_nothing, NULL, MHD_OPTION_END);
142
143 if (d == NULL)
144 return 64;
145 if (MHD_run (d) != MHD_NO)
146 return 128;
147 MHD_stop_daemon (d);
148 return 0;
149}
150
151int
152main (int argc, char *const *argv)
153{
154 unsigned int errorCount = 0;
155 errorCount += testStartError ();
156 errorCount += testStartStop ();
157 errorCount += testExternalRun ();
158 errorCount += testThread ();
159 errorCount += testMultithread ();
160 if (errorCount != 0)
161 fprintf (stderr, "Error (code: %u)\n", errorCount);
162 return errorCount != 0; /* 0 == pass */
163}
diff --git a/src/testzzuf/daemontest_get.c b/src/testzzuf/daemontest_get.c
new file mode 100644
index 00000000..2d5729c1
--- /dev/null
+++ b/src/testzzuf/daemontest_get.c
@@ -0,0 +1,330 @@
1/*
2 This file is part of libmicrohttpd
3 (C) 2007 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., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20
21/**
22 * @file daemontest_get.c
23 * @brief Testcase for libmicrohttpd GET operations
24 * TODO: test parsing of query
25 * @author Christian Grothoff
26 */
27
28#include "config.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
39static int oneone;
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
60static int
61ahc_echo (void *cls,
62 struct MHD_Connection *connection,
63 const char *url,
64 const char *method,
65 const char *version,
66 const char *upload_data, unsigned int *upload_data_size,
67 void **unused)
68{
69 static int ptr;
70 const char *me = cls;
71 struct MHD_Response *response;
72 int ret;
73
74 if (0 != strcmp (me, method))
75 return MHD_NO; /* unexpected method */
76 if (&ptr != *unused)
77 {
78 *unused = &ptr;
79 return MHD_YES;
80 }
81 *unused = NULL;
82 response = MHD_create_response_from_data (strlen (url),
83 (void *) url, MHD_NO, MHD_YES);
84 ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
85 MHD_destroy_response (response);
86 if (ret == MHD_NO)
87 abort ();
88 return ret;
89}
90
91
92static int
93testInternalGet ()
94{
95 struct MHD_Daemon *d;
96 CURL *c;
97 char buf[2048];
98 struct CBC cbc;
99 CURLcode errornum;
100
101 cbc.buf = buf;
102 cbc.size = 2048;
103 cbc.pos = 0;
104 d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG,
105 11080, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END);
106 if (d == NULL)
107 return 1;
108 c = curl_easy_init ();
109 curl_easy_setopt (c, CURLOPT_URL, "http://localhost:11080/hello_world");
110 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
111 curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
112 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
113 curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
114 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L);
115 if (oneone)
116 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
117 else
118 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
119 // NOTE: use of CONNECTTIMEOUT without also
120 // setting NOSIGNAL results in really weird
121 // crashes on my system!
122 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
123 if (CURLE_OK != (errornum = curl_easy_perform (c)))
124 {
125 fprintf (stderr,
126 "curl_easy_perform failed: `%s'\n",
127 curl_easy_strerror (errornum));
128 curl_easy_cleanup (c);
129 MHD_stop_daemon (d);
130 return 2;
131 }
132 curl_easy_cleanup (c);
133 MHD_stop_daemon (d);
134 if (cbc.pos != strlen ("/hello_world"))
135 return 4;
136 if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
137 return 8;
138 return 0;
139}
140
141static int
142testMultithreadedGet ()
143{
144 struct MHD_Daemon *d;
145 CURL *c;
146 char buf[2048];
147 struct CBC cbc;
148 CURLcode errornum;
149
150 cbc.buf = buf;
151 cbc.size = 2048;
152 cbc.pos = 0;
153 d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_DEBUG,
154 1081, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END);
155 if (d == NULL)
156 return 16;
157 c = curl_easy_init ();
158 curl_easy_setopt (c, CURLOPT_URL, "http://localhost:1081/hello_world");
159 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
160 curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
161 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
162 curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
163 if (oneone)
164 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
165 else
166 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
167 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L);
168 // NOTE: use of CONNECTTIMEOUT without also
169 // setting NOSIGNAL results in really weird
170 // crashes on my system!
171 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
172 if (CURLE_OK != (errornum = curl_easy_perform (c)))
173 {
174 fprintf (stderr,
175 "curl_easy_perform failed: `%s'\n",
176 curl_easy_strerror (errornum));
177 curl_easy_cleanup (c);
178 MHD_stop_daemon (d);
179 return 32;
180 }
181 curl_easy_cleanup (c);
182 MHD_stop_daemon (d);
183 if (cbc.pos != strlen ("/hello_world"))
184 return 64;
185 if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
186 return 128;
187 return 0;
188}
189
190
191static int
192testExternalGet ()
193{
194 struct MHD_Daemon *d;
195 CURL *c;
196 char buf[2048];
197 struct CBC cbc;
198 CURLM *multi;
199 CURLMcode mret;
200 fd_set rs;
201 fd_set ws;
202 fd_set es;
203 int max;
204 int running;
205 struct CURLMsg *msg;
206 time_t start;
207 struct timeval tv;
208
209 multi = NULL;
210 cbc.buf = buf;
211 cbc.size = 2048;
212 cbc.pos = 0;
213 d = MHD_start_daemon (MHD_USE_DEBUG,
214 1082, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END);
215 if (d == NULL)
216 return 256;
217 c = curl_easy_init ();
218 curl_easy_setopt (c, CURLOPT_URL, "http://localhost:1082/hello_world");
219 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
220 curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
221 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
222 if (oneone)
223 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
224 else
225 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
226 curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
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, 1);
232
233
234 multi = curl_multi_init ();
235 if (multi == NULL)
236 {
237 curl_easy_cleanup (c);
238 MHD_stop_daemon (d);
239 return 512;
240 }
241 mret = curl_multi_add_handle (multi, c);
242 if (mret != CURLM_OK)
243 {
244 curl_multi_cleanup (multi);
245 curl_easy_cleanup (c);
246 MHD_stop_daemon (d);
247 return 1024;
248 }
249 start = time (NULL);
250 while ((time (NULL) - start < 5) && (multi != NULL))
251 {
252 max = 0;
253 FD_ZERO (&rs);
254 FD_ZERO (&ws);
255 FD_ZERO (&es);
256 curl_multi_perform (multi, &running);
257 mret = curl_multi_fdset (multi, &rs, &ws, &es, &max);
258 if (mret != CURLM_OK)
259 {
260 curl_multi_remove_handle (multi, c);
261 curl_multi_cleanup (multi);
262 curl_easy_cleanup (c);
263 MHD_stop_daemon (d);
264 return 2048;
265 }
266 if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &max))
267 {
268 curl_multi_remove_handle (multi, c);
269 curl_multi_cleanup (multi);
270 curl_easy_cleanup (c);
271 MHD_stop_daemon (d);
272 return 4096;
273 }
274 tv.tv_sec = 0;
275 tv.tv_usec = 1000;
276 select (max + 1, &rs, &ws, &es, &tv);
277 curl_multi_perform (multi, &running);
278 if (running == 0)
279 {
280 msg = curl_multi_info_read (multi, &running);
281 if (msg == NULL)
282 break;
283 if (msg->msg == CURLMSG_DONE)
284 {
285 if (msg->data.result != CURLE_OK)
286 printf ("%s failed at %s:%d: `%s'\n",
287 "curl_multi_perform",
288 __FILE__,
289 __LINE__, curl_easy_strerror (msg->data.result));
290 curl_multi_remove_handle (multi, c);
291 curl_multi_cleanup (multi);
292 curl_easy_cleanup (c);
293 c = NULL;
294 multi = NULL;
295 }
296 }
297 MHD_run (d);
298 }
299 if (multi != NULL)
300 {
301 curl_multi_remove_handle (multi, c);
302 curl_easy_cleanup (c);
303 curl_multi_cleanup (multi);
304 }
305 MHD_stop_daemon (d);
306 if (cbc.pos != strlen ("/hello_world"))
307 return 8192;
308 if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
309 return 16384;
310 return 0;
311}
312
313
314
315int
316main (int argc, char *const *argv)
317{
318 unsigned int errorCount = 0;
319
320 oneone = NULL != strstr (argv[0], "11");
321 if (0 != curl_global_init (CURL_GLOBAL_WIN32))
322 return 2;
323 errorCount += testInternalGet ();
324 errorCount += testMultithreadedGet ();
325 errorCount += testExternalGet ();
326 if (errorCount != 0)
327 fprintf (stderr, "Error (code: %u)\n", errorCount);
328 curl_global_cleanup ();
329 return errorCount != 0; /* 0 == pass */
330}
diff --git a/src/testzzuf/daemontest_get_chunked.c b/src/testzzuf/daemontest_get_chunked.c
new file mode 100644
index 00000000..4b2739cf
--- /dev/null
+++ b/src/testzzuf/daemontest_get_chunked.c
@@ -0,0 +1,364 @@
1/*
2 This file is part of libmicrohttpd
3 (C) 2007 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., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20
21/**
22 * @file daemontest_get_chunked.c
23 * @brief Testcase for libmicrohttpd GET operations with chunked content encoding
24 * TODO:
25 * - how to test that chunking was actually used?
26 * - use CURLOPT_HEADERFUNCTION to validate
27 * footer was sent
28 * @author Christian Grothoff
29 */
30
31#include "config.h"
32#include <curl/curl.h>
33#include <microhttpd.h>
34#include <stdlib.h>
35#include <string.h>
36#include <time.h>
37
38#ifndef WINDOWS
39#include <unistd.h>
40#endif
41
42struct CBC
43{
44 char *buf;
45 size_t pos;
46 size_t size;
47};
48
49static size_t
50copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx)
51{
52 struct CBC *cbc = ctx;
53
54 if (cbc->pos + size * nmemb > cbc->size)
55 return 0; /* overflow */
56 memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb);
57 cbc->pos += size * nmemb;
58 return size * nmemb;
59}
60
61/**
62 * MHD content reader callback that returns
63 * data in chunks.
64 */
65static int
66crc (void *cls, size_t pos, char *buf, int 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 -1; /* 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 * Dummy function that does nothing.
83 */
84static void
85crcf (void *ptr)
86{
87 free (ptr);
88}
89
90static int
91ahc_echo (void *cls,
92 struct MHD_Connection *connection,
93 const char *url,
94 const char *method,
95 const char *version,
96 const char *upload_data, unsigned int *upload_data_size, void **ptr)
97{
98 static int aptr;
99 const char *me = cls;
100 struct MHD_Response *response;
101 struct MHD_Response **responseptr;
102 int ret;
103
104 if (0 != strcmp (me, method))
105 return MHD_NO; /* unexpected method */
106 if (&aptr != *ptr)
107 {
108 /* do never respond on first call */
109 *ptr = &aptr;
110 return MHD_YES;
111 }
112 responseptr = malloc (sizeof (struct MHD_Response *));
113 response = MHD_create_response_from_callback (-1,
114 1024,
115 &crc, responseptr, &crcf);
116 *responseptr = response;
117 ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
118 MHD_destroy_response (response);
119 return ret;
120}
121
122static int
123validate (struct CBC cbc, int ebase)
124{
125 int i;
126 char buf[128];
127
128 if (cbc.pos != 128 * 10)
129 return ebase;
130
131 for (i = 0; i < 10; i++)
132 {
133 memset (buf, 'A' + i, 128);
134 if (0 != memcmp (buf, &cbc.buf[i * 128], 128))
135 {
136 fprintf (stderr,
137 "Got `%.*s'\nWant `%.*s'\n",
138 128, buf, 128, &cbc.buf[i * 128]);
139 return ebase * 2;
140 }
141 }
142 return 0;
143}
144
145static int
146testInternalGet ()
147{
148 struct MHD_Daemon *d;
149 CURL *c;
150 char buf[2048];
151 struct CBC cbc;
152 CURLcode errornum;
153
154 cbc.buf = buf;
155 cbc.size = 2048;
156 cbc.pos = 0;
157 d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG,
158 1080, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END);
159 if (d == NULL)
160 return 1;
161 c = curl_easy_init ();
162 curl_easy_setopt (c, CURLOPT_URL, "http://localhost:1080/hello_world");
163 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
164 curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
165 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
166 curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
167 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L);
168 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
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, 1);
173 if (CURLE_OK != (errornum = curl_easy_perform (c)))
174 {
175 fprintf (stderr,
176 "curl_easy_perform failed: `%s'\n",
177 curl_easy_strerror (errornum));
178 curl_easy_cleanup (c);
179 MHD_stop_daemon (d);
180 return 2;
181 }
182 curl_easy_cleanup (c);
183 MHD_stop_daemon (d);
184 return validate (cbc, 4);
185}
186
187static int
188testMultithreadedGet ()
189{
190 struct MHD_Daemon *d;
191 CURL *c;
192 char buf[2048];
193 struct CBC cbc;
194 CURLcode errornum;
195
196 cbc.buf = buf;
197 cbc.size = 2048;
198 cbc.pos = 0;
199 d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_DEBUG,
200 1081, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END);
201 if (d == NULL)
202 return 16;
203 c = curl_easy_init ();
204 curl_easy_setopt (c, CURLOPT_URL, "http://localhost:1081/hello_world");
205 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
206 curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
207 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
208 curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
209 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
210 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L);
211 // NOTE: use of CONNECTTIMEOUT without also
212 // setting NOSIGNAL results in really weird
213 // crashes on my system!
214 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
215 if (CURLE_OK != (errornum = curl_easy_perform (c)))
216 {
217 fprintf (stderr,
218 "curl_easy_perform failed: `%s'\n",
219 curl_easy_strerror (errornum));
220 curl_easy_cleanup (c);
221 MHD_stop_daemon (d);
222 return 32;
223 }
224 curl_easy_cleanup (c);
225 MHD_stop_daemon (d);
226 return validate (cbc, 64);
227}
228
229
230static int
231testExternalGet ()
232{
233 struct MHD_Daemon *d;
234 CURL *c;
235 char buf[2048];
236 struct CBC cbc;
237 CURLM *multi;
238 CURLMcode mret;
239 fd_set rs;
240 fd_set ws;
241 fd_set es;
242 int max;
243 int running;
244 struct CURLMsg *msg;
245 time_t start;
246 struct timeval tv;
247
248 multi = NULL;
249 cbc.buf = buf;
250 cbc.size = 2048;
251 cbc.pos = 0;
252 d = MHD_start_daemon (MHD_USE_DEBUG,
253 1082, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END);
254 if (d == NULL)
255 return 256;
256 c = curl_easy_init ();
257 curl_easy_setopt (c, CURLOPT_URL, "http://localhost:1082/hello_world");
258 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
259 curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
260 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
261 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
262 curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
263 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 5L);
264 // NOTE: use of CONNECTTIMEOUT without also
265 // setting NOSIGNAL results in really weird
266 // crashes on my system!
267 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
268
269
270 multi = curl_multi_init ();
271 if (multi == NULL)
272 {
273 curl_easy_cleanup (c);
274 MHD_stop_daemon (d);
275 return 512;
276 }
277 mret = curl_multi_add_handle (multi, c);
278 if (mret != CURLM_OK)
279 {
280 curl_multi_cleanup (multi);
281 curl_easy_cleanup (c);
282 MHD_stop_daemon (d);
283 return 1024;
284 }
285 start = time (NULL);
286 while ((time (NULL) - start < 5) && (multi != NULL))
287 {
288 max = 0;
289 FD_ZERO (&rs);
290 FD_ZERO (&ws);
291 FD_ZERO (&es);
292 curl_multi_perform (multi, &running);
293 mret = curl_multi_fdset (multi, &rs, &ws, &es, &max);
294 if (mret != CURLM_OK)
295 {
296 curl_multi_remove_handle (multi, c);
297 curl_multi_cleanup (multi);
298 curl_easy_cleanup (c);
299 MHD_stop_daemon (d);
300 return 2048;
301 }
302 if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &max))
303 {
304 curl_multi_remove_handle (multi, c);
305 curl_multi_cleanup (multi);
306 curl_easy_cleanup (c);
307 MHD_stop_daemon (d);
308 return 4096;
309 }
310 tv.tv_sec = 0;
311 tv.tv_usec = 1000;
312 select (max + 1, &rs, &ws, &es, &tv);
313 curl_multi_perform (multi, &running);
314 if (running == 0)
315 {
316 msg = curl_multi_info_read (multi, &running);
317 if (msg == NULL)
318 break;
319 if (msg->msg == CURLMSG_DONE)
320 {
321 if (msg->data.result != CURLE_OK)
322 printf ("%s failed at %s:%d: `%s'\n",
323 "curl_multi_perform",
324 __FILE__,
325 __LINE__, curl_easy_strerror (msg->data.result));
326 curl_multi_remove_handle (multi, c);
327 curl_multi_cleanup (multi);
328 curl_easy_cleanup (c);
329 c = NULL;
330 multi = NULL;
331 }
332 }
333 MHD_run (d);
334 }
335 if (multi != NULL)
336 {
337 curl_multi_remove_handle (multi, c);
338 curl_easy_cleanup (c);
339 curl_multi_cleanup (multi);
340 }
341 MHD_stop_daemon (d);
342 return validate (cbc, 8192);
343}
344
345
346
347int
348main (int argc, char *const *argv)
349{
350 unsigned int errorCount = 0;
351
352 if (0 != curl_global_init (CURL_GLOBAL_WIN32))
353 return 2;
354 errorCount += testInternalGet ();
355 if (0)
356 {
357 errorCount += testMultithreadedGet ();
358 errorCount += testExternalGet ();
359 }
360 if (errorCount != 0)
361 fprintf (stderr, "Error (code: %u)\n", errorCount);
362 curl_global_cleanup ();
363 return errorCount != 0; /* 0 == pass */
364}
diff --git a/src/testzzuf/daemontest_large_put.c b/src/testzzuf/daemontest_large_put.c
new file mode 100644
index 00000000..b0c7bf37
--- /dev/null
+++ b/src/testzzuf/daemontest_large_put.c
@@ -0,0 +1,404 @@
1/*
2 This file is part of libmicrohttpd
3 (C) 2007 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., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20
21/**
22 * @file daemontest_put.c
23 * @brief Testcase for libmicrohttpd PUT operations
24 * @author Christian Grothoff
25 */
26
27#include "config.h"
28#include <curl/curl.h>
29#include <microhttpd.h>
30#include <stdlib.h>
31#include <string.h>
32#include <time.h>
33
34#ifndef WINDOWS
35#include <unistd.h>
36#endif
37
38static int oneone;
39
40/**
41 * Do not make this much larger since we will hit the
42 * MHD default buffer limit and the test code is not
43 * written for incremental upload processing...
44 */
45#define PUT_SIZE (512 * 1024)
46
47static char *put_buffer;
48
49struct CBC
50{
51 char *buf;
52 size_t pos;
53 size_t size;
54};
55
56static size_t
57putBuffer (void *stream, size_t size, size_t nmemb, void *ptr)
58{
59 unsigned int *pos = ptr;
60 unsigned int wrt;
61
62 wrt = size * nmemb;
63 if (wrt > PUT_SIZE - (*pos))
64 wrt = PUT_SIZE - (*pos);
65 memcpy (stream, &put_buffer[*pos], wrt);
66 (*pos) += wrt;
67 return wrt;
68}
69
70static size_t
71copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx)
72{
73 struct CBC *cbc = ctx;
74
75 if (cbc->pos + size * nmemb > cbc->size)
76 return 0; /* overflow */
77 memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb);
78 cbc->pos += size * nmemb;
79 return size * nmemb;
80}
81
82static int
83ahc_echo (void *cls,
84 struct MHD_Connection *connection,
85 const char *url,
86 const char *method,
87 const char *version,
88 const char *upload_data, unsigned int *upload_data_size,
89 void **unused)
90{
91 int *done = cls;
92 struct MHD_Response *response;
93 int ret;
94
95 if (0 != strcmp ("PUT", method))
96 return MHD_NO; /* unexpected method */
97 if ((*done) == 0)
98 {
99 if (*upload_data_size != PUT_SIZE)
100 {
101#if 0
102 fprintf (stderr,
103 "Waiting for more data (%u/%u)...\n",
104 *upload_data_size, PUT_SIZE);
105#endif
106 return MHD_YES; /* not yet ready */
107 }
108 if (0 == memcmp (upload_data, put_buffer, PUT_SIZE))
109 {
110 *upload_data_size = 0;
111 }
112 else
113 {
114 printf ("Invalid upload data!\n");
115 return MHD_NO;
116 }
117 *done = 1;
118 return MHD_YES;
119 }
120 response = MHD_create_response_from_data (strlen (url),
121 (void *) url, MHD_NO, MHD_YES);
122 ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
123 MHD_destroy_response (response);
124 return ret;
125}
126
127
128static int
129testInternalPut ()
130{
131 struct MHD_Daemon *d;
132 CURL *c;
133 struct CBC cbc;
134 unsigned int pos = 0;
135 int done_flag = 0;
136 CURLcode errornum;
137 char buf[2048];
138
139 cbc.buf = buf;
140 cbc.size = 2048;
141 cbc.pos = 0;
142 d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG,
143 1080,
144 NULL, NULL, &ahc_echo, &done_flag, MHD_OPTION_END);
145 if (d == NULL)
146 return 1;
147 c = curl_easy_init ();
148 curl_easy_setopt (c, CURLOPT_URL, "http://localhost:1080/hello_world");
149 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
150 curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
151 curl_easy_setopt (c, CURLOPT_READFUNCTION, &putBuffer);
152 curl_easy_setopt (c, CURLOPT_READDATA, &pos);
153 curl_easy_setopt (c, CURLOPT_UPLOAD, 1L);
154 curl_easy_setopt (c, CURLOPT_INFILESIZE, (long) PUT_SIZE);
155 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
156 curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
157 if (oneone)
158 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
159 else
160 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
161 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L);
162 // NOTE: use of CONNECTTIMEOUT without also
163 // setting NOSIGNAL results in really weird
164 // crashes on my system!
165 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
166 if (CURLE_OK != (errornum = curl_easy_perform (c)))
167 {
168 fprintf (stderr,
169 "curl_easy_perform failed: `%s'\n",
170 curl_easy_strerror (errornum));
171 curl_easy_cleanup (c);
172 MHD_stop_daemon (d);
173 return 2;
174 }
175 curl_easy_cleanup (c);
176 MHD_stop_daemon (d);
177 if (cbc.pos != strlen ("/hello_world"))
178 return 4;
179 if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
180 return 8;
181 return 0;
182}
183
184static int
185testMultithreadedPut ()
186{
187 struct MHD_Daemon *d;
188 CURL *c;
189 struct CBC cbc;
190 unsigned int pos = 0;
191 int done_flag = 0;
192 CURLcode errornum;
193 char buf[2048];
194
195 cbc.buf = buf;
196 cbc.size = 2048;
197 cbc.pos = 0;
198 d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_DEBUG,
199 1081,
200 NULL, NULL, &ahc_echo, &done_flag, MHD_OPTION_END);
201 if (d == NULL)
202 {
203 free (cbc.buf);
204 return 16;
205 }
206 c = curl_easy_init ();
207 curl_easy_setopt (c, CURLOPT_URL, "http://localhost:1081/hello_world");
208 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
209 curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
210 curl_easy_setopt (c, CURLOPT_READFUNCTION, &putBuffer);
211 curl_easy_setopt (c, CURLOPT_READDATA, &pos);
212 curl_easy_setopt (c, CURLOPT_UPLOAD, 1L);
213 curl_easy_setopt (c, CURLOPT_INFILESIZE, (long) PUT_SIZE);
214 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
215 curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
216 if (oneone)
217 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
218 else
219 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
220 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L);
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, 1);
225 if (CURLE_OK != (errornum = curl_easy_perform (c)))
226 {
227 fprintf (stderr,
228 "curl_easy_perform failed: `%s'\n",
229 curl_easy_strerror (errornum));
230 curl_easy_cleanup (c);
231 MHD_stop_daemon (d);
232 return 32;
233 }
234 curl_easy_cleanup (c);
235 MHD_stop_daemon (d);
236 if (cbc.pos != strlen ("/hello_world"))
237 {
238 fprintf (stderr, "Got invalid response `%.*s'\n", cbc.pos, cbc.buf);
239 return 64;
240 }
241 if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
242 return 128;
243 return 0;
244}
245
246
247static int
248testExternalPut ()
249{
250 struct MHD_Daemon *d;
251 CURL *c;
252 struct CBC cbc;
253 CURLM *multi;
254 CURLMcode mret;
255 fd_set rs;
256 fd_set ws;
257 fd_set es;
258 int max;
259 int running;
260 struct CURLMsg *msg;
261 time_t start;
262 struct timeval tv;
263 unsigned int pos = 0;
264 int done_flag = 0;
265 char buf[2048];
266
267 cbc.buf = buf;
268 cbc.size = 2048;
269 cbc.pos = 0;
270 multi = NULL;
271 d = MHD_start_daemon (MHD_USE_DEBUG,
272 1082,
273 NULL, NULL, &ahc_echo, &done_flag,
274 MHD_OPTION_CONNECTION_MEMORY_LIMIT,
275 PUT_SIZE * 4, MHD_OPTION_END);
276 if (d == NULL)
277 return 256;
278 c = curl_easy_init ();
279 curl_easy_setopt (c, CURLOPT_URL, "http://localhost:1082/hello_world");
280 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
281 curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
282 curl_easy_setopt (c, CURLOPT_READFUNCTION, &putBuffer);
283 curl_easy_setopt (c, CURLOPT_READDATA, &pos);
284 curl_easy_setopt (c, CURLOPT_UPLOAD, 1L);
285 curl_easy_setopt (c, CURLOPT_INFILESIZE, (long) PUT_SIZE);
286 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
287 curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
288 if (oneone)
289 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
290 else
291 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
292 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L);
293 // NOTE: use of CONNECTTIMEOUT without also
294 // setting NOSIGNAL results in really weird
295 // crashes on my system!
296 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
297
298
299 multi = curl_multi_init ();
300 if (multi == NULL)
301 {
302 curl_easy_cleanup (c);
303 MHD_stop_daemon (d);
304 return 512;
305 }
306 mret = curl_multi_add_handle (multi, c);
307 if (mret != CURLM_OK)
308 {
309 curl_multi_cleanup (multi);
310 curl_easy_cleanup (c);
311 MHD_stop_daemon (d);
312 return 1024;
313 }
314 start = time (NULL);
315 while ((time (NULL) - start < 5) && (multi != NULL))
316 {
317 max = 0;
318 FD_ZERO (&rs);
319 FD_ZERO (&ws);
320 FD_ZERO (&es);
321 curl_multi_perform (multi, &running);
322 mret = curl_multi_fdset (multi, &rs, &ws, &es, &max);
323 if (mret != CURLM_OK)
324 {
325 curl_multi_remove_handle (multi, c);
326 curl_multi_cleanup (multi);
327 curl_easy_cleanup (c);
328 MHD_stop_daemon (d);
329 return 2048;
330 }
331 if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &max))
332 {
333 curl_multi_remove_handle (multi, c);
334 curl_multi_cleanup (multi);
335 curl_easy_cleanup (c);
336 MHD_stop_daemon (d);
337 return 4096;
338 }
339 tv.tv_sec = 0;
340 tv.tv_usec = 1000;
341 select (max + 1, &rs, &ws, &es, &tv);
342 curl_multi_perform (multi, &running);
343 if (running == 0)
344 {
345 msg = curl_multi_info_read (multi, &running);
346 if (msg == NULL)
347 break;
348 if (msg->msg == CURLMSG_DONE)
349 {
350 if (msg->data.result != CURLE_OK)
351 printf ("%s failed at %s:%d: `%s'\n",
352 "curl_multi_perform",
353 __FILE__,
354 __LINE__, curl_easy_strerror (msg->data.result));
355 curl_multi_remove_handle (multi, c);
356 curl_multi_cleanup (multi);
357 curl_easy_cleanup (c);
358 c = NULL;
359 multi = NULL;
360 }
361 }
362 MHD_run (d);
363 }
364 if (multi != NULL)
365 {
366 curl_multi_remove_handle (multi, c);
367 curl_easy_cleanup (c);
368 curl_multi_cleanup (multi);
369 }
370 MHD_stop_daemon (d);
371 if (cbc.pos != strlen ("/hello_world"))
372 {
373 fprintf (stderr, "Got invalid response `%.*s'\n", cbc.pos, cbc.buf);
374 return 8192;
375 }
376 if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
377 return 16384;
378 return 0;
379}
380
381
382
383int
384main (int argc, char *const *argv)
385{
386 unsigned int errorCount = 0;
387
388 oneone = NULL != strstr (argv[0], "11");
389 if (0 != curl_global_init (CURL_GLOBAL_WIN32))
390 return 2;
391 put_buffer = malloc (PUT_SIZE);
392 memset (put_buffer, 1, PUT_SIZE);
393 if (0)
394 {
395 errorCount += testInternalPut ();
396 errorCount += testMultithreadedPut ();
397 }
398 errorCount += testExternalPut ();
399 free (put_buffer);
400 if (errorCount != 0)
401 fprintf (stderr, "Error (code: %u)\n", errorCount);
402 curl_global_cleanup ();
403 return errorCount != 0; /* 0 == pass */
404}
diff --git a/src/testzzuf/daemontest_long_header.c b/src/testzzuf/daemontest_long_header.c
new file mode 100644
index 00000000..385b9776
--- /dev/null
+++ b/src/testzzuf/daemontest_long_header.c
@@ -0,0 +1,240 @@
1/*
2 This file is part of libmicrohttpd
3 (C) 2007 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., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20
21/**
22 * @file daemontest_long_header.c
23 * @brief Testcase for libmicrohttpd handling of very long headers
24 * @author Christian Grothoff
25 */
26
27#include "config.h"
28#include <curl/curl.h>
29#include <microhttpd.h>
30#include <stdlib.h>
31#include <string.h>
32#include <time.h>
33
34#ifndef WINDOWS
35#include <unistd.h>
36#endif
37
38/**
39 * We will set the memory available per connection to
40 * half of this value, so the actual value does not have
41 * to be big at all...
42 */
43#define VERY_LONG (1024*10)
44
45static int oneone;
46
47static int
48apc_all (void *cls, const struct sockaddr *addr, socklen_t addrlen)
49{
50 return MHD_YES;
51}
52
53struct CBC
54{
55 char *buf;
56 size_t pos;
57 size_t size;
58};
59
60static size_t
61copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx)
62{
63 return size * nmemb;
64}
65
66static int
67ahc_echo (void *cls,
68 struct MHD_Connection *connection,
69 const char *url,
70 const char *method,
71 const char *version,
72 const char *upload_data, unsigned int *upload_data_size,
73 void **unused)
74{
75 const char *me = cls;
76 struct MHD_Response *response;
77 int ret;
78
79 if (0 != strcmp (me, method))
80 return MHD_NO; /* unexpected method */
81 response = MHD_create_response_from_data (strlen (url),
82 (void *) url, MHD_NO, MHD_YES);
83 ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
84 MHD_destroy_response (response);
85 return ret;
86}
87
88
89static int
90testLongUrlGet ()
91{
92 struct MHD_Daemon *d;
93 CURL *c;
94 char buf[2048];
95 struct CBC cbc;
96 char *url;
97 long code;
98
99 cbc.buf = buf;
100 cbc.size = 2048;
101 cbc.pos = 0;
102 d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY /* | MHD_USE_DEBUG */ ,
103 1080,
104 &apc_all,
105 NULL,
106 &ahc_echo,
107 "GET",
108 MHD_OPTION_CONNECTION_MEMORY_LIMIT,
109 VERY_LONG / 2, MHD_OPTION_END);
110 if (d == NULL)
111 return 1;
112 c = curl_easy_init ();
113 url = malloc (VERY_LONG);
114 memset (url, 'a', VERY_LONG);
115 url[VERY_LONG - 1] = '\0';
116 memcpy (url, "http://localhost:1080/", strlen ("http://localhost:1080/"));
117 curl_easy_setopt (c, CURLOPT_URL, url);
118 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
119 curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
120 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
121 curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
122 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L);
123 if (oneone)
124 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
125 else
126 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
127 // NOTE: use of CONNECTTIMEOUT without also
128 // setting NOSIGNAL results in really weird
129 // crashes on my system!
130 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
131 if (CURLE_OK == curl_easy_perform (c))
132 {
133 curl_easy_cleanup (c);
134 MHD_stop_daemon (d);
135 free (url);
136 return 2;
137 }
138 if (CURLE_OK != curl_easy_getinfo (c, CURLINFO_RESPONSE_CODE, &code))
139 {
140 curl_easy_cleanup (c);
141 MHD_stop_daemon (d);
142 free (url);
143 return 4;
144 }
145 curl_easy_cleanup (c);
146 MHD_stop_daemon (d);
147 free (url);
148 if (code != MHD_HTTP_REQUEST_URI_TOO_LONG)
149 return 8;
150 return 0;
151}
152
153
154static int
155testLongHeaderGet ()
156{
157 struct MHD_Daemon *d;
158 CURL *c;
159 char buf[2048];
160 struct CBC cbc;
161 char *url;
162 long code;
163 struct curl_slist *header = NULL;
164
165 cbc.buf = buf;
166 cbc.size = 2048;
167 cbc.pos = 0;
168 d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY /* | MHD_USE_DEBUG */ ,
169 1080,
170 &apc_all,
171 NULL,
172 &ahc_echo,
173 "GET",
174 MHD_OPTION_CONNECTION_MEMORY_LIMIT,
175 VERY_LONG / 2, MHD_OPTION_END);
176 if (d == NULL)
177 return 16;
178 c = curl_easy_init ();
179 url = malloc (VERY_LONG);
180 memset (url, 'a', VERY_LONG);
181 url[VERY_LONG - 1] = '\0';
182 url[VERY_LONG / 2] = ':';
183 url[VERY_LONG / 2 + 1] = ':';
184 header = curl_slist_append (header, url);
185
186 curl_easy_setopt (c, CURLOPT_HTTPHEADER, header);
187 curl_easy_setopt (c, CURLOPT_URL, "http://localhost:1080/hello_world");
188 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
189 curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
190 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
191 curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
192 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L);
193 if (oneone)
194 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
195 else
196 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
197 // NOTE: use of CONNECTTIMEOUT without also
198 // setting NOSIGNAL results in really weird
199 // crashes on my system!
200 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
201 if (CURLE_OK == curl_easy_perform (c))
202 {
203 curl_easy_cleanup (c);
204 MHD_stop_daemon (d);
205 curl_slist_free_all (header);
206 free (url);
207 return 32;
208 }
209 if (CURLE_OK != curl_easy_getinfo (c, CURLINFO_RESPONSE_CODE, &code))
210 {
211 curl_slist_free_all (header);
212 curl_easy_cleanup (c);
213 MHD_stop_daemon (d);
214 free (url);
215 return 64;
216 }
217 curl_slist_free_all (header);
218 curl_easy_cleanup (c);
219 MHD_stop_daemon (d);
220 free (url);
221 if (code != MHD_HTTP_REQUEST_ENTITY_TOO_LARGE)
222 return 128;
223 return 0;
224}
225
226int
227main (int argc, char *const *argv)
228{
229 unsigned int errorCount = 0;
230
231 oneone = NULL != strstr (argv[0], "11");
232 if (0 != curl_global_init (CURL_GLOBAL_WIN32))
233 return 2;
234 errorCount += testLongUrlGet ();
235 errorCount += testLongHeaderGet ();
236 if (errorCount != 0)
237 fprintf (stderr, "Error (code: %u)\n", errorCount);
238 curl_global_cleanup ();
239 return errorCount != 0; /* 0 == pass */
240}
diff --git a/src/testzzuf/daemontest_put.c b/src/testzzuf/daemontest_put.c
new file mode 100644
index 00000000..e1f89402
--- /dev/null
+++ b/src/testzzuf/daemontest_put.c
@@ -0,0 +1,375 @@
1/*
2 This file is part of libmicrohttpd
3 (C) 2007 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., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20
21/**
22 * @file daemontest_put.c
23 * @brief Testcase for libmicrohttpd PUT operations
24 * @author Christian Grothoff
25 */
26
27#include "config.h"
28#include <curl/curl.h>
29#include <microhttpd.h>
30#include <stdlib.h>
31#include <string.h>
32#include <time.h>
33
34#ifndef WINDOWS
35#include <unistd.h>
36#endif
37
38static int oneone;
39
40struct CBC
41{
42 char *buf;
43 size_t pos;
44 size_t size;
45};
46
47static size_t
48putBuffer (void *stream, size_t size, size_t nmemb, void *ptr)
49{
50 unsigned int *pos = ptr;
51 unsigned int wrt;
52
53 wrt = size * nmemb;
54 if (wrt > 8 - (*pos))
55 wrt = 8 - (*pos);
56 memcpy (stream, &("Hello123"[*pos]), wrt);
57 (*pos) += wrt;
58 return wrt;
59}
60
61static size_t
62copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx)
63{
64 struct CBC *cbc = ctx;
65
66 if (cbc->pos + size * nmemb > cbc->size)
67 return 0; /* overflow */
68 memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb);
69 cbc->pos += size * nmemb;
70 return size * nmemb;
71}
72
73static int
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, unsigned int *upload_data_size,
80 void **unused)
81{
82 int *done = cls;
83 struct MHD_Response *response;
84 int ret;
85
86 if (0 != strcmp ("PUT", method))
87 return MHD_NO; /* unexpected method */
88 if ((*done) == 0)
89 {
90 if (*upload_data_size != 8)
91 return MHD_YES; /* not yet ready */
92 if (0 == memcmp (upload_data, "Hello123", 8))
93 {
94 *upload_data_size = 0;
95 }
96 else
97 {
98 printf ("Invalid upload data `%8s'!\n", upload_data);
99 return MHD_NO;
100 }
101 *done = 1;
102 return MHD_YES;
103 }
104 response = MHD_create_response_from_data (strlen (url),
105 (void *) url, MHD_NO, MHD_YES);
106 ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
107 MHD_destroy_response (response);
108 return ret;
109}
110
111
112static int
113testInternalPut ()
114{
115 struct MHD_Daemon *d;
116 CURL *c;
117 char buf[2048];
118 struct CBC cbc;
119 unsigned int pos = 0;
120 int done_flag = 0;
121 CURLcode errornum;
122
123 cbc.buf = buf;
124 cbc.size = 2048;
125 cbc.pos = 0;
126 d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG,
127 1080,
128 NULL, NULL, &ahc_echo, &done_flag, MHD_OPTION_END);
129 if (d == NULL)
130 return 1;
131 c = curl_easy_init ();
132 curl_easy_setopt (c, CURLOPT_URL, "http://localhost:1080/hello_world");
133 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
134 curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
135 curl_easy_setopt (c, CURLOPT_READFUNCTION, &putBuffer);
136 curl_easy_setopt (c, CURLOPT_READDATA, &pos);
137 curl_easy_setopt (c, CURLOPT_UPLOAD, 1L);
138 curl_easy_setopt (c, CURLOPT_INFILESIZE_LARGE, (curl_off_t) 8L);
139 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
140 curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
141 if (oneone)
142 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
143 else
144 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
145 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L);
146 // NOTE: use of CONNECTTIMEOUT without also
147 // setting NOSIGNAL results in really weird
148 // crashes on my system!
149 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
150 if (CURLE_OK != (errornum = curl_easy_perform (c)))
151 {
152 fprintf (stderr,
153 "curl_easy_perform failed: `%s'\n",
154 curl_easy_strerror (errornum));
155 curl_easy_cleanup (c);
156 MHD_stop_daemon (d);
157 return 2;
158 }
159 curl_easy_cleanup (c);
160 MHD_stop_daemon (d);
161 if (cbc.pos != strlen ("/hello_world"))
162 return 4;
163 if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
164 return 8;
165 return 0;
166}
167
168static int
169testMultithreadedPut ()
170{
171 struct MHD_Daemon *d;
172 CURL *c;
173 char buf[2048];
174 struct CBC cbc;
175 unsigned int pos = 0;
176 int done_flag = 0;
177 CURLcode errornum;
178
179 cbc.buf = buf;
180 cbc.size = 2048;
181 cbc.pos = 0;
182 d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_DEBUG,
183 1081,
184 NULL, NULL, &ahc_echo, &done_flag, MHD_OPTION_END);
185 if (d == NULL)
186 return 16;
187 c = curl_easy_init ();
188 curl_easy_setopt (c, CURLOPT_URL, "http://localhost:1081/hello_world");
189 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
190 curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
191 curl_easy_setopt (c, CURLOPT_READFUNCTION, &putBuffer);
192 curl_easy_setopt (c, CURLOPT_READDATA, &pos);
193 curl_easy_setopt (c, CURLOPT_UPLOAD, 1L);
194 curl_easy_setopt (c, CURLOPT_INFILESIZE_LARGE, (curl_off_t) 8L);
195 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
196 curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
197 if (oneone)
198 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
199 else
200 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
201 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L);
202 // NOTE: use of CONNECTTIMEOUT without also
203 // setting NOSIGNAL results in really weird
204 // crashes on my system!
205 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
206 if (CURLE_OK != (errornum = curl_easy_perform (c)))
207 {
208 fprintf (stderr,
209 "curl_easy_perform failed: `%s'\n",
210 curl_easy_strerror (errornum));
211 curl_easy_cleanup (c);
212 MHD_stop_daemon (d);
213 return 32;
214 }
215 curl_easy_cleanup (c);
216 MHD_stop_daemon (d);
217 if (cbc.pos != strlen ("/hello_world"))
218 return 64;
219 if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
220 return 128;
221
222 return 0;
223}
224
225
226static int
227testExternalPut ()
228{
229 struct MHD_Daemon *d;
230 CURL *c;
231 char buf[2048];
232 struct CBC cbc;
233 CURLM *multi;
234 CURLMcode mret;
235 fd_set rs;
236 fd_set ws;
237 fd_set es;
238 int max;
239 int running;
240 struct CURLMsg *msg;
241 time_t start;
242 struct timeval tv;
243 unsigned int pos = 0;
244 int done_flag = 0;
245
246 multi = NULL;
247 cbc.buf = buf;
248 cbc.size = 2048;
249 cbc.pos = 0;
250 d = MHD_start_daemon (MHD_USE_DEBUG,
251 1082,
252 NULL, NULL, &ahc_echo, &done_flag, MHD_OPTION_END);
253 if (d == NULL)
254 return 256;
255 c = curl_easy_init ();
256 curl_easy_setopt (c, CURLOPT_URL, "http://localhost:1082/hello_world");
257 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
258 curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
259 curl_easy_setopt (c, CURLOPT_READFUNCTION, &putBuffer);
260 curl_easy_setopt (c, CURLOPT_READDATA, &pos);
261 curl_easy_setopt (c, CURLOPT_UPLOAD, 1L);
262 curl_easy_setopt (c, CURLOPT_INFILESIZE_LARGE, (curl_off_t) 8L);
263 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
264 curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
265 if (oneone)
266 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
267 else
268 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
269 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L);
270 // NOTE: use of CONNECTTIMEOUT without also
271 // setting NOSIGNAL results in really weird
272 // crashes on my system!
273 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
274
275
276 multi = curl_multi_init ();
277 if (multi == NULL)
278 {
279 curl_easy_cleanup (c);
280 MHD_stop_daemon (d);
281 return 512;
282 }
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 MHD_stop_daemon (d);
289 return 1024;
290 }
291 start = time (NULL);
292 while ((time (NULL) - start < 5) && (multi != NULL))
293 {
294 max = 0;
295 FD_ZERO (&rs);
296 FD_ZERO (&ws);
297 FD_ZERO (&es);
298 curl_multi_perform (multi, &running);
299 mret = curl_multi_fdset (multi, &rs, &ws, &es, &max);
300 if (mret != CURLM_OK)
301 {
302 curl_multi_remove_handle (multi, c);
303 curl_multi_cleanup (multi);
304 curl_easy_cleanup (c);
305 MHD_stop_daemon (d);
306 return 2048;
307 }
308 if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &max))
309 {
310 curl_multi_remove_handle (multi, c);
311 curl_multi_cleanup (multi);
312 curl_easy_cleanup (c);
313 MHD_stop_daemon (d);
314 return 4096;
315 }
316 tv.tv_sec = 0;
317 tv.tv_usec = 1000;
318 select (max + 1, &rs, &ws, &es, &tv);
319 curl_multi_perform (multi, &running);
320 if (running == 0)
321 {
322 msg = curl_multi_info_read (multi, &running);
323 if (msg == NULL)
324 break;
325 if (msg->msg == CURLMSG_DONE)
326 {
327 if (msg->data.result != CURLE_OK)
328 printf ("%s failed at %s:%d: `%s'\n",
329 "curl_multi_perform",
330 __FILE__,
331 __LINE__, curl_easy_strerror (msg->data.result));
332 curl_multi_remove_handle (multi, c);
333 curl_multi_cleanup (multi);
334 curl_easy_cleanup (c);
335 c = NULL;
336 multi = NULL;
337 }
338 }
339 MHD_run (d);
340 }
341 if (multi != NULL)
342 {
343 curl_multi_remove_handle (multi, c);
344 curl_easy_cleanup (c);
345 curl_multi_cleanup (multi);
346 }
347 MHD_stop_daemon (d);
348 if (cbc.pos != strlen ("/hello_world"))
349 return 8192;
350 if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
351 return 16384;
352 return 0;
353}
354
355
356
357int
358main (int argc, char *const *argv)
359{
360 unsigned int errorCount = 0;
361
362 oneone = NULL != strstr (argv[0], "11");
363 if (0 != curl_global_init (CURL_GLOBAL_WIN32))
364 return 2;
365 errorCount += testInternalPut ();
366 if (0)
367 {
368 errorCount += testMultithreadedPut ();
369 errorCount += testExternalPut ();
370 }
371 if (errorCount != 0)
372 fprintf (stderr, "Error (code: %u)\n", errorCount);
373 curl_global_cleanup ();
374 return errorCount != 0; /* 0 == pass */
375}
diff --git a/src/testzzuf/daemontest_put_chunked.c b/src/testzzuf/daemontest_put_chunked.c
new file mode 100644
index 00000000..0cc3eb8f
--- /dev/null
+++ b/src/testzzuf/daemontest_put_chunked.c
@@ -0,0 +1,383 @@
1/*
2 This file is part of libmicrohttpd
3 (C) 2007 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., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, 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 "config.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
39struct CBC
40{
41 char *buf;
42 size_t pos;
43 size_t size;
44};
45
46static size_t
47putBuffer (void *stream, size_t size, size_t nmemb, void *ptr)
48{
49 unsigned int *pos = ptr;
50 unsigned int wrt;
51
52 wrt = size * nmemb;
53 if (wrt > 8 - (*pos))
54 wrt = 8 - (*pos);
55 if (wrt > 4)
56 wrt = 4; /* only send half at first => force multiple chunks! */
57 memcpy (stream, &("Hello123"[*pos]), wrt);
58 (*pos) += wrt;
59 return wrt;
60}
61
62static size_t
63copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx)
64{
65 struct CBC *cbc = ctx;
66
67 if (cbc->pos + size * nmemb > cbc->size)
68 return 0; /* overflow */
69 memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb);
70 cbc->pos += size * nmemb;
71 return size * nmemb;
72}
73
74static int
75ahc_echo (void *cls,
76 struct MHD_Connection *connection,
77 const char *url,
78 const char *method,
79 const char *version,
80 const char *upload_data, unsigned int *upload_data_size,
81 void **unused)
82{
83 int *done = cls;
84 struct MHD_Response *response;
85 int ret;
86 int have;
87
88 if (0 != strcmp ("PUT", method))
89 return MHD_NO; /* unexpected method */
90 if ((*done) < 8)
91 {
92 have = *upload_data_size;
93 if (have + *done > 8)
94 {
95 printf ("Invalid upload data `%8s'!\n", upload_data);
96 return MHD_NO;
97 }
98 if (0 == memcmp (upload_data, &"Hello123"[*done], have))
99 {
100 *done += have;
101 *upload_data_size = 0;
102 }
103 else
104 {
105 printf ("Invalid upload data `%8s'!\n", upload_data);
106 return MHD_NO;
107 }
108#if 0
109 fprintf (stderr, "Not ready for response: %u/%u\n", *done, 8);
110#endif
111 return MHD_YES;
112 }
113 response = MHD_create_response_from_data (strlen (url),
114 (void *) url, MHD_NO, MHD_YES);
115 ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
116 MHD_destroy_response (response);
117 return ret;
118}
119
120
121static int
122testInternalPut ()
123{
124 struct MHD_Daemon *d;
125 CURL *c;
126 char buf[2048];
127 struct CBC cbc;
128 unsigned int pos = 0;
129 int done_flag = 0;
130 CURLcode errornum;
131
132 cbc.buf = buf;
133 cbc.size = 2048;
134 cbc.pos = 0;
135 d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG,
136 11080,
137 NULL, NULL, &ahc_echo, &done_flag, MHD_OPTION_END);
138 if (d == NULL)
139 return 1;
140 c = curl_easy_init ();
141 curl_easy_setopt (c, CURLOPT_URL, "http://localhost:11080/hello_world");
142 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
143 curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
144 curl_easy_setopt (c, CURLOPT_READFUNCTION, &putBuffer);
145 curl_easy_setopt (c, CURLOPT_READDATA, &pos);
146 curl_easy_setopt (c, CURLOPT_UPLOAD, 1L);
147 /*
148 // by not giving the file size, we force chunking!
149 curl_easy_setopt (c, CURLOPT_INFILESIZE_LARGE, (curl_off_t) 8L);
150 */
151 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
152 curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
153 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
154 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L);
155 // NOTE: use of CONNECTTIMEOUT without also
156 // setting NOSIGNAL results in really weird
157 // crashes on my system!
158 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
159 if (CURLE_OK != (errornum = curl_easy_perform (c)))
160 {
161 fprintf (stderr,
162 "curl_easy_perform failed: `%s'\n",
163 curl_easy_strerror (errornum));
164 curl_easy_cleanup (c);
165 MHD_stop_daemon (d);
166 return 2;
167 }
168 curl_easy_cleanup (c);
169 MHD_stop_daemon (d);
170 if (cbc.pos != strlen ("/hello_world"))
171 return 4;
172 if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
173 return 8;
174 return 0;
175}
176
177static int
178testMultithreadedPut ()
179{
180 struct MHD_Daemon *d;
181 CURL *c;
182 char buf[2048];
183 struct CBC cbc;
184 unsigned int pos = 0;
185 int done_flag = 0;
186 CURLcode errornum;
187
188 cbc.buf = buf;
189 cbc.size = 2048;
190 cbc.pos = 0;
191 d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_DEBUG,
192 11081,
193 NULL, NULL, &ahc_echo, &done_flag, MHD_OPTION_END);
194 if (d == NULL)
195 return 16;
196 c = curl_easy_init ();
197 curl_easy_setopt (c, CURLOPT_URL, "http://localhost:11081/hello_world");
198 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
199 curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
200 curl_easy_setopt (c, CURLOPT_READFUNCTION, &putBuffer);
201 curl_easy_setopt (c, CURLOPT_READDATA, &pos);
202 curl_easy_setopt (c, CURLOPT_UPLOAD, 1L);
203 /*
204 // by not giving the file size, we force chunking!
205 curl_easy_setopt (c, CURLOPT_INFILESIZE_LARGE, (curl_off_t) 8L);
206 */
207 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
208 curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
209 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
210 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L);
211 // NOTE: use of CONNECTTIMEOUT without also
212 // setting NOSIGNAL results in really weird
213 // crashes on my system!
214 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
215 if (CURLE_OK != (errornum = curl_easy_perform (c)))
216 {
217 fprintf (stderr,
218 "curl_easy_perform failed: `%s'\n",
219 curl_easy_strerror (errornum));
220 curl_easy_cleanup (c);
221 MHD_stop_daemon (d);
222 return 32;
223 }
224 curl_easy_cleanup (c);
225 MHD_stop_daemon (d);
226 if (cbc.pos != strlen ("/hello_world"))
227 return 64;
228 if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
229 return 128;
230
231 return 0;
232}
233
234
235static int
236testExternalPut ()
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 struct CURLMsg *msg;
250 time_t start;
251 struct timeval tv;
252 unsigned int pos = 0;
253 int done_flag = 0;
254
255 multi = NULL;
256 cbc.buf = buf;
257 cbc.size = 2048;
258 cbc.pos = 0;
259 d = MHD_start_daemon (MHD_USE_DEBUG,
260 11082,
261 NULL, NULL, &ahc_echo, &done_flag, MHD_OPTION_END);
262 if (d == NULL)
263 return 256;
264 c = curl_easy_init ();
265 curl_easy_setopt (c, CURLOPT_URL, "http://localhost:11082/hello_world");
266 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
267 curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
268 curl_easy_setopt (c, CURLOPT_READFUNCTION, &putBuffer);
269 curl_easy_setopt (c, CURLOPT_READDATA, &pos);
270 curl_easy_setopt (c, CURLOPT_UPLOAD, 1L);
271 /*
272 // by not giving the file size, we force chunking!
273 curl_easy_setopt (c, CURLOPT_INFILESIZE_LARGE, (curl_off_t) 8L);
274 */
275 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
276 curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
277 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
278 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L);
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, 1);
283
284
285 multi = curl_multi_init ();
286 if (multi == NULL)
287 {
288 curl_easy_cleanup (c);
289 MHD_stop_daemon (d);
290 return 512;
291 }
292 mret = curl_multi_add_handle (multi, c);
293 if (mret != CURLM_OK)
294 {
295 curl_multi_cleanup (multi);
296 curl_easy_cleanup (c);
297 MHD_stop_daemon (d);
298 return 1024;
299 }
300 start = time (NULL);
301 while ((time (NULL) - start < 5) && (multi != NULL))
302 {
303 max = 0;
304 FD_ZERO (&rs);
305 FD_ZERO (&ws);
306 FD_ZERO (&es);
307 curl_multi_perform (multi, &running);
308 mret = curl_multi_fdset (multi, &rs, &ws, &es, &max);
309 if (mret != CURLM_OK)
310 {
311 curl_multi_remove_handle (multi, c);
312 curl_multi_cleanup (multi);
313 curl_easy_cleanup (c);
314 MHD_stop_daemon (d);
315 return 2048;
316 }
317 if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &max))
318 {
319 curl_multi_remove_handle (multi, c);
320 curl_multi_cleanup (multi);
321 curl_easy_cleanup (c);
322 MHD_stop_daemon (d);
323 return 4096;
324 }
325 tv.tv_sec = 0;
326 tv.tv_usec = 1000;
327 select (max + 1, &rs, &ws, &es, &tv);
328 curl_multi_perform (multi, &running);
329 if (running == 0)
330 {
331 msg = curl_multi_info_read (multi, &running);
332 if (msg == NULL)
333 break;
334 if (msg->msg == CURLMSG_DONE)
335 {
336 if (msg->data.result != CURLE_OK)
337 printf ("%s failed at %s:%d: `%s'\n",
338 "curl_multi_perform",
339 __FILE__,
340 __LINE__, curl_easy_strerror (msg->data.result));
341 curl_multi_remove_handle (multi, c);
342 curl_multi_cleanup (multi);
343 curl_easy_cleanup (c);
344 c = NULL;
345 multi = NULL;
346 }
347 }
348 MHD_run (d);
349 }
350 if (multi != NULL)
351 {
352 curl_multi_remove_handle (multi, c);
353 curl_easy_cleanup (c);
354 curl_multi_cleanup (multi);
355 }
356 MHD_stop_daemon (d);
357 if (cbc.pos != strlen ("/hello_world"))
358 return 8192;
359 if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
360 return 16384;
361 return 0;
362}
363
364
365
366int
367main (int argc, char *const *argv)
368{
369 unsigned int errorCount = 0;
370
371 if (0 != curl_global_init (CURL_GLOBAL_WIN32))
372 return 2;
373 errorCount += testInternalPut ();
374 if (0)
375 {
376 errorCount += testMultithreadedPut ();
377 errorCount += testExternalPut ();
378 }
379 if (errorCount != 0)
380 fprintf (stderr, "Error (code: %u)\n", errorCount);
381 curl_global_cleanup ();
382 return errorCount != 0; /* 0 == pass */
383}