libmicrohttpd

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

chunked_example.c (6002B)


      1 /*
      2      This file is part of libmicrohttpd
      3      Copyright (C) 2015 Christian Grothoff (and other contributing authors)
      4      Copyright (C) 2016-2022 Evgeny Grin (Karlson2k)
      5 
      6      This library is free software; you can redistribute it and/or
      7      modify it under the terms of the GNU Lesser General Public
      8      License as published by the Free Software Foundation; either
      9      version 2.1 of the License, or (at your option) any later version.
     10 
     11      This library is distributed in the hope that it will be useful,
     12      but WITHOUT ANY WARRANTY; without even the implied warranty of
     13      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     14      Lesser General Public License for more details.
     15 
     16      You should have received a copy of the GNU Lesser General Public
     17      License along with this library; if not, write to the Free Software
     18      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
     19 */
     20 /**
     21  * @file chunked_example.c
     22  * @brief example for generating chunked encoding with libmicrohttpd
     23  * @author Christian Grothoff
     24  * @author Karlson2k (Evgeny Grin)
     25  */
     26 
     27 #include "platform.h"
     28 #include <microhttpd.h>
     29 
     30 struct ResponseContentCallbackParam
     31 {
     32   const char *response_data;
     33   size_t response_size;
     34 };
     35 
     36 
     37 static ssize_t
     38 callback (void *cls,
     39           uint64_t pos,
     40           char *buf,
     41           size_t buf_size)
     42 {
     43   size_t size_to_copy;
     44   struct ResponseContentCallbackParam *const param =
     45     (struct ResponseContentCallbackParam *) cls;
     46 
     47   /* Note: 'pos' will never exceed size of transmitted data. */
     48   /* You can use 'pos == param->response_size' in next check. */
     49   if (pos >= param->response_size)
     50   {   /* Whole response was sent. Signal end of response. */
     51     return MHD_CONTENT_READER_END_OF_STREAM;
     52   }
     53 
     54   /* Pseudo code.        *
     55   if (data_not_ready)
     56     {
     57       // Callback will be called again on next loop.
     58       // Consider suspending connection until data will be ready.
     59       return 0;
     60     }
     61    * End of pseudo code. */
     62   if (buf_size < (param->response_size - pos))
     63     size_to_copy = buf_size;
     64   else
     65     size_to_copy = (size_t) (param->response_size - pos);
     66 
     67   memcpy (buf, param->response_data + pos, size_to_copy);
     68 
     69   /* Pseudo code.        *
     70   if (error_preparing_response)
     71     {
     72       // Close connection with error.
     73       return MHD_CONTENT_READER_END_WITH_ERROR;
     74     }
     75    * End of pseudo code. */
     76   /* Return amount of data copied to buffer. */
     77   /* The 'buf_size' is always smaller than SSIZE_MAX therefore it's safe
     78    * to cast 'size_to_copy' to 'ssize_t'. */
     79   /* assert (size_to_copy <= buf_size); */
     80   return (ssize_t) size_to_copy;
     81 }
     82 
     83 
     84 static void
     85 free_callback_param (void *cls)
     86 {
     87   free (cls);
     88 }
     89 
     90 
     91 static const char simple_response_text[] =
     92   "<html><head><title>Simple response</title></head>"
     93   "<body>Simple response text</body></html>";
     94 
     95 
     96 static enum MHD_Result
     97 ahc_echo (void *cls,
     98           struct MHD_Connection *connection,
     99           const char *url,
    100           const char *method,
    101           const char *version,
    102           const char *upload_data,
    103           size_t *upload_data_size,
    104           void **req_cls)
    105 {
    106   static int aptr;
    107   struct ResponseContentCallbackParam *callback_param;
    108   struct MHD_Response *response;
    109   enum MHD_Result ret;
    110   (void) cls;               /* Unused. Silent compiler warning. */
    111   (void) url;               /* Unused. Silent compiler warning. */
    112   (void) version;           /* Unused. Silent compiler warning. */
    113   (void) upload_data;       /* Unused. Silent compiler warning. */
    114   (void) upload_data_size;  /* Unused. Silent compiler warning. */
    115 
    116   if (0 != strcmp (method, "GET"))
    117     return MHD_NO;              /* unexpected method */
    118   if (&aptr != *req_cls)
    119   {
    120     /* do never respond on first call */
    121     *req_cls = &aptr;
    122     return MHD_YES;
    123   }
    124 
    125   callback_param = malloc (sizeof(struct ResponseContentCallbackParam));
    126   if (NULL == callback_param)
    127     return MHD_NO; /* Not enough memory. */
    128 
    129   callback_param->response_data = simple_response_text;
    130   callback_param->response_size = (sizeof(simple_response_text)
    131                                    / sizeof(char)) - 1;
    132 
    133   *req_cls = NULL;                  /* reset when done */
    134   response = MHD_create_response_from_callback (MHD_SIZE_UNKNOWN,
    135                                                 1024,
    136                                                 &callback,
    137                                                 callback_param,
    138                                                 &free_callback_param);
    139   if (NULL == response)
    140   {
    141     free (callback_param);
    142     return MHD_NO;
    143   }
    144   /* Enforce chunked response, even for non-keep-alive connection. */
    145   if (MHD_NO == MHD_add_response_header (response,
    146                                          MHD_HTTP_HEADER_TRANSFER_ENCODING,
    147                                          "chunked"))
    148   {
    149     free (callback_param);
    150     MHD_destroy_response (response);
    151     return MHD_NO;
    152   }
    153   ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
    154   MHD_destroy_response (response);
    155   return ret;
    156 }
    157 
    158 
    159 int
    160 main (int argc, char *const *argv)
    161 {
    162   struct MHD_Daemon *d;
    163   int port;
    164 
    165   if (argc != 2)
    166   {
    167     printf ("%s PORT\n", argv[0]);
    168     return 1;
    169   }
    170   port = atoi (argv[1]);
    171   if ( (1 > port) ||
    172        (port > UINT16_MAX) )
    173   {
    174     fprintf (stderr,
    175              "Port must be a number between 1 and 65535.\n");
    176     return 1;
    177   }
    178   d = MHD_start_daemon (/* MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG, */
    179     MHD_USE_AUTO | MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG,
    180     /* MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG | MHD_USE_POLL, */
    181     /* MHD_USE_THREAD_PER_CONNECTION | MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG | MHD_USE_POLL, */
    182     /* MHD_USE_THREAD_PER_CONNECTION | MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG, */
    183     (uint16_t) port,
    184     NULL, NULL,
    185     &ahc_echo, NULL,
    186     MHD_OPTION_CONNECTION_TIMEOUT, (unsigned int) 120,
    187     MHD_OPTION_END);
    188   if (NULL == d)
    189     return 1;
    190   (void) getc (stdin);
    191   MHD_stop_daemon (d);
    192   return 0;
    193 }