Home | History | Annotate | Download | only in testcurl
      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
     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
     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
     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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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