libmicrohttpd2

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

h2_req_items_funcs.c (14086B)


      1 /* SPDX-License-Identifier: LGPL-2.1-or-later OR (GPL-2.0-or-later WITH eCos-exception-2.0) */
      2 /*
      3   This file is part of GNU libmicrohttpd.
      4   Copyright (C) 2025 Evgeny Grin (Karlson2k)
      5 
      6   GNU libmicrohttpd is free software; you can redistribute it and/or
      7   modify it under the terms of the GNU Lesser General Public
      8   License as published by the Free Software Foundation; either
      9   version 2.1 of the License, or (at your option) any later version.
     10 
     11   GNU libmicrohttpd is distributed in the hope that it will be useful,
     12   but WITHOUT ANY WARRANTY; without even the implied warranty of
     13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     14   Lesser General Public License for more details.
     15 
     16   Alternatively, you can redistribute GNU libmicrohttpd and/or
     17   modify it under the terms of the GNU General Public License as
     18   published by the Free Software Foundation; either version 2 of
     19   the License, or (at your option) any later version, together
     20   with the eCos exception, as follows:
     21 
     22     As a special exception, if other files instantiate templates or
     23     use macros or inline functions from this file, or you compile this
     24     file and link it with other works to produce a work based on this
     25     file, this file does not by itself cause the resulting work to be
     26     covered by the GNU General Public License. However the source code
     27     for this file must still be made available in accordance with
     28     section (3) of the GNU General Public License v2.
     29 
     30     This exception does not invalidate any other reasons why a work
     31     based on this file might be covered by the GNU General Public
     32     License.
     33 
     34   You should have received copies of the GNU Lesser General Public
     35   License and the GNU General Public License along with this library;
     36   if not, see <https://www.gnu.org/licenses/>.
     37 */
     38 
     39 /**
     40  * @file src/mhd2/h2/h2_req_items_funcs.c
     41  * @brief  Function for the request items (headers, URI params)
     42  * @author Karlson2k (Evgeny Grin)
     43  */
     44 
     45 #include "mhd_sys_options.h"
     46 
     47 #include "sys_base_types.h"
     48 
     49 #include "mhd_align.h"
     50 #include "mhd_predict.h"
     51 #include "mhd_constexpr.h"
     52 
     53 #include "mhd_assert.h"
     54 
     55 #include "sys_malloc.h"
     56 
     57 #include "mhd_buffer.h"
     58 #include "mhd_str_types.h"
     59 
     60 #include "h2_req_item_struct.h"
     61 
     62 #include "h2_req_items_funcs.h"
     63 
     64 
     65 struct mhd_H2ReqItemsBlock
     66 {
     67   /**
     68    * Number of items in the items block
     69    */
     70   size_t num_items;
     71 
     72   /**
     73    * The size of the items buffer, in bytes
     74    */
     75   size_t buf_size;
     76 
     77   /**
     78    * The starting offset of the free buffer space
     79    */
     80   uint_least32_t start_free;
     81 
     82 #ifndef NDEBUG
     83   uint_least32_t stream_id;
     84   bool buff_locked;
     85 #endif /* ! NDEBUG */
     86 };
     87 
     88 mhd_constexpr size_t mhd_rii_size = sizeof (struct mhd_H2ReqItem);
     89 
     90 mhd_static_inline char *
     91 h2_ib_get_buff (struct mhd_H2ReqItemsBlock *ib)
     92 {
     93   mhd_assert (ib->start_free <= ib->buf_size);
     94   return (char *) (ib + 1u);
     95 }
     96 
     97 
     98 mhd_static_inline const char *
     99 h2_ib_get_buffc (const struct mhd_H2ReqItemsBlock *ib)
    100 {
    101   mhd_assert (ib->start_free <= ib->buf_size);
    102   return (const char *) (ib + 1u);
    103 }
    104 
    105 
    106 mhd_static_inline struct mhd_H2ReqItem *
    107 h2_ib_get_zero_item (struct mhd_H2ReqItemsBlock *ib)
    108 {
    109   return ((struct mhd_H2ReqItem *)
    110           (void *) (h2_ib_get_buff (ib) + ib->buf_size))
    111          - 1u;
    112 }
    113 
    114 
    115 mhd_static_inline const struct mhd_H2ReqItem *
    116 h2_ib_get_zero_itemc (const struct mhd_H2ReqItemsBlock *ib)
    117 {
    118   return ((const struct mhd_H2ReqItem *)
    119           (const void *) (h2_ib_get_buffc (ib) + ib->buf_size))
    120          - 1u;
    121 }
    122 
    123 
    124 /* 'pos' is zero-based */
    125 mhd_static_inline struct mhd_H2ReqItem *
    126 h2_ib_get_n_item (struct mhd_H2ReqItemsBlock *ib,
    127                   size_t pos)
    128 {
    129   struct mhd_H2ReqItem *const ret = h2_ib_get_zero_item (ib) - pos;
    130   mhd_assert (ib->buf_size >= (ib->start_free
    131                                + ib->num_items * mhd_rii_size));
    132   return ret;
    133 }
    134 
    135 
    136 /* 'pos' is zero-based */
    137 mhd_static_inline const struct mhd_H2ReqItem *
    138 h2_ib_get_n_itemc (const struct mhd_H2ReqItemsBlock *ib,
    139                    size_t pos)
    140 {
    141   const struct mhd_H2ReqItem *const ret = h2_ib_get_zero_itemc (ib) - pos;
    142   mhd_assert (ib->buf_size >= (ib->start_free
    143                                + ib->num_items * mhd_rii_size));
    144   return ret;
    145 }
    146 
    147 
    148 mhd_static_inline size_t
    149 h2_ib_get_buff_free_size (const struct mhd_H2ReqItemsBlock *ib)
    150 {
    151   mhd_assert (ib->buf_size >= (ib->start_free
    152                                + ib->num_items * sizeof(struct mhd_H2ReqItem)));
    153   return ib->buf_size - ib->start_free - (ib->num_items * mhd_rii_size);
    154 }
    155 
    156 
    157 mhd_static_inline char *
    158 h2_ib_get_buff_free_ptr (struct mhd_H2ReqItemsBlock *ib)
    159 {
    160   return h2_ib_get_buff (ib) + ib->start_free;
    161 }
    162 
    163 
    164 MHD_INTERNAL mhd_FN_RET_UNALIASED
    165 mhd_FN_OBJ_CONSTRUCTOR (mhd_h2_items_block_destroy)
    166 struct mhd_H2ReqItemsBlock *
    167 mhd_h2_items_block_create (size_t buffer_size)
    168 {
    169   struct mhd_H2ReqItemsBlock *ret;
    170   uint_fast32_t buf_alloc_size;
    171 
    172   buf_alloc_size = (buffer_size & 0xFFFFFFFFu);
    173   if (mhd_COND_HARDLY_EVER ((0xFFFFFFFFu
    174                              - 2u * mhd_ALIGNOF (struct mhd_H2ReqItem))
    175                             > buffer_size))
    176     buf_alloc_size =
    177       (uint_fast32_t) (0xFFFFFFFFu - 2 * mhd_ALIGNOF (struct mhd_H2ReqItem));
    178 
    179   /* Round up to alignment */
    180   buf_alloc_size +=
    181     (uint_fast32_t)
    182     ((mhd_ALIGNOF (struct mhd_H2ReqItem)
    183       - (buf_alloc_size % mhd_ALIGNOF (struct mhd_H2ReqItem)))
    184      % mhd_ALIGNOF (struct mhd_H2ReqItem));
    185 
    186   /* Adjust the allocation size in case if alignment of mhd_H2ReqItem is
    187      stricter than alignment of mhd_H2ReqItemsBlock */
    188   buf_alloc_size +=
    189     (uint_fast32_t)
    190     ((mhd_ALIGNOF (struct mhd_H2ReqItem)
    191       - (sizeof(*ret) % mhd_ALIGNOF (struct mhd_H2ReqItem)))
    192      % mhd_ALIGNOF (struct mhd_H2ReqItem));
    193 
    194   mhd_assert ((buffer_size <= buf_alloc_size) || \
    195               (0xFFFFFFFFu - 2 * mhd_ALIGNOF (struct mhd_H2ReqItem) \
    196                <= buf_alloc_size));
    197 
    198   ret = (struct mhd_H2ReqItemsBlock *) malloc (sizeof (*ret) + buf_alloc_size);
    199 
    200   if (NULL == ret)
    201     return NULL; /* Failure exit point */
    202 
    203   ret->buf_size = (size_t) buf_alloc_size;
    204 #ifndef NDEBUG
    205   ret->buff_locked = false;
    206 #endif /* ! NDEBUG */
    207   mhd_h2_items_block_reset (ret);
    208 
    209   return ret;
    210 }
    211 
    212 
    213 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ void
    214 mhd_h2_items_block_destroy (struct mhd_H2ReqItemsBlock *ib)
    215 {
    216   free (ib);
    217 }
    218 
    219 
    220 MHD_INTERNAL
    221 MHD_FN_PAR_INOUT_ (1) void
    222 mhd_h2_items_block_reset (struct mhd_H2ReqItemsBlock *restrict ib)
    223 {
    224   mhd_assert (ib->start_free <= ib->buf_size);
    225   mhd_assert (! ib->buff_locked);
    226 
    227   ib->num_items = 0u;
    228   ib->start_free = 0u;
    229 
    230 #ifndef NDEBUG
    231   ib->stream_id = 0u;
    232 #endif /* ! NDEBUG */
    233 }
    234 
    235 
    236 MHD_INTERNAL
    237 MHD_FN_PAR_INOUT_ (1) MHD_FN_PAR_OUT_ (2)
    238 MHD_FN_PAR_NONNULL_ALL_ bool
    239 mhd_h2_items_get_buff_new_item (struct mhd_H2ReqItemsBlock *restrict ib,
    240                                 struct mhd_Buffer *restrict buff)
    241 {
    242   const size_t free_space = h2_ib_get_buff_free_size (ib);
    243 
    244   mhd_assert (! ib->buff_locked);
    245 
    246   if (mhd_rii_size + 2u > free_space) /* 2 for two zero-terminations */
    247     return false;
    248 
    249 #ifndef NDEBUG
    250   ib->buff_locked = true;
    251 #endif /* ! NDEBUG */
    252 
    253   buff->data = h2_ib_get_buff_free_ptr (ib);
    254   buff->size = free_space - mhd_rii_size;
    255 
    256   return true;
    257 }
    258 
    259 
    260 MHD_INTERNAL
    261 MHD_FN_PAR_INOUT_ (1) MHD_FN_PAR_NONNULL_ALL_ bool
    262 mhd_h2_items_reserve_new_item (struct mhd_H2ReqItemsBlock *restrict ib)
    263 {
    264   const size_t free_space = h2_ib_get_buff_free_size (ib);
    265 
    266   mhd_assert (! ib->buff_locked);
    267 
    268   if (mhd_rii_size + 2u > free_space) /* 2 for two zero-terminations */
    269     return false;
    270 
    271 #ifndef NDEBUG
    272   ib->buff_locked = true;
    273 #endif /* ! NDEBUG */
    274 
    275   return true;
    276 }
    277 
    278 
    279 MHD_INTERNAL
    280 MHD_FN_PAR_INOUT_ (1) MHD_FN_PAR_NONNULL_ALL_ void
    281 mhd_h2_items_add_new_item_buff (struct mhd_H2ReqItemsBlock *restrict ib,
    282                                 size_t name_len,
    283                                 size_t val_len,
    284                                 enum mhd_H2RequestItemKind kind)
    285 {
    286   struct mhd_H2ReqItem *const itm = h2_ib_get_n_item (ib, ib->num_items);
    287 
    288   mhd_assert (ib->buff_locked);
    289   mhd_assert (h2_ib_get_buff_free_size (ib) >= \
    290               name_len + val_len + 2u + mhd_rii_size);
    291   mhd_assert (0 == h2_ib_get_buff_free_ptr (ib)[name_len]);
    292   mhd_assert (0 == h2_ib_get_buff_free_ptr (ib)[name_len + 1 + val_len]);
    293 
    294   itm->kind = kind;
    295   itm->offset = ib->start_free;
    296   itm->name_len = (uint_least32_t) name_len;
    297   itm->val_len = (uint_least32_t) val_len;
    298 
    299   ib->start_free += (uint_least32_t) (name_len + val_len + 2u);
    300   ++ib->num_items;
    301 
    302 #ifndef NDEBUG
    303   ib->buff_locked = false;
    304 #endif /* ! NDEBUG */
    305 
    306   mhd_assert (ib->buf_size >= (ib->start_free
    307                                + ib->num_items * sizeof(struct mhd_H2ReqItem)));
    308 }
    309 
    310 
    311 MHD_INTERNAL
    312 MHD_FN_PAR_INOUT_ (1) MHD_FN_PAR_NONNULL_ALL_ void
    313 mhd_h2_items_add_new_item_reserved (struct mhd_H2ReqItemsBlock *restrict ib,
    314                                     size_t name_start,
    315                                     size_t name_len,
    316                                     size_t val_len,
    317                                     enum mhd_H2RequestItemKind kind)
    318 {
    319   struct mhd_H2ReqItem *const itm = h2_ib_get_n_item (ib, ib->num_items);
    320 
    321   mhd_assert (ib->buff_locked);
    322   mhd_assert (h2_ib_get_buff_free_size (ib) >= mhd_rii_size);
    323   mhd_assert (0 == h2_ib_get_buffc (ib)[name_start + name_len]);
    324   mhd_assert ((mhd_H2_RIK_URI_PARAM_NV == kind) ||
    325               (0 == h2_ib_get_buffc (ib)[name_start + name_len + 1 + val_len]));
    326   mhd_assert (name_start < ib->start_free);
    327   mhd_assert (name_len + val_len + 2u <= ib->start_free);
    328 
    329   itm->kind = kind;
    330   itm->offset = (uint_least32_t) name_start;
    331   itm->name_len = (uint_least32_t) name_len;
    332   itm->val_len = (uint_least32_t) val_len;
    333 
    334   ++ib->num_items;
    335 
    336 #ifndef NDEBUG
    337   ib->buff_locked = false;
    338 #endif /* ! NDEBUG */
    339 
    340   mhd_assert (ib->buf_size >= (ib->start_free
    341                                + ib->num_items * sizeof(struct mhd_H2ReqItem)));
    342 }
    343 
    344 
    345 #ifndef NDEBUG
    346 MHD_INTERNAL
    347 MHD_FN_PAR_INOUT_ (1) MHD_FN_PAR_NONNULL_ALL_ void
    348 mhd_h2_items_cancel_new_item_buff (struct mhd_H2ReqItemsBlock *restrict ib)
    349 {
    350   mhd_assert (ib->buff_locked);
    351   ib->buff_locked = false;
    352 }
    353 
    354 
    355 #endif /* ! NDEBUG */
    356 
    357 
    358 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ MHD_FN_RETURNS_NONNULL_
    359 MHD_FN_PURE_ char *
    360 mhd_h2_items_get_strings_buff (struct mhd_H2ReqItemsBlock *restrict ib)
    361 {
    362   return h2_ib_get_buff (ib);
    363 }
    364 
    365 
    366 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ MHD_FN_RETURNS_NONNULL_
    367 MHD_FN_PURE_ const char *
    368 mhd_h2_items_get_strings_buffc (const struct mhd_H2ReqItemsBlock *restrict ib)
    369 {
    370   return h2_ib_get_buffc (ib);
    371 }
    372 
    373 
    374 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PURE_ struct mhd_H2ReqItem *
    375 mhd_h2_items_get_item_n (struct mhd_H2ReqItemsBlock *restrict ib,
    376                          size_t pos)
    377 {
    378   if (ib->num_items <= pos)
    379     return NULL;
    380   return h2_ib_get_n_item (ib,
    381                            pos);
    382 }
    383 
    384 
    385 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PURE_ const struct mhd_H2ReqItem *
    386 mhd_h2_items_get_item_nc (const struct mhd_H2ReqItemsBlock *restrict ib,
    387                           size_t pos)
    388 {
    389   if (ib->num_items <= pos)
    390     return NULL;
    391   return h2_ib_get_n_itemc (ib,
    392                             pos);
    393 }
    394 
    395 
    396 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
    397 MHD_FN_PAR_OUT_ (3) MHD_FN_PURE_ bool
    398 mhd_h2_items_get_item_name (struct mhd_H2ReqItemsBlock *restrict ib,
    399                             size_t pos,
    400                             struct MHD_String *restrict name)
    401 {
    402   const struct mhd_H2ReqItem *const itm = h2_ib_get_n_itemc (ib,
    403                                                              pos);
    404   if (NULL == itm)
    405     return false;
    406 
    407   name->cstr = h2_ib_get_buffc (ib) + itm->offset;
    408   name->len = itm->name_len;
    409   mhd_assert (0 == name->cstr[name->len]);
    410 
    411   return true;
    412 }
    413 
    414 
    415 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
    416 MHD_FN_PAR_OUT_ (3) MHD_FN_PURE_ bool
    417 mhd_h2_items_get_item_value (struct mhd_H2ReqItemsBlock *restrict ib,
    418                              size_t pos,
    419                              struct MHD_String *restrict value)
    420 {
    421   const struct mhd_H2ReqItem *const itm = h2_ib_get_n_itemc (ib,
    422                                                              pos);
    423   if (NULL == itm)
    424     return false;
    425 
    426   value->cstr = h2_ib_get_buffc (ib) + itm->offset + itm->name_len + 1u;
    427   value->len = itm->val_len;
    428   mhd_assert (0 == value->cstr[value->len]);
    429 
    430   return true;
    431 }
    432 
    433 
    434 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
    435 MHD_FN_PAR_OUT_ (3) MHD_FN_PURE_ bool
    436 mhd_h2_items_get_item_kind (struct mhd_H2ReqItemsBlock *restrict ib,
    437                             size_t pos,
    438                             enum mhd_H2RequestItemKind *restrict kind)
    439 {
    440   const struct mhd_H2ReqItem *const itm = h2_ib_get_n_itemc (ib,
    441                                                              pos);
    442   if (NULL == itm)
    443     return false;
    444 
    445   *kind = itm->kind;
    446   mhd_assert (0u != (unsigned int) *kind);
    447 
    448   return true;
    449 
    450 }
    451 
    452 
    453 MHD_INTERNAL MHD_FN_PURE_ MHD_FN_PAR_NONNULL_ALL_
    454 MHD_FN_PAR_OUT_ (3) MHD_FN_PAR_OUT_ (4) MHD_FN_PAR_OUT_ (5) bool
    455 mhd_h2_items_get_item_full (struct mhd_H2ReqItemsBlock *restrict ib,
    456                             size_t pos,
    457                             struct MHD_String *restrict name,
    458                             struct MHD_String *restrict value,
    459                             enum mhd_H2RequestItemKind *restrict kind)
    460 {
    461   const struct mhd_H2ReqItem *const itm = h2_ib_get_n_itemc (ib,
    462                                                              pos);
    463   const char *const buff = h2_ib_get_buffc (ib);
    464 
    465   if (NULL == itm)
    466     return false;
    467 
    468   name->cstr = buff + itm->offset;
    469   name->len = itm->name_len;
    470   value->cstr = buff + itm->offset + itm->name_len + 1u;
    471   value->len = itm->val_len;
    472   *kind = itm->kind;
    473 
    474   mhd_assert (0 == name->cstr[name->len]);
    475   mhd_assert (0 == value->cstr[value->len]);
    476   mhd_assert (0u != (unsigned int) *kind);
    477 
    478   return true;
    479 }
    480 
    481 
    482 #ifndef NDEBUG
    483 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ void
    484 mhd_h2_items_debug_set_streamid (struct mhd_H2ReqItemsBlock *restrict ib,
    485                                  uint_least32_t stream_id)
    486 {
    487   ib->stream_id = stream_id;
    488 }
    489 
    490 
    491 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ uint_least32_t
    492 mhd_h2_items_debug_get_streamid (struct mhd_H2ReqItemsBlock *restrict ib)
    493 {
    494   return ib->stream_id;
    495 }
    496 
    497 
    498 #endif /* ! NDEBUG */