mhd_hpack_codec.h (21409B)
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/hpack/mhd_hpack_codec.h 41 * @brief The declarations for HPACK header compression codec functions 42 * @author Karlson2k (Evgeny Grin) 43 * 44 * The sizes of all strings are intentionally limited to 32 bits (4GiB). 45 */ 46 47 #ifndef MHD_HPACK_CODEC_H 48 #define MHD_HPACK_CODEC_H 1 49 50 #include "mhd_sys_options.h" 51 52 #include "sys_bool_type.h" 53 #include "sys_base_types.h" 54 55 #include "mhd_buffer.h" 56 57 #ifndef mhd_HPACK_DTBL_BITS 58 # if ((SIZEOF_SIZE_T + 0) >= 4) && ((SIZEOF_VOIDP + 0) >= 4) 59 # define mhd_HPACK_DTBL_BITS 32 60 # else 61 # define mhd_HPACK_DTBL_BITS 16 62 # endif 63 #else /* mhd_HPACK_DTBL_BITS */ 64 # if (mhd_HPACK_DTBL_BITS != 16) && (mhd_HPACK_DTBL_BITS != 32) 65 #error Unsupported mhd_HPACK_DTBL_BITS value 66 # endif 67 #endif /* mhd_HPACK_DTBL_BITS */ 68 69 /** 70 * @def mhd_DTBL_MAX_SIZE 71 * The maximum possible size of the dynamic table 72 */ 73 #if mhd_HPACK_DTBL_BITS == 32 74 # define mhd_DTBL_MAX_SIZE (((size_t) 1u) * 1024u * 1024u) 75 #elif mhd_HPACK_DTBL_BITS == 16 76 # define mhd_DTBL_MAX_SIZE (((size_t) 60u) * 1024u) 77 #endif 78 79 struct mhd_HpackDecContext; /* forward declaration */ 80 81 /** 82 * Initialise HPACK decoder context and create the dynamic table. 83 * @param hk_dec the decoder context to initialise 84 * @return 'true' on success, 85 * 'false' on allocation error 86 */ 87 MHD_INTERNAL bool 88 mhd_hpack_dec_init (struct mhd_HpackDecContext *hk_dec) 89 MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_OUT_ (1); 90 91 /** 92 * Deinitialise HPACK decoder context and free the dynamic table if present. 93 * @param hk_dec the pointer to the decoder context 94 */ 95 MHD_INTERNAL void 96 mhd_hpack_dec_deinit (struct mhd_HpackDecContext *hk_dec) 97 MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_INOUT_ (1); 98 99 /** 100 * Set the maximum allowed dynamic table size for the decoder. 101 * Should be called when the remote peer has ACKed settings with an updated 102 * dynamic table size. 103 * @param hk_dec the decoder context 104 * @param new_allowed_dyn_size new limit in bytes, 105 * must be <= #mhd_DTBL_MAX_SIZE 106 */ 107 MHD_INTERNAL void 108 mhd_hpack_dec_set_allowed_dyn_size (struct mhd_HpackDecContext *hk_dec, 109 size_t new_allowed_dyn_size) 110 MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_INOUT_ (1); 111 112 /** 113 * Result codes of #mhd_hpack_dec_data() 114 */ 115 enum MHD_FIXED_ENUM_ mhd_HpackDecResult 116 { 117 /** 118 * Success, no new field decoded. 119 * Could be decoding of a Dynamic Table Size Update message. 120 */ 121 mhd_HPACK_DEC_RES_NO_NEW_FIELD = -1 122 , 123 /** 124 * Success, new field decoded. 125 */ 126 mhd_HPACK_DEC_RES_NEW_FIELD = 0 127 , 128 /** 129 * The encoded data is incomplete. More data needed. 130 */ 131 mhd_HPACK_DEC_RES_INCOMPLETE = 1 132 , 133 /** 134 * Memory allocation error when resizing the dynamic table. 135 */ 136 mhd_HPACK_DEC_RES_ALLOC_ERR 137 , 138 /** 139 * The output buffer is too small for the decoded field. 140 */ 141 mhd_HPACK_DEC_RES_BUFFER_TOO_SMALL 142 , 143 /** 144 * The length of the field strings is too long for this code (> 4GiB). 145 */ 146 mhd_HPACK_DEC_RES_STRING_TOO_LONG 147 , 148 /** 149 * The length of the number in the encoded form is too long. 150 * The encoded number used more bytes than needed to encode 64-bit nu 151 */ 152 mhd_HPACK_DEC_RES_NUMBER_TOO_LONG 153 , 154 /** 155 * Received a Dynamic Table Size Update message with a size larger than 156 * allowed. 157 */ 158 mhd_HPACK_DEC_RES_DYN_SIZE_UPD_TOO_LARGE 159 , 160 /** 161 * The remote peer did not send the expected Dynamic Table Size 162 * Update. 163 */ 164 mhd_HPACK_DEC_RES_DYN_SIZE_UPD_MISSING 165 , 166 /** 167 * Huffman decoding error 168 */ 169 mhd_HPACK_DEC_RES_HUFFMAN_ERR 170 , 171 /** 172 * Field (header) index specified in HPACK data does not exist. 173 */ 174 mhd_HPACK_DEC_RES_HPACK_BAD_IDX 175 , 176 /** 177 * Other HPACK decoding errors 178 */ 179 mhd_HPACK_DEC_RES_HPACK_ERR 180 , 181 /** 182 * Internal error. 183 * Should never happen. 184 */ 185 mhd_HPACK_DEC_RES_INTERNAL_ERR 186 }; 187 188 /** 189 * Check whether the @a dec_res is a kind of error code. 190 * @param dec_res result code returned by #mhd_hpack_dec_data() 191 * @return boolean 'true' if @a dec_res denotes an error; 192 * boolean 'false' otherwise 193 */ 194 #define mhd_HPACK_DEC_RES_IS_ERR(dec_res) \ 195 (mhd_HPACK_DEC_RES_NEW_FIELD < (dec_res)) 196 197 198 /** 199 * Decode a single HPACK representation (indexed, literal, or size 200 * update). 201 * For header fields, writes "name\0value\0" to @a out_buff. 202 * @param hk_dec the decoder context 203 * @param enc_data_size the size of @a enc_data, must not be zero 204 * @param enc_data the encoded data 205 * @param out_buff_size the size of @a out_buff, must be at least two bytes 206 * @param[out] out_buff the output buffer for the decoded strings 207 * @param[out] name_len to be set to the length of the name, not counting 208 * zero-terminating 209 * @param[out] val_len to be set to the length of the value, not counting 210 * zero-terminating 211 * @param[out] bytes_decoded to be set to the number of decoded bytes 212 * @return #mhd_HPACK_DEC_RES_NEW_FIELD if new field successfully 213 * decoded and placed into 214 * @a out_buff, 215 * #mhd_HPACK_DEC_RES_NO_NEW_FIELD if chunk of data 216 * successfully decoded, but 217 * no new field added, 218 * error code otherwise 219 */ 220 MHD_INTERNAL enum mhd_HpackDecResult 221 mhd_hpack_dec_data (struct mhd_HpackDecContext *restrict hk_dec, 222 const size_t enc_data_size, 223 const uint8_t *restrict enc_data, 224 size_t out_buff_size, 225 char *restrict out_buff, 226 size_t *restrict name_len, 227 size_t *restrict val_len, 228 size_t *restrict bytes_decoded) 229 MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_INOUT_(1) 230 MHD_FN_PAR_IN_SIZE_(3, 2) 231 MHD_FN_PAR_OUT_SIZE_(5, 4) 232 MHD_FN_PAR_OUT_(6) MHD_FN_PAR_OUT_(7) MHD_FN_PAR_OUT_ (8); 233 234 235 struct mhd_HpackEncContext; /* forward declaration */ 236 237 /** 238 * Initialise HPACK encoder context and create the dynamic table. 239 * @param hk_enc the encoder context to initialise 240 * @return 'true' on success, 241 * 'false' on allocation error 242 */ 243 MHD_INTERNAL bool 244 mhd_hpack_enc_init (struct mhd_HpackEncContext *hk_enc) 245 MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_OUT_ (1); 246 247 /** 248 * Deinitialise HPACK encoder context and free the dynamic table if 249 * present. 250 * @param hk_enc the encoder context 251 */ 252 MHD_INTERNAL void 253 mhd_hpack_enc_deinit (struct mhd_HpackEncContext *hk_enc) 254 MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_INOUT_ (1); 255 256 /** 257 * Set the current maximum dynamic table size for the encoder. 258 * 259 * To avoid repetitive memory allocations, the real table resize is performed 260 * later. 261 * 262 * @param hk_enc the encoder context 263 * @param new_dyn_size the new limit in bytes, 264 * must be <= #mhd_DTBL_MAX_SIZE and must be within 265 * the limits expected by the remote peer 266 */ 267 MHD_INTERNAL void 268 mhd_hpack_enc_set_dyn_size (struct mhd_HpackEncContext *hk_enc, 269 size_t new_dyn_size) 270 MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_INOUT_ (1); 271 272 /** 273 * Perform dynamic table resize if it is pending. 274 * 275 * If table is resized before encoding new fields, then encoding functions 276 * never return #mhd_HPACK_ENC_RES_ALLOC_ERR. 277 * 278 * @param hk_enc the encoder context 279 * @return 'true' on success, 280 * 'false' on allocation error 281 */ 282 MHD_INTERNAL bool 283 mhd_hpack_enc_dyn_resize (struct mhd_HpackEncContext *hk_enc) 284 MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_INOUT_ (1); 285 286 /** 287 * Preference for HPACK encoding 288 * 289 * The items are sorted, keep them in this order. 290 */ 291 enum MHD_FIXED_ENUM_ mhd_HpackEncPolicy 292 { 293 /** 294 * Force the field to be encoded literally and added to the dynamic 295 * table. If the field does not fit the dynamic table, the dynamic 296 * table is completely evicted without adding the new field. 297 * The name of the field can be encoded as a reference to the name 298 * in the static or dynamic table. 299 */ 300 mhd_HPACK_ENC_POL_FORCED_NEW_IDX 301 , 302 /** 303 * Encode the field literally; if the field fits the dynamic table, 304 * add it to the dynamic table as a new index even if the same field 305 * is already in the tables. If the field does not fit the dynamic 306 * table, it is encoded literally without adding it to the table. 307 * The name of the field can be encoded as a reference to the name 308 * in the static or dynamic table. 309 */ 310 mhd_HPACK_ENC_POL_ALWAYS_NEW_IDX_IF_FIT 311 , 312 /** 313 * Allow field encoding as a reference to an indexed field in the 314 * static or dynamic table; if the field is not in the tables and 315 * the field does not fit the dynamic table, the dynamic table is 316 * completely evicted without adding the new field. 317 * When the field is not in the tables, the name of the field can be 318 * encoded as a reference to the name in the static or dynamic 319 * table. 320 */ 321 mhd_HPACK_ENC_POL_FORCED 322 , 323 /** 324 * Allow field encoding as a reference to an indexed field in the 325 * static or dynamic table; if the field is not in the tables, 326 * always add the field to the dynamic table if it fits the table. 327 * When the field is not in the tables, the name of the field can be 328 * encoded as a reference to the name in the static or dynamic 329 * table. 330 */ 331 mhd_HPACK_ENC_POL_ALWAYS_IF_FIT 332 , 333 /** 334 * Allow field encoding as a reference to an indexed field in the 335 * static or dynamic table; if the field is not in the tables, 336 * prefer adding the field to the dynamic table if possible. 337 * When the field is not in the tables, the name of the field can be 338 * encoded as a reference to the name in the static or dynamic 339 * table. 340 */ 341 mhd_HPACK_ENC_POL_DESIRABLE 342 , 343 /** 344 * Allow field encoding as a reference to an indexed field in the 345 * static or dynamic table; if the field is not in the tables, use 346 * a neutral preference regarding adding the field to the dynamic 347 * table. 348 * When the field is not in the tables, the name of the field can be 349 * encoded as a reference to the name in the static or dynamic 350 * table. 351 */ 352 mhd_HPACK_ENC_POL_NEUTRAL 353 , 354 /** 355 * Allow field encoding as a reference to an indexed field in the 356 * static or dynamic table; if the field is not in the tables, 357 * consider adding the field to the dynamic table only with low 358 * priority (the encoder may choose not to add it). 359 * When the field is not in the tables, the name of the field can be 360 * encoded as a reference to the name in the static or dynamic 361 * table. 362 */ 363 mhd_HPACK_ENC_POL_LOW_PRIO 364 , 365 /** 366 * Allow field encoding as a reference to an indexed field in the 367 * static or dynamic table; if the field is not in the tables, 368 * consider adding the field to the dynamic table only with the 369 * lowest priority (the encoder is expected to avoid adding it in 370 * most cases). 371 * When the field is not in the tables, the name of the field can be 372 * encoded as a reference to the name in the static or dynamic 373 * table. 374 */ 375 mhd_HPACK_ENC_POL_LOWEST_PRIO 376 , 377 /** 378 * Allow field encoding as a reference to an indexed field in the 379 * static or dynamic table; if the field is not in the tables already, 380 * avoid adding the field to the dynamic table. 381 * When the field is not in the tables, the name of the field can be 382 * encoded as a reference to the name in the static or dynamic 383 * table. 384 */ 385 mhd_HPACK_ENC_POL_AVOID_NEW_IDX 386 , 387 /** 388 * Use field literal encoding without indexing. 389 * The name of the field can still be encoded as a reference to the 390 * name in the static or dynamic table. 391 */ 392 mhd_HPACK_ENC_POL_NOT_INDEXED 393 , 394 /** 395 * Use field literal encoding without indexing, with an additional 396 * "never indexed" mark to signal intermediaries to avoid using it 397 * as an indexed field when re-encoding the message. 398 * The name of the field can still be encoded as a reference to the 399 * name in the static or dynamic table. 400 */ 401 mhd_HPACK_ENC_POL_NEVER_W_NAME_IDX 402 , 403 /** 404 * Use field literal encoding without indexing, with an additional 405 * "never indexed" mark to signal intermediaries to avoid using it 406 * as an indexed field when re-encoding the message. 407 * The name of the field can be encoded as a reference to the name 408 * in the static table. 409 */ 410 mhd_HPACK_ENC_POL_NEVER_W_NAME_IDX_STATIC 411 , 412 /** 413 * Use field literal encoding without indexing, with an additional 414 * "never indexed" mark to signal intermediaries to avoid using it 415 * as an indexed field when re-encoding the message. 416 * The name of the field is always encoded literally. 417 */ 418 mhd_HPACK_ENC_POL_NEVER_W_NAME_LIT_FORCED 419 , 420 /** 421 * Use field literal encoding without indexing, with an additional 422 * "never indexed" mark to signal intermediaries to avoid using it 423 * as an indexed field when re-encoding the message. 424 * The name of the field is always encoded literally, and Huffman 425 * encoding is not used for the name or the value of the field. 426 */ 427 mhd_HPACK_ENC_POL_NEVER_W_NAME_LIT_NO_HUFFMAN 428 }; 429 430 431 /** 432 * Result codes of field encoding 433 */ 434 enum MHD_FIXED_ENUM_ mhd_HpackEncResult 435 { 436 /** 437 * The field has been encoded successfully 438 */ 439 mhd_HPACK_ENC_RES_OK = 0 440 , 441 /** 442 * The output buffer is too small to fit the data 443 */ 444 mhd_HPACK_ENC_BUFFER_TOO_SMALL 445 , 446 /** 447 * Error allocating memory when resizing the dynamic table 448 */ 449 mhd_HPACK_ENC_RES_ALLOC_ERR 450 }; 451 452 /** 453 * Encode a single HPACK field. 454 * 455 * May emit a Dynamic Table Size Update representation first if the encoder 456 * has a pending size change. Encodes the field using indexed or literal 457 * representation according to @a enc_pol and the state of the static/dynamic 458 * tables. On success, the number of bytes written is stored in 459 * @a bytes_encoded. 460 * 461 * @param hk_enc the encoder context 462 * @param name the field name, must be a "real" header, 463 * must not start with the ':' character 464 * @param value the field value 465 * @param enc_pol the encoding policy to apply 466 * @param out_buff_size the size of @a out_buff in bytes 467 * @param[out] out_buff the output buffer to receive the encoded data 468 * @param[out] bytes_encoded set to the number of bytes written to @a out_buff 469 * @return #mhd_HPACK_ENC_RES_OK on success; 470 * #mhd_HPACK_ENC_BUFFER_TOO_SMALL if the output buffer is too small; 471 * #mhd_HPACK_ENC_RES_ALLOC_ERR on dynamic table allocation error, 472 * never returned if #mhd_hpack_enc_set_dyn_size() was not earlier or 473 * if #mhd_hpack_enc_dyn_resize() after #mhd_hpack_enc_set_dyn_size() 474 */ 475 MHD_INTERNAL enum mhd_HpackEncResult 476 mhd_hpack_enc_field (struct mhd_HpackEncContext *restrict hk_enc, 477 const struct mhd_BufferConst *restrict name, 478 const struct mhd_BufferConst *restrict value, 479 enum mhd_HpackEncPolicy enc_pol, 480 const size_t out_buff_size, 481 uint8_t *restrict out_buff, 482 size_t *restrict bytes_encoded) 483 MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_INOUT_(1) 484 MHD_FN_PAR_IN_(2) MHD_FN_PAR_IN_(3) 485 MHD_FN_PAR_OUT_SIZE_(6,5) MHD_FN_PAR_OUT_ (7); 486 487 488 /** 489 * Preference for HPACK encoding of pseudo-header ":status" 490 * 491 * The items are sorted, keep them in this order. 492 */ 493 enum MHD_FIXED_ENUM_ mhd_HpackEncPFieldStatusPolicy 494 { 495 /** 496 * Encode the pseudo-header literally; if the pseudo-header fits the dynamic 497 * table, add it to the dynamic table as a new index even if the same 498 * pseudo-header is already in the tables. If the pseudo-header does not fit 499 * the dynamic table, it is encoded literally without adding it to the 500 * table. 501 * The name of the pseudo-header is encoded as a reference to the name 502 * in the static table. 503 */ 504 mhd_HPACK_ENC_PFS_POL_ALWAYS_NEW_IDX_IF_FIT 505 , 506 /** 507 * Allow pseudo-header encoding as a reference to an indexed pseudo-header in 508 * the static or dynamic table; if the pseudo-header is not in the tables, 509 * add the pseudo-header to the dynamic table if possible. 510 * When the pseudo-header is not in the tables, the name of the pseudo-header 511 * is encoded as a reference to the name in the static table. 512 */ 513 mhd_HPACK_ENC_PFS_POL_NORMAL 514 , 515 /** 516 * Allow pseudo-header encoding as a reference to an indexed pseudo-header in 517 * the static or dynamic table; if the pseudo-header is not in the tables 518 * already, avoid adding the pseudo-header to the dynamic table. 519 * When the pseudo-header is not in the tables, the name of the pseudo-header 520 * is encoded as a reference to the name in the static table. 521 */ 522 mhd_HPACK_ENC_PFS_POL_AVOID_NEW_IDX 523 , 524 /** 525 * Allow pseudo-header encoding as a reference to an indexed pseudo-header in 526 * the static table only; if the pseudo-header is not in the static table, 527 * encode it literally, without adding to the dynamic table. 528 * When the pseudo-header is not in the static table, the name of the 529 * pseudo-header is encoded as a reference to the name in the static table. 530 */ 531 mhd_HPACK_ENC_PFS_POL_STATIC_IDX 532 , 533 /** 534 * Use pseudo-header literal encoding without indexing. 535 * The name of the pseudo-header is encoded as a reference to the name in 536 * the static table. 537 */ 538 mhd_HPACK_ENC_PFS_POL_NOT_INDEXED 539 , 540 /** 541 * Use pseudo-header literal encoding without indexing, with an additional 542 * "never indexed" mark to signal intermediaries to avoid using it 543 * as an indexed pseudo-header when re-encoding the message. 544 * The name of the pseudo-header is encoded as a reference to the name in 545 * the static table. 546 */ 547 mhd_HPACK_ENC_PFS_POL_NEVER_W_NAME_IDX 548 , 549 /** 550 * Use pseudo-header literal encoding without indexing, with an additional 551 * "never indexed" mark to signal intermediaries to avoid using it 552 * as an indexed pseudo-header when re-encoding the message. 553 * The name of the pseudo-header is always encoded literally. 554 */ 555 mhd_HPACK_ENC_PFS_POL_NEVER_W_NAME_LIT_FORCED 556 , 557 /** 558 * Use pseudo-header literal encoding without indexing, with an additional 559 * "never indexed" mark to signal intermediaries to avoid using it 560 * as an indexed pseudo-header when re-encoding the message. 561 * The name of the pseudo-header is always encoded literally, and Huffman 562 * encoding is not used for the name or the value of the pseudo-header. 563 */ 564 mhd_HPACK_ENC_PFS_POL_NEVER_W_NAME_LIT_NO_HUFFMAN 565 }; 566 567 /** 568 * Encode a single HPACK pseudo-header ":status". 569 * 570 * May emit a Dynamic Table Size Update representation first if the encoder 571 * has a pending size change. 572 * On success, the number of bytes written is stored in @a bytes_encoded. 573 * 574 * @param hk_enc the encoder context 575 * @param code the status code, must be >= 100 and <= 699 576 * @param enc_pol the encoding policy to apply 577 * @param out_buff_size the size of @a out_buff in bytes 578 * @param[out] out_buff the output buffer to receive the encoded data 579 * @param[out] bytes_encoded set to the number of bytes written to @a out_buff 580 * @return #mhd_HPACK_ENC_RES_OK on success, 581 * #mhd_HPACK_ENC_BUFFER_TOO_SMALL if the output buffer is too small, 582 * #mhd_HPACK_ENC_RES_ALLOC_ERR on dynamic table allocation error 583 */ 584 MHD_INTERNAL enum mhd_HpackEncResult 585 mhd_hpack_enc_ph_status (struct mhd_HpackEncContext *restrict hk_enc, 586 uint_fast16_t code, 587 enum mhd_HpackEncPFieldStatusPolicy enc_pol, 588 const size_t out_buff_size, 589 uint8_t *restrict out_buff, 590 size_t *restrict bytes_encoded) 591 MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_INOUT_(1) 592 MHD_FN_PAR_OUT_SIZE_(5,4) MHD_FN_PAR_OUT_ (6); 593 594 #endif /* ! MHD_HPACK_CODEC_H */