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