• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2      This file is part of libmicrohttpd
3      Copyright (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 test_post.c
23  * @brief  Testcase for libmicrohttpd POST operations using URL-encoding
24  * @author Christian Grothoff
25  */
26 
27 #include "MHD_config.h"
28 #include "platform.h"
29 #include <curl/curl.h>
30 #include <microhttpd.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <time.h>
34 
35 #ifndef WINDOWS
36 #include <unistd.h>
37 #endif
38 
39 #ifdef _WIN32
40 #ifndef WIN32_LEAN_AND_MEAN
41 #define WIN32_LEAN_AND_MEAN 1
42 #endif /* !WIN32_LEAN_AND_MEAN */
43 #include <windows.h>
44 #endif
45 
46 #if defined(CPU_COUNT) && (CPU_COUNT+0) < 2
47 #undef CPU_COUNT
48 #endif
49 #if !defined(CPU_COUNT)
50 #define CPU_COUNT 2
51 #endif
52 
53 #define POST_DATA "name=daniel&project=curl"
54 
55 static int oneone;
56 
57 struct CBC
58 {
59   char *buf;
60   size_t pos;
61   size_t size;
62 };
63 
64 
65 static void
completed_cb(void * cls,struct MHD_Connection * connection,void ** con_cls,enum MHD_RequestTerminationCode toe)66 completed_cb (void *cls,
67 	      struct MHD_Connection *connection,
68 	      void **con_cls,
69 	      enum MHD_RequestTerminationCode toe)
70 {
71   struct MHD_PostProcessor *pp = *con_cls;
72 
73   if (NULL != pp)
74     MHD_destroy_post_processor (pp);
75   *con_cls = NULL;
76 }
77 
78 
79 static size_t
copyBuffer(void * ptr,size_t size,size_t nmemb,void * ctx)80 copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx)
81 {
82   struct CBC *cbc = ctx;
83 
84   if (cbc->pos + size * nmemb > cbc->size)
85     return 0;                   /* overflow */
86   memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb);
87   cbc->pos += size * nmemb;
88   return size * nmemb;
89 }
90 
91 
92 /**
93  * Note that this post_iterator is not perfect
94  * in that it fails to support incremental processing.
95  * (to be fixed in the future)
96  */
97 static int
post_iterator(void * cls,enum MHD_ValueKind kind,const char * key,const char * filename,const char * content_type,const char * transfer_encoding,const char * value,uint64_t off,size_t size)98 post_iterator (void *cls,
99                enum MHD_ValueKind kind,
100                const char *key,
101                const char *filename,
102                const char *content_type,
103                const char *transfer_encoding,
104                const char *value, uint64_t off, size_t size)
105 {
106   int *eok = cls;
107 
108   if ((0 == strcmp (key, "name")) &&
109       (size == strlen ("daniel")) && (0 == strncmp (value, "daniel", size)))
110     (*eok) |= 1;
111   if ((0 == strcmp (key, "project")) &&
112       (size == strlen ("curl")) && (0 == strncmp (value, "curl", size)))
113     (*eok) |= 2;
114   return MHD_YES;
115 }
116 
117 
118 static int
ahc_echo(void * cls,struct MHD_Connection * connection,const char * url,const char * method,const char * version,const char * upload_data,size_t * upload_data_size,void ** unused)119 ahc_echo (void *cls,
120           struct MHD_Connection *connection,
121           const char *url,
122           const char *method,
123           const char *version,
124           const char *upload_data, size_t *upload_data_size,
125           void **unused)
126 {
127   static int eok;
128   struct MHD_Response *response;
129   struct MHD_PostProcessor *pp;
130   int ret;
131 
132   if (0 != strcmp ("POST", method))
133     {
134       printf ("METHOD: %s\n", method);
135       return MHD_NO;            /* unexpected method */
136     }
137   pp = *unused;
138   if (pp == NULL)
139     {
140       eok = 0;
141       pp = MHD_create_post_processor (connection, 1024, &post_iterator, &eok);
142       *unused = pp;
143     }
144   MHD_post_process (pp, upload_data, *upload_data_size);
145   if ((eok == 3) && (0 == *upload_data_size))
146     {
147       response = MHD_create_response_from_buffer (strlen (url),
148 						  (void *) url,
149 						  MHD_RESPMEM_MUST_COPY);
150       ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
151       MHD_destroy_response (response);
152       MHD_destroy_post_processor (pp);
153       *unused = NULL;
154       return ret;
155     }
156   *upload_data_size = 0;
157   return MHD_YES;
158 }
159 
160 
161 static int
testInternalPost()162 testInternalPost ()
163 {
164   struct MHD_Daemon *d;
165   CURL *c;
166   char buf[2048];
167   struct CBC cbc;
168   CURLcode errornum;
169 
170   cbc.buf = buf;
171   cbc.size = 2048;
172   cbc.pos = 0;
173   d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG,
174                         1080, NULL, NULL, &ahc_echo, NULL,
175 			MHD_OPTION_NOTIFY_COMPLETED, &completed_cb, NULL,
176 			MHD_OPTION_END);
177   if (d == NULL)
178     return 1;
179   c = curl_easy_init ();
180   curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:1080/hello_world");
181   curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
182   curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
183   curl_easy_setopt (c, CURLOPT_POSTFIELDS, POST_DATA);
184   curl_easy_setopt (c, CURLOPT_POSTFIELDSIZE, strlen (POST_DATA));
185   curl_easy_setopt (c, CURLOPT_POST, 1L);
186   curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
187   curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
188   if (oneone)
189     curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
190   else
191     curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
192   curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
193   // NOTE: use of CONNECTTIMEOUT without also
194   //   setting NOSIGNAL results in really weird
195   //   crashes on my system!
196   curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
197   if (CURLE_OK != (errornum = curl_easy_perform (c)))
198     {
199       fprintf (stderr,
200                "curl_easy_perform failed: `%s'\n",
201                curl_easy_strerror (errornum));
202       curl_easy_cleanup (c);
203       MHD_stop_daemon (d);
204       return 2;
205     }
206   curl_easy_cleanup (c);
207   MHD_stop_daemon (d);
208   if (cbc.pos != strlen ("/hello_world"))
209     return 4;
210   if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
211     return 8;
212   return 0;
213 }
214 
215 static int
testMultithreadedPost()216 testMultithreadedPost ()
217 {
218   struct MHD_Daemon *d;
219   CURL *c;
220   char buf[2048];
221   struct CBC cbc;
222   CURLcode errornum;
223 
224   cbc.buf = buf;
225   cbc.size = 2048;
226   cbc.pos = 0;
227   d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_DEBUG,
228                         1081, NULL, NULL, &ahc_echo, NULL,
229 			MHD_OPTION_NOTIFY_COMPLETED, &completed_cb, NULL,
230 			MHD_OPTION_END);
231   if (d == NULL)
232     return 16;
233   c = curl_easy_init ();
234   curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:1081/hello_world");
235   curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
236   curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
237   curl_easy_setopt (c, CURLOPT_POSTFIELDS, POST_DATA);
238   curl_easy_setopt (c, CURLOPT_POSTFIELDSIZE, strlen (POST_DATA));
239   curl_easy_setopt (c, CURLOPT_POST, 1L);
240   curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
241   curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
242   if (oneone)
243     curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
244   else
245     curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
246   curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
247   // NOTE: use of CONNECTTIMEOUT without also
248   //   setting NOSIGNAL results in really weird
249   //   crashes on my system!
250   curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
251   if (CURLE_OK != (errornum = curl_easy_perform (c)))
252     {
253       fprintf (stderr,
254                "curl_easy_perform failed: `%s'\n",
255                curl_easy_strerror (errornum));
256       curl_easy_cleanup (c);
257       MHD_stop_daemon (d);
258       return 32;
259     }
260   curl_easy_cleanup (c);
261   MHD_stop_daemon (d);
262   if (cbc.pos != strlen ("/hello_world"))
263     return 64;
264   if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
265     return 128;
266   return 0;
267 }
268 
269 static int
testMultithreadedPoolPost()270 testMultithreadedPoolPost ()
271 {
272   struct MHD_Daemon *d;
273   CURL *c;
274   char buf[2048];
275   struct CBC cbc;
276   CURLcode errornum;
277 
278   cbc.buf = buf;
279   cbc.size = 2048;
280   cbc.pos = 0;
281   d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG,
282                         1081, NULL, NULL, &ahc_echo, NULL,
283                         MHD_OPTION_THREAD_POOL_SIZE, CPU_COUNT,
284 			MHD_OPTION_NOTIFY_COMPLETED, &completed_cb, NULL,
285 			MHD_OPTION_END);
286   if (d == NULL)
287     return 16;
288   c = curl_easy_init ();
289   curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:1081/hello_world");
290   curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
291   curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
292   curl_easy_setopt (c, CURLOPT_POSTFIELDS, POST_DATA);
293   curl_easy_setopt (c, CURLOPT_POSTFIELDSIZE, strlen (POST_DATA));
294   curl_easy_setopt (c, CURLOPT_POST, 1L);
295   curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
296   curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
297   if (oneone)
298     curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
299   else
300     curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
301   curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
302   // NOTE: use of CONNECTTIMEOUT without also
303   //   setting NOSIGNAL results in really weird
304   //   crashes on my system!
305   curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
306   if (CURLE_OK != (errornum = curl_easy_perform (c)))
307     {
308       fprintf (stderr,
309                "curl_easy_perform failed: `%s'\n",
310                curl_easy_strerror (errornum));
311       curl_easy_cleanup (c);
312       MHD_stop_daemon (d);
313       return 32;
314     }
315   curl_easy_cleanup (c);
316   MHD_stop_daemon (d);
317   if (cbc.pos != strlen ("/hello_world"))
318     return 64;
319   if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
320     return 128;
321   return 0;
322 }
323 
324 static int
testExternalPost()325 testExternalPost ()
326 {
327   struct MHD_Daemon *d;
328   CURL *c;
329   char buf[2048];
330   struct CBC cbc;
331   CURLM *multi;
332   CURLMcode mret;
333   fd_set rs;
334   fd_set ws;
335   fd_set es;
336   MHD_socket max;
337   int running;
338   struct CURLMsg *msg;
339   time_t start;
340   struct timeval tv;
341 
342   multi = NULL;
343   cbc.buf = buf;
344   cbc.size = 2048;
345   cbc.pos = 0;
346   d = MHD_start_daemon (MHD_USE_DEBUG,
347                         1082, NULL, NULL, &ahc_echo, NULL,
348 			MHD_OPTION_NOTIFY_COMPLETED, &completed_cb, NULL,
349 			MHD_OPTION_END);
350   if (d == NULL)
351     return 256;
352   c = curl_easy_init ();
353   curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:1082/hello_world");
354   curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
355   curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
356   curl_easy_setopt (c, CURLOPT_POSTFIELDS, POST_DATA);
357   curl_easy_setopt (c, CURLOPT_POSTFIELDSIZE, strlen (POST_DATA));
358   curl_easy_setopt (c, CURLOPT_POST, 1L);
359   curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
360   curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
361   if (oneone)
362     curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
363   else
364     curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
365   curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
366   // NOTE: use of CONNECTTIMEOUT without also
367   //   setting NOSIGNAL results in really weird
368   //   crashes on my system!
369   curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
370 
371 
372   multi = curl_multi_init ();
373   if (multi == NULL)
374     {
375       curl_easy_cleanup (c);
376       MHD_stop_daemon (d);
377       return 512;
378     }
379   mret = curl_multi_add_handle (multi, c);
380   if (mret != CURLM_OK)
381     {
382       curl_multi_cleanup (multi);
383       curl_easy_cleanup (c);
384       MHD_stop_daemon (d);
385       return 1024;
386     }
387   start = time (NULL);
388   while ((time (NULL) - start < 5) && (multi != NULL))
389     {
390       max = 0;
391       FD_ZERO (&rs);
392       FD_ZERO (&ws);
393       FD_ZERO (&es);
394       curl_multi_perform (multi, &running);
395       mret = curl_multi_fdset (multi, &rs, &ws, &es, &max);
396       if (mret != CURLM_OK)
397         {
398           curl_multi_remove_handle (multi, c);
399           curl_multi_cleanup (multi);
400           curl_easy_cleanup (c);
401           MHD_stop_daemon (d);
402           return 2048;
403         }
404       if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &max))
405         {
406           curl_multi_remove_handle (multi, c);
407           curl_multi_cleanup (multi);
408           curl_easy_cleanup (c);
409           MHD_stop_daemon (d);
410           return 4096;
411         }
412       tv.tv_sec = 0;
413       tv.tv_usec = 1000;
414       select (max + 1, &rs, &ws, &es, &tv);
415       curl_multi_perform (multi, &running);
416       if (running == 0)
417         {
418           msg = curl_multi_info_read (multi, &running);
419           if (msg == NULL)
420             break;
421           if (msg->msg == CURLMSG_DONE)
422             {
423               if (msg->data.result != CURLE_OK)
424                 printf ("%s failed at %s:%d: `%s'\n",
425                         "curl_multi_perform",
426                         __FILE__,
427                         __LINE__, curl_easy_strerror (msg->data.result));
428               curl_multi_remove_handle (multi, c);
429               curl_multi_cleanup (multi);
430               curl_easy_cleanup (c);
431               c = NULL;
432               multi = NULL;
433             }
434         }
435       MHD_run (d);
436     }
437   if (multi != NULL)
438     {
439       curl_multi_remove_handle (multi, c);
440       curl_easy_cleanup (c);
441       curl_multi_cleanup (multi);
442     }
443   MHD_stop_daemon (d);
444   if (cbc.pos != strlen ("/hello_world"))
445     return 8192;
446   if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
447     return 16384;
448   return 0;
449 }
450 
451 
452 static int
ahc_cancel(void * cls,struct MHD_Connection * connection,const char * url,const char * method,const char * version,const char * upload_data,size_t * upload_data_size,void ** unused)453 ahc_cancel (void *cls,
454 	    struct MHD_Connection *connection,
455 	    const char *url,
456 	    const char *method,
457 	    const char *version,
458 	    const char *upload_data, size_t *upload_data_size,
459 	    void **unused)
460 {
461   struct MHD_Response *response;
462   int ret;
463 
464   if (0 != strcmp ("POST", method))
465     {
466       fprintf (stderr,
467 	       "Unexpected method `%s'\n", method);
468       return MHD_NO;
469     }
470 
471   if (*unused == NULL)
472     {
473       *unused = "wibble";
474       /* We don't want the body. Send a 500. */
475       response = MHD_create_response_from_buffer (0, NULL,
476 						  MHD_RESPMEM_PERSISTENT);
477       ret = MHD_queue_response(connection, 500, response);
478       if (ret != MHD_YES)
479 	fprintf(stderr, "Failed to queue response\n");
480       MHD_destroy_response(response);
481       return ret;
482     }
483   else
484     {
485       fprintf(stderr,
486 	      "In ahc_cancel again. This should not happen.\n");
487       return MHD_NO;
488     }
489 }
490 
491 struct CRBC
492 {
493   const char *buffer;
494   size_t size;
495   size_t pos;
496 };
497 
498 
499 static size_t
readBuffer(void * p,size_t size,size_t nmemb,void * opaque)500 readBuffer(void *p, size_t size, size_t nmemb, void *opaque)
501 {
502   struct CRBC *data = opaque;
503   size_t required = size * nmemb;
504   size_t left = data->size - data->pos;
505 
506   if (required > left)
507     required = left;
508 
509   memcpy(p, data->buffer + data->pos, required);
510   data->pos += required;
511 
512   return required/size;
513 }
514 
515 
516 static size_t
slowReadBuffer(void * p,size_t size,size_t nmemb,void * opaque)517 slowReadBuffer(void *p, size_t size, size_t nmemb, void *opaque)
518 {
519   sleep(1);
520   return readBuffer(p, size, nmemb, opaque);
521 }
522 
523 
524 #define FLAG_EXPECT_CONTINUE 1
525 #define FLAG_CHUNKED 2
526 #define FLAG_FORM_DATA 4
527 #define FLAG_SLOW_READ 8
528 #define FLAG_COUNT 16
529 
530 
531 static int
testMultithreadedPostCancelPart(int flags)532 testMultithreadedPostCancelPart(int flags)
533 {
534   struct MHD_Daemon *d;
535   CURL *c;
536   char buf[2048];
537   struct CBC cbc;
538   CURLcode errornum;
539   struct curl_slist *headers = NULL;
540   long response_code;
541   CURLcode cc;
542   int result = 0;
543   struct CRBC crbc;
544 
545   /* Don't test features that aren't available with HTTP/1.0 in
546    * HTTP/1.0 mode. */
547   if (!oneone && (flags & (FLAG_EXPECT_CONTINUE | FLAG_CHUNKED)))
548     return 0;
549 
550   cbc.buf = buf;
551   cbc.size = 2048;
552   cbc.pos = 0;
553   d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_DEBUG,
554                         1081, NULL, NULL, &ahc_cancel, NULL,
555 			MHD_OPTION_END);
556   if (d == NULL)
557     return 32768;
558 
559   crbc.buffer = "Test content";
560   crbc.size = strlen(crbc.buffer);
561   crbc.pos = 0;
562 
563   c = curl_easy_init ();
564   curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:1081/hello_world");
565   curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
566   curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
567   curl_easy_setopt (c, CURLOPT_READFUNCTION, (flags & FLAG_SLOW_READ) ? &slowReadBuffer : &readBuffer);
568   curl_easy_setopt (c, CURLOPT_READDATA, &crbc);
569   curl_easy_setopt (c, CURLOPT_POSTFIELDS, NULL);
570   curl_easy_setopt (c, CURLOPT_POSTFIELDSIZE, crbc.size);
571   curl_easy_setopt (c, CURLOPT_POST, 1L);
572   curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
573   curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
574   if (oneone)
575     curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
576   else
577     curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
578   curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
579   // NOTE: use of CONNECTTIMEOUT without also
580   //   setting NOSIGNAL results in really weird
581   //   crashes on my system!
582   curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
583 
584   if (flags & FLAG_CHUNKED)
585       headers = curl_slist_append(headers, "Transfer-Encoding: chunked");
586   if (!(flags & FLAG_FORM_DATA))
587   headers = curl_slist_append(headers, "Content-Type: application/octet-stream");
588   if (flags & FLAG_EXPECT_CONTINUE)
589       headers = curl_slist_append(headers, "Expect: 100-Continue");
590   curl_easy_setopt(c, CURLOPT_HTTPHEADER, headers);
591 
592   if (CURLE_HTTP_RETURNED_ERROR != (errornum = curl_easy_perform (c)))
593     {
594       fprintf (stderr,
595                "flibbet curl_easy_perform didn't fail as expected: `%s' %d\n",
596                curl_easy_strerror (errornum), errornum);
597       curl_easy_cleanup (c);
598       MHD_stop_daemon (d);
599       curl_slist_free_all(headers);
600       return 65536;
601     }
602 
603   if (CURLE_OK != (cc = curl_easy_getinfo(c, CURLINFO_RESPONSE_CODE, &response_code)))
604     {
605       fprintf(stderr, "curl_easy_getinfo failed: '%s'\n", curl_easy_strerror(errornum));
606       result = 65536;
607     }
608 
609   if (!result && (response_code != 500))
610     {
611       fprintf(stderr, "Unexpected response code: %ld\n", response_code);
612       result = 131072;
613     }
614 
615   if (!result && (cbc.pos != 0))
616     result = 262144;
617 
618   curl_easy_cleanup (c);
619   MHD_stop_daemon (d);
620   curl_slist_free_all(headers);
621   return result;
622 }
623 
624 
625 static int
testMultithreadedPostCancel()626 testMultithreadedPostCancel()
627 {
628   int result = 0;
629   int flags;
630   for(flags = 0; flags < FLAG_COUNT; ++flags)
631     result |= testMultithreadedPostCancelPart(flags);
632   return result;
633 }
634 
635 
636 int
main(int argc,char * const * argv)637 main (int argc, char *const *argv)
638 {
639   unsigned int errorCount = 0;
640 
641   oneone = (NULL != strrchr (argv[0], (int) '/')) ?
642     (NULL != strstr (strrchr (argv[0], (int) '/'), "11")) : 0;
643   if (0 != curl_global_init (CURL_GLOBAL_WIN32))
644     return 2;
645   errorCount += testMultithreadedPostCancel ();
646   errorCount += testInternalPost ();
647   errorCount += testMultithreadedPost ();
648   errorCount += testMultithreadedPoolPost ();
649   errorCount += testExternalPost ();
650   if (errorCount != 0)
651     fprintf (stderr, "Error (code: %u)\n", errorCount);
652   curl_global_cleanup ();
653   return errorCount != 0;       /* 0 == pass */
654 }
655