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