libmicrohttpd

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

test_quiesce_stream.c (6746B)


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