commit e080c7a65bd06a43a32da9522a63af0632a2e3e0
parent 2b784d29c07f09aa8a79606e93b421b565be4341
Author: Evgeny Grin (Karlson2k) <k2k@drgrin.dev>
Date: Fri, 28 Aug 2026 11:38:54 +0200
HPACK: fixed assert in literal name encoding, improved code and doxy
Diffstat:
1 file changed, 72 insertions(+), 34 deletions(-)
diff --git a/src/mhd2/h2/hpack/mhd_hpack_codec.c b/src/mhd2/h2/hpack/mhd_hpack_codec.c
@@ -4083,6 +4083,11 @@ stbl_idx_entry_info (dtbl_idx_ft hpack_idx)
#define mhd_HPACK_STBL_NORM_WITH_VALUE_POS (15u)
/**
+ * The index of the first real (non-pseudo) header
+ */
+#define mhd_HPACK_STBL_NORM_START_IDX (mhd_HPACK_STBL_NORM_START_POS + 1u)
+
+/**
* Get a static-table entry by HPACK index.
*
* The index @a idx must refer to the static table
@@ -5643,33 +5648,38 @@ hpack_enc_string_literal (const struct mhd_BufferConst *restrict str_data,
* value is always encoded literally.
* String representations may use Huffman coding if permitted.
*
- * @param[in,out] hk_enc the encoder context
- * @param[in] name the field name bytes and size
- * @param[in] name_idx the field name index if known and indexed name is
- * allowed,
- * zero if index is not known or indexed name is not
- * allowed
- * @param[in] value the field value bytes and size
- * @param[in] msg_type the literal representation kind to use
- * @param[in] name_idx_stat_allowed set to 'true' if name encoding as a
- * reference to the static table is allowed
- * @param[in] name_idx_dyn_allowed set to 'true' if name encoding as a
- * reference to the dynamic table is allowed
- * @param[in] huffman_allowed set to 'true' if Huffman coding is allowed
- * @param[in] out_buff_size the size of @a out_buff in bytes,
- * could be zero (the function will always fail
- * if it is less than two)
- * @param[out] out_buff the output buffer for the encoded field
- * @param[out] bytes_encoded to be set to the number of bytes written to
- * the @a out_buff
+ * @param[in] hk_enc the encoder context
+ * @param[in] name the field name bytes and size
+ * @param[in] name_idx the field name index if known,
+ * zero if index is not known or indexed name is not
+ * allowed, zero must not be used for pseudo-header
+ * names (names starting with ':'),
+ * when non-zero the name is encoded by index reference
+ * if any of @p name_idx_stat_allowed or
+ * @p name_idx_dyn_allowed is 'true'
+ * @param[in] value the field value bytes and size
+ * @param[in] msg_type the literal representation kind to use
+ * @param[in] name_idx_stat_allowed allow name lookup in static table (or
+ * use @p name_idx if provided) and encode
+ * the name as a reference
+ * @param[in] name_idx_dyn_allowed allow name lookup in dynamic table (or
+ * use @p name_idx if provided) and encode
+ * the name as a reference
+ * @param[in] huffman_allowed set to 'true' if Huffman coding is allowed
+ * @param[in] out_buff_size the size of @p out_buff in bytes,
+ * could be zero (the function will always fail
+ * if it is less than two)
+ * @param[out] out_buff the output buffer for the encoded field
+ * @param[out] bytes_encoded to be set to the number of bytes written to
+ * the @p out_buff
* @return 'true' on success;
* 'false' if the output buffer is too small
*/
static MHD_FN_PAR_NONNULL_ALL_
-MHD_FN_PAR_INOUT_ (1)
+MHD_FN_PAR_IN_ (1)
MHD_FN_PAR_IN_ (2) MHD_FN_PAR_IN_ (4)
MHD_FN_PAR_OUT_SIZE_ (10, 9) MHD_FN_PAR_OUT_ (11) bool
-hpack_enc_field_literal (struct mhd_HpackEncContext *restrict hk_enc,
+hpack_enc_field_literal (const struct mhd_HpackEncContext *restrict hk_enc,
const struct mhd_BufferConst *restrict name,
dtbl_idx_ft name_idx,
const struct mhd_BufferConst *restrict value,
@@ -5688,12 +5698,22 @@ hpack_enc_field_literal (struct mhd_HpackEncContext *restrict hk_enc,
mhd_constexpr uint_fast8_t field_never_idxng_prfx = (uint_fast8_t)(1u << 4u);
mhd_constexpr uint_fast8_t field_never_idxng_prfx_bits = 4u;
struct mhd_HpackDTblContext const *restrict dyn = hk_enc->dyn;
+ dtbl_idx_ft name_idx_enc;
uint_fast8_t first_byte_prefix;
uint_fast8_t first_byte_prefix_bits;
size_t pos;
size_t pos_incr;
- mhd_assert ((0u == name->size) || (':' != name->data[0]));
+ mhd_assert ((0u == name->size)
+ || (':' != name->data[0])
+ || (0u != name_idx));
+ mhd_assert ((0u == name->size)
+ || (':' != name->data[0])
+ || (mhd_HPACK_STBL_NORM_START_IDX > name_idx));
+ mhd_assert ((0u == name->size)
+ || (':' != name->data[0])
+ || name_idx_stat_allowed
+ || !name_idx_dyn_allowed);
if (2u > out_buff_size)
return false; /* No space even for the minimal field */
@@ -5717,37 +5737,56 @@ hpack_enc_field_literal (struct mhd_HpackEncContext *restrict hk_enc,
return false;
}
+ name_idx_enc = 0u;
if (0u == name_idx)
{
if (name_idx_stat_allowed && name_idx_dyn_allowed)
- name_idx = mhd_htbl_find_name_real (dyn,
- name->size,
- name->data);
+ name_idx_enc = mhd_htbl_find_name_real (dyn,
+ name->size,
+ name->data);
else if (name_idx_stat_allowed && (0u != name->size))
- name_idx = mhd_stbl_find_name_real (name->size,
- name->data);
+ name_idx_enc = mhd_stbl_find_name_real (name->size,
+ name->data);
else if (mhd_COND_ALMOST_NEVER (name_idx_dyn_allowed))
- name_idx = mhd_dtbl_find_name (dyn,
- name->size,
- name->data);
+ name_idx_enc = mhd_dtbl_find_name (dyn,
+ name->size,
+ name->data);
}
else
{
+# if 0 /* This optimisation could be used if more requirements added to the caller side */
mhd_assert (name_idx_stat_allowed \
|| (mhd_HPACK_STBL_LAST_IDX < name_idx));
mhd_assert (name_idx_dyn_allowed \
|| (mhd_HPACK_STBL_LAST_IDX >= name_idx));
+# endif /* 0 */
+# ifndef NDEBUG
+ if (1)
+ {
+ struct mhd_BufferConst chk_name;
+ struct mhd_BufferConst chk_value;
+ mhd_assert (mhd_htbl_get_entry (dyn,
+ name_idx,
+ &chk_name,
+ &chk_value));
+ mhd_assert (name->size == chk_name.size);
+ mhd_assert (0 == memcmp (name->data, chk_name.data, name->size));
+ }
+# endif /* !NDEBUG */
+
+ if (name_idx_stat_allowed || name_idx_dyn_allowed)
+ name_idx_enc = name_idx;
}
pos = 0u;
- if (0u != name_idx)
+ if (0u != name_idx_enc)
{
/* Add name as a reference */
mhd_assert (name_idx_dyn_allowed || name_idx_stat_allowed);
pos_incr = hpack_put_number_to_buf (first_byte_prefix,
first_byte_prefix_bits,
- name_idx,
+ name_idx_enc,
out_buff_size - pos - 1u, /* Reserve one byte for the field value */
out_buff + pos);
if (0u == pos_incr)
@@ -6468,8 +6507,7 @@ hpack_enc_pf_status (struct mhd_HpackEncContext *restrict hk_enc,
(mhd_HPACK_ENC_PFS_POL_NEVER_W_NAME_LIT_NO_HUFFMAN > enc_pol);
if (!hpack_enc_field_literal (hk_enc,
&pf_status_str,
- name_idx_stat_allowed ?
- pf_status_first_idx : 0u,
+ pf_status_first_idx,
&code_val,
mhd_HPACK_ENC_LIT_IDX_TYPE_NEVER_INDEXING,
name_idx_stat_allowed,