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 }