github.com/Andyfoo/golang/x/net@v0.0.0-20190901054642-57c1bf301704/http2/hpack/hpack_test.go (about) 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 BenchmarkHuffmanDecode(b *testing.B) { 466 b.StopTimer() 467 enc, err := hex.DecodeString(strings.Replace("94e7 821d d7f2 e6c7 b335 dfdf cd5b 3960 d5af 2708 7f36 72c1 ab27 0fb5 291f 9587 3160 65c0 03ed 4ee5 b106 3d50 07", 468 " ", "", -1)) 469 if err != nil { 470 b.Fatal(err) 471 } 472 b.ReportAllocs() 473 b.StartTimer() 474 var buf bytes.Buffer 475 for i := 0; i < b.N; i++ { 476 buf.Reset() 477 if _, err := HuffmanDecode(&buf, enc); err != nil { 478 b.Fatalf("decode error: %v", err) 479 } 480 if string(buf.Bytes()) != "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1" { 481 b.Fatalf("bogus output %q", buf.Bytes()) 482 } 483 } 484 } 485 486 func TestAppendHuffmanString(t *testing.T) { 487 tests := []struct { 488 in, want string 489 }{ 490 {"www.example.com", "f1e3 c2e5 f23a 6ba0 ab90 f4ff"}, 491 {"no-cache", "a8eb 1064 9cbf"}, 492 {"custom-key", "25a8 49e9 5ba9 7d7f"}, 493 {"custom-value", "25a8 49e9 5bb8 e8b4 bf"}, 494 {"302", "6402"}, 495 {"private", "aec3 771a 4b"}, 496 {"Mon, 21 Oct 2013 20:13:21 GMT", "d07a be94 1054 d444 a820 0595 040b 8166 e082 a62d 1bff"}, 497 {"https://www.example.com", "9d29 ad17 1863 c78f 0b97 c8e9 ae82 ae43 d3"}, 498 {"gzip", "9bd9 ab"}, 499 {"foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1", 500 "94e7 821d d7f2 e6c7 b335 dfdf cd5b 3960 d5af 2708 7f36 72c1 ab27 0fb5 291f 9587 3160 65c0 03ed 4ee5 b106 3d50 07"}, 501 } 502 for i, tt := range tests { 503 buf := []byte{} 504 want := strings.Replace(tt.want, " ", "", -1) 505 buf = AppendHuffmanString(buf, tt.in) 506 if got := hex.EncodeToString(buf); want != got { 507 t.Errorf("%d. encode = %q; want %q", i, got, want) 508 } 509 } 510 } 511 512 func TestHuffmanMaxStrLen(t *testing.T) { 513 const msg = "Some string" 514 huff := AppendHuffmanString(nil, msg) 515 516 testGood := func(max int) { 517 var out bytes.Buffer 518 if err := huffmanDecode(&out, max, huff); err != nil { 519 t.Errorf("For maxLen=%d, unexpected error: %v", max, err) 520 } 521 if out.String() != msg { 522 t.Errorf("For maxLen=%d, out = %q; want %q", max, out.String(), msg) 523 } 524 } 525 testGood(0) 526 testGood(len(msg)) 527 testGood(len(msg) + 1) 528 529 var out bytes.Buffer 530 if err := huffmanDecode(&out, len(msg)-1, huff); err != ErrStringLength { 531 t.Errorf("err = %v; want ErrStringLength", err) 532 } 533 } 534 535 func TestHuffmanRoundtripStress(t *testing.T) { 536 const Len = 50 // of uncompressed string 537 input := make([]byte, Len) 538 var output bytes.Buffer 539 var huff []byte 540 541 n := 5000 542 if testing.Short() { 543 n = 100 544 } 545 seed := time.Now().UnixNano() 546 t.Logf("Seed = %v", seed) 547 src := rand.New(rand.NewSource(seed)) 548 var encSize int64 549 for i := 0; i < n; i++ { 550 for l := range input { 551 input[l] = byte(src.Intn(256)) 552 } 553 huff = AppendHuffmanString(huff[:0], string(input)) 554 encSize += int64(len(huff)) 555 output.Reset() 556 if err := huffmanDecode(&output, 0, huff); err != nil { 557 t.Errorf("Failed to decode %q -> %q -> error %v", input, huff, err) 558 continue 559 } 560 if !bytes.Equal(output.Bytes(), input) { 561 t.Errorf("Roundtrip failure on %q -> %q -> %q", input, huff, output.Bytes()) 562 } 563 } 564 t.Logf("Compressed size of original: %0.02f%% (%v -> %v)", 100*(float64(encSize)/(Len*float64(n))), Len*n, encSize) 565 } 566 567 func TestHuffmanDecodeFuzz(t *testing.T) { 568 const Len = 50 // of compressed 569 var buf, zbuf bytes.Buffer 570 571 n := 5000 572 if testing.Short() { 573 n = 100 574 } 575 seed := time.Now().UnixNano() 576 t.Logf("Seed = %v", seed) 577 src := rand.New(rand.NewSource(seed)) 578 numFail := 0 579 for i := 0; i < n; i++ { 580 zbuf.Reset() 581 if i == 0 { 582 // Start with at least one invalid one. 583 zbuf.WriteString("00\x91\xff\xff\xff\xff\xc8") 584 } else { 585 for l := 0; l < Len; l++ { 586 zbuf.WriteByte(byte(src.Intn(256))) 587 } 588 } 589 590 buf.Reset() 591 if err := huffmanDecode(&buf, 0, zbuf.Bytes()); err != nil { 592 if err == ErrInvalidHuffman { 593 numFail++ 594 continue 595 } 596 t.Errorf("Failed to decode %q: %v", zbuf.Bytes(), err) 597 continue 598 } 599 } 600 t.Logf("%0.02f%% are invalid (%d / %d)", 100*float64(numFail)/float64(n), numFail, n) 601 if numFail < 1 { 602 t.Error("expected at least one invalid huffman encoding (test starts with one)") 603 } 604 } 605 606 func TestReadVarInt(t *testing.T) { 607 type res struct { 608 i uint64 609 consumed int 610 err error 611 } 612 tests := []struct { 613 n byte 614 p []byte 615 want res 616 }{ 617 // Fits in a byte: 618 {1, []byte{0}, res{0, 1, nil}}, 619 {2, []byte{2}, res{2, 1, nil}}, 620 {3, []byte{6}, res{6, 1, nil}}, 621 {4, []byte{14}, res{14, 1, nil}}, 622 {5, []byte{30}, res{30, 1, nil}}, 623 {6, []byte{62}, res{62, 1, nil}}, 624 {7, []byte{126}, res{126, 1, nil}}, 625 {8, []byte{254}, res{254, 1, nil}}, 626 627 // Doesn't fit in a byte: 628 {1, []byte{1}, res{0, 0, errNeedMore}}, 629 {2, []byte{3}, res{0, 0, errNeedMore}}, 630 {3, []byte{7}, res{0, 0, errNeedMore}}, 631 {4, []byte{15}, res{0, 0, errNeedMore}}, 632 {5, []byte{31}, res{0, 0, errNeedMore}}, 633 {6, []byte{63}, res{0, 0, errNeedMore}}, 634 {7, []byte{127}, res{0, 0, errNeedMore}}, 635 {8, []byte{255}, res{0, 0, errNeedMore}}, 636 637 // Ignoring top bits: 638 {5, []byte{255, 154, 10}, res{1337, 3, nil}}, // high dummy three bits: 111 639 {5, []byte{159, 154, 10}, res{1337, 3, nil}}, // high dummy three bits: 100 640 {5, []byte{191, 154, 10}, res{1337, 3, nil}}, // high dummy three bits: 101 641 642 // Extra byte: 643 {5, []byte{191, 154, 10, 2}, res{1337, 3, nil}}, // extra byte 644 645 // Short a byte: 646 {5, []byte{191, 154}, res{0, 0, errNeedMore}}, 647 648 // integer overflow: 649 {1, []byte{255, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128}, res{0, 0, errVarintOverflow}}, 650 } 651 for _, tt := range tests { 652 i, remain, err := readVarInt(tt.n, tt.p) 653 consumed := len(tt.p) - len(remain) 654 got := res{i, consumed, err} 655 if got != tt.want { 656 t.Errorf("readVarInt(%d, %v ~ %x) = %+v; want %+v", tt.n, tt.p, tt.p, got, tt.want) 657 } 658 } 659 } 660 661 // Fuzz crash, originally reported at https://github.com/bradfitz/http2/issues/56 662 func TestHuffmanFuzzCrash(t *testing.T) { 663 got, err := HuffmanDecodeToString([]byte("00\x91\xff\xff\xff\xff\xc8")) 664 if got != "" { 665 t.Errorf("Got %q; want empty string", got) 666 } 667 if err != ErrInvalidHuffman { 668 t.Errorf("Err = %v; want ErrInvalidHuffman", err) 669 } 670 } 671 672 func pair(name, value string) HeaderField { 673 return HeaderField{Name: name, Value: value} 674 } 675 676 func dehex(s string) []byte { 677 s = strings.Replace(s, " ", "", -1) 678 s = strings.Replace(s, "\n", "", -1) 679 b, err := hex.DecodeString(s) 680 if err != nil { 681 panic(err) 682 } 683 return b 684 } 685 686 func TestEmitEnabled(t *testing.T) { 687 var buf bytes.Buffer 688 enc := NewEncoder(&buf) 689 enc.WriteField(HeaderField{Name: "foo", Value: "bar"}) 690 enc.WriteField(HeaderField{Name: "foo", Value: "bar"}) 691 692 numCallback := 0 693 var dec *Decoder 694 dec = NewDecoder(8<<20, func(HeaderField) { 695 numCallback++ 696 dec.SetEmitEnabled(false) 697 }) 698 if !dec.EmitEnabled() { 699 t.Errorf("initial emit enabled = false; want true") 700 } 701 if _, err := dec.Write(buf.Bytes()); err != nil { 702 t.Error(err) 703 } 704 if numCallback != 1 { 705 t.Errorf("num callbacks = %d; want 1", numCallback) 706 } 707 if dec.EmitEnabled() { 708 t.Errorf("emit enabled = true; want false") 709 } 710 } 711 712 func TestSaveBufLimit(t *testing.T) { 713 const maxStr = 1 << 10 714 var got []HeaderField 715 dec := NewDecoder(initialHeaderTableSize, func(hf HeaderField) { 716 got = append(got, hf) 717 }) 718 dec.SetMaxStringLength(maxStr) 719 var frag []byte 720 frag = append(frag[:0], encodeTypeByte(false, false)) 721 frag = appendVarInt(frag, 7, 3) 722 frag = append(frag, "foo"...) 723 frag = appendVarInt(frag, 7, 3) 724 frag = append(frag, "bar"...) 725 726 if _, err := dec.Write(frag); err != nil { 727 t.Fatal(err) 728 } 729 730 want := []HeaderField{{Name: "foo", Value: "bar"}} 731 if !reflect.DeepEqual(got, want) { 732 t.Errorf("After small writes, got %v; want %v", got, want) 733 } 734 735 frag = append(frag[:0], encodeTypeByte(false, false)) 736 frag = appendVarInt(frag, 7, maxStr*3) 737 frag = append(frag, make([]byte, maxStr*3)...) 738 739 _, err := dec.Write(frag) 740 if err != ErrStringLength { 741 t.Fatalf("Write error = %v; want ErrStringLength", err) 742 } 743 } 744 745 func TestDynamicSizeUpdate(t *testing.T) { 746 var buf bytes.Buffer 747 enc := NewEncoder(&buf) 748 enc.SetMaxDynamicTableSize(255) 749 enc.WriteField(HeaderField{Name: "foo", Value: "bar"}) 750 751 d := NewDecoder(4096, func(_ HeaderField) {}) 752 _, err := d.Write(buf.Bytes()) 753 if err != nil { 754 t.Fatalf("unexpected error: got = %v", err) 755 } 756 757 d.Close() 758 759 // Start a new header 760 _, err = d.Write(buf.Bytes()) 761 if err != nil { 762 t.Fatalf("unexpected error: got = %v", err) 763 } 764 765 // must fail since the dynamic table update must be at the beginning 766 _, err = d.Write(buf.Bytes()) 767 if err == nil { 768 t.Fatalf("dynamic table size update not at the beginning of a header block") 769 } 770 }