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 */