1 /* 2 * nghttp3 3 * 4 * Copyright (c) 2019 nghttp3 contributors 5 * Copyright (c) 2013 nghttp2 contributors 6 * 7 * Permission is hereby granted, free of charge, to any person obtaining 8 * a copy of this software and associated documentation files (the 9 * "Software"), to deal in the Software without restriction, including 10 * without limitation the rights to use, copy, modify, merge, publish, 11 * distribute, sublicense, and/or sell copies of the Software, and to 12 * permit persons to whom the Software is furnished to do so, subject to 13 * the following conditions: 14 * 15 * The above copyright notice and this permission notice shall be 16 * included in all copies or substantial portions of the Software. 17 * 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 19 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 21 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 22 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 24 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 */ 26 #ifndef NGHTTP3_QPACK_H 27 #define NGHTTP3_QPACK_H 28 29 #ifdef HAVE_CONFIG_H 30 # include <config.h> 31 #endif /* HAVE_CONFIG_H */ 32 33 #include <nghttp3/nghttp3.h> 34 35 #include "nghttp3_rcbuf.h" 36 #include "nghttp3_map.h" 37 #include "nghttp3_pq.h" 38 #include "nghttp3_ringbuf.h" 39 #include "nghttp3_buf.h" 40 #include "nghttp3_ksl.h" 41 #include "nghttp3_qpack_huffman.h" 42 43 #define NGHTTP3_QPACK_INT_MAX ((1ull << 62) - 1) 44 45 /* NGHTTP3_QPACK_MAX_NAMELEN is the maximum (compressed) length of 46 header name this library can decode. */ 47 #define NGHTTP3_QPACK_MAX_NAMELEN 256 48 /* NGHTTP3_QPACK_MAX_VALUELEN is the maximum (compressed) length of 49 header value this library can decode. */ 50 #define NGHTTP3_QPACK_MAX_VALUELEN 65536 51 52 /* nghttp3_qpack_indexing_mode is a indexing strategy. */ 53 typedef enum nghttp3_qpack_indexing_mode { 54 /* NGHTTP3_QPACK_INDEXING_MODE_LITERAL means that header field 55 should not be inserted into dynamic table. */ 56 NGHTTP3_QPACK_INDEXING_MODE_LITERAL, 57 /* NGHTTP3_QPACK_INDEXING_MODE_STORE means that header field can be 58 inserted into dynamic table. */ 59 NGHTTP3_QPACK_INDEXING_MODE_STORE, 60 /* NGHTTP3_QPACK_INDEXING_MODE_NEVER means that header field should 61 not be inserted into dynamic table and this must be true for all 62 forwarding paths. */ 63 NGHTTP3_QPACK_INDEXING_MODE_NEVER, 64 } nghttp3_qpack_indexing_mode; 65 66 typedef struct nghttp3_qpack_entry nghttp3_qpack_entry; 67 68 struct nghttp3_qpack_entry { 69 /* The header field name/value pair */ 70 nghttp3_qpack_nv nv; 71 /* map_next points to the entry which shares same bucket in hash 72 table. */ 73 nghttp3_qpack_entry *map_next; 74 /* sum is the sum of all entries inserted up to this entry. This 75 value does not contain the space required for this entry. */ 76 size_t sum; 77 /* absidx is the absolute index of this entry. */ 78 uint64_t absidx; 79 /* The hash value for header name (nv.name). */ 80 uint32_t hash; 81 }; 82 83 /* The entry used for static table. */ 84 typedef struct nghttp3_qpack_static_entry { 85 uint64_t absidx; 86 int32_t token; 87 uint32_t hash; 88 } nghttp3_qpack_static_entry; 89 90 typedef struct nghttp3_qpack_static_header { 91 nghttp3_rcbuf name; 92 nghttp3_rcbuf value; 93 int32_t token; 94 } nghttp3_qpack_static_header; 95 96 /* 97 * nghttp3_qpack_header_block_ref is created per encoded header block 98 * and includes the required insert count and the minimum insert count 99 * of dynamic table entry it refers to. 100 */ 101 typedef struct nghttp3_qpack_header_block_ref { 102 nghttp3_pq_entry max_cnts_pe; 103 nghttp3_pq_entry min_cnts_pe; 104 /* max_cnt is the required insert count. */ 105 uint64_t max_cnt; 106 /* min_cnt is the minimum insert count of dynamic table entry it 107 refers to. In other words, this is the minimum absolute index of 108 dynamic header table entry this encoded block refers to plus 109 1. */ 110 uint64_t min_cnt; 111 } nghttp3_qpack_header_block_ref; 112 113 int nghttp3_qpack_header_block_ref_new(nghttp3_qpack_header_block_ref **pref, 114 uint64_t max_cnt, uint64_t min_cnt, 115 const nghttp3_mem *mem); 116 117 void nghttp3_qpack_header_block_ref_del(nghttp3_qpack_header_block_ref *ref, 118 const nghttp3_mem *mem); 119 120 typedef struct nghttp3_qpack_stream { 121 int64_t stream_id; 122 /* refs is an array of pointer to nghttp3_qpack_header_block_ref in 123 the order of the time they are encoded. HTTP/3 allows multiple 124 header blocks (e.g., non-final response headers, final response 125 headers, trailers, and push promises) per stream. */ 126 nghttp3_ringbuf refs; 127 /* max_cnts is a priority queue sorted by descending order of 128 max_cnt of nghttp3_qpack_header_block_ref. */ 129 nghttp3_pq max_cnts; 130 } nghttp3_qpack_stream; 131 132 int nghttp3_qpack_stream_new(nghttp3_qpack_stream **pstream, int64_t stream_id, 133 const nghttp3_mem *mem); 134 135 void nghttp3_qpack_stream_del(nghttp3_qpack_stream *stream, 136 const nghttp3_mem *mem); 137 138 uint64_t nghttp3_qpack_stream_get_max_cnt(const nghttp3_qpack_stream *stream); 139 140 int nghttp3_qpack_stream_add_ref(nghttp3_qpack_stream *stream, 141 nghttp3_qpack_header_block_ref *ref); 142 143 void nghttp3_qpack_stream_pop_ref(nghttp3_qpack_stream *stream); 144 145 #define NGHTTP3_QPACK_ENTRY_OVERHEAD 32 146 147 typedef struct nghttp3_qpack_context { 148 /* dtable is a dynamic table */ 149 nghttp3_ringbuf dtable; 150 /* mem is memory allocator */ 151 const nghttp3_mem *mem; 152 /* dtable_size is abstracted buffer size of dtable as described in 153 the spec. This is the sum of length of name/value in dtable + 154 NGHTTP3_QPACK_ENTRY_OVERHEAD bytes overhead per each entry. */ 155 size_t dtable_size; 156 size_t dtable_sum; 157 /* hard_max_dtable_capacity is the maximum size of dynamic table. 158 In HTTP/3, it is notified by decoder as 159 SETTINGS_QPACK_MAX_TABLE_CAPACITY. Any value lower than or equal 160 to SETTINGS_QPACK_MAX_TABLE_CAPACITY is OK because encoder has 161 the authority to decide how many entries are inserted into 162 dynamic table. */ 163 size_t hard_max_dtable_capacity; 164 /* max_dtable_capacity is the effective maximum size of dynamic 165 table. */ 166 size_t max_dtable_capacity; 167 /* max_blocked_streams is the maximum number of stream which can be 168 blocked. */ 169 size_t max_blocked_streams; 170 /* next_absidx is the next absolute index for nghttp3_qpack_entry. 171 It is equivalent to insert count. */ 172 uint64_t next_absidx; 173 /* If inflate/deflate error occurred, this value is set to 1 and 174 further invocation of inflate/deflate will fail with 175 NGHTTP3_ERR_QPACK_FATAL. */ 176 uint8_t bad; 177 } nghttp3_qpack_context; 178 179 typedef struct nghttp3_qpack_read_state { 180 nghttp3_qpack_huffman_decode_context huffman_ctx; 181 nghttp3_buf namebuf; 182 nghttp3_buf valuebuf; 183 nghttp3_rcbuf *name; 184 nghttp3_rcbuf *value; 185 uint64_t left; 186 size_t prefix; 187 size_t shift; 188 uint64_t absidx; 189 int never; 190 int dynamic; 191 int huffman_encoded; 192 } nghttp3_qpack_read_state; 193 194 void nghttp3_qpack_read_state_free(nghttp3_qpack_read_state *rstate); 195 196 void nghttp3_qpack_read_state_reset(nghttp3_qpack_read_state *rstate); 197 198 #define NGHTTP3_QPACK_MAP_SIZE 64 199 200 typedef struct nghttp3_qpack_map { 201 nghttp3_qpack_entry *table[NGHTTP3_QPACK_MAP_SIZE]; 202 } nghttp3_qpack_map; 203 204 /* nghttp3_qpack_decoder_stream_state is a set of states when decoding 205 decoder stream. */ 206 typedef enum nghttp3_qpack_decoder_stream_state { 207 NGHTTP3_QPACK_DS_STATE_OPCODE, 208 NGHTTP3_QPACK_DS_STATE_READ_NUMBER, 209 } nghttp3_qpack_decoder_stream_state; 210 211 /* nghttp3_qpack_decoder_stream_opcode is opcode used in decoder 212 stream. */ 213 typedef enum nghttp3_qpack_decoder_stream_opcode { 214 NGHTTP3_QPACK_DS_OPCODE_ICNT_INCREMENT, 215 NGHTTP3_QPACK_DS_OPCODE_SECTION_ACK, 216 NGHTTP3_QPACK_DS_OPCODE_STREAM_CANCEL, 217 } nghttp3_qpack_decoder_stream_opcode; 218 219 /* QPACK encoder flags */ 220 221 /* NGHTTP3_QPACK_ENCODER_FLAG_NONE indicates that no flag is set. */ 222 #define NGHTTP3_QPACK_ENCODER_FLAG_NONE 0x00 223 /* NGHTTP3_QPACK_ENCODER_FLAG_PENDING_SET_DTABLE_CAP indicates that 224 Set Dynamic Table Capacity is required. */ 225 #define NGHTTP3_QPACK_ENCODER_FLAG_PENDING_SET_DTABLE_CAP 0x01 226 227 struct nghttp3_qpack_encoder { 228 nghttp3_qpack_context ctx; 229 /* dtable_map is a map of hash to nghttp3_qpack_entry to provide 230 fast access to an entry in dynamic table. */ 231 nghttp3_qpack_map dtable_map; 232 /* streams is a map of stream ID to nghttp3_qpack_stream to keep 233 track of unacknowledged streams. */ 234 nghttp3_map streams; 235 /* blocked_streams is an ordered list of nghttp3_qpack_stream, in 236 descending order of max_cnt, to search the unblocked streams by 237 received known count. */ 238 nghttp3_ksl blocked_streams; 239 /* min_cnts is a priority queue of nghttp3_qpack_header_block_ref 240 sorted by ascending order of min_cnt to know that an entry can be 241 evicted from dynamic table. */ 242 nghttp3_pq min_cnts; 243 /* krcnt is Known Received Count. */ 244 uint64_t krcnt; 245 /* state is a current state of reading decoder stream. */ 246 nghttp3_qpack_decoder_stream_state state; 247 /* opcode is a decoder stream opcode being processed. */ 248 nghttp3_qpack_decoder_stream_opcode opcode; 249 /* rstate is a set of intermediate state which are used to process 250 decoder stream. */ 251 nghttp3_qpack_read_state rstate; 252 /* min_dtable_update is the minimum dynamic table size required. */ 253 size_t min_dtable_update; 254 /* last_max_dtable_update is the dynamic table size last 255 requested. */ 256 size_t last_max_dtable_update; 257 /* flags is bitwise OR of zero or more of 258 NGHTTP3_QPACK_ENCODER_FLAG_*. */ 259 uint8_t flags; 260 }; 261 262 /* 263 * nghttp3_qpack_encoder_init initializes |encoder|. |mem| is a 264 * memory allocator. 265 * 266 * This function returns 0 if it succeeds, or one of the following 267 * negative error codes: 268 * 269 * NGHTTP3_ERR_NOMEM 270 * Out of memory. 271 */ 272 int nghttp3_qpack_encoder_init(nghttp3_qpack_encoder *encoder, 273 const nghttp3_mem *mem); 274 275 /* 276 * nghttp3_qpack_encoder_free frees memory allocated for |encoder|. 277 * This function does not free memory pointed by |encoder|. 278 */ 279 void nghttp3_qpack_encoder_free(nghttp3_qpack_encoder *encoder); 280 281 /* 282 * nghttp3_qpack_encoder_encode_nv encodes |nv|. It writes request 283 * stream into |rbuf| and writes encoder stream into |ebuf|. |nv| is 284 * a header field to encode. |base| is base. |allow_blocking| is 285 * nonzero if this stream can be blocked (or it has been blocked 286 * already). 287 * 288 * This function returns 0 if it succeeds, or one of the following 289 * negative error codes: 290 * 291 * NGHTTP3_ERR_NOMEM 292 * Out of memory. 293 */ 294 int nghttp3_qpack_encoder_encode_nv(nghttp3_qpack_encoder *encoder, 295 uint64_t *pmax_cnt, uint64_t *pmin_cnt, 296 nghttp3_buf *rbuf, nghttp3_buf *ebuf, 297 const nghttp3_nv *nv, uint64_t base, 298 int allow_blocking); 299 300 /* nghttp3_qpack_lookup_result stores a result of table lookup. */ 301 typedef struct nghttp3_qpack_lookup_result { 302 /* index is an index of matched entry. -1 if no match is made. */ 303 nghttp3_ssize index; 304 /* name_value_match is nonzero if both name and value are 305 matched. */ 306 int name_value_match; 307 /* pb_index is the absolute index of matched post-based dynamic 308 table entry. -1 if no such entry exists. */ 309 nghttp3_ssize pb_index; 310 } nghttp3_qpack_lookup_result; 311 312 /* 313 * nghttp3_qpack_lookup_stable searches |nv| in static table. |token| 314 * is a token of nv->name and it is -1 if there is no corresponding 315 * token defined. |indexing_mode| provides indexing strategy. 316 */ 317 nghttp3_qpack_lookup_result 318 nghttp3_qpack_lookup_stable(const nghttp3_nv *nv, int32_t token, 319 nghttp3_qpack_indexing_mode indexing_mode); 320 321 /* 322 * nghttp3_qpack_encoder_lookup_dtable searches |nv| in dynamic table. 323 * |token| is a token of nv->name and it is -1 if there is no 324 * corresponding token defined. |hash| is a hash of nv->name. 325 * |indexing_mode| provides indexing strategy. |krcnt| is Known 326 * Received Count. |allow_blocking| is nonzero if this stream can be 327 * blocked (or it has been blocked already). 328 */ 329 nghttp3_qpack_lookup_result nghttp3_qpack_encoder_lookup_dtable( 330 nghttp3_qpack_encoder *encoder, const nghttp3_nv *nv, int32_t token, 331 uint32_t hash, nghttp3_qpack_indexing_mode indexing_mode, uint64_t krcnt, 332 int allow_blocking); 333 334 /* 335 * nghttp3_qpack_encoder_write_field_section_prefix writes Encoded 336 * Field Section Prefix into |pbuf|. |ricnt| is Required Insert 337 * Count. |base| is Base. 338 * 339 * This function returns 0 if it succeeds, or one of the following 340 * negative error codes: 341 * 342 * NGHTTP3_ERR_NOMEM 343 * Out of memory. 344 */ 345 int nghttp3_qpack_encoder_write_field_section_prefix( 346 nghttp3_qpack_encoder *encoder, nghttp3_buf *pbuf, uint64_t ricnt, 347 uint64_t base); 348 349 /* 350 * nghttp3_qpack_encoder_write_static_indexed writes Indexed Header 351 * Field to |rbuf|. |absidx| is an absolute index into static table. 352 * 353 * This function returns 0 if it succeeds, or one of the following 354 * negative error codes: 355 * 356 * NGHTTP3_ERR_NOMEM 357 * Out of memory. 358 */ 359 int nghttp3_qpack_encoder_write_static_indexed(nghttp3_qpack_encoder *encoder, 360 nghttp3_buf *rbuf, 361 uint64_t absidx); 362 363 /* 364 * nghttp3_qpack_encoder_write_dynamic_indexed writes Indexed Header 365 * Field to |rbuf|. |absidx| is an absolute index into dynamic table. 366 * |base| is base. 367 * 368 * This function returns 0 if it succeeds, or one of the following 369 * negative error codes: 370 * 371 * NGHTTP3_ERR_NOMEM 372 * Out of memory. 373 */ 374 int nghttp3_qpack_encoder_write_dynamic_indexed(nghttp3_qpack_encoder *encoder, 375 nghttp3_buf *rbuf, 376 uint64_t absidx, uint64_t base); 377 378 /* 379 * nghttp3_qpack_encoder_write_static_indexed writes Literal Header 380 * Field With Name Reference to |rbuf|. |absidx| is an absolute index 381 * into static table to reference a name. |nv| is a header field to 382 * encode. 383 * 384 * This function returns 0 if it succeeds, or one of the following 385 * negative error codes: 386 * 387 * NGHTTP3_ERR_NOMEM 388 * Out of memory. 389 */ 390 int nghttp3_qpack_encoder_write_static_indexed_name( 391 nghttp3_qpack_encoder *encoder, nghttp3_buf *rbuf, uint64_t absidx, 392 const nghttp3_nv *nv); 393 394 /* 395 * nghttp3_qpack_encoder_write_dynamic_indexed writes Literal Header 396 * Field With Name Reference to |rbuf|. |absidx| is an absolute index 397 * into dynamic table to reference a name. |base| is a base. |nv| is 398 * a header field to encode. 399 * 400 * This function returns 0 if it succeeds, or one of the following 401 * negative error codes: 402 * 403 * NGHTTP3_ERR_NOMEM 404 * Out of memory. 405 */ 406 int nghttp3_qpack_encoder_write_dynamic_indexed_name( 407 nghttp3_qpack_encoder *encoder, nghttp3_buf *rbuf, uint64_t absidx, 408 uint64_t base, const nghttp3_nv *nv); 409 410 /* 411 * nghttp3_qpack_encoder_write_literal writes Literal Header Field 412 * With Literal Name to |rbuf|. |nv| is a header field to encode. 413 * 414 * This function returns 0 if it succeeds, or one of the following 415 * negative error codes: 416 * 417 * NGHTTP3_ERR_NOMEM 418 * Out of memory. 419 */ 420 int nghttp3_qpack_encoder_write_literal(nghttp3_qpack_encoder *encoder, 421 nghttp3_buf *rbuf, 422 const nghttp3_nv *nv); 423 424 /* 425 * nghttp3_qpack_encoder_write_static_insert writes Insert With Name 426 * Reference to |ebuf|. |absidx| is an absolute index into static 427 * table to reference a name. |nv| is a header field to insert. 428 * 429 * This function returns 0 if it succeeds, or one of the following 430 * negative error codes: 431 * 432 * NGHTTP3_ERR_NOMEM 433 * Out of memory. 434 */ 435 int nghttp3_qpack_encoder_write_static_insert(nghttp3_qpack_encoder *encoder, 436 nghttp3_buf *ebuf, 437 uint64_t absidx, 438 const nghttp3_nv *nv); 439 440 /* 441 * nghttp3_qpack_encoder_write_dynamic_insert writes Insert With Name 442 * Reference to |ebuf|. |absidx| is an absolute index into dynamic 443 * table to reference a name. |nv| is a header field to insert. 444 * 445 * This function returns 0 if it succeeds, or one of the following 446 * negative error codes: 447 * 448 * NGHTTP3_ERR_NOMEM 449 * Out of memory. 450 */ 451 int nghttp3_qpack_encoder_write_dynamic_insert(nghttp3_qpack_encoder *encoder, 452 nghttp3_buf *ebuf, 453 uint64_t absidx, 454 const nghttp3_nv *nv); 455 456 /* 457 * nghttp3_qpack_encoder_write_duplicate_insert writes Duplicate to 458 * |ebuf|. |absidx| is an absolute index into dynamic table to 459 * reference an entry. 460 * 461 * This function returns 0 if it succeeds, or one of the following 462 * negative error codes: 463 * 464 * NGHTTP3_ERR_NOMEM 465 * Out of memory. 466 */ 467 int nghttp3_qpack_encoder_write_duplicate_insert(nghttp3_qpack_encoder *encoder, 468 nghttp3_buf *ebuf, 469 uint64_t absidx); 470 471 /* 472 * nghttp3_qpack_encoder_write_literal_insert writes Insert With 473 * Literal Name to |ebuf|. |nv| is a header field to insert. 474 * 475 * This function returns 0 if it succeeds, or one of the following 476 * negative error codes: 477 * 478 * NGHTTP3_ERR_NOMEM 479 * Out of memory. 480 */ 481 int nghttp3_qpack_encoder_write_literal_insert(nghttp3_qpack_encoder *encoder, 482 nghttp3_buf *ebuf, 483 const nghttp3_nv *nv); 484 485 int nghttp3_qpack_encoder_stream_is_blocked(nghttp3_qpack_encoder *encoder, 486 nghttp3_qpack_stream *stream); 487 488 /* 489 * nghttp3_qpack_encoder_block_stream blocks |stream|. 490 * 491 * This function returns 0 if it succeeds, or one of the following 492 * negative error codes: 493 * 494 * NGHTTP3_ERR_NOMEM 495 * Out of memory. 496 */ 497 int nghttp3_qpack_encoder_block_stream(nghttp3_qpack_encoder *encoder, 498 nghttp3_qpack_stream *stream); 499 500 /* 501 * nghttp3_qpack_encoder_unblock_stream unblocks |stream|. 502 */ 503 void nghttp3_qpack_encoder_unblock_stream(nghttp3_qpack_encoder *encoder, 504 nghttp3_qpack_stream *stream); 505 506 /* 507 * nghttp3_qpack_encoder_unblock unblocks stream whose max_cnt is less 508 * than or equal to |max_cnt|. 509 */ 510 void nghttp3_qpack_encoder_unblock(nghttp3_qpack_encoder *encoder, 511 uint64_t max_cnt); 512 513 /* 514 * nghttp3_qpack_encoder_find_stream returns stream whose stream ID is 515 * |stream_id|. This function returns NULL if there is no such 516 * stream. 517 */ 518 nghttp3_qpack_stream * 519 nghttp3_qpack_encoder_find_stream(nghttp3_qpack_encoder *encoder, 520 int64_t stream_id); 521 522 uint64_t nghttp3_qpack_encoder_get_min_cnt(nghttp3_qpack_encoder *encoder); 523 524 /* 525 * nghttp3_qpack_encoder_shrink_dtable shrinks dynamic table so that 526 * the dynamic table size is less than or equal to maximum size. 527 */ 528 void nghttp3_qpack_encoder_shrink_dtable(nghttp3_qpack_encoder *encoder); 529 530 /* 531 * nghttp3_qpack_encoder_process_dtable_update processes pending 532 * dynamic table size update. It might write encoder stream into 533 * |ebuf|. 534 * 535 * This function returns 0 if it succeeds, or one of the following 536 * negative error codes: 537 * 538 * NGHTTP3_ERR_NOMEM 539 * Out of memory. 540 */ 541 int nghttp3_qpack_encoder_process_dtable_update(nghttp3_qpack_encoder *encoder, 542 nghttp3_buf *ebuf); 543 544 /* 545 * nghttp3_qpack_encoder_write_set_dtable_cap writes Set Dynamic Table 546 * Capacity. to |ebuf|. |cap| is the capacity of dynamic table. 547 * 548 * This function returns 0 if it succeeds, or one of the following 549 * negative error codes: 550 * 551 * NGHTTP3_ERR_NOMEM 552 * Out of memory. 553 */ 554 int nghttp3_qpack_encoder_write_set_dtable_cap(nghttp3_qpack_encoder *encoder, 555 nghttp3_buf *ebuf, size_t cap); 556 557 /* 558 * nghttp3_qpack_context_dtable_add adds |qnv| to dynamic table. If 559 * |ctx| is a part of encoder, |dtable_map| is not NULL. |hash| is a 560 * hash value of name. 561 * 562 * This function returns 0 if it succeeds, or one of the following 563 * negative error codes: 564 * 565 * NGHTTP3_ERR_NOMEM 566 * Out of memory. 567 */ 568 int nghttp3_qpack_context_dtable_add(nghttp3_qpack_context *ctx, 569 nghttp3_qpack_nv *qnv, 570 nghttp3_qpack_map *dtable_map, 571 uint32_t hash); 572 573 /* 574 * nghttp3_qpack_encoder_dtable_static_add adds |nv| to dynamic table 575 * by referencing static table entry at an absolute index |absidx|. 576 * The hash of name is given as |hash|. 577 * 578 * This function returns 0 if it succeeds, or one of the following 579 * negative error codes: 580 * 581 * NGHTTP3_ERR_NOMEM 582 * Out of memory. 583 */ 584 int nghttp3_qpack_encoder_dtable_static_add(nghttp3_qpack_encoder *encoder, 585 uint64_t absidx, 586 const nghttp3_nv *nv, 587 uint32_t hash); 588 589 /* 590 * nghttp3_qpack_encoder_dtable_dynamic_add adds |nv| to dynamic table 591 * by referencing dynamic table entry at an absolute index |absidx|. 592 * The hash of name is given as |hash|. 593 * 594 * This function returns 0 if it succeeds, or one of the following 595 * negative error codes: 596 * 597 * NGHTTP3_ERR_NOMEM 598 * Out of memory. 599 */ 600 int nghttp3_qpack_encoder_dtable_dynamic_add(nghttp3_qpack_encoder *encoder, 601 uint64_t absidx, 602 const nghttp3_nv *nv, 603 uint32_t hash); 604 605 /* 606 * nghttp3_qpack_encoder_dtable_duplicate_add duplicates dynamic table 607 * entry at an absolute index |absidx|. 608 * 609 * This function returns 0 if it succeeds, or one of the following 610 * negative error codes: 611 * 612 * NGHTTP3_ERR_NOMEM 613 * Out of memory. 614 */ 615 int nghttp3_qpack_encoder_dtable_duplicate_add(nghttp3_qpack_encoder *encoder, 616 uint64_t absidx); 617 618 /* 619 * nghttp3_qpack_encoder_dtable_literal_add adds |nv| to dynamic 620 * table. |token| is a token of name and is -1 if it has no token 621 * value defined. |hash| is a hash of name. 622 * 623 * NGHTTP3_ERR_NOMEM Out of memory. 624 */ 625 int nghttp3_qpack_encoder_dtable_literal_add(nghttp3_qpack_encoder *encoder, 626 const nghttp3_nv *nv, 627 int32_t token, uint32_t hash); 628 629 /* 630 * `nghttp3_qpack_encoder_ack_header` tells |encoder| that header 631 * block for a stream denoted by |stream_id| was acknowledged by 632 * decoder. 633 * 634 * This function returns 0 if it succeeds, or one of the following 635 * negative error codes: 636 * 637 * :macro:`NGHTTP3_ERR_QPACK_DECODER_STREAM_ERROR` 638 * Section Acknowledgement for a stream denoted by |stream_id| is 639 * unexpected. 640 */ 641 int nghttp3_qpack_encoder_ack_header(nghttp3_qpack_encoder *encoder, 642 int64_t stream_id); 643 644 /* 645 * `nghttp3_qpack_encoder_add_icnt` increments known received count of 646 * |encoder| by |n|. 647 * 648 * This function returns 0 if it succeeds, or one of the following 649 * negative error codes: 650 * 651 * :macro:`NGHTTP3_ERR_NOMEM` 652 * Out of memory. 653 * :macro:`NGHTTP3_ERR_QPACK_DECODER_STREAM_ERROR` 654 * |n| is too large. 655 */ 656 int nghttp3_qpack_encoder_add_icnt(nghttp3_qpack_encoder *encoder, uint64_t n); 657 658 /* 659 * `nghttp3_qpack_encoder_cancel_stream` tells |encoder| that stream 660 * denoted by |stream_id| is cancelled. This function is provided for 661 * debugging purpose only. In HTTP/3, |encoder| knows this by reading 662 * decoder stream with `nghttp3_qpack_encoder_read_decoder()`. 663 */ 664 void nghttp3_qpack_encoder_cancel_stream(nghttp3_qpack_encoder *encoder, 665 int64_t stream_id); 666 667 /* 668 * nghttp3_qpack_context_dtable_get returns dynamic table entry whose 669 * absolute index is |absidx|. This function assumes that such entry 670 * exists. 671 */ 672 nghttp3_qpack_entry * 673 nghttp3_qpack_context_dtable_get(nghttp3_qpack_context *ctx, uint64_t absidx); 674 675 /* 676 * nghttp3_qpack_context_dtable_top returns latest dynamic table 677 * entry. This function assumes dynamic table is not empty. 678 */ 679 nghttp3_qpack_entry * 680 nghttp3_qpack_context_dtable_top(nghttp3_qpack_context *ctx); 681 682 /* 683 * nghttp3_qpack_entry_init initializes |ent|. |qnv| is a header 684 * field. |sum| is the sum of table space occupied by all entries 685 * inserted so far. It does not include this entry. |absidx| is an 686 * absolute index of this entry. |hash| is a hash of header field 687 * name. This function increases reference count of qnv->nv.name and 688 * qnv->nv.value. 689 */ 690 void nghttp3_qpack_entry_init(nghttp3_qpack_entry *ent, nghttp3_qpack_nv *qnv, 691 size_t sum, uint64_t absidx, uint32_t hash); 692 693 /* 694 * nghttp3_qpack_entry_free frees memory allocated for |ent|. 695 */ 696 void nghttp3_qpack_entry_free(nghttp3_qpack_entry *ent); 697 698 /* 699 * nghttp3_qpack_put_varint_len returns the required number of bytes 700 * to encode |n| with |prefix| bits. 701 */ 702 size_t nghttp3_qpack_put_varint_len(uint64_t n, size_t prefix); 703 704 /* 705 * nghttp3_qpack_put_varint encodes |n| using variable integer 706 * encoding with |prefix| bits into |buf|. This function assumes the 707 * buffer pointed by |buf| has enough space. This function returns 708 * the one byte beyond the last write (buf + 709 * nghttp3_qpack_put_varint_len(n, prefix)). 710 */ 711 uint8_t *nghttp3_qpack_put_varint(uint8_t *buf, uint64_t n, size_t prefix); 712 713 /* nghttp3_qpack_encoder_stream_state is a set of states for encoder 714 stream decoding. */ 715 typedef enum nghttp3_qpack_encoder_stream_state { 716 NGHTTP3_QPACK_ES_STATE_OPCODE, 717 NGHTTP3_QPACK_ES_STATE_READ_INDEX, 718 NGHTTP3_QPACK_ES_STATE_CHECK_NAME_HUFFMAN, 719 NGHTTP3_QPACK_ES_STATE_READ_NAMELEN, 720 NGHTTP3_QPACK_ES_STATE_READ_NAME_HUFFMAN, 721 NGHTTP3_QPACK_ES_STATE_READ_NAME, 722 NGHTTP3_QPACK_ES_STATE_CHECK_VALUE_HUFFMAN, 723 NGHTTP3_QPACK_ES_STATE_READ_VALUELEN, 724 NGHTTP3_QPACK_ES_STATE_READ_VALUE_HUFFMAN, 725 NGHTTP3_QPACK_ES_STATE_READ_VALUE, 726 } nghttp3_qpack_encoder_stream_state; 727 728 /* nghttp3_qpack_encoder_stream_opcode is a set of opcodes used in 729 encoder stream. */ 730 typedef enum nghttp3_qpack_encoder_stream_opcode { 731 NGHTTP3_QPACK_ES_OPCODE_INSERT_INDEXED, 732 NGHTTP3_QPACK_ES_OPCODE_INSERT, 733 NGHTTP3_QPACK_ES_OPCODE_DUPLICATE, 734 NGHTTP3_QPACK_ES_OPCODE_SET_DTABLE_CAP, 735 } nghttp3_qpack_encoder_stream_opcode; 736 737 /* nghttp3_qpack_request_stream_state is a set of states for request 738 stream decoding. */ 739 typedef enum nghttp3_qpack_request_stream_state { 740 NGHTTP3_QPACK_RS_STATE_RICNT, 741 NGHTTP3_QPACK_RS_STATE_DBASE_SIGN, 742 NGHTTP3_QPACK_RS_STATE_DBASE, 743 NGHTTP3_QPACK_RS_STATE_OPCODE, 744 NGHTTP3_QPACK_RS_STATE_READ_INDEX, 745 NGHTTP3_QPACK_RS_STATE_CHECK_NAME_HUFFMAN, 746 NGHTTP3_QPACK_RS_STATE_READ_NAMELEN, 747 NGHTTP3_QPACK_RS_STATE_READ_NAME_HUFFMAN, 748 NGHTTP3_QPACK_RS_STATE_READ_NAME, 749 NGHTTP3_QPACK_RS_STATE_CHECK_VALUE_HUFFMAN, 750 NGHTTP3_QPACK_RS_STATE_READ_VALUELEN, 751 NGHTTP3_QPACK_RS_STATE_READ_VALUE_HUFFMAN, 752 NGHTTP3_QPACK_RS_STATE_READ_VALUE, 753 NGHTTP3_QPACK_RS_STATE_BLOCKED, 754 } nghttp3_qpack_request_stream_state; 755 756 /* nghttp3_qpack_request_stream_opcode is a set of opcodes used in 757 request stream. */ 758 typedef enum nghttp3_qpack_request_stream_opcode { 759 NGHTTP3_QPACK_RS_OPCODE_INDEXED, 760 NGHTTP3_QPACK_RS_OPCODE_INDEXED_PB, 761 NGHTTP3_QPACK_RS_OPCODE_INDEXED_NAME, 762 NGHTTP3_QPACK_RS_OPCODE_INDEXED_NAME_PB, 763 NGHTTP3_QPACK_RS_OPCODE_LITERAL, 764 } nghttp3_qpack_request_stream_opcode; 765 766 struct nghttp3_qpack_decoder { 767 nghttp3_qpack_context ctx; 768 /* state is a current state of reading encoder stream. */ 769 nghttp3_qpack_encoder_stream_state state; 770 /* opcode is an encoder stream opcode being processed. */ 771 nghttp3_qpack_encoder_stream_opcode opcode; 772 /* rstate is a set of intermediate state which are used to process 773 encoder stream. */ 774 nghttp3_qpack_read_state rstate; 775 /* dbuf is decoder stream. */ 776 nghttp3_buf dbuf; 777 /* written_icnt is Insert Count written to decoder stream so far. */ 778 uint64_t written_icnt; 779 /* max_concurrent_streams is the number of concurrent streams that a 780 remote endpoint can open, including both bidirectional and 781 unidirectional streams which potentially receives QPACK encoded 782 HEADER frame. */ 783 size_t max_concurrent_streams; 784 }; 785 786 /* 787 * nghttp3_qpack_decoder_init initializes |decoder|. 788 * |max_dtable_capacity| is the maximum size of dynamic table. 789 * |max_blocked_streams| is the maximum number of stream which can be 790 * blocked. |mem| is a memory allocator. 791 * 792 * This function returns 0 if it succeeds, or one of the following 793 * negative error codes: 794 * 795 * NGHTTP3_ERR_NOMEM 796 * Out of memory. 797 */ 798 int nghttp3_qpack_decoder_init(nghttp3_qpack_decoder *decoder, 799 size_t max_dtable_capacity, 800 size_t max_blocked_streams, 801 const nghttp3_mem *mem); 802 803 /* 804 * nghttp3_qpack_decoder_free frees memory allocated for |decoder|. 805 * This function does not free memory pointed by |decoder|. 806 */ 807 void nghttp3_qpack_decoder_free(nghttp3_qpack_decoder *decoder); 808 809 /* 810 * nghttp3_qpack_decoder_dtable_indexed_add adds entry received in 811 * Insert With Name Reference to dynamic table. 812 * 813 * This function returns 0 if it succeeds, or one of the following 814 * negative error codes: 815 * 816 * NGHTTP3_ERR_NOMEM 817 * Out of memory. 818 * NGHTTP3_ERR_QPACK_ENCODER_STREAM 819 * Space required for a decoded entry exceeds max dynamic table 820 * size. 821 */ 822 int nghttp3_qpack_decoder_dtable_indexed_add(nghttp3_qpack_decoder *decoder); 823 824 /* 825 * nghttp3_qpack_decoder_dtable_static_add adds entry received in 826 * Insert With Name Reference (static) to dynamic table. 827 * 828 * This function returns 0 if it succeeds, or one of the following 829 * negative error codes: 830 * 831 * NGHTTP3_ERR_NOMEM 832 * Out of memory. 833 * NGHTTP3_ERR_QPACK_ENCODER_STREAM 834 * Space required for a decoded entry exceeds max dynamic table 835 * size. 836 */ 837 int nghttp3_qpack_decoder_dtable_static_add(nghttp3_qpack_decoder *decoder); 838 839 /* 840 * nghttp3_qpack_decoder_dtable_dynamic_add adds entry received in 841 * Insert With Name Reference (dynamic) to dynamic table. 842 * 843 * This function returns 0 if it succeeds, or one of the following 844 * negative error codes: 845 * 846 * NGHTTP3_ERR_NOMEM 847 * Out of memory. 848 * NGHTTP3_ERR_QPACK_ENCODER_STREAM 849 * Space required for a decoded entry exceeds max dynamic table 850 * size. 851 */ 852 int nghttp3_qpack_decoder_dtable_dynamic_add(nghttp3_qpack_decoder *decoder); 853 854 /* 855 * nghttp3_qpack_decoder_dtable_duplicate_add adds entry received in 856 * Duplicate to dynamic table. 857 * 858 * This function returns 0 if it succeeds, or one of the following 859 * negative error codes: 860 * 861 * NGHTTP3_ERR_NOMEM 862 * Out of memory. 863 * NGHTTP3_ERR_QPACK_ENCODER_STREAM 864 * Space required for a decoded entry exceeds max dynamic table 865 * size. 866 */ 867 int nghttp3_qpack_decoder_dtable_duplicate_add(nghttp3_qpack_decoder *decoder); 868 869 /* 870 * nghttp3_qpack_decoder_dtable_literal_add adds entry received in 871 * Insert With Literal Name to dynamic table. 872 * 873 * This function returns 0 if it succeeds, or one of the following 874 * negative error codes: 875 * 876 * NGHTTP3_ERR_NOMEM 877 * Out of memory. 878 * NGHTTP3_ERR_QPACK_ENCODER_STREAM 879 * Space required for a decoded entry exceeds max dynamic table 880 * size. 881 */ 882 int nghttp3_qpack_decoder_dtable_literal_add(nghttp3_qpack_decoder *decoder); 883 884 struct nghttp3_qpack_stream_context { 885 /* state is a current state of reading request stream. */ 886 nghttp3_qpack_request_stream_state state; 887 /* rstate is a set of intermediate state which are used to process 888 request stream. */ 889 nghttp3_qpack_read_state rstate; 890 const nghttp3_mem *mem; 891 /* opcode is a request stream opcode being processed. */ 892 nghttp3_qpack_request_stream_opcode opcode; 893 int64_t stream_id; 894 /* ricnt is Required Insert Count to decode this header block. */ 895 uint64_t ricnt; 896 /* base is Base in Header Block Prefix. */ 897 uint64_t base; 898 /* dbase_sign is the delta base sign in Header Block Prefix. */ 899 int dbase_sign; 900 }; 901 902 /* 903 * nghttp3_qpack_stream_context_init initializes |sctx|. 904 */ 905 void nghttp3_qpack_stream_context_init(nghttp3_qpack_stream_context *sctx, 906 int64_t stream_id, 907 const nghttp3_mem *mem); 908 909 /* 910 * nghttp3_qpack_stream_context_free frees memory allocated for 911 * |sctx|. This function does not free memory pointed by |sctx|. 912 */ 913 void nghttp3_qpack_stream_context_free(nghttp3_qpack_stream_context *sctx); 914 915 /* 916 * nghttp3_qpack_decoder_reconstruct_ricnt reconstructs Required 917 * Insert Count from the encoded form |encricnt| and stores Required 918 * Insert Count in |*dest|. 919 * 920 * This function returns 0 if it succeeds, or one of the following 921 * negative error codes: 922 * 923 * NGHTTP3_ERR_QPACK_DECOMPRESSION_FAILED 924 * Unable to reconstruct Required Insert Count. 925 */ 926 int nghttp3_qpack_decoder_reconstruct_ricnt(nghttp3_qpack_decoder *decoder, 927 uint64_t *dest, uint64_t encricnt); 928 929 /* 930 * nghttp3_qpack_decoder_rel2abs converts relative index rstate->left 931 * received in encoder stream to absolute index and stores it in 932 * rstate->absidx. 933 * 934 * This function returns 0 if it succeeds, or one of the following 935 * negative error codes: 936 * 937 * NGHTTP3_ERR_QPACK_ENCODER_STREAM 938 * Relative index is invalid. 939 */ 940 int nghttp3_qpack_decoder_rel2abs(nghttp3_qpack_decoder *decoder, 941 nghttp3_qpack_read_state *rstate); 942 943 /* 944 * nghttp3_qpack_decoder_brel2abs converts Base relative index 945 * rstate->left received in request stream to absolute index and 946 * stores it in rstate->absidx. 947 * 948 * This function returns 0 if it succeeds, or one of the following 949 * negative error codes: 950 * 951 * NGHTTP3_ERR_QPACK_DECOMPRESSION_FAILED 952 * Base relative index is invalid. 953 */ 954 int nghttp3_qpack_decoder_brel2abs(nghttp3_qpack_decoder *decoder, 955 nghttp3_qpack_stream_context *sctx); 956 957 /* 958 * nghttp3_qpack_decoder_pbrel2abs converts Post-Base relative index 959 * rstate->left received in request stream to absolute index and 960 * stores it in rstate->absidx. 961 * 962 * This function returns 0 if it succeeds, or one of the following 963 * negative error codes: 964 * 965 * NGHTTP3_ERR_QPACK_DECOMPRESSION_FAILED 966 * Post-Base relative index is invalid. 967 */ 968 int nghttp3_qpack_decoder_pbrel2abs(nghttp3_qpack_decoder *decoder, 969 nghttp3_qpack_stream_context *sctx); 970 971 void nghttp3_qpack_decoder_emit_indexed(nghttp3_qpack_decoder *decoder, 972 nghttp3_qpack_stream_context *sctx, 973 nghttp3_qpack_nv *nv); 974 975 void nghttp3_qpack_decoder_emit_indexed_name(nghttp3_qpack_decoder *decoder, 976 nghttp3_qpack_stream_context *sctx, 977 nghttp3_qpack_nv *nv); 978 979 void nghttp3_qpack_decoder_emit_literal(nghttp3_qpack_decoder *decoder, 980 nghttp3_qpack_stream_context *sctx, 981 nghttp3_qpack_nv *nv); 982 983 /* 984 * nghttp3_qpack_decoder_write_section_ack writes Section 985 * Acknowledgement to decoder stream. 986 * 987 * This function returns 0 if it succeeds, or one of the following 988 * negative error codes: 989 * 990 * NGHTTP3_ERR_NOMEM 991 * Out of memory. 992 * NGHTTP3_ERR_QPACK_FATAL 993 * Decoder stream overflow. 994 */ 995 int nghttp3_qpack_decoder_write_section_ack( 996 nghttp3_qpack_decoder *decoder, const nghttp3_qpack_stream_context *sctx); 997 998 #endif /* NGHTTP3_QPACK_H */ 999