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:
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 */