libmicrohttpd2

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

commit 86e0ab38d04baf3afd70db67a6529c7060bb712e
parent 7acad4742ce595aa370b90448b031f0bd6b25c0c
Author: Evgeny Grin (Karlson2k) <k2k@drgrin.dev>
Date:   Sun, 15 Jun 2025 15:49:31 +0200

Added reporting of response is aborted in the middle.

Do not report when responding hasn't been started yet.

Diffstat:
Msrc/include/microhttpd2.h | 65+++++++++++++++++++++++++++++++++++++++++++++++++----------------
Msrc/include/microhttpd2_preamble.h.in | 65+++++++++++++++++++++++++++++++++++++++++++++++++----------------
Msrc/mhd2/stream_funcs.c | 60+++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
3 files changed, 155 insertions(+), 35 deletions(-)

diff --git a/src/include/microhttpd2.h b/src/include/microhttpd2.h @@ -582,6 +582,11 @@ enum MHD_FIXED_ENUM_MHD_SET_ MHD_StatusCode */ MHD_SC_UPGRADED_NET_TIMEOUT = 30161 , + /** + * Not enough system resources + */ + MHD_SC_NO_SYS_RESOURCES = 30180 + , /* 40000-level errors are caused by the HTTP client (or the network) */ @@ -593,22 +598,6 @@ enum MHD_FIXED_ENUM_MHD_SET_ MHD_StatusCode MHD_SC_CONNECTION_PARSE_FAIL_CLOSED = 40000 , /** - * MHD is closing a connection because it was reset. - */ - MHD_SC_CONNECTION_RESET_CLOSED = 40001 - , - /** - * MHD is closing a connection because receiving the - * request failed. - */ - MHD_SC_CONNECTION_RECV_FAIL_CLOSED = 40002 - , - /** - * MHD is closing a connection because sending the response failed. - */ - MHD_SC_CONNECTION_SEND_FAIL_CLOSED = 40003 - , - /** * MHD is returning an error because the header provided * by the client is too big. */ @@ -776,6 +765,50 @@ enum MHD_FIXED_ENUM_MHD_SET_ MHD_StatusCode */ MHD_SC_REQ_PROCCESSING_ERR_REPLY = 41000 , + /** + * MHD is closing a connection because of timeout. + */ + MHD_SC_CONNECTION_TIMEOUT = 42000 + , + /** + * MHD is closing a connection because receiving the + * request failed. + */ + MHD_SC_CONNECTION_RECV_FAIL_CLOSED = 42020 + , + /** + * MHD is closing a connection because sending the response failed. + */ + MHD_SC_CONNECTION_SEND_FAIL_CLOSED = 42021 + , + /** + * MHD is closing a connection because remote client shut down its sending + * side before full request was sent. + */ + MHD_SC_CLIENT_SHUTDOWN_EARLY = 42040 + , + /** + * MHD is closing a connection because remote client closed connection + * early. + */ + MHD_SC_CLIENT_CLOSED_CONN_EARLY = 42041 + , + /** + * MHD is closing a connection connection has been (remotely) aborted. + */ + MHD_SC_CONNECTION_ABORTED = 42042 + , + /** + * MHD is closing a connection because it was reset. + */ + MHD_SC_CONNECTION_RESET = 42060 + , + /** + * MHD is closing a connection connection (or connection socket) has + * been broken. + */ + MHD_SC_CONNECTION_BROKEN = 42061 + , /* 50000-level errors are because of an error internal to the MHD logic, possibly including our interaction diff --git a/src/include/microhttpd2_preamble.h.in b/src/include/microhttpd2_preamble.h.in @@ -582,6 +582,11 @@ enum MHD_FIXED_ENUM_MHD_SET_ MHD_StatusCode */ MHD_SC_UPGRADED_NET_TIMEOUT = 30161 , + /** + * Not enough system resources + */ + MHD_SC_NO_SYS_RESOURCES = 30180 + , /* 40000-level errors are caused by the HTTP client (or the network) */ @@ -593,22 +598,6 @@ enum MHD_FIXED_ENUM_MHD_SET_ MHD_StatusCode MHD_SC_CONNECTION_PARSE_FAIL_CLOSED = 40000 , /** - * MHD is closing a connection because it was reset. - */ - MHD_SC_CONNECTION_RESET_CLOSED = 40001 - , - /** - * MHD is closing a connection because receiving the - * request failed. - */ - MHD_SC_CONNECTION_RECV_FAIL_CLOSED = 40002 - , - /** - * MHD is closing a connection because sending the response failed. - */ - MHD_SC_CONNECTION_SEND_FAIL_CLOSED = 40003 - , - /** * MHD is returning an error because the header provided * by the client is too big. */ @@ -776,6 +765,50 @@ enum MHD_FIXED_ENUM_MHD_SET_ MHD_StatusCode */ MHD_SC_REQ_PROCCESSING_ERR_REPLY = 41000 , + /** + * MHD is closing a connection because of timeout. + */ + MHD_SC_CONNECTION_TIMEOUT = 42000 + , + /** + * MHD is closing a connection because receiving the + * request failed. + */ + MHD_SC_CONNECTION_RECV_FAIL_CLOSED = 42020 + , + /** + * MHD is closing a connection because sending the response failed. + */ + MHD_SC_CONNECTION_SEND_FAIL_CLOSED = 42021 + , + /** + * MHD is closing a connection because remote client shut down its sending + * side before full request was sent. + */ + MHD_SC_CLIENT_SHUTDOWN_EARLY = 42040 + , + /** + * MHD is closing a connection because remote client closed connection + * early. + */ + MHD_SC_CLIENT_CLOSED_CONN_EARLY = 42041 + , + /** + * MHD is closing a connection connection has been (remotely) aborted. + */ + MHD_SC_CONNECTION_ABORTED = 42042 + , + /** + * MHD is closing a connection because it was reset. + */ + MHD_SC_CONNECTION_RESET = 42060 + , + /** + * MHD is closing a connection connection (or connection socket) has + * been broken. + */ + MHD_SC_CONNECTION_BROKEN = 42061 + , /* 50000-level errors are because of an error internal to the MHD logic, possibly including our interaction diff --git a/src/mhd2/stream_funcs.c b/src/mhd2/stream_funcs.c @@ -745,6 +745,7 @@ mhd_conn_start_closing (struct MHD_Connection *restrict c, bool close_hard; enum MHD_RequestEndedCode end_code; enum MHD_StatusCode sc; + bool reply_sending_aborted; #ifdef mhd_DEBUG_CONN_ADD_CLOSE fprintf (stderr, @@ -756,6 +757,9 @@ mhd_conn_start_closing (struct MHD_Connection *restrict c, log_msg ? "\"" : ""); #endif /* mhd_DEBUG_CONN_ADD_CLOSE */ + reply_sending_aborted = + ((mhd_HTTP_STAGE_HEADERS_SENDING <= c->stage) + && (mhd_HTTP_STAGE_FULL_REPLY_SENT > c->stage)); sc = MHD_SC_INTERNAL_ERROR; switch (reason) { @@ -763,15 +767,18 @@ mhd_conn_start_closing (struct MHD_Connection *restrict c, close_hard = true; end_code = MHD_REQUEST_ENDED_HTTP_PROTOCOL_ERROR; sc = MHD_SC_REQ_MALFORMED; + mhd_assert (! reply_sending_aborted); break; case mhd_CONN_CLOSE_NO_POOL_MEM_FOR_REQUEST: close_hard = true; end_code = MHD_REQUEST_ENDED_NO_RESOURCES; + mhd_assert (! reply_sending_aborted); break; case mhd_CONN_CLOSE_CLIENT_SHUTDOWN_EARLY: close_hard = true; end_code = MHD_REQUEST_ENDED_CLIENT_ABORT; - sc = MHD_SC_REPLY_POOL_ALLOCATION_FAILURE; + sc = MHD_SC_CLIENT_SHUTDOWN_EARLY; + mhd_assert (! reply_sending_aborted); break; case mhd_CONN_CLOSE_NO_POOL_MEM_FOR_REPLY: close_hard = true; @@ -779,6 +786,9 @@ mhd_conn_start_closing (struct MHD_Connection *restrict c, MHD_REQUEST_ENDED_NO_RESOURCES : MHD_REQUEST_ENDED_HTTP_PROTOCOL_ERROR; sc = MHD_SC_REPLY_POOL_ALLOCATION_FAILURE; + if (reply_sending_aborted && (NULL == log_msg)) + log_msg = mhd_MSG4LOG ("Response aborted due to insufficient memory " \ + "in the connection pool"); break; case mhd_CONN_CLOSE_NO_MEM_FOR_ERR_RESPONSE: close_hard = true; @@ -791,47 +801,71 @@ mhd_conn_start_closing (struct MHD_Connection *restrict c, close_hard = true; end_code = MHD_REQUEST_ENDED_BY_APP_ERROR; sc = MHD_SC_APPLICATION_DATA_GENERATION_FAILURE_CLOSED; + if (reply_sending_aborted && (NULL == log_msg)) + log_msg = mhd_MSG4LOG ("Response aborted due to application reply " \ + "generation failure"); break; case mhd_CONN_CLOSE_APP_ABORTED: close_hard = true; end_code = MHD_REQUEST_ENDED_BY_APP_ABORT; sc = MHD_SC_APPLICATION_CALLBACK_ABORT_ACTION; + if (reply_sending_aborted && (NULL == log_msg)) + log_msg = mhd_MSG4LOG ("Application aborted reply sending"); 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; + if (reply_sending_aborted && (NULL == log_msg)) + log_msg = mhd_MSG4LOG ("Response aborted because OS failed " \ + "to read too large response file"); 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; + if (reply_sending_aborted && (NULL == log_msg)) + log_msg = mhd_MSG4LOG ("Response aborted because OS failed " \ + "to read response file"); 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; + if (reply_sending_aborted && (NULL == log_msg)) + log_msg = mhd_MSG4LOG ("Response aborted because response file is " + "shorter that expected"); break; #ifdef MHD_SUPPORT_AUTH_DIGEST case mhd_CONN_CLOSE_NONCE_ERROR: close_hard = true; end_code = MHD_REQUEST_ENDED_NONCE_ERROR; sc = MHD_SC_REPLY_NONCE_ERROR; + mhd_assert (! reply_sending_aborted); break; #endif /* MHD_SUPPORT_AUTH_DIGEST */ case mhd_CONN_CLOSE_INT_ERROR: close_hard = true; end_code = MHD_REQUEST_ENDED_NO_RESOURCES; + if (reply_sending_aborted && (NULL == log_msg)) + log_msg = mhd_MSG4LOG ("Response aborted due to MHD internal error"); break; case mhd_CONN_CLOSE_EXTR_EVENT_REG_FAILED: close_hard = true; end_code = MHD_REQUEST_ENDED_BY_EXT_EVENT_ERROR; sc = MHD_SC_EXTR_EVENT_REG_FAILED; + if (reply_sending_aborted && (NULL == log_msg)) + log_msg = mhd_MSG4LOG ("Response aborted due to external event " \ + "registration failure"); break; case mhd_CONN_CLOSE_NO_SYS_RESOURCES: close_hard = true; end_code = MHD_REQUEST_ENDED_NO_RESOURCES; + sc = MHD_SC_NO_SYS_RESOURCES; + if (reply_sending_aborted && (NULL == log_msg)) + log_msg = mhd_MSG4LOG ("Response aborted due to lack of " \ + "system resources"); break; case mhd_CONN_CLOSE_SOCKET_ERR: close_hard = true; @@ -839,15 +873,29 @@ mhd_conn_start_closing (struct MHD_Connection *restrict c, { case mhd_SOCKET_ERR_NOMEM: end_code = MHD_REQUEST_ENDED_NO_RESOURCES; + sc = MHD_SC_NO_SYS_RESOURCES; + if (reply_sending_aborted && (NULL == log_msg)) + log_msg = mhd_MSG4LOG ("Response aborted because system closed " \ + "socket due to lack of system resources"); break; case mhd_SOCKET_ERR_REMT_DISCONN: close_hard = false; end_code = (mhd_HTTP_STAGE_INIT == c->stage) ? - MHD_REQUEST_ENDED_COMPLETED_OK /* Not used */ : - MHD_REQUEST_ENDED_CLIENT_ABORT; + MHD_REQUEST_ENDED_COMPLETED_OK /* Not used */ + : MHD_REQUEST_ENDED_CLIENT_ABORT; + if (reply_sending_aborted) + { + sc = MHD_SC_CLIENT_CLOSED_CONN_EARLY; + if (NULL == log_msg) + log_msg = mhd_MSG4LOG ("Response aborted because remote client " \ + "closed connection early"); + } break; case mhd_SOCKET_ERR_CONNRESET: end_code = MHD_REQUEST_ENDED_CLIENT_ABORT; + sc = MHD_SC_CONNECTION_RESET; + if (reply_sending_aborted && (NULL == log_msg)) + log_msg = mhd_MSG4LOG ("Response aborted due to aborted connection"); break; case mhd_SOCKET_ERR_CONN_BROKEN: case mhd_SOCKET_ERR_NOTCONN: @@ -862,6 +910,9 @@ mhd_conn_start_closing (struct MHD_Connection *restrict c, case mhd_SOCKET_ERR_INTERNAL: case mhd_SOCKET_ERR_NO_ERROR: end_code = MHD_REQUEST_ENDED_CONNECTION_ERROR; + sc = MHD_SC_CONNECTION_BROKEN; + if (reply_sending_aborted && (NULL == log_msg)) + log_msg = mhd_MSG4LOG ("Response aborted due to broken connection"); break; case mhd_SOCKET_ERR_AGAIN: case mhd_SOCKET_ERR_INTR: @@ -884,6 +935,9 @@ mhd_conn_start_closing (struct MHD_Connection *restrict c, } close_hard = true; end_code = MHD_REQUEST_ENDED_TIMEOUT_REACHED; + sc = MHD_SC_CONNECTION_TIMEOUT; + if (reply_sending_aborted && (NULL == log_msg)) + log_msg = mhd_MSG4LOG ("Response aborted due to sending timeout"); break; case mhd_CONN_CLOSE_ERR_REPLY_SENT: