libmicrohttpd

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

test_callback.c (7575B)


      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 struct callback_closure
     35 {
     36   unsigned int called;
     37 };
     38 
     39 
     40 static ssize_t
     41 called_twice (void *cls, uint64_t pos, char *buf, size_t max)
     42 {
     43   struct callback_closure *cls2 = cls;
     44 
     45   (void) pos;    /* Unused. Silence compiler warning. */
     46   (void) max;
     47   if (cls2->called == 0)
     48   {
     49     memcpy (buf, "test", 5);
     50     cls2->called = 1;
     51     return (ssize_t) strlen (buf);
     52   }
     53   if (cls2->called == 1)
     54   {
     55     cls2->called = 2;
     56     return MHD_CONTENT_READER_END_OF_STREAM;
     57   }
     58   fprintf (stderr,
     59            "Handler called after returning END_OF_STREAM!\n");
     60   abort ();
     61   return MHD_CONTENT_READER_END_WITH_ERROR;
     62 }
     63 
     64 
     65 static enum MHD_Result
     66 callback (void *cls,
     67           struct MHD_Connection *connection,
     68           const char *url,
     69           const char *method,
     70           const char *version,
     71           const char *upload_data,
     72           size_t *upload_data_size,
     73           void **req_cls)
     74 {
     75   struct callback_closure *cbc = calloc (1, sizeof(struct callback_closure));
     76   struct MHD_Response *r;
     77   enum MHD_Result ret;
     78 
     79   (void) cls;
     80   (void) url;                          /* Unused. Silent compiler warning. */
     81   (void) method;
     82   (void) version;
     83   (void) upload_data; /* Unused. Silent compiler warning. */
     84   (void) upload_data_size;
     85   (void) req_cls;         /* Unused. Silent compiler warning. */
     86 
     87   if (NULL == cbc)
     88     return MHD_NO;
     89   r = MHD_create_response_from_callback (MHD_SIZE_UNKNOWN, 1024,
     90                                          &called_twice, cbc,
     91                                          &free);
     92   if (NULL == r)
     93   {
     94     free (cbc);
     95     return MHD_NO;
     96   }
     97   ret = MHD_queue_response (connection,
     98                             MHD_HTTP_OK,
     99                             r);
    100   MHD_destroy_response (r);
    101   return ret;
    102 }
    103 
    104 
    105 static size_t
    106 discard_buffer (void *ptr,
    107                 size_t size,
    108                 size_t nmemb,
    109                 void *ctx)
    110 {
    111   (void) ptr; (void) ctx;  /* Unused. Silent compiler warning. */
    112   return size * nmemb;
    113 }
    114 
    115 
    116 int
    117 main (int argc, char **argv)
    118 {
    119   struct MHD_Daemon *d;
    120   fd_set rs;
    121   fd_set ws;
    122   fd_set es;
    123   MHD_socket maxsock;
    124 #ifdef MHD_WINSOCK_SOCKETS
    125   int maxposixs; /* Max socket number unused on W32 */
    126 #else  /* MHD_POSIX_SOCKETS */
    127 #define maxposixs maxsock
    128 #endif /* MHD_POSIX_SOCKETS */
    129   CURL *c;
    130   CURLM *multi;
    131   CURLMcode mret;
    132   struct CURLMsg *msg;
    133   int running;
    134   struct timeval tv;
    135   int extra;
    136   uint16_t port;
    137   (void) argc; (void) argv; /* Unused. Silent compiler warning. */
    138 
    139   if (MHD_NO != MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT))
    140     port = 0;
    141   else
    142     port = 1140;
    143 
    144   d = MHD_start_daemon (MHD_USE_NO_THREAD_SAFETY,
    145                         port,
    146                         NULL,
    147                         NULL,
    148                         &callback,
    149                         NULL,
    150                         MHD_OPTION_APP_FD_SETSIZE, (int) FD_SETSIZE,
    151                         MHD_OPTION_END);
    152   if (d == NULL)
    153     return 32;
    154   if (0 == port)
    155   {
    156     const union MHD_DaemonInfo *dinfo;
    157     dinfo = MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT);
    158     if ((NULL == dinfo) || (0 == dinfo->port) )
    159     {
    160       MHD_stop_daemon (d); return 48;
    161     }
    162     port = dinfo->port;
    163   }
    164   c = curl_easy_init ();
    165   curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1/");
    166   curl_easy_setopt (c, CURLOPT_PORT, (long) port);
    167   curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &discard_buffer);
    168   curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L);
    169   curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
    170   curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
    171   curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
    172   curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
    173   multi = curl_multi_init ();
    174   if (multi == NULL)
    175   {
    176     curl_easy_cleanup (c);
    177     MHD_stop_daemon (d);
    178     return 99;
    179   }
    180   mret = curl_multi_add_handle (multi, c);
    181   if (mret != CURLM_OK)
    182   {
    183     curl_multi_cleanup (multi);
    184     curl_easy_cleanup (c);
    185     MHD_stop_daemon (d);
    186     return 99;
    187   }
    188   extra = 10;
    189   while ( (c != NULL) || (--extra > 0) )
    190   {
    191     maxsock = MHD_INVALID_SOCKET;
    192     maxposixs = -1;
    193     FD_ZERO (&ws);
    194     FD_ZERO (&rs);
    195     FD_ZERO (&es);
    196     curl_multi_perform (multi, &running);
    197     if (NULL != multi)
    198     {
    199       mret = curl_multi_fdset (multi, &rs, &ws, &es, &maxposixs);
    200       if (mret != CURLM_OK)
    201       {
    202         curl_multi_remove_handle (multi, c);
    203         curl_multi_cleanup (multi);
    204         curl_easy_cleanup (c);
    205         MHD_stop_daemon (d);
    206         return 99;
    207       }
    208     }
    209     if (MHD_YES !=
    210         MHD_get_fdset (d, &rs, &ws, &es, &maxsock))
    211     {
    212       curl_multi_remove_handle (multi, c);
    213       curl_multi_cleanup (multi);
    214       curl_easy_cleanup (c);
    215       MHD_stop_daemon (d);
    216       return 4;
    217     }
    218     tv.tv_sec = 0;
    219     tv.tv_usec = 1000;
    220     if (-1 == select (maxposixs + 1, &rs, &ws, &es, &tv))
    221     {
    222 #ifdef MHD_POSIX_SOCKETS
    223       if (EINTR != errno)
    224       {
    225         fprintf (stderr, "Unexpected select() error: %d. Line: %d\n",
    226                  (int) errno, __LINE__);
    227         fflush (stderr);
    228         exit (99);
    229       }
    230 #else
    231       if ((WSAEINVAL != WSAGetLastError ()) ||
    232           (0 != rs.fd_count) || (0 != ws.fd_count) || (0 != es.fd_count) )
    233       {
    234         fprintf (stderr, "Unexpected select() error: %d. Line: %d\n",
    235                  (int) WSAGetLastError (), __LINE__);
    236         fflush (stderr);
    237         exit (99);
    238       }
    239       Sleep (1);
    240 #endif
    241     }
    242     if (NULL != multi)
    243     {
    244       curl_multi_perform (multi, &running);
    245       if (0 == running)
    246       {
    247         int pending;
    248         int curl_fine = 0;
    249         while (NULL != (msg = curl_multi_info_read (multi, &pending)))
    250         {
    251           if (msg->msg == CURLMSG_DONE)
    252           {
    253             if (msg->data.result == CURLE_OK)
    254               curl_fine = 1;
    255             else
    256             {
    257               fprintf (stderr,
    258                        "%s failed at %s:%d: `%s'\n",
    259                        "curl_multi_perform",
    260                        __FILE__,
    261                        __LINE__, curl_easy_strerror (msg->data.result));
    262               abort ();
    263             }
    264           }
    265         }
    266         if (! curl_fine)
    267         {
    268           fprintf (stderr, "libcurl haven't returned OK code\n");
    269           abort ();
    270         }
    271         curl_multi_remove_handle (multi, c);
    272         curl_multi_cleanup (multi);
    273         curl_easy_cleanup (c);
    274         c = NULL;
    275         multi = NULL;
    276       }
    277     }
    278     MHD_run (d);
    279   }
    280   MHD_stop_daemon (d);
    281   return 0;
    282 }