lsqpack 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/Gemfile +19 -0
- data/Gemfile.lock +82 -0
- data/LICENSE +21 -0
- data/README.md +36 -0
- data/Rakefile +19 -0
- data/Steepfile +6 -0
- data/ext/lsqpack/extconf.rb +18 -0
- data/ext/lsqpack/lsqpack.c +426 -0
- data/ext/lsqpack/lsqpack.h +6 -0
- data/lib/lsqpack/version.rb +5 -0
- data/lib/lsqpack.rb +30 -0
- data/ls-qpack/.appveyor.yml +14 -0
- data/ls-qpack/.cirrus.yml +6 -0
- data/ls-qpack/.travis.yml +32 -0
- data/ls-qpack/CMakeLists.txt +66 -0
- data/ls-qpack/LICENSE +21 -0
- data/ls-qpack/README.md +65 -0
- data/ls-qpack/bin/CMakeLists.txt +21 -0
- data/ls-qpack/bin/encode-int.c +87 -0
- data/ls-qpack/bin/fuzz-decode.c +247 -0
- data/ls-qpack/bin/interop-decode.c +433 -0
- data/ls-qpack/bin/interop-encode.c +554 -0
- data/ls-qpack/deps/xxhash/xxhash.c +941 -0
- data/ls-qpack/deps/xxhash/xxhash.h +160 -0
- data/ls-qpack/fuzz/decode/a/README +3 -0
- data/ls-qpack/fuzz/decode/a/preamble +0 -0
- data/ls-qpack/fuzz/decode/a/test-cases/id_000000,sig_06,src_000390,op_havoc,rep_4 +0 -0
- data/ls-qpack/fuzz/decode/a/test-cases/id_000000,sig_06,src_000579,op_flip1,pos_14 +0 -0
- data/ls-qpack/fuzz/decode/a/test-cases/id_000000,src_000000,op_flip2,pos_12 +0 -0
- data/ls-qpack/fuzz/decode/a/test-cases/id_000001,sig_11,src_000579,op_havoc,rep_4 +0 -0
- data/ls-qpack/fuzz/decode/a/test-cases/id_000002,sig_11,src_000481,op_int16,pos_15,val_-1 +0 -0
- data/ls-qpack/fuzz/decode/a/test-cases/id_000002,src_000000,op_havoc,rep_8 +0 -0
- data/ls-qpack/fuzz/decode/a/test-cases/id_000006,src_000285,op_flip2,pos_14 +0 -0
- data/ls-qpack/fuzz/decode/a/test-cases/id_000008,src_000285,op_flip2,pos_20 +0 -0
- data/ls-qpack/fuzz/decode/a/test-cases/id_000010,src_000306,op_flip2,pos_75 +0 -0
- data/ls-qpack/fuzz/decode/a/test-cases/id_000011,src_000344,op_havoc,rep_2 +0 -0
- data/ls-qpack/fuzz/decode/a/test-cases/id_000014,src_000366,op_flip2,pos_28 +0 -0
- data/ls-qpack/fuzz/decode/b/README +1 -0
- data/ls-qpack/fuzz/decode/b/preamble +0 -0
- data/ls-qpack/fuzz/decode/b/test-cases/seed +0 -0
- data/ls-qpack/fuzz/decode/c/setup.sh +3 -0
- data/ls-qpack/fuzz/decode/c/test-cases/fb-req.qif.proxygen.out.256.100.0-chopped +0 -0
- data/ls-qpack/fuzz/decode/d/preamble +0 -0
- data/ls-qpack/fuzz/decode/d/setup.sh +3 -0
- data/ls-qpack/fuzz/decode/d/test-cases/fb-resp.minhq.256.128.0.ack +0 -0
- data/ls-qpack/fuzz/input/256.100.1/fb-req.out.256.100.1 +0 -0
- data/ls-qpack/fuzz/input/256.100.1/fb-resp.out.256.100.1 +0 -0
- data/ls-qpack/fuzz/input/256.100.1/netbsd.out.256.100.1 +0 -0
- data/ls-qpack/huff-tables.h +136247 -0
- data/ls-qpack/lsqpack.c +5547 -0
- data/ls-qpack/lsqpack.h +768 -0
- data/ls-qpack/test/CMakeLists.txt +76 -0
- data/ls-qpack/test/lsqpack-test.h +43 -0
- data/ls-qpack/test/qifs/fb-req.qif +4917 -0
- data/ls-qpack/test/qifs/fb-resp.qif +5982 -0
- data/ls-qpack/test/qifs/long-codes.qif +5984 -0
- data/ls-qpack/test/qifs/netbsd.qif +235 -0
- data/ls-qpack/test/run-qif.pl +97 -0
- data/ls-qpack/test/run-scenario.sh +68 -0
- data/ls-qpack/test/scenarios/0.95-reset.sce +10 -0
- data/ls-qpack/test/scenarios/cancel-stream.sce +22 -0
- data/ls-qpack/test/scenarios/drain-2.sce +37 -0
- data/ls-qpack/test/scenarios/drain.sce +37 -0
- data/ls-qpack/test/scenarios/end-dst-2.sce +14 -0
- data/ls-qpack/test/scenarios/end-dst.sce +14 -0
- data/ls-qpack/test/scenarios/incl-name.sce +13 -0
- data/ls-qpack/test/scenarios/multi-byte-int-dyn-ref-1.sce +110 -0
- data/ls-qpack/test/scenarios/multi-byte-int-dyn-ref-2.sce +161 -0
- data/ls-qpack/test/scenarios/post-base-1.sce +10 -0
- data/ls-qpack/test/scenarios/post-base-2.sce +13 -0
- data/ls-qpack/test/scenarios/post-base-nr.sce +10 -0
- data/ls-qpack/test/scenarios/set-max-cap.sce +15 -0
- data/ls-qpack/test/test_enc_str.c +139 -0
- data/ls-qpack/test/test_get_stx_id.c +144 -0
- data/ls-qpack/test/test_huff_dec.c +399 -0
- data/ls-qpack/test/test_int.c +220 -0
- data/ls-qpack/test/test_qpack.c +856 -0
- data/ls-qpack/test/test_read_enc_stream.c +256 -0
- data/ls-qpack/tools/har2qif.pl +139 -0
- data/ls-qpack/tools/randomize-cookies.pl +41 -0
- data/ls-qpack/tools/sort-qif.pl +31 -0
- data/ls-qpack/wincompat/getopt.c +758 -0
- data/ls-qpack/wincompat/getopt.h +131 -0
- data/ls-qpack/wincompat/getopt1.c +188 -0
- data/ls-qpack/wincompat/sys/queue.h +859 -0
- data/lsqpack.gemspec +39 -0
- data/sig/lsqpack.rbs +29 -0
- metadata +135 -0
data/ls-qpack/lsqpack.h
ADDED
@@ -0,0 +1,768 @@
|
|
1
|
+
/*
|
2
|
+
* lsqpack.h - QPACK library
|
3
|
+
*/
|
4
|
+
|
5
|
+
/*
|
6
|
+
MIT License
|
7
|
+
|
8
|
+
Copyright (c) 2018 - 2020 LiteSpeed Technologies Inc
|
9
|
+
|
10
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
11
|
+
of this software and associated documentation files (the "Software"), to deal
|
12
|
+
in the Software without restriction, including without limitation the rights
|
13
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
14
|
+
copies of the Software, and to permit persons to whom the Software is
|
15
|
+
furnished to do so, subject to the following conditions:
|
16
|
+
|
17
|
+
The above copyright notice and this permission notice shall be included in all
|
18
|
+
copies or substantial portions of the Software.
|
19
|
+
|
20
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
21
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
22
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
23
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
24
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
25
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
26
|
+
SOFTWARE.
|
27
|
+
*/
|
28
|
+
|
29
|
+
#ifndef LSQPACK_H
|
30
|
+
#define LSQPACK_H 1
|
31
|
+
|
32
|
+
#ifdef __cplusplus
|
33
|
+
extern "C" {
|
34
|
+
#endif
|
35
|
+
|
36
|
+
#include <limits.h>
|
37
|
+
#include <stdint.h>
|
38
|
+
#include <stdio.h>
|
39
|
+
|
40
|
+
#if defined(_MSC_VER)
|
41
|
+
#include <BaseTsd.h>
|
42
|
+
typedef SSIZE_T ssize_t;
|
43
|
+
#endif
|
44
|
+
|
45
|
+
#define LSQPACK_MAJOR_VERSION 1
|
46
|
+
#define LSQPACK_MINOR_VERSION 0
|
47
|
+
#define LSQPACK_PATCH_VERSION 3
|
48
|
+
|
49
|
+
/** Let's start with four billion for now */
|
50
|
+
typedef unsigned lsqpack_abs_id_t;
|
51
|
+
|
52
|
+
#define LSQPACK_MAX_ABS_ID (~((lsqpack_abs_id_t) 0))
|
53
|
+
|
54
|
+
#define LSQPACK_DEF_DYN_TABLE_SIZE 0
|
55
|
+
#define LSQPACK_DEF_MAX_RISKED_STREAMS 0
|
56
|
+
|
57
|
+
struct lsqpack_enc;
|
58
|
+
struct lsqpack_dec;
|
59
|
+
|
60
|
+
enum lsqpack_enc_opts
|
61
|
+
{
|
62
|
+
/**
|
63
|
+
* Client and server follow different heuristics. The encoder is either
|
64
|
+
* in one or the other mode.
|
65
|
+
*
|
66
|
+
* At the moment this option is a no-op. This is a potential future
|
67
|
+
* work item where some heuristics may be added to the library.
|
68
|
+
*/
|
69
|
+
LSQPACK_ENC_OPT_SERVER = 1 << 0,
|
70
|
+
|
71
|
+
/**
|
72
|
+
* The encoder was pre-initialized using @ref lsqpack_enc_preinit() and
|
73
|
+
* so some initialization steps can be skipped.
|
74
|
+
*/
|
75
|
+
LSQPACK_ENC_OPT_STAGE_2 = 1 << 1,
|
76
|
+
|
77
|
+
/* The options below are advanced. The author only uses them for debugging
|
78
|
+
* or testing.
|
79
|
+
*/
|
80
|
+
|
81
|
+
/**
|
82
|
+
* Disable emitting dup instructions.
|
83
|
+
*
|
84
|
+
* Disabling dup instructions usually makes compression performance
|
85
|
+
* significanly worse. Do not use unless you know what you are doing.
|
86
|
+
*/
|
87
|
+
LSQPACK_ENC_OPT_NO_DUP = 1 << 2,
|
88
|
+
|
89
|
+
/**
|
90
|
+
* Index aggressively: ignore history
|
91
|
+
*
|
92
|
+
* Ignoring history usually makes compression performance significanly
|
93
|
+
* worse. Do not use unless you know what you are doing.
|
94
|
+
*/
|
95
|
+
LSQPACK_ENC_OPT_IX_AGGR = 1 << 3,
|
96
|
+
|
97
|
+
/**
|
98
|
+
* Turn off memory guard: keep on allocating state tracking oustanding
|
99
|
+
* headers even if they never get acknowledged.
|
100
|
+
*
|
101
|
+
* This is useful for some forms of testing.
|
102
|
+
*/
|
103
|
+
LSQPACK_ENC_OPT_NO_MEM_GUARD = 1 << 4,
|
104
|
+
};
|
105
|
+
|
106
|
+
|
107
|
+
/**
|
108
|
+
* Initialize the encoder so that it can be used without using the
|
109
|
+
* dynamic table. Once peer's settings are known, call
|
110
|
+
* @ref lsqpack_enc_init().
|
111
|
+
*
|
112
|
+
* `logger_ctx' can be set to NULL if no special logging is set up.
|
113
|
+
*/
|
114
|
+
void
|
115
|
+
lsqpack_enc_preinit (struct lsqpack_enc *, void *logger_ctx);
|
116
|
+
|
117
|
+
/**
|
118
|
+
* Number of bytes required to encode the longest possible Set Dynamic Table
|
119
|
+
* Capacity instruction. This is a theoretical limit based on the integral
|
120
|
+
* type (unsigned int) used by this library to store the capacity value. If
|
121
|
+
* the encoder is initialized with a smaller maximum table capacity, it is
|
122
|
+
* safe to use fewer bytes.
|
123
|
+
*
|
124
|
+
* SDTC instructtion can be produced by @ref lsqpack_enc_init() and
|
125
|
+
* @ref lsqpack_enc_set_max_capacity().
|
126
|
+
*/
|
127
|
+
#if UINT_MAX == 65535
|
128
|
+
#define LSQPACK_LONGEST_SDTC 4
|
129
|
+
#elif UINT_MAX == 4294967295
|
130
|
+
#define LSQPACK_LONGEST_SDTC 6
|
131
|
+
#elif UINT_MAX == 18446744073709551615ULL
|
132
|
+
#define LSQPACK_LONGEST_SDTC 11
|
133
|
+
#else
|
134
|
+
#error unexpected sizeof(unsigned)
|
135
|
+
#endif
|
136
|
+
|
137
|
+
int
|
138
|
+
lsqpack_enc_init (struct lsqpack_enc *,
|
139
|
+
/** `logger_ctx' can be set to NULL if no special logging is set up. */
|
140
|
+
void *logger_ctx,
|
141
|
+
/**
|
142
|
+
* As specified by the decoder. This value is used to calculate
|
143
|
+
* MaxEntries.
|
144
|
+
*/
|
145
|
+
unsigned max_table_size,
|
146
|
+
/**
|
147
|
+
* Actual dynamic table size to use.
|
148
|
+
*/
|
149
|
+
unsigned dyn_table_size,
|
150
|
+
unsigned max_risked_streams, enum lsqpack_enc_opts,
|
151
|
+
/**
|
152
|
+
* If `dyn_table_size' is not zero, Set Dynamic Table Capacity (SDTC)
|
153
|
+
* instruction is generated and placed into `sdtc_buf'. `sdtc_buf_sz'
|
154
|
+
* parameter is used both for input and output.
|
155
|
+
*
|
156
|
+
* If `dyn_table_size' is zero, `sdtc_buf' and `sdtc_buf_sz' are optional
|
157
|
+
* and can be set to NULL.
|
158
|
+
*/
|
159
|
+
unsigned char *sdtc_buf, size_t *sdtc_buf_sz);
|
160
|
+
|
161
|
+
/**
|
162
|
+
* Set table size to `capacity'. If necessary, Set Dynamic Table Capacity
|
163
|
+
* (SDTC) instruction is generated and placed into `tsu_buf'. If `capacity'
|
164
|
+
* is larger than the maximum table size specified during initialization, an
|
165
|
+
* error is returned.
|
166
|
+
*/
|
167
|
+
int
|
168
|
+
lsqpack_enc_set_max_capacity (struct lsqpack_enc *enc, unsigned capacity,
|
169
|
+
unsigned char *sdtc_buf, size_t *sdtc_buf_sz);
|
170
|
+
|
171
|
+
/** Start a new header block. Return 0 on success or -1 on error. */
|
172
|
+
int
|
173
|
+
lsqpack_enc_start_header (struct lsqpack_enc *, uint64_t stream_id,
|
174
|
+
unsigned seqno);
|
175
|
+
|
176
|
+
/** Status returned by @ref lsqpack_enc_encode() */
|
177
|
+
enum lsqpack_enc_status
|
178
|
+
{
|
179
|
+
/** Header field encoded successfully */
|
180
|
+
LQES_OK,
|
181
|
+
/** There was not enough room in the encoder stream buffer */
|
182
|
+
LQES_NOBUF_ENC,
|
183
|
+
/** There was not enough room in the header block buffer */
|
184
|
+
LQES_NOBUF_HEAD,
|
185
|
+
};
|
186
|
+
|
187
|
+
enum lsqpack_enc_flags
|
188
|
+
{
|
189
|
+
/**
|
190
|
+
* Do not index this header field. No output to the encoder stream
|
191
|
+
* will be produced.
|
192
|
+
*/
|
193
|
+
LQEF_NO_INDEX = 1 << 0,
|
194
|
+
/**
|
195
|
+
* Never index this field. This will set the 'N' bit on Literal Header
|
196
|
+
* Field With Name Reference, Literal Header Field With Post-Base Name
|
197
|
+
* Reference, and Literal Header Field Without Name Reference instructions
|
198
|
+
* in the header block. Implies LQEF_NO_INDEX.
|
199
|
+
*/
|
200
|
+
LQEF_NEVER_INDEX = 1 << 1,
|
201
|
+
/**
|
202
|
+
* Do not update history.
|
203
|
+
*/
|
204
|
+
LQEF_NO_HIST_UPD = 1 << 2,
|
205
|
+
/**
|
206
|
+
* Do not use the dynamic table. This is stricter than LQEF_NO_INDEX:
|
207
|
+
* this means that the dynamic table will be neither referenced nor
|
208
|
+
* modified.
|
209
|
+
*/
|
210
|
+
LQEF_NO_DYN = 1 << 3,
|
211
|
+
};
|
212
|
+
|
213
|
+
/**
|
214
|
+
* Encode header field into current header block.
|
215
|
+
*
|
216
|
+
* See @ref lsqpack_enc_status for explanation of the return values.
|
217
|
+
*
|
218
|
+
* enc_sz and header_sz parameters are used for both input and output. If
|
219
|
+
* the return value is LQES_OK, they contain number of bytes written to
|
220
|
+
* enc_buf and header_buf, respectively. enc_buf contains the bytes that
|
221
|
+
* must be written to the encoder stream; header_buf contains bytes that
|
222
|
+
* must be written to the header block.
|
223
|
+
*
|
224
|
+
* Note that even though this function may allocate memory, it falls back to
|
225
|
+
* not using the dynamic table should memory allocation fail. Thus, failures
|
226
|
+
* to encode due to not enough memory do not exist.
|
227
|
+
*/
|
228
|
+
enum lsqpack_enc_status
|
229
|
+
lsqpack_enc_encode (struct lsqpack_enc *,
|
230
|
+
unsigned char *enc_buf, size_t *enc_sz,
|
231
|
+
unsigned char *header_buf, size_t *header_sz,
|
232
|
+
const char *name, unsigned name_sz,
|
233
|
+
const char *value, unsigned value_sz,
|
234
|
+
enum lsqpack_enc_flags);
|
235
|
+
|
236
|
+
/**
|
237
|
+
* Cancel current header block. Cancellation is only allowed if the dynamic
|
238
|
+
* table is not used. Returns 0 on success, -1 on failure.
|
239
|
+
*/
|
240
|
+
int
|
241
|
+
lsqpack_enc_cancel_header (struct lsqpack_enc *);
|
242
|
+
|
243
|
+
|
244
|
+
/**
|
245
|
+
* Properties of the current header block
|
246
|
+
*/
|
247
|
+
enum lsqpack_enc_header_flags
|
248
|
+
{
|
249
|
+
/** Set if there are at-risk references in this header block */
|
250
|
+
LSQECH_REF_AT_RISK = 1 << 0,
|
251
|
+
/** Set if the header block references newly inserted entries */
|
252
|
+
LSQECH_REF_NEW_ENTRIES = 1 << 1,
|
253
|
+
/** Set if min-reffed value is cached */
|
254
|
+
LSQECH_MINREF_CACHED = 1 << 2,
|
255
|
+
};
|
256
|
+
|
257
|
+
|
258
|
+
/**
|
259
|
+
* End current header block. The Header Block Prefix is written to `buf'.
|
260
|
+
*
|
261
|
+
* `buf' must be at least two bytes. 11 bytes are necessary to encode
|
262
|
+
* UINT64_MAX using 7- or 8-bit prefix. Therefore, 22 bytes is the
|
263
|
+
* theoretical maximum for this library.
|
264
|
+
*
|
265
|
+
* Use @ref lsqpack_enc_header_block_prefix_size() if you require better
|
266
|
+
* precision.
|
267
|
+
*
|
268
|
+
* Returns:
|
269
|
+
* - A positive value indicates success and is the number of bytes
|
270
|
+
* written to `buf'.
|
271
|
+
* - Zero means that there is not enough room in `buf' to write out the
|
272
|
+
* full prefix.
|
273
|
+
* - A negative value means an error. This is returned if there is no
|
274
|
+
* started header to end.
|
275
|
+
*
|
276
|
+
* If header was ended successfully and @ref flags is not NULL, it is
|
277
|
+
* assigned properties of the header block.
|
278
|
+
*/
|
279
|
+
ssize_t
|
280
|
+
lsqpack_enc_end_header (struct lsqpack_enc *, unsigned char *buf, size_t,
|
281
|
+
enum lsqpack_enc_header_flags *flags /* Optional */);
|
282
|
+
|
283
|
+
/**
|
284
|
+
* Process next chunk of bytes from the decoder stream. Returns 0 on success,
|
285
|
+
* -1 on failure. The failure should be treated as fatal.
|
286
|
+
*/
|
287
|
+
int
|
288
|
+
lsqpack_enc_decoder_in (struct lsqpack_enc *, const unsigned char *, size_t);
|
289
|
+
|
290
|
+
/**
|
291
|
+
* Return estimated compression ratio until this point. Compression ratio
|
292
|
+
* is defined as size of the output divided by the size of the input, where
|
293
|
+
* output includes both header blocks and instructions sent on the encoder
|
294
|
+
* stream.
|
295
|
+
*/
|
296
|
+
float
|
297
|
+
lsqpack_enc_ratio (const struct lsqpack_enc *);
|
298
|
+
|
299
|
+
/**
|
300
|
+
* Return maximum size needed to encode Header Block Prefix
|
301
|
+
*/
|
302
|
+
size_t
|
303
|
+
lsqpack_enc_header_block_prefix_size (const struct lsqpack_enc *);
|
304
|
+
|
305
|
+
void
|
306
|
+
lsqpack_enc_cleanup (struct lsqpack_enc *);
|
307
|
+
|
308
|
+
/**
|
309
|
+
* The header is a single name/value pair. The strings are not NUL-terminated.
|
310
|
+
*/
|
311
|
+
struct lsqpack_header
|
312
|
+
{
|
313
|
+
const char *qh_name;
|
314
|
+
const char *qh_value;
|
315
|
+
unsigned qh_name_len;
|
316
|
+
unsigned qh_value_len;
|
317
|
+
unsigned qh_static_id;
|
318
|
+
enum {
|
319
|
+
/** Must be encoded with a literal representation */
|
320
|
+
QH_NEVER = 1 << 0,
|
321
|
+
/** qh_static_id is set */
|
322
|
+
QH_ID_SET = 1 << 1,
|
323
|
+
} qh_flags;
|
324
|
+
};
|
325
|
+
|
326
|
+
/**
|
327
|
+
* The header list represents the decoded header block.
|
328
|
+
*/
|
329
|
+
struct lsqpack_header_list
|
330
|
+
{
|
331
|
+
struct lsqpack_header **qhl_headers;
|
332
|
+
unsigned qhl_count;
|
333
|
+
};
|
334
|
+
|
335
|
+
void
|
336
|
+
lsqpack_dec_init (struct lsqpack_dec *, void *logger_ctx,
|
337
|
+
unsigned dyn_table_size, unsigned max_risked_streams,
|
338
|
+
void (*hblock_unblocked)(void *hblock_ctx));
|
339
|
+
|
340
|
+
/**
|
341
|
+
* Values returned by @ref lsqpack_dec_header_in() and
|
342
|
+
* @ref lsqpack_dec_header_read()
|
343
|
+
*/
|
344
|
+
enum lsqpack_read_header_status
|
345
|
+
{
|
346
|
+
/**
|
347
|
+
* The header list has been placed in `hlist' and `buf' has been advanced.
|
348
|
+
* This header should be released using
|
349
|
+
* @ref lsqpack_dec_destroy_header_list() after the caller is done with it.
|
350
|
+
*
|
351
|
+
* Note that the header list in `hlist' has an unlimited lifetime. Even
|
352
|
+
* destroying it after @ref lsqpack_dec_cleanup() is called is OK and
|
353
|
+
* will not leak memory.
|
354
|
+
*/
|
355
|
+
LQRHS_DONE,
|
356
|
+
/**
|
357
|
+
* The decoder cannot decode the header block until more dynamic table
|
358
|
+
* entries become available. `buf' is advanced. When the header block
|
359
|
+
* becomes unblocked, the decoder will call hblock_unblocked() callback
|
360
|
+
* specified in the constructor. See @ref lsqpack_dec_init().
|
361
|
+
*
|
362
|
+
* Once a header block is unblocked, it cannot get blocked again. In
|
363
|
+
* other words, this status can only be returned once per header block.
|
364
|
+
*/
|
365
|
+
LQRHS_BLOCKED,
|
366
|
+
/**
|
367
|
+
* The decoder needs more bytes from the header block to proceed. When
|
368
|
+
* they become available, call @ref lsqpack_dec_header_read(). `buf' is
|
369
|
+
* advanced.
|
370
|
+
*/
|
371
|
+
LQRHS_NEED,
|
372
|
+
/**
|
373
|
+
* An error has occurred. This can be any error: decoding error, memory
|
374
|
+
* allocation failure, or some internal error.
|
375
|
+
*/
|
376
|
+
LQRHS_ERROR,
|
377
|
+
};
|
378
|
+
|
379
|
+
/**
|
380
|
+
* Number of bytes needed to encode the longest Header Acknowledgement
|
381
|
+
* instruction.
|
382
|
+
*/
|
383
|
+
#define LSQPACK_LONGEST_HEADER_ACK 10
|
384
|
+
|
385
|
+
|
386
|
+
/**
|
387
|
+
* Call this function when the header blocks is first read. The decoder
|
388
|
+
* will try to decode the header block. The decoder can process header
|
389
|
+
* blocks in a streaming fashion, which means that there is no need to
|
390
|
+
* buffer the header block. As soon as header block bytes become available,
|
391
|
+
* they can be fed to this function or @ref lsqpack_dec_header_read().
|
392
|
+
*
|
393
|
+
* See @ref lsqpack_read_header_status for explanation of the return codes.
|
394
|
+
*
|
395
|
+
* If the decoder returns LQRHS_NEED or LQRHS_BLOCKED, it keeps a reference to
|
396
|
+
* the user-provided header block context `hblock_ctx'. It uses this value for
|
397
|
+
* two purposes:
|
398
|
+
* 1. to use as argument to hblock_unblocked(); and
|
399
|
+
* 2. to locate header block state when @ref lsqpack_dec_header_read() is
|
400
|
+
* called.
|
401
|
+
*
|
402
|
+
* If the decoder returns LQRHS_DONE or LQRHS_ERROR, it means that it no
|
403
|
+
* longer has a reference to the header block.
|
404
|
+
*/
|
405
|
+
enum lsqpack_read_header_status
|
406
|
+
lsqpack_dec_header_in (struct lsqpack_dec *, void *hblock_ctx,
|
407
|
+
uint64_t stream_id, size_t header_block_size,
|
408
|
+
const unsigned char **buf, size_t bufsz,
|
409
|
+
struct lsqpack_header_list **hlist,
|
410
|
+
unsigned char *dec_buf, size_t *dec_buf_sz);
|
411
|
+
|
412
|
+
/**
|
413
|
+
* Call this function when more header block bytes are become available
|
414
|
+
* after this function or @ref lsqpack_dec_header_in() returned LQRHS_NEED
|
415
|
+
* or hblock_unblocked() callback has been called. This function behaves
|
416
|
+
* similarly to @ref lsqpack_dec_header_in(): see its comments for more
|
417
|
+
* information.
|
418
|
+
*/
|
419
|
+
enum lsqpack_read_header_status
|
420
|
+
lsqpack_dec_header_read (struct lsqpack_dec *dec, void *hblock_ctx,
|
421
|
+
const unsigned char **buf, size_t bufsz,
|
422
|
+
struct lsqpack_header_list **hlist,
|
423
|
+
unsigned char *dec_buf, size_t *dec_buf_sz);
|
424
|
+
|
425
|
+
/**
|
426
|
+
* Feed encoder stream data to the decoder. Zero is returned on success,
|
427
|
+
* negative value on error.
|
428
|
+
*/
|
429
|
+
int
|
430
|
+
lsqpack_dec_enc_in (struct lsqpack_dec *, const unsigned char *, size_t);
|
431
|
+
|
432
|
+
/**
|
433
|
+
* Destroy the header list returned by either
|
434
|
+
* @ref lsqpack_dec_header_in() or @ref lsqpack_dec_header_read().
|
435
|
+
*/
|
436
|
+
void
|
437
|
+
lsqpack_dec_destroy_header_list (struct lsqpack_header_list *);
|
438
|
+
|
439
|
+
/**
|
440
|
+
* Returns true if Insert Count Increment (ICI) instruction is pending.
|
441
|
+
*/
|
442
|
+
int
|
443
|
+
lsqpack_dec_ici_pending (const struct lsqpack_dec *dec);
|
444
|
+
|
445
|
+
/**
|
446
|
+
* Number of bytes required to encode the longest Insert Count Increment (ICI)
|
447
|
+
* instruction.
|
448
|
+
*/
|
449
|
+
#define LSQPACK_LONGEST_ICI 6
|
450
|
+
|
451
|
+
ssize_t
|
452
|
+
lsqpack_dec_write_ici (struct lsqpack_dec *, unsigned char *, size_t);
|
453
|
+
|
454
|
+
/** Number of bytes required to encode the longest cancel instruction */
|
455
|
+
#define LSQPACK_LONGEST_CANCEL 6
|
456
|
+
|
457
|
+
/**
|
458
|
+
* Cancel stream associated with the header block context `hblock_ctx' and
|
459
|
+
* write cancellation instruction to `buf'. `buf' must be at least
|
460
|
+
* @ref LSQPACK_LONGEST_CANCEL bytes long.
|
461
|
+
*
|
462
|
+
* Number of bytes written to `buf' is returned. If stream `stream_id'
|
463
|
+
* could not be found, zero is returned. If `buf' is too short, -1 is
|
464
|
+
* returned.
|
465
|
+
*/
|
466
|
+
ssize_t
|
467
|
+
lsqpack_dec_cancel_stream (struct lsqpack_dec *, void *hblock_ctx,
|
468
|
+
unsigned char *buf, size_t buf_sz);
|
469
|
+
|
470
|
+
/**
|
471
|
+
* Generate Cancel Stream instruction for stream `stream_id'. Call when
|
472
|
+
* abandoning stream (see [draft-ietf-quic-qpack-14] Section 2.2.2.2).
|
473
|
+
*
|
474
|
+
* Return values:
|
475
|
+
* -1 error (`buf' is too short)
|
476
|
+
* 0 Emitting Cancel Stream instruction is unnecessary
|
477
|
+
* >0 Size of Cancel Stream instruction written to `buf'.
|
478
|
+
*/
|
479
|
+
ssize_t
|
480
|
+
lsqpack_dec_cancel_stream_id (struct lsqpack_dec *dec, uint64_t stream_id,
|
481
|
+
unsigned char *buf, size_t buf_sz);
|
482
|
+
|
483
|
+
/**
|
484
|
+
* Delete reference to the header block context `hblock_ctx'. Use this
|
485
|
+
* instead of @ref lsqpack_dec_cancel_stream() when producing a Cancel Stream
|
486
|
+
* instruction is not necessary.
|
487
|
+
*/
|
488
|
+
int
|
489
|
+
lsqpack_dec_unref_stream (struct lsqpack_dec *, void *hblock_ctx);
|
490
|
+
|
491
|
+
/**
|
492
|
+
* Return estimated compression ratio until this point. Compression ratio
|
493
|
+
* is defined as size of the input divided by the size of the output, where
|
494
|
+
* input includes both header blocks and instructions received on the encoder
|
495
|
+
* stream.
|
496
|
+
*/
|
497
|
+
float
|
498
|
+
lsqpack_dec_ratio (const struct lsqpack_dec *);
|
499
|
+
|
500
|
+
/**
|
501
|
+
* Clean up the decoder. If any there are any blocked header blocks,
|
502
|
+
* references to them will be discarded.
|
503
|
+
*/
|
504
|
+
void
|
505
|
+
lsqpack_dec_cleanup (struct lsqpack_dec *);
|
506
|
+
|
507
|
+
/**
|
508
|
+
* Print human-readable decoder table.
|
509
|
+
*/
|
510
|
+
void
|
511
|
+
lsqpack_dec_print_table (const struct lsqpack_dec *, FILE *out);
|
512
|
+
|
513
|
+
|
514
|
+
struct lsqpack_dec_err
|
515
|
+
{
|
516
|
+
enum {
|
517
|
+
LSQPACK_DEC_ERR_LOC_HEADER_BLOCK,
|
518
|
+
LSQPACK_DEC_ERR_LOC_ENC_STREAM,
|
519
|
+
} type;
|
520
|
+
int line; /* In the source file */
|
521
|
+
uint64_t off; /* Offset in header block or on encoder stream */
|
522
|
+
uint64_t stream_id; /* Only applicable to header block */
|
523
|
+
};
|
524
|
+
|
525
|
+
|
526
|
+
const struct lsqpack_dec_err *
|
527
|
+
lsqpack_dec_get_err_info (const struct lsqpack_dec *);
|
528
|
+
|
529
|
+
/**
|
530
|
+
* Look for match in static table.
|
531
|
+
*
|
532
|
+
* Return a non-negative integer on success -- that's the static table ID --
|
533
|
+
* or -1 on failure.
|
534
|
+
*/
|
535
|
+
int
|
536
|
+
lsqpack_get_stx_tab_id (const char *name, size_t,
|
537
|
+
const char *val, size_t val_len);
|
538
|
+
|
539
|
+
/*
|
540
|
+
* Internals follow. The internals are subject to change without notice.
|
541
|
+
*/
|
542
|
+
|
543
|
+
#include <sys/queue.h>
|
544
|
+
|
545
|
+
/* It takes 11 bytes to encode UINT64_MAX as HPACK integer */
|
546
|
+
#define LSQPACK_UINT64_ENC_SZ 11u
|
547
|
+
|
548
|
+
struct lsqpack_enc_table_entry;
|
549
|
+
|
550
|
+
STAILQ_HEAD(lsqpack_enc_head, lsqpack_enc_table_entry);
|
551
|
+
struct lsqpack_double_enc_head;
|
552
|
+
|
553
|
+
struct lsqpack_header_info_arr;
|
554
|
+
|
555
|
+
struct lsqpack_dec_int_state
|
556
|
+
{
|
557
|
+
int resume;
|
558
|
+
unsigned M, nread;
|
559
|
+
uint64_t val;
|
560
|
+
};
|
561
|
+
|
562
|
+
struct lsqpack_enc
|
563
|
+
{
|
564
|
+
/* The number of all the entries in the dynamic table that have been
|
565
|
+
* created so far. This is used to calculate the Absolute Index.
|
566
|
+
*/
|
567
|
+
lsqpack_abs_id_t qpe_ins_count;
|
568
|
+
lsqpack_abs_id_t qpe_max_acked_id;
|
569
|
+
lsqpack_abs_id_t qpe_last_ici;
|
570
|
+
|
571
|
+
enum {
|
572
|
+
LSQPACK_ENC_HEADER = 1 << 0,
|
573
|
+
LSQPACK_ENC_USE_DUP = 1 << 1,
|
574
|
+
LSQPACK_ENC_NO_MEM_GUARD = 1 << 2,
|
575
|
+
} qpe_flags;
|
576
|
+
|
577
|
+
unsigned qpe_cur_bytes_used;
|
578
|
+
unsigned qpe_cur_max_capacity;
|
579
|
+
unsigned qpe_real_max_capacity;
|
580
|
+
unsigned qpe_max_entries;
|
581
|
+
/* Sum of all dropped entries. OK if it overflows. */
|
582
|
+
unsigned qpe_dropped;
|
583
|
+
|
584
|
+
/* The maximum risked streams is the SETTINGS_QPACK_BLOCKED_STREAMS
|
585
|
+
* setting. Note that streams must be differentiated from headers.
|
586
|
+
*/
|
587
|
+
unsigned qpe_max_risked_streams;
|
588
|
+
unsigned qpe_cur_streams_at_risk;
|
589
|
+
|
590
|
+
/* Number of used entries in qpe_hinfo_arrs */
|
591
|
+
unsigned qpe_hinfo_arrs_count;
|
592
|
+
|
593
|
+
/* Dynamic table entries (struct enc_table_entry) live in two hash
|
594
|
+
* tables: name/value hash table and name hash table. These tables
|
595
|
+
* are the same size.
|
596
|
+
*/
|
597
|
+
unsigned qpe_nelem;
|
598
|
+
unsigned qpe_nbits;
|
599
|
+
struct lsqpack_enc_head qpe_all_entries;
|
600
|
+
struct lsqpack_double_enc_head
|
601
|
+
*qpe_buckets;
|
602
|
+
|
603
|
+
STAILQ_HEAD(, lsqpack_header_info_arr)
|
604
|
+
qpe_hinfo_arrs;
|
605
|
+
TAILQ_HEAD(, lsqpack_header_info)
|
606
|
+
qpe_all_hinfos;
|
607
|
+
TAILQ_HEAD(, lsqpack_header_info)
|
608
|
+
qpe_risked_hinfos;
|
609
|
+
|
610
|
+
/* Current header state */
|
611
|
+
struct {
|
612
|
+
struct lsqpack_header_info *hinfo, *other_at_risk;
|
613
|
+
|
614
|
+
/* Number of headers in this header list added to the history */
|
615
|
+
unsigned n_hdr_added_to_hist;
|
616
|
+
lsqpack_abs_id_t min_reffed;
|
617
|
+
enum lsqpack_enc_header_flags
|
618
|
+
flags;
|
619
|
+
lsqpack_abs_id_t base_idx;
|
620
|
+
} qpe_cur_header;
|
621
|
+
|
622
|
+
struct {
|
623
|
+
struct lsqpack_dec_int_state dec_int_state;
|
624
|
+
int (*handler)(struct lsqpack_enc *, uint64_t);
|
625
|
+
} qpe_dec_stream_state;
|
626
|
+
|
627
|
+
/* Used to calculate estimated compression ratio. Note that the `out'
|
628
|
+
* part contains bytes sent on the decoder stream, as it also counts
|
629
|
+
* toward the overhead.
|
630
|
+
*/
|
631
|
+
unsigned qpe_bytes_in;
|
632
|
+
unsigned qpe_bytes_out;
|
633
|
+
void *qpe_logger_ctx;
|
634
|
+
|
635
|
+
/* Exponential moving averages (EMAs) of the number of elements in the
|
636
|
+
* dynamic table and the number of header fields in a single header list.
|
637
|
+
* These values are used to adjust history size.
|
638
|
+
*/
|
639
|
+
float qpe_table_nelem_ema;
|
640
|
+
float qpe_header_count_ema;
|
641
|
+
|
642
|
+
struct lsqpack_hist_el *qpe_hist_els;
|
643
|
+
unsigned qpe_hist_idx;
|
644
|
+
unsigned qpe_hist_nels;
|
645
|
+
int qpe_hist_wrapped;
|
646
|
+
};
|
647
|
+
|
648
|
+
struct lsqpack_ringbuf
|
649
|
+
{
|
650
|
+
unsigned rb_nalloc, rb_head, rb_tail;
|
651
|
+
void **rb_els;
|
652
|
+
};
|
653
|
+
|
654
|
+
TAILQ_HEAD(lsqpack_header_sets, lsqpack_header_set_elem);
|
655
|
+
|
656
|
+
struct lsqpack_header_block;
|
657
|
+
|
658
|
+
struct lsqpack_decode_status
|
659
|
+
{
|
660
|
+
uint8_t state;
|
661
|
+
uint8_t eos;
|
662
|
+
};
|
663
|
+
|
664
|
+
struct lsqpack_huff_decode_state
|
665
|
+
{
|
666
|
+
int resume;
|
667
|
+
struct lsqpack_decode_status status;
|
668
|
+
};
|
669
|
+
|
670
|
+
struct lsqpack_dec_inst;
|
671
|
+
|
672
|
+
struct lsqpack_dec
|
673
|
+
{
|
674
|
+
/** This is the hard limit set at initialization */
|
675
|
+
unsigned qpd_max_capacity;
|
676
|
+
/** The current maximum capacity can be adjusted at run-time */
|
677
|
+
unsigned qpd_cur_max_capacity;
|
678
|
+
unsigned qpd_cur_capacity;
|
679
|
+
unsigned qpd_max_risked_streams;
|
680
|
+
unsigned qpd_max_entries;
|
681
|
+
/* Used to calculate estimated compression ratio. Note that the `in'
|
682
|
+
* part contains bytes sent on the decoder stream, as it also counts
|
683
|
+
* toward the overhead.
|
684
|
+
*/
|
685
|
+
unsigned qpd_bytes_in;
|
686
|
+
unsigned qpd_bytes_out;
|
687
|
+
/** ID of the last dynamic table entry. Has the range
|
688
|
+
* [0, qpd_max_entries * 2 - 1 ]
|
689
|
+
*/
|
690
|
+
lsqpack_abs_id_t qpd_last_id;
|
691
|
+
/** TODO: describe the mechanism */
|
692
|
+
lsqpack_abs_id_t qpd_largest_known_id;
|
693
|
+
void (*qpd_hblock_unblocked)(void *hblock_ctx);
|
694
|
+
|
695
|
+
void *qpd_logger_ctx;
|
696
|
+
|
697
|
+
/** This is the dynamic table */
|
698
|
+
struct lsqpack_ringbuf qpd_dyn_table;
|
699
|
+
|
700
|
+
TAILQ_HEAD(, header_block_read_ctx)
|
701
|
+
qpd_hbrcs;
|
702
|
+
|
703
|
+
/** Blocked headers are kept in a small hash */
|
704
|
+
#define LSQPACK_DEC_BLOCKED_BITS 3
|
705
|
+
TAILQ_HEAD(, header_block_read_ctx)
|
706
|
+
qpd_blocked_headers[1 << LSQPACK_DEC_BLOCKED_BITS];
|
707
|
+
/** Number of blocked streams (in qpd_blocked_headers) */
|
708
|
+
unsigned qpd_n_blocked;
|
709
|
+
|
710
|
+
/** Average number of header fields in header list */
|
711
|
+
float qpd_hlist_size_ema;
|
712
|
+
|
713
|
+
/** Reading the encoder stream */
|
714
|
+
struct {
|
715
|
+
int resume;
|
716
|
+
union {
|
717
|
+
/* State for reading in the Insert With Named Reference
|
718
|
+
* instruction.
|
719
|
+
*/
|
720
|
+
struct {
|
721
|
+
struct lsqpack_dec_int_state dec_int_state;
|
722
|
+
struct lsqpack_huff_decode_state dec_huff_state;
|
723
|
+
unsigned name_idx;
|
724
|
+
unsigned val_len;
|
725
|
+
struct lsqpack_dec_table_entry *reffed_entry;
|
726
|
+
struct lsqpack_dec_table_entry *entry;
|
727
|
+
const char *name;
|
728
|
+
unsigned alloced_val_len;
|
729
|
+
unsigned val_off;
|
730
|
+
unsigned nread;
|
731
|
+
unsigned name_len;
|
732
|
+
signed char is_huffman;
|
733
|
+
signed char is_static;
|
734
|
+
} with_namref;
|
735
|
+
|
736
|
+
/* State for reading in the Insert Without Named Reference
|
737
|
+
* instruction.
|
738
|
+
*/
|
739
|
+
struct {
|
740
|
+
struct lsqpack_dec_int_state dec_int_state;
|
741
|
+
struct lsqpack_huff_decode_state dec_huff_state;
|
742
|
+
unsigned str_len;
|
743
|
+
struct lsqpack_dec_table_entry *entry;
|
744
|
+
unsigned alloced_len;
|
745
|
+
unsigned str_off;
|
746
|
+
unsigned nread;
|
747
|
+
signed char is_huffman;
|
748
|
+
} wo_namref;
|
749
|
+
|
750
|
+
struct {
|
751
|
+
struct lsqpack_dec_int_state dec_int_state;
|
752
|
+
unsigned index;
|
753
|
+
} duplicate;
|
754
|
+
|
755
|
+
struct {
|
756
|
+
struct lsqpack_dec_int_state dec_int_state;
|
757
|
+
uint64_t new_size;
|
758
|
+
} sdtc;
|
759
|
+
} ctx_u;
|
760
|
+
} qpd_enc_state;
|
761
|
+
struct lsqpack_dec_err qpd_err;
|
762
|
+
};
|
763
|
+
|
764
|
+
#ifdef __cplusplus
|
765
|
+
}
|
766
|
+
#endif
|
767
|
+
|
768
|
+
#endif
|