libmicrohttpd2

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

h2_req_items_funcs.c (14589B)


      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 #include "mhd_assume.h"
     53 
     54 #include "mhd_assert.h"
     55 
     56 #include "sys_malloc.h"
     57 
     58 #include "mhd_buffer.h"
     59 #include "mhd_str_types.h"
     60 
     61 #include "h2_req_item_struct.h"
     62 
     63 #include "h2_req_items_funcs.h"
     64 
     65 
     66 struct mhd_H2ReqItemsBlock
     67 {
     68   /**
     69    * Number of items in the items block
     70    */
     71   size_t num_items;
     72 
     73   /**
     74    * The size of the items buffer, in bytes
     75    */
     76   size_t buf_size;
     77 
     78   /**
     79    * The starting offset of the free buffer space
     80    */
     81   uint_least32_t start_free;
     82 
     83 #ifndef NDEBUG
     84   uint_least32_t stream_id;
     85   bool inited;
     86   bool buff_locked;
     87 #endif /* ! NDEBUG */
     88 };
     89 
     90 mhd_constexpr size_t mhd_rii_size = sizeof (struct mhd_H2ReqItem);
     91 
     92 mhd_static_inline char *
     93 h2_ib_get_buff (struct mhd_H2ReqItemsBlock *ib)
     94 {
     95   mhd_assert (ib->inited);
     96   mhd_assert (ib->start_free <= ib->buf_size);
     97   return (char *)(ib + 1u);
     98 }
     99 
    100 
    101 mhd_static_inline const char *
    102 h2_ib_get_buffc (const struct mhd_H2ReqItemsBlock *ib)
    103 {
    104   mhd_assert (ib->inited);
    105   mhd_assert (ib->start_free <= ib->buf_size);
    106   return (const char *)(ib + 1u);
    107 }
    108 
    109 
    110 mhd_static_inline struct mhd_H2ReqItem *
    111 h2_ib_get_zero_item (struct mhd_H2ReqItemsBlock *ib)
    112 {
    113   return ((struct mhd_H2ReqItem *)
    114           (void *)(h2_ib_get_buff (ib) + ib->buf_size))
    115          - 1u;
    116 }
    117 
    118 
    119 mhd_static_inline const struct mhd_H2ReqItem *
    120 h2_ib_get_zero_itemc (const struct mhd_H2ReqItemsBlock *ib)
    121 {
    122   return ((const struct mhd_H2ReqItem *)
    123           (const void *)(h2_ib_get_buffc (ib) + ib->buf_size))
    124          - 1u;
    125 }
    126 
    127 
    128 /* 'pos' is zero-based */
    129 mhd_static_inline struct mhd_H2ReqItem *
    130 h2_ib_get_n_item (struct mhd_H2ReqItemsBlock *ib,
    131                   size_t pos)
    132 {
    133   struct mhd_H2ReqItem *const ret = h2_ib_get_zero_item (ib) - pos;
    134   mhd_assert (ib->buf_size >= (ib->start_free
    135                                + ib->num_items * mhd_rii_size));
    136   return ret;
    137 }
    138 
    139 
    140 /* 'pos' is zero-based */
    141 mhd_static_inline const struct mhd_H2ReqItem *
    142 h2_ib_get_n_itemc (const struct mhd_H2ReqItemsBlock *ib,
    143                    size_t pos)
    144 {
    145   const struct mhd_H2ReqItem *const ret = h2_ib_get_zero_itemc (ib) - pos;
    146   mhd_assert (ib->buf_size >= (ib->start_free
    147                                + ib->num_items * mhd_rii_size));
    148   return ret;
    149 }
    150 
    151 
    152 mhd_static_inline size_t
    153 h2_ib_get_buff_free_size (const struct mhd_H2ReqItemsBlock *ib)
    154 {
    155   mhd_assert (ib->inited);
    156   mhd_assert (ib->buf_size >= (ib->start_free
    157                                + ib->num_items * sizeof(struct mhd_H2ReqItem)));
    158   return ib->buf_size - ib->start_free - (ib->num_items * mhd_rii_size);
    159 }
    160 
    161 
    162 mhd_static_inline char *
    163 h2_ib_get_buff_free_ptr (struct mhd_H2ReqItemsBlock *ib)
    164 {
    165   return h2_ib_get_buff (ib) + ib->start_free;
    166 }
    167 
    168 
    169 MHD_INTERNAL mhd_FN_RET_UNALIASED
    170 mhd_FN_OBJ_CONSTRUCTOR (mhd_h2_items_block_destroy)
    171 struct mhd_H2ReqItemsBlock *
    172 mhd_h2_items_block_create (size_t buffer_size)
    173 {
    174   struct mhd_H2ReqItemsBlock *ret;
    175   uint_fast32_t buf_size_u32;
    176   uint_fast32_t buf_alloc_size;
    177   size_t malloc_size;
    178 
    179   if (mhd_COND_HARDLY_EVER ((0xFFFFFFFFu
    180                              - 2u * mhd_ALIGNOF (struct mhd_H2ReqItem))
    181                             < buffer_size))
    182     return NULL;
    183 
    184   buf_size_u32 = (uint_fast32_t)(buffer_size & 0xFFFFFFFFu);
    185   mhd_ASSUME (buffer_size == buf_size_u32);
    186 
    187   /* Round up to alignment */
    188   buf_alloc_size =
    189     buf_size_u32
    190     + (uint_fast32_t)
    191     ((mhd_ALIGNOF (struct mhd_H2ReqItem)
    192       - (buf_size_u32 % mhd_ALIGNOF (struct mhd_H2ReqItem)))
    193      % mhd_ALIGNOF (struct mhd_H2ReqItem));
    194 
    195   /* Adjust the allocation size in case if alignment of mhd_H2ReqItem is
    196      stricter than alignment of mhd_H2ReqItemsBlock */
    197   buf_alloc_size +=
    198     (uint_fast32_t)
    199     ((mhd_ALIGNOF (struct mhd_H2ReqItem)
    200       - (sizeof(*ret) % mhd_ALIGNOF (struct mhd_H2ReqItem)))
    201      % mhd_ALIGNOF (struct mhd_H2ReqItem));
    202 
    203   mhd_assert (buffer_size <= buf_alloc_size);
    204 
    205   malloc_size = sizeof (*ret) + (size_t)buf_alloc_size;
    206   if (mhd_COND_HARDLY_EVER (buf_alloc_size > malloc_size))
    207     return NULL; /* Overflow or truncation on a less-than-64-bit platform */
    208 
    209   mhd_assert (buffer_size < malloc_size);
    210 
    211   ret = (struct mhd_H2ReqItemsBlock *)malloc (malloc_size);
    212 
    213   if (NULL == ret)
    214     return NULL; /* Failure exit point */
    215 
    216   ret->buf_size = (size_t)buf_alloc_size;
    217 #ifndef NDEBUG
    218   ret->inited = false;
    219   ret->buff_locked = false;
    220 #endif /* ! NDEBUG */
    221   mhd_h2_items_block_reset (ret);
    222 
    223   return ret;
    224 }
    225 
    226 
    227 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ void
    228 mhd_h2_items_block_destroy (struct mhd_H2ReqItemsBlock *ib)
    229 {
    230   mhd_assert (ib->inited);
    231 #ifndef NDEBUG
    232   ib->inited = false;
    233 #endif /* ! NDEBUG */
    234   free (ib);
    235 }
    236 
    237 
    238 MHD_INTERNAL
    239 MHD_FN_PAR_INOUT_ (1) void
    240 mhd_h2_items_block_reset (struct mhd_H2ReqItemsBlock *restrict ib)
    241 {
    242   mhd_assert ((!ib->inited) || (ib->start_free <= ib->buf_size));
    243   mhd_assert (!ib->buff_locked);
    244 
    245   ib->num_items = 0u;
    246   ib->start_free = 0u;
    247 
    248 #ifndef NDEBUG
    249   ib->inited = true;
    250   ib->stream_id = 0u;
    251 #endif /* ! NDEBUG */
    252 }
    253 
    254 
    255 MHD_INTERNAL
    256 MHD_FN_PAR_INOUT_ (1) MHD_FN_PAR_OUT_ (2)
    257 MHD_FN_PAR_NONNULL_ALL_ bool
    258 mhd_h2_items_get_buff_new_item (struct mhd_H2ReqItemsBlock *restrict ib,
    259                                 struct mhd_Buffer *restrict buff)
    260 {
    261   const size_t free_space = h2_ib_get_buff_free_size (ib);
    262 
    263   mhd_assert (!ib->buff_locked);
    264 
    265   if (mhd_rii_size + 2u > free_space) /* 2 for two zero-terminations */
    266     return false;
    267 
    268 #ifndef NDEBUG
    269   ib->buff_locked = true;
    270 #endif /* ! NDEBUG */
    271 
    272   buff->data = h2_ib_get_buff_free_ptr (ib);
    273   buff->size = free_space - mhd_rii_size;
    274 
    275   return true;
    276 }
    277 
    278 
    279 MHD_INTERNAL
    280 MHD_FN_PAR_INOUT_ (1) MHD_FN_PAR_NONNULL_ALL_ bool
    281 mhd_h2_items_reserve_new_item (struct mhd_H2ReqItemsBlock *restrict ib)
    282 {
    283   const size_t free_space = h2_ib_get_buff_free_size (ib);
    284 
    285   mhd_assert (!ib->buff_locked);
    286 
    287   if (mhd_rii_size + 2u > free_space) /* 2 for two zero-terminations */
    288     return false;
    289 
    290 #ifndef NDEBUG
    291   ib->buff_locked = true;
    292 #endif /* ! NDEBUG */
    293 
    294   return true;
    295 }
    296 
    297 
    298 MHD_INTERNAL
    299 MHD_FN_PAR_INOUT_ (1) MHD_FN_PAR_NONNULL_ALL_ void
    300 mhd_h2_items_add_new_item_buff (struct mhd_H2ReqItemsBlock *restrict ib,
    301                                 size_t name_len,
    302                                 size_t val_len,
    303                                 enum mhd_H2RequestItemKind kind)
    304 {
    305   struct mhd_H2ReqItem *const itm = h2_ib_get_n_item (ib, ib->num_items);
    306 
    307   mhd_assert (ib->buff_locked);
    308   mhd_assert (h2_ib_get_buff_free_size (ib) >= \
    309               name_len + val_len + 2u + mhd_rii_size);
    310   mhd_assert (0 == h2_ib_get_buff_free_ptr (ib)[name_len]);
    311   mhd_assert (0 == h2_ib_get_buff_free_ptr (ib)[name_len + 1 + val_len]);
    312 
    313   itm->kind = kind;
    314   itm->offset = ib->start_free;
    315   itm->name_len = (uint_least32_t)name_len;
    316   itm->val_len = (uint_least32_t)val_len;
    317 
    318   ib->start_free += (uint_least32_t)(name_len + val_len + 2u);
    319   ++ib->num_items;
    320 
    321 #ifndef NDEBUG
    322   ib->buff_locked = false;
    323 #endif /* ! NDEBUG */
    324 
    325   mhd_assert (ib->buf_size >= (ib->start_free
    326                                + ib->num_items * sizeof(struct mhd_H2ReqItem)));
    327 }
    328 
    329 
    330 MHD_INTERNAL
    331 MHD_FN_PAR_INOUT_ (1) MHD_FN_PAR_NONNULL_ALL_ void
    332 mhd_h2_items_add_new_item_reserved (struct mhd_H2ReqItemsBlock *restrict ib,
    333                                     size_t name_start,
    334                                     size_t name_len,
    335                                     size_t val_len,
    336                                     enum mhd_H2RequestItemKind kind)
    337 {
    338   struct mhd_H2ReqItem *const itm = h2_ib_get_n_item (ib, ib->num_items);
    339 
    340   mhd_assert (ib->buff_locked);
    341   mhd_assert (h2_ib_get_buff_free_size (ib) >= mhd_rii_size);
    342   mhd_assert (0 == h2_ib_get_buffc (ib)[name_start + name_len]);
    343   mhd_assert ((mhd_H2_RIK_URI_PARAM_NV == kind)
    344               || (0 ==
    345                   h2_ib_get_buffc (ib)[name_start + name_len + 1 + val_len]));
    346   mhd_assert (name_start < ib->start_free);
    347   mhd_assert (name_len + val_len + 2u <= ib->start_free);
    348 
    349   itm->kind = kind;
    350   itm->offset = (uint_least32_t)name_start;
    351   itm->name_len = (uint_least32_t)name_len;
    352   itm->val_len = (uint_least32_t)val_len;
    353 
    354   ++ib->num_items;
    355 
    356 #ifndef NDEBUG
    357   ib->buff_locked = false;
    358 #endif /* ! NDEBUG */
    359 
    360   mhd_assert (ib->buf_size >= (ib->start_free
    361                                + ib->num_items * sizeof(struct mhd_H2ReqItem)));
    362 }
    363 
    364 
    365 #ifndef NDEBUG
    366 MHD_INTERNAL
    367 MHD_FN_PAR_INOUT_ (1) MHD_FN_PAR_NONNULL_ALL_ void
    368 mhd_h2_items_cancel_new_item_buff (struct mhd_H2ReqItemsBlock *restrict ib)
    369 {
    370   mhd_assert (ib->inited);
    371   mhd_assert (ib->buff_locked);
    372   ib->buff_locked = false;
    373 }
    374 
    375 
    376 #endif /* ! NDEBUG */
    377 
    378 
    379 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ MHD_FN_RETURNS_NONNULL_
    380 MHD_FN_PURE_ char *
    381 mhd_h2_items_get_strings_buff (struct mhd_H2ReqItemsBlock *restrict ib)
    382 {
    383   return h2_ib_get_buff (ib);
    384 }
    385 
    386 
    387 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ MHD_FN_RETURNS_NONNULL_
    388 MHD_FN_PURE_ const char *
    389 mhd_h2_items_get_strings_buffc (const struct mhd_H2ReqItemsBlock *restrict ib)
    390 {
    391   return h2_ib_get_buffc (ib);
    392 }
    393 
    394 
    395 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PURE_ struct mhd_H2ReqItem *
    396 mhd_h2_items_get_item_n (struct mhd_H2ReqItemsBlock *restrict ib,
    397                          size_t pos)
    398 {
    399   mhd_assert (ib->inited);
    400   if (ib->num_items <= pos)
    401     return NULL;
    402   return h2_ib_get_n_item (ib,
    403                            pos);
    404 }
    405 
    406 
    407 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PURE_ const struct mhd_H2ReqItem *
    408 mhd_h2_items_get_item_nc (const struct mhd_H2ReqItemsBlock *restrict ib,
    409                           size_t pos)
    410 {
    411   mhd_assert (ib->inited);
    412   if (ib->num_items <= pos)
    413     return NULL;
    414   return h2_ib_get_n_itemc (ib,
    415                             pos);
    416 }
    417 
    418 
    419 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
    420 MHD_FN_PAR_OUT_ (3) bool
    421 mhd_h2_items_get_item_name (struct mhd_H2ReqItemsBlock *restrict ib,
    422                             size_t pos,
    423                             struct MHD_String *restrict name)
    424 {
    425   const struct mhd_H2ReqItem *const itm = h2_ib_get_n_itemc (ib,
    426                                                              pos);
    427   if (NULL == itm)
    428     return false;
    429 
    430   name->cstr = h2_ib_get_buffc (ib) + itm->offset;
    431   name->len = itm->name_len;
    432   mhd_assert (0 == name->cstr[name->len]);
    433 
    434   return true;
    435 }
    436 
    437 
    438 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
    439 MHD_FN_PAR_OUT_ (3) bool
    440 mhd_h2_items_get_item_value (struct mhd_H2ReqItemsBlock *restrict ib,
    441                              size_t pos,
    442                              struct MHD_String *restrict value)
    443 {
    444   const struct mhd_H2ReqItem *const itm = h2_ib_get_n_itemc (ib,
    445                                                              pos);
    446   if (NULL == itm)
    447     return false;
    448 
    449   value->cstr = h2_ib_get_buffc (ib) + itm->offset + itm->name_len + 1u;
    450   value->len = itm->val_len;
    451   mhd_assert (0 == value->cstr[value->len]);
    452 
    453   return true;
    454 }
    455 
    456 
    457 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
    458 MHD_FN_PAR_OUT_ (3) bool
    459 mhd_h2_items_get_item_kind (struct mhd_H2ReqItemsBlock *restrict ib,
    460                             size_t pos,
    461                             enum mhd_H2RequestItemKind *restrict kind)
    462 {
    463   const struct mhd_H2ReqItem *const itm = h2_ib_get_n_itemc (ib,
    464                                                              pos);
    465   if (NULL == itm)
    466     return false;
    467 
    468   *kind = itm->kind;
    469   mhd_assert (0u != (unsigned int)*kind);
    470 
    471   return true;
    472 
    473 }
    474 
    475 
    476 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
    477 MHD_FN_PAR_OUT_ (3) MHD_FN_PAR_OUT_ (4) MHD_FN_PAR_OUT_ (5) bool
    478 mhd_h2_items_get_item_full (struct mhd_H2ReqItemsBlock *restrict ib,
    479                             size_t pos,
    480                             struct MHD_String *restrict name,
    481                             struct MHD_String *restrict value,
    482                             enum mhd_H2RequestItemKind *restrict kind)
    483 {
    484   const struct mhd_H2ReqItem *const itm = h2_ib_get_n_itemc (ib,
    485                                                              pos);
    486   const char *const buff = h2_ib_get_buffc (ib);
    487 
    488   if (NULL == itm)
    489     return false;
    490 
    491   name->cstr = buff + itm->offset;
    492   name->len = itm->name_len;
    493   value->cstr = buff + itm->offset + itm->name_len + 1u;
    494   value->len = itm->val_len;
    495   *kind = itm->kind;
    496 
    497   mhd_assert (0 == name->cstr[name->len]);
    498   mhd_assert (0 == value->cstr[value->len]);
    499   mhd_assert (0u != (unsigned int)*kind);
    500 
    501   return true;
    502 }
    503 
    504 
    505 #ifndef NDEBUG
    506 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ void
    507 mhd_h2_items_debug_set_streamid (struct mhd_H2ReqItemsBlock *restrict ib,
    508                                  uint_least32_t stream_id)
    509 {
    510   mhd_assert (ib->inited);
    511   ib->stream_id = stream_id;
    512 }
    513 
    514 
    515 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ uint_least32_t
    516 mhd_h2_items_debug_get_streamid (struct mhd_H2ReqItemsBlock *restrict ib)
    517 {
    518   mhd_assert (ib->inited);
    519   return ib->stream_id;
    520 }
    521 
    522 
    523 #endif /* ! NDEBUG */