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:
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);