1 /**
2  * Huffman Tests
3  * 
4  * Copyright:
5  * (C) 2012-2015 Tatsuhiro Tsujikawa
6  * (C) 2014-2015 Etienne Cimon
7  *
8  * License: 
9  * Distributed under the terms of the MIT license with an additional section 1.2 of the curl/libcurl project. 
10  * Consult the provided LICENSE.md file for details
11  */
12 module libhttp2.huffman_tests;
13 
14 import libhttp2.constants;
15 static if (TEST_ALL):
16 
17 import libhttp2.buffers;
18 import libhttp2.huffman;
19 import libhttp2.deflater;
20 import libhttp2.inflater;
21 import libhttp2.types;
22 import libhttp2.frame;
23 import libhttp2.helpers;
24 import libhttp2.tests;
25 import std.c.string : memcmp, memset;
26 
27 void test_hd_deflate() {
28 	Deflater deflater = Deflater(DEFAULT_MAX_DEFLATE_BUFFER_SIZE);
29 	Inflater inflater = Inflater(true);
30 	HeaderField[] hfa1 = [HeaderField(":path", "/my-example/index.html"), HeaderField(":scheme", "https"), HeaderField("hello", "world")];
31 	HeaderField[] hfa2 = [HeaderField(":path", "/script.js"), HeaderField(":scheme", "https")];
32 	HeaderField[] hfa3 = [HeaderField("cookie", "k1=v1"), HeaderField("cookie", "k2=v2"), HeaderField("via", "proxy")];
33 	HeaderField[] hfa4 = [HeaderField(":path", "/style.css"), HeaderField("cookie", "k1=v1"), HeaderField("cookie", "k1=v1")];
34 	HeaderField[] hfa5 = [HeaderField(":path", "/style.css"), HeaderField("x-nghttp2", "")];
35 	Buffers bufs = framePackBuffers();
36 	size_t blocklen;
37 	HeaderFields output;
38 	ErrorCode rv;
39 
40 	rv = deflater.deflate(bufs, hfa1);
41 	blocklen = bufs.length;
42 	assert(0 == rv);
43 	assert(blocklen > 0);
44 	assert(blocklen == output.inflate(inflater, bufs, 0));
45 	
46 	assert(3 == output.length);
47 	assert(hfa1.equals(output[0 .. 3]));
48 	
49 	output.reset();
50 	bufs.reset();
51 	
52 	/* Second headers */
53 	rv = deflater.deflate(bufs, hfa2);
54 	blocklen = bufs.length;
55 	
56 	assert(0 == rv);
57 	assert(blocklen > 0);
58 	assert(blocklen == output.inflate(inflater, bufs, 0));
59 	
60 	assert(2 == output.length);
61 	assert(hfa2.equals(output[0 .. 2]));
62 	
63 	output.reset();
64 	bufs.reset();
65 	
66 	/* Third headers, including same header field name, but value is not
67      the same. */
68 	rv = deflater.deflate(bufs, hfa3);
69 	blocklen = bufs.length;
70 	
71 	assert(0 == rv);
72 	assert(blocklen > 0);
73 	assert(blocklen == output.inflate(inflater, bufs, 0));
74 	
75 	assert(3 == output.length);
76 	assert(hfa3.equals(output[0 .. 3]));
77 	
78 	output.reset();
79 	bufs.reset();
80 	
81 	/* Fourth headers, including duplicate header fields. */
82 	rv = deflater.deflate(bufs, hfa4);
83 	blocklen = bufs.length;
84 	
85 	assert(0 == rv);
86 	assert(blocklen > 0);
87 	assert(blocklen == output.inflate(inflater, bufs, 0));
88 	
89 	assert(3 == output.length);
90 	assert(hfa4.equals(output[0 .. 3]));
91 	
92 	output.reset();
93 	bufs.reset();
94 	
95 	/* Fifth headers includes empty value */
96 	rv = deflater.deflate(bufs, hfa5);
97 	blocklen = bufs.length;
98 	
99 	assert(0 == rv);
100 	assert(blocklen > 0);
101 	assert(blocklen == output.inflate(inflater, bufs, 0));
102 	
103 	assert(2 == output.length);
104 	assert(hfa5.equals(output[0 .. 2]));
105 	
106 	output.reset();
107 	bufs.reset();
108 	
109 	/* Cleanup */
110 	bufs.free();
111 	inflater.free();
112 	deflater.free();
113 }
114 
115 void test_hd_deflate_same_indexed_repr() {
116 	Deflater deflater = Deflater(DEFAULT_MAX_DEFLATE_BUFFER_SIZE);
117 	Inflater inflater = Inflater(true);
118 	HeaderField[] hfa1 = [HeaderField("cookie", "alpha"), HeaderField("cookie", "alpha")];
119 	HeaderField[] hfa2 = [HeaderField("cookie", "alpha"), HeaderField("cookie", "alpha"), HeaderField("cookie", "alpha")];
120 	Buffers bufs = framePackBuffers();
121 	size_t blocklen;
122 	HeaderFields output;
123 	ErrorCode rv;
124 
125 	/* Encode 2 same headers.  Emit 1 literal reprs and 1 index repr. */
126 	rv = deflater.deflate(bufs, hfa1);
127 	blocklen = bufs.length;
128 	
129 	assert(0 == rv);
130 	assert(blocklen > 0);
131 	assert(blocklen == output.inflate(inflater, bufs, 0));
132 	
133 	assert(2 == output.length);
134 	assert(hfa1.equals(output[]));
135 	
136 	output.reset();
137 	bufs.reset();
138 	
139 	/* Encode 3 same headers.  This time, emits 3 index reprs. */
140 	rv = deflater.deflate(bufs, hfa2);
141 	blocklen = bufs.length;
142 	
143 	assert(0 == rv);
144 	assert(blocklen == 3);
145 	assert(blocklen == output.inflate(inflater, bufs, 0));
146 	
147 	assert(3 == output.length);
148 	assert(hfa2.equals(output[0 .. 3]));
149 	
150 	output.reset();
151 	bufs.reset();
152 	
153 	/* Cleanup */
154 	bufs.free();
155 	inflater.free();
156 	deflater.free();
157 }
158 
159 void test_hd_inflate_indexed() {
160 	Inflater inflater = Inflater(true);
161 	Buffers bufs = framePackBuffers();
162 	size_t blocklen;
163 	HeaderField hf = HeaderField(":path", "/");
164 	HeaderFields output;
165 
166 	bufs.add((1 << 7) | 4);
167 	
168 	blocklen = bufs.length;
169 	
170 	assert(1 == blocklen);
171 	assert(blocklen == output.inflate(inflater, bufs, 0));
172 	
173 	assert(1 == output.length);
174 	
175 	assert(hf == output.hfa_raw[0]);
176 	
177 	output.reset();
178 	bufs.reset();
179 	
180 	/* index = 0 is error */
181 	bufs.add(1 << 7);
182 	
183 	blocklen = bufs.length;
184 	
185 	assert(1 == blocklen);
186 	assert(ErrorCode.HEADER_COMP == output.inflate(inflater, bufs, 0));
187 	
188 	bufs.free();
189 	inflater.free();
190 }
191 
192 void test_hd_inflate_indname_noinc() {
193 	Inflater inflater = Inflater(true);
194 	Buffers bufs = framePackBuffers();
195 	size_t blocklen;
196 	HeaderField[] hfa = [
197 		/* Huffman */
198 		HeaderField("user-agent", "nghttp2"),
199 		/* Expecting no huffman */
200 		HeaderField("user-agent", "x")
201 	];
202 	size_t i;
203 	HeaderFields output;
204 
205 	foreach (ref hf; hfa) {
206 		assert(0 == bufs.emitIndexedNameBlock(57, hf, false));
207 		blocklen = bufs.length;
208 		
209 		assert(blocklen > 0);
210 		assert(blocklen == output.inflate(inflater, bufs, 0));
211 		assert(1 == output.length);
212 		assert(hf == output.hfa_raw[0]);
213 		assert(0 == inflater.ctx.hd_table.length);
214 		
215 		output.reset();
216 		bufs.reset();
217 	}
218 	
219 	bufs.free();
220 	inflater.free();
221 }
222 
223 void test_hd_inflate_indname_inc() {
224 	Inflater inflater = Inflater(true);
225 	Buffers bufs = framePackBuffers();
226 	size_t blocklen;
227 	HeaderField hf = HeaderField("user-agent", "nghttp2");
228 	HeaderFields output;
229 	assert(0 == bufs.emitIndexedNameBlock(57, hf, 1));
230 	blocklen = bufs.length;
231 	
232 	assert(blocklen > 0);
233 	assert(blocklen == output.inflate(inflater, bufs, 0));
234 	assert(1 == output.length);
235 	assert(hf == output.hfa_raw[0]);
236 	assert(1 == inflater.ctx.hd_table.length);
237 	assert(hf == inflater.ctx.get(static_table.length + inflater.ctx.hd_table.length - 1).hf);
238 	
239 	output.reset();
240 	bufs.free();
241 	inflater.free();
242 }
243 
244 void test_hd_inflate_indname_inc_eviction() {
245 	Inflater inflater = Inflater(true);
246 	Buffers bufs = framePackBuffers();
247 	size_t blocklen;
248 	ubyte[1024] value;
249 	memset(value.ptr, '0', value.length);
250 	HeaderFields output;
251 	HeaderField hf;
252 
253 	hf.value = cast(string)value;
254 	hf.flag = HeaderFlag.NONE;
255 
256 	assert(0 == bufs.emitIndexedNameBlock(14, hf, true));
257 	assert(0 == bufs.emitIndexedNameBlock(15, hf, true));
258 	assert(0 == bufs.emitIndexedNameBlock(16, hf, true));
259 	assert(0 == bufs.emitIndexedNameBlock(17, hf, true));
260 	
261 	blocklen = bufs.length;
262 
263 	assert(blocklen > 0);
264 	
265 	assert(blocklen == output.inflate(inflater, bufs, 0));
266 	
267 	assert(4 == output.length);
268 	assert(14 == output.hfa_raw[0].name.length);
269 	assert("accept-charset" == output.hfa_raw[0].name);
270 	assert(value.length == output.hfa_raw[0].value.length);
271 	
272 	output.reset();
273 	bufs.reset();
274 	
275 	assert(3 == inflater.ctx.hd_table.length);
276 	
277 	bufs.free();
278 	inflater.free();
279 }
280 
281 void test_hd_inflate_newname_noinc() {
282 	Inflater inflater = Inflater(true);
283 	Buffers bufs = framePackBuffers();
284 	size_t blocklen;
285 	HeaderField[] hfa = [/* Expecting huffman for both */
286 		HeaderField("my-long-content-length", "nghttp2"),
287 		/* Expecting no huffman for both */
288 		HeaderField("x", "y"),
289 		/* Huffman for key only */
290 		HeaderField("my-long-content-length", "y"),
291 		/* Huffman for value only */
292 		HeaderField("x", "nghttp2")];
293 	size_t i;
294 	HeaderFields output;
295 	
296 	foreach (ref hf; hfa) {
297 		assert(0 == bufs.emitNewNameBlock(hf, false));
298 		
299 		blocklen = bufs.length;
300 		
301 		assert(blocklen > 0);
302 		assert(blocklen == output.inflate(inflater, bufs, 0));
303 		
304 		assert(1 == output.length);
305 		assert(hf == output.hfa_raw[0]);
306 		assert(0 == inflater.ctx.hd_table.length);
307 		
308 		output.reset();
309 		bufs.reset();
310 	}
311 	
312 	bufs.free();
313 	inflater.free();
314 }
315 
316 void test_hd_inflate_newname_inc() {
317 	Inflater inflater = Inflater(true);
318 	Buffers bufs = framePackBuffers();
319 	size_t blocklen;
320 	HeaderField hf = HeaderField("x-rel", "nghttp2");
321 	HeaderFields output;
322 
323 	assert(0 == bufs.emitNewNameBlock(hf, true));
324 	
325 	blocklen = bufs.length;
326 	
327 	assert(blocklen > 0);
328 	assert(blocklen == output.inflate(inflater, bufs, 0));
329 	
330 	assert(1 == output.length);
331 	assert(hf == output.hfa_raw[0]);
332 	assert(1 == inflater.ctx.hd_table.length);
333 	assert(hf == inflater.ctx.get(static_table.length + inflater.ctx.hd_table.length - 1).hf);
334 	
335 	output.reset();
336 	bufs.free();
337 	inflater.free();
338 }
339 
340 void test_hd_inflate_clearall_inc() {
341 	Inflater inflater = Inflater(true);
342 	Buffers bufs = largeBuffers(8192);
343 	size_t blocklen;
344 	HeaderField hf;
345 	ubyte[4060] value;
346 	memset(value.ptr, '0', value.length);
347 	HeaderFields output;
348 
349 	/* Total 4097 bytes space required to hold this entry */
350 	hf.name = "alpha";
351 	hf.value = cast(string)value;
352 	hf.flag = HeaderFlag.NONE;
353 		
354 	assert(0 == bufs.emitNewNameBlock(hf, true));
355 	
356 	blocklen = bufs.length;
357 	
358 	assert(blocklen > 0);
359 	assert(blocklen == output.inflate(inflater, bufs, 0));
360 	
361 	assert(1 == output.length);
362 	assert(hf == output.hfa_raw[0]);
363 	assert(0 == inflater.ctx.hd_table.length);
364 	
365 	output.reset();
366 	
367 	/* Do it again */
368 	assert(blocklen == output.inflate(inflater, bufs, 0));
369 	
370 	assert(1 == output.length);
371 	assert(hf == output.hfa_raw[0]);
372 	assert(0 == inflater.ctx.hd_table.length);
373 	
374 	output.reset();
375 	bufs.reset();
376 	
377 	/* This time, 4096 bytes space required, which is just fits in the header table */	
378 	hf.value = hf.value[0 .. 4059];
379 	assert(0 == bufs.emitNewNameBlock(hf, true));
380 	
381 	blocklen = bufs.length;
382 	
383 	assert(blocklen > 0);
384 	assert(blocklen == output.inflate(inflater, bufs, 0));
385 	
386 	assert(1 == output.length);
387 	assert(hf == output.hfa_raw[0]);
388 	assert(1 == inflater.ctx.hd_table.length);
389 	
390 	output.reset();
391 	bufs.reset();
392 	
393 	bufs.free();
394 	inflater.free();
395 }
396 
397 void test_hd_inflate_zero_length_huffman() {
398 	Inflater inflater = Inflater(true);
399 	Buffers bufs = framePackBuffers();
400 	/* Literal header without indexing - new name */
401 	ubyte[] data = [0x40, 0x01, 0x78 /* 'x' */, 0x80];
402 	HeaderFields output;
403 
404 	bufs.add(cast(string)data);
405 	
406 	/* /\* Literal header without indexing - new name *\/ */
407 	/* ptr[0] = 0x40; */
408 	/* ptr[1] = 1; */
409 	/* ptr[2] = 'x'; */
410 	/* ptr[3] = 0x80; */
411 	
412 	
413 	assert(4 == output.inflate(inflater, bufs, 0));
414 	
415 	assert(1 == output.length);
416 	assert(1 == output.hfa_raw[0].name.length);
417 	assert('x' == output.hfa_raw[0].name[0]);
418 	assert(null == output.hfa_raw[0].value);
419 	assert(0 == output.hfa_raw[0].value.length);
420 	
421 	output.reset();
422 	bufs.free();
423 	inflater.free();
424 }
425 
426 void test_hd_ringbuf_reserve() {
427 	Deflater deflater;
428 	Inflater inflater = Inflater(true);
429 	HeaderField hf;
430 	Buffers bufs = framePackBuffers();
431 	HeaderFields output;
432 	int i;
433 	size_t rv;
434 	size_t blocklen;
435 		
436 	hf.flag = HeaderFlag.NONE;
437 	hf.name = "a";
438 	char[] value = Mem.alloc!(char[])(4);
439 	memset(value.ptr, 0, value.length);
440 	hf.value = cast(string) value;
441 	deflater = Deflater(8000);
442 	
443 	
444 	inflater.changeTableSize(8000);
445 	deflater.changeTableSize(8000);
446 	
447 	for (i = 0; i < 150; ++i) {
448 		memcpy(value.ptr, &i, i.sizeof);
449 		rv = deflater.deflate(bufs, hf);
450 		blocklen = bufs.length;
451 		
452 		assert(0 == rv);
453 		assert(blocklen > 0);
454 		
455 		assert(blocklen == output.inflate(inflater, bufs, 0));
456 		
457 		assert(1 == output.length);
458 		assert(hf == output.hfa_raw[0]);
459 		
460 		output.reset();
461 		bufs.reset();
462 	}
463 	
464 	bufs.free();
465 	inflater.free();
466 	deflater.free();
467 	
468 	Mem.free(hf.value);
469 }
470 
471 void test_hd_change_table_size() {
472 	Deflater deflater = Deflater(DEFAULT_MAX_DEFLATE_BUFFER_SIZE);
473 	Inflater inflater = Inflater(true);
474 	HeaderField[] hfa = [HeaderField("alpha", "bravo"), HeaderField("charlie", "delta")];
475 	HeaderField[] hfa2 = [HeaderField(":path", "/")];
476 	Buffers bufs = framePackBuffers();
477 	size_t rv;
478 	HeaderFields output;
479 	size_t blocklen;
480 		
481 	/* inflater changes notifies 8000 max header table size */
482 	inflater.changeTableSize(8000);
483 	deflater.changeTableSize(8000);
484 	
485 	assert(4096 == deflater.ctx.hd_table_bufsize_max);
486 	
487 	assert(8000 == inflater.ctx.hd_table_bufsize_max);
488 	assert(8000 == inflater.settings_hd_table_bufsize_max);
489 	
490 	/* This will emit encoding context update with header table size 4096 */
491 	rv = deflater.deflate(bufs, hfa[0 .. 2]);
492 	blocklen = bufs.length;
493 	
494 	assert(0 == rv);
495 	assert(blocklen > 0);
496 	assert(2 == deflater.ctx.hd_table.length);
497 	assert(4096 == deflater.ctx.hd_table_bufsize_max);
498 	
499 	assert(blocklen == output.inflate(inflater, bufs, 0));
500 	assert(2 == inflater.ctx.hd_table.length);
501 	assert(4096 == inflater.ctx.hd_table_bufsize_max);
502 	assert(8000 == inflater.settings_hd_table_bufsize_max);
503 	
504 	output.reset();
505 	bufs.reset();
506 	
507 	/* inflater changes header table size to 1024 */
508 	inflater.changeTableSize(1024);
509 	deflater.changeTableSize(1024);
510 	
511 	assert(1024 == deflater.ctx.hd_table_bufsize_max);
512 	
513 	assert(1024 == inflater.ctx.hd_table_bufsize_max);
514 	assert(1024 == inflater.settings_hd_table_bufsize_max);
515 	
516 	rv = deflater.deflate(bufs, hfa[0 .. 2]);
517 	blocklen = bufs.length;
518 	
519 	assert(0 == rv);
520 	assert(blocklen > 0);
521 	assert(2 == deflater.ctx.hd_table.length);
522 	assert(1024 == deflater.ctx.hd_table_bufsize_max);
523 	
524 	assert(blocklen == output.inflate(inflater, bufs, 0));
525 	assert(2 == inflater.ctx.hd_table.length);
526 	assert(1024 == inflater.ctx.hd_table_bufsize_max);
527 	assert(1024 == inflater.settings_hd_table_bufsize_max);
528 	
529 	output.reset();
530 	bufs.reset();
531 	
532 	/* inflater changes header table size to 0 */
533 	inflater.changeTableSize(0);
534 	deflater.changeTableSize(0);
535 	
536 	assert(0 == deflater.ctx.hd_table.length);
537 	assert(0 == deflater.ctx.hd_table_bufsize_max);
538 	
539 	assert(0 == inflater.ctx.hd_table.length);
540 	assert(0 == inflater.ctx.hd_table_bufsize_max);
541 	assert(0 == inflater.settings_hd_table_bufsize_max);
542 	
543 	rv = deflater.deflate(bufs, hfa[0 .. 2]);
544 	blocklen = bufs.length;
545 	
546 	assert(0 == rv);
547 	assert(blocklen > 0);
548 	assert(0 == deflater.ctx.hd_table.length);
549 	assert(0 == deflater.ctx.hd_table_bufsize_max);
550 	
551 	assert(blocklen == output.inflate(inflater, bufs, 0));
552 	assert(0 == inflater.ctx.hd_table.length);
553 	assert(0 == inflater.ctx.hd_table_bufsize_max);
554 	assert(0 == inflater.settings_hd_table_bufsize_max);
555 	
556 	output.reset();
557 	bufs.reset();
558 	
559 	bufs.free();
560 	inflater.free();
561 	deflater.free();
562 	
563 	/* Check table buffer is expanded */
564 	bufs = framePackBuffers();
565 	
566 	deflater = Deflater(8192);
567 	inflater = Inflater(true);
568 	
569 	/* First inflater changes header table size to 8000 */
570 	inflater.changeTableSize(8000);
571 	deflater.changeTableSize(8000);
572 	
573 	assert(8000 == deflater.ctx.hd_table_bufsize_max);
574 	
575 	assert(8000 == inflater.ctx.hd_table_bufsize_max);
576 	assert(8000 == inflater.settings_hd_table_bufsize_max);
577 	
578 	rv = deflater.deflate(bufs, hfa[0 .. 2]);
579 	blocklen = bufs.length;
580 	
581 	assert(0 == rv);
582 	assert(blocklen > 0);
583 	assert(2 == deflater.ctx.hd_table.length);
584 	assert(8000 == deflater.ctx.hd_table_bufsize_max);
585 	
586 	assert(blocklen == output.inflate(inflater, bufs, 0));
587 	assert(2 == inflater.ctx.hd_table.length);
588 	assert(8000 == inflater.ctx.hd_table_bufsize_max);
589 	assert(8000 == inflater.settings_hd_table_bufsize_max);
590 	
591 	output.reset();
592 	bufs.reset();
593 	
594 	inflater.changeTableSize(16383);
595 	deflater.changeTableSize(16383);
596 	
597 	assert(8192 == deflater.ctx.hd_table_bufsize_max);
598 	
599 	assert(16383 == inflater.ctx.hd_table_bufsize_max);
600 	assert(16383 == inflater.settings_hd_table_bufsize_max);
601 	
602 	rv = deflater.deflate(bufs, hfa[0 .. 2]);
603 	blocklen = bufs.length;
604 	
605 	assert(0 == rv);
606 	assert(blocklen > 0);
607 	assert(2 == deflater.ctx.hd_table.length);
608 	assert(8192 == deflater.ctx.hd_table_bufsize_max);
609 	
610 	assert(blocklen == output.inflate(inflater, bufs, 0));
611 	assert(2 == inflater.ctx.hd_table.length);
612 	assert(8192 == inflater.ctx.hd_table_bufsize_max);
613 	assert(16383 == inflater.settings_hd_table_bufsize_max);
614 	
615 	output.reset();
616 	bufs.reset();
617 	
618 	/* Lastly, check the error condition */
619 	
620 	rv = bufs.emitTableSize(25600);
621 	assert(rv == 0);
622 	assert(ErrorCode.HEADER_COMP == output.inflate(inflater, bufs, 0));
623 	
624 	output.reset();
625 	bufs.reset();
626 	
627 	inflater.free();
628 	deflater.free();
629 	
630 	/* Check that encoder can handle the case where its allowable buffer
631      size is less than default size, 4096 */
632 	deflater = Deflater(1024);
633 	inflater = Inflater(true);
634 	
635 	assert(1024 == deflater.ctx.hd_table_bufsize_max);
636 	
637 	/* This emits context update with buffer size 1024 */
638 	rv = deflater.deflate(bufs, hfa[0 .. 2]);
639 	blocklen = bufs.length;
640 	
641 	assert(0 == rv);
642 	assert(blocklen > 0);
643 	assert(2 == deflater.ctx.hd_table.length);
644 	assert(1024 == deflater.ctx.hd_table_bufsize_max);
645 	
646 	assert(blocklen == output.inflate(inflater, bufs, 0));
647 	assert(2 == inflater.ctx.hd_table.length);
648 	assert(1024 == inflater.ctx.hd_table_bufsize_max);
649 	assert(4096 == inflater.settings_hd_table_bufsize_max);
650 	
651 	output.reset();
652 	bufs.reset();
653 	
654 	inflater.free();
655 	deflater.free();
656 	
657 	/* Check that table size uint.max can be received */
658 	deflater = Deflater(uint.max);
659 	inflater = Inflater(true);
660 	
661 	inflater.changeTableSize(uint.max);
662 	deflater.changeTableSize(uint.max);
663 	
664 	rv = deflater.deflate(bufs, hfa[0 .. 2]);
665 	blocklen = bufs.length;
666 	
667 	assert(0 == rv);
668 	assert(uint.max == deflater.ctx.hd_table_bufsize_max);
669 	
670 	assert(blocklen == output.inflate(inflater, bufs, 0));
671 	assert(uint.max == inflater.ctx.hd_table_bufsize_max);
672 	assert(uint.max == inflater.settings_hd_table_bufsize_max);
673 	
674 	output.reset();
675 	bufs.reset();
676 	
677 	inflater.free();
678 	deflater.free();
679 	
680 	/* Check that context update emitted twice
681 	 */
682 	deflater = Deflater(4096);
683 	inflater = Inflater(true);
684 	
685 	inflater.changeTableSize(0);
686 	inflater.changeTableSize(3000);
687 	deflater.changeTableSize(0);
688 	deflater.changeTableSize(3000);
689 	
690 	assert(0 == deflater.min_hd_table_bufsize_max);
691 	assert(3000 == deflater.ctx.hd_table_bufsize_max);
692 	
693 	rv = deflater.deflate(bufs, hfa2[0 .. 1]);
694 	blocklen = bufs.length;
695 	
696 	assert(0 == rv);
697 	assert(3 < blocklen);
698 	assert(3000 == deflater.ctx.hd_table_bufsize_max);
699 	assert(uint.max == deflater.min_hd_table_bufsize_max);
700 	
701 	assert(blocklen == output.inflate(inflater, bufs, 0));
702 	assert(3000 == inflater.ctx.hd_table_bufsize_max);
703 	assert(3000 == inflater.settings_hd_table_bufsize_max);
704 	
705 	output.reset();
706 	
707 	inflater.free();
708 	deflater.free();
709 	
710 	bufs.free();
711 }
712 
713 void check_deflate_inflate(ref Deflater deflater, ref Inflater inflater, HeaderField[] hfa) 
714 {
715 	Buffers bufs = framePackBuffers();
716 	size_t blocklen;
717 	HeaderFields output;
718 	ErrorCode rv;
719 
720 	rv = deflater.deflate(bufs, hfa);
721 	blocklen = bufs.length;
722 	
723 	assert(0 == rv);
724 	assert(blocklen >= 0);
725 	assert(blocklen == output.inflate(inflater, bufs, 0));
726 	assert(hfa.length == output.length);
727 	assert(hfa.equals(output[]));
728 	output.reset();
729 	bufs.free();
730 }
731 
732 void test_hd_deflate_inflate() {
733 	Deflater deflater = Deflater(DEFAULT_MAX_DEFLATE_BUFFER_SIZE);
734 	Inflater inflater = Inflater(true);
735 	HeaderField[] hfa1 = [
736 		HeaderField(":status", "200 OK"),
737 		HeaderField("access-control-allow-origin", "*"),
738 		HeaderField("cache-control", "private, max-age=0, must-revalidate"),
739 		HeaderField("content-length", "76073"),
740 		HeaderField("content-type", "text/html"),
741 		HeaderField("date", "Sat, 27 Jul 2013 06:22:12 GMT"),
742 		HeaderField("expires", "Sat, 27 Jul 2013 06:22:12 GMT"),
743 		HeaderField("server", "Apache"),
744 		HeaderField("vary", "foobar"),
745 		HeaderField("via", "1.1 alphabravo (squid/3.x.x), 1.1 nghttpx"),
746 		HeaderField("x-cache", "MISS from alphabravo"),
747 		HeaderField("x-cache-action", "MISS"),
748 		HeaderField("x-cache-age", "0"),
749 		HeaderField("x-cache-lookup", "MISS from alphabravo:3128"),
750 		HeaderField("x-lb-nocache", "true")
751 	];
752 	HeaderField[] hfa2 = [
753 		HeaderField(":status", "304 Not Modified"),
754 		HeaderField("age", "0"),
755 		HeaderField("cache-control", "max-age=56682045"),
756 		HeaderField("content-type", "text/css"),
757 		HeaderField("date", "Sat, 27 Jul 2013 06:22:12 GMT"),
758 		HeaderField("expires", "Thu, 14 May 2015 07:22:57 GMT"),
759 		HeaderField("last-modified", "Tue, 14 May 2013 07:22:15 GMT"),
760 		HeaderField("vary", "Accept-Encoding"),
761 		HeaderField("via", "1.1 alphabravo (squid/3.x.x), 1.1 nghttpx"),
762 		HeaderField("x-cache", "HIT from alphabravo"),
763 		HeaderField("x-cache-lookup", "HIT from alphabravo:3128")];
764 
765 	HeaderField[] hfa3 = [
766 		HeaderField(":status", "304 Not Modified"),
767 		HeaderField("age", "0"),
768 		HeaderField("cache-control", "max-age=56682072"),
769 		HeaderField("content-type", "text/css"),
770 		HeaderField("date", "Sat, 27 Jul 2013 06:22:12 GMT"),
771 		HeaderField("expires", "Thu, 14 May 2015 07:23:24 GMT"),
772 		HeaderField("last-modified", "Tue, 14 May 2013 07:22:13 GMT"),
773 		HeaderField("vary", "Accept-Encoding"),
774 		HeaderField("via", "1.1 alphabravo (squid/3.x.x), 1.1 nghttpx"),
775 		HeaderField("x-cache", "HIT from alphabravo"),
776 		HeaderField("x-cache-lookup", "HIT from alphabravo:3128")
777 	];
778 
779 	HeaderField[] hfa4 = [
780 		HeaderField(":status", "304 Not Modified"),
781 		HeaderField("age", "0"),
782 		HeaderField("cache-control", "max-age=56682022"),
783 		HeaderField("content-type", "text/css"),
784 		HeaderField("date", "Sat, 27 Jul 2013 06:22:12 GMT"),
785 		HeaderField("expires", "Thu, 14 May 2015 07:22:34 GMT"),
786 		HeaderField("last-modified", "Tue, 14 May 2013 07:22:14 GMT"),
787 		HeaderField("vary", "Accept-Encoding"),
788 		HeaderField("via", "1.1 alphabravo (squid/3.x.x), 1.1 nghttpx"),
789 		HeaderField("x-cache", "HIT from alphabravo"),
790 		HeaderField("x-cache-lookup", "HIT from alphabravo:3128")
791 	];
792 	HeaderField[] hfa5 = [
793 		HeaderField(":status", "304 Not Modified"),
794 		HeaderField("age", "0"),
795 		HeaderField("cache-control", "max-age=4461139"),
796 		HeaderField("content-type", "application/x-javascript"),
797 		HeaderField("date", "Sat, 27 Jul 2013 06:22:12 GMT"),
798 		HeaderField("expires", "Mon, 16 Sep 2013 21:34:31 GMT"),
799 		HeaderField("last-modified", "Thu, 05 May 2011 09:15:59 GMT"),
800 		HeaderField("vary", "Accept-Encoding"),
801 		HeaderField("via", "1.1 alphabravo (squid/3.x.x), 1.1 nghttpx"),
802 		HeaderField("x-cache", "HIT from alphabravo"),
803 		HeaderField("x-cache-lookup", "HIT from alphabravo:3128")
804 	];
805 
806 	HeaderField[] hfa6 = [
807 		HeaderField(":status", "304 Not Modified"),
808 		HeaderField("age", "0"),
809 		HeaderField("cache-control", "max-age=18645951"),
810 		HeaderField("content-type", "application/x-javascript"),
811 		HeaderField("date", "Sat, 27 Jul 2013 06:22:12 GMT"),
812 		HeaderField("expires", "Fri, 28 Feb 2014 01:48:03 GMT"),
813 		HeaderField("last-modified", "Tue, 12 Jul 2011 16:02:59 GMT"),
814 		HeaderField("vary", "Accept-Encoding"),
815 		HeaderField("via", "1.1 alphabravo (squid/3.x.x), 1.1 nghttpx"),
816 		HeaderField("x-cache", "HIT from alphabravo"),
817 		HeaderField("x-cache-lookup", "HIT from alphabravo:3128"),
818 	];
819 	HeaderField[] hfa7 = [
820 		HeaderField(":status", "304 Not Modified"),
821 		HeaderField("age", "0"),
822 		HeaderField("cache-control", "max-age=31536000"),
823 		HeaderField("content-type", "application/javascript"),
824 		HeaderField("date", "Sat, 27 Jul 2013 06:22:12 GMT"),
825 		HeaderField("etag", "\"6807-4dc5b54e0dcc0\""),
826 		HeaderField("expires", "Wed, 21 May 2014 08:32:17 GMT"),
827 		HeaderField("last-modified", "Fri, 10 May 2013 11:18:51 GMT"),
828 		HeaderField("via", "1.1 alphabravo (squid/3.x.x), 1.1 nghttpx"),
829 		HeaderField("x-cache", "HIT from alphabravo"),
830 		HeaderField("x-cache-lookup", "HIT from alphabravo:3128")
831 	];
832 	HeaderField[] hfa8 = [
833 		HeaderField(":status", "304 Not Modified"),
834 		HeaderField("age", "0"),
835 		HeaderField("cache-control", "max-age=31536000"),
836 		HeaderField("content-type", "application/javascript"),
837 		HeaderField("date", "Sat, 27 Jul 2013 06:22:12 GMT"),
838 		HeaderField("etag", "\"41c6-4de7d28585b00\""),
839 		HeaderField("expires", "Thu, 12 Jun 2014 10:00:58 GMT"),
840 		HeaderField("last-modified", "Thu, 06 Jun 2013 14:30:36 GMT"),
841 		HeaderField("via", "1.1 alphabravo (squid/3.x.x), 1.1 nghttpx"),
842 		HeaderField("x-cache", "HIT from alphabravo"),
843 		HeaderField("x-cache-lookup", "HIT from alphabravo:3128")
844 	];
845 
846 	HeaderField[] hfa9 = [
847 		HeaderField(":status", "304 Not Modified"),
848 		HeaderField("age", "0"),
849 		HeaderField("cache-control", "max-age=31536000"),
850 		HeaderField("content-type", "application/javascript"),
851 		HeaderField("date", "Sat, 27 Jul 2013 06:22:12 GMT"),
852 		HeaderField("etag", "\"19d6e-4dc5b35a541c0\""),
853 		HeaderField("expires", "Wed, 21 May 2014 08:32:18 GMT"),
854 		HeaderField("last-modified", "Fri, 10 May 2013 11:10:07 GMT"),
855 		HeaderField("via", "1.1 alphabravo (squid/3.x.x), 1.1 nghttpx"),
856 		HeaderField("x-cache", "HIT from alphabravo"),
857 		HeaderField("x-cache-lookup", "HIT from alphabravo:3128")
858 	];
859 	HeaderField[] hfa10 = [
860 		HeaderField(":status", "304 Not Modified"),
861 		HeaderField("age", "0"),
862 		HeaderField("cache-control", "max-age=56682045"),
863 		HeaderField("content-type", "text/css"),
864 		HeaderField("date", "Sat, 27 Jul 2013 06:22:12 GMT"),
865 		HeaderField("expires", "Thu, 14 May 2015 07:22:57 GMT"),
866 		HeaderField("last-modified", "Tue, 14 May 2013 07:21:53 GMT"),
867 		HeaderField("vary", "Accept-Encoding"),
868 		HeaderField("via", "1.1 alphabravo (squid/3.x.x), 1.1 nghttpx"),
869 		HeaderField("x-cache", "HIT from alphabravo"),
870 		HeaderField("x-cache-lookup", "HIT from alphabravo:3128")
871 	];
872 
873 	check_deflate_inflate(deflater, inflater, hfa1);
874 	check_deflate_inflate(deflater, inflater, hfa2);
875 	check_deflate_inflate(deflater, inflater, hfa3);
876 	check_deflate_inflate(deflater, inflater, hfa4);
877 	check_deflate_inflate(deflater, inflater, hfa5);
878 	check_deflate_inflate(deflater, inflater, hfa6);
879 	check_deflate_inflate(deflater, inflater, hfa7);
880 	check_deflate_inflate(deflater, inflater, hfa8);
881 	check_deflate_inflate(deflater, inflater, hfa9);
882 	check_deflate_inflate(deflater, inflater, hfa10);
883 	
884 	inflater.free();
885 	deflater.free();
886 }
887 
888 void test_hd_no_index() {
889 	Deflater deflater = Deflater(DEFAULT_MAX_DEFLATE_BUFFER_SIZE);
890 	Inflater inflater = Inflater(true);
891 	Buffers bufs = framePackBuffers();
892 	size_t blocklen;
893 	HeaderField[] hfa = [
894 		HeaderField(":method", "GET"), HeaderField(":method", "POST"),
895 		HeaderField(":path", "/foo"),  HeaderField("version", "HTTP/1.1"),
896 		HeaderField(":method", "GET")
897 	];
898 	size_t i;
899 	HeaderFields output;
900 	ErrorCode rv;
901 	
902 	/* 1st :method: GET can be indexable, last one is not */
903 	foreach (ref hf; hfa[1 .. $]) {
904 		hf.flag = HeaderFlag.NO_INDEX;
905 	}
906 
907 	rv = deflater.deflate(bufs, hfa);
908 	blocklen = bufs.length;
909 	
910 	assert(0 == rv);
911 	assert(blocklen > 0);
912 	assert(blocklen == output.inflate(inflater, bufs, 0));
913 	
914 	assert(hfa.length == output.length);
915 	assert(hfa.equals(output[]));
916 	
917 	assert(output.hfa_raw[0].flag == HeaderFlag.NONE);
918 
919 	foreach (ref hf; output[][1 .. $])
920 		assert(hf.flag == HeaderFlag.NO_INDEX);
921 	
922 	output.reset();
923 	
924 	bufs.free();
925 	inflater.free();
926 	deflater.free();
927 }
928 
929 void test_hd_deflate_bound() {
930 	Deflater deflater = Deflater(DEFAULT_MAX_DEFLATE_BUFFER_SIZE);
931 	HeaderField[] hfa = [HeaderField(":method", "GET"), HeaderField("alpha", "bravo")];
932 	Buffers bufs = framePackBuffers();
933 	size_t bound, bound2;
934 	
935 	bound = deflater.upperBound(hfa);
936 	
937 	assert(12 + 6 * 2 * 2 + hfa[0].name.length + hfa[0].value.length + hfa[1].name.length + hfa[1].value.length == bound);
938 	
939 	deflater.deflate(bufs, hfa);
940 	
941 	assert(bound > cast(size_t)bufs.length);
942 	
943 	bound2 = deflater.upperBound(hfa);
944 	
945 	assert(bound == bound2);
946 	
947 	bufs.free();
948 	deflater.free();
949 }
950 
951 void test_hd_public_api() {
952 	Deflater deflater = Deflater(4096);
953 	Inflater inflater = Inflater(true);
954 	HeaderField[] hfa = [HeaderField("alpha", "bravo"), HeaderField("charlie", "delta")];
955 	ubyte[4096] buf;
956 	size_t buflen;
957 	size_t blocklen;
958 	Buffers bufs = framePackBuffers();
959 
960 	buflen = deflater.upperBound(hfa);
961 	
962 	blocklen = deflater.deflate(buf[0 .. buflen], hfa);
963 	
964 	assert(blocklen > 0);
965 	bufs.free();
966 	bufs = new Buffers(buf[0 .. blocklen]);
967 	bufs.head.buf.last += blocklen;
968 	HeaderFields dummy;
969 	assert(blocklen == dummy.inflate(inflater, bufs, 0));
970 	dummy.reset();
971 	bufs.free();
972 	
973 	inflater.free();
974 	deflater.free();
975 
976 	/* See ErrorCode.INSUFF_BUFSIZE */
977 	deflater = Deflater(4096);
978 
979 	blocklen = deflater.deflate(buf[0 .. blocklen - 1], hfa);
980 	
981 	assert(ErrorCode.INSUFF_BUFSIZE == blocklen);
982 	deflater.free();
983 }
984 
985 private size_t encodeLength(ubyte *buf, ulong n, size_t prefix) {
986 	size_t k = (1 << prefix) - 1;
987 	size_t len;
988 	*buf &= ~(cast(ubyte)k);
989 	if (n >= k) {
990 		*buf++ |= cast(ubyte) k;
991 		n -= k;
992 		++len;
993 	} else {
994 		*buf++ |= cast(ubyte) n;
995 		return 1;
996 	}
997 	do {
998 		++len;
999 		if (n >= 128) {
1000 			*buf++ = cast(ubyte)((1 << 7) | ((cast(ubyte)n) & 0x7f));
1001 			n >>= 7;
1002 		} else {
1003 			*buf++ = cast(ubyte)n;
1004 			break;
1005 		}
1006 	} while (n);
1007 	return len;
1008 }
1009 
1010 void test_hd_decode_length() {
1011 	uint output;
1012 	size_t shift;
1013 	bool is_final;
1014 	ubyte[16] buf;
1015 	ubyte* bufp;
1016 	size_t len;
1017 	size_t rv;
1018 	size_t i;
1019 
1020 	len = encodeLength(buf.ptr, uint.max, 7);
1021 
1022 	rv = output.decodeLength(shift, is_final, 0, 0, buf.ptr, buf.ptr + cast(size_t)len, 7);
1023 	
1024 	assert(cast(int)len == rv, len.to!string ~ " != " ~ rv.to!string);
1025 	assert(false != is_final);
1026 	assert(uint.max == output);
1027 	
1028 	/* Make sure that we can decode integer if we feed 1 byte at a time */
1029 	output = 0;
1030 	shift = 0;
1031 	is_final = false;
1032 	bufp = buf.ptr;
1033 	
1034 	for (i = 0; i < len; ++i, ++bufp) {
1035 		rv = output.decodeLength(shift, is_final, output, shift, bufp, bufp + 1, 7);
1036 		assert(rv == 1);
1037 		
1038 		if (is_final) {
1039 			break;
1040 		}
1041 	}
1042 	
1043 	assert(i == len - 1);
1044 	assert(0 != is_final);
1045 	assert(uint.max == output);
1046 	
1047 	/* Check overflow case */
1048 	memset(buf.ptr, 0, buf.length);
1049 	len = encodeLength(buf.ptr, 1L << 32, 7);
1050 	
1051 	rv = output.decodeLength(shift, is_final, 0, 0, buf.ptr, buf.ptr + len, 7);
1052 	
1053 	assert(-1 == rv);
1054 }
1055 
1056 void test_hd_huff_encode() {
1057 	ErrorCode rv;
1058 	size_t len;
1059 	Buffers bufs, outbufs;
1060 	Decoder ctx;
1061 	const ubyte[] t1 = [22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9,  8,  7,  6,  5,  4,  3,  2,  1,  0];
1062 	
1063 	bufs = framePackBuffers();
1064 	outbufs = framePackBuffers();
1065 
1066 	rv = bufs.encodeHuffman(cast(string)t1);
1067 	
1068 	assert(rv == 0);
1069 		
1070 	len = ctx.decode(outbufs, bufs.cur.buf[], true);
1071 	
1072 	assert(bufs.length == len);
1073 	assert(cast(size_t)t1.length == outbufs.length);
1074 	
1075 	assert(t1[0 .. $] == outbufs.cur.buf.pos[0 .. t1.length]);
1076 	
1077 	bufs.free();
1078 	outbufs.free();
1079 }
1080 
1081 unittest {
1082 	import memutils.allocators;
1083 	enum Debugger = 0x02;
1084 	assert(0 == getAllocator!Debugger().bytesAllocated());
1085 	test_hd_deflate();
1086 	test_hd_deflate_same_indexed_repr();
1087 	test_hd_inflate_indexed();
1088 	test_hd_inflate_indname_noinc();
1089 	test_hd_inflate_indname_inc();
1090 	test_hd_inflate_indname_inc_eviction();
1091 	test_hd_inflate_newname_noinc();
1092 	test_hd_inflate_newname_inc();
1093 	test_hd_inflate_clearall_inc();
1094 	test_hd_inflate_zero_length_huffman();
1095 	test_hd_ringbuf_reserve();
1096 	test_hd_change_table_size();
1097 	test_hd_deflate_inflate();
1098 	test_hd_no_index();
1099 	test_hd_deflate_bound();
1100 	test_hd_public_api();
1101 	test_hd_decode_length();
1102 	test_hd_huff_encode();
1103 	assert(0 == getAllocator!Debugger().bytesAllocated());
1104 }