libmicrohttpd2

HTTP server C library (MHD 2.x, alpha)
Log | Files | Refs | README | LICENSE

commit 6c8ff9a082e87c9cf440d581daee2962ef06a7b1
parent e891b0218fefa1ec89b06a1948bc32639fb4a955
Author: Evgeny Grin (Karlson2k) <k2k@drgrin.dev>
Date:   Fri, 30 Oct 2026 18:25:07 +0100

MHD_upgraded_send(): returned early on zero size, allowed NULL buffers

Diffstat:
Mdoc/manual/responses.inc | 13++++++++++---
Msrc/include/microhttpd2.h | 18+++++++++++++-----
Msrc/include/microhttpd2_main.h.in | 18+++++++++++++-----
Msrc/mhd2/upgraded_net.c | 7++++++-
4 files changed, 42 insertions(+), 14 deletions(-)

diff --git a/doc/manual/responses.inc b/doc/manual/responses.inc @@ -1136,16 +1136,22 @@ The function will return if one of the following happens: @item a network error occurs @end itemize +If @var{send_buf_size} is zero, no data is sent or pushed to the network. +For a valid @var{urh}, the function returns @code{MHD_SC_OK} immediately +and stores zero in the variable pointed to by @var{sent_size}. + @table @var @item urh identifies the upgraded connection to transmit data on @item send_buf_size -the number of bytes of data in the @var{send_buf} +the number of bytes of data in the @var{send_buf}, must be zero if +@var{send_buf} is @code{NULL} @item send_buf -the buffer with the data to send +the buffer with the data to send, can be @code{NULL} if +@var{send_buf_size} is zero @item sent_size the pointer where MHD will return the number of bytes of data actually sent @@ -1169,7 +1175,8 @@ TCP PUSH). Returns: @table @code @item MHD_SC_OK -if any data was sent (check the @var{sent_size}); +if any data was sent or @var{send_buf_size} is zero +(check the @var{sent_size}); @item MHD_SC_UPGRADED_NET_TIMEOUT if no data was sent and the timeout was reached; diff --git a/src/include/microhttpd2.h b/src/include/microhttpd2.h @@ -7504,9 +7504,15 @@ MHD_FN_PAR_OUT_ (4); * the network more effeciently delaying the last network packet, if it is * incomplete, to combine it with the next data provided. * + * If @a send_buf_size is zero, no data are sent or pushed to the network. + * For a valid @a urh, the function returns #MHD_SC_OK immediately and stores + * zero in the variable pointed to by @a sent_size. + * * @param urh the HTTP-Upgraded handle - * @param send_buf_size the amount of data in the @a send_buf - * @param send_buf the buffer with the data to send + * @param send_buf_size the amount of data in the @a send_buf, + * must be zero if @a send_buf is NULL + * @param send_buf the buffer with the data to send, + * can be NULL if @a send_buf_size is zero * @param sent_size the pointer to get the amout of sent data * @param max_wait_millisec the maximum wait time for the data, * non-blocking operation if set to zero, @@ -7522,7 +7528,8 @@ MHD_FN_PAR_OUT_ (4); * the message (or file) and it should be pushed * to the network (and to the client) as soon * as possible - * @return #MHD_SC_OK if ANY data sent (check the @a sent_size), + * @return #MHD_SC_OK if any data were sent or @a send_buf_size is zero + * (check @a sent_size), * #MHD_SC_UPGRADED_NET_TIMEOUT if NO data sent but timeout expired, * #MHD_SC_UPGRADED_NET_CONN_CLOSED if network connection has been * closed, @@ -7542,8 +7549,9 @@ MHD_upgraded_send (struct MHD_UpgradedHandle *MHD_RESTRICT urh, size_t *MHD_RESTRICT sent_size, uint_fast64_t max_wait_millisec, enum MHD_Bool more_data_to_come) -MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_IN_SIZE_ (3, 2) -MHD_FN_PAR_OUT_ (4); +MHD_FN_PAR_NONNULL_ (1) +MHD_FN_PAR_NONNULL_IF_NONZERO_ (3, 2) MHD_FN_PAR_IN_SIZE_ (3, 2) +MHD_FN_PAR_NONNULL_ (4) MHD_FN_PAR_OUT_ (4); /** diff --git a/src/include/microhttpd2_main.h.in b/src/include/microhttpd2_main.h.in @@ -2442,9 +2442,15 @@ MHD_FN_PAR_OUT_ (4); * the network more effeciently delaying the last network packet, if it is * incomplete, to combine it with the next data provided. * + * If @a send_buf_size is zero, no data are sent or pushed to the network. + * For a valid @a urh, the function returns #MHD_SC_OK immediately and stores + * zero in the variable pointed to by @a sent_size. + * * @param urh the HTTP-Upgraded handle - * @param send_buf_size the amount of data in the @a send_buf - * @param send_buf the buffer with the data to send + * @param send_buf_size the amount of data in the @a send_buf, + * must be zero if @a send_buf is NULL + * @param send_buf the buffer with the data to send, + * can be NULL if @a send_buf_size is zero * @param sent_size the pointer to get the amout of sent data * @param max_wait_millisec the maximum wait time for the data, * non-blocking operation if set to zero, @@ -2460,7 +2466,8 @@ MHD_FN_PAR_OUT_ (4); * the message (or file) and it should be pushed * to the network (and to the client) as soon * as possible - * @return #MHD_SC_OK if ANY data sent (check the @a sent_size), + * @return #MHD_SC_OK if any data were sent or @a send_buf_size is zero + * (check @a sent_size), * #MHD_SC_UPGRADED_NET_TIMEOUT if NO data sent but timeout expired, * #MHD_SC_UPGRADED_NET_CONN_CLOSED if network connection has been * closed, @@ -2480,8 +2487,9 @@ MHD_upgraded_send (struct MHD_UpgradedHandle *MHD_RESTRICT urh, size_t *MHD_RESTRICT sent_size, uint_fast64_t max_wait_millisec, enum MHD_Bool more_data_to_come) -MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_IN_SIZE_ (3, 2) -MHD_FN_PAR_OUT_ (4); +MHD_FN_PAR_NONNULL_ (1) +MHD_FN_PAR_NONNULL_IF_NONZERO_ (3, 2) MHD_FN_PAR_IN_SIZE_ (3, 2) +MHD_FN_PAR_NONNULL_ (4) MHD_FN_PAR_OUT_ (4); /** diff --git a/src/mhd2/upgraded_net.c b/src/mhd2/upgraded_net.c @@ -350,8 +350,10 @@ MHD_upgraded_recv (struct MHD_UpgradedHandle *MHD_RESTRICT urh, MHD_EXTERN_ -MHD_FN_PAR_NONNULL_ALL_ +MHD_FN_PAR_NONNULL_ (1) +MHD_FN_PAR_NONNULL_IF_NONZERO_ (3, 2) MHD_FN_PAR_IN_SIZE_ (3, 2) +MHD_FN_PAR_NONNULL_ (4) MHD_FN_PAR_OUT_ (4) enum MHD_StatusCode MHD_upgraded_send (struct MHD_UpgradedHandle *MHD_RESTRICT urh, size_t send_buf_size, @@ -377,6 +379,9 @@ MHD_upgraded_send (struct MHD_UpgradedHandle *MHD_RESTRICT urh, if (mhd_HTTP_STAGE_UPGRADED != c->stage) return MHD_SC_UPGRADED_HANDLE_INVALID; + if (0 == send_buf_size) + return MHD_SC_OK; + finish_time_set = false; wait_indefinitely = (MHD_WAIT_INDEFINITELY <= max_wait_millisec);