Hello everyone, I've tried to compress a chunked data using ZLib & MHD, but the connection is closed while the data are transferred. Using the curl tool as client, it reports "curl: (23) Failed writing data" when we try to get a large file (about 100 kB). The attached MHD example uses the files "README" and " ChangeLog", available in the MHD sources, but it fails to send the " ChangeLog" file, because it is about 100 kB.
It is easy to reproduce the problem. Just download the attached file, and: $ gcc -o httpsrv main.c -lmicrohttpd -lz $ ./httpsrv Now, open another tab on your terminal, and: $ curl -v --compressed http://localhost:8080 You will get something like: [snip] ... Tue Jul 23 11:32:00 MSK 2017 Updated chunked_example.c to provide real illustration of usage of chunked encoding. -EG Thu Jul 13 21:41:00 MSK 2017 Restored SIGPIPE suppression in TLS mode. * Failed writing data * stopped the pause stream! * Closing connection 0 curl: (23) Failed writing data Added new value MHD_FEATURE_AUTOSUPPRESS Lastly, comment the line 56 (file = fopen(MHD_DIR "ChangeLog", "rb");) and uncomment the 57 (/*file = fopen(MHD_DIR "README", "rb");*/), rebuild the test and use curl again, you will get the the entire content of the README file. I've used the latest MHD from trunk (default build, by "./configure && make install-strip"), and the ZLib version is 1.2.11. I'm on Xubuntu 18.04 64-bit. Could you confirm if it is some bug in MHD? Thanks in advance! P.S.: remember to change the line 7 (#define MHD_DIR "~/libmicrohttpd/") to avoid application crash, all the errors handling was omitted to make the example clear and small. -- Silvio Clécio
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <zlib.h> #include <microhttpd.h> #define MHD_DIR "~/libmicrohttpd/" /* change it to your MHD directory */ static int compress_buf(void **buf, size_t *size) { Bytef *cbuf; uLongf csize; int ret; csize = compressBound(*size); cbuf = malloc(csize); if (!cbuf) return MHD_NO; ret = compress2(cbuf, &csize, *buf, *size, Z_BEST_COMPRESSION); if ((ret != Z_OK) || (csize >= *size)) { free(cbuf); return MHD_NO; } free(*buf); *buf = cbuf; *size = csize; return MHD_YES; } ssize_t read_cb(void *cls, uint64_t pos, char *buf, size_t size) { size_t zsize; void *zbuf = malloc(size); zsize = fread(zbuf, 1, size, cls); if (zsize == 0) { free(zbuf); return MHD_CONTENT_READER_END_OF_STREAM; } compress_buf(&zbuf, &zsize); memcpy(buf, zbuf, zsize); free(zbuf); return zsize; } void free_cb(void *cls) { fclose(cls); } int ahc_echo(void *cls, struct MHD_Connection *con, const char *url, const char *method, const char *version, const char *data, size_t *size, void **ptr) { struct MHD_Response *res; FILE *file; int ret; if (!*ptr) { *ptr = (void *) 1; return MHD_YES; } *ptr = NULL; file = fopen(MHD_DIR "ChangeLog", "rb"); /*file = fopen(MHD_DIR "README", "rb");*/ res = MHD_create_response_from_callback(MHD_SIZE_UNKNOWN, 1024, &read_cb, file, &free_cb); MHD_add_response_header(res, MHD_HTTP_HEADER_CONTENT_ENCODING, "deflate"); MHD_add_response_header(res, MHD_HTTP_HEADER_CONTENT_TYPE, "text/plain"); ret = MHD_queue_response(con, MHD_HTTP_OK, res); MHD_destroy_response(res); return ret; } int main() { struct MHD_Daemon *d; d = MHD_start_daemon(MHD_USE_AUTO | MHD_USE_INTERNAL_POLLING_THREAD, 8080, NULL, NULL, &ahc_echo, NULL, MHD_OPTION_END); getchar(); MHD_stop_daemon(d); return 0; }