libmicrohttpd

HTTP/1.x server C library (MHD 1.x, stable)
Log | Files | Refs | Submodules | README | LICENSE

test_callback.c (7742B)


      1 /*
      2      This file is part of libmicrohttpd
      3      Copyright (C) 2007, 2009, 2011 Christian Grothoff
      4      Copyright (C) 2014-2022 Evgeny Grin (Karlson2k)
      5 
      6      libmicrohttpd is free software; you can redistribute it and/or modify
      7      it under the terms of the GNU General Public License as published
      8      by the Free Software Foundation; either version 2, or (at your
      9      option) any later version.
     10 
     11      libmicrohttpd is distributed in the hope that it will be useful, but
     12      WITHOUT ANY WARRANTY; without even the implied warranty of
     13      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     14      General Public License for more details.
     15 
     16      You should have received a copy of the GNU General Public License
     17      along with libmicrohttpd; see the file COPYING.  If not, write to the
     18      Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     19      Boston, MA 02110-1301, USA.
     20 */
     21 /**
     22  * @file test_callback.c
     23  * @brief Testcase for MHD not calling the callback too often
     24  * @author Jan Seeger
     25  * @author Christian Grothoff
     26  * @author Karlson2k (Evgeny Grin)
     27  */
     28 #include "MHD_config.h"
     29 #include "platform.h"
     30 #include <curl/curl.h>
     31 #include <microhttpd.h>
     32 #include <errno.h>
     33 
     34 /* Turn any MHD_PANIC() or failing mhd_assert() reached from this
     35    test into a marked, classifiable test error (TESTING.md, P5). */
     36 #include "mhd_panic_tripwire.h"
     37 
     38 struct callback_closure
     39 {
     40   unsigned int called;
     41 };
     42 
     43 
     44 static ssize_t
     45 called_twice (void *cls, uint64_t pos, char *buf, size_t max)
     46 {
     47   struct callback_closure *cls2 = cls;
     48 
     49   (void) pos;    /* Unused. Silence compiler warning. */
     50   (void) max;
     51   if (cls2->called == 0)
     52   {
     53     memcpy (buf, "test", 5);
     54     cls2->called = 1;
     55     return (ssize_t) strlen (buf);
     56   }
     57   if (cls2->called == 1)
     58   {
     59     cls2->called = 2;
     60     return MHD_CONTENT_READER_END_OF_STREAM;
     61   }
     62   fprintf (stderr,
     63            "Handler called after returning END_OF_STREAM!\n");
     64   abort ();
     65   return MHD_CONTENT_READER_END_WITH_ERROR;
     66 }
     67 
     68 
     69 static enum MHD_Result
     70 callback (void *cls,
     71           struct MHD_Connection *connection,
     72           const char *url,
     73           const char *method,
     74           const char *version,
     75           const char *upload_data,
     76           size_t *upload_data_size,
     77           void **req_cls)
     78 {
     79   struct callback_closure *cbc = calloc (1, sizeof(struct callback_closure));
     80   struct MHD_Response *r;
     81   enum MHD_Result ret;
     82 
     83   (void) cls;
     84   (void) url;                          /* Unused. Silent compiler warning. */
     85   (void) method;
     86   (void) version;
     87   (void) upload_data; /* Unused. Silent compiler warning. */
     88   (void) upload_data_size;
     89   (void) req_cls;         /* Unused. Silent compiler warning. */
     90 
     91   if (NULL == cbc)
     92     return MHD_NO;
     93   r = MHD_create_response_from_callback (MHD_SIZE_UNKNOWN, 1024,
     94                                          &called_twice, cbc,
     95                                          &free);
     96   if (NULL == r)
     97   {
     98     free (cbc);
     99     return MHD_NO;
    100   }
    101   ret = MHD_queue_response (connection,
    102                             MHD_HTTP_OK,
    103                             r);
    104   MHD_destroy_response (r);
    105   return ret;
    106 }
    107 
    108 
    109 static size_t
    110 discard_buffer (void *ptr,
    111                 size_t size,
    112                 size_t nmemb,
    113                 void *ctx)
    114 {
    115   (void) ptr; (void) ctx;  /* Unused. Silent compiler warning. */
    116   return size * nmemb;
    117 }
    118 
    119 
    120 int
    121 main (int argc, char **argv)
    122 {
    123   struct MHD_Daemon *d;
    124   fd_set rs;
    125   fd_set ws;
    126   fd_set es;
    127   MHD_socket maxsock;
    128 #ifdef MHD_WINSOCK_SOCKETS
    129   int maxposixs; /* Max socket number unused on W32 */
    130 #else  /* MHD_POSIX_SOCKETS */
    131 #define maxposixs maxsock
    132 #endif /* MHD_POSIX_SOCKETS */
    133   CURL *c;
    134   CURLM *multi;
    135   CURLMcode mret;
    136   struct CURLMsg *msg;
    137   int running;
    138   struct timeval tv;
    139   int extra;
    140   uint16_t port;
    141   (void) argc; (void) argv; /* Unused. Silent compiler warning. */
    142 
    143   if (MHD_NO != MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT))
    144     port = 0;
    145   else
    146     port = 1140;
    147 
    148   d = MHD_start_daemon (MHD_USE_NO_THREAD_SAFETY,
    149                         port,
    150                         NULL,
    151                         NULL,
    152                         &callback,
    153                         NULL,
    154                         MHD_OPTION_APP_FD_SETSIZE, (int) FD_SETSIZE,
    155                         MHD_OPTION_END);
    156   if (d == NULL)
    157     return 32;
    158   if (0 == port)
    159   {
    160     const union MHD_DaemonInfo *dinfo;
    161     dinfo = MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT);
    162     if ((NULL == dinfo) || (0 == dinfo->port) )
    163     {
    164       MHD_stop_daemon (d); return 48;
    165     }
    166     port = dinfo->port;
    167   }
    168   c = curl_easy_init ();
    169   curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1/");
    170   curl_easy_setopt (c, CURLOPT_PORT, (long) port);
    171   curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &discard_buffer);
    172   curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L);
    173   curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
    174   curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
    175   curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
    176   curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
    177   multi = curl_multi_init ();
    178   if (multi == NULL)
    179   {
    180     curl_easy_cleanup (c);
    181     MHD_stop_daemon (d);
    182     return 99;
    183   }
    184   mret = curl_multi_add_handle (multi, c);
    185   if (mret != CURLM_OK)
    186   {
    187     curl_multi_cleanup (multi);
    188     curl_easy_cleanup (c);
    189     MHD_stop_daemon (d);
    190     return 99;
    191   }
    192   extra = 10;
    193   while ( (c != NULL) || (--extra > 0) )
    194   {
    195     maxsock = MHD_INVALID_SOCKET;
    196     maxposixs = -1;
    197     FD_ZERO (&ws);
    198     FD_ZERO (&rs);
    199     FD_ZERO (&es);
    200     curl_multi_perform (multi, &running);
    201     if (NULL != multi)
    202     {
    203       mret = curl_multi_fdset (multi, &rs, &ws, &es, &maxposixs);
    204       if (mret != CURLM_OK)
    205       {
    206         curl_multi_remove_handle (multi, c);
    207         curl_multi_cleanup (multi);
    208         curl_easy_cleanup (c);
    209         MHD_stop_daemon (d);
    210         return 99;
    211       }
    212     }
    213     if (MHD_YES !=
    214         MHD_get_fdset (d, &rs, &ws, &es, &maxsock))
    215     {
    216       curl_multi_remove_handle (multi, c);
    217       curl_multi_cleanup (multi);
    218       curl_easy_cleanup (c);
    219       MHD_stop_daemon (d);
    220       return 4;
    221     }
    222     tv.tv_sec = 0;
    223     tv.tv_usec = 1000;
    224     if (-1 == select (maxposixs + 1, &rs, &ws, &es, &tv))
    225     {
    226 #ifdef MHD_POSIX_SOCKETS
    227       if (EINTR != errno)
    228       {
    229         fprintf (stderr, "Unexpected select() error: %d. Line: %d\n",
    230                  (int) errno, __LINE__);
    231         fflush (stderr);
    232         exit (99);
    233       }
    234 #else
    235       if ((WSAEINVAL != WSAGetLastError ()) ||
    236           (0 != rs.fd_count) || (0 != ws.fd_count) || (0 != es.fd_count) )
    237       {
    238         fprintf (stderr, "Unexpected select() error: %d. Line: %d\n",
    239                  (int) WSAGetLastError (), __LINE__);
    240         fflush (stderr);
    241         exit (99);
    242       }
    243       Sleep (1);
    244 #endif
    245     }
    246     if (NULL != multi)
    247     {
    248       curl_multi_perform (multi, &running);
    249       if (0 == running)
    250       {
    251         int pending;
    252         int curl_fine = 0;
    253         while (NULL != (msg = curl_multi_info_read (multi, &pending)))
    254         {
    255           if (msg->msg == CURLMSG_DONE)
    256           {
    257             if (msg->data.result == CURLE_OK)
    258               curl_fine = 1;
    259             else
    260             {
    261               fprintf (stderr,
    262                        "%s failed at %s:%d: `%s'\n",
    263                        "curl_multi_perform",
    264                        __FILE__,
    265                        __LINE__, curl_easy_strerror (msg->data.result));
    266               abort ();
    267             }
    268           }
    269         }
    270         if (! curl_fine)
    271         {
    272           fprintf (stderr, "libcurl haven't returned OK code\n");
    273           abort ();
    274         }
    275         curl_multi_remove_handle (multi, c);
    276         curl_multi_cleanup (multi);
    277         curl_easy_cleanup (c);
    278         c = NULL;
    279         multi = NULL;
    280       }
    281     }
    282     MHD_run (d);
    283   }
    284   MHD_stop_daemon (d);
    285   return 0;
    286 }