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