libmicrohttpd2

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

h2_req_items_funcs.c (14089B)


      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 ==
    326                   h2_ib_get_buffc (ib)[name_start + name_len + 1 + val_len]));
    327   mhd_assert (name_start < ib->start_free);
    328   mhd_assert (name_len + val_len + 2u <= ib->start_free);
    329 
    330   itm->kind = kind;
    331   itm->offset = (uint_least32_t)name_start;
    332   itm->name_len = (uint_least32_t)name_len;
    333   itm->val_len = (uint_least32_t)val_len;
    334 
    335   ++ib->num_items;
    336 
    337 #ifndef NDEBUG
    338   ib->buff_locked = false;
    339 #endif /* ! NDEBUG */
    340 
    341   mhd_assert (ib->buf_size >= (ib->start_free
    342                                + ib->num_items * sizeof(struct mhd_H2ReqItem)));
    343 }
    344 
    345 
    346 #ifndef NDEBUG
    347 MHD_INTERNAL
    348 MHD_FN_PAR_INOUT_ (1) MHD_FN_PAR_NONNULL_ALL_ void
    349 mhd_h2_items_cancel_new_item_buff (struct mhd_H2ReqItemsBlock *restrict ib)
    350 {
    351   mhd_assert (ib->buff_locked);
    352   ib->buff_locked = false;
    353 }
    354 
    355 
    356 #endif /* ! NDEBUG */
    357 
    358 
    359 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ MHD_FN_RETURNS_NONNULL_
    360 MHD_FN_PURE_ char *
    361 mhd_h2_items_get_strings_buff (struct mhd_H2ReqItemsBlock *restrict ib)
    362 {
    363   return h2_ib_get_buff (ib);
    364 }
    365 
    366 
    367 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ MHD_FN_RETURNS_NONNULL_
    368 MHD_FN_PURE_ const char *
    369 mhd_h2_items_get_strings_buffc (const struct mhd_H2ReqItemsBlock *restrict ib)
    370 {
    371   return h2_ib_get_buffc (ib);
    372 }
    373 
    374 
    375 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PURE_ struct mhd_H2ReqItem *
    376 mhd_h2_items_get_item_n (struct mhd_H2ReqItemsBlock *restrict ib,
    377                          size_t pos)
    378 {
    379   if (ib->num_items <= pos)
    380     return NULL;
    381   return h2_ib_get_n_item (ib,
    382                            pos);
    383 }
    384 
    385 
    386 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PURE_ const struct mhd_H2ReqItem *
    387 mhd_h2_items_get_item_nc (const struct mhd_H2ReqItemsBlock *restrict ib,
    388                           size_t pos)
    389 {
    390   if (ib->num_items <= pos)
    391     return NULL;
    392   return h2_ib_get_n_itemc (ib,
    393                             pos);
    394 }
    395 
    396 
    397 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
    398 MHD_FN_PAR_OUT_ (3) MHD_FN_PURE_ bool
    399 mhd_h2_items_get_item_name (struct mhd_H2ReqItemsBlock *restrict ib,
    400                             size_t pos,
    401                             struct MHD_String *restrict name)
    402 {
    403   const struct mhd_H2ReqItem *const itm = h2_ib_get_n_itemc (ib,
    404                                                              pos);
    405   if (NULL == itm)
    406     return false;
    407 
    408   name->cstr = h2_ib_get_buffc (ib) + itm->offset;
    409   name->len = itm->name_len;
    410   mhd_assert (0 == name->cstr[name->len]);
    411 
    412   return true;
    413 }
    414 
    415 
    416 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
    417 MHD_FN_PAR_OUT_ (3) MHD_FN_PURE_ bool
    418 mhd_h2_items_get_item_value (struct mhd_H2ReqItemsBlock *restrict ib,
    419                              size_t pos,
    420                              struct MHD_String *restrict value)
    421 {
    422   const struct mhd_H2ReqItem *const itm = h2_ib_get_n_itemc (ib,
    423                                                              pos);
    424   if (NULL == itm)
    425     return false;
    426 
    427   value->cstr = h2_ib_get_buffc (ib) + itm->offset + itm->name_len + 1u;
    428   value->len = itm->val_len;
    429   mhd_assert (0 == value->cstr[value->len]);
    430 
    431   return true;
    432 }
    433 
    434 
    435 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
    436 MHD_FN_PAR_OUT_ (3) MHD_FN_PURE_ bool
    437 mhd_h2_items_get_item_kind (struct mhd_H2ReqItemsBlock *restrict ib,
    438                             size_t pos,
    439                             enum mhd_H2RequestItemKind *restrict kind)
    440 {
    441   const struct mhd_H2ReqItem *const itm = h2_ib_get_n_itemc (ib,
    442                                                              pos);
    443   if (NULL == itm)
    444     return false;
    445 
    446   *kind = itm->kind;
    447   mhd_assert (0u != (unsigned int)*kind);
    448 
    449   return true;
    450 
    451 }
    452 
    453 
    454 MHD_INTERNAL MHD_FN_PURE_ MHD_FN_PAR_NONNULL_ALL_
    455 MHD_FN_PAR_OUT_ (3) MHD_FN_PAR_OUT_ (4) MHD_FN_PAR_OUT_ (5) bool
    456 mhd_h2_items_get_item_full (struct mhd_H2ReqItemsBlock *restrict ib,
    457                             size_t pos,
    458                             struct MHD_String *restrict name,
    459                             struct MHD_String *restrict value,
    460                             enum mhd_H2RequestItemKind *restrict kind)
    461 {
    462   const struct mhd_H2ReqItem *const itm = h2_ib_get_n_itemc (ib,
    463                                                              pos);
    464   const char *const buff = h2_ib_get_buffc (ib);
    465 
    466   if (NULL == itm)
    467     return false;
    468 
    469   name->cstr = buff + itm->offset;
    470   name->len = itm->name_len;
    471   value->cstr = buff + itm->offset + itm->name_len + 1u;
    472   value->len = itm->val_len;
    473   *kind = itm->kind;
    474 
    475   mhd_assert (0 == name->cstr[name->len]);
    476   mhd_assert (0 == value->cstr[value->len]);
    477   mhd_assert (0u != (unsigned int)*kind);
    478 
    479   return true;
    480 }
    481 
    482 
    483 #ifndef NDEBUG
    484 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ void
    485 mhd_h2_items_debug_set_streamid (struct mhd_H2ReqItemsBlock *restrict ib,
    486                                  uint_least32_t stream_id)
    487 {
    488   ib->stream_id = stream_id;
    489 }
    490 
    491 
    492 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ uint_least32_t
    493 mhd_h2_items_debug_get_streamid (struct mhd_H2ReqItemsBlock *restrict ib)
    494 {
    495   return ib->stream_id;
    496 }
    497 
    498 
    499 #endif /* ! NDEBUG */