libmicrohttpd

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

test_quiesce_stream.c (6913B)


      1 /*
      2      This file is part of libmicrohttpd
      3      Copyright (C) 2016 Christian Grothoff
      4      Copyright (C) 2016-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_quiesce_stream.c
     23  * @brief  Testcase for libmicrohttpd quiescing
     24  * @author Markus Doppelbauer
     25  * @author Christian Grothoff
     26  * @author Karlson2k (Evgeny Grin)
     27  */
     28 #include "mhd_options.h"
     29 #include <stdlib.h>
     30 #include <stdio.h>
     31 #include <string.h>
     32 #include <errno.h>
     33 #include <pthread.h>
     34 #include <microhttpd.h>
     35 
     36 /* Turn any MHD_PANIC() or failing mhd_assert() reached from this
     37    test into a marked, classifiable test error (TESTING.md, P5). */
     38 #include "mhd_panic_tripwire.h"
     39 #ifdef HAVE_UNISTD_H
     40 #include <unistd.h>
     41 #elif defined(_WIN32)
     42 #include <windows.h>
     43 #define sleep(s) (Sleep ((s) * 1000), 0)
     44 #endif /* _WIN32 */
     45 
     46 
     47 static volatile unsigned int request_counter;
     48 
     49 
     50 _MHD_NORETURN static void
     51 http_PanicCallback (void *cls,
     52                     const char *file,
     53                     unsigned int line,
     54                     const char *reason)
     55 {
     56   (void) cls;    /* Unused. Silent compiler warning. */
     57   fprintf (stderr,
     58            "PANIC: exit process: %s at %s:%u\n",
     59            reason,
     60            file,
     61            line);
     62   exit (EXIT_FAILURE);
     63 }
     64 
     65 
     66 static void *
     67 resume_connection (void *arg)
     68 {
     69   struct MHD_Connection *connection = arg;
     70 
     71   /* fprintf (stderr, "Calling resume\n"); */
     72   MHD_resume_connection (connection);
     73   return NULL;
     74 }
     75 
     76 
     77 static void
     78 suspend_connection (struct MHD_Connection *connection)
     79 {
     80   pthread_t thread_id;
     81   int status;
     82 
     83   /* fprintf (stderr, "Calling suspend\n"); */
     84   MHD_suspend_connection (connection);
     85   status = pthread_create (&thread_id,
     86                            NULL,
     87                            &resume_connection,
     88                            connection);
     89   if (0 != status)
     90   {
     91     fprintf (stderr,
     92              "Could not create thead\n");
     93     exit (EXIT_FAILURE);
     94   }
     95   pthread_detach (thread_id);
     96 }
     97 
     98 
     99 struct ContentReaderUserdata
    100 {
    101   size_t bytes_written;
    102   struct MHD_Connection *connection;
    103 };
    104 
    105 
    106 static ssize_t
    107 http_ContentReaderCallback (void *cls,
    108                             uint64_t pos,
    109                             char *buf,
    110                             size_t max)
    111 {
    112   static const char alphabet[] =
    113     "\nABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
    114   struct ContentReaderUserdata *userdata = cls;
    115   (void) pos; (void) max;  /* Unused. Silent compiler warning. */
    116 
    117   if (userdata->bytes_written >= 1024)
    118   {
    119     fprintf (stderr,
    120              "finish: %u\n",
    121              request_counter);
    122     return MHD_CONTENT_READER_END_OF_STREAM;
    123   }
    124   userdata->bytes_written++;
    125   buf[0] = alphabet[userdata->bytes_written % (sizeof(alphabet) - 1)];
    126   suspend_connection (userdata->connection);
    127 
    128   return 1;
    129 }
    130 
    131 
    132 static void
    133 free_crc_data (void *crc_data)
    134 {
    135   struct ContentReaderUserdata *userdata = crc_data;
    136 
    137   free (userdata);
    138 }
    139 
    140 
    141 static enum MHD_Result
    142 http_AccessHandlerCallback (void *cls,
    143                             struct MHD_Connection *connection,
    144                             const char *url,
    145                             const char *method,
    146                             const char *version,
    147                             const char *upload_data,
    148                             size_t *upload_data_size,
    149                             void **req_cls)
    150 {
    151   enum MHD_Result ret;
    152   struct MHD_Response *response;
    153   (void) cls; (void) url;                        /* Unused. Silent compiler warning. */
    154   (void) method; (void) version; (void) upload_data; /* Unused. Silent compiler warning. */
    155   (void) upload_data_size;                       /* Unused. Silent compiler warning. */
    156 
    157   /* Never respond on first call */
    158   if (NULL == *req_cls)
    159   {
    160     struct ContentReaderUserdata *userdata;
    161     fprintf (stderr,
    162              "start: %u\n",
    163              ++request_counter);
    164 
    165     userdata = malloc (sizeof(struct ContentReaderUserdata));
    166 
    167     if (NULL == userdata)
    168       return MHD_NO;
    169     userdata->bytes_written = 0;
    170     userdata->connection = connection;
    171     *req_cls = userdata;
    172     return MHD_YES;
    173   }
    174 
    175   /* Second call: create response */
    176   response
    177     = MHD_create_response_from_callback (MHD_SIZE_UNKNOWN,
    178                                          32 * 1024,
    179                                          &http_ContentReaderCallback,
    180                                          *req_cls,
    181                                          &free_crc_data);
    182   ret = MHD_queue_response (connection,
    183                             MHD_HTTP_OK,
    184                             response);
    185   MHD_destroy_response (response);
    186 
    187   suspend_connection (connection);
    188   return ret;
    189 }
    190 
    191 
    192 int
    193 main (void)
    194 {
    195   uint16_t port;
    196   char command_line[1024];
    197   /* Flags */
    198   unsigned int daemon_flags
    199     = MHD_USE_INTERNAL_POLLING_THREAD
    200       | MHD_USE_AUTO
    201       | MHD_ALLOW_SUSPEND_RESUME
    202       | MHD_USE_ITC;
    203   struct MHD_Daemon *daemon;
    204 
    205   if (MHD_NO != MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT))
    206     port = 0;
    207   else
    208     port = 1470;
    209 
    210   /* Panic callback */
    211   MHD_set_panic_func (&http_PanicCallback,
    212                       NULL);
    213 
    214 
    215   /* Create daemon */
    216   daemon = MHD_start_daemon (daemon_flags,
    217                              port,
    218                              NULL,
    219                              NULL,
    220                              &http_AccessHandlerCallback,
    221                              NULL,
    222                              MHD_OPTION_END);
    223   if (NULL == daemon)
    224     return 1;
    225   if (0 == port)
    226   {
    227     const union MHD_DaemonInfo *dinfo;
    228     dinfo = MHD_get_daemon_info (daemon, MHD_DAEMON_INFO_BIND_PORT);
    229     if ((NULL == dinfo) || (0 == dinfo->port) )
    230     {
    231       MHD_stop_daemon (daemon); return 32;
    232     }
    233     port = dinfo->port;
    234   }
    235   snprintf (command_line,
    236             sizeof (command_line),
    237             "curl -s http://127.0.0.1:%u",
    238             (unsigned int) port);
    239 
    240   if (0 != system (command_line))
    241   {
    242     MHD_stop_daemon (daemon);
    243     return 1;
    244   }
    245   /* wait for a request */
    246   while (0 == request_counter)
    247     (void) sleep (1);
    248 
    249   fprintf (stderr,
    250            "quiesce\n");
    251   MHD_quiesce_daemon (daemon);
    252 
    253   /* wait a second */
    254   (void) sleep (1);
    255 
    256   fprintf (stderr,
    257            "stopping daemon\n");
    258   MHD_stop_daemon (daemon);
    259 
    260   return 0;
    261 }