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 } 723