aboutsummaryrefslogtreecommitdiff
path: root/src/testcurl/test_large_put.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/testcurl/test_large_put.c')
-rw-r--r--src/testcurl/test_large_put.c471
1 files changed, 471 insertions, 0 deletions
diff --git a/src/testcurl/test_large_put.c b/src/testcurl/test_large_put.c
new file mode 100644
index 00000000..4b9ae5fc
--- /dev/null
+++ b/src/testcurl/test_large_put.c
@@ -0,0 +1,471 @@
1/*
2 This file is part of libmicrohttpd
3 (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., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20
21/**
22 * @file daemontest_large_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
39static int oneone;
40
41/**
42 * Do not make this much larger since we will hit the
43 * MHD default buffer limit and the test code is not
44 * written for incremental upload processing...
45 * (larger values will likely cause MHD to generate
46 * an internal server error -- which would be avoided
47 * by writing the putBuffer method in a more general
48 * fashion).
49 */
50#define PUT_SIZE (256 * 1024)
51
52static char *put_buffer;
53
54struct CBC
55{
56 char *buf;
57 size_t pos;
58 size_t size;
59};
60
61static size_t
62putBuffer (void *stream, size_t size, size_t nmemb, void *ptr)
63{
64 unsigned int *pos = ptr;
65 unsigned int wrt;
66
67 wrt = size * nmemb;
68 if (wrt > PUT_SIZE - (*pos))
69 wrt = PUT_SIZE - (*pos);
70 memcpy (stream, &put_buffer[*pos], wrt);
71 (*pos) += wrt;
72 return wrt;
73}
74
75static size_t
76copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx)
77{
78 struct CBC *cbc = ctx;
79
80 if (cbc->pos + size * nmemb > cbc->size)
81 return 0; /* overflow */
82 memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb);
83 cbc->pos += size * nmemb;
84 return size * nmemb;
85}
86
87static int
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 **unused)
95{
96 int *done = cls;
97 struct MHD_Response *response;
98 int ret;
99
100 if (0 != strcmp ("PUT", method))
101 return MHD_NO; /* unexpected method */
102 if ((*done) == 0)
103 {
104 if (*upload_data_size != PUT_SIZE)
105 {
106#if 0
107 fprintf (stderr,
108 "Waiting for more data (%u/%u)...\n",
109 *upload_data_size, PUT_SIZE);
110#endif
111 return MHD_YES; /* not yet ready */
112 }
113 if (0 == memcmp (upload_data, put_buffer, PUT_SIZE))
114 {
115 *upload_data_size = 0;
116 }
117 else
118 {
119 printf ("Invalid upload data!\n");
120 return MHD_NO;
121 }
122 *done = 1;
123 return MHD_YES;
124 }
125 response = MHD_create_response_from_buffer (strlen (url),
126 (void *) url,
127 MHD_RESPMEM_MUST_COPY);
128 ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
129 MHD_destroy_response (response);
130 return ret;
131}
132
133
134static int
135testInternalPut ()
136{
137 struct MHD_Daemon *d;
138 CURL *c;
139 struct CBC cbc;
140 unsigned int pos = 0;
141 int done_flag = 0;
142 CURLcode errornum;
143 char buf[2048];
144
145 cbc.buf = buf;
146 cbc.size = 2048;
147 cbc.pos = 0;
148 d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG,
149 1080,
150 NULL, NULL, &ahc_echo, &done_flag,
151 MHD_OPTION_CONNECTION_MEMORY_LIMIT, (size_t) (1024*1024),
152 MHD_OPTION_END);
153 if (d == NULL)
154 return 1;
155 c = curl_easy_init ();
156 curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:1080/hello_world");
157 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
158 curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
159 curl_easy_setopt (c, CURLOPT_READFUNCTION, &putBuffer);
160 curl_easy_setopt (c, CURLOPT_READDATA, &pos);
161 curl_easy_setopt (c, CURLOPT_UPLOAD, 1L);
162 curl_easy_setopt (c, CURLOPT_INFILESIZE, (long) PUT_SIZE);
163 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
164 curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
165 if (oneone)
166 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
167 else
168 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
169 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
170 // NOTE: use of CONNECTTIMEOUT without also
171 // setting NOSIGNAL results in really weird
172 // crashes on my system!
173 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
174 if (CURLE_OK != (errornum = curl_easy_perform (c)))
175 {
176 fprintf (stderr,
177 "curl_easy_perform failed: `%s'\n",
178 curl_easy_strerror (errornum));
179 curl_easy_cleanup (c);
180 MHD_stop_daemon (d);
181 return 2;
182 }
183 curl_easy_cleanup (c);
184 MHD_stop_daemon (d);
185 if (cbc.pos != strlen ("/hello_world"))
186 return 4;
187 if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
188 return 8;
189 return 0;
190}
191
192static int
193testMultithreadedPut ()
194{
195 struct MHD_Daemon *d;
196 CURL *c;
197 struct CBC cbc;
198 unsigned int pos = 0;
199 int done_flag = 0;
200 CURLcode errornum;
201 char buf[2048];
202
203 cbc.buf = buf;
204 cbc.size = 2048;
205 cbc.pos = 0;
206 d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_DEBUG,
207 1081,
208 NULL, NULL, &ahc_echo, &done_flag,
209 MHD_OPTION_CONNECTION_MEMORY_LIMIT, (size_t) (1024*1024),
210 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:1081/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 curl_easy_setopt (c, CURLOPT_INFILESIZE, (long) PUT_SIZE);
221 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
222 curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
223 if (oneone)
224 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
225 else
226 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
227 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
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 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 {
245 fprintf (stderr, "Got invalid response `%.*s'\n", (int)cbc.pos, cbc.buf);
246 return 64;
247 }
248 if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
249 return 128;
250 return 0;
251}
252
253static int
254testMultithreadedPoolPut ()
255{
256 struct MHD_Daemon *d;
257 CURL *c;
258 struct CBC cbc;
259 unsigned int pos = 0;
260 int done_flag = 0;
261 CURLcode errornum;
262 char buf[2048];
263
264 cbc.buf = buf;
265 cbc.size = 2048;
266 cbc.pos = 0;
267 d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG,
268 1081,
269 NULL, NULL, &ahc_echo, &done_flag,
270 MHD_OPTION_THREAD_POOL_SIZE, 4,
271 MHD_OPTION_CONNECTION_MEMORY_LIMIT, (size_t) (1024*1024),
272 MHD_OPTION_END);
273 if (d == NULL)
274 return 16;
275 c = curl_easy_init ();
276 curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:1081/hello_world");
277 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
278 curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
279 curl_easy_setopt (c, CURLOPT_READFUNCTION, &putBuffer);
280 curl_easy_setopt (c, CURLOPT_READDATA, &pos);
281 curl_easy_setopt (c, CURLOPT_UPLOAD, 1L);
282 curl_easy_setopt (c, CURLOPT_INFILESIZE, (long) PUT_SIZE);
283 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
284 curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
285 if (oneone)
286 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
287 else
288 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
289 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
290 // NOTE: use of CONNECTTIMEOUT without also
291 // setting NOSIGNAL results in really weird
292 // crashes on my system!
293 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
294 if (CURLE_OK != (errornum = curl_easy_perform (c)))
295 {
296 fprintf (stderr,
297 "curl_easy_perform failed: `%s'\n",
298 curl_easy_strerror (errornum));
299 curl_easy_cleanup (c);
300 MHD_stop_daemon (d);
301 return 32;
302 }
303 curl_easy_cleanup (c);
304 MHD_stop_daemon (d);
305 if (cbc.pos != strlen ("/hello_world"))
306 {
307 fprintf (stderr, "Got invalid response `%.*s'\n", (int)cbc.pos, cbc.buf);
308 return 64;
309 }
310 if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
311 return 128;
312 return 0;
313}
314
315static int
316testExternalPut ()
317{
318 struct MHD_Daemon *d;
319 CURL *c;
320 struct CBC cbc;
321 CURLM *multi;
322 CURLMcode mret;
323 fd_set rs;
324 fd_set ws;
325 fd_set es;
326 int max;
327 int running;
328 struct CURLMsg *msg;
329 time_t start;
330 struct timeval tv;
331 unsigned int pos = 0;
332 int done_flag = 0;
333 char buf[2048];
334
335 cbc.buf = buf;
336 cbc.size = 2048;
337 cbc.pos = 0;
338 multi = NULL;
339 d = MHD_start_daemon (MHD_USE_DEBUG,
340 1082,
341 NULL, NULL, &ahc_echo, &done_flag,
342 MHD_OPTION_CONNECTION_MEMORY_LIMIT,
343 (size_t) (PUT_SIZE * 4), MHD_OPTION_END);
344 if (d == NULL)
345 return 256;
346 c = curl_easy_init ();
347 curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:1082/hello_world");
348 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
349 curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
350 curl_easy_setopt (c, CURLOPT_READFUNCTION, &putBuffer);
351 curl_easy_setopt (c, CURLOPT_READDATA, &pos);
352 curl_easy_setopt (c, CURLOPT_UPLOAD, 1L);
353 curl_easy_setopt (c, CURLOPT_INFILESIZE, (long) PUT_SIZE);
354 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
355 curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
356 if (oneone)
357 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
358 else
359 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
360 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
361 // NOTE: use of CONNECTTIMEOUT without also
362 // setting NOSIGNAL results in really weird
363 // crashes on my system!
364 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
365
366
367 multi = curl_multi_init ();
368 if (multi == NULL)
369 {
370 curl_easy_cleanup (c);
371 MHD_stop_daemon (d);
372 return 512;
373 }
374 mret = curl_multi_add_handle (multi, c);
375 if (mret != CURLM_OK)
376 {
377 curl_multi_cleanup (multi);
378 curl_easy_cleanup (c);
379 MHD_stop_daemon (d);
380 return 1024;
381 }
382 start = time (NULL);
383 while ((time (NULL) - start < 5) && (multi != NULL))
384 {
385 max = 0;
386 FD_ZERO (&rs);
387 FD_ZERO (&ws);
388 FD_ZERO (&es);
389 curl_multi_perform (multi, &running);
390 mret = curl_multi_fdset (multi, &rs, &ws, &es, &max);
391 if (mret != CURLM_OK)
392 {
393 curl_multi_remove_handle (multi, c);
394 curl_multi_cleanup (multi);
395 curl_easy_cleanup (c);
396 MHD_stop_daemon (d);
397 return 2048;
398 }
399 if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &max))
400 {
401 curl_multi_remove_handle (multi, c);
402 curl_multi_cleanup (multi);
403 curl_easy_cleanup (c);
404 MHD_stop_daemon (d);
405 return 4096;
406 }
407 tv.tv_sec = 0;
408 tv.tv_usec = 1000;
409 select (max + 1, &rs, &ws, &es, &tv);
410 curl_multi_perform (multi, &running);
411 if (running == 0)
412 {
413 msg = curl_multi_info_read (multi, &running);
414 if (msg == NULL)
415 break;
416 if (msg->msg == CURLMSG_DONE)
417 {
418 if (msg->data.result != CURLE_OK)
419 printf ("%s failed at %s:%d: `%s'\n",
420 "curl_multi_perform",
421 __FILE__,
422 __LINE__, curl_easy_strerror (msg->data.result));
423 curl_multi_remove_handle (multi, c);
424 curl_multi_cleanup (multi);
425 curl_easy_cleanup (c);
426 c = NULL;
427 multi = NULL;
428 }
429 }
430 MHD_run (d);
431 }
432 if (multi != NULL)
433 {
434 curl_multi_remove_handle (multi, c);
435 curl_easy_cleanup (c);
436 curl_multi_cleanup (multi);
437 }
438 MHD_stop_daemon (d);
439 if (cbc.pos != strlen ("/hello_world"))
440 {
441 fprintf (stderr, "Got invalid response `%.*s'\n", (int)cbc.pos, cbc.buf);
442 return 8192;
443 }
444 if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
445 return 16384;
446 return 0;
447}
448
449
450
451int
452main (int argc, char *const *argv)
453{
454 unsigned int errorCount = 0;
455
456 oneone = NULL != strstr (argv[0], "11");
457 if (0 != curl_global_init (CURL_GLOBAL_WIN32))
458 return 2;
459 put_buffer = malloc (PUT_SIZE);
460 if (NULL == put_buffer) return 1;
461 memset (put_buffer, 1, PUT_SIZE);
462 errorCount += testInternalPut ();
463 errorCount += testMultithreadedPut ();
464 errorCount += testMultithreadedPoolPut ();
465 errorCount += testExternalPut ();
466 free (put_buffer);
467 if (errorCount != 0)
468 fprintf (stderr, "Error (code: %u)\n", errorCount);
469 curl_global_cleanup ();
470 return errorCount != 0; /* 0 == pass */
471}