libmicrohttpd2

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

commit 92f142bffd8e7ba3981750ebf6d99cdcf8d4b6ff
parent 1d6f9c1662e0b7fefdcd64d2c5a560147b65a8f4
Author: Evgeny Grin (Karlson2k) <k2k@drgrin.dev>
Date:   Tue, 25 Aug 2026 17:48:06 +0200

Unified data tagging for HTTP family. Should help future HTTP/3 code

Diffstat:
Msrc/incl_priv/mhd_sys_options.h | 10++++++++++
Msrc/mhd2/Makefile.am | 2+-
Msrc/mhd2/h2/h2_action.c | 2+-
Msrc/mhd2/h2/h2_conn_streams.c | 4++--
Msrc/mhd2/h2/h2_reply_funcs.c | 2+-
Msrc/mhd2/h2/h2_req_data.h | 10++++++++--
Msrc/mhd2/h2/h2_req_get_items.c | 8++++----
Msrc/mhd2/h2/h2_stream_data.h | 9+++++++--
Asrc/mhd2/mhd_handle_tag.h | 132+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/mhd2/mhd_request.h | 17++++++++---------
Msrc/mhd2/mhd_stream.h | 18++++++++++--------
11 files changed, 184 insertions(+), 30 deletions(-)

diff --git a/src/incl_priv/mhd_sys_options.h b/src/incl_priv/mhd_sys_options.h @@ -674,6 +674,16 @@ # define MHD_AUTH_DIGEST_DEF_MAX_NC 1000 #endif /* ! MHD_AUTH_DIGEST_DEF_MAX_NC */ +#ifdef MHD_SUPPORT_HTTP2 +/* Note: HTTP/1.x support is mandatory in the current code */ + +/** + * Defined if more than one HTTP protocol family is supported by this build + * and therefore the protocol kind of the handles must be detected in run-time. + */ +# define mhd_MULTI_HTTP_VER_BUILD 1 +#endif /* MHD_SUPPORT_HTTP2 */ + #ifndef mhd_HAVE_TLS_THREAD_CLEANUP # ifdef MHD_SUPPORT_OPENSSL /** diff --git a/src/mhd2/Makefile.am b/src/mhd2/Makefile.am @@ -59,7 +59,7 @@ libmicrohttpd2_la_SOURCES = \ lib_get_info.c \ mhd_dlinked_list.h \ mhd_conn_socket.h mhd_connection.h \ - mhd_stream.h \ + mhd_stream.h mhd_handle_tag.h \ mhd_locks.h mhd_locksrw.h \ mhd_itc.c mhd_itc.h mhd_itc_types.h \ mhd_mono_clock.c mhd_mono_clock.h \ diff --git a/src/mhd2/h2/h2_action.c b/src/mhd2/h2/h2_action.c @@ -58,7 +58,7 @@ MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ bool mhd_h2_act_is_resp_h2_compatible (const struct mhd_H2RequestData *restrict req, const struct MHD_Response *restrict response) { - mhd_assert (req->is_http2); + mhd_assert (mhd_HNDL_IS_HTTP2 (req)); // TODO: move new two checks to the unified (HTTP/1.x and HTTP/2) code if ((mhd_HTTP_METHOD_CONNECT == req->method) diff --git a/src/mhd2/h2/h2_conn_streams.c b/src/mhd2/h2/h2_conn_streams.c @@ -94,7 +94,7 @@ conn_add_new_stream (struct MHD_Connection *restrict c, if (NULL == s) return NULL; - s->is_h2 = true; + mhd_HNDL_TAG_SET_HTTP2 (s); s->stream_id = stream_id; #ifndef HAVE_NULL_PTR_ALL_ZEROS @@ -105,7 +105,7 @@ conn_add_new_stream (struct MHD_Connection *restrict c, s->c = c; - s->req.is_http2 = true; + mhd_HNDL_TAG_SET_HTTP2 (&(s->req)); s->req.stage = mhd_H2_REQ_STAGE_HEADERS_INCOMPLETE; s->req.pos_method = mhd_H2_REQ_ITEM_POS_INVALID; s->req.pos_path = mhd_H2_REQ_ITEM_POS_INVALID; diff --git a/src/mhd2/h2/h2_reply_funcs.c b/src/mhd2/h2/h2_reply_funcs.c @@ -606,7 +606,7 @@ stream_content_send (struct mhd_H2Stream *s) MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ bool mhd_h2_stream_reply_send (struct mhd_H2Stream *s) { - mhd_assert (s->is_h2); + mhd_assert (mhd_HNDL_IS_HTTP2 (s)); mhd_assert (mhd_H2_RPL_STAGE_END_STREAM != s->rpl.stage); mhd_assert (mhd_H2_RPL_STAGE_BROKEN != s->rpl.stage); diff --git a/src/mhd2/h2/h2_req_data.h b/src/mhd2/h2/h2_req_data.h @@ -50,6 +50,8 @@ #include "sys_bool_type.h" #include "sys_base_types.h" +#include "mhd_handle_tag.h" + #include "http_method.h" struct MHD_Connection; /* Forward declaration */ @@ -99,10 +101,14 @@ enum MHD_FIXED_ENUM_ mhd_H2ReqStage struct mhd_H2RequestData { +#ifdef mhd_MULTI_HTTP_VER_BUILD /** - * Always 'true' + * The handle tag. + * Must be the first member, see #mhd_HandleTag. + * Always indicates HTTP/2 for this structure. */ - bool is_http2; + struct mhd_HandleTag tag; +#endif /* mhd_MULTI_HTTP_VER_BUILD */ enum mhd_H2ReqStage stage; diff --git a/src/mhd2/h2/h2_req_get_items.c b/src/mhd2/h2/h2_req_get_items.c @@ -103,8 +103,8 @@ mhd_h2_request_get_value_n (struct MHD_Request *restrict r, unsigned int type_mask; const char *buff; - mhd_assert (r->is_http2); - mhd_assert (s->is_h2); + mhd_assert (mhd_HNDL_IS_HTTP2 (r)); + mhd_assert (mhd_HNDL_IS_HTTP2 (s)); if ((mhd_H2_REQ_STAGE_HEADERS_DECODING != s->req.stage) && (mhd_H2_REQ_STAGE_HEADERS_PROCESSING != s->req.stage) @@ -199,8 +199,8 @@ mhd_h2_request_get_values_cb (struct MHD_Request *r, size_t count; - mhd_assert (r->is_http2); - mhd_assert (s->is_h2); + mhd_assert (mhd_HNDL_IS_HTTP2 (r)); + mhd_assert (mhd_HNDL_IS_HTTP2 (s)); if ((mhd_H2_REQ_STAGE_HEADERS_DECODING != s->req.stage) && (mhd_H2_REQ_STAGE_HEADERS_PROCESSING != s->req.stage) diff --git a/src/mhd2/h2/h2_stream_data.h b/src/mhd2/h2/h2_stream_data.h @@ -51,6 +51,7 @@ #include "sys_base_types.h" #include "mhd_dlinked_list.h" +#include "mhd_handle_tag.h" #include "h2_err_codes.h" @@ -120,10 +121,14 @@ mhd_DLINKEDL_LINKS_DEF (mhd_H2Stream); struct mhd_H2Stream { +#ifdef mhd_MULTI_HTTP_VER_BUILD /** - * Must be always 'true' + * The handle tag. + * Must be the first member, see #mhd_HandleTag. + * Always indicates HTTP/2 for this structure. */ - bool is_h2; + struct mhd_HandleTag tag; +#endif /* mhd_MULTI_HTTP_VER_BUILD */ uint_least32_t stream_id; diff --git a/src/mhd2/mhd_handle_tag.h b/src/mhd2/mhd_handle_tag.h @@ -0,0 +1,132 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later OR (GPL-2.0-or-later WITH eCos-exception-2.0) */ +/* + This file is part of GNU libmicrohttpd. + Copyright (C) 2026 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. + + Alternatively, you can redistribute GNU libmicrohttpd and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version, together + with the eCos exception, as follows: + + As a special exception, if other files instantiate templates or + use macros or inline functions from this file, or you compile this + file and link it with other works to produce a work based on this + file, this file does not by itself cause the resulting work to be + covered by the GNU General Public License. However the source code + for this file must still be made available in accordance with + section (3) of the GNU General Public License v2. + + This exception does not invalidate any other reasons why a work + based on this file might be covered by the GNU General Public + License. + + You should have received copies of the GNU Lesser General Public + License and the GNU General Public License along with this library; + if not, see <https://www.gnu.org/licenses/>. +*/ + +/** + * @file src/mhd2/mhd_handle_tag.h + * @brief The handle tag and the related macros + * @author Karlson2k (Evgeny Grin) + * + * The public handles (#MHD_Request, #MHD_Stream) are used for both HTTP/1.x + * and HTTP/2 data. The actual type is detected by the leading member, which + * is the same in both halves of every such pair. + */ + +#ifndef MHD_HANDLE_TAG_H +#define MHD_HANDLE_TAG_H 1 + +#include "mhd_sys_options.h" + +#include "sys_bool_type.h" + +/* Note: HTTP/1.x support is mandatory in the current code */ + +/* Sanity check */ +#ifndef mhd_MULTI_HTTP_VER_BUILD +# ifdef MHD_SUPPORT_HTTP2 +# error MHD_SUPPORT_HTTP2 is defined, but mhd_MULTI_HTTP_VER_BUILD is not +# endif +#else /* ! mhd_MULTI_HTTP_VER_BUILD */ +# ifndef MHD_SUPPORT_HTTP2 +# error mhd_MULTI_HTTP_VER_BUILD is defined, but MHD_SUPPORT_HTTP2 is not +# endif +#endif /* ! mhd_MULTI_HTTP_VER_BUILD */ + +#ifdef mhd_MULTI_HTTP_VER_BUILD +/** + * The handle tag. + * + * MUST be the first member of both halves of every pair: #MHD_Request and + * #mhd_H2RequestData, #MHD_Stream and #mhd_H2Stream. + * Do not access the members directly, use #mhd_HNDL_IS_HTTP2() and + * the related macros. + */ +struct mhd_HandleTag +{ + /** + * 'true' for HTTP/2 handles, 'false' for HTTP/1.x handles + */ + bool is_http2; +}; + +/** + * Get the pointer to the tag of the handle. + * A pointer to a structure points to its initial member, therefore the tag of + * any half of the pair is reachable by this conversion. + */ +# define mhd_HNDL_TAG_(handle) \ + ((const struct mhd_HandleTag *) (const void *) (handle)) + +/** + * Check whether the handle is an HTTP/2 handle + */ +# define mhd_HNDL_IS_HTTP2(handle) (mhd_HNDL_TAG_ (handle)->is_http2) + +/** + * Set the tag of the handle to HTTP/1.x + */ +# define mhd_HNDL_TAG_SET_HTTP1(handle) \ + ((void) ((handle)->tag.is_http2 = false)) +/** + * Set the tag of the handle to HTTP/2 + */ +# define mhd_HNDL_TAG_SET_HTTP2(handle) \ + ((void) ((handle)->tag.is_http2 = true)) +#else /* ! mhd_MULTI_HTTP_VER_BUILD */ + +/** + * Check whether the handle is an HTTP/2 handle + */ +# define mhd_HNDL_IS_HTTP2(handle) (((void) (handle)), (! ! 0)) + +/** + * Set the tag of the handle to HTTP/1.x. No-op, the tag is not used. + */ +# define mhd_HNDL_TAG_SET_HTTP1(handle) ((void) (handle)) +/** + * Set the tag of the handle to HTTP/2. No-op, the tag is not used. + */ +# define mhd_HNDL_TAG_SET_HTTP2(handle) ((void) (handle)) +#endif /* ! mhd_MULTI_HTTP_VER_BUILD */ + +/** + * Check whether the handle is an HTTP/1.x handle + */ +#define mhd_HNDL_IS_HTTP1(handle) (! mhd_HNDL_IS_HTTP2 (handle)) + + +#endif /* ! MHD_HANDLE_TAG_H */ diff --git a/src/mhd2/mhd_request.h b/src/mhd2/mhd_request.h @@ -53,6 +53,7 @@ #include "mhd_public_api.h" #include "mhd_dlinked_list.h" +#include "mhd_handle_tag.h" #include "http_prot_ver.h" #include "http_method.h" @@ -386,12 +387,14 @@ struct mhd_ReqAuthData */ struct MHD_Request { -#ifdef MHD_SUPPORT_HTTP2 +#ifdef mhd_MULTI_HTTP_VER_BUILD /** - * Always 'false' in HTTP/1.x requests + * The handle tag. + * Must be the first member, see #mhd_HandleTag. + * Always indicates HTTP/1.x for this structure. */ - bool is_http2; -#endif /* MHD_SUPPORT_HTTP2 */ + struct mhd_HandleTag tag; +#endif /* mhd_MULTI_HTTP_VER_BUILD */ /** * Linked list of parsed headers. */ @@ -550,11 +553,7 @@ struct MHD_Request union MHD_HeadersProcessing hdrs; }; -#ifdef MHD_SUPPORT_HTTP2 -# define mhd_REQ_IS_HTTP2(req) ((req)->is_http2) -#else /* ! MHD_SUPPORT_HTTP2 */ -# define mhd_REQ_IS_HTTP2(req) (! ! 0) -#endif /* ! MHD_SUPPORT_HTTP2 */ +#define mhd_REQ_IS_HTTP2(req) mhd_HNDL_IS_HTTP2 (req) #ifdef MHD_SUPPORT_HTTP2 # define mhd_REQ_GET_ACT_UNION(req) \ diff --git a/src/mhd2/mhd_stream.h b/src/mhd2/mhd_stream.h @@ -47,7 +47,7 @@ #include "mhd_sys_options.h" -#include "sys_bool_type.h" +#include "mhd_handle_tag.h" /** * The HTTP stream data. @@ -55,16 +55,18 @@ */ struct MHD_Stream { +#ifdef mhd_MULTI_HTTP_VER_BUILD /** - * Always 'false' for HTTP/1.x streams + * The handle tag. + * Must be the first member, see #mhd_HandleTag. + * Always indicates HTTP/1.x for this structure. */ - bool is_http2; + struct mhd_HandleTag tag; +#else /* ! mhd_MULTI_HTTP_VER_BUILD */ + char dummy; /* C has no empty structures */ +#endif /* ! mhd_MULTI_HTTP_VER_BUILD */ }; -#ifdef MHD_SUPPORT_HTTP2 -# define mhd_STRM_IS_HTTP2(stream) ((stream)->is_http2) -#else /* ! MHD_SUPPORT_HTTP2 */ -# define mhd_STRM_IS_HTTP2(stream) (! ! 0) -#endif /* ! MHD_SUPPORT_HTTP2 */ +#define mhd_STRM_IS_HTTP2(stream) mhd_HNDL_IS_HTTP2 (stream) #endif /* ! MHD_STREAM_H */