lsqpack 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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