aboutsummaryrefslogtreecommitdiff
path: root/src/testcurl/test_put_chunked.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/testcurl/test_put_chunked.c')
-rw-r--r--src/testcurl/test_put_chunked.c441
1 files changed, 441 insertions, 0 deletions
diff --git a/src/testcurl/test_put_chunked.c b/src/testcurl/test_put_chunked.c
new file mode 100644
index 00000000..ced7b29d
--- /dev/null
+++ b/src/testcurl/test_put_chunked.c
@@ -0,0 +1,441 @@
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 "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
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 if (wrt > 4)
57 wrt = 4; /* only send half at first => force multiple chunks! */
58 memcpy (stream, &("Hello123"[*pos]), wrt);
59 (*pos) += wrt;
60 return wrt;
61}
62
63static size_t
64copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx)
65{
66 struct CBC *cbc = ctx;
67
68 if (cbc->pos + size * nmemb > cbc->size)
69 return 0; /* overflow */
70 memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb);
71 cbc->pos += size * nmemb;
72 return size * nmemb;
73}
74
75static int
76ahc_echo (void *cls,
77 struct MHD_Connection *connection,
78 const char *url,
79 const char *method,
80 const char *version,
81 const char *upload_data, size_t *upload_data_size,
82 void **unused)
83{
84 int *done = cls;
85 struct MHD_Response *response;
86 int ret;
87 int have;
88
89 if (0 != strcmp ("PUT", method))
90 return MHD_NO; /* unexpected method */
91 if ((*done) < 8)
92 {
93 have = *upload_data_size;
94 if (have + *done > 8)
95 {
96 printf ("Invalid upload data `%8s'!\n", upload_data);
97 return MHD_NO;
98 }
99 if (0 == memcmp (upload_data, &"Hello123"[*done], have))
100 {
101 *done += have;
102 *upload_data_size = 0;
103 }
104 else
105 {
106 printf ("Invalid upload data `%8s'!\n", upload_data);
107 return MHD_NO;
108 }
109#if 0
110 fprintf (stderr, "Not ready for response: %u/%u\n", *done, 8);
111#endif
112 return MHD_YES;
113 }
114 response = MHD_create_response_from_buffer (strlen (url),
115 (void *) url,
116 MHD_RESPMEM_MUST_COPY);
117 ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
118 MHD_destroy_response (response);
119 return ret;
120}
121
122
123static int
124testInternalPut ()
125{
126 struct MHD_Daemon *d;
127 CURL *c;
128 char buf[2048];
129 struct CBC cbc;
130 unsigned int pos = 0;
131 int done_flag = 0;
132 CURLcode errornum;
133
134 cbc.buf = buf;
135 cbc.size = 2048;
136 cbc.pos = 0;
137 d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG,
138 11080,
139 NULL, NULL, &ahc_echo, &done_flag, MHD_OPTION_END);
140 if (d == NULL)
141 return 1;
142 c = curl_easy_init ();
143 curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:11080/hello_world");
144 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
145 curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
146 curl_easy_setopt (c, CURLOPT_READFUNCTION, &putBuffer);
147 curl_easy_setopt (c, CURLOPT_READDATA, &pos);
148 curl_easy_setopt (c, CURLOPT_UPLOAD, 1L);
149 /*
150 // by not giving the file size, we force chunking!
151 curl_easy_setopt (c, CURLOPT_INFILESIZE_LARGE, (curl_off_t) 8L);
152 */
153 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
154 curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
155 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
156 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
157 // NOTE: use of CONNECTTIMEOUT without also
158 // setting NOSIGNAL results in really weird
159 // crashes on my system!
160 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
161 if (CURLE_OK != (errornum = curl_easy_perform (c)))
162 {
163 fprintf (stderr,
164 "curl_easy_perform failed: `%s'\n",
165 curl_easy_strerror (errornum));
166 curl_easy_cleanup (c);
167 MHD_stop_daemon (d);
168 return 2;
169 }
170 curl_easy_cleanup (c);
171 MHD_stop_daemon (d);
172 if (cbc.pos != strlen ("/hello_world"))
173 return 4;
174 if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
175 return 8;
176 return 0;
177}
178
179static int
180testMultithreadedPut ()
181{
182 struct MHD_Daemon *d;
183 CURL *c;
184 char buf[2048];
185 struct CBC cbc;
186 unsigned int pos = 0;
187 int done_flag = 0;
188 CURLcode errornum;
189
190 cbc.buf = buf;
191 cbc.size = 2048;
192 cbc.pos = 0;
193 d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_DEBUG,
194 11081,
195 NULL, NULL, &ahc_echo, &done_flag, MHD_OPTION_END);
196 if (d == NULL)
197 return 16;
198 c = curl_easy_init ();
199 curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:11081/hello_world");
200 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
201 curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
202 curl_easy_setopt (c, CURLOPT_READFUNCTION, &putBuffer);
203 curl_easy_setopt (c, CURLOPT_READDATA, &pos);
204 curl_easy_setopt (c, CURLOPT_UPLOAD, 1L);
205 /*
206 // by not giving the file size, we force chunking!
207 curl_easy_setopt (c, CURLOPT_INFILESIZE_LARGE, (curl_off_t) 8L);
208 */
209 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
210 curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
211 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
212 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
213 // NOTE: use of CONNECTTIMEOUT without also
214 // setting NOSIGNAL results in really weird
215 // crashes on my system!
216 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
217 if (CURLE_OK != (errornum = curl_easy_perform (c)))
218 {
219 fprintf (stderr,
220 "curl_easy_perform failed: `%s'\n",
221 curl_easy_strerror (errornum));
222 curl_easy_cleanup (c);
223 MHD_stop_daemon (d);
224 return 32;
225 }
226 curl_easy_cleanup (c);
227 MHD_stop_daemon (d);
228 if (cbc.pos != strlen ("/hello_world"))
229 return 64;
230 if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
231 return 128;
232
233 return 0;
234}
235
236static int
237testMultithreadedPoolPut ()
238{
239 struct MHD_Daemon *d;
240 CURL *c;
241 char buf[2048];
242 struct CBC cbc;
243 unsigned int pos = 0;
244 int done_flag = 0;
245 CURLcode errornum;
246
247 cbc.buf = buf;
248 cbc.size = 2048;
249 cbc.pos = 0;
250 d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG,
251 11081,
252 NULL, NULL, &ahc_echo, &done_flag,
253 MHD_OPTION_THREAD_POOL_SIZE, 4, MHD_OPTION_END);
254 if (d == NULL)
255 return 16;
256 c = curl_easy_init ();
257 curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:11081/hello_world");
258 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
259 curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
260 curl_easy_setopt (c, CURLOPT_READFUNCTION, &putBuffer);
261 curl_easy_setopt (c, CURLOPT_READDATA, &pos);
262 curl_easy_setopt (c, CURLOPT_UPLOAD, 1L);
263 /*
264 // by not giving the file size, we force chunking!
265 curl_easy_setopt (c, CURLOPT_INFILESIZE_LARGE, (curl_off_t) 8L);
266 */
267 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
268 curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
269 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
270 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
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, 1);
275 if (CURLE_OK != (errornum = curl_easy_perform (c)))
276 {
277 fprintf (stderr,
278 "curl_easy_perform failed: `%s'\n",
279 curl_easy_strerror (errornum));
280 curl_easy_cleanup (c);
281 MHD_stop_daemon (d);
282 return 32;
283 }
284 curl_easy_cleanup (c);
285 MHD_stop_daemon (d);
286 if (cbc.pos != strlen ("/hello_world"))
287 return 64;
288 if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
289 return 128;
290
291 return 0;
292}
293
294
295static int
296testExternalPut ()
297{
298 struct MHD_Daemon *d;
299 CURL *c;
300 char buf[2048];
301 struct CBC cbc;
302 CURLM *multi;
303 CURLMcode mret;
304 fd_set rs;
305 fd_set ws;
306 fd_set es;
307 int max;
308 int running;
309 struct CURLMsg *msg;
310 time_t start;
311 struct timeval tv;
312 unsigned int pos = 0;
313 int done_flag = 0;
314
315 multi = NULL;
316 cbc.buf = buf;
317 cbc.size = 2048;
318 cbc.pos = 0;
319 d = MHD_start_daemon (MHD_USE_DEBUG,
320 11082,
321 NULL, NULL, &ahc_echo, &done_flag, MHD_OPTION_END);
322 if (d == NULL)
323 return 256;
324 c = curl_easy_init ();
325 curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:11082/hello_world");
326 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
327 curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
328 curl_easy_setopt (c, CURLOPT_READFUNCTION, &putBuffer);
329 curl_easy_setopt (c, CURLOPT_READDATA, &pos);
330 curl_easy_setopt (c, CURLOPT_UPLOAD, 1L);
331 /*
332 // by not giving the file size, we force chunking!
333 curl_easy_setopt (c, CURLOPT_INFILESIZE_LARGE, (curl_off_t) 8L);
334 */
335 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
336 curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
337 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
338 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
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, 1);
343
344
345 multi = curl_multi_init ();
346 if (multi == NULL)
347 {
348 curl_easy_cleanup (c);
349 MHD_stop_daemon (d);
350 return 512;
351 }
352 mret = curl_multi_add_handle (multi, c);
353 if (mret != CURLM_OK)
354 {
355 curl_multi_cleanup (multi);
356 curl_easy_cleanup (c);
357 MHD_stop_daemon (d);
358 return 1024;
359 }
360 start = time (NULL);
361 while ((time (NULL) - start < 5) && (multi != NULL))
362 {
363 max = 0;
364 FD_ZERO (&rs);
365 FD_ZERO (&ws);
366 FD_ZERO (&es);
367 curl_multi_perform (multi, &running);
368 mret = curl_multi_fdset (multi, &rs, &ws, &es, &max);
369 if (mret != CURLM_OK)
370 {
371 curl_multi_remove_handle (multi, c);
372 curl_multi_cleanup (multi);
373 curl_easy_cleanup (c);
374 MHD_stop_daemon (d);
375 return 2048;
376 }
377 if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &max))
378 {
379 curl_multi_remove_handle (multi, c);
380 curl_multi_cleanup (multi);
381 curl_easy_cleanup (c);
382 MHD_stop_daemon (d);
383 return 4096;
384 }
385 tv.tv_sec = 0;
386 tv.tv_usec = 1000;
387 select (max + 1, &rs, &ws, &es, &tv);
388 curl_multi_perform (multi, &running);
389 if (running == 0)
390 {
391 msg = curl_multi_info_read (multi, &running);
392 if (msg == NULL)
393 break;
394 if (msg->msg == CURLMSG_DONE)
395 {
396 if (msg->data.result != CURLE_OK)
397 printf ("%s failed at %s:%d: `%s'\n",
398 "curl_multi_perform",
399 __FILE__,
400 __LINE__, curl_easy_strerror (msg->data.result));
401 curl_multi_remove_handle (multi, c);
402 curl_multi_cleanup (multi);
403 curl_easy_cleanup (c);
404 c = NULL;
405 multi = NULL;
406 }
407 }
408 MHD_run (d);
409 }
410 if (multi != NULL)
411 {
412 curl_multi_remove_handle (multi, c);
413 curl_easy_cleanup (c);
414 curl_multi_cleanup (multi);
415 }
416 MHD_stop_daemon (d);
417 if (cbc.pos != strlen ("/hello_world"))
418 return 8192;
419 if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
420 return 16384;
421 return 0;
422}
423
424
425
426int
427main (int argc, char *const *argv)
428{
429 unsigned int errorCount = 0;
430
431 if (0 != curl_global_init (CURL_GLOBAL_WIN32))
432 return 2;
433 errorCount += testInternalPut ();
434 errorCount += testMultithreadedPut ();
435 errorCount += testMultithreadedPoolPut ();
436 errorCount += testExternalPut ();
437 if (errorCount != 0)
438 fprintf (stderr, "Error (code: %u)\n", errorCount);
439 curl_global_cleanup ();
440 return errorCount != 0; /* 0 == pass */
441}