libmicrohttpd

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

commit e2c268e3796557560fb2ffe3c2e9c18f74fc9471
parent 154d0fd6a11b813c006e775fc01ab665c5e75317
Author: silvioprog <silvioprog@gmail.com>
Date:   Sun, 10 Feb 2019 21:13:57 -0300

Added example for how to compress chunked HTTP response.

Diffstat:
MChangeLog | 3+++
Msrc/examples/Makefile.am | 8+++++++-
Asrc/examples/http_chunked_compression.c | 199+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 209 insertions(+), 1 deletion(-)

diff --git a/ChangeLog b/ChangeLog @@ -1,3 +1,6 @@ +Sun Feb 10 21:00:37 BRT 2019 + Added example for how to compress a chunked HTTP response. -SC + Sun 10 Feb 2019 05:03:44 PM CET Releasing libmicrohttpd 0.9.63. -CG diff --git a/src/examples/Makefile.am b/src/examples/Makefile.am @@ -70,7 +70,8 @@ endif if HAVE_ZLIB noinst_PROGRAMS += \ - http_compression + http_compression \ + http_chunked_compression endif if HAVE_W32 @@ -206,8 +207,13 @@ https_fileserver_example_LDADD = \ http_compression_SOURCES = \ http_compression.c +http_chunked_compression_SOURCES = \ + http_chunked_compression.c http_compression_LDADD = \ $(top_builddir)/src/microhttpd/libmicrohttpd.la +http_chunked_compression_LDADD = \ + $(top_builddir)/src/microhttpd/libmicrohttpd.la if HAVE_ZLIB http_compression_LDADD += -lz + http_chunked_compression_LDADD += -lz endif \ No newline at end of file diff --git a/src/examples/http_chunked_compression.c b/src/examples/http_chunked_compression.c @@ -0,0 +1,199 @@ +/* + 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_chunked_compression.c + * @brief example for how to compress a chunked HTTP response + * @author Silvio Clecio (silvioprog) + */ + +#include "platform.h" +#include <zlib.h> +#include <microhttpd.h> + +#define CHUNK 16384 + +struct Holder { + FILE *file; + z_stream stream; + void *buf; +}; + +static int +compress_buf (z_stream *strm, const void *src, size_t src_size, size_t *offset, void **dest, size_t *dest_size, + void *tmp) +{ + unsigned int have; + int ret; + int flush; + *dest = NULL; + *dest_size = 0; + do + { + if (src_size > CHUNK) + { + strm->avail_in = CHUNK; + src_size -= CHUNK; + flush = Z_NO_FLUSH; + } + else + { + strm->avail_in = (uInt) src_size; + flush = Z_SYNC_FLUSH; + } + *offset += strm->avail_in; + strm->next_in = (Bytef *) src; + do + { + strm->avail_out = CHUNK; + strm->next_out = tmp; + ret = deflate (strm, flush); + have = CHUNK - strm->avail_out; + *dest_size += have; + *dest = realloc (*dest, *dest_size); + if (NULL == *dest) + return MHD_NO; + memcpy ((*dest) + ((*dest_size) - have), tmp, have); + } + while (0 == strm->avail_out); + } + while (flush != Z_SYNC_FLUSH); + return (Z_OK == ret) ? MHD_YES : MHD_NO; +} + +static ssize_t +read_cb (void *cls, uint64_t pos, char *mem, size_t size) +{ + struct Holder *holder = cls; + void *src; + void *buf; + src = malloc (size); + if (NULL == src) + return MHD_CONTENT_READER_END_WITH_ERROR; + size = fread (src, 1, size, holder->file); + if (size < 0) + { + size = MHD_CONTENT_READER_END_WITH_ERROR; + goto done; + } + if (0 == size) + { + size = MHD_CONTENT_READER_END_OF_STREAM; + goto done; + } + if (MHD_YES != compress_buf (&holder->stream, src, size, &pos, &buf, &size, holder->buf)) + size = MHD_CONTENT_READER_END_WITH_ERROR; + else + { + memcpy (mem, buf, size); + free (buf); + } +done: + free (src); + return size; +} + +static void +free_cb (void *cls) +{ + struct Holder *holder = cls; + fclose (holder->file); + deflateEnd (&holder->stream); + free (holder->buf); + free (holder); +} + +static int +ahc_echo (void *cls, struct MHD_Connection *con, const char *url, const char *method, const char *version, + const char *upload_data, size_t *upload_size, void **ptr) +{ + struct Holder *holder; + struct MHD_Response *res; + int ret; + (void) cls; + (void) url; + (void) method; + (void) version; + (void) upload_data; + (void) upload_size; + if (NULL == *ptr) + { + *ptr = (void *) 1; + return MHD_YES; + } + *ptr = NULL; + holder = calloc (1, sizeof (struct Holder)); + if (!holder) + return MHD_NO; + holder->file = fopen (__FILE__, "rb"); + if (NULL == holder->file) + goto file_error; + ret = deflateInit(&holder->stream, Z_BEST_COMPRESSION); + if (ret != Z_OK) + goto stream_error; + holder->buf = malloc (CHUNK); + if (NULL == holder->buf) + goto buf_error; + res = MHD_create_response_from_callback (MHD_SIZE_UNKNOWN, 1024, &read_cb, holder, &free_cb); + if (NULL == res) + goto error; + ret = MHD_add_response_header (res, MHD_HTTP_HEADER_CONTENT_ENCODING, "deflate"); + if (MHD_YES != ret) + goto res_error; + ret = MHD_add_response_header (res, MHD_HTTP_HEADER_CONTENT_TYPE, "text/x-c"); + if (MHD_YES != ret) + goto res_error; + ret = MHD_queue_response (con, MHD_HTTP_OK, res); +res_error: + MHD_destroy_response (res); + return ret; +error: + free (holder->buf); +buf_error: + deflateEnd (&holder->stream); +stream_error: + fclose (holder->file); +file_error: + free (holder); + return MHD_NO; +} + +int +main (int argc, char *const *argv) +{ + struct MHD_Daemon *d; + unsigned int port; + if ((argc != 2) || + (1 != sscanf (argv[1], "%u", &port)) || + (UINT16_MAX < port)) + { + fprintf (stderr, "%s PORT\n", argv[0]); + return 1; + } + d = MHD_start_daemon (MHD_USE_AUTO | MHD_USE_INTERNAL_POLLING_THREAD, (uint16_t) port, NULL, NULL, + &ahc_echo, NULL, + MHD_OPTION_END); + if (NULL == d) + return 1; + if (0 == port) + MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT, &port); + fprintf (stdout, "HTTP server running at http://localhost:%u\n\nPress ENTER to stop the server ...\n", port); + (void) getc (stdin); + MHD_stop_daemon (d); + return 0; +}