lsqpack 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (89) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +19 -0
  3. data/Gemfile.lock +82 -0
  4. data/LICENSE +21 -0
  5. data/README.md +36 -0
  6. data/Rakefile +19 -0
  7. data/Steepfile +6 -0
  8. data/ext/lsqpack/extconf.rb +18 -0
  9. data/ext/lsqpack/lsqpack.c +426 -0
  10. data/ext/lsqpack/lsqpack.h +6 -0
  11. data/lib/lsqpack/version.rb +5 -0
  12. data/lib/lsqpack.rb +30 -0
  13. data/ls-qpack/.appveyor.yml +14 -0
  14. data/ls-qpack/.cirrus.yml +6 -0
  15. data/ls-qpack/.travis.yml +32 -0
  16. data/ls-qpack/CMakeLists.txt +66 -0
  17. data/ls-qpack/LICENSE +21 -0
  18. data/ls-qpack/README.md +65 -0
  19. data/ls-qpack/bin/CMakeLists.txt +21 -0
  20. data/ls-qpack/bin/encode-int.c +87 -0
  21. data/ls-qpack/bin/fuzz-decode.c +247 -0
  22. data/ls-qpack/bin/interop-decode.c +433 -0
  23. data/ls-qpack/bin/interop-encode.c +554 -0
  24. data/ls-qpack/deps/xxhash/xxhash.c +941 -0
  25. data/ls-qpack/deps/xxhash/xxhash.h +160 -0
  26. data/ls-qpack/fuzz/decode/a/README +3 -0
  27. data/ls-qpack/fuzz/decode/a/preamble +0 -0
  28. data/ls-qpack/fuzz/decode/a/test-cases/id_000000,sig_06,src_000390,op_havoc,rep_4 +0 -0
  29. data/ls-qpack/fuzz/decode/a/test-cases/id_000000,sig_06,src_000579,op_flip1,pos_14 +0 -0
  30. data/ls-qpack/fuzz/decode/a/test-cases/id_000000,src_000000,op_flip2,pos_12 +0 -0
  31. data/ls-qpack/fuzz/decode/a/test-cases/id_000001,sig_11,src_000579,op_havoc,rep_4 +0 -0
  32. data/ls-qpack/fuzz/decode/a/test-cases/id_000002,sig_11,src_000481,op_int16,pos_15,val_-1 +0 -0
  33. data/ls-qpack/fuzz/decode/a/test-cases/id_000002,src_000000,op_havoc,rep_8 +0 -0
  34. data/ls-qpack/fuzz/decode/a/test-cases/id_000006,src_000285,op_flip2,pos_14 +0 -0
  35. data/ls-qpack/fuzz/decode/a/test-cases/id_000008,src_000285,op_flip2,pos_20 +0 -0
  36. data/ls-qpack/fuzz/decode/a/test-cases/id_000010,src_000306,op_flip2,pos_75 +0 -0
  37. data/ls-qpack/fuzz/decode/a/test-cases/id_000011,src_000344,op_havoc,rep_2 +0 -0
  38. data/ls-qpack/fuzz/decode/a/test-cases/id_000014,src_000366,op_flip2,pos_28 +0 -0
  39. data/ls-qpack/fuzz/decode/b/README +1 -0
  40. data/ls-qpack/fuzz/decode/b/preamble +0 -0
  41. data/ls-qpack/fuzz/decode/b/test-cases/seed +0 -0
  42. data/ls-qpack/fuzz/decode/c/setup.sh +3 -0
  43. data/ls-qpack/fuzz/decode/c/test-cases/fb-req.qif.proxygen.out.256.100.0-chopped +0 -0
  44. data/ls-qpack/fuzz/decode/d/preamble +0 -0
  45. data/ls-qpack/fuzz/decode/d/setup.sh +3 -0
  46. data/ls-qpack/fuzz/decode/d/test-cases/fb-resp.minhq.256.128.0.ack +0 -0
  47. data/ls-qpack/fuzz/input/256.100.1/fb-req.out.256.100.1 +0 -0
  48. data/ls-qpack/fuzz/input/256.100.1/fb-resp.out.256.100.1 +0 -0
  49. data/ls-qpack/fuzz/input/256.100.1/netbsd.out.256.100.1 +0 -0
  50. data/ls-qpack/huff-tables.h +136247 -0
  51. data/ls-qpack/lsqpack.c +5547 -0
  52. data/ls-qpack/lsqpack.h +768 -0
  53. data/ls-qpack/test/CMakeLists.txt +76 -0
  54. data/ls-qpack/test/lsqpack-test.h +43 -0
  55. data/ls-qpack/test/qifs/fb-req.qif +4917 -0
  56. data/ls-qpack/test/qifs/fb-resp.qif +5982 -0
  57. data/ls-qpack/test/qifs/long-codes.qif +5984 -0
  58. data/ls-qpack/test/qifs/netbsd.qif +235 -0
  59. data/ls-qpack/test/run-qif.pl +97 -0
  60. data/ls-qpack/test/run-scenario.sh +68 -0
  61. data/ls-qpack/test/scenarios/0.95-reset.sce +10 -0
  62. data/ls-qpack/test/scenarios/cancel-stream.sce +22 -0
  63. data/ls-qpack/test/scenarios/drain-2.sce +37 -0
  64. data/ls-qpack/test/scenarios/drain.sce +37 -0
  65. data/ls-qpack/test/scenarios/end-dst-2.sce +14 -0
  66. data/ls-qpack/test/scenarios/end-dst.sce +14 -0
  67. data/ls-qpack/test/scenarios/incl-name.sce +13 -0
  68. data/ls-qpack/test/scenarios/multi-byte-int-dyn-ref-1.sce +110 -0
  69. data/ls-qpack/test/scenarios/multi-byte-int-dyn-ref-2.sce +161 -0
  70. data/ls-qpack/test/scenarios/post-base-1.sce +10 -0
  71. data/ls-qpack/test/scenarios/post-base-2.sce +13 -0
  72. data/ls-qpack/test/scenarios/post-base-nr.sce +10 -0
  73. data/ls-qpack/test/scenarios/set-max-cap.sce +15 -0
  74. data/ls-qpack/test/test_enc_str.c +139 -0
  75. data/ls-qpack/test/test_get_stx_id.c +144 -0
  76. data/ls-qpack/test/test_huff_dec.c +399 -0
  77. data/ls-qpack/test/test_int.c +220 -0
  78. data/ls-qpack/test/test_qpack.c +856 -0
  79. data/ls-qpack/test/test_read_enc_stream.c +256 -0
  80. data/ls-qpack/tools/har2qif.pl +139 -0
  81. data/ls-qpack/tools/randomize-cookies.pl +41 -0
  82. data/ls-qpack/tools/sort-qif.pl +31 -0
  83. data/ls-qpack/wincompat/getopt.c +758 -0
  84. data/ls-qpack/wincompat/getopt.h +131 -0
  85. data/ls-qpack/wincompat/getopt1.c +188 -0
  86. data/ls-qpack/wincompat/sys/queue.h +859 -0
  87. data/lsqpack.gemspec +39 -0
  88. data/sig/lsqpack.rbs +29 -0
  89. metadata +135 -0
@@ -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