libmicrohttpd

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

http_compression.c (5265B)


      1 /*
      2      This file is part of libmicrohttpd
      3      Copyright (C) 2019 Christian Grothoff (and other contributing authors)
      4      Copyright (C) 2019-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 http_compression.c
     22  * @brief minimal example for how to compress HTTP response
     23  * @author Silvio Clecio (silvioprog)
     24  * @author Karlson2k (Evgeny Grin)
     25  */
     26 
     27 #include "platform.h"
     28 #include <zlib.h>
     29 #include <microhttpd.h>
     30 
     31 #define PAGE                                                        \
     32   "<html><head><title>HTTP compression</title></head><body>Hello, " \
     33   "hello, hello. This is a 'hello world' message for the world, "   \
     34   "repeat, for the world.</body></html>"
     35 
     36 static enum MHD_Result
     37 can_compress (struct MHD_Connection *con)
     38 {
     39   const char *ae;
     40   const char *de;
     41 
     42   ae = MHD_lookup_connection_value (con,
     43                                     MHD_HEADER_KIND,
     44                                     MHD_HTTP_HEADER_ACCEPT_ENCODING);
     45   if (NULL == ae)
     46     return MHD_NO;
     47   if (0 == strcmp (ae,
     48                    "*"))
     49     return MHD_YES;
     50   de = strstr (ae,
     51                "deflate");
     52   if (NULL == de)
     53     return MHD_NO;
     54   if (((de == ae) ||
     55        (de[-1] == ',') ||
     56        (de[-1] == ' ')) &&
     57       ((de[strlen ("deflate")] == '\0') ||
     58        (de[strlen ("deflate")] == ',') ||
     59        (de[strlen ("deflate")] == ';')))
     60     return MHD_YES;
     61   return MHD_NO;
     62 }
     63 
     64 
     65 static enum MHD_Result
     66 body_compress (void **buf,
     67                size_t *buf_size)
     68 {
     69   Bytef *cbuf;
     70   uLongf cbuf_size;
     71   int ret;
     72 
     73   cbuf_size = compressBound ((uLong) * buf_size);
     74   cbuf = malloc (cbuf_size);
     75   if (NULL == cbuf)
     76     return MHD_NO;
     77   ret = compress (cbuf,
     78                   &cbuf_size,
     79                   (const Bytef *) *buf,
     80                   (uLong) * buf_size);
     81   if ((Z_OK != ret) ||
     82       (cbuf_size >= *buf_size))
     83   {
     84     /* compression failed */
     85     free (cbuf);
     86     return MHD_NO;
     87   }
     88   free (*buf);
     89   *buf = (void *) cbuf;
     90   *buf_size = (size_t) cbuf_size;
     91   return MHD_YES;
     92 }
     93 
     94 
     95 static enum MHD_Result
     96 ahc_echo (void *cls,
     97           struct MHD_Connection *connection,
     98           const char *url,
     99           const char *method,
    100           const char *version,
    101           const char *upload_data, size_t *upload_data_size, void **req_cls)
    102 {
    103   struct MHD_Response *response;
    104   enum MHD_Result ret;
    105   enum MHD_Result comp;
    106   size_t body_len;
    107   char *body_str;
    108   (void) cls;               /* Unused. Silent compiler warning. */
    109   (void) url;               /* Unused. Silent compiler warning. */
    110   (void) version;           /* Unused. Silent compiler warning. */
    111   (void) upload_data;       /* Unused. Silent compiler warning. */
    112   (void) upload_data_size;  /* Unused. Silent compiler warning. */
    113 
    114   if (0 != strcmp (method, "GET"))
    115     return MHD_NO; /* unexpected method */
    116   if (! *req_cls)
    117   {
    118     *req_cls = (void *) 1;
    119     return MHD_YES;
    120   }
    121   *req_cls = NULL;
    122 
    123   body_str = strdup (PAGE);
    124   if (NULL == body_str)
    125   {
    126     return MHD_NO;
    127   }
    128   body_len = strlen (body_str);
    129   /* try to compress the body */
    130   comp = MHD_NO;
    131   if (MHD_YES ==
    132       can_compress (connection))
    133     comp = body_compress ((void **) &body_str,
    134                           &body_len);
    135   response =
    136     MHD_create_response_from_buffer_with_free_callback (body_len,
    137                                                         body_str,
    138                                                         &free);
    139 
    140   if (NULL == response)
    141   {
    142     free (body_str);
    143     return MHD_NO;
    144   }
    145 
    146   if (MHD_YES == comp)
    147   {
    148     /* Need to indicate to client that body is compressed */
    149     if (MHD_NO ==
    150         MHD_add_response_header (response,
    151                                  MHD_HTTP_HEADER_CONTENT_ENCODING,
    152                                  "deflate"))
    153     {
    154       MHD_destroy_response (response);
    155       return MHD_NO;
    156     }
    157   }
    158   ret = MHD_queue_response (connection,
    159                             200,
    160                             response);
    161   MHD_destroy_response (response);
    162   return ret;
    163 }
    164 
    165 
    166 int
    167 main (int argc, char *const *argv)
    168 {
    169   struct MHD_Daemon *d;
    170   unsigned int port;
    171 
    172   if ( (argc != 2) ||
    173        (1 != sscanf (argv[1], "%u", &port)) ||
    174        (65535 < port) )
    175   {
    176     printf ("%s PORT\n", argv[0]);
    177     return 1;
    178   }
    179   d = MHD_start_daemon (MHD_USE_AUTO | MHD_USE_INTERNAL_POLLING_THREAD
    180                         | MHD_USE_ERROR_LOG,
    181                         (uint16_t) port, NULL, NULL,
    182                         &ahc_echo, NULL,
    183                         MHD_OPTION_END);
    184   if (NULL == d)
    185     return 1;
    186   (void) getc (stdin);
    187   MHD_stop_daemon (d);
    188   return 0;
    189 }