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,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
+ }