libmicrohttpd2

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

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:
Msrc/mhd2/h2/hpack/mhd_hpack_codec.c | 106+++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------------
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,