From 7aa923019d5d03ab5f64a9bbd5fabfa1802129e1 Mon Sep 17 00:00:00 2001 From: "Evgeny Grin (Karlson2k)" Date: Mon, 25 Nov 2024 18:43:27 +0300 Subject: [PATCH] Implemented fallback file reader for the responses --- configure.ac | 24 +++- src/incl_priv/mhd_sys_options.h | 15 ++- src/include/microhttpd2.h | 29 ++++- src/include/microhttpd2_preamble.h.in | 29 ++++- src/mhd2/Makefile.am | 1 + src/mhd2/mhd_read_file.c | 177 ++++++++++++++++++++++++++ src/mhd2/mhd_read_file.h | 83 ++++++++++++ src/mhd2/stream_funcs.c | 15 +++ src/mhd2/stream_funcs.h | 15 +++ src/mhd2/stream_process_reply.c | 97 ++++++++++++-- 10 files changed, 465 insertions(+), 20 deletions(-) create mode 100644 src/mhd2/mhd_read_file.c create mode 100644 src/mhd2/mhd_read_file.h diff --git a/configure.ac b/configure.ac index bce531a6..17320db6 100644 --- a/configure.ac +++ b/configure.ac @@ -4526,10 +4526,16 @@ AM_CONDITIONAL([MHD_HAVE_LIBMAGIC], [[test "x$mhd_cv_have_func_magic_open" = "xy # large file support (> 4 GB) MHD_CHECK_FUNC([lseek64], [[ +#ifndef _LARGEFILE64_SOURCE +# define _LARGEFILE64_SOURCE 1 +#endif #if defined(HAVE_SYS_TYPES_H) # include #endif -#include +#include +#ifdef HAVE_UNISTD_H +# include +#endif ]], [[ i][f (((off64_t) -1) == lseek64(0, (off64_t) 0, SEEK_SET)) @@ -4538,10 +4544,16 @@ MHD_CHECK_FUNC([lseek64], ) MHD_CHECK_FUNC([pread64], [[ +#ifndef _LARGEFILE64_SOURCE +# define _LARGEFILE64_SOURCE 1 +#endif #if defined(HAVE_SYS_TYPES_H) # include #endif -#include +#include +#ifdef HAVE_UNISTD_H +# include +#endif ]], [[ char buf[5]; @@ -4554,7 +4566,10 @@ MHD_CHECK_FUNC([pread], #if defined(HAVE_SYS_TYPES_H) # include #endif -#include +#include +#ifdef HAVE_UNISTD_H +# include +#endif ]], [[ char buf[5]; @@ -4608,6 +4623,9 @@ static void empty_func(void) AC_MSG_RESULT([[yes]]) MHD_CHECK_FUNC([sendfile64], [[ +#ifndef _LARGEFILE64_SOURCE +# define _LARGEFILE64_SOURCE 1 +#endif #include ]], [[ diff --git a/src/incl_priv/mhd_sys_options.h b/src/incl_priv/mhd_sys_options.h index 846acbe5..6d99ebbc 100644 --- a/src/incl_priv/mhd_sys_options.h +++ b/src/incl_priv/mhd_sys_options.h @@ -332,6 +332,13 @@ # endif #endif /* mhd_THREADS_KIND_POSIX || mhd_THREADS_KIND_W32 */ +#if defined(_WIN32) && ! defined(__CYGWIN__) +/** + * Defined if the platform is native W32. + * Not define on Cygwin. + */ +# define mhd_W32_NATIVE 1 +#endif /** * Macro to drop 'const' qualifier from pointer. * Try to avoid compiler warning. @@ -401,10 +408,12 @@ #define RESTRICT __restrict__ #endif /* __VXWORKS__ || __vxworks || OS_VXWORKS */ -#if defined(LINUX) && (defined(HAVE_SENDFILE64) || defined(HAVE_LSEEK64)) && \ - ! defined(_LARGEFILE64_SOURCE) +#if defined(__linux__) && \ + (defined(HAVE_SENDFILE64) || defined(HAVE_LSEEK64) || defined(HAVE_PREAD64)) +# if ! defined(_LARGEFILE64_SOURCE) /* On Linux, special macro is required to enable definitions of some xxx64 functions */ -#define _LARGEFILE64_SOURCE 1 +# define _LARGEFILE64_SOURCE 1 +# endif #endif #ifdef HAVE_C11_GMTIME_S diff --git a/src/include/microhttpd2.h b/src/include/microhttpd2.h index 93a77fad..afb913cc 100644 --- a/src/include/microhttpd2.h +++ b/src/include/microhttpd2.h @@ -1152,6 +1152,11 @@ enum MHD_FIXED_ENUM_MHD_SET_ MHD_StatusCode */ MHD_SC_REPLY_POOL_ALLOCATION_FAILURE = 50231 , + /** + * Failed to read the file for file-backed response. + */ + MHD_SC_REPLY_FILE_READ_ERROR = 50232 + , /** * Failed to allocate memory in connection's pool for the reply. */ @@ -1457,6 +1462,18 @@ enum MHD_FIXED_ENUM_MHD_SET_ MHD_StatusCode */ MHD_SC_REPLY_HEADERS_TOO_LARGE = 60103 , + /** + * Specified offset in file-backed response is too large and not supported + * by the platform + */ + MHD_SC_REPLY_FILE_OFFSET_TOO_LARGE = 60104 + , + /** + * File-backed response has file smaller than specified combination of + * the file offset and the response size. + */ + MHD_SC_REPLY_FILE_TOO_SHORT = 60105 + , /** * The new connection cannot be used because the FD number is higher than * the limit set by FD_SETSIZE (if internal polling with select is used) or @@ -3734,8 +3751,7 @@ enum MHD_FIXED_ENUM_MHD_SET_ MHD_RequestEndedCode MHD_REQUEST_ENDED_CLIENT_ABORT = 30 , /** - * The request is not valid according to - * HTTP specifications. + * The request is not valid according to HTTP specifications. * @ingroup request */ MHD_REQUEST_ENDED_HTTP_PROTOCOL_ERROR = 31 @@ -3747,7 +3763,8 @@ enum MHD_FIXED_ENUM_MHD_SET_ MHD_RequestEndedCode MHD_REQUEST_ENDED_BY_APP_ABORT = 40 , /** - * The application aborted request without response. + * The request was aborted due to the application failed to provide a valid + * resonse. * @ingroup request */ MHD_REQUEST_ENDED_BY_APP_ERROR = 41 @@ -3758,6 +3775,12 @@ enum MHD_FIXED_ENUM_MHD_SET_ MHD_RequestEndedCode */ MHD_REQUEST_ENDED_NO_RESOURCES = 50 , + /** + * The request was aborted due to error reading file for file-backed response + * @ingroup request + */ + MHD_REQUEST_ENDED_FILE_ERROR = 51 + , /** * Closing the session since MHD is being shut down. * @ingroup request diff --git a/src/include/microhttpd2_preamble.h.in b/src/include/microhttpd2_preamble.h.in index e6f7b3ef..cc4c295c 100644 --- a/src/include/microhttpd2_preamble.h.in +++ b/src/include/microhttpd2_preamble.h.in @@ -1152,6 +1152,11 @@ enum MHD_FIXED_ENUM_MHD_SET_ MHD_StatusCode */ MHD_SC_REPLY_POOL_ALLOCATION_FAILURE = 50231 , + /** + * Failed to read the file for file-backed response. + */ + MHD_SC_REPLY_FILE_READ_ERROR = 50232 + , /** * Failed to allocate memory in connection's pool for the reply. */ @@ -1457,6 +1462,18 @@ enum MHD_FIXED_ENUM_MHD_SET_ MHD_StatusCode */ MHD_SC_REPLY_HEADERS_TOO_LARGE = 60103 , + /** + * Specified offset in file-backed response is too large and not supported + * by the platform + */ + MHD_SC_REPLY_FILE_OFFSET_TOO_LARGE = 60104 + , + /** + * File-backed response has file smaller than specified combination of + * the file offset and the response size. + */ + MHD_SC_REPLY_FILE_TOO_SHORT = 60105 + , /** * The new connection cannot be used because the FD number is higher than * the limit set by FD_SETSIZE (if internal polling with select is used) or @@ -3734,8 +3751,7 @@ enum MHD_FIXED_ENUM_MHD_SET_ MHD_RequestEndedCode MHD_REQUEST_ENDED_CLIENT_ABORT = 30 , /** - * The request is not valid according to - * HTTP specifications. + * The request is not valid according to HTTP specifications. * @ingroup request */ MHD_REQUEST_ENDED_HTTP_PROTOCOL_ERROR = 31 @@ -3747,7 +3763,8 @@ enum MHD_FIXED_ENUM_MHD_SET_ MHD_RequestEndedCode MHD_REQUEST_ENDED_BY_APP_ABORT = 40 , /** - * The application aborted request without response. + * The request was aborted due to the application failed to provide a valid + * resonse. * @ingroup request */ MHD_REQUEST_ENDED_BY_APP_ERROR = 41 @@ -3758,6 +3775,12 @@ enum MHD_FIXED_ENUM_MHD_SET_ MHD_RequestEndedCode */ MHD_REQUEST_ENDED_NO_RESOURCES = 50 , + /** + * The request was aborted due to error reading file for file-backed response + * @ingroup request + */ + MHD_REQUEST_ENDED_FILE_ERROR = 51 + , /** * Closing the session since MHD is being shut down. * @ingroup request diff --git a/src/mhd2/Makefile.am b/src/mhd2/Makefile.am index 14d8fde6..ec88862d 100644 --- a/src/mhd2/Makefile.am +++ b/src/mhd2/Makefile.am @@ -55,6 +55,7 @@ libmicrohttpd2_la_SOURCES = \ mhd_threads.c mhd_threads.h sys_thread_entry_type.h \ mhd_mono_clock.c mhd_mono_clock.h \ mhd_mempool.c mhd_mempool.h \ + mhd_read_file.c mhd_read_file.h \ mhd_recv.c mhd_recv.h \ mhd_send.c mhd_send.h \ mhd_daemon.h \ diff --git a/src/mhd2/mhd_read_file.c b/src/mhd2/mhd_read_file.c new file mode 100644 index 00000000..32fe2234 --- /dev/null +++ b/src/mhd2/mhd_read_file.c @@ -0,0 +1,177 @@ +/* + This file is part of GNU libmicrohttpd + Copyright (C) 2024 Evgeny Grin (Karlson2k) + + GNU libmicrohttpd 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. + + GNU libmicrohttpd 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 src/mhd2/mhd_read_file.c + * @brief The implementation of mhd_read_file() function + * @author Karlson2k (Evgeny Grin) + */ + +#include "mhd_sys_options.h" + +#include "mhd_read_file.h" + +#include +#ifdef HAVE_UNISTD_H +# include +#endif + +#if ! defined(mhd_W32_NATIVE) +# include "mhd_limits.h" +#else +/* Native W32 */ +# include +# include /* for memset() */ +#endif +/** + * Read data from the file to the provided buffer + * + * @param file_fd the FD of file to read + * @param buf_size the size of the @a buf buffer + * @param[out] buf the buffer to fill with the read data + * @param[out] size_filled the pointer to variable to get the size of the data + * actually put to the @a buffer + * @return #mhd_FILE_READ_OK if succeed (the @a size_filled gets the actual + * read size), + * error otherwise + */ +MHD_INTERNAL MHD_FN_MUST_CHECK_RESULT_ MHD_FN_PAR_NONNULL_ALL_ +MHD_FN_PAR_OUT_SIZE_ (4, 3) MHD_FN_PAR_OUT_ (5) enum mhd_FileReadResult +mhd_read_file (int file_fd, + uint_fast64_t offset, + size_t buf_size, + char buf[MHD_FN_PAR_DYN_ARR_SIZE_ (buf_size)], + size_t *restrict size_filled) +{ +#if (defined(HAVE_PREAD64) || defined(HAVE_PREAD)) && ! defined(mhd_W32_NATIVE) +# ifdef HAVE_PREAD64 + const off64_t pos_off = (off64_t) offset; +# else /* HAVE_PREAD */ + const off_t pos_off = (off_t) offset; +# endif /* HAVE_PREAD */ + ssize_t res; + + *size_filled = 0; + + if ((0 > pos_off) || + (offset != (uint_fast64_t) pos_off)) + return mhd_FILE_READ_OFFSET_TOO_LARGE; + + if (0 > (ssize_t) buf_size) + buf_size = SSIZE_MAX; /* Larger sizes may result in undefined behaviour */ + +# ifdef HAVE_PREAD64 + res = pread64 (file_fd, + buf, + buf_size, + pos_off); +# else /* HAVE_PREAD */ + res = pread (file_fd, + buf, + buf_size, + pos_off); +# endif /* HAVE_PREAD */ + + if (0 > res) + return mhd_FILE_READ_ERROR; + + if (0 == res) + return mhd_FILE_READ_EOF; + + *size_filled = (size_t) res; + return mhd_FILE_READ_OK; +#elif ! defined(mhd_W32_NATIVE) + /* Multithread-unsafe emulation */ +# ifdef HAVE_LSEEK64 + const off64_t pos_off = (off64_t) offset; +# else + const off_t pos_off = (off_t) offset; +# endif + ssize_t res; + + *size_filled = 0; + + if ((0 > pos_off) || + (offset != (uint_fast64_t) pos_off)) + return mhd_FILE_READ_OFFSET_TOO_LARGE; + + if (0 > (ssize_t) buf_size) + buf_size = SSIZE_MAX; /* Larger sizes may result in undefined behaviour */ + +# ifdef HAVE_LSEEK64 + if (pos_off != lseek64 (file_fd, + pos_off, + SEEK_SET)) + return mhd_FILE_READ_ERROR; +# else + if (pos_off != lseek (file_fd, + pos_off, + SEEK_SET)) + return mhd_FILE_READ_ERROR; +# endif + + res = read (file_fd, + buf, + buf_size); + + if (0 > res) + return mhd_FILE_READ_ERROR; + + if (0 == res) + return mhd_FILE_READ_EOF; + + *size_filled = (size_t) res; + return mhd_FILE_READ_OK; + +#else /* Native W32 */ + const intptr_t sys_fd = _get_osfhandle (file_fd); + const HANDLE w_hndl = (HANDLE) sys_fd; + OVERLAPPED ovrlp; + DWORD reqReadSize; + DWORD resReadSize; + + *size_filled = 0; + if (INVALID_HANDLE_VALUE == w_hndl) + return mhd_FILE_READ_ERROR; + + memset (&ovrlp, 0, sizeof(ovrlp)); + reqReadSize = (DWORD) buf_size; + if (reqReadSize != buf_size) + reqReadSize = (DWORD) (~((DWORD) 0)); + ovrlp.Offset = (DWORD) offset; + offset >>= 32; + ovrlp.OffsetHigh = (DWORD) offset; + if (0 != (offset >> 32)) + return mhd_FILE_READ_OFFSET_TOO_LARGE; + + if (! ReadFile (w_hndl, + buf, + reqReadSize, + &resReadSize, + &ovrlp)) + return mhd_FILE_READ_ERROR; + + if (0 == resReadSize) + return mhd_FILE_READ_EOF; + + *size_filled = resReadSize; + return mhd_FILE_READ_OK; +#endif /* Native W32 */ +} diff --git a/src/mhd2/mhd_read_file.h b/src/mhd2/mhd_read_file.h new file mode 100644 index 00000000..4f51da5e --- /dev/null +++ b/src/mhd2/mhd_read_file.h @@ -0,0 +1,83 @@ +/* + This file is part of GNU libmicrohttpd + Copyright (C) 2024 Evgeny Grin (Karlson2k) + + GNU libmicrohttpd 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. + + GNU libmicrohttpd 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 src/mhd2/mhd_read_file.h + * @brief The declaration of mhd_read_file() function + * @author Karlson2k (Evgeny Grin) + */ + +#ifndef MHD_READ_FILE_H +#define MHD_READ_FILE_H 1 + +#include "mhd_sys_options.h" + +#include "sys_base_types.h" + +/** + * Results of file reading + */ +enum mhd_FileReadResult +{ + /** + * File read succeed + */ + mhd_FILE_READ_OK = 0 + , + /** + * File read failed + */ + mhd_FILE_READ_ERROR + , + /** + * The requested offset is too large + */ + mhd_FILE_READ_OFFSET_TOO_LARGE + , + /** + * Got "end of file" + */ + mhd_FILE_READ_EOF +}; + + +/** + * Read data from the file to the provided buffer + * + * @param file_fd the FD of file to read + * @param buf_size the size of the @a buf buffer + * @param[out] buf the buffer to fill with the read data + * @param[out] size_filled the pointer to variable to get the size of the data + * actually put to the @a buffer + * @return #mhd_FILE_READ_OK if succeed (the @a size_filled gets the actual + * read size), + * error otherwise + */ +MHD_INTERNAL enum mhd_FileReadResult +mhd_read_file (int file_fd, + uint_fast64_t offset, + size_t buf_size, + char buf[MHD_FN_PAR_DYN_ARR_SIZE_ (buf_size)], + size_t *restrict size_filled) +MHD_FN_MUST_CHECK_RESULT_ MHD_FN_PAR_NONNULL_ALL_ +MHD_FN_PAR_OUT_SIZE_(4, 3) MHD_FN_PAR_OUT_ (5); + + +#endif /* ! MHD_READ_FILE_H */ diff --git a/src/mhd2/stream_funcs.c b/src/mhd2/stream_funcs.c index 88081235..1e64678b 100644 --- a/src/mhd2/stream_funcs.c +++ b/src/mhd2/stream_funcs.c @@ -720,6 +720,21 @@ mhd_conn_start_closing (struct MHD_Connection *restrict c, end_code = MHD_REQUEST_ENDED_BY_APP_ABORT; sc = MHD_SC_APPLICATION_CALLBACK_ABORT_ACTION; break; + case mhd_CONN_CLOSE_FILE_OFFSET_TOO_LARGE: + close_hard = true; + end_code = MHD_REQUEST_ENDED_FILE_ERROR; + sc = MHD_SC_REPLY_FILE_OFFSET_TOO_LARGE; + break; + case mhd_CONN_CLOSE_FILE_READ_ERROR: + close_hard = true; + end_code = MHD_REQUEST_ENDED_FILE_ERROR; + sc = MHD_SC_REPLY_FILE_READ_ERROR; + break; + case mhd_CONN_CLOSE_FILE_TOO_SHORT: + close_hard = true; + end_code = MHD_REQUEST_ENDED_BY_APP_ERROR; + sc = MHD_SC_REPLY_FILE_TOO_SHORT; + break; case mhd_CONN_CLOSE_INT_ERROR: close_hard = true; end_code = MHD_REQUEST_ENDED_NO_RESOURCES; diff --git a/src/mhd2/stream_funcs.h b/src/mhd2/stream_funcs.h index 14a0a1e5..f04c9b6b 100644 --- a/src/mhd2/stream_funcs.h +++ b/src/mhd2/stream_funcs.h @@ -198,6 +198,21 @@ enum mhd_ConnCloseReason */ mhd_CONN_CLOSE_APP_ABORTED , + /** + * File-backed response too large (unsupported by OS) file offset + */ + mhd_CONN_CLOSE_FILE_OFFSET_TOO_LARGE + , + /** + * Error reading file-backed response + */ + mhd_CONN_CLOSE_FILE_READ_ERROR + , + /** + * File-backed response has file smaller than specified by application + */ + mhd_CONN_CLOSE_FILE_TOO_SHORT + , /* Hard problem while receiving or sending */ /** diff --git a/src/mhd2/stream_process_reply.c b/src/mhd2/stream_process_reply.c index 12cc3a60..c861cd25 100644 --- a/src/mhd2/stream_process_reply.c +++ b/src/mhd2/stream_process_reply.c @@ -53,6 +53,8 @@ #include "stream_funcs.h" #include "request_get_value.h" +#include "mhd_read_file.h" + #include "mhd_public_api.h" MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ void @@ -964,6 +966,67 @@ preprocess_dcc_action (struct MHD_Connection *restrict c, } +/** + * Read next portion of the response file to the buffer, based on information + * about amount of response content position. + * Handle file read errors, update response position. + * @param c the stream to use + * @param r the response to use + * @param buf_size the size of the @a buf buffer + * @param[out] buf the buffer to fill with the file data + * @param[out] size_filled the pointer to variable to get the size of the data + * actually put to the @a buffer + * @return 'true' if succeed (size_filled and response position are updated), + * 'false' if failed (the stream is closed) + */ +static MHD_FN_MUST_CHECK_RESULT_ MHD_FN_PAR_NONNULL_ALL_ +MHD_FN_PAR_OUT_SIZE_ (4, 3) MHD_FN_PAR_OUT_ (5) bool +read_response_file (struct MHD_Connection *restrict c, + struct MHD_Response *const restrict r, + size_t buf_size, + char buf[MHD_FN_PAR_DYN_ARR_SIZE_ (buf_size)], + size_t *restrict size_filled) +{ + mhd_assert (r == c->rp.response); + mhd_assert (mhd_RESPONSE_CONTENT_DATA_FILE == r->cntn_dtype); + + switch (mhd_read_file (r->cntn.file.fd, + r->cntn.file.offset + c->rp.rsp_cntn_read_pos, + buf_size, + buf, + size_filled)) + { + case mhd_FILE_READ_OK: + break; + case mhd_FILE_READ_ERROR: + mhd_STREAM_ABORT (c, \ + mhd_CONN_CLOSE_FILE_READ_ERROR, \ + "Error reading file for file-backed response."); + return false; + case mhd_FILE_READ_OFFSET_TOO_LARGE: + mhd_STREAM_ABORT (c, \ + mhd_CONN_CLOSE_FILE_OFFSET_TOO_LARGE, \ + "The offset for file-backed response is too large " \ + "for this platform."); + return false; + case mhd_FILE_READ_EOF: + mhd_STREAM_ABORT (c, \ + mhd_CONN_CLOSE_FILE_TOO_SHORT, \ + "The file for file-backed response is smaller " \ + "than specified by application."); + return false; + default: + mhd_assert (0 && "Impossible value"); + MHD_UNREACHABLE_; + c->rp.cntn_loc = mhd_REPLY_CNTN_LOC_NOWHERE; + return false; + } + + c->rp.rsp_cntn_read_pos += *size_filled; + return true; +} + + MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ bool mhd_stream_prep_unchunked_body (struct MHD_Connection *restrict c) { @@ -1049,10 +1112,21 @@ mhd_stream_prep_unchunked_body (struct MHD_Connection *restrict c) } else if (mhd_RESPONSE_CONTENT_DATA_FILE == r->cntn_dtype) { - // TODO: implement fallback - mhd_assert (0 && "Not implemented yet"); - c->rp.cntn_loc = mhd_REPLY_CNTN_LOC_NOWHERE; - c->rp.rsp_cntn_read_pos = r->cntn_size; + size_t size_to_fill = + c->write_buffer_size - c->write_buffer_append_offset; + size_t filled; + + if (size_to_fill > left_to_send) + size_to_fill = (size_t) left_to_send; + + if (! read_response_file (c, + r, + size_to_fill, + c->write_buffer + c->write_buffer_append_offset, + &filled)) + return true; /* Error, the stream is closed */ + + c->write_buffer_append_offset += filled; } else { @@ -1061,10 +1135,6 @@ mhd_stream_prep_unchunked_body (struct MHD_Connection *restrict c) c->rp.cntn_loc = mhd_REPLY_CNTN_LOC_NOWHERE; c->rp.rsp_cntn_read_pos = r->cntn_size; } - - mhd_assert (0 && "Not implemented yet"); - c->rp.cntn_loc = mhd_REPLY_CNTN_LOC_NOWHERE; - c->rp.rsp_cntn_read_pos = r->cntn_size; } else if (mhd_REPLY_CNTN_LOC_IOV == c->rp.cntn_loc) { @@ -1215,6 +1285,17 @@ mhd_stream_prep_chunked_body (struct MHD_Connection *restrict c) c->rp.rsp_cntn_read_pos += filled; c->write_buffer_append_offset += filled; } + else if (mhd_RESPONSE_CONTENT_DATA_FILE == r->cntn_dtype) + { + if (! read_response_file (c, + r, + size_to_fill, + c->write_buffer + max_chunk_hdr_len, + &filled)) + return true; /* Error, the stream is closed */ + + c->write_buffer_append_offset += filled; + } else { mhd_assert (0 && "Not implemented yet");