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