libmicrohttpd2

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

commit 47b46bec6d9e91f10e1032f99cee77a8994ee448
parent fb58efc21be3c64e6882d8c7c9182fe3ad68ef65
Author: Evgeny Grin (Karlson2k) <k2k@drgrin.dev>
Date:   Sun, 30 Aug 2026 17:36:27 +0200

Fixed processing early disconnects and shutdowns

Diffstat:
Msrc/mhd2/stream_process_states.c | 83+++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------------
1 file changed, 56 insertions(+), 27 deletions(-)

diff --git a/src/mhd2/stream_process_states.c b/src/mhd2/stream_process_states.c @@ -66,6 +66,9 @@ #ifdef MHD_SUPPORT_HTTP2 # include "h2/h2_comm.h" #endif +#ifdef MHD_SUPPORT_HTTPS +# include "mhd_tls_funcs.h" +#endif /* MHD_SUPPORT_HTTPS */ #include "stream_process_states.h" #include "stream_funcs.h" @@ -276,6 +279,20 @@ finish_resume (struct MHD_Connection *restrict c) } +/* always return 'false' */ +static MHD_FN_PAR_NONNULL_ALL_ bool +handle_early_peer_shutdown (struct MHD_Connection *restrict c, + bool has_unfinished_process) +{ + mhd_conn_start_closing (c, + has_unfinished_process ? + mhd_CONN_CLOSE_CLIENT_SHUTDOWN_EARLY : + mhd_CONN_CLOSE_HTTP_COMPLETED, + NULL); + return false; +} + + MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ bool mhd_conn_process_data (struct MHD_Connection *restrict c) { @@ -288,25 +305,39 @@ mhd_conn_process_data (struct MHD_Connection *restrict c) return true; } - switch (process_http_comm_layer (c)) - { - case mhd_COMM_LAYER_OK: - break; /* Process HTTP data */ - case mhd_COMM_LAYER_PROCESSING: - mhd_assert (!c->resuming); - return true; /* Too early for HTTP */ - case mhd_COMM_LAYER_BROKEN: - mhd_assert (c->dbg.closing_started); - return false; /* Connection is broken */ - default: - mhd_UNREACHABLE (); - return false; - } + mhd_assert ((!mhd_SCKT_NET_ST_HAS_FLAG (c->sk.ready, + mhd_SOCKET_NET_STATE_ERROR_READY)) + || (mhd_SOCKET_ERR_NO_ERROR != c->sk.state.discnt_err)); - if (c->resuming) + if (mhd_SOCKET_ERR_NO_ERROR == c->sk.state.discnt_err) { - mhd_assert (!mhd_C_IS_HTTP2 (c)); - finish_resume (c); + switch (process_http_comm_layer (c)) + { + case mhd_COMM_LAYER_OK: + break; /* Process HTTP data */ + case mhd_COMM_LAYER_PROCESSING: + mhd_assert (!c->resuming); + if (c->sk.state.rmt_shut_wr) + { + bool unfinished; + unfinished = (0 != c->read_buffer_offset); +#ifdef MHD_SUPPORT_HTTPS + if (!unfinished + && mhd_C_HAS_TLS (c)) + unfinished = + (mhd_TLS_ALPN_PROT_HTTP2 == mhd_tls_conn_get_alpn_prot (c->tls)); +#endif /* MHD_SUPPORT_HTTPS */ + return handle_early_peer_shutdown (c, + unfinished); + } + return true; /* Too early for HTTP */ + case mhd_COMM_LAYER_BROKEN: + mhd_assert (c->dbg.closing_started); + return false; /* Connection is broken */ + default: + mhd_UNREACHABLE (); + return false; + } } #ifdef MHD_SUPPORT_HTTP2 @@ -323,23 +354,21 @@ mhd_conn_process_data (struct MHD_Connection *restrict c) mhd_assert (mhd_D_IS_HTTP1_ENABLED (d) || (!mhd_C_IS_HTTP2 (c)) \ || c->stop_with_error); + if (c->resuming) + { + mhd_assert (!mhd_C_IS_HTTP2 (c)); + finish_resume (c); + } + if ((c->sk.state.rmt_shut_wr) && (mhd_HTTP_STAGE_START_REPLY > c->stage)) { if (0 == c->read_buffer_offset) { /* Read buffer is empty, connection state is actual */ - mhd_conn_start_closing (c, - (mhd_HTTP_STAGE_INIT == c->stage) ? - mhd_CONN_CLOSE_HTTP_COMPLETED : - mhd_CONN_CLOSE_CLIENT_SHUTDOWN_EARLY, - NULL); - return false; + return handle_early_peer_shutdown (c, + (mhd_HTTP_STAGE_INIT != c->stage)); } } - mhd_assert ((!mhd_SCKT_NET_ST_HAS_FLAG (c->sk.ready, - mhd_SOCKET_NET_STATE_ERROR_READY)) - || (mhd_SOCKET_ERR_NO_ERROR != c->sk.state.discnt_err)); - if (mhd_SOCKET_ERR_NO_ERROR != c->sk.state.discnt_err) { mhd_assert (mhd_SOCKET_ERR_IS_HARD (c->sk.state.discnt_err));