143a63c18SDmitri Tikhonov/*
243a63c18SDmitri Tikhonov * lsqpack.h - QPACK library
343a63c18SDmitri Tikhonov */
443a63c18SDmitri Tikhonov
543a63c18SDmitri Tikhonov/*
643a63c18SDmitri TikhonovMIT License
743a63c18SDmitri Tikhonov
8ecccd919SGeorge WangCopyright (c) 2018 - 2022 LiteSpeed Technologies Inc
943a63c18SDmitri Tikhonov
1043a63c18SDmitri TikhonovPermission is hereby granted, free of charge, to any person obtaining a copy
1143a63c18SDmitri Tikhonovof this software and associated documentation files (the "Software"), to deal
1243a63c18SDmitri Tikhonovin the Software without restriction, including without limitation the rights
1343a63c18SDmitri Tikhonovto use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1443a63c18SDmitri Tikhonovcopies of the Software, and to permit persons to whom the Software is
1543a63c18SDmitri Tikhonovfurnished to do so, subject to the following conditions:
1643a63c18SDmitri Tikhonov
1743a63c18SDmitri TikhonovThe above copyright notice and this permission notice shall be included in all
1843a63c18SDmitri Tikhonovcopies or substantial portions of the Software.
1943a63c18SDmitri Tikhonov
2043a63c18SDmitri TikhonovTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2143a63c18SDmitri TikhonovIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2243a63c18SDmitri TikhonovFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
2343a63c18SDmitri TikhonovAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2443a63c18SDmitri TikhonovLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2543a63c18SDmitri TikhonovOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2643a63c18SDmitri TikhonovSOFTWARE.
2743a63c18SDmitri Tikhonov*/
2843a63c18SDmitri Tikhonov
2943a63c18SDmitri Tikhonov#ifndef LSQPACK_H
3043a63c18SDmitri Tikhonov#define LSQPACK_H 1
3143a63c18SDmitri Tikhonov
3243a63c18SDmitri Tikhonov#ifdef __cplusplus
3343a63c18SDmitri Tikhonovextern "C" {
3443a63c18SDmitri Tikhonov#endif
3543a63c18SDmitri Tikhonov
36a122a7bdSDmitri Tikhonov#include <limits.h>
3743a63c18SDmitri Tikhonov#include <stdint.h>
38dc162d4eSDmitri Tikhonov#include <stdio.h>
3943a63c18SDmitri Tikhonov
40205a2804SDmitri Tikhonov#if defined(_MSC_VER)
41205a2804SDmitri Tikhonov#include <BaseTsd.h>
42205a2804SDmitri Tikhonovtypedef SSIZE_T ssize_t;
43205a2804SDmitri Tikhonov#endif
44205a2804SDmitri Tikhonov
4560620859SDmitri Tikhonov#define LSQPACK_MAJOR_VERSION 2
46ecccd919SGeorge Wang#define LSQPACK_MINOR_VERSION 3
47ecccd919SGeorge Wang#define LSQPACK_PATCH_VERSION 0
48c16eb90bSDmitri Tikhonov
4943a63c18SDmitri Tikhonov/** Let's start with four billion for now */
5043a63c18SDmitri Tikhonovtypedef unsigned lsqpack_abs_id_t;
5143a63c18SDmitri Tikhonov
528eecc05bSDmitri Tikhonov#define LSQPACK_MAX_ABS_ID (~((lsqpack_abs_id_t) 0))
538eecc05bSDmitri Tikhonov
54ee20de75SDmitri Tikhonov#define LSQPACK_DEF_DYN_TABLE_SIZE      0
55ee20de75SDmitri Tikhonov#define LSQPACK_DEF_MAX_RISKED_STREAMS  0
566b87e695SDmitri Tikhonov
5743a63c18SDmitri Tikhonovstruct lsqpack_enc;
585989f779SDmitri Tikhonovstruct lsqpack_dec;
5960620859SDmitri Tikhonovstruct lsxpack_header;
605989f779SDmitri Tikhonov
61f3eec0d9SDmitri Tikhonovenum lsqpack_enc_opts
62f3eec0d9SDmitri Tikhonov{
63f3eec0d9SDmitri Tikhonov    /**
64f3eec0d9SDmitri Tikhonov     * Client and server follow different heuristics.  The encoder is either
65f3eec0d9SDmitri Tikhonov     * in one or the other mode.
6615bcefabSDmitri Tikhonov     *
6715bcefabSDmitri Tikhonov     * At the moment this option is a no-op.  This is a potential future
6815bcefabSDmitri Tikhonov     * work item where some heuristics may be added to the library.
69f3eec0d9SDmitri Tikhonov     */
70f3eec0d9SDmitri Tikhonov    LSQPACK_ENC_OPT_SERVER  = 1 << 0,
71f3eec0d9SDmitri Tikhonov
72f3eec0d9SDmitri Tikhonov    /**
7307831cdfSDmitri Tikhonov     * The encoder was pre-initialized using @ref lsqpack_enc_preinit() and
7407831cdfSDmitri Tikhonov     * so some initialization steps can be skipped.
7507831cdfSDmitri Tikhonov     */
7607831cdfSDmitri Tikhonov    LSQPACK_ENC_OPT_STAGE_2 = 1 << 1,
7707831cdfSDmitri Tikhonov
7807831cdfSDmitri Tikhonov    /* The options below are advanced.  The author only uses them for debugging
7907831cdfSDmitri Tikhonov     * or testing.
80f3eec0d9SDmitri Tikhonov     */
818fb62aa5SDmitri Tikhonov
828fb62aa5SDmitri Tikhonov    /**
8307831cdfSDmitri Tikhonov     * Disable emitting dup instructions.
8407831cdfSDmitri Tikhonov     *
8507831cdfSDmitri Tikhonov     * Disabling dup instructions usually makes compression performance
8607831cdfSDmitri Tikhonov     * significanly worse.  Do not use unless you know what you are doing.
878fb62aa5SDmitri Tikhonov     */
8807831cdfSDmitri Tikhonov    LSQPACK_ENC_OPT_NO_DUP  = 1 << 2,
890d818d0fSDmitri Tikhonov
900d818d0fSDmitri Tikhonov    /**
9107831cdfSDmitri Tikhonov     * Index aggressively: ignore history
9207831cdfSDmitri Tikhonov     *
9307831cdfSDmitri Tikhonov     * Ignoring history usually makes compression performance significanly
9407831cdfSDmitri Tikhonov     * worse.  Do not use unless you know what you are doing.
950d818d0fSDmitri Tikhonov     */
9607831cdfSDmitri Tikhonov    LSQPACK_ENC_OPT_IX_AGGR = 1 << 3,
97ecec593fSDmitri Tikhonov
98ecec593fSDmitri Tikhonov    /**
99ecec593fSDmitri Tikhonov     * Turn off memory guard: keep on allocating state tracking oustanding
100ecec593fSDmitri Tikhonov     * headers even if they never get acknowledged.
101ecec593fSDmitri Tikhonov     *
102ecec593fSDmitri Tikhonov     * This is useful for some forms of testing.
103ecec593fSDmitri Tikhonov     */
104ecec593fSDmitri Tikhonov    LSQPACK_ENC_OPT_NO_MEM_GUARD = 1 << 4,
105f3eec0d9SDmitri Tikhonov};
106f3eec0d9SDmitri Tikhonov
1070d818d0fSDmitri Tikhonov
1080d818d0fSDmitri Tikhonov/**
1090d818d0fSDmitri Tikhonov * Initialize the encoder so that it can be used without using the
1100d818d0fSDmitri Tikhonov * dynamic table.  Once peer's settings are known, call
1110d818d0fSDmitri Tikhonov * @ref lsqpack_enc_init().
1126686ad13SDmitri Tikhonov *
1136686ad13SDmitri Tikhonov * `logger_ctx' can be set to NULL if no special logging is set up.
1140d818d0fSDmitri Tikhonov */
1150d818d0fSDmitri Tikhonovvoid
1166686ad13SDmitri Tikhonovlsqpack_enc_preinit (struct lsqpack_enc *, void *logger_ctx);
1170d818d0fSDmitri Tikhonov
1188624e82bSDmitri Tikhonov/**
119a122a7bdSDmitri Tikhonov * Number of bytes required to encode the longest possible Set Dynamic Table
120a122a7bdSDmitri Tikhonov * Capacity instruction.  This is a theoretical limit based on the integral
121a122a7bdSDmitri Tikhonov * type (unsigned int) used by this library to store the capacity value.  If
122a122a7bdSDmitri Tikhonov * the encoder is initialized with a smaller maximum table capacity, it is
123a122a7bdSDmitri Tikhonov * safe to use fewer bytes.
124a122a7bdSDmitri Tikhonov *
1256e082c27SDmitri Tikhonov * SDTC instructtion can be produced by @ref lsqpack_enc_init() and
1266e082c27SDmitri Tikhonov * @ref lsqpack_enc_set_max_capacity().
1278624e82bSDmitri Tikhonov */
128a122a7bdSDmitri Tikhonov#if UINT_MAX == 65535
129a122a7bdSDmitri Tikhonov#define LSQPACK_LONGEST_SDTC 4
130a122a7bdSDmitri Tikhonov#elif UINT_MAX == 4294967295
131a122a7bdSDmitri Tikhonov#define LSQPACK_LONGEST_SDTC 6
13218758f49SDmitri Tikhonov#elif UINT_MAX == 18446744073709551615ULL
133a122a7bdSDmitri Tikhonov#define LSQPACK_LONGEST_SDTC 11
134a122a7bdSDmitri Tikhonov#else
135a122a7bdSDmitri Tikhonov#error unexpected sizeof(unsigned)
136a122a7bdSDmitri Tikhonov#endif
1378624e82bSDmitri Tikhonov
13843a63c18SDmitri Tikhonovint
13964096c11SDmitri Tikhonovlsqpack_enc_init (struct lsqpack_enc *,
1406686ad13SDmitri Tikhonov    /** `logger_ctx' can be set to NULL if no special logging is set up. */
1416686ad13SDmitri Tikhonov    void *logger_ctx,
14264096c11SDmitri Tikhonov    /**
14364096c11SDmitri Tikhonov     * As specified by the decoder.  This value is used to calculate
14464096c11SDmitri Tikhonov     * MaxEntries.
14564096c11SDmitri Tikhonov     */
14664096c11SDmitri Tikhonov    unsigned max_table_size,
14764096c11SDmitri Tikhonov    /**
14864096c11SDmitri Tikhonov     * Actual dynamic table size to use.
14964096c11SDmitri Tikhonov     */
15064096c11SDmitri Tikhonov    unsigned dyn_table_size,
1518624e82bSDmitri Tikhonov    unsigned max_risked_streams, enum lsqpack_enc_opts,
1528624e82bSDmitri Tikhonov    /**
153a122a7bdSDmitri Tikhonov     * If `dyn_table_size' is not zero, Set Dynamic Table Capacity (SDTC)
154a122a7bdSDmitri Tikhonov     * instruction is generated and placed into `sdtc_buf'.  `sdtc_buf_sz'
155a122a7bdSDmitri Tikhonov     * parameter is used both for input and output.
1568624e82bSDmitri Tikhonov     *
157a122a7bdSDmitri Tikhonov     * If `dyn_table_size' is zero, `sdtc_buf' and `sdtc_buf_sz' are optional
158a122a7bdSDmitri Tikhonov     * and can be set to NULL.
1598624e82bSDmitri Tikhonov     */
160b4deb1a5SDmitri Tikhonov    unsigned char *sdtc_buf, size_t *sdtc_buf_sz);
161f3eec0d9SDmitri Tikhonov
1628624e82bSDmitri Tikhonov/**
163a122a7bdSDmitri Tikhonov * Set table size to `capacity'.  If necessary, Set Dynamic Table Capacity
164a122a7bdSDmitri Tikhonov * (SDTC) instruction is generated and placed into `tsu_buf'.  If `capacity'
165a122a7bdSDmitri Tikhonov * is larger than the maximum table size specified during initialization, an
166a122a7bdSDmitri Tikhonov * error is returned.
1678624e82bSDmitri Tikhonov */
1688624e82bSDmitri Tikhonovint
1698624e82bSDmitri Tikhonovlsqpack_enc_set_max_capacity (struct lsqpack_enc *enc, unsigned capacity,
170a122a7bdSDmitri Tikhonov                                    unsigned char *sdtc_buf, size_t *sdtc_buf_sz);
17143a63c18SDmitri Tikhonov
172f23744beSDmitri Tikhonov/** Start a new header block.  Return 0 on success or -1 on error. */
17343a63c18SDmitri Tikhonovint
17443a63c18SDmitri Tikhonovlsqpack_enc_start_header (struct lsqpack_enc *, uint64_t stream_id,
17543a63c18SDmitri Tikhonov                            unsigned seqno);
17643a63c18SDmitri Tikhonov
1776e082c27SDmitri Tikhonov/** Status returned by @ref lsqpack_enc_encode() */
17843a63c18SDmitri Tikhonovenum lsqpack_enc_status
17943a63c18SDmitri Tikhonov{
180a122a7bdSDmitri Tikhonov    /** Header field encoded successfully */
18143a63c18SDmitri Tikhonov    LQES_OK,
182a122a7bdSDmitri Tikhonov    /** There was not enough room in the encoder stream buffer */
18343a63c18SDmitri Tikhonov    LQES_NOBUF_ENC,
184a122a7bdSDmitri Tikhonov    /** There was not enough room in the header block buffer */
18543a63c18SDmitri Tikhonov    LQES_NOBUF_HEAD,
18643a63c18SDmitri Tikhonov};
18743a63c18SDmitri Tikhonov
188c30ffe13SDmitri Tikhonovenum lsqpack_enc_flags
189c30ffe13SDmitri Tikhonov{
19077647c9cSDmitri Tikhonov    /**
19177647c9cSDmitri Tikhonov     * Do not index this header field.  No output to the encoder stream
19277647c9cSDmitri Tikhonov     * will be produced.
19377647c9cSDmitri Tikhonov     */
19477647c9cSDmitri Tikhonov    LQEF_NO_INDEX    = 1 << 0,
19577647c9cSDmitri Tikhonov    /**
19677647c9cSDmitri Tikhonov     * Never index this field.  This will set the 'N' bit on Literal Header
19777647c9cSDmitri Tikhonov     * Field With Name Reference, Literal Header Field With Post-Base Name
19877647c9cSDmitri Tikhonov     * Reference, and Literal Header Field Without Name Reference instructions
1994220db22SDmitri Tikhonov     * in the header block.  Implies LQEF_NO_INDEX.
20077647c9cSDmitri Tikhonov     */
20177647c9cSDmitri Tikhonov    LQEF_NEVER_INDEX = 1 << 1,
20202c4e282SDmitri Tikhonov    /**
20302c4e282SDmitri Tikhonov     * Do not update history.
20402c4e282SDmitri Tikhonov     */
20502c4e282SDmitri Tikhonov    LQEF_NO_HIST_UPD = 1 << 2,
20602c4e282SDmitri Tikhonov    /**
20702c4e282SDmitri Tikhonov     * Do not use the dynamic table.  This is stricter than LQEF_NO_INDEX:
20802c4e282SDmitri Tikhonov     * this means that the dynamic table will be neither referenced nor
20902c4e282SDmitri Tikhonov     * modified.
21002c4e282SDmitri Tikhonov     */
21102c4e282SDmitri Tikhonov    LQEF_NO_DYN      = 1 << 3,
212c30ffe13SDmitri Tikhonov};
213c30ffe13SDmitri Tikhonov
21443a63c18SDmitri Tikhonov/**
215a122a7bdSDmitri Tikhonov * Encode header field into current header block.
216a122a7bdSDmitri Tikhonov *
217a122a7bdSDmitri Tikhonov * See @ref lsqpack_enc_status for explanation of the return values.
2181c8b6a70SDmitri Tikhonov *
2191c8b6a70SDmitri Tikhonov * enc_sz and header_sz parameters are used for both input and output.  If
2201c8b6a70SDmitri Tikhonov * the return value is LQES_OK, they contain number of bytes written to
22135d8b99eSDmitri Tikhonov * enc_buf and header_buf, respectively.  enc_buf contains the bytes that
22235d8b99eSDmitri Tikhonov * must be written to the encoder stream; header_buf contains bytes that
22335d8b99eSDmitri Tikhonov * must be written to the header block.
224a122a7bdSDmitri Tikhonov *
225a122a7bdSDmitri Tikhonov * Note that even though this function may allocate memory, it falls back to
226a122a7bdSDmitri Tikhonov * not using the dynamic table should memory allocation fail.  Thus, failures
227a122a7bdSDmitri Tikhonov * to encode due to not enough memory do not exist.
22843a63c18SDmitri Tikhonov */
22943a63c18SDmitri Tikhonovenum lsqpack_enc_status
23043a63c18SDmitri Tikhonovlsqpack_enc_encode (struct lsqpack_enc *,
2311c8b6a70SDmitri Tikhonov    unsigned char *enc_buf, size_t *enc_sz,
2321c8b6a70SDmitri Tikhonov    unsigned char *header_buf, size_t *header_sz,
23360620859SDmitri Tikhonov    const struct lsxpack_header *,
23460620859SDmitri Tikhonov    enum lsqpack_enc_flags flags);
23543a63c18SDmitri Tikhonov
23643a63c18SDmitri Tikhonov/**
237d4822b2bSDaan De Meyer * Cancel current header block. Cancellation is only allowed if the dynamic
238d4822b2bSDaan De Meyer * table is not used. Returns 0 on success, -1 on failure.
239d4822b2bSDaan De Meyer */
240d4822b2bSDaan De Meyerint
241d4822b2bSDaan De Meyerlsqpack_enc_cancel_header (struct lsqpack_enc *);
242d4822b2bSDaan De Meyer
2433ce33568SDmitri Tikhonov
2443ce33568SDmitri Tikhonov/**
2453ce33568SDmitri Tikhonov * Properties of the current header block
2463ce33568SDmitri Tikhonov */
2473ce33568SDmitri Tikhonovenum lsqpack_enc_header_flags
2483ce33568SDmitri Tikhonov{
2493ce33568SDmitri Tikhonov    /** Set if there are at-risk references in this header block */
2503ce33568SDmitri Tikhonov    LSQECH_REF_AT_RISK      = 1 << 0,
2513ce33568SDmitri Tikhonov    /** Set if the header block references newly inserted entries */
252147b1758SDmitri Tikhonov    LSQECH_REF_NEW_ENTRIES  = 1 << 1,
2539ef79d2cSDmitri Tikhonov    /** Set if min-reffed value is cached */
2549ef79d2cSDmitri Tikhonov    LSQECH_MINREF_CACHED    = 1 << 2,
2553ce33568SDmitri Tikhonov};
2563ce33568SDmitri Tikhonov
2573ce33568SDmitri Tikhonov
258d4822b2bSDaan De Meyer/**
259a122a7bdSDmitri Tikhonov * End current header block.  The Header Block Prefix is written to `buf'.
260a122a7bdSDmitri Tikhonov *
261a122a7bdSDmitri Tikhonov * `buf' must be at least two bytes.  11 bytes are necessary to encode
262a122a7bdSDmitri Tikhonov * UINT64_MAX using 7- or 8-bit prefix.  Therefore, 22 bytes is the
263a122a7bdSDmitri Tikhonov * theoretical maximum for this library.
264a122a7bdSDmitri Tikhonov *
2656e082c27SDmitri Tikhonov * Use @ref lsqpack_enc_header_block_prefix_size() if you require better
266a122a7bdSDmitri Tikhonov * precision.
2672a47c2feSDmitri Tikhonov *
2682a47c2feSDmitri Tikhonov * Returns:
269a122a7bdSDmitri Tikhonov *  -   A positive value indicates success and is the number of bytes
2702a47c2feSDmitri Tikhonov *      written to `buf'.
2712a47c2feSDmitri Tikhonov *  -   Zero means that there is not enough room in `buf' to write out the
2722a47c2feSDmitri Tikhonov *      full prefix.
2732a47c2feSDmitri Tikhonov *  -   A negative value means an error.  This is returned if there is no
2742a47c2feSDmitri Tikhonov *      started header to end.
2753ce33568SDmitri Tikhonov *
2763ce33568SDmitri Tikhonov * If header was ended successfully and @ref flags is not NULL, it is
2773ce33568SDmitri Tikhonov * assigned properties of the header block.
27843a63c18SDmitri Tikhonov */
279f23744beSDmitri Tikhonovssize_t
2803ce33568SDmitri Tikhonovlsqpack_enc_end_header (struct lsqpack_enc *, unsigned char *buf, size_t,
2813ce33568SDmitri Tikhonov    enum lsqpack_enc_header_flags *flags /* Optional */);
28243a63c18SDmitri Tikhonov
2830dc575feSDmitri Tikhonov/**
284471f84fdSDmitri Tikhonov * Process next chunk of bytes from the decoder stream.  Returns 0 on success,
285471f84fdSDmitri Tikhonov * -1 on failure.  The failure should be treated as fatal.
2860dc575feSDmitri Tikhonov */
2870dc575feSDmitri Tikhonovint
288471f84fdSDmitri Tikhonovlsqpack_enc_decoder_in (struct lsqpack_enc *, const unsigned char *, size_t);
2890dc575feSDmitri Tikhonov
2901678c8a4SDmitri Tikhonov/**
2911678c8a4SDmitri Tikhonov * Return estimated compression ratio until this point.  Compression ratio
292490aea6cSDmitri Tikhonov * is defined as size of the output divided by the size of the input, where
293490aea6cSDmitri Tikhonov * output includes both header blocks and instructions sent on the encoder
294490aea6cSDmitri Tikhonov * stream.
2951678c8a4SDmitri Tikhonov */
2961678c8a4SDmitri Tikhonovfloat
2971678c8a4SDmitri Tikhonovlsqpack_enc_ratio (const struct lsqpack_enc *);
2981678c8a4SDmitri Tikhonov
299e64d77fdSDmitri Tikhonov/**
300a122a7bdSDmitri Tikhonov * Return maximum size needed to encode Header Block Prefix
301e64d77fdSDmitri Tikhonov */
302e64d77fdSDmitri Tikhonovsize_t
303a122a7bdSDmitri Tikhonovlsqpack_enc_header_block_prefix_size (const struct lsqpack_enc *);
304e64d77fdSDmitri Tikhonov
30543a63c18SDmitri Tikhonovvoid
30643a63c18SDmitri Tikhonovlsqpack_enc_cleanup (struct lsqpack_enc *);
30743a63c18SDmitri Tikhonov
30860620859SDmitri Tikhonov/** Decoder header set interface */
30960620859SDmitri Tikhonovstruct lsqpack_dec_hset_if
3105989f779SDmitri Tikhonov{
31160620859SDmitri Tikhonov    void    (*dhi_unblocked)(void *hblock_ctx);
31260620859SDmitri Tikhonov    struct lsxpack_header *
31360620859SDmitri Tikhonov            (*dhi_prepare_decode)(void *hblock_ctx,
31460620859SDmitri Tikhonov                                  struct lsxpack_header *, size_t space);
31560620859SDmitri Tikhonov    int     (*dhi_process_header)(void *hblock_ctx, struct lsxpack_header *);
3165989f779SDmitri Tikhonov};
3175989f779SDmitri Tikhonov
31860620859SDmitri Tikhonovenum lsqpack_dec_opts
3195989f779SDmitri Tikhonov{
32060620859SDmitri Tikhonov    /**
32160620859SDmitri Tikhonov     * In this mode, returned lsxpack_header will contain ": " between
32260620859SDmitri Tikhonov     * name and value strings and have "\r\n" after the value.
32360620859SDmitri Tikhonov     */
32460620859SDmitri Tikhonov    LSQPACK_DEC_OPT_HTTP1X          = 1 << 0,
32560620859SDmitri Tikhonov    /** Include name hash into lsxpack_header */
32660620859SDmitri Tikhonov    LSQPACK_DEC_OPT_HASH_NAME       = 1 << 1,
32760620859SDmitri Tikhonov    /** Include nameval hash into lsxpack_header */
32860620859SDmitri Tikhonov    LSQPACK_DEC_OPT_HASH_NAMEVAL    = 1 << 2,
3295989f779SDmitri Tikhonov};
3305989f779SDmitri Tikhonov
331a5cdaf71SDmitri Tikhonovvoid
3326686ad13SDmitri Tikhonovlsqpack_dec_init (struct lsqpack_dec *, void *logger_ctx,
3336686ad13SDmitri Tikhonov    unsigned dyn_table_size, unsigned max_risked_streams,
33460620859SDmitri Tikhonov    const struct lsqpack_dec_hset_if *, enum lsqpack_dec_opts);
33575f5f4c1SDmitri Tikhonov
3366e082c27SDmitri Tikhonov/**
3376e082c27SDmitri Tikhonov * Values returned by @ref lsqpack_dec_header_in() and
3386e082c27SDmitri Tikhonov * @ref lsqpack_dec_header_read()
3396e082c27SDmitri Tikhonov */
34075f5f4c1SDmitri Tikhonovenum lsqpack_read_header_status
34175f5f4c1SDmitri Tikhonov{
3426e082c27SDmitri Tikhonov    /**
34345c0a0abSDmitri Tikhonov     * The header list has been placed in `hlist' and `buf' has been advanced.
3446e082c27SDmitri Tikhonov     * This header should be released using
34545c0a0abSDmitri Tikhonov     * @ref lsqpack_dec_destroy_header_list() after the caller is done with it.
34635d8b99eSDmitri Tikhonov     *
34745c0a0abSDmitri Tikhonov     * Note that the header list in `hlist' has an unlimited lifetime.  Even
34835d8b99eSDmitri Tikhonov     * destroying it after @ref lsqpack_dec_cleanup() is called is OK and
34935d8b99eSDmitri Tikhonov     * will not leak memory.
3506e082c27SDmitri Tikhonov     */
35175f5f4c1SDmitri Tikhonov    LQRHS_DONE,
3526e082c27SDmitri Tikhonov    /**
3536e082c27SDmitri Tikhonov     * The decoder cannot decode the header block until more dynamic table
3546e082c27SDmitri Tikhonov     * entries become available.  `buf' is advanced.  When the header block
3556e082c27SDmitri Tikhonov     * becomes unblocked, the decoder will call hblock_unblocked() callback
3566e082c27SDmitri Tikhonov     * specified in the constructor.  See @ref lsqpack_dec_init().
3576e082c27SDmitri Tikhonov     *
3586e082c27SDmitri Tikhonov     * Once a header block is unblocked, it cannot get blocked again.  In
3596e082c27SDmitri Tikhonov     * other words, this status can only be returned once per header block.
3606e082c27SDmitri Tikhonov     */
36175f5f4c1SDmitri Tikhonov    LQRHS_BLOCKED,
3626e082c27SDmitri Tikhonov    /**
3636e082c27SDmitri Tikhonov     * The decoder needs more bytes from the header block to proceed.  When
3646e082c27SDmitri Tikhonov     * they become available, call @ref lsqpack_dec_header_read().  `buf' is
3656e082c27SDmitri Tikhonov     * advanced.
3666e082c27SDmitri Tikhonov     */
36775f5f4c1SDmitri Tikhonov    LQRHS_NEED,
3686e082c27SDmitri Tikhonov    /**
3696e082c27SDmitri Tikhonov     * An error has occurred.  This can be any error: decoding error, memory
3706e082c27SDmitri Tikhonov     * allocation failure, or some internal error.
3716e082c27SDmitri Tikhonov     */
37275f5f4c1SDmitri Tikhonov    LQRHS_ERROR,
37375f5f4c1SDmitri Tikhonov};
37475f5f4c1SDmitri Tikhonov
375a122a7bdSDmitri Tikhonov/**
376a122a7bdSDmitri Tikhonov * Number of bytes needed to encode the longest Header Acknowledgement
377a122a7bdSDmitri Tikhonov * instruction.
378a122a7bdSDmitri Tikhonov */
379a122a7bdSDmitri Tikhonov#define LSQPACK_LONGEST_HEADER_ACK 10
380937be392SDmitri Tikhonov
38175f5f4c1SDmitri Tikhonov
38275f5f4c1SDmitri Tikhonov/**
38375f5f4c1SDmitri Tikhonov * Call this function when the header blocks is first read.  The decoder
3846e082c27SDmitri Tikhonov * will try to decode the header block.  The decoder can process header
3856e082c27SDmitri Tikhonov * blocks in a streaming fashion, which means that there is no need to
3866e082c27SDmitri Tikhonov * buffer the header block.  As soon as header block bytes become available,
3876e082c27SDmitri Tikhonov * they can be fed to this function or @ref lsqpack_dec_header_read().
38875f5f4c1SDmitri Tikhonov *
3896e082c27SDmitri Tikhonov * See @ref lsqpack_read_header_status for explanation of the return codes.
39075f5f4c1SDmitri Tikhonov *
39175f5f4c1SDmitri Tikhonov * If the decoder returns LQRHS_NEED or LQRHS_BLOCKED, it keeps a reference to
3926e082c27SDmitri Tikhonov * the user-provided header block context `hblock_ctx'.  It uses this value for
3936e082c27SDmitri Tikhonov * two purposes:
3946e082c27SDmitri Tikhonov *  1. to use as argument to hblock_unblocked(); and
3956e082c27SDmitri Tikhonov *  2. to locate header block state when @ref lsqpack_dec_header_read() is
3966e082c27SDmitri Tikhonov *     called.
39775f5f4c1SDmitri Tikhonov *
39875f5f4c1SDmitri Tikhonov * If the decoder returns LQRHS_DONE or LQRHS_ERROR, it means that it no
39975f5f4c1SDmitri Tikhonov * longer has a reference to the header block.
4005989f779SDmitri Tikhonov */
40175f5f4c1SDmitri Tikhonovenum lsqpack_read_header_status
4026e082c27SDmitri Tikhonovlsqpack_dec_header_in (struct lsqpack_dec *, void *hblock_ctx,
40375f5f4c1SDmitri Tikhonov                       uint64_t stream_id, size_t header_block_size,
40475f5f4c1SDmitri Tikhonov                       const unsigned char **buf, size_t bufsz,
405937be392SDmitri Tikhonov                       unsigned char *dec_buf, size_t *dec_buf_sz);
4065989f779SDmitri Tikhonov
40744e7b699SDmitri Tikhonov/**
40875f5f4c1SDmitri Tikhonov * Call this function when more header block bytes are become available
40975f5f4c1SDmitri Tikhonov * after this function or @ref lsqpack_dec_header_in() returned LQRHS_NEED
4106e082c27SDmitri Tikhonov * or hblock_unblocked() callback has been called.  This function behaves
4116e082c27SDmitri Tikhonov * similarly to @ref lsqpack_dec_header_in(): see its comments for more
4126e082c27SDmitri Tikhonov * information.
41344e7b699SDmitri Tikhonov */
41475f5f4c1SDmitri Tikhonovenum lsqpack_read_header_status
4156e082c27SDmitri Tikhonovlsqpack_dec_header_read (struct lsqpack_dec *dec, void *hblock_ctx,
41675f5f4c1SDmitri Tikhonov                         const unsigned char **buf, size_t bufsz,
417937be392SDmitri Tikhonov                         unsigned char *dec_buf, size_t *dec_buf_sz);
41844e7b699SDmitri Tikhonov
41944e7b699SDmitri Tikhonov/**
42044e7b699SDmitri Tikhonov * Feed encoder stream data to the decoder.  Zero is returned on success,
42144e7b699SDmitri Tikhonov * negative value on error.
42244e7b699SDmitri Tikhonov */
423d8424881SDmitri Tikhonovint
424d8424881SDmitri Tikhonovlsqpack_dec_enc_in (struct lsqpack_dec *, const unsigned char *, size_t);
425d8424881SDmitri Tikhonov
426e1b88773SDmitri Tikhonov/**
427a122a7bdSDmitri Tikhonov * Returns true if Insert Count Increment (ICI) instruction is pending.
428cddfe77cSDmitri Tikhonov */
429cddfe77cSDmitri Tikhonovint
430a122a7bdSDmitri Tikhonovlsqpack_dec_ici_pending (const struct lsqpack_dec *dec);
431cddfe77cSDmitri Tikhonov
432a122a7bdSDmitri Tikhonov/**
433a122a7bdSDmitri Tikhonov * Number of bytes required to encode the longest Insert Count Increment (ICI)
434a122a7bdSDmitri Tikhonov * instruction.
435a122a7bdSDmitri Tikhonov */
436a122a7bdSDmitri Tikhonov#define LSQPACK_LONGEST_ICI 6
437cddfe77cSDmitri Tikhonov
438cddfe77cSDmitri Tikhonovssize_t
439a122a7bdSDmitri Tikhonovlsqpack_dec_write_ici (struct lsqpack_dec *, unsigned char *, size_t);
440cddfe77cSDmitri Tikhonov
441ab2c97dcSDmitri Tikhonov/** Number of bytes required to encode the longest cancel instruction */
442ab2c97dcSDmitri Tikhonov#define LSQPACK_LONGEST_CANCEL 6
443ab2c97dcSDmitri Tikhonov
444ab2c97dcSDmitri Tikhonov/**
4456e082c27SDmitri Tikhonov * Cancel stream associated with the header block context `hblock_ctx' and
4466e082c27SDmitri Tikhonov * write cancellation instruction to `buf'.  `buf' must be at least
447ab2c97dcSDmitri Tikhonov * @ref LSQPACK_LONGEST_CANCEL bytes long.
448ab2c97dcSDmitri Tikhonov *
449ab2c97dcSDmitri Tikhonov * Number of bytes written to `buf' is returned.  If stream `stream_id'
450ab2c97dcSDmitri Tikhonov * could not be found, zero is returned.  If `buf' is too short, -1 is
451ab2c97dcSDmitri Tikhonov * returned.
452ab2c97dcSDmitri Tikhonov */
453ab2c97dcSDmitri Tikhonovssize_t
4546e082c27SDmitri Tikhonovlsqpack_dec_cancel_stream (struct lsqpack_dec *, void *hblock_ctx,
455ab2c97dcSDmitri Tikhonov                                unsigned char *buf, size_t buf_sz);
456ab2c97dcSDmitri Tikhonov
457d6ed115cSDmitri Tikhonov/**
458f4161384SDmitri Tikhonov * Generate Cancel Stream instruction for stream `stream_id'.  Call when
459f4161384SDmitri Tikhonov * abandoning stream (see [draft-ietf-quic-qpack-14] Section 2.2.2.2).
460f4161384SDmitri Tikhonov *
461f4161384SDmitri Tikhonov * Return values:
462f4161384SDmitri Tikhonov *  -1  error (`buf' is too short)
463f4161384SDmitri Tikhonov *   0  Emitting Cancel Stream instruction is unnecessary
464f4161384SDmitri Tikhonov *  >0  Size of Cancel Stream instruction written to `buf'.
465f4161384SDmitri Tikhonov */
466f4161384SDmitri Tikhonovssize_t
467f4161384SDmitri Tikhonovlsqpack_dec_cancel_stream_id (struct lsqpack_dec *dec, uint64_t stream_id,
468f4161384SDmitri Tikhonov                                        unsigned char *buf, size_t buf_sz);
469f4161384SDmitri Tikhonov
470f4161384SDmitri Tikhonov/**
4716e082c27SDmitri Tikhonov * Delete reference to the header block context `hblock_ctx'.  Use this
4726e082c27SDmitri Tikhonov * instead of @ref lsqpack_dec_cancel_stream() when producing a Cancel Stream
473d6ed115cSDmitri Tikhonov * instruction is not necessary.
474d6ed115cSDmitri Tikhonov */
475d6ed115cSDmitri Tikhonovint
4766e082c27SDmitri Tikhonovlsqpack_dec_unref_stream (struct lsqpack_dec *, void *hblock_ctx);
477d6ed115cSDmitri Tikhonov
478d6ed115cSDmitri Tikhonov/**
479490aea6cSDmitri Tikhonov * Return estimated compression ratio until this point.  Compression ratio
480490aea6cSDmitri Tikhonov * is defined as size of the input divided by the size of the output, where
481490aea6cSDmitri Tikhonov * input includes both header blocks and instructions received on the encoder
482490aea6cSDmitri Tikhonov * stream.
483490aea6cSDmitri Tikhonov */
484490aea6cSDmitri Tikhonovfloat
485490aea6cSDmitri Tikhonovlsqpack_dec_ratio (const struct lsqpack_dec *);
486490aea6cSDmitri Tikhonov
487490aea6cSDmitri Tikhonov/**
488d6ed115cSDmitri Tikhonov * Clean up the decoder.  If any there are any blocked header blocks,
4896b691f35SDmitri Tikhonov * references to them will be discarded.
4905989f779SDmitri Tikhonov */
4915989f779SDmitri Tikhonovvoid
4925989f779SDmitri Tikhonovlsqpack_dec_cleanup (struct lsqpack_dec *);
4935989f779SDmitri Tikhonov
494dc162d4eSDmitri Tikhonov/**
495dc162d4eSDmitri Tikhonov * Print human-readable decoder table.
496dc162d4eSDmitri Tikhonov */
497dc162d4eSDmitri Tikhonovvoid
498dc162d4eSDmitri Tikhonovlsqpack_dec_print_table (const struct lsqpack_dec *, FILE *out);
499dc162d4eSDmitri Tikhonov
50011fc5170SDmitri Tikhonov
50111fc5170SDmitri Tikhonovstruct lsqpack_dec_err
50211fc5170SDmitri Tikhonov{
50311fc5170SDmitri Tikhonov    enum {
50411fc5170SDmitri Tikhonov        LSQPACK_DEC_ERR_LOC_HEADER_BLOCK,
50511fc5170SDmitri Tikhonov        LSQPACK_DEC_ERR_LOC_ENC_STREAM,
50611fc5170SDmitri Tikhonov    }           type;
50711fc5170SDmitri Tikhonov    int         line;       /* In the source file */
50811fc5170SDmitri Tikhonov    uint64_t    off;        /* Offset in header block or on encoder stream */
50911fc5170SDmitri Tikhonov    uint64_t    stream_id;  /* Only applicable to header block */
51011fc5170SDmitri Tikhonov};
51111fc5170SDmitri Tikhonov
51211fc5170SDmitri Tikhonov
51311fc5170SDmitri Tikhonovconst struct lsqpack_dec_err *
51411fc5170SDmitri Tikhonovlsqpack_dec_get_err_info (const struct lsqpack_dec *);
51511fc5170SDmitri Tikhonov
516059dd705SDmitri Tikhonov/**
51760620859SDmitri Tikhonov * Enum for name/value entries in the static table.  Use it to speed up
51860620859SDmitri Tikhonov * encoding by setting xhdr->qpack_index and LSXPACK_QPACK_IDX flag.  If
51960620859SDmitri Tikhonov * it's a full match, set LSXPACK_VAL_MATCHED flag as well.
52060620859SDmitri Tikhonov */
52160620859SDmitri Tikhonovenum lsqpack_tnv
52260620859SDmitri Tikhonov{
52360620859SDmitri Tikhonov    LSQPACK_TNV_AUTHORITY = 0, /* ":authority" "" */
52460620859SDmitri Tikhonov    LSQPACK_TNV_PATH = 1, /* ":path" "/" */
52560620859SDmitri Tikhonov    LSQPACK_TNV_AGE_0 = 2, /* "age" "0" */
52660620859SDmitri Tikhonov    LSQPACK_TNV_CONTENT_DISPOSITION = 3, /* "content-disposition" "" */
52760620859SDmitri Tikhonov    LSQPACK_TNV_CONTENT_LENGTH_0 = 4, /* "content-length" "0" */
52860620859SDmitri Tikhonov    LSQPACK_TNV_COOKIE = 5, /* "cookie" "" */
52960620859SDmitri Tikhonov    LSQPACK_TNV_DATE = 6, /* "date" "" */
53060620859SDmitri Tikhonov    LSQPACK_TNV_ETAG = 7, /* "etag" "" */
53160620859SDmitri Tikhonov    LSQPACK_TNV_IF_MODIFIED_SINCE = 8, /* "if-modified-since" "" */
53260620859SDmitri Tikhonov    LSQPACK_TNV_IF_NONE_MATCH = 9, /* "if-none-match" "" */
53360620859SDmitri Tikhonov    LSQPACK_TNV_LAST_MODIFIED = 10, /* "last-modified" "" */
53460620859SDmitri Tikhonov    LSQPACK_TNV_LINK = 11, /* "link" "" */
53560620859SDmitri Tikhonov    LSQPACK_TNV_LOCATION = 12, /* "location" "" */
53660620859SDmitri Tikhonov    LSQPACK_TNV_REFERER = 13, /* "referer" "" */
53760620859SDmitri Tikhonov    LSQPACK_TNV_SET_COOKIE = 14, /* "set-cookie" "" */
53860620859SDmitri Tikhonov    LSQPACK_TNV_METHOD_CONNECT = 15, /* ":method" "CONNECT" */
53960620859SDmitri Tikhonov    LSQPACK_TNV_METHOD_DELETE = 16, /* ":method" "DELETE" */
54060620859SDmitri Tikhonov    LSQPACK_TNV_METHOD_GET = 17, /* ":method" "GET" */
54160620859SDmitri Tikhonov    LSQPACK_TNV_METHOD_HEAD = 18, /* ":method" "HEAD" */
54260620859SDmitri Tikhonov    LSQPACK_TNV_METHOD_OPTIONS = 19, /* ":method" "OPTIONS" */
54360620859SDmitri Tikhonov    LSQPACK_TNV_METHOD_POST = 20, /* ":method" "POST" */
54460620859SDmitri Tikhonov    LSQPACK_TNV_METHOD_PUT = 21, /* ":method" "PUT" */
54560620859SDmitri Tikhonov    LSQPACK_TNV_SCHEME_HTTP = 22, /* ":scheme" "http" */
54660620859SDmitri Tikhonov    LSQPACK_TNV_SCHEME_HTTPS = 23, /* ":scheme" "https" */
54760620859SDmitri Tikhonov    LSQPACK_TNV_STATUS_103 = 24, /* ":status" "103" */
54860620859SDmitri Tikhonov    LSQPACK_TNV_STATUS_200 = 25, /* ":status" "200" */
54960620859SDmitri Tikhonov    LSQPACK_TNV_STATUS_304 = 26, /* ":status" "304" */
55060620859SDmitri Tikhonov    LSQPACK_TNV_STATUS_404 = 27, /* ":status" "404" */
55160620859SDmitri Tikhonov    LSQPACK_TNV_STATUS_503 = 28, /* ":status" "503" */
55260620859SDmitri Tikhonov    LSQPACK_TNV_ACCEPT = 29, /* "accept" star slash star */
55360620859SDmitri Tikhonov    LSQPACK_TNV_ACCEPT_APPLICATION_DNS_MESSAGE = 30, /* "accept" "application/dns-message" */
55460620859SDmitri Tikhonov    LSQPACK_TNV_ACCEPT_ENCODING_GZIP_DEFLATE_BR = 31, /* "accept-encoding" "gzip, deflate, br" */
55560620859SDmitri Tikhonov    LSQPACK_TNV_ACCEPT_RANGES_BYTES = 32, /* "accept-ranges" "bytes" */
55660620859SDmitri Tikhonov    LSQPACK_TNV_ACCESS_CONTROL_ALLOW_HEADERS_CACHE_CONTROL = 33, /* "access-control-allow-headers" "cache-control" */
55760620859SDmitri Tikhonov    LSQPACK_TNV_ACCESS_CONTROL_ALLOW_HEADERS_CONTENT_TYPE = 34, /* "access-control-allow-headers" "content-type" */
55860620859SDmitri Tikhonov    LSQPACK_TNV_ACCESS_CONTROL_ALLOW_ORIGIN = 35, /* "access-control-allow-origin" "*" */
55960620859SDmitri Tikhonov    LSQPACK_TNV_CACHE_CONTROL_MAX_AGE_0 = 36, /* "cache-control" "max-age=0" */
56060620859SDmitri Tikhonov    LSQPACK_TNV_CACHE_CONTROL_MAX_AGE_2592000 = 37, /* "cache-control" "max-age=2592000" */
56160620859SDmitri Tikhonov    LSQPACK_TNV_CACHE_CONTROL_MAX_AGE_604800 = 38, /* "cache-control" "max-age=604800" */
56260620859SDmitri Tikhonov    LSQPACK_TNV_CACHE_CONTROL_NO_CACHE = 39, /* "cache-control" "no-cache" */
56360620859SDmitri Tikhonov    LSQPACK_TNV_CACHE_CONTROL_NO_STORE = 40, /* "cache-control" "no-store" */
56460620859SDmitri Tikhonov    LSQPACK_TNV_CACHE_CONTROL_PUBLIC_MAX_AGE_31536000 = 41, /* "cache-control" "public, max-age=31536000" */
56560620859SDmitri Tikhonov    LSQPACK_TNV_CONTENT_ENCODING_BR = 42, /* "content-encoding" "br" */
56660620859SDmitri Tikhonov    LSQPACK_TNV_CONTENT_ENCODING_GZIP = 43, /* "content-encoding" "gzip" */
56760620859SDmitri Tikhonov    LSQPACK_TNV_CONTENT_TYPE_APPLICATION_DNS_MESSAGE = 44, /* "content-type" "application/dns-message" */
56860620859SDmitri Tikhonov    LSQPACK_TNV_CONTENT_TYPE_APPLICATION_JAVASCRIPT = 45, /* "content-type" "application/javascript" */
56960620859SDmitri Tikhonov    LSQPACK_TNV_CONTENT_TYPE_APPLICATION_JSON = 46, /* "content-type" "application/json" */
57060620859SDmitri Tikhonov    LSQPACK_TNV_CONTENT_TYPE_APPLICATION_X_WWW_FORM_URLENCODED = 47, /* "content-type" "application/x-www-form-urlencoded" */
57160620859SDmitri Tikhonov    LSQPACK_TNV_CONTENT_TYPE_IMAGE_GIF = 48, /* "content-type" "image/gif" */
57260620859SDmitri Tikhonov    LSQPACK_TNV_CONTENT_TYPE_IMAGE_JPEG = 49, /* "content-type" "image/jpeg" */
57360620859SDmitri Tikhonov    LSQPACK_TNV_CONTENT_TYPE_IMAGE_PNG = 50, /* "content-type" "image/png" */
57460620859SDmitri Tikhonov    LSQPACK_TNV_CONTENT_TYPE_TEXT_CSS = 51, /* "content-type" "text/css" */
57560620859SDmitri Tikhonov    LSQPACK_TNV_CONTENT_TYPE_TEXT_HTML_CHARSET_UTF_8 = 52, /* "content-type" "text/html; charset=utf-8" */
57660620859SDmitri Tikhonov    LSQPACK_TNV_CONTENT_TYPE_TEXT_PLAIN = 53, /* "content-type" "text/plain" */
57760620859SDmitri Tikhonov    LSQPACK_TNV_CONTENT_TYPE_TEXT_PLAIN_CHARSET_UTF_8 = 54, /* "content-type" "text/plain;charset=utf-8" */
57860620859SDmitri Tikhonov    LSQPACK_TNV_RANGE_BYTES_0 = 55, /* "range" "bytes=0-" */
57960620859SDmitri Tikhonov    LSQPACK_TNV_STRICT_TRANSPORT_SECURITY_MAX_AGE_31536000 = 56, /* "strict-transport-security" "max-age=31536000" */
58060620859SDmitri Tikhonov    LSQPACK_TNV_STRICT_TRANSPORT_SECURITY_MAX_AGE_31536000_INCLUDESUBDOMAINS = 57, /* "strict-transport-security" "max-age=31536000; includesubdomains" */
58160620859SDmitri Tikhonov    LSQPACK_TNV_STRICT_TRANSPORT_SECURITY_MAX_AGE_31536000_INCLUDESUBDOMAINS_PRELOAD = 58, /* "strict-transport-security" "max-age=31536000; includesubdomains; preload" */
58260620859SDmitri Tikhonov    LSQPACK_TNV_VARY_ACCEPT_ENCODING = 59, /* "vary" "accept-encoding" */
58360620859SDmitri Tikhonov    LSQPACK_TNV_VARY_ORIGIN = 60, /* "vary" "origin" */
58460620859SDmitri Tikhonov    LSQPACK_TNV_X_CONTENT_TYPE_OPTIONS_NOSNIFF = 61, /* "x-content-type-options" "nosniff" */
58560620859SDmitri Tikhonov    LSQPACK_TNV_X_XSS_PROTECTION_1_MODE_BLOCK = 62, /* "x-xss-protection" "1; mode=block" */
58660620859SDmitri Tikhonov    LSQPACK_TNV_STATUS_100 = 63, /* ":status" "100" */
58760620859SDmitri Tikhonov    LSQPACK_TNV_STATUS_204 = 64, /* ":status" "204" */
58860620859SDmitri Tikhonov    LSQPACK_TNV_STATUS_206 = 65, /* ":status" "206" */
58960620859SDmitri Tikhonov    LSQPACK_TNV_STATUS_302 = 66, /* ":status" "302" */
59060620859SDmitri Tikhonov    LSQPACK_TNV_STATUS_400 = 67, /* ":status" "400" */
59160620859SDmitri Tikhonov    LSQPACK_TNV_STATUS_403 = 68, /* ":status" "403" */
59260620859SDmitri Tikhonov    LSQPACK_TNV_STATUS_421 = 69, /* ":status" "421" */
59360620859SDmitri Tikhonov    LSQPACK_TNV_STATUS_425 = 70, /* ":status" "425" */
59460620859SDmitri Tikhonov    LSQPACK_TNV_STATUS_500 = 71, /* ":status" "500" */
59560620859SDmitri Tikhonov    LSQPACK_TNV_ACCEPT_LANGUAGE = 72, /* "accept-language" "" */
59660620859SDmitri Tikhonov    LSQPACK_TNV_ACCESS_CONTROL_ALLOW_CREDENTIALS_FALSE = 73, /* "access-control-allow-credentials" "FALSE" */
59760620859SDmitri Tikhonov    LSQPACK_TNV_ACCESS_CONTROL_ALLOW_CREDENTIALS_TRUE = 74, /* "access-control-allow-credentials" "TRUE" */
59860620859SDmitri Tikhonov    LSQPACK_TNV_ACCESS_CONTROL_ALLOW_HEADERS = 75, /* "access-control-allow-headers" "*" */
59960620859SDmitri Tikhonov    LSQPACK_TNV_ACCESS_CONTROL_ALLOW_METHODS_GET = 76, /* "access-control-allow-methods" "get" */
60060620859SDmitri Tikhonov    LSQPACK_TNV_ACCESS_CONTROL_ALLOW_METHODS_GET_POST_OPTIONS = 77, /* "access-control-allow-methods" "get, post, options" */
60160620859SDmitri Tikhonov    LSQPACK_TNV_ACCESS_CONTROL_ALLOW_METHODS_OPTIONS = 78, /* "access-control-allow-methods" "options" */
60260620859SDmitri Tikhonov    LSQPACK_TNV_ACCESS_CONTROL_EXPOSE_HEADERS_CONTENT_LENGTH = 79, /* "access-control-expose-headers" "content-length" */
60360620859SDmitri Tikhonov    LSQPACK_TNV_ACCESS_CONTROL_REQUEST_HEADERS_CONTENT_TYPE = 80, /* "access-control-request-headers" "content-type" */
60460620859SDmitri Tikhonov    LSQPACK_TNV_ACCESS_CONTROL_REQUEST_METHOD_GET = 81, /* "access-control-request-method" "get" */
60560620859SDmitri Tikhonov    LSQPACK_TNV_ACCESS_CONTROL_REQUEST_METHOD_POST = 82, /* "access-control-request-method" "post" */
60660620859SDmitri Tikhonov    LSQPACK_TNV_ALT_SVC_CLEAR = 83, /* "alt-svc" "clear" */
60760620859SDmitri Tikhonov    LSQPACK_TNV_AUTHORIZATION = 84, /* "authorization" "" */
60860620859SDmitri Tikhonov    LSQPACK_TNV_CONTENT_SECURITY_POLICY_SCRIPT_SRC_NONE_OBJECT_SRC_NONE_BASE_URI_NONE = 85, /* "content-security-policy" "script-src 'none'; object-src 'none'; base-uri 'none'" */
60960620859SDmitri Tikhonov    LSQPACK_TNV_EARLY_DATA_1 = 86, /* "early-data" "1" */
61060620859SDmitri Tikhonov    LSQPACK_TNV_EXPECT_CT = 87, /* "expect-ct" "" */
61160620859SDmitri Tikhonov    LSQPACK_TNV_FORWARDED = 88, /* "forwarded" "" */
61260620859SDmitri Tikhonov    LSQPACK_TNV_IF_RANGE = 89, /* "if-range" "" */
61360620859SDmitri Tikhonov    LSQPACK_TNV_ORIGIN = 90, /* "origin" "" */
61460620859SDmitri Tikhonov    LSQPACK_TNV_PURPOSE_PREFETCH = 91, /* "purpose" "prefetch" */
61560620859SDmitri Tikhonov    LSQPACK_TNV_SERVER = 92, /* "server" "" */
61660620859SDmitri Tikhonov    LSQPACK_TNV_TIMING_ALLOW_ORIGIN = 93, /* "timing-allow-origin" "*" */
61760620859SDmitri Tikhonov    LSQPACK_TNV_UPGRADE_INSECURE_REQUESTS_1 = 94, /* "upgrade-insecure-requests" "1" */
61860620859SDmitri Tikhonov    LSQPACK_TNV_USER_AGENT = 95, /* "user-agent" "" */
61960620859SDmitri Tikhonov    LSQPACK_TNV_X_FORWARDED_FOR = 96, /* "x-forwarded-for" "" */
62060620859SDmitri Tikhonov    LSQPACK_TNV_X_FRAME_OPTIONS_DENY = 97, /* "x-frame-options" "deny" */
62160620859SDmitri Tikhonov    LSQPACK_TNV_X_FRAME_OPTIONS_SAMEORIGIN = 98, /* "x-frame-options" "sameorigin" */
62260620859SDmitri Tikhonov};
62360620859SDmitri Tikhonov
62460620859SDmitri Tikhonov
62543a63c18SDmitri Tikhonov/*
626a5cdaf71SDmitri Tikhonov * Internals follow.  The internals are subject to change without notice.
62743a63c18SDmitri Tikhonov */
62843a63c18SDmitri Tikhonov
62943a63c18SDmitri Tikhonov#include <sys/queue.h>
63043a63c18SDmitri Tikhonov
631d8424881SDmitri Tikhonov/* It takes 11 bytes to encode UINT64_MAX as HPACK integer */
632fc959618SDmitri Tikhonov#define LSQPACK_UINT64_ENC_SZ 11u
633d8424881SDmitri Tikhonov
63443a63c18SDmitri Tikhonovstruct lsqpack_enc_table_entry;
63543a63c18SDmitri Tikhonov
63643a63c18SDmitri TikhonovSTAILQ_HEAD(lsqpack_enc_head, lsqpack_enc_table_entry);
63743a63c18SDmitri Tikhonovstruct lsqpack_double_enc_head;
63843a63c18SDmitri Tikhonov
639c8a6e15dSDmitri Tikhonovstruct lsqpack_header_info_arr;
64043a63c18SDmitri Tikhonov
641471f84fdSDmitri Tikhonovstruct lsqpack_dec_int_state
642471f84fdSDmitri Tikhonov{
643471f84fdSDmitri Tikhonov    int         resume;
644471f84fdSDmitri Tikhonov    unsigned    M, nread;
645471f84fdSDmitri Tikhonov    uint64_t    val;
646471f84fdSDmitri Tikhonov};
647471f84fdSDmitri Tikhonov
64843a63c18SDmitri Tikhonovstruct lsqpack_enc
64943a63c18SDmitri Tikhonov{
65043a63c18SDmitri Tikhonov    /* The number of all the entries in the dynamic table that have been
65143a63c18SDmitri Tikhonov     * created so far.  This is used to calculate the Absolute Index.
65243a63c18SDmitri Tikhonov     */
6538eecc05bSDmitri Tikhonov    lsqpack_abs_id_t            qpe_ins_count;
6542a47c2feSDmitri Tikhonov    lsqpack_abs_id_t            qpe_max_acked_id;
655a122a7bdSDmitri Tikhonov    lsqpack_abs_id_t            qpe_last_ici;
65643a63c18SDmitri Tikhonov
657492ef85eSDmitri Tikhonov    enum {
658492ef85eSDmitri Tikhonov        LSQPACK_ENC_HEADER  = 1 << 0,
6590d818d0fSDmitri Tikhonov        LSQPACK_ENC_USE_DUP = 1 << 1,
660ecec593fSDmitri Tikhonov        LSQPACK_ENC_NO_MEM_GUARD    = 1 << 2,
661492ef85eSDmitri Tikhonov    }                           qpe_flags;
662492ef85eSDmitri Tikhonov
6638624e82bSDmitri Tikhonov    unsigned                    qpe_cur_bytes_used;
6648624e82bSDmitri Tikhonov    unsigned                    qpe_cur_max_capacity;
6658624e82bSDmitri Tikhonov    unsigned                    qpe_real_max_capacity;
66664096c11SDmitri Tikhonov    unsigned                    qpe_max_entries;
6673ac7e2c0SDmitri Tikhonov    /* Sum of all dropped entries.  OK if it overflows. */
6683ac7e2c0SDmitri Tikhonov    unsigned                    qpe_dropped;
66943a63c18SDmitri Tikhonov
670cf123c39SDmitri Tikhonov    /* The maximum risked streams is the SETTINGS_QPACK_BLOCKED_STREAMS
671cf123c39SDmitri Tikhonov     * setting.  Note that streams must be differentiated from headers.
672cf123c39SDmitri Tikhonov     */
673cf123c39SDmitri Tikhonov    unsigned                    qpe_max_risked_streams;
674cf123c39SDmitri Tikhonov    unsigned                    qpe_cur_streams_at_risk;
675cf123c39SDmitri Tikhonov
676fa7d152dSDmitri Tikhonov    /* Number of used entries in qpe_hinfo_arrs */
677fa7d152dSDmitri Tikhonov    unsigned                    qpe_hinfo_arrs_count;
67843a63c18SDmitri Tikhonov
67943a63c18SDmitri Tikhonov    /* Dynamic table entries (struct enc_table_entry) live in two hash
68043a63c18SDmitri Tikhonov     * tables: name/value hash table and name hash table.  These tables
68143a63c18SDmitri Tikhonov     * are the same size.
68243a63c18SDmitri Tikhonov     */
68343a63c18SDmitri Tikhonov    unsigned                    qpe_nelem;
68443a63c18SDmitri Tikhonov    unsigned                    qpe_nbits;
68543a63c18SDmitri Tikhonov    struct lsqpack_enc_head     qpe_all_entries;
68643a63c18SDmitri Tikhonov    struct lsqpack_double_enc_head
68743a63c18SDmitri Tikhonov                               *qpe_buckets;
68843a63c18SDmitri Tikhonov
689c8a6e15dSDmitri Tikhonov    STAILQ_HEAD(, lsqpack_header_info_arr)
690c8a6e15dSDmitri Tikhonov                                qpe_hinfo_arrs;
691c8a6e15dSDmitri Tikhonov    TAILQ_HEAD(, lsqpack_header_info)
692147b1758SDmitri Tikhonov                                qpe_all_hinfos;
693147b1758SDmitri Tikhonov    TAILQ_HEAD(, lsqpack_header_info)
694147b1758SDmitri Tikhonov                                qpe_risked_hinfos;
69543a63c18SDmitri Tikhonov
69643a63c18SDmitri Tikhonov    /* Current header state */
69743a63c18SDmitri Tikhonov    struct {
698147b1758SDmitri Tikhonov        struct lsqpack_header_info  *hinfo, *other_at_risk;
699492ef85eSDmitri Tikhonov
7002d8d35acSStephen Petrides        /* Number of headers in this header list added to the history */
7012d8d35acSStephen Petrides        unsigned            n_hdr_added_to_hist;
7029ef79d2cSDmitri Tikhonov        lsqpack_abs_id_t    min_reffed;
7033ce33568SDmitri Tikhonov        enum lsqpack_enc_header_flags
7043ce33568SDmitri Tikhonov                            flags;
70504a69767SDmitri Tikhonov        lsqpack_abs_id_t    base_idx;
70643a63c18SDmitri Tikhonov    }                           qpe_cur_header;
7070dc575feSDmitri Tikhonov
708471f84fdSDmitri Tikhonov    struct {
709471f84fdSDmitri Tikhonov        struct lsqpack_dec_int_state dec_int_state;
710471f84fdSDmitri Tikhonov        int   (*handler)(struct lsqpack_enc *, uint64_t);
711471f84fdSDmitri Tikhonov    }                           qpe_dec_stream_state;
7121678c8a4SDmitri Tikhonov
7131678c8a4SDmitri Tikhonov    /* Used to calculate estimated compression ratio.  Note that the `out'
7141678c8a4SDmitri Tikhonov     * part contains bytes sent on the decoder stream, as it also counts
7151678c8a4SDmitri Tikhonov     * toward the overhead.
7161678c8a4SDmitri Tikhonov     */
717c7039a37SDmitri Tikhonov    unsigned                    qpe_bytes_in;
718c7039a37SDmitri Tikhonov    unsigned                    qpe_bytes_out;
7196686ad13SDmitri Tikhonov    void                       *qpe_logger_ctx;
7209342ea7eSDmitri Tikhonov
7219342ea7eSDmitri Tikhonov    /* Exponential moving averages (EMAs) of the number of elements in the
72245c0a0abSDmitri Tikhonov     * dynamic table and the number of header fields in a single header list.
7239342ea7eSDmitri Tikhonov     * These values are used to adjust history size.
7249342ea7eSDmitri Tikhonov     */
7259342ea7eSDmitri Tikhonov    float                       qpe_table_nelem_ema;
7269342ea7eSDmitri Tikhonov    float                       qpe_header_count_ema;
727b97e4a73SDmitri Tikhonov
728823f604fSDmitri Tikhonov    struct lsqpack_hist_el     *qpe_hist_els;
729b97e4a73SDmitri Tikhonov    unsigned                    qpe_hist_idx;
730b97e4a73SDmitri Tikhonov    unsigned                    qpe_hist_nels;
731b97e4a73SDmitri Tikhonov    int                         qpe_hist_wrapped;
73243a63c18SDmitri Tikhonov};
73343a63c18SDmitri Tikhonov
73411fc5170SDmitri Tikhonovstruct lsqpack_ringbuf
73543a63c18SDmitri Tikhonov{
73611fc5170SDmitri Tikhonov    unsigned        rb_nalloc, rb_head, rb_tail;
73711fc5170SDmitri Tikhonov    void          **rb_els;
73843a63c18SDmitri Tikhonov};
73943a63c18SDmitri Tikhonov
740a5cdaf71SDmitri TikhonovTAILQ_HEAD(lsqpack_header_sets, lsqpack_header_set_elem);
741d8424881SDmitri Tikhonov
742d8424881SDmitri Tikhonovstruct lsqpack_header_block;
743a5cdaf71SDmitri Tikhonov
744d082bd25SDmitri Tikhonovstruct lsqpack_decode_status
745d082bd25SDmitri Tikhonov{
746d082bd25SDmitri Tikhonov    uint8_t state;
747d082bd25SDmitri Tikhonov    uint8_t eos;
748d082bd25SDmitri Tikhonov};
749d082bd25SDmitri Tikhonov
750d082bd25SDmitri Tikhonovstruct lsqpack_huff_decode_state
751d082bd25SDmitri Tikhonov{
752d082bd25SDmitri Tikhonov    int                             resume;
753d082bd25SDmitri Tikhonov    struct lsqpack_decode_status    status;
754d082bd25SDmitri Tikhonov};
755d082bd25SDmitri Tikhonov
756c9805df0SDmitri Tikhonovstruct lsqpack_dec_inst;
757c9805df0SDmitri Tikhonov
758a5cdaf71SDmitri Tikhonovstruct lsqpack_dec
759a5cdaf71SDmitri Tikhonov{
76060620859SDmitri Tikhonov    enum lsqpack_dec_opts   qpd_opts;
761a5cdaf71SDmitri Tikhonov    /** This is the hard limit set at initialization */
762a5cdaf71SDmitri Tikhonov    unsigned                qpd_max_capacity;
763a5cdaf71SDmitri Tikhonov    /** The current maximum capacity can be adjusted at run-time */
764a5cdaf71SDmitri Tikhonov    unsigned                qpd_cur_max_capacity;
765a5cdaf71SDmitri Tikhonov    unsigned                qpd_cur_capacity;
766a5cdaf71SDmitri Tikhonov    unsigned                qpd_max_risked_streams;
76711fc5170SDmitri Tikhonov    unsigned                qpd_max_entries;
76893b5499dSDmitri Tikhonov    /* Used to calculate estimated compression ratio.  Note that the `in'
769490aea6cSDmitri Tikhonov     * part contains bytes sent on the decoder stream, as it also counts
770490aea6cSDmitri Tikhonov     * toward the overhead.
771490aea6cSDmitri Tikhonov     */
772490aea6cSDmitri Tikhonov    unsigned                qpd_bytes_in;
773490aea6cSDmitri Tikhonov    unsigned                qpd_bytes_out;
77411fc5170SDmitri Tikhonov    /** ID of the last dynamic table entry.  Has the range
77511fc5170SDmitri Tikhonov     * [0, qpd_max_entries * 2 - 1 ]
77611fc5170SDmitri Tikhonov     */
77711fc5170SDmitri Tikhonov    lsqpack_abs_id_t        qpd_last_id;
77828a3d41dSDmitri Tikhonov    /** TODO: describe the mechanism */
77928a3d41dSDmitri Tikhonov    lsqpack_abs_id_t        qpd_largest_known_id;
78060620859SDmitri Tikhonov    const struct lsqpack_dec_hset_if
78160620859SDmitri Tikhonov                           *qpd_dh_if;
782a5cdaf71SDmitri Tikhonov
7836686ad13SDmitri Tikhonov    void                   *qpd_logger_ctx;
7846686ad13SDmitri Tikhonov
785a5cdaf71SDmitri Tikhonov    /** This is the dynamic table */
78611fc5170SDmitri Tikhonov    struct lsqpack_ringbuf  qpd_dyn_table;
787a5cdaf71SDmitri Tikhonov
78844e7b699SDmitri Tikhonov    TAILQ_HEAD(, header_block_read_ctx)
78944e7b699SDmitri Tikhonov                            qpd_hbrcs;
79044e7b699SDmitri Tikhonov
79111fc5170SDmitri Tikhonov    /** Blocked headers are kept in a small hash */
79211fc5170SDmitri Tikhonov#define LSQPACK_DEC_BLOCKED_BITS 3
79311fc5170SDmitri Tikhonov    TAILQ_HEAD(, header_block_read_ctx)
79411fc5170SDmitri Tikhonov                            qpd_blocked_headers[1 << LSQPACK_DEC_BLOCKED_BITS];
79511fc5170SDmitri Tikhonov    /** Number of blocked streams (in qpd_blocked_headers) */
79611fc5170SDmitri Tikhonov    unsigned                qpd_n_blocked;
797122d1163SDmitri Tikhonov
798e613bc69SDmitri Tikhonov    /** Average number of header fields in header list */
799e613bc69SDmitri Tikhonov    float                   qpd_hlist_size_ema;
800e613bc69SDmitri Tikhonov
801d082bd25SDmitri Tikhonov    /** Reading the encoder stream */
802d082bd25SDmitri Tikhonov    struct {
803d082bd25SDmitri Tikhonov        int                                                 resume;
804d082bd25SDmitri Tikhonov        union {
805d082bd25SDmitri Tikhonov            /* State for reading in the Insert With Named Reference
806d082bd25SDmitri Tikhonov             * instruction.
807d082bd25SDmitri Tikhonov             */
808d082bd25SDmitri Tikhonov            struct {
809d082bd25SDmitri Tikhonov                struct lsqpack_dec_int_state        dec_int_state;
810d082bd25SDmitri Tikhonov                struct lsqpack_huff_decode_state    dec_huff_state;
81166c4caf1SDmitri Tikhonov                unsigned                            name_idx;
81266c4caf1SDmitri Tikhonov                unsigned                            val_len;
813d082bd25SDmitri Tikhonov                struct lsqpack_dec_table_entry     *reffed_entry;
814d082bd25SDmitri Tikhonov                struct lsqpack_dec_table_entry     *entry;
815d082bd25SDmitri Tikhonov                const char                         *name;
816d082bd25SDmitri Tikhonov                unsigned                            alloced_val_len;
817d082bd25SDmitri Tikhonov                unsigned                            val_off;
818d082bd25SDmitri Tikhonov                unsigned                            nread;
819d082bd25SDmitri Tikhonov                unsigned                            name_len;
820d082bd25SDmitri Tikhonov                signed char                         is_huffman;
821d082bd25SDmitri Tikhonov                signed char                         is_static;
822d082bd25SDmitri Tikhonov            }                                               with_namref;
823d082bd25SDmitri Tikhonov
8245c0ba798SDmitri Tikhonov            /* State for reading in the Insert Without Named Reference
8255c0ba798SDmitri Tikhonov             * instruction.
8265c0ba798SDmitri Tikhonov             */
827d082bd25SDmitri Tikhonov            struct {
8285c0ba798SDmitri Tikhonov                struct lsqpack_dec_int_state        dec_int_state;
8295c0ba798SDmitri Tikhonov                struct lsqpack_huff_decode_state    dec_huff_state;
83066c4caf1SDmitri Tikhonov                unsigned                            str_len;
8315c0ba798SDmitri Tikhonov                struct lsqpack_dec_table_entry     *entry;
8325c0ba798SDmitri Tikhonov                unsigned                            alloced_len;
8335c0ba798SDmitri Tikhonov                unsigned                            str_off;
8345c0ba798SDmitri Tikhonov                unsigned                            nread;
8355c0ba798SDmitri Tikhonov                signed char                         is_huffman;
836d082bd25SDmitri Tikhonov            }                                               wo_namref;
837d082bd25SDmitri Tikhonov
838d082bd25SDmitri Tikhonov            struct {
839608798c5SDmitri Tikhonov                struct lsqpack_dec_int_state        dec_int_state;
84066c4caf1SDmitri Tikhonov                unsigned                            index;
841d082bd25SDmitri Tikhonov            }                                               duplicate;
8428aab2f7dSDmitri Tikhonov
8438aab2f7dSDmitri Tikhonov            struct {
8448aab2f7dSDmitri Tikhonov                struct lsqpack_dec_int_state        dec_int_state;
8458aab2f7dSDmitri Tikhonov                uint64_t                            new_size;
846a122a7bdSDmitri Tikhonov            }                                               sdtc;
847d082bd25SDmitri Tikhonov        }               ctx_u;
848d082bd25SDmitri Tikhonov    }                       qpd_enc_state;
84911fc5170SDmitri Tikhonov    struct lsqpack_dec_err  qpd_err;
850a5cdaf71SDmitri Tikhonov};
851a5cdaf71SDmitri Tikhonov
85243a63c18SDmitri Tikhonov#ifdef __cplusplus
85343a63c18SDmitri Tikhonov}
85443a63c18SDmitri Tikhonov#endif
85543a63c18SDmitri Tikhonov
85643a63c18SDmitri Tikhonov#endif
857