| /* |
| This file is part of libmicrohttpd |
| Copyright (C) 2019 Christian Grothoff (and other contributing authors) |
| Copyright (C) 2019-2022 Evgeny Grin (Karlson2k) |
| |
| This library is free software; you can redistribute it and/or |
| modify it under the terms of the GNU Lesser General Public |
| License as published by the Free Software Foundation; either |
| version 2.1 of the License, or (at your option) any later version. |
| |
| This library is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| Lesser General Public License for more details. |
| |
| You should have received a copy of the GNU Lesser General Public |
| License along with this library; if not, write to the Free Software |
| Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
| */ |
| /** |
| * @file http_compression.c |
| * @brief minimal example for how to compress HTTP response |
| * @author Silvio Clecio (silvioprog) |
| * @author Karlson2k (Evgeny Grin) |
| */ |
| |
| #include "platform.h" |
| #include <zlib.h> |
| #include <microhttpd.h> |
| |
| #define PAGE \ |
| "<html><head><title>HTTP compression</title></head><body>Hello, " \ |
| "hello, hello. This is a 'hello world' message for the world, " \ |
| "repeat, for the world.</body></html>" |
| |
| static enum MHD_Result |
| can_compress (struct MHD_Connection *con) |
| { |
| const char *ae; |
| const char *de; |
| |
| ae = MHD_lookup_connection_value (con, |
| MHD_HEADER_KIND, |
| MHD_HTTP_HEADER_ACCEPT_ENCODING); |
| if (NULL == ae) |
| return MHD_NO; |
| if (0 == strcmp (ae, |
| "*")) |
| return MHD_YES; |
| de = strstr (ae, |
| "deflate"); |
| if (NULL == de) |
| return MHD_NO; |
| if (((de == ae) || |
| (de[-1] == ',') || |
| (de[-1] == ' ')) && |
| ((de[strlen ("deflate")] == '\0') || |
| (de[strlen ("deflate")] == ',') || |
| (de[strlen ("deflate")] == ';'))) |
| return MHD_YES; |
| return MHD_NO; |
| } |
| |
| |
| static enum MHD_Result |
| body_compress (void **buf, |
| size_t *buf_size) |
| { |
| Bytef *cbuf; |
| uLongf cbuf_size; |
| int ret; |
| |
| cbuf_size = compressBound ((uLong) * buf_size); |
| cbuf = malloc (cbuf_size); |
| if (NULL == cbuf) |
| return MHD_NO; |
| ret = compress (cbuf, |
| &cbuf_size, |
| (const Bytef *) *buf, |
| (uLong) * buf_size); |
| if ((Z_OK != ret) || |
| (cbuf_size >= *buf_size)) |
| { |
| /* compression failed */ |
| free (cbuf); |
| return MHD_NO; |
| } |
| free (*buf); |
| *buf = (void *) cbuf; |
| *buf_size = (size_t) cbuf_size; |
| return MHD_YES; |
| } |
| |
| |
| static enum MHD_Result |
| ahc_echo (void *cls, |
| struct MHD_Connection *connection, |
| const char *url, |
| const char *method, |
| const char *version, |
| const char *upload_data, size_t *upload_data_size, void **req_cls) |
| { |
| struct MHD_Response *response; |
| enum MHD_Result ret; |
| enum MHD_Result comp; |
| size_t body_len; |
| char *body_str; |
| (void) cls; /* Unused. Silent compiler warning. */ |
| (void) url; /* Unused. Silent compiler warning. */ |
| (void) version; /* Unused. Silent compiler warning. */ |
| (void) upload_data; /* Unused. Silent compiler warning. */ |
| (void) upload_data_size; /* Unused. Silent compiler warning. */ |
| |
| if (0 != strcmp (method, "GET")) |
| return MHD_NO; /* unexpected method */ |
| if (! *req_cls) |
| { |
| *req_cls = (void *) 1; |
| return MHD_YES; |
| } |
| *req_cls = NULL; |
| |
| body_str = strdup (PAGE); |
| if (NULL == body_str) |
| { |
| return MHD_NO; |
| } |
| body_len = strlen (body_str); |
| /* try to compress the body */ |
| comp = MHD_NO; |
| if (MHD_YES == |
| can_compress (connection)) |
| comp = body_compress ((void **) &body_str, |
| &body_len); |
| response = |
| MHD_create_response_from_buffer_with_free_callback (body_len, |
| body_str, |
| &free); |
| |
| if (NULL == response) |
| { |
| free (body_str); |
| return MHD_NO; |
| } |
| |
| if (MHD_YES == comp) |
| { |
| /* Need to indicate to client that body is compressed */ |
| if (MHD_NO == |
| MHD_add_response_header (response, |
| MHD_HTTP_HEADER_CONTENT_ENCODING, |
| "deflate")) |
| { |
| MHD_destroy_response (response); |
| return MHD_NO; |
| } |
| } |
| ret = MHD_queue_response (connection, |
| 200, |
| response); |
| MHD_destroy_response (response); |
| return ret; |
| } |
| |
| |
| int |
| main (int argc, char *const *argv) |
| { |
| struct MHD_Daemon *d; |
| unsigned int port; |
| |
| if ( (argc != 2) || |
| (1 != sscanf (argv[1], "%u", &port)) || |
| (65535 < port) ) |
| { |
| printf ("%s PORT\n", argv[0]); |
| return 1; |
| } |
| d = MHD_start_daemon (MHD_USE_AUTO | MHD_USE_INTERNAL_POLLING_THREAD |
| | MHD_USE_ERROR_LOG, |
| (uint16_t) port, NULL, NULL, |
| &ahc_echo, NULL, |
| MHD_OPTION_END); |
| if (NULL == d) |
| return 1; |
| (void) getc (stdin); |
| MHD_stop_daemon (d); |
| return 0; |
| } |