From dad0746a1006e7c2bd856fd4767b34c7cd6e0f74 Mon Sep 17 00:00:00 2001 From: silvioprog Date: Tue, 8 Jan 2019 03:00:17 -0300 Subject: Added minimal example for how to compress HTTP response. (#4914) --- ChangeLog | 3 + configure.ac | 3 + src/examples/Makefile.am | 13 +++ src/examples/http_compression.c | 177 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 196 insertions(+) create mode 100644 src/examples/http_compression.c diff --git a/ChangeLog b/ChangeLog index 1227571f..aaf17bb2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,6 @@ +Tue Jan 8 02:57:21 BRT 2019 + Added minimal example for how to compress HTTP response. -SC + Wed Dec 19 00:06:03 CET 2018 Check for GNUTLS_E_AGAIN instead of GNUTLS_E_INTERRUPTED when giving up on a TLS connection. -LM/CG diff --git a/configure.ac b/configure.ac index 44c7d294..cfe7af90 100644 --- a/configure.ac +++ b/configure.ac @@ -766,6 +766,9 @@ AM_CONDITIONAL([MHD_HAVE_TSEARCH], [[test "x$ac_cv_header_search_h" = xyes && te AC_CHECK_HEADERS([dlfcn.h],[have_tlsplugin=yes],[have_tlsplugin=no], [AC_INCLUDES_DEFAULT]) AM_CONDITIONAL([MHD_HAVE_TLS_PLUGIN], [[test "x$have_tlsplugin" = xyes]]) +AC_CHECK_HEADERS([zlib.h],[have_zlib=yes],[have_zlib=no], [AC_INCLUDES_DEFAULT]) +AM_CONDITIONAL([HAVE_ZLIB], [[test "x$have_zlib" = xyes]]) + # Check for generic functions AC_CHECK_FUNCS([rand random]) diff --git a/src/examples/Makefile.am b/src/examples/Makefile.am index 545a236a..ce01107a 100644 --- a/src/examples/Makefile.am +++ b/src/examples/Makefile.am @@ -68,6 +68,11 @@ noinst_PROGRAMS += \ endif endif +if HAVE_ZLIB +noinst_PROGRAMS += \ + http_compression +endif + if HAVE_W32 AM_CFLAGS += -DWINDOWS endif @@ -198,3 +203,11 @@ https_fileserver_example_CPPFLAGS = \ $(AM_CPPFLAGS) $(GNUTLS_CPPFLAGS) https_fileserver_example_LDADD = \ $(top_builddir)/src/microhttpd/libmicrohttpd.la + +http_compression_SOURCES = \ + http_compression.c +http_compression_LDADD = \ + $(top_builddir)/src/microhttpd/libmicrohttpd.la +if HAVE_ZLIB + http_compression_LDADD += -lz +endif \ No newline at end of file diff --git a/src/examples/http_compression.c b/src/examples/http_compression.c new file mode 100644 index 00000000..a88be54e --- /dev/null +++ b/src/examples/http_compression.c @@ -0,0 +1,177 @@ +/* + This file is part of libmicrohttpd + Copyright (C) 2019 Christian Grothoff (and other contributing authors) + + 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) + */ + +#include "platform.h" +#include +#include + +#define PAGE \ + "HTTP compressionHello, " \ + "hello, hello. This is a 'hello world' message for the world, " \ + "repeat, for the world." + +static int +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 int +body_compress (void **buf, + size_t *buf_size) +{ + Bytef *cbuf; + uLongf cbuf_size; + int ret; + + cbuf_size = compressBound (*buf_size); + cbuf = malloc (cbuf_size); + if (NULL == cbuf) + return MHD_NO; + ret = compress (cbuf, + &cbuf_size, + (const Bytef *) *buf, + *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 int +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 **ptr) +{ + struct MHD_Response *response; + int ret; + int comp; + size_t body_len; + char *body_str; + (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 (!*ptr) + { + *ptr = (void *) 1; + return MHD_YES; + } + *ptr = 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 (body_len, + body_str, + MHD_RESPMEM_MUST_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; + + if (argc != 2) + { + printf ("%s PORT\n", argv[0]); + return 1; + } + d = MHD_start_daemon (MHD_USE_AUTO | MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG, + atoi (argv[1]), NULL, NULL, + &ahc_echo, NULL, + MHD_OPTION_END); + if (NULL == d) + return 1; + (void) getc (stdin); + MHD_stop_daemon (d); + return 0; +} -- cgit v1.2.3