OSDN Git Service

new repo
[bytom/vapor.git] / vendor / golang.org / x / net / http2 / hpack / hpack_test.go
1 // Copyright 2014 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 package hpack
6
7 import (
8         "bytes"
9         "encoding/hex"
10         "fmt"
11         "math/rand"
12         "reflect"
13         "strings"
14         "testing"
15         "time"
16 )
17
18 func (d *Decoder) mustAt(idx int) HeaderField {
19         if hf, ok := d.at(uint64(idx)); !ok {
20                 panic(fmt.Sprintf("bogus index %d", idx))
21         } else {
22                 return hf
23         }
24 }
25
26 func TestDynamicTableAt(t *testing.T) {
27         d := NewDecoder(4096, nil)
28         at := d.mustAt
29         if got, want := at(2), (pair(":method", "GET")); got != want {
30                 t.Errorf("at(2) = %v; want %v", got, want)
31         }
32         d.dynTab.add(pair("foo", "bar"))
33         d.dynTab.add(pair("blake", "miz"))
34         if got, want := at(staticTable.len()+1), (pair("blake", "miz")); got != want {
35                 t.Errorf("at(dyn 1) = %v; want %v", got, want)
36         }
37         if got, want := at(staticTable.len()+2), (pair("foo", "bar")); got != want {
38                 t.Errorf("at(dyn 2) = %v; want %v", got, want)
39         }
40         if got, want := at(3), (pair(":method", "POST")); got != want {
41                 t.Errorf("at(3) = %v; want %v", got, want)
42         }
43 }
44
45 func TestDynamicTableSizeEvict(t *testing.T) {
46         d := NewDecoder(4096, nil)
47         if want := uint32(0); d.dynTab.size != want {
48                 t.Fatalf("size = %d; want %d", d.dynTab.size, want)
49         }
50         add := d.dynTab.add
51         add(pair("blake", "eats pizza"))
52         if want := uint32(15 + 32); d.dynTab.size != want {
53                 t.Fatalf("after pizza, size = %d; want %d", d.dynTab.size, want)
54         }
55         add(pair("foo", "bar"))
56         if want := uint32(15 + 32 + 6 + 32); d.dynTab.size != want {
57                 t.Fatalf("after foo bar, size = %d; want %d", d.dynTab.size, want)
58         }
59         d.dynTab.setMaxSize(15 + 32 + 1 /* slop */)
60         if want := uint32(6 + 32); d.dynTab.size != want {
61                 t.Fatalf("after setMaxSize, size = %d; want %d", d.dynTab.size, want)
62         }
63         if got, want := d.mustAt(staticTable.len()+1), (pair("foo", "bar")); got != want {
64                 t.Errorf("at(dyn 1) = %v; want %v", got, want)
65         }
66         add(pair("long", strings.Repeat("x", 500)))
67         if want := uint32(0); d.dynTab.size != want {
68                 t.Fatalf("after big one, size = %d; want %d", d.dynTab.size, want)
69         }
70 }
71
72 func TestDecoderDecode(t *testing.T) {
73         tests := []struct {
74                 name       string
75                 in         []byte
76                 want       []HeaderField
77                 wantDynTab []HeaderField // newest entry first
78         }{
79                 // C.2.1 Literal Header Field with Indexing
80                 // http://http2.github.io/http2-spec/compression.html#rfc.section.C.2.1
81                 {"C.2.1", dehex("400a 6375 7374 6f6d 2d6b 6579 0d63 7573 746f 6d2d 6865 6164 6572"),
82                         []HeaderField{pair("custom-key", "custom-header")},
83                         []HeaderField{pair("custom-key", "custom-header")},
84                 },
85
86                 // C.2.2 Literal Header Field without Indexing
87                 // http://http2.github.io/http2-spec/compression.html#rfc.section.C.2.2
88                 {"C.2.2", dehex("040c 2f73 616d 706c 652f 7061 7468"),
89                         []HeaderField{pair(":path", "/sample/path")},
90                         []HeaderField{}},
91
92                 // C.2.3 Literal Header Field never Indexed
93                 // http://http2.github.io/http2-spec/compression.html#rfc.section.C.2.3
94                 {"C.2.3", dehex("1008 7061 7373 776f 7264 0673 6563 7265 74"),
95                         []HeaderField{{"password", "secret", true}},
96                         []HeaderField{}},
97
98                 // C.2.4 Indexed Header Field
99                 // http://http2.github.io/http2-spec/compression.html#rfc.section.C.2.4
100                 {"C.2.4", []byte("\x82"),
101                         []HeaderField{pair(":method", "GET")},
102                         []HeaderField{}},
103         }
104         for _, tt := range tests {
105                 d := NewDecoder(4096, nil)
106                 hf, err := d.DecodeFull(tt.in)
107                 if err != nil {
108                         t.Errorf("%s: %v", tt.name, err)
109                         continue
110                 }
111                 if !reflect.DeepEqual(hf, tt.want) {
112                         t.Errorf("%s: Got %v; want %v", tt.name, hf, tt.want)
113                 }
114                 gotDynTab := d.dynTab.reverseCopy()
115                 if !reflect.DeepEqual(gotDynTab, tt.wantDynTab) {
116                         t.Errorf("%s: dynamic table after = %v; want %v", tt.name, gotDynTab, tt.wantDynTab)
117                 }
118         }
119 }
120
121 func (dt *dynamicTable) reverseCopy() (hf []HeaderField) {
122         hf = make([]HeaderField, len(dt.table.ents))
123         for i := range hf {
124                 hf[i] = dt.table.ents[len(dt.table.ents)-1-i]
125         }
126         return
127 }
128
129 type encAndWant struct {
130         enc         []byte
131         want        []HeaderField
132         wantDynTab  []HeaderField
133         wantDynSize uint32
134 }
135
136 // C.3 Request Examples without Huffman Coding
137 // http://http2.github.io/http2-spec/compression.html#rfc.section.C.3
138 func TestDecodeC3_NoHuffman(t *testing.T) {
139         testDecodeSeries(t, 4096, []encAndWant{
140                 {dehex("8286 8441 0f77 7777 2e65 7861 6d70 6c65 2e63 6f6d"),
141                         []HeaderField{
142                                 pair(":method", "GET"),
143                                 pair(":scheme", "http"),
144                                 pair(":path", "/"),
145                                 pair(":authority", "www.example.com"),
146                         },
147                         []HeaderField{
148                                 pair(":authority", "www.example.com"),
149                         },
150                         57,
151                 },
152                 {dehex("8286 84be 5808 6e6f 2d63 6163 6865"),
153                         []HeaderField{
154                                 pair(":method", "GET"),
155                                 pair(":scheme", "http"),
156                                 pair(":path", "/"),
157                                 pair(":authority", "www.example.com"),
158                                 pair("cache-control", "no-cache"),
159                         },
160                         []HeaderField{
161                                 pair("cache-control", "no-cache"),
162                                 pair(":authority", "www.example.com"),
163                         },
164                         110,
165                 },
166                 {dehex("8287 85bf 400a 6375 7374 6f6d 2d6b 6579 0c63 7573 746f 6d2d 7661 6c75 65"),
167                         []HeaderField{
168                                 pair(":method", "GET"),
169                                 pair(":scheme", "https"),
170                                 pair(":path", "/index.html"),
171                                 pair(":authority", "www.example.com"),
172                                 pair("custom-key", "custom-value"),
173                         },
174                         []HeaderField{
175                                 pair("custom-key", "custom-value"),
176                                 pair("cache-control", "no-cache"),
177                                 pair(":authority", "www.example.com"),
178                         },
179                         164,
180                 },
181         })
182 }
183
184 // C.4 Request Examples with Huffman Coding
185 // http://http2.github.io/http2-spec/compression.html#rfc.section.C.4
186 func TestDecodeC4_Huffman(t *testing.T) {
187         testDecodeSeries(t, 4096, []encAndWant{
188                 {dehex("8286 8441 8cf1 e3c2 e5f2 3a6b a0ab 90f4 ff"),
189                         []HeaderField{
190                                 pair(":method", "GET"),
191                                 pair(":scheme", "http"),
192                                 pair(":path", "/"),
193                                 pair(":authority", "www.example.com"),
194                         },
195                         []HeaderField{
196                                 pair(":authority", "www.example.com"),
197                         },
198                         57,
199                 },
200                 {dehex("8286 84be 5886 a8eb 1064 9cbf"),
201                         []HeaderField{
202                                 pair(":method", "GET"),
203                                 pair(":scheme", "http"),
204                                 pair(":path", "/"),
205                                 pair(":authority", "www.example.com"),
206                                 pair("cache-control", "no-cache"),
207                         },
208                         []HeaderField{
209                                 pair("cache-control", "no-cache"),
210                                 pair(":authority", "www.example.com"),
211                         },
212                         110,
213                 },
214                 {dehex("8287 85bf 4088 25a8 49e9 5ba9 7d7f 8925 a849 e95b b8e8 b4bf"),
215                         []HeaderField{
216                                 pair(":method", "GET"),
217                                 pair(":scheme", "https"),
218                                 pair(":path", "/index.html"),
219                                 pair(":authority", "www.example.com"),
220                                 pair("custom-key", "custom-value"),
221                         },
222                         []HeaderField{
223                                 pair("custom-key", "custom-value"),
224                                 pair("cache-control", "no-cache"),
225                                 pair(":authority", "www.example.com"),
226                         },
227                         164,
228                 },
229         })
230 }
231
232 // http://http2.github.io/http2-spec/compression.html#rfc.section.C.5
233 // "This section shows several consecutive header lists, corresponding
234 // to HTTP responses, on the same connection. The HTTP/2 setting
235 // parameter SETTINGS_HEADER_TABLE_SIZE is set to the value of 256
236 // octets, causing some evictions to occur."
237 func TestDecodeC5_ResponsesNoHuff(t *testing.T) {
238         testDecodeSeries(t, 256, []encAndWant{
239                 {dehex(`
240 4803 3330 3258 0770 7269 7661 7465 611d
241 4d6f 6e2c 2032 3120 4f63 7420 3230 3133
242 2032 303a 3133 3a32 3120 474d 546e 1768
243 7474 7073 3a2f 2f77 7777 2e65 7861 6d70
244 6c65 2e63 6f6d
245 `),
246                         []HeaderField{
247                                 pair(":status", "302"),
248                                 pair("cache-control", "private"),
249                                 pair("date", "Mon, 21 Oct 2013 20:13:21 GMT"),
250                                 pair("location", "https://www.example.com"),
251                         },
252                         []HeaderField{
253                                 pair("location", "https://www.example.com"),
254                                 pair("date", "Mon, 21 Oct 2013 20:13:21 GMT"),
255                                 pair("cache-control", "private"),
256                                 pair(":status", "302"),
257                         },
258                         222,
259                 },
260                 {dehex("4803 3330 37c1 c0bf"),
261                         []HeaderField{
262                                 pair(":status", "307"),
263                                 pair("cache-control", "private"),
264                                 pair("date", "Mon, 21 Oct 2013 20:13:21 GMT"),
265                                 pair("location", "https://www.example.com"),
266                         },
267                         []HeaderField{
268                                 pair(":status", "307"),
269                                 pair("location", "https://www.example.com"),
270                                 pair("date", "Mon, 21 Oct 2013 20:13:21 GMT"),
271                                 pair("cache-control", "private"),
272                         },
273                         222,
274                 },
275                 {dehex(`
276 88c1 611d 4d6f 6e2c 2032 3120 4f63 7420
277 3230 3133 2032 303a 3133 3a32 3220 474d
278 54c0 5a04 677a 6970 7738 666f 6f3d 4153
279 444a 4b48 514b 425a 584f 5157 454f 5049
280 5541 5851 5745 4f49 553b 206d 6178 2d61
281 6765 3d33 3630 303b 2076 6572 7369 6f6e
282 3d31
283 `),
284                         []HeaderField{
285                                 pair(":status", "200"),
286                                 pair("cache-control", "private"),
287                                 pair("date", "Mon, 21 Oct 2013 20:13:22 GMT"),
288                                 pair("location", "https://www.example.com"),
289                                 pair("content-encoding", "gzip"),
290                                 pair("set-cookie", "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1"),
291                         },
292                         []HeaderField{
293                                 pair("set-cookie", "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1"),
294                                 pair("content-encoding", "gzip"),
295                                 pair("date", "Mon, 21 Oct 2013 20:13:22 GMT"),
296                         },
297                         215,
298                 },
299         })
300 }
301
302 // http://http2.github.io/http2-spec/compression.html#rfc.section.C.6
303 // "This section shows the same examples as the previous section, but
304 // using Huffman encoding for the literal values. The HTTP/2 setting
305 // parameter SETTINGS_HEADER_TABLE_SIZE is set to the value of 256
306 // octets, causing some evictions to occur. The eviction mechanism
307 // uses the length of the decoded literal values, so the same
308 // evictions occurs as in the previous section."
309 func TestDecodeC6_ResponsesHuffman(t *testing.T) {
310         testDecodeSeries(t, 256, []encAndWant{
311                 {dehex(`
312 4882 6402 5885 aec3 771a 4b61 96d0 7abe
313 9410 54d4 44a8 2005 9504 0b81 66e0 82a6
314 2d1b ff6e 919d 29ad 1718 63c7 8f0b 97c8
315 e9ae 82ae 43d3
316 `),
317                         []HeaderField{
318                                 pair(":status", "302"),
319                                 pair("cache-control", "private"),
320                                 pair("date", "Mon, 21 Oct 2013 20:13:21 GMT"),
321                                 pair("location", "https://www.example.com"),
322                         },
323                         []HeaderField{
324                                 pair("location", "https://www.example.com"),
325                                 pair("date", "Mon, 21 Oct 2013 20:13:21 GMT"),
326                                 pair("cache-control", "private"),
327                                 pair(":status", "302"),
328                         },
329                         222,
330                 },
331                 {dehex("4883 640e ffc1 c0bf"),
332                         []HeaderField{
333                                 pair(":status", "307"),
334                                 pair("cache-control", "private"),
335                                 pair("date", "Mon, 21 Oct 2013 20:13:21 GMT"),
336                                 pair("location", "https://www.example.com"),
337                         },
338                         []HeaderField{
339                                 pair(":status", "307"),
340                                 pair("location", "https://www.example.com"),
341                                 pair("date", "Mon, 21 Oct 2013 20:13:21 GMT"),
342                                 pair("cache-control", "private"),
343                         },
344                         222,
345                 },
346                 {dehex(`
347 88c1 6196 d07a be94 1054 d444 a820 0595
348 040b 8166 e084 a62d 1bff c05a 839b d9ab
349 77ad 94e7 821d d7f2 e6c7 b335 dfdf cd5b
350 3960 d5af 2708 7f36 72c1 ab27 0fb5 291f
351 9587 3160 65c0 03ed 4ee5 b106 3d50 07
352 `),
353                         []HeaderField{
354                                 pair(":status", "200"),
355                                 pair("cache-control", "private"),
356                                 pair("date", "Mon, 21 Oct 2013 20:13:22 GMT"),
357                                 pair("location", "https://www.example.com"),
358                                 pair("content-encoding", "gzip"),
359                                 pair("set-cookie", "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1"),
360                         },
361                         []HeaderField{
362                                 pair("set-cookie", "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1"),
363                                 pair("content-encoding", "gzip"),
364                                 pair("date", "Mon, 21 Oct 2013 20:13:22 GMT"),
365                         },
366                         215,
367                 },
368         })
369 }
370
371 func testDecodeSeries(t *testing.T, size uint32, steps []encAndWant) {
372         d := NewDecoder(size, nil)
373         for i, step := range steps {
374                 hf, err := d.DecodeFull(step.enc)
375                 if err != nil {
376                         t.Fatalf("Error at step index %d: %v", i, err)
377                 }
378                 if !reflect.DeepEqual(hf, step.want) {
379                         t.Fatalf("At step index %d: Got headers %v; want %v", i, hf, step.want)
380                 }
381                 gotDynTab := d.dynTab.reverseCopy()
382                 if !reflect.DeepEqual(gotDynTab, step.wantDynTab) {
383                         t.Errorf("After step index %d, dynamic table = %v; want %v", i, gotDynTab, step.wantDynTab)
384                 }
385                 if d.dynTab.size != step.wantDynSize {
386                         t.Errorf("After step index %d, dynamic table size = %v; want %v", i, d.dynTab.size, step.wantDynSize)
387                 }
388         }
389 }
390
391 func TestHuffmanDecodeExcessPadding(t *testing.T) {
392         tests := [][]byte{
393                 {0xff},                                   // Padding Exceeds 7 bits
394                 {0x1f, 0xff},                             // {"a", 1 byte excess padding}
395                 {0x1f, 0xff, 0xff},                       // {"a", 2 byte excess padding}
396                 {0x1f, 0xff, 0xff, 0xff},                 // {"a", 3 byte excess padding}
397                 {0xff, 0x9f, 0xff, 0xff, 0xff},           // {"a", 29 bit excess padding}
398                 {'R', 0xbc, '0', 0xff, 0xff, 0xff, 0xff}, // Padding ends on partial symbol.
399         }
400         for i, in := range tests {
401                 var buf bytes.Buffer
402                 if _, err := HuffmanDecode(&buf, in); err != ErrInvalidHuffman {
403                         t.Errorf("test-%d: decode(%q) = %v; want ErrInvalidHuffman", i, in, err)
404                 }
405         }
406 }
407
408 func TestHuffmanDecodeEOS(t *testing.T) {
409         in := []byte{0xff, 0xff, 0xff, 0xff, 0xfc} // {EOS, "?"}
410         var buf bytes.Buffer
411         if _, err := HuffmanDecode(&buf, in); err != ErrInvalidHuffman {
412                 t.Errorf("error = %v; want ErrInvalidHuffman", err)
413         }
414 }
415
416 func TestHuffmanDecodeMaxLengthOnTrailingByte(t *testing.T) {
417         in := []byte{0x00, 0x01} // {"0", "0", "0"}
418         var buf bytes.Buffer
419         if err := huffmanDecode(&buf, 2, in); err != ErrStringLength {
420                 t.Errorf("error = %v; want ErrStringLength", err)
421         }
422 }
423
424 func TestHuffmanDecodeCorruptPadding(t *testing.T) {
425         in := []byte{0x00}
426         var buf bytes.Buffer
427         if _, err := HuffmanDecode(&buf, in); err != ErrInvalidHuffman {
428                 t.Errorf("error = %v; want ErrInvalidHuffman", err)
429         }
430 }
431
432 func TestHuffmanDecode(t *testing.T) {
433         tests := []struct {
434                 inHex, want string
435         }{
436                 {"f1e3 c2e5 f23a 6ba0 ab90 f4ff", "www.example.com"},
437                 {"a8eb 1064 9cbf", "no-cache"},
438                 {"25a8 49e9 5ba9 7d7f", "custom-key"},
439                 {"25a8 49e9 5bb8 e8b4 bf", "custom-value"},
440                 {"6402", "302"},
441                 {"aec3 771a 4b", "private"},
442                 {"d07a be94 1054 d444 a820 0595 040b 8166 e082 a62d 1bff", "Mon, 21 Oct 2013 20:13:21 GMT"},
443                 {"9d29 ad17 1863 c78f 0b97 c8e9 ae82 ae43 d3", "https://www.example.com"},
444                 {"9bd9 ab", "gzip"},
445                 {"94e7 821d d7f2 e6c7 b335 dfdf cd5b 3960 d5af 2708 7f36 72c1 ab27 0fb5 291f 9587 3160 65c0 03ed 4ee5 b106 3d50 07",
446                         "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1"},
447         }
448         for i, tt := range tests {
449                 var buf bytes.Buffer
450                 in, err := hex.DecodeString(strings.Replace(tt.inHex, " ", "", -1))
451                 if err != nil {
452                         t.Errorf("%d. hex input error: %v", i, err)
453                         continue
454                 }
455                 if _, err := HuffmanDecode(&buf, in); err != nil {
456                         t.Errorf("%d. decode error: %v", i, err)
457                         continue
458                 }
459                 if got := buf.String(); tt.want != got {
460                         t.Errorf("%d. decode = %q; want %q", i, got, tt.want)
461                 }
462         }
463 }
464
465 func TestAppendHuffmanString(t *testing.T) {
466         tests := []struct {
467                 in, want string
468         }{
469                 {"www.example.com", "f1e3 c2e5 f23a 6ba0 ab90 f4ff"},
470                 {"no-cache", "a8eb 1064 9cbf"},
471                 {"custom-key", "25a8 49e9 5ba9 7d7f"},
472                 {"custom-value", "25a8 49e9 5bb8 e8b4 bf"},
473                 {"302", "6402"},
474                 {"private", "aec3 771a 4b"},
475                 {"Mon, 21 Oct 2013 20:13:21 GMT", "d07a be94 1054 d444 a820 0595 040b 8166 e082 a62d 1bff"},
476                 {"https://www.example.com", "9d29 ad17 1863 c78f 0b97 c8e9 ae82 ae43 d3"},
477                 {"gzip", "9bd9 ab"},
478                 {"foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1",
479                         "94e7 821d d7f2 e6c7 b335 dfdf cd5b 3960 d5af 2708 7f36 72c1 ab27 0fb5 291f 9587 3160 65c0 03ed 4ee5 b106 3d50 07"},
480         }
481         for i, tt := range tests {
482                 buf := []byte{}
483                 want := strings.Replace(tt.want, " ", "", -1)
484                 buf = AppendHuffmanString(buf, tt.in)
485                 if got := hex.EncodeToString(buf); want != got {
486                         t.Errorf("%d. encode = %q; want %q", i, got, want)
487                 }
488         }
489 }
490
491 func TestHuffmanMaxStrLen(t *testing.T) {
492         const msg = "Some string"
493         huff := AppendHuffmanString(nil, msg)
494
495         testGood := func(max int) {
496                 var out bytes.Buffer
497                 if err := huffmanDecode(&out, max, huff); err != nil {
498                         t.Errorf("For maxLen=%d, unexpected error: %v", max, err)
499                 }
500                 if out.String() != msg {
501                         t.Errorf("For maxLen=%d, out = %q; want %q", max, out.String(), msg)
502                 }
503         }
504         testGood(0)
505         testGood(len(msg))
506         testGood(len(msg) + 1)
507
508         var out bytes.Buffer
509         if err := huffmanDecode(&out, len(msg)-1, huff); err != ErrStringLength {
510                 t.Errorf("err = %v; want ErrStringLength", err)
511         }
512 }
513
514 func TestHuffmanRoundtripStress(t *testing.T) {
515         const Len = 50 // of uncompressed string
516         input := make([]byte, Len)
517         var output bytes.Buffer
518         var huff []byte
519
520         n := 5000
521         if testing.Short() {
522                 n = 100
523         }
524         seed := time.Now().UnixNano()
525         t.Logf("Seed = %v", seed)
526         src := rand.New(rand.NewSource(seed))
527         var encSize int64
528         for i := 0; i < n; i++ {
529                 for l := range input {
530                         input[l] = byte(src.Intn(256))
531                 }
532                 huff = AppendHuffmanString(huff[:0], string(input))
533                 encSize += int64(len(huff))
534                 output.Reset()
535                 if err := huffmanDecode(&output, 0, huff); err != nil {
536                         t.Errorf("Failed to decode %q -> %q -> error %v", input, huff, err)
537                         continue
538                 }
539                 if !bytes.Equal(output.Bytes(), input) {
540                         t.Errorf("Roundtrip failure on %q -> %q -> %q", input, huff, output.Bytes())
541                 }
542         }
543         t.Logf("Compressed size of original: %0.02f%% (%v -> %v)", 100*(float64(encSize)/(Len*float64(n))), Len*n, encSize)
544 }
545
546 func TestHuffmanDecodeFuzz(t *testing.T) {
547         const Len = 50 // of compressed
548         var buf, zbuf bytes.Buffer
549
550         n := 5000
551         if testing.Short() {
552                 n = 100
553         }
554         seed := time.Now().UnixNano()
555         t.Logf("Seed = %v", seed)
556         src := rand.New(rand.NewSource(seed))
557         numFail := 0
558         for i := 0; i < n; i++ {
559                 zbuf.Reset()
560                 if i == 0 {
561                         // Start with at least one invalid one.
562                         zbuf.WriteString("00\x91\xff\xff\xff\xff\xc8")
563                 } else {
564                         for l := 0; l < Len; l++ {
565                                 zbuf.WriteByte(byte(src.Intn(256)))
566                         }
567                 }
568
569                 buf.Reset()
570                 if err := huffmanDecode(&buf, 0, zbuf.Bytes()); err != nil {
571                         if err == ErrInvalidHuffman {
572                                 numFail++
573                                 continue
574                         }
575                         t.Errorf("Failed to decode %q: %v", zbuf.Bytes(), err)
576                         continue
577                 }
578         }
579         t.Logf("%0.02f%% are invalid (%d / %d)", 100*float64(numFail)/float64(n), numFail, n)
580         if numFail < 1 {
581                 t.Error("expected at least one invalid huffman encoding (test starts with one)")
582         }
583 }
584
585 func TestReadVarInt(t *testing.T) {
586         type res struct {
587                 i        uint64
588                 consumed int
589                 err      error
590         }
591         tests := []struct {
592                 n    byte
593                 p    []byte
594                 want res
595         }{
596                 // Fits in a byte:
597                 {1, []byte{0}, res{0, 1, nil}},
598                 {2, []byte{2}, res{2, 1, nil}},
599                 {3, []byte{6}, res{6, 1, nil}},
600                 {4, []byte{14}, res{14, 1, nil}},
601                 {5, []byte{30}, res{30, 1, nil}},
602                 {6, []byte{62}, res{62, 1, nil}},
603                 {7, []byte{126}, res{126, 1, nil}},
604                 {8, []byte{254}, res{254, 1, nil}},
605
606                 // Doesn't fit in a byte:
607                 {1, []byte{1}, res{0, 0, errNeedMore}},
608                 {2, []byte{3}, res{0, 0, errNeedMore}},
609                 {3, []byte{7}, res{0, 0, errNeedMore}},
610                 {4, []byte{15}, res{0, 0, errNeedMore}},
611                 {5, []byte{31}, res{0, 0, errNeedMore}},
612                 {6, []byte{63}, res{0, 0, errNeedMore}},
613                 {7, []byte{127}, res{0, 0, errNeedMore}},
614                 {8, []byte{255}, res{0, 0, errNeedMore}},
615
616                 // Ignoring top bits:
617                 {5, []byte{255, 154, 10}, res{1337, 3, nil}}, // high dummy three bits: 111
618                 {5, []byte{159, 154, 10}, res{1337, 3, nil}}, // high dummy three bits: 100
619                 {5, []byte{191, 154, 10}, res{1337, 3, nil}}, // high dummy three bits: 101
620
621                 // Extra byte:
622                 {5, []byte{191, 154, 10, 2}, res{1337, 3, nil}}, // extra byte
623
624                 // Short a byte:
625                 {5, []byte{191, 154}, res{0, 0, errNeedMore}},
626
627                 // integer overflow:
628                 {1, []byte{255, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128}, res{0, 0, errVarintOverflow}},
629         }
630         for _, tt := range tests {
631                 i, remain, err := readVarInt(tt.n, tt.p)
632                 consumed := len(tt.p) - len(remain)
633                 got := res{i, consumed, err}
634                 if got != tt.want {
635                         t.Errorf("readVarInt(%d, %v ~ %x) = %+v; want %+v", tt.n, tt.p, tt.p, got, tt.want)
636                 }
637         }
638 }
639
640 // Fuzz crash, originally reported at https://github.com/bradfitz/http2/issues/56
641 func TestHuffmanFuzzCrash(t *testing.T) {
642         got, err := HuffmanDecodeToString([]byte("00\x91\xff\xff\xff\xff\xc8"))
643         if got != "" {
644                 t.Errorf("Got %q; want empty string", got)
645         }
646         if err != ErrInvalidHuffman {
647                 t.Errorf("Err = %v; want ErrInvalidHuffman", err)
648         }
649 }
650
651 func pair(name, value string) HeaderField {
652         return HeaderField{Name: name, Value: value}
653 }
654
655 func dehex(s string) []byte {
656         s = strings.Replace(s, " ", "", -1)
657         s = strings.Replace(s, "\n", "", -1)
658         b, err := hex.DecodeString(s)
659         if err != nil {
660                 panic(err)
661         }
662         return b
663 }
664
665 func TestEmitEnabled(t *testing.T) {
666         var buf bytes.Buffer
667         enc := NewEncoder(&buf)
668         enc.WriteField(HeaderField{Name: "foo", Value: "bar"})
669         enc.WriteField(HeaderField{Name: "foo", Value: "bar"})
670
671         numCallback := 0
672         var dec *Decoder
673         dec = NewDecoder(8<<20, func(HeaderField) {
674                 numCallback++
675                 dec.SetEmitEnabled(false)
676         })
677         if !dec.EmitEnabled() {
678                 t.Errorf("initial emit enabled = false; want true")
679         }
680         if _, err := dec.Write(buf.Bytes()); err != nil {
681                 t.Error(err)
682         }
683         if numCallback != 1 {
684                 t.Errorf("num callbacks = %d; want 1", numCallback)
685         }
686         if dec.EmitEnabled() {
687                 t.Errorf("emit enabled = true; want false")
688         }
689 }
690
691 func TestSaveBufLimit(t *testing.T) {
692         const maxStr = 1 << 10
693         var got []HeaderField
694         dec := NewDecoder(initialHeaderTableSize, func(hf HeaderField) {
695                 got = append(got, hf)
696         })
697         dec.SetMaxStringLength(maxStr)
698         var frag []byte
699         frag = append(frag[:0], encodeTypeByte(false, false))
700         frag = appendVarInt(frag, 7, 3)
701         frag = append(frag, "foo"...)
702         frag = appendVarInt(frag, 7, 3)
703         frag = append(frag, "bar"...)
704
705         if _, err := dec.Write(frag); err != nil {
706                 t.Fatal(err)
707         }
708
709         want := []HeaderField{{Name: "foo", Value: "bar"}}
710         if !reflect.DeepEqual(got, want) {
711                 t.Errorf("After small writes, got %v; want %v", got, want)
712         }
713
714         frag = append(frag[:0], encodeTypeByte(false, false))
715         frag = appendVarInt(frag, 7, maxStr*3)
716         frag = append(frag, make([]byte, maxStr*3)...)
717
718         _, err := dec.Write(frag)
719         if err != ErrStringLength {
720                 t.Fatalf("Write error = %v; want ErrStringLength", err)
721         }
722 }