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,856 @@
1
+ /*
2
+ * Test QPACK.
3
+ */
4
+
5
+ #include <assert.h>
6
+ #include <ctype.h>
7
+ #include <stdint.h>
8
+ #include <stdio.h>
9
+ #include <stdlib.h>
10
+ #include <string.h>
11
+
12
+ #include "lsqpack.h"
13
+ #include "lsqpack-test.h"
14
+
15
+ #define ENC_BUF_SZ 200
16
+ #define HEADER_BUF_SZ 200
17
+ #define PREFIX_BUF_SZ 10
18
+
19
+ static const struct qpack_header_block_test
20
+ {
21
+ /* Identification: */
22
+ int qhbt_lineno;
23
+
24
+ /* Input: */
25
+ unsigned qhbt_table_size;
26
+ unsigned qhbt_max_risked_streams;
27
+ unsigned qhbt_n_headers;
28
+ struct {
29
+ const char *name, *value;
30
+ enum lsqpack_enc_flags flags;
31
+ } qhbt_headers[10];
32
+
33
+ /* Output: */
34
+ size_t qhbt_enc_sz;
35
+ unsigned char qhbt_enc_buf[ENC_BUF_SZ];
36
+
37
+ size_t qhbt_prefix_sz;
38
+ unsigned char qhbt_prefix_buf[PREFIX_BUF_SZ];
39
+
40
+ size_t qhbt_header_sz;
41
+ unsigned char qhbt_header_buf[HEADER_BUF_SZ];
42
+ } header_block_tests[] =
43
+ {
44
+
45
+ {
46
+ .qhbt_lineno = __LINE__,
47
+ .qhbt_table_size = 0x1000,
48
+ .qhbt_max_risked_streams = 100,
49
+ .qhbt_n_headers = 1,
50
+ .qhbt_headers = {
51
+ { ":method", "GET", 0, },
52
+ },
53
+ .qhbt_enc_sz = 0,
54
+ .qhbt_prefix_sz = 2,
55
+ .qhbt_prefix_buf = "\x00\x00",
56
+ .qhbt_header_sz = 1,
57
+ .qhbt_header_buf = {
58
+ 0x80 | 0x40 | 17,
59
+ },
60
+ },
61
+
62
+ {
63
+ .qhbt_lineno = __LINE__,
64
+ .qhbt_table_size = 0x1000,
65
+ .qhbt_max_risked_streams = 100,
66
+ .qhbt_n_headers = 1,
67
+ .qhbt_headers = {
68
+ { ":method", "method", LQEF_NEVER_INDEX, },
69
+ },
70
+ .qhbt_enc_sz = 0,
71
+ .qhbt_prefix_sz = 2,
72
+ .qhbt_prefix_buf = "\x00\x00",
73
+ .qhbt_header_sz = 8,
74
+ .qhbt_header_buf = {
75
+ 0x40 | 0x20 | 0x10 | 0x0F, 0x00,
76
+ 0x80 /* Huffman */ | 5 /* length */,
77
+ 0xa4, 0xa9, 0x9c, 0xf2, 0x7f,
78
+ },
79
+ },
80
+
81
+ {
82
+ .qhbt_lineno = __LINE__,
83
+ .qhbt_table_size = 0x1000,
84
+ .qhbt_max_risked_streams = 0,
85
+ .qhbt_n_headers = 1,
86
+ .qhbt_headers = {
87
+ { ":method", "method", 0, },
88
+ },
89
+ .qhbt_enc_sz = 7,
90
+ .qhbt_enc_buf = {
91
+ 0x80 | 0x40 /* static */ | 15 /* name index */,
92
+ 0x80 /* Huffman */ | 5 /* length */,
93
+ 0xa4, 0xa9, 0x9c, 0xf2, 0x7f,
94
+ },
95
+ .qhbt_prefix_sz = 2,
96
+ .qhbt_prefix_buf = "\x00\x00",
97
+ .qhbt_header_sz = 8,
98
+ .qhbt_header_buf = {
99
+ 0x40 | 0x10 /* Static */ | 15, 0x00,
100
+ 0x80 /* Huffman */ | 5 /* length */,
101
+ 0xa4, 0xa9, 0x9c, 0xf2, 0x7f,
102
+ },
103
+ },
104
+
105
+ {
106
+ .qhbt_lineno = __LINE__,
107
+ .qhbt_table_size = 0x1000,
108
+ .qhbt_max_risked_streams = 0x1000,
109
+ .qhbt_n_headers = 1,
110
+ .qhbt_headers = {
111
+ { ":method", "method", 0, },
112
+ },
113
+ .qhbt_enc_sz = 7,
114
+ .qhbt_enc_buf = {
115
+ 0x80 | 0x40 /* static */ | 15 /* name index */,
116
+ 0x80 /* Huffman */ | 5 /* length */,
117
+ 0xa4, 0xa9, 0x9c, 0xf2, 0x7f,
118
+ },
119
+ .qhbt_prefix_sz = 2,
120
+ .qhbt_prefix_buf = { 0x02, 0x80, },
121
+ .qhbt_header_sz = 1,
122
+ .qhbt_header_buf = {
123
+ 0x10 | 0 /* Relative dynamic ID */,
124
+ },
125
+ },
126
+
127
+ {
128
+ .qhbt_lineno = __LINE__,
129
+ .qhbt_table_size = 0x1000,
130
+ .qhbt_max_risked_streams = 0x1000,
131
+ .qhbt_n_headers = 1,
132
+ .qhbt_headers = {
133
+ { "dude", "where is my car?", LQEF_NEVER_INDEX, },
134
+ },
135
+ .qhbt_enc_sz = 0,
136
+ .qhbt_prefix_sz = 2,
137
+ .qhbt_prefix_buf = "\x00\x00",
138
+ .qhbt_header_sz = 17,
139
+ .qhbt_header_buf = {
140
+ 0x20 | 0x10 /* No index */ | 0x08 | 3,
141
+ 0x92, 0xd9, 0x0b,
142
+ 0x80 | 0xC,
143
+ 0xf1, 0x39, 0x6c, 0x2a, 0x86, 0x42, 0x94, 0xfa,
144
+ 0x50, 0x83, 0xb3, 0xfc,
145
+ },
146
+ },
147
+
148
+ {
149
+ .qhbt_lineno = __LINE__,
150
+ .qhbt_table_size = 0x1000,
151
+ .qhbt_max_risked_streams = 0,
152
+ .qhbt_n_headers = 1,
153
+ .qhbt_headers = {
154
+ { "dude", "where is my car?", 0, },
155
+ },
156
+ .qhbt_enc_sz = 17,
157
+ .qhbt_enc_buf = {
158
+ 0x40 | 0x20 | 3,
159
+ 0x92, 0xd9, 0x0b,
160
+ 0x80 | 0xC,
161
+ 0xf1, 0x39, 0x6c, 0x2a, 0x86, 0x42, 0x94, 0xfa,
162
+ 0x50, 0x83, 0xb3, 0xfc,
163
+ },
164
+ .qhbt_prefix_sz = 2,
165
+ .qhbt_prefix_buf = "\x00\x00",
166
+ .qhbt_header_sz = 17,
167
+ .qhbt_header_buf = {
168
+ 0x20 | 0x08 | 3,
169
+ 0x92, 0xd9, 0x0b,
170
+ 0x80 | 0xC,
171
+ 0xf1, 0x39, 0x6c, 0x2a, 0x86, 0x42, 0x94, 0xfa,
172
+ 0x50, 0x83, 0xb3, 0xfc,
173
+ },
174
+ },
175
+
176
+ {
177
+ .qhbt_lineno = __LINE__,
178
+ .qhbt_table_size = 0x1000,
179
+ .qhbt_max_risked_streams = 1,
180
+ .qhbt_n_headers = 1,
181
+ .qhbt_headers = {
182
+ { "dude", "where is my car?", 0, },
183
+ },
184
+ .qhbt_enc_sz = 17,
185
+ .qhbt_enc_buf = {
186
+ 0x40 | 0x20 | 3,
187
+ 0x92, 0xd9, 0x0b,
188
+ 0x80 | 0xC,
189
+ 0xf1, 0x39, 0x6c, 0x2a, 0x86, 0x42, 0x94, 0xfa,
190
+ 0x50, 0x83, 0xb3, 0xfc,
191
+ },
192
+ .qhbt_prefix_sz = 2,
193
+ .qhbt_prefix_buf = { 0x02, 0x80, },
194
+ .qhbt_header_sz = 1,
195
+ .qhbt_header_buf = {
196
+ 0x10 | 0 /* Relative dynamic ID */,
197
+ },
198
+ },
199
+
200
+ };
201
+
202
+
203
+ static void
204
+ run_header_test (const struct qpack_header_block_test *test)
205
+ {
206
+ unsigned char header_buf[HEADER_BUF_SZ], enc_buf[ENC_BUF_SZ],
207
+ prefix_buf[PREFIX_BUF_SZ];
208
+ unsigned header_off, enc_off;
209
+ size_t header_sz, enc_sz, dec_sz;
210
+ struct lsqpack_enc enc;
211
+ unsigned i;
212
+ size_t nw;
213
+ int s;
214
+ enum lsqpack_enc_status enc_st;
215
+ float ratio;
216
+ unsigned char dec_buf[LSQPACK_LONGEST_SDTC];
217
+
218
+ dec_sz = sizeof(dec_buf);
219
+ s = lsqpack_enc_init(&enc, stderr, test->qhbt_table_size,
220
+ test->qhbt_table_size, test->qhbt_max_risked_streams,
221
+ LSQPACK_ENC_OPT_IX_AGGR, dec_buf, &dec_sz);
222
+ assert(s == 0);
223
+
224
+ s = lsqpack_enc_start_header(&enc, 0, 0);
225
+ assert(s == 0);
226
+
227
+ header_off = 0, enc_off = 0;
228
+ for (i = 0; i < test->qhbt_n_headers; ++i)
229
+ {
230
+ /* Increase buffers one by one to exercise error conditions */
231
+ enc_sz = 0;
232
+ header_sz = 0;
233
+ while (1)
234
+ {
235
+ enc_st = lsqpack_enc_encode(&enc,
236
+ enc_buf + enc_off, &enc_sz,
237
+ header_buf + header_off, &header_sz,
238
+ test->qhbt_headers[i].name,
239
+ strlen(test->qhbt_headers[i].name),
240
+ test->qhbt_headers[i].value,
241
+ strlen(test->qhbt_headers[i].value),
242
+ test->qhbt_headers[i].flags);
243
+ switch (enc_st)
244
+ {
245
+ case LQES_NOBUF_ENC:
246
+ if (enc_sz < sizeof(enc_buf) - enc_off)
247
+ ++enc_sz;
248
+ else
249
+ assert(0);
250
+ break;
251
+ case LQES_NOBUF_HEAD:
252
+ if (header_sz < sizeof(header_buf) - header_off)
253
+ ++header_sz;
254
+ else
255
+ assert(0);
256
+ break;
257
+ default:
258
+ assert(enc_st == LQES_OK);
259
+ goto end_encode_one_header;
260
+ }
261
+ }
262
+ end_encode_one_header:
263
+ enc_off += enc_sz;
264
+ header_off += header_sz;
265
+ }
266
+
267
+ nw = lsqpack_enc_end_header(&enc, prefix_buf, sizeof(prefix_buf), NULL);
268
+ assert(nw == test->qhbt_prefix_sz);
269
+ assert(0 == memcmp(test->qhbt_prefix_buf, prefix_buf, nw));
270
+ assert(enc_off == test->qhbt_enc_sz);
271
+ assert(0 == memcmp(test->qhbt_enc_buf, enc_buf, enc_off));
272
+ assert(header_off == test->qhbt_header_sz);
273
+ assert(0 == memcmp(test->qhbt_header_buf, header_buf, header_off));
274
+ assert(lsqpack_enc_ratio(&enc) > 0.0);
275
+
276
+ lsqpack_enc_cleanup(&enc);
277
+ }
278
+
279
+ static void
280
+ run_header_cancellation_test(const struct qpack_header_block_test *test) {
281
+ unsigned char header_buf[HEADER_BUF_SZ];
282
+ size_t header_sz, enc_sz;
283
+ struct lsqpack_enc enc;
284
+ int s;
285
+ enum lsqpack_enc_status enc_st;
286
+
287
+ s = lsqpack_enc_init(&enc, stderr, 0, 0, test->qhbt_max_risked_streams,
288
+ LSQPACK_ENC_OPT_IX_AGGR, NULL, NULL);
289
+ assert(s == 0);
290
+
291
+ s = lsqpack_enc_start_header(&enc, 0, 0);
292
+ assert(s == 0);
293
+
294
+ header_sz = HEADER_BUF_SZ;
295
+ enc_sz = 0;
296
+
297
+ enc_st = lsqpack_enc_encode(&enc,
298
+ NULL, &enc_sz,
299
+ header_buf, &header_sz,
300
+ test->qhbt_headers[0].name,
301
+ strlen(test->qhbt_headers[0].name),
302
+ test->qhbt_headers[0].value,
303
+ strlen(test->qhbt_headers[0].value),
304
+ 0);
305
+ assert(enc_st == LQES_OK);
306
+
307
+ s = lsqpack_enc_cancel_header(&enc);
308
+ assert(s == 0);
309
+
310
+ /* Check that we can start again after cancelling. */
311
+ s = lsqpack_enc_start_header(&enc, 0, 0);
312
+ assert(s == 0);
313
+
314
+ lsqpack_enc_cleanup(&enc);
315
+ }
316
+
317
+
318
+ static void
319
+ test_enc_init (void)
320
+ {
321
+ struct lsqpack_enc enc;
322
+ size_t dec_sz;
323
+ int s;
324
+ unsigned i;
325
+ const unsigned char *p;
326
+ uint64_t val;
327
+ struct lsqpack_dec_int_state state;
328
+ unsigned char dec_buf[LSQPACK_LONGEST_SDTC];
329
+
330
+ const struct {
331
+ unsigned peer_max_size; /* Value provided by peer */
332
+ unsigned our_max_size; /* Value to use */
333
+ int expected_tsu; /* Expecting TSU instruction? */
334
+ } tests[] = {
335
+ { 0x1000, 0x1000, 1, },
336
+ { 0x1000, 1, 1, },
337
+ { 0x100, 0x100, 1, },
338
+ { 0x1000, 0, 0, },
339
+ };
340
+
341
+ for (i = 0; i < sizeof(tests) / sizeof(tests[0]); ++i)
342
+ {
343
+ dec_sz = sizeof(dec_buf);
344
+ s = lsqpack_enc_init(&enc, stderr, tests[i].peer_max_size,
345
+ tests[i].our_max_size, 0, 0, dec_buf, &dec_sz);
346
+ assert(s == 0);
347
+ if (tests[i].expected_tsu)
348
+ {
349
+ assert(dec_sz > 0);
350
+ assert((dec_buf[0] & 0xE0) == 0x20);
351
+ p = dec_buf;
352
+ state.resume = 0;
353
+ s = lsqpack_dec_int(&p, p + dec_sz, 5, &val, &state);
354
+ assert(s == 0);
355
+ assert(val == tests[i].our_max_size);
356
+ }
357
+ else
358
+ assert(dec_sz == 0);
359
+ lsqpack_enc_cleanup(&enc);
360
+ }
361
+ }
362
+
363
+
364
+ /* Test that push promise header does not use the dynamic table, nor does
365
+ * it update history.
366
+ */
367
+ static void
368
+ test_push_promise (void)
369
+ {
370
+ struct lsqpack_enc enc;
371
+ ssize_t nw;
372
+ enum lsqpack_enc_status enc_st;
373
+ int s;
374
+ unsigned i;
375
+ const unsigned char *p;
376
+ uint64_t val;
377
+ struct lsqpack_dec_int_state state;
378
+ unsigned char dec_buf[LSQPACK_LONGEST_SDTC];
379
+ unsigned char header_buf[HEADER_BUF_SZ], enc_buf[ENC_BUF_SZ],
380
+ prefix_buf[PREFIX_BUF_SZ];
381
+ size_t header_sz, enc_sz, dec_sz;
382
+ enum lsqpack_enc_header_flags hflags;
383
+
384
+ dec_sz = sizeof(dec_buf);
385
+ s = lsqpack_enc_init(&enc, stderr, 0x1000, 0x1000, 100, 0, dec_buf, &dec_sz);
386
+ assert(0 == s);
387
+
388
+ (void) dec_sz; /* We don't care for this test */
389
+
390
+ s = lsqpack_enc_start_header(&enc, 0, 0);
391
+ assert(0 == s);
392
+ enc_sz = sizeof(enc_buf);
393
+ header_sz = sizeof(header_buf);
394
+ enc_st = lsqpack_enc_encode(&enc,
395
+ enc_buf, &enc_sz, header_buf, &header_sz,
396
+ ":method", 7, "dude!", 5, 0);
397
+ assert(LQES_OK == enc_st);
398
+ enc_sz = sizeof(enc_buf);
399
+ header_sz = sizeof(header_buf);
400
+ enc_st = lsqpack_enc_encode(&enc,
401
+ enc_buf, &enc_sz, header_buf, &header_sz,
402
+ ":method", 7, "dude!", 5, 0);
403
+ assert(LQES_OK == enc_st);
404
+ nw = lsqpack_enc_end_header(&enc, prefix_buf, sizeof(prefix_buf), &hflags);
405
+ assert(2 == nw);
406
+ assert(!(prefix_buf[0] == 0 && prefix_buf[1] == 0)); /* Dynamic table used */
407
+ assert(hflags & LSQECH_REF_NEW_ENTRIES);
408
+ assert(hflags & LSQECH_REF_AT_RISK);
409
+
410
+ s = lsqpack_enc_start_header(&enc, 0, 0);
411
+ assert(0 == s);
412
+ enc_sz = sizeof(enc_buf);
413
+ header_sz = sizeof(header_buf);
414
+ enc_st = lsqpack_enc_encode(&enc,
415
+ enc_buf, &enc_sz, header_buf, &header_sz,
416
+ ":method", 7, "dude!", 5, LQEF_NO_HIST_UPD|LQEF_NO_DYN);
417
+ assert(LQES_OK == enc_st);
418
+ enc_sz = sizeof(enc_buf);
419
+ header_sz = sizeof(header_buf);
420
+ enc_st = lsqpack_enc_encode(&enc,
421
+ enc_buf, &enc_sz, header_buf, &header_sz,
422
+ ":method", 7, "where is my car?", 16, LQEF_NO_HIST_UPD|LQEF_NO_DYN);
423
+ nw = lsqpack_enc_end_header(&enc, prefix_buf, sizeof(prefix_buf), &hflags);
424
+ assert(2 == nw);
425
+ assert(prefix_buf[0] == 0 && prefix_buf[1] == 0); /* Dynamic table not used */
426
+ assert(!(hflags & LSQECH_REF_NEW_ENTRIES));
427
+
428
+ /* Last check that history was not updated: */
429
+ s = lsqpack_enc_start_header(&enc, 4, 0);
430
+ assert(0 == s);
431
+ enc_sz = sizeof(enc_buf);
432
+ header_sz = sizeof(header_buf);
433
+ enc_st = lsqpack_enc_encode(&enc,
434
+ enc_buf, &enc_sz, header_buf, &header_sz,
435
+ ":method", 7, "where is my car?", 16, 0);
436
+ assert(enc_sz == 0);
437
+ assert(LQES_OK == enc_st);
438
+ nw = lsqpack_enc_end_header(&enc, prefix_buf, sizeof(prefix_buf), &hflags);
439
+ assert(2 == nw);
440
+ assert(prefix_buf[0] == 0 && prefix_buf[1] == 0); /* Dynamic table not used */
441
+ assert(!(hflags & LSQECH_REF_AT_RISK));
442
+
443
+ lsqpack_enc_cleanup(&enc);
444
+ }
445
+
446
+
447
+ static void
448
+ test_discard_header (int err)
449
+ {
450
+ struct lsqpack_dec dec;
451
+ enum lsqpack_read_header_status rhs;
452
+ const unsigned char *buf;
453
+ struct lsqpack_header_list *hlist = NULL;
454
+ unsigned char header_block[] = "\x00\x00\xC0\x80";
455
+
456
+ lsqpack_dec_init(&dec, NULL, 0, 0, NULL);
457
+
458
+ buf = header_block;
459
+ rhs = lsqpack_dec_header_in(&dec, (void *) 1, 0, 10,
460
+ &buf, 3 + !!err, &hlist, NULL, NULL);
461
+ if (err)
462
+ {
463
+ assert(hlist == NULL);
464
+ assert(LQRHS_ERROR == rhs);
465
+ }
466
+ else
467
+ {
468
+ assert(hlist == NULL);
469
+ assert(3 == buf - header_block);
470
+ assert(LQRHS_NEED == rhs);
471
+ lsqpack_dec_cleanup(&dec);
472
+ }
473
+ }
474
+
475
+
476
+ static void
477
+ test_static_bounds_header_block (void)
478
+ {
479
+ struct lsqpack_dec dec;
480
+ enum lsqpack_read_header_status rhs;
481
+ const unsigned char *buf;
482
+ struct lsqpack_header_list *hlist = NULL;
483
+ /* Static table index 1000 */
484
+ unsigned char header_block[] = "\x00\x00\xFF\xA9\x07";
485
+
486
+ lsqpack_dec_init(&dec, stderr, 0, 0, NULL);
487
+ buf = header_block;
488
+ rhs = lsqpack_dec_header_in(&dec, (void *) 1, 0, 10,
489
+ &buf, 5, &hlist, NULL, NULL);
490
+ assert(hlist == NULL);
491
+ assert(LQRHS_ERROR == rhs);
492
+ lsqpack_dec_cleanup(&dec);
493
+ }
494
+
495
+
496
+ static void
497
+ test_static_bounds_enc_stream (void)
498
+ {
499
+ struct lsqpack_dec dec;
500
+ int r;
501
+ /* Static table index 1000 */
502
+ unsigned char enc_stream[] = "\xFF\xA9\x07\x04" "dude";
503
+
504
+ lsqpack_dec_init(&dec, stderr, 0, 0, NULL);
505
+ r = lsqpack_dec_enc_in(&dec, enc_stream, 8);
506
+ assert(r == -1);
507
+ lsqpack_dec_cleanup(&dec);
508
+ }
509
+
510
+
511
+ static void
512
+ test_wonr_name_too_large_huffman (void)
513
+ {
514
+ struct lsqpack_dec dec;
515
+ int r;
516
+ /* Partial Insert Without Name Reference with Huffman-encoded name
517
+ * string that is larger than 4 x capacity (0x4001)
518
+ */
519
+ unsigned char enc_stream[] = "\x7F\xE2\x7F";
520
+
521
+ lsqpack_dec_init(&dec, stderr, 0x1000, 0, NULL);
522
+ r = lsqpack_dec_enc_in(&dec, enc_stream, 3);
523
+ assert(r == -1);
524
+ lsqpack_dec_cleanup(&dec);
525
+ }
526
+
527
+
528
+ static void
529
+ test_wonr_name_too_large_plain (void)
530
+ {
531
+ struct lsqpack_dec dec;
532
+ int r;
533
+ /* Partial Insert Without Name Reference with plain-encoded name
534
+ * string that is larger than capacity (0x1001)
535
+ */
536
+ unsigned char enc_stream[] = "\x5F\xE2\x1F";
537
+
538
+ lsqpack_dec_init(&dec, stderr, 0x1000, 0, NULL);
539
+ r = lsqpack_dec_enc_in(&dec, enc_stream, 3);
540
+ assert(r == -1);
541
+ lsqpack_dec_cleanup(&dec);
542
+ }
543
+
544
+
545
+ static void
546
+ test_wonr_value_too_large_huffman (void)
547
+ {
548
+ struct lsqpack_dec dec;
549
+ int r;
550
+ /* Partial Insert Without Name Reference with Huffman-encoded value
551
+ * string that, together with name, is larger than 4 x capacity (0x3FFF)
552
+ */
553
+ unsigned char enc_stream[] = "\x42OK\xFF\x80\x7F";
554
+
555
+ lsqpack_dec_init(&dec, stderr, 0x1000, 0, NULL);
556
+ r = lsqpack_dec_enc_in(&dec, enc_stream, 6);
557
+ assert(r == -1);
558
+ lsqpack_dec_cleanup(&dec);
559
+ }
560
+
561
+
562
+ static void
563
+ test_wonr_value_too_large_plain (void)
564
+ {
565
+ struct lsqpack_dec dec;
566
+ int r;
567
+ /* Partial Insert Without Name Reference with plain-encoded value
568
+ * string that, together with name, is larger than capacity (0xFFF)
569
+ */
570
+ unsigned char enc_stream[] = "\x42OK\x7F\x80\x1F";
571
+
572
+ lsqpack_dec_init(&dec, stderr, 0x1000, 0, NULL);
573
+ r = lsqpack_dec_enc_in(&dec, enc_stream, 6);
574
+ assert(r == -1);
575
+ lsqpack_dec_cleanup(&dec);
576
+ }
577
+
578
+
579
+ static void
580
+ test_winr_value_too_large_huffman (void)
581
+ {
582
+ struct lsqpack_dec dec;
583
+ int r;
584
+ /* Partial Insert With Name Reference with Huffman-encoded value
585
+ * string that, together with name, is larger than 4 x capacity (0x3FE4)
586
+ */
587
+ /* Refer to static entry 79: access-control-refer-headers (length 28) */
588
+ unsigned char enc_stream[] = "\xFF\x10\xFF\xE5\x7E";
589
+
590
+ lsqpack_dec_init(&dec, stderr, 0x1000, 0, NULL);
591
+ r = lsqpack_dec_enc_in(&dec, enc_stream, 5);
592
+ assert(r == -1);
593
+ lsqpack_dec_cleanup(&dec);
594
+ }
595
+
596
+
597
+ static void
598
+ test_winr_value_too_large_plain (void)
599
+ {
600
+ struct lsqpack_dec dec;
601
+ int r;
602
+ /* Partial Insert With Name Reference with plain-encoded value
603
+ * string that, together with name, is larger than capacity (0xFE4)
604
+ */
605
+ /* Refer to static entry 79: access-control-refer-headers (length 28) */
606
+ unsigned char enc_stream[] = "\xFF\x10\x7F\xE5\x1E";
607
+
608
+ lsqpack_dec_init(&dec, stderr, 0x1000, 0, NULL);
609
+ r = lsqpack_dec_enc_in(&dec, enc_stream, 5);
610
+ assert(r == -1);
611
+ lsqpack_dec_cleanup(&dec);
612
+ }
613
+
614
+
615
+ /* This is an odd case, but if the first call should provide no input at all,
616
+ * the decoder should return LQRHS_NEED
617
+ */
618
+ static void
619
+ test_dec_header_zero_in (void)
620
+ {
621
+ struct lsqpack_dec dec;
622
+ struct lsqpack_header_list *hlist;
623
+ enum lsqpack_read_header_status rhs;
624
+ const unsigned char *buf = (unsigned char *) "";
625
+
626
+ lsqpack_dec_init(&dec, stderr, 0x1000, 0, NULL);
627
+
628
+ rhs = lsqpack_dec_header_in(&dec,
629
+ (void *) 123 /* hblock */,
630
+ 2 /* Stream ID */,
631
+ 100 /* How long the thing is */,
632
+ &buf,
633
+ 0 /* How many bytes are available */,
634
+ &hlist,
635
+ NULL, 0);
636
+ assert(LQRHS_NEED == rhs);
637
+
638
+ lsqpack_dec_cleanup(&dec);
639
+ }
640
+
641
+
642
+ /* Header that's too should should return LQRHS_ERROR */
643
+ static void
644
+ test_dec_header_too_short (size_t header_size)
645
+ {
646
+ struct lsqpack_dec dec;
647
+ struct lsqpack_header_list *hlist;
648
+ enum lsqpack_read_header_status rhs;
649
+ const unsigned char *buf = (unsigned char *) "";
650
+
651
+ lsqpack_dec_init(&dec, stderr, 0x1000, 0, NULL);
652
+
653
+ rhs = lsqpack_dec_header_in(&dec,
654
+ (void *) 123 /* hblock */,
655
+ 2 /* Stream ID */,
656
+ header_size,
657
+ &buf,
658
+ 0 /* How many bytes are available */,
659
+ &hlist,
660
+ NULL, 0);
661
+ assert(LQRHS_ERROR == rhs);
662
+
663
+ lsqpack_dec_cleanup(&dec);
664
+ }
665
+
666
+
667
+ static void
668
+ test_enc_risked_streams_test (const char *test)
669
+ {
670
+ struct lsqpack_enc enc;
671
+ int s;
672
+ size_t sz;
673
+ ssize_t ssz;
674
+ long arg;
675
+ enum lsqpack_enc_status es;
676
+ unsigned n_seqnos = 0;
677
+ struct {
678
+ uint64_t stream_id;
679
+ unsigned seqno;
680
+ } seqnos[10], *seq_el;
681
+ unsigned char buf[0x100];
682
+ unsigned char *end_cmd;
683
+ int expect_failure;
684
+
685
+ const struct {
686
+ const char *name;
687
+ unsigned name_len;
688
+ const char *value;
689
+ unsigned value_len;
690
+ } headers[] = {
691
+ { "some", 4, "header", 6, },
692
+ { "another", 7, "header", 6, },
693
+ { "and yet another", 15, "header, duh", 11, },
694
+ };
695
+
696
+ fprintf(stderr, "BEGIN TEST %s\n", test);
697
+ lsqpack_enc_preinit(&enc, stderr);
698
+
699
+ while (1)
700
+ {
701
+ expect_failure = isupper(*test);
702
+ switch (*test++)
703
+ {
704
+ case 'i':
705
+ arg = strtol(test, (char**)&test, 10);
706
+ sz = sizeof(buf);
707
+ s = lsqpack_enc_init(&enc, stderr, 0x1000, 0x1000,
708
+ (unsigned) arg, 0, buf, &sz);
709
+ assert(s == 0);
710
+ break;
711
+ case 'r':
712
+ arg = strtol(test, (char**)&test, 10);
713
+ assert((unsigned) arg == enc.qpe_cur_streams_at_risk);
714
+ break;
715
+ case 's': /* Start header */
716
+ arg = strtol(test, (char**)&test, 10);
717
+ for (seq_el = seqnos; seq_el < seqnos + n_seqnos; ++seq_el)
718
+ if (seq_el->stream_id == arg)
719
+ break;
720
+ assert(seq_el < seqnos + sizeof(seqnos) / sizeof(seqnos[0]));
721
+ if (seq_el == seqnos + n_seqnos)
722
+ {
723
+ ++n_seqnos;
724
+ seq_el->stream_id = arg;
725
+ seq_el->seqno = 0;
726
+ }
727
+ s = lsqpack_enc_start_header(&enc, arg, seq_el->seqno++);
728
+ assert(s == 0);
729
+ break;
730
+ case 'c': /* En*C*ode */
731
+ arg = strtol(test, (char**)&test, 10);
732
+ sz = sizeof(buf);
733
+ /* We ignore the output */
734
+ es = lsqpack_enc_encode(&enc, buf, &sz, buf, &sz,
735
+ headers[arg].name, headers[arg].name_len,
736
+ headers[arg].value, headers[arg].value_len, 0);
737
+ assert(LQES_OK == es);
738
+ break;
739
+ case 'e': /* End header */
740
+ ssz = lsqpack_enc_end_header(&enc, buf, sizeof(buf), NULL);
741
+ assert(ssz > 0);
742
+ break;
743
+ case 'a': /* ACK header */
744
+ case 'A':
745
+ arg = strtol(test, (char**)&test, 10);
746
+ buf[0] = 0x80;
747
+ end_cmd = lsqpack_enc_int(buf, buf + sizeof(buf), arg, 7);
748
+ s = lsqpack_enc_decoder_in(&enc, buf, end_cmd - buf);
749
+ if (expect_failure)
750
+ assert(s < 0);
751
+ else
752
+ assert(s == 0);
753
+ break;
754
+ case 'L': /* Cancel header */
755
+ case 'l':
756
+ arg = strtol(test, (char**)&test, 10);
757
+ buf[0] = 0x40;
758
+ end_cmd = lsqpack_enc_int(buf, buf + sizeof(buf), arg, 6);
759
+ s = lsqpack_enc_decoder_in(&enc, buf, end_cmd - buf);
760
+ if (expect_failure)
761
+ assert(s < 0);
762
+ else
763
+ assert(s == 0);
764
+ break;
765
+ case 'N': /* Insert Count Increment */
766
+ case 'n':
767
+ arg = strtol(test, (char**)&test, 10);
768
+ buf[0] = 0x00;
769
+ end_cmd = lsqpack_enc_int(buf, buf + sizeof(buf), arg, 6);
770
+ s = lsqpack_enc_decoder_in(&enc, buf, end_cmd - buf);
771
+ if (expect_failure)
772
+ assert(s < 0);
773
+ else
774
+ assert(s == 0);
775
+ break;
776
+ break;
777
+ case '\0':
778
+ goto end;
779
+ default:
780
+ assert("unknown action");
781
+ goto end;
782
+ }
783
+ }
784
+
785
+ end:
786
+ lsqpack_enc_cleanup(&enc);
787
+ }
788
+
789
+
790
+ static void
791
+ test_enc_risked_streams (void)
792
+ {
793
+ const char **test;
794
+ const char *tests[] =
795
+ {
796
+ "i0r0s1c0er0",
797
+ "i1r0s1c0er0s2c0er1A1r1a2r0",
798
+ "i1r0s1c0er0s2c0er1s2c0c1er1a2r0a2r0",
799
+
800
+ "i1r0s1c0c1er0"
801
+ "s2c0er1"
802
+ "s2c0c1er1"
803
+ "a2r1" /* Ack first seqno, # of risked streams still 1 */
804
+ "a2r0",
805
+
806
+ "i1r0s1c0c1er0"
807
+ "s2c0er1"
808
+ "s2c0c1er1"
809
+ "l2r0" /* Cancel */
810
+ ,
811
+
812
+ "i1r0s1c0c1er0"
813
+ "s2c0er1"
814
+ "s2c0c1er1"
815
+ "N3"
816
+ "n1r1"
817
+ "n1r0"
818
+ ,
819
+
820
+ NULL,
821
+ };
822
+
823
+ for (test = tests; *test; ++test)
824
+ test_enc_risked_streams_test(*test);
825
+ }
826
+
827
+
828
+ int
829
+ main (void)
830
+ {
831
+ unsigned i;
832
+
833
+ for (i = 0; i < sizeof(header_block_tests)
834
+ / sizeof(header_block_tests[0]); ++i)
835
+ run_header_test(&header_block_tests[i]);
836
+
837
+ run_header_cancellation_test(&header_block_tests[0]);
838
+ test_enc_init();
839
+ test_push_promise();
840
+ test_discard_header(0);
841
+ test_discard_header(1);
842
+ test_static_bounds_header_block();
843
+ test_static_bounds_enc_stream();
844
+ test_wonr_name_too_large_huffman();
845
+ test_wonr_name_too_large_plain();
846
+ test_wonr_value_too_large_huffman();
847
+ test_wonr_value_too_large_plain();
848
+ test_winr_value_too_large_huffman();
849
+ test_winr_value_too_large_plain();
850
+ test_dec_header_zero_in();
851
+ test_dec_header_too_short(0);
852
+ test_dec_header_too_short(1);
853
+ test_enc_risked_streams();
854
+
855
+ return 0;
856
+ }